/* Security BSides Dehradun 0x03 — polish.css
   ==========================================================================
   The site-wide "premium finish" layer for every page EXCEPT the home page
   (index.html gets the same treatment from apple.css, which also carries the
   hero/orb work). This sheet is the additive rounding pass the rest of the
   site asked for, plus the board-page hover-transition.

   WHY A SEPARATE, UNLAYERED SHEET
   The base is deliberately sharp — tokens.css:148 says so outright: "Radii:
   Swiss is sharp. Nothing above 2px except status pills." We are intentionally
   softening that, additively, without editing the base files so they stay
   recoverable. base.css/components.css/pages.css live in @layer, so an
   UNLAYERED sheet (this one) beats them at equal specificity regardless of
   source order — the same mechanism apple.css uses on the home page. Load this
   LAST in the <head>.

   SCOPE OF ROUNDING
   We round the things that read as "surfaces" (cards, media/photo frames,
   inputs, code, nav panels, accordions) and turn buttons into full capsules.
   We deliberately DO NOT round the editorial hairline devices the design is
   built from — page mastheads, coordinate/meta stamps, the .rule divider,
   the tier-card "table" rows, section seams. Those are lines, not boxes.

   CSP: style-src 'self' — everything here is a same-origin stylesheet, no
   inline styles, no script. The hover-transition needs no JS.
   ========================================================================== */

/* Radius scale — identical values to apple.css so the two premium sheets agree
   on what "rounded" means across home and the rest of the site. */
:root {
  --r-sm:   8px;
  --r-md:   12px;
  --r-lg:   18px;
  --r-xl:   24px;
  --r-2xl:  30px;
  /* --r-pill (999px) already exists in tokens.css */
}

/* ==========================================================================
   1. BUTTONS — full capsules everywhere (matches the home page).
   ========================================================================== */
.btn {
  border-radius: var(--r-pill);
}
/* The tiny status dot inside a button is already a circle; leave it. */

/* ==========================================================================
   2. CARDS & PANELS — soften the hairline boxes into material.
   ==========================================================================
   .card is "hairline only" in the base by design (components.css:2054); the
   brief is explicitly to round these to match the home look, so we override. */
.card {
  border-radius: var(--r-xl);
}
/* Media that bleeds to a card edge must round with the card so the corner is
   clean (the box already clips with overflow:hidden). Inset one step so the
   inner corner sits concentrically inside the card's own corner. */
.card__plate,
.card__plate .plate__box,
.card__plate img,
.card__media,
.card__media img {
  border-radius: calc(var(--r-xl) - var(--s-4));
  overflow: clip;
}

/* Desktop nav dropdown panel — a floating surface, round it like a menu. */
.nav-group__panel {
  border-radius: var(--r-md);
}

/* Accordions read as a stacked panel; round the group and clip the items so
   the open/close animation stays inside the corner. */
.accordion {
  border-radius: var(--r-lg);
  overflow: clip;
}

/* ==========================================================================
   3. PHOTO PLATES — round the frames (site-wide equivalent of apple.css §4c).
   ==========================================================================
   .plate__box already clips with overflow:hidden; rounding it rounds the
   image. Set the value on the image too as belt-and-braces against the 1px
   corner bleed some engines show when a filled child meets a rounded parent
   (most plate images are wrapped in <picture>, so `inherit` wouldn't reach
   them). */
.plate__box {
  border-radius: var(--r-lg);
}
.plate__img,
.plate__box > img {
  border-radius: var(--r-lg);
}

/* ==========================================================================
   4. FORM CONTROLS — round to match the capsules' family (was 2px).
   ========================================================================== */
.field__input,
input[type="text"],
input[type="email"],
input[type="url"],
input[type="tel"],
input[type="search"],
input[type="number"],
textarea,
select {
  border-radius: var(--r-md);
}

/* ==========================================================================
   5. CODE — inline code, kbd and code blocks (were 2px / sharp).
   ========================================================================== */
code,
kbd {
  border-radius: var(--r-sm);
}
pre {
  border-radius: var(--r-md);
}

/* ==========================================================================
   6. BOARD PEOPLE — the "Hover Transition" (advisory-board + review-board).
   ==========================================================================
   A card that swaps from a DEFAULT face (portrait + name + role + org) to a
   HOVER face (bio + profile link on an accent panel), like the referenced
   component. Each card carries a different motion via data-hover-effect; five
   ship: wipe | curtain | sweep | slide | fade.

   HOW IT'S BUILT (pure CSS, no markup restructure)
   The existing card is a flex column: portrait, name, role, org, bio, link.
   Above the phone breakpoint we make the card the positioning context and lift
   the bio + link out of flow as an absolutely-positioned accent panel that
   covers the whole card, hidden at rest and revealed on hover/focus. The
   portrait/name/role/org stay in normal flow as the front face, so the card
   keeps its natural height and its document order is unchanged (screen readers
   still read name→role→org→bio→link once, in order).

   ACCESSIBILITY / TOUCH
   The reveal is gated behind `@media (hover: hover) and (pointer: fine)` AND a
   min-width, so touch devices and phones NEVER hide anything — they get the
   full static card exactly as today (the ≤34rem sideways layout, which depends
   on five text children after the portrait, is on the other side of the gate
   and untouched). Keyboard users get the same reveal via :focus-within. The
   panel uses opacity/clip/transform, never display:none, so the bio stays in
   the a11y tree. Reduced-motion collapses everything to a plain fade. If this
   sheet never loads, the card is unchanged. */

/* Portrait rounds on every board, every viewport, to match the site. */
.person__portrait {
  border-radius: var(--r-lg);
}

@media (hover: hover) and (pointer: fine) and (min-width: 34.0625rem) {
  /* The card becomes the stage and clips the (square-cornered) accent panel to
     its own rounded box. box-shadow is drawn outside the box and is not
     affected by the clip, so the hover lift still reads. */
  .person[data-hover-effect] {
    position: relative;
    border-radius: var(--r-lg);
    overflow: clip;
    isolation: isolate;
    transition: box-shadow var(--dur) var(--ease),
                transform var(--dur) var(--ease);
  }
  .person[data-hover-effect]:hover,
  .person[data-hover-effect]:focus-within {
    box-shadow: var(--shadow-overlay);
    transform: translateY(-2px);
  }

  /* Back face = bio + link, lifted onto one accent panel covering the card.
     Both share --accent so they paint as a single surface; the link sits above
     the bio (higher z-index) and the bio reserves bottom padding so its last
     line never tucks under the link bar. Hidden at rest via opacity; each
     effect layers a clip/transform on top. */
  .person[data-hover-effect] .person__bio,
  .person[data-hover-effect] .person__link {
    position: absolute;
    inset-inline: 0;
    margin: 0;
    background: var(--accent);
    color: var(--accent-ink);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) var(--ease),
                transform var(--dur) var(--ease),
                clip-path var(--dur) var(--ease);
  }
  .person[data-hover-effect] .person__bio {
    inset-block: 0;
    z-index: 2;
    padding: var(--s-5) var(--s-5) var(--s-8);
    font-size: var(--fs-sm);
    line-height: var(--lh-body);
    color: var(--accent-ink);
    overflow: auto;
  }
  .person[data-hover-effect] .person__link {
    inset-block-end: 0;
    z-index: 3;
    padding: var(--s-4) var(--s-5) var(--s-5);
    color: var(--accent-ink);
    text-decoration: underline;
    text-underline-offset: 0.2em;
  }

  /* Reveal on hover/focus: fade in and settle to the neutral box. */
  .person[data-hover-effect]:hover .person__bio,
  .person[data-hover-effect]:hover .person__link,
  .person[data-hover-effect]:focus-within .person__bio,
  .person[data-hover-effect]:focus-within .person__link {
    opacity: 1;
    pointer-events: auto;
    transform: none;
    clip-path: inset(0);
  }

  /* ---- Per-card motion. Only the rest state differs; reveal is shared. ---- */

  /* WIPE — reveal left → right. */
  .person[data-hover-effect="wipe"] .person__bio,
  .person[data-hover-effect="wipe"] .person__link {
    clip-path: inset(0 100% 0 0);
  }

  /* CURTAIN — reveal top → down. */
  .person[data-hover-effect="curtain"] .person__bio,
  .person[data-hover-effect="curtain"] .person__link {
    clip-path: inset(0 0 100% 0);
  }

  /* SWEEP — reveal right → left. */
  .person[data-hover-effect="sweep"] .person__bio,
  .person[data-hover-effect="sweep"] .person__link {
    clip-path: inset(0 0 0 100%);
  }

  /* SLIDE — a gentle rise from below while it fades in. */
  .person[data-hover-effect="slide"] .person__bio,
  .person[data-hover-effect="slide"] .person__link {
    transform: translateY(16px);
  }

  /* FADE — opacity only; the shared rest state (opacity:0) is all it needs. */

  /* Reduced motion: no travel, no clip — just a fade, and no card lift. */
  @media (prefers-reduced-motion: reduce) {
    .person[data-hover-effect] .person__bio,
    .person[data-hover-effect] .person__link {
      transition: opacity var(--dur) var(--ease);
      transform: none !important;
      clip-path: none !important;
      opacity: 0;
    }
    .person[data-hover-effect]:hover .person__bio,
    .person[data-hover-effect]:hover .person__link,
    .person[data-hover-effect]:focus-within .person__bio,
    .person[data-hover-effect]:focus-within .person__link {
      opacity: 1;
    }
    .person[data-hover-effect]:hover,
    .person[data-hover-effect]:focus-within {
      transform: none;
    }
  }
}

/* ==========================================================================
   7. PREMIUM TOKENS — the depth vocabulary the home page (apple.css) has and
   the rest of the site did not. Additive; defined here because apple.css only
   loads on index.html. Shadows are Apple-faint and ink-hue tinted (265) so
   they read as warm depth on paper, never as grey smudges. Values match
   apple.css exactly so home and the rest of the site agree on "depth".
   ========================================================================== */
:root {
  --shadow-soft:
    0 1px 2px oklch(20% 0.03 265 / 0.04),
    0 2px 4px oklch(20% 0.03 265 / 0.04);
  --shadow-lift:
    0 2px 6px oklch(20% 0.03 265 / 0.05),
    0 6px 16px oklch(20% 0.03 265 / 0.06);

  --glass-bg:        color-mix(in oklab, var(--paper) 72%, transparent);
  --glass-bg-strong: color-mix(in oklab, var(--paper) 86%, transparent);
  --glass-blur:      blur(20px) saturate(180%);
  --glass-hairline:  color-mix(in oklab, var(--ink) 7%, transparent);

  /* Apple's decelerating curve for the small transforms this sheet adds (card
     lift). Defined here because it lives only in apple.css otherwise, and a
     transition referencing an undefined var() is invalid at computed-value
     time — which would silently drop the whole declaration. Matches apple.css. */
  --ease-apple: cubic-bezier(0.25, 0.1, 0.25, 1);
}

/* Dark mode needs more presence on a dark ground; the frost highlight brightens.
   Mirror tokens.css's two triggers exactly (media query + explicit attribute),
   the same pattern apple.css uses. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --shadow-soft: 0 1px 2px oklch(0% 0 0 / 0.28), 0 2px 4px oklch(0% 0 0 / 0.28);
    --shadow-lift: 0 2px 6px oklch(0% 0 0 / 0.34), 0 6px 16px oklch(0% 0 0 / 0.40);
    --glass-hairline: color-mix(in oklab, var(--ink) 14%, transparent);
  }
}
:root[data-theme="dark"] {
  --shadow-soft: 0 1px 2px oklch(0% 0 0 / 0.28), 0 2px 4px oklch(0% 0 0 / 0.28);
  --shadow-lift: 0 2px 6px oklch(0% 0 0 / 0.34), 0 6px 16px oklch(0% 0 0 / 0.40);
  --glass-hairline: color-mix(in oklab, var(--ink) 14%, transparent);
}

/* ==========================================================================
   8. HEADER — the frosted material the home page floats. The base already
   blurs (components.css:76, 14px/140%) and toggles [data-scrolled]; this
   deepens the frost to the home value and adds the on-scroll shadow-lift so
   the bar reads as a floating pane once you leave the top of the page.
   ==========================================================================
   The blur lives on ::before (a pseudo-element), NOT the header, because a
   backdrop-filter would trap the fixed mobile-nav overlay inside the header
   box — the base solved this and we must not undo it, so we only restyle the
   same ::before. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header::before {
    background: var(--glass-bg);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
  }
  .site-header[data-scrolled]::before {
    background: var(--glass-bg-strong);
  }
}
.site-header::before {
  box-shadow: inset 0 1px 0 var(--glass-hairline);
}
.site-header[data-scrolled] {
  box-shadow: var(--shadow-lift);
}
/* INVARIANT (guard, higher specificity than the glass rule above): with the
   mobile nav open the header must be fully opaque — a translucent strip above
   an opaque overlay reads as a rendering fault. The base asserts this in a
   layer; re-assert it unlayered so our glass override can never win over it. */
[data-nav-open] .site-header::before {
  background: var(--paper);
}

/* ==========================================================================
   9. CARDS — the hover shadow-lift. The base card hover is deliberately a
   drawing accent-rule + a 1px nudge and NO shadow (components.css:2156). This
   composes ON TOP: the rule still draws, and a soft shadow + a slightly deeper
   lift give the Apple "tile floats toward you" read. Speakers/workshops cards
   (which had only the hairline) now feel alive like the board cards do.
   ==========================================================================
   `translate` (not `transform`) is load-bearing: a card can also wear .reveal,
   whose entrance owns `transform`; the two compose. We redeclare the base
   transition and ADD box-shadow to it so hover-out eases too. Unlayered, so
   this wins over the base at equal specificity. */
.card {
  transition:
    border-color var(--dur) var(--ease),
    translate var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease-apple);
}
@media (hover: hover) and (pointer: fine) {
  .card:has(a:hover),
  .card--link:hover {
    translate: 0 -3px;
    box-shadow: var(--shadow-lift);
  }
}
/* Press settles back to the surface — matches the base's active state. */
.card:has(a:active),
.card--link:active {
  translate: 0 0;
  box-shadow: var(--shadow-soft);
}

/* ==========================================================================
   10. PHOTO FRAMES — a subtle resting shadow so real photographs sit as
   material, matching the rounded corners §3 already gave them. Scoped to
   PHOTO plates only: .partner__mark is a monochrome mask-image logo (ink on
   nothing), so a box-shadow there would draw a ghost rectangle — excluded.
   ========================================================================== */
.plate__box {
  box-shadow: var(--shadow-soft);
}

/* ==========================================================================
   11. FOOTER — email overflow guard (a real bug the content pages share with
   home). .site-footer__mailto is a flex row [icon · long mono address · JS
   Copy button] in a narrow column; the address + button is a hair wider than
   the track at tight widths and escapes past the viewport edge. Let the row
   wrap and let the address break as a last resort. Layout, not theme, but
   lives here to keep the base files recoverable. */
.site-footer__mailto {
  flex-wrap: wrap;
}
.site-footer__email {
  overflow-wrap: anywhere;
}

/* Desktop email alignment + icon removal. The contact column is only
   `11 / span 2` (~160–190px across desktop widths), narrower than the ~198px
   mono address, so the overflow guard above broke the address mid-word
   (…co / m) — the exact misalignment in the footer. Two fixes:
     • Drop the decorative (already aria-hidden) mail icon so the row is just
       the address — the icon also stole ~28px the narrow track couldn't spare.
     • Widen contact to 3 tracks (nav gives one back). This is the same span
       the base already uses just below 75rem, so nav still holds all four
       groups on one row, and the 3-track contact (~250–300px) fits the
       address on a single line with room to spare.
   Scoped 1px above the base's own 75rem footer breakpoint so tablet/mobile —
   where the column is already full/near-full width — are untouched. Layout,
   not theme, but lives here to keep the base files recoverable. */
.site-footer__mailto .icon {
  display: none;
}
@media (min-width: 75.0625rem) {
  .site-footer__nav     { grid-column: 4 / span 6; }
  .site-footer__contact { grid-column: 10 / span 3; }
}

/* ==========================================================================
   12. TYPOGRAPHY — line-breaking only. `balance` evens ragged headings across
   their lines; `pretty` prevents orphan last-words in prose. Both affect where
   lines BREAK, never the type scale, size, or the base's measured letter-
   spacing — so there is no layout shift and the Swiss type system is untouched.
   Unsupported browsers ignore both and get today's wrapping.
   ========================================================================== */
h1, h2, h3,
.section-head__title,
.masthead__title {
  text-wrap: balance;
}
p, li,
.card__body,
.lead {
  text-wrap: pretty;
}

/* ==========================================================================
   13. ACCESSIBILITY GUARDS for §8–§10.
   ========================================================================== */

/* Reduced motion: the shadow appearing is not motion (no travel), but the lift
   is — zero the translate so nothing moves; keep the depth cue. */
@media (prefers-reduced-motion: reduce) {
  .card { transition: box-shadow var(--dur) var(--ease); }
  .card:has(a:hover),
  .card--link:hover,
  .card:has(a:active),
  .card--link:active {
    translate: 0;
  }
}

/* Reduced transparency: swap the header glass for a solid pane and drop the
   backdrop-filter, mirroring the base/apple contract. The frost is decoration;
   the header must still read. */
@media (prefers-reduced-transparency: reduce) {
  .site-header::before { background: var(--paper); }
  .site-header[data-scrolled]::before { background: var(--paper); }
  @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .site-header::before {
      -webkit-backdrop-filter: none;
      backdrop-filter: none;
    }
  }
}
