/* =========================================================
   PUCAR — The Litigant's Journey
   Palette + aesthetic borrowed from pucar.org (warm, paper,
   editorial), storytelling scroll mechanic inspired by
   only8.org (fixed subject, scrolling world, stat beats).
   ========================================================= */

:root{
  /* colour: PUCAR brand — warm paper base + ink, dominant accent
     green #30CF8C (also the logo mark colour) with a dark-green
     ink used for deep/pinned backgrounds instead of navy, and a
     secondary pink accent #DA6EAA for highlights/labels.
     Old variable names (--navy, --terracotta, --gold) are kept as
     aliases pointing at the new brand colours so every existing
     rule that referenced them repaints correctly with no renames
     needed at each call site. */
  --cream:        #F6F1E6;
  --cream-deep:   #ECE2CE;
  --paper:        #FBF8F2;
  --ink:          #241E1A;
  --ink-soft:     #55493F;
  --muted:        #8A7E6E;

  --green:        #30CF8C; /* dominant accent — matches the logo mark */
  --green-soft:   #CCEBDE; /* pale tint of --green */
  --pink:         #DA6EAA; /* secondary accent */
  --pink-soft:    #F1D0E2; /* pale tint of --pink */
  --forest:       #111F26; /* dark teal-green background, sampled from user swatch */
  --forest-deep:  #0A151A; /* darkest shade of --forest */

  /* aliases: keep pre-existing rules working unchanged */
  --navy:         var(--forest);
  --navy-deep:    var(--forest-deep);
  --terracotta:   var(--green);
  --terracotta-soft: var(--green-soft);
  --gold:         var(--pink);

  --line:         rgba(36,30,26,0.12);

  --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --font-body: 'Source Sans 3', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --pin-pad: clamp(20px, 5vw, 72px);
}

*,*::before,*::after{ box-sizing:border-box; }

html{
  scroll-behavior:smooth;
}

body{
  margin:0;
  background:var(--cream);
  color:var(--ink);
  font-family:var(--font-body);
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

a{ color:inherit; }

h1,h2,h3{
  font-family:var(--font-display);
  margin:0;
  line-height:1.05;
  font-weight:500;
}

p{ margin:0; }

sup{ font-size:.55em; opacity:.6; font-style:italic; }

/* ---------------- header ---------------- */
.site-header{
  /* ABSOLUTE, not fixed: the logo lives in the header flow and scrolls away
     with the page (explicit request -- "the logo doesn't need to be
     sticky"). The nav + CTA are pulled out and pinned separately below. */
  position:absolute;
  top:0; left:0; right:0;
  z-index:50;
  display:flex;
  align-items:center;
  justify-content:space-between;
  padding: 18px clamp(20px,4vw,48px);
  pointer-events:none;
}
/* ---- ecosystem switcher: caret beside the logo opens a dark panel
   linking to the sibling Agami missions (modelled on opennyai.org's).
   Pure CSS hover/focus-within; hidden on phones. ---- */
.brand-switch{
  position:relative;
  pointer-events:auto;
  align-self:center;
  /* hug the logo on the left, push the nav cluster back to the right */
  margin:0 auto 0 8px;
}
.brand-switch-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:28px;
  height:28px;
  border:0;
  border-radius:50%;
  background:transparent;
  color:var(--ink-soft);
  cursor:pointer;
  transition:background .2s ease, color .2s ease;
}
.brand-switch-btn svg{ transition:transform .25s ease; }
.brand-switch:hover .brand-switch-btn,
.brand-switch:focus-within .brand-switch-btn{ background:rgba(36,30,26,.08); }
.brand-switch:hover .brand-switch-btn svg,
.brand-switch:focus-within .brand-switch-btn svg{ transform:rotate(180deg); }
/* dark-half flip, same conditions as the logo/nav */
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .brand-switch-btn{
  color:rgba(251,248,242,.85);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .brand-switch:hover .brand-switch-btn{
  background:rgba(251,248,242,.14);
}
/* invisible bridge so the pointer can travel from caret to panel */
.brand-switch::after{
  content:"";
  position:absolute;
  top:100%;
  left:0;
  width:100%;
  height:12px;
}
.brand-menu{
  position:absolute;
  top:calc(100% + 10px);
  left:-8px;
  min-width:282px;
  padding:14px 20px 10px;
  background:var(--forest); /* dark panel: the sibling logos are white/colour-on-dark */
  border:1px solid rgba(251,248,242,.14);
  border-radius:16px;
  box-shadow:0 24px 60px rgba(17,31,38,.4);
  opacity:0;
  translate:0 8px;
  /* GRACE PERIOD on close: the panel lingers ~0.55s after the pointer
     leaves (visibility waits even longer), so drifting off the caret and
     back doesn't force a re-engage. Hit-testing stays on while visible,
     so re-entering the panel during the grace cancels the close. */
  visibility:hidden;
  transition:opacity .25s ease .55s, translate .25s ease .55s, visibility 0s linear .8s;
  z-index:60;
}
.brand-switch:hover .brand-menu,
.brand-switch:focus-within .brand-menu{
  opacity:1;
  translate:0 0;
  visibility:visible;
  transition:opacity .22s ease, translate .22s ease, visibility 0s;
}
.brand-menu-label{
  margin:0 0 4px;
  font-size:.62rem;
  font-weight:800;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--green);
}
.brand-menu-item{
  display:block;
  padding:13px 2px;
}
.brand-menu-item + .brand-menu-item{ border-top:1px solid rgba(251,248,242,.12); }
.brand-menu-item img{
  display:block;
  height:24px;
  width:auto;
  opacity:.88;
  transition:opacity .2s ease, transform .2s ease;
}
.brand-menu-item:hover img,
.brand-menu-item:focus-visible img{ opacity:1; transform:translateX(2px); }
/* two-line blurb slides open under the hovered logo */
.brand-menu-desc{
  display:block;
  /* fills the panel width; no ch cap (it left a dead right gutter) */
  font-size:.78rem;
  line-height:1.45;
  color:rgba(251,248,242,.65);
  max-height:0;
  opacity:0;
  overflow:hidden;
  margin-top:0;
  /* EXIT: text fades first, then the space closes smoothly under it */
  transition:max-height .32s cubic-bezier(.4,.1,.2,1) .05s, opacity .16s ease, margin-top .32s cubic-bezier(.4,.1,.2,1) .05s;
}
.brand-menu-item:hover .brand-menu-desc,
.brand-menu-item:focus-visible .brand-menu-desc{
  max-height:6.5em; /* room for three full lines, nothing clipped */
  opacity:1;
  margin-top:9px;
  /* ENTER: space opens first, text fades in as it lands */
  transition:max-height .3s cubic-bezier(.4,.1,.2,1), opacity .24s ease .1s, margin-top .3s cubic-bezier(.4,.1,.2,1);
}
@media (max-width: 640px){
  .brand-switch{ display:none; } /* not needed on phones (explicit) */
}

/* nav + CTA stay pinned: homepage wraps them in .header-right; generated
   pages carry a .nav-cluster (main nav + optional page sub-nav) */
.header-right,
body.job-page .site-header > .nav-cluster{
  position:fixed;
  top:18px;
  right:clamp(20px,4vw,48px);
  z-index:50;
  /* slides up with body.film-playing (the header itself no longer needs
     to, the logo has scrolled away by the film) */
  transition: translate .55s cubic-bezier(.4,.1,.3,1);
}
.nav-cluster{
  pointer-events:auto;
  display:flex;
  gap:10px;
  align-items:flex-start;
}
/* never wrap during the width FLIP: mid-animation widths would otherwise
   fold the menu names onto a second line and balloon the pill's height */
.nav-cluster .site-nav{
  flex-wrap:nowrap;
  white-space:nowrap;
}
/* collapse/expand: a collapsed nav shows ONLY its burger toggle; an
   expanded nav hides its toggle (you collapse it by expanding the other) */
.nav-toggle{
  display:none;
  align-items:center;
  gap:8px;
  padding:8px 15px;
  border:0;
  border-radius:999px;
  background:transparent;
  color:var(--ink-soft);
  font:600 .9rem var(--font-body);
  letter-spacing:.01em;
  cursor:pointer;
  white-space:nowrap;
}
.site-nav.is-collapsed > *:not(.nav-toggle){ display:none !important; }
.site-nav.is-collapsed > .nav-toggle{ display:inline-flex; }
/* items stay INVISIBLE until the width FLIP has finished, then fade in --
   no text painting mid-animation (delay ~= the 160ms FLIP duration).
   NOT the glider: it's a direct child too, and this animation's backwards
   fill (opacity:0) OVERRIDES the glider's inline opacity whenever the
   animation restarts -- that was the "hover pill disappears, lit text
   unreadable" bug on sub-nav clicks. Its opacity is JS-driven only. */
.site-nav.just-in > *:not(.nav-toggle):not(.nav-glider){
  /* SCOPED to .just-in, a one-shot class swapNavs() sets on the expanding
     nav and removes 500ms later. It used to hang off :not(.is-collapsed),
     which let the browser RESTART the animation outside any swap (observed
     twice: gliders erased, then clicked links frozen ghost-faint at the
     opacity:0 start frame) -- with backwards fill, any restart makes
     children invisible. Now it can only run during a real expand. */
  animation:navItemsIn .14s ease .16s backwards;
}
@keyframes navItemsIn{
  from{ opacity:0; }
  to{ opacity:1; }
}
/* while the pills are mid-FLIP no hover state can fire: js/nav.js sets
   is-swapping for the animation's duration, which freezes pointer-events
   (so :hover/gliders can't land on links that aren't in position yet) */
.nav-cluster.is-swapping .site-nav{ pointer-events:none; }
.nav-cluster.is-swapping .nav-glider{ opacity:0 !important; }
/* sub-nav up-arrow loops on hover, same as the homepage's */
.subnav-top:hover svg,
.subnav-top:focus-visible svg{
  animation:navArrowUp 1s ease-in-out infinite;
}
/* sub-nav: same pill, slightly different underlying tint */
.site-nav.sub-nav{
  background:rgba(210,236,220,.6);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav.sub-nav{
  background:rgba(23,48,40,.62);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .nav-toggle{
  color:rgba(251,248,242,.88);
}

body.film-playing .header-right{
  translate:0 -120%;
  pointer-events:none;
}
body.film-playing .progress-rail{
  /* an ABSOLUTE distance, not a %: the rail is only ~20px tall, so the
     old 200% moved it ~40px -- not even past its own bottom:28px offset,
     which left it peeking over the film. 90px clears offset + height with
     room to spare, and the fade covers any transition frame. */
  translate:0 90px;
  opacity:0;
}

.site-header .logo{
  pointer-events:auto;
  position:relative;
  display:inline-flex;
  align-items:center;
  text-decoration:none;
}
.site-header .logo img{
  display:block;
  height:28px; /* nudged down from 34px -- read as too large in the header (footer logo, 22px, is untouched) */
  width:auto;
}
/* two variants stacked in place; only one is visible at a time depending on
   what's behind the fixed header (see the :has() rules below). Pages without
   the scrollytelling story (job/contributor pages) never match those rules,
   so they simply show the light-background mark, which is correct there
   since those pages are cream throughout. */
.site-header .logo-light,
.site-header .logo-dark{
  transition: opacity .6s ease; /* matches .pin's own background-color transition timing */
}
.site-header .logo-dark{
  position:absolute;
  left:0; top:50%;
  transform:translateY(-50%);
  opacity:0;
}
body:has(.pin[data-beat="4"]) .site-header .logo-light,
body:has(.pin[data-beat="5"]) .site-header .logo-light,
body:has(.pin[data-beat="6"]) .site-header .logo-light,
body:has(.pin[data-beat="7"]) .site-header .logo-light,
body:has(.pin[data-beat="8"]) .site-header .logo-light,
body:has(.pin[data-beat="9"]) .site-header .logo-light{ opacity:0; }
body:has(.pin[data-beat="4"]) .site-header .logo-dark,
body:has(.pin[data-beat="5"]) .site-header .logo-dark,
body:has(.pin[data-beat="6"]) .site-header .logo-dark,
body:has(.pin[data-beat="7"]) .site-header .logo-dark,
body:has(.pin[data-beat="8"]) .site-header .logo-dark,
body:has(.pin[data-beat="9"]) .site-header .logo-dark{ opacity:1; }
/* both the light and dark marks come in two lengths: full wordmark (+
   tagline) on desktop, PUCAR-only below 640px (same breakpoint .site-nav
   collapses at). Which length shows is independent of the opacity toggle
   above, which only decides whether the light *or* dark colourway shows. */
.site-header .logo img.logo-light-short,
.site-header .logo img.logo-dark-short{ display:none; } /* needs the `img` to out-specify ".logo img{display:block}" above */
.site-nav{
  pointer-events:auto;
  display:flex;
  gap:2px;
  /* frosted glass: a light wash + heavy blur/saturate reads well over both
     the cream hero and the dark story half; the inset highlight gives the
     top edge a glass "catch" */
  background:rgba(251,248,242,.52);
  backdrop-filter:blur(16px) saturate(1.6);
  -webkit-backdrop-filter:blur(16px) saturate(1.6);
  border:1px solid rgba(26,26,26,.07);
  border-radius:999px;
  padding:5px;
  box-shadow:
    0 12px 32px rgba(17,31,38,.10),
    inset 0 1px 0 rgba(255,255,255,.55);
  transition:background .45s ease, border-color .45s ease, box-shadow .45s ease;
}
.site-nav a{
  text-decoration:none;
  font-size:.9rem; /* matches .btn / the Get in touch CTA next to it */
  font-weight:600;
  letter-spacing:.01em;
  color:var(--ink-soft);
  padding:8px 15px;
  border-radius:999px;
  transition:background .22s ease, color .22s ease, box-shadow .22s ease;
}
.site-nav a:hover{
  background:var(--forest);
  color:var(--paper);
  box-shadow:0 4px 12px rgba(17,31,38,.25);
}

/* NOTE the a.nav-home specificity: the generic `.site-nav a` rule declares
   its own transition (background/color/box-shadow) which would otherwise
   override this one and make the reveal instant. */
.site-nav a.nav-home{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:0;
  padding:8px 0 !important; /* keep the pill height, no horizontal footprint while hidden */
  opacity:0;
  transform:scale(.5);
  overflow:hidden;
  /* slow, springy reveal: the slot opens first, then the icon fades/pops in.
     On hide everything runs together (no delay) so it melts away. */
  transition:width .45s cubic-bezier(.4,.1,.2,1), padding .45s cubic-bezier(.4,.1,.2,1),
    opacity .3s ease, transform .45s cubic-bezier(.34,1.4,.44,1),
    background .22s ease, color .22s ease;
}
.site-nav.show-home a.nav-home{
  width:38px;
  padding:8px 8px !important;
  opacity:1;
  transform:scale(1);
  transition-delay:0s, 0s, .12s, .12s, 0s, 0s; /* icon arrives after the slot opens */
}

/* tooltip under the icon (content from data-tip: "Back to Top" on the
   homepage arrow, "Home" on other pages' house). The button's
   overflow:hidden is lifted once revealed so the tooltip can escape. */
.site-nav.show-home a.nav-home{ overflow:visible; position:relative; }
.nav-home::after{
  content:attr(data-tip);
  position:absolute;
  top:calc(100% + 14px);
  left:50%;
  translate:-50% 4px;
  background:var(--forest);
  color:var(--paper);
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.03em;
  white-space:nowrap;
  padding:6px 12px;
  border-radius:9px;
  box-shadow:0 10px 24px rgba(17,31,38,.28);
  opacity:0;
  pointer-events:none;
  transition:opacity .18s ease, translate .18s ease;
  z-index:70;
}
.nav-home::before{ /* caret */
  content:"";
  position:absolute;
  top:calc(100% + 3px);
  left:50%;
  translate:-50% 4px;
  border:6px solid transparent;
  border-bottom-color:var(--forest);
  opacity:0;
  pointer-events:none;
  transition:opacity .18s ease, translate .18s ease;
  z-index:70;
}
.site-nav.show-home a.nav-home:hover::after,
.site-nav.show-home a.nav-home:focus-visible::after,
.site-nav.show-home a.nav-home:hover::before,
.site-nav.show-home a.nav-home:focus-visible::before{
  opacity:1;
  translate:-50% 0;
}

/* the homepage up-arrow drifts upward on loop: rises, fades out at the top,
   re-enters from below (#navHome is homepage-only; other pages' house icon
   stays still) */
/* loop only on hover/focus -- always-on was distracting */
#navHome:hover svg,
#navHome:focus-visible svg{
  animation:navArrowUp 1s ease-in-out infinite;
}
@keyframes navArrowUp{
  0%  { transform:translateY(5px);  opacity:0; }
  30% { transform:translateY(1px);  opacity:1; }
  70% { transform:translateY(-2px); opacity:1; }
  100%{ transform:translateY(-6px); opacity:0; }
}
@media (prefers-reduced-motion: reduce){
  #navHome svg{ animation:none; }
}

/* ---- glider: a pill that slides between links on hover (homepage only,
   js/script.js injects it and adds .has-glider). The plain :hover above
   stays as the fallback for generated pages, which don't load script.js. */
.site-nav{ position:relative; }
/* top-level pills only -- .nav-menu-item hovers keep their own bg */
.site-nav.has-glider > a:hover,
.site-nav.has-glider > .nav-drop > a:hover{ background:transparent; box-shadow:none; }
.site-nav.has-glider > a,
.site-nav.has-glider > .nav-drop > a{ position:relative; z-index:1; }
.site-nav.has-glider .nav-drop{ position:static; }
.site-nav.has-glider .nav-drop .nav-menu{ z-index:2; }
.nav-glider{
  position:absolute;
  z-index:0;
  border-radius:999px;
  background:var(--forest);
  box-shadow:0 4px 12px rgba(17,31,38,.25);
  opacity:0;
  transition:left .28s cubic-bezier(.5,.1,.2,1), width .28s cubic-bezier(.5,.1,.2,1),
    top .28s ease, height .28s ease, opacity .2s ease;
  pointer-events:none;
}
.site-nav a.is-lit{ color:var(--paper); }

/* ---- dark-half nav: over the story's dark beats the cream glass pill and
   ink text lose contrast, so flip: dark glass, light text, brand-green
   glider with dark text (same family as the header CTA's dark-half flip) */
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav{
  background:rgba(10,21,26,.55);
  border-color:rgba(251,248,242,.16);
  box-shadow:0 12px 32px rgba(0,0,0,.35), inset 0 1px 0 rgba(251,248,242,.12);
}
/* generated pages: js/nav.js toggles body.nav-dark when the header floats
   over a dark section, mirroring the homepage's beat-driven flip -- the
   :is(...) selector lists in this block serve both. Logo flips along. */
body.nav-dark .site-header .logo-light{ opacity:0; }
body.nav-dark .site-header .logo-dark{ opacity:1; }

/* top-level pills only: the dropdown panel stays paper with ink text, so its
   items must NOT inherit the light-on-dark colours */
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav > a,
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav > .nav-drop > a{
  color:rgba(251,248,242,.88);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav > a:hover,
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav > .nav-drop > a:hover{
  background:var(--green);
  color:var(--forest);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav.has-glider > a:hover,
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav.has-glider > .nav-drop > a:hover{
  background:transparent;
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .nav-glider{
  background:var(--green);
  box-shadow:0 4px 12px rgba(0,0,0,.35);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav > a.is-lit,
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav > .nav-drop > a.is-lit{
  color:var(--forest);
}
/* the dropdown panel follows the same flip: dark panel, light text,
   green glider/hover with dark text */
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .nav-menu{
  background:#0E1B21; /* a step above --forest-deep so it reads as a panel */
  border-color:rgba(251,248,242,.14);
  box-shadow:0 22px 50px rgba(0,0,0,.5);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .nav-menu-label{
  color:rgba(251,248,242,.6);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav .nav-menu-item{
  color:var(--paper);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav .nav-menu-item:hover{
  background:var(--green);
  color:var(--forest);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav .nav-menu.has-glider .nav-menu-item:hover{
  background:transparent;
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .nav-menu .menu-glider{
  background:var(--green);
}
:is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .site-nav .nav-menu .nav-menu-item.is-lit{
  color:var(--forest);
}

/* ---------------- Collaborate nav dropdown ---------------- */
.nav-drop{ position:relative; display:inline-flex; }
.nav-drop-trigger{
  display:inline-flex;
  align-items:center;
  gap:6px;
}
.nav-caret{
  flex:none;
  opacity:.6;
  transition:transform .18s ease, opacity .18s ease;
}
.nav-drop:hover .nav-caret,
.nav-drop:focus-within .nav-caret{
  transform:rotate(180deg);
  opacity:1;
}
.nav-menu{
  position:absolute;
  top:100%;
  right:0;
  padding:14px 6px 8px;
  margin-top:8px;
  min-width:300px;
  background:var(--paper);
  border:1px solid rgba(26,26,26,.08);
  border-radius:16px;
  box-shadow:0 22px 50px rgba(17,31,38,.22);
  opacity:0;
  visibility:hidden;
  translate:0 6px;
  transition:opacity .18s ease, translate .18s ease, visibility .18s,
    background .45s ease, border-color .45s ease, box-shadow .45s ease;
  z-index:60;
}
/* bridge the 8px gap so the menu doesn't close mid-travel */
.nav-menu::before{
  content:"";
  position:absolute;
  top:-10px; left:0; right:0; height:10px;
}
.nav-drop:hover .nav-menu,
.nav-drop:focus-within .nav-menu{
  opacity:1;
  visibility:visible;
  translate:0 0;
}
.nav-menu-label{
  margin:6px 0 2px;
  padding:0 14px;
  font-size:.66rem;
  font-weight:600;
  text-transform:uppercase;
  letter-spacing:.12em;
  color:var(--ink-soft);
  opacity:.7;
}
.nav-menu-label + .nav-menu-label,
.nav-menu-item + .nav-menu-label{ margin-top:14px; }
.site-nav .nav-menu-item{
  display:flex;
  flex-direction:column;
  gap:1px;
  padding:9px 14px;
  border-radius:10px;
  color:var(--ink);
  font-size:.88rem;
}
.site-nav .nav-menu-item:hover{ background:var(--forest); color:var(--paper); }
.nav-menu-title{ font-weight:600; line-height:1.3; }
/* glider inside the dropdown: same sliding-pill trick as the main bar
   (js/script.js adds .has-glider and the .menu-glider element) */
.nav-menu .menu-glider{
  position:absolute;
  z-index:0;
  border-radius:10px;
  background:var(--forest);
  opacity:0;
  pointer-events:none;
  transition:top .24s cubic-bezier(.5,.1,.2,1), height .24s cubic-bezier(.5,.1,.2,1),
    left .24s ease, width .24s ease, opacity .18s ease;
}
.nav-menu.has-glider .nav-menu-item{ position:relative; z-index:1; }
/* box-shadow too: .site-nav a:hover's shadow would otherwise pop in on the
   hovered item before the glider pill has slid over to it */
.nav-menu.has-glider .nav-menu-item:hover{ background:transparent; box-shadow:none; }
.nav-menu .nav-menu-item.is-lit{ color:var(--paper); }
.nav-menu-sub{
  font-size:.76rem;
  line-height:1.35;
  opacity:.65;
}

/* nav + the Get in touch CTA sit together on the right */
.header-right{
  pointer-events:auto;
  display:flex;
  align-items:center;
  gap:12px;
}
.header-cta{
  border:none;
  cursor:pointer;
  font-family:var(--font-body);
  background:var(--forest);
  color:var(--paper);
  padding:12px 22px;
  transition: background .2s ease, translate .2s ease, box-shadow .2s ease;
}
.header-cta:hover{
  background:#1C3540; /* lighter forest -- same hover family as .btn-primary on light */
  translate:0 -1px;
  box-shadow:0 6px 16px rgba(17,31,38,.3);
}
/* on the story's dark half the forest button would sink into the forest
   background -- flip to the bright brand green (dark-bg only, per the
   palette rule), same mechanism as the logo swap */
body:has(.pin[data-beat="4"]) .header-cta,
body:has(.pin[data-beat="5"]) .header-cta,
body:has(.pin[data-beat="6"]) .header-cta,
body:has(.pin[data-beat="7"]) .header-cta,
body:has(.pin[data-beat="8"]) .header-cta,
body:has(.pin[data-beat="9"]) .header-cta,
body.nav-dark .header-cta{
  background:var(--green);
  color:var(--ink);
}
body:has(.pin[data-beat="4"]) .header-cta:hover,
body:has(.pin[data-beat="5"]) .header-cta:hover,
body:has(.pin[data-beat="6"]) .header-cta:hover,
body:has(.pin[data-beat="7"]) .header-cta:hover,
body:has(.pin[data-beat="8"]) .header-cta:hover,
body:has(.pin[data-beat="9"]) .header-cta:hover{
  background:#51D79E; /* lighter brand green, matching .btn-primary's dark-bg hover */
  box-shadow:0 6px 16px rgba(0,0,0,.3);
}

/* ---------------- contact modal + Netlify form ---------------- */
.contact-panel{ max-width:560px; }
.contact-intro{
  margin:6px 0 6px;
  font-size:.98rem;
  line-height:1.6;
  color:var(--ink-soft);
  max-width:46ch;
}
.contact-form{ margin-top:10px; }
.contact-form label{
  display:flex;
  flex-direction:column;
  gap:7px;
  margin-bottom:16px;
  font-size:.85rem;
  font-weight:600;
  color:var(--ink-soft);
}
.contact-form input,
.contact-form textarea{
  font:400 1rem var(--font-body);
  color:var(--ink);
  background:#fff;
  border:1px solid var(--line);
  border-radius:12px;
  padding:12px 14px;
  resize:vertical;
}
.contact-form input:focus,
.contact-form textarea:focus{
  outline:2px solid var(--forest);
  outline-offset:1px;
  border-color:var(--forest);
}
/* themed inline validation (replaces the browser's native bubbles) */
.contact-form .is-invalid{
  border-color:#B0402F;
}
.contact-form .is-invalid:focus{
  outline-color:#B0402F;
  border-color:#B0402F;
}
.field-error{
  font-size:.8rem;
  font-weight:500;
  font-style:italic;
  color:#B0402F;
  min-height:0;
}
.field-error:empty{ display:none; }
.contact-form .cta-row{ margin-top:6px; }
.contact-form .btn{ border:none; cursor:pointer; font-family:var(--font-body); }
.contact-error{
  font-size:.88rem;
  color:#B0402F;
  margin-bottom:8px;
}
.contact-success{
  margin-top:18px;
  font-size:1.08rem;
  line-height:1.6;
  color:var(--forest);
  font-weight:600;
}

/* ---------------- mobile nav (≤640px) ----------------
   The pills never fit a phone (expanded menus ran over the logo), so:
   the wordmark collapses to the standalone "P" mark, the nav pills hide,
   js/mobile-nav.js drops in a "Main Menu" burger pill, and tapping it
   opens a full-screen tinted overlay with a vertical list that keeps the
   dropdowns' hierarchy. */
.site-header .logo img.logo-p{ display:none; }
.mobile-nav-btn{ display:none; }
@media (max-width: 640px){
  .site-nav{ display:none !important; }
  /* Get in touch lives INSIDE the menu overlay on phones (.mnav-cta);
     no room for it beside the burger */
  .header-cta{ display:none !important; }
  .site-header .logo img{ display:none; }
  /* the green P works on the cream hero AND the dark half: no light/dark
     swap needed, unlike the wordmarks */
  .site-header .logo img.logo-p{
    display:block;
    height:36px;
    width:auto;
  }
  .mobile-nav-btn{
    display:inline-flex;
    align-items:center;
    gap:8px;
    padding:11px 18px;
    border:1px solid rgba(26,26,26,.07);
    border-radius:999px;
    /* same frosted glass as the desktop nav pill */
    background:rgba(251,248,242,.52);
    backdrop-filter:blur(16px) saturate(1.6);
    -webkit-backdrop-filter:blur(16px) saturate(1.6);
    box-shadow:0 12px 32px rgba(17,31,38,.10), inset 0 1px 0 rgba(255,255,255,.55);
    color:var(--ink-soft);
    font:600 .88rem var(--font-body);
    cursor:pointer;
  }
  :is(body:has(.pin:is([data-beat="4"],[data-beat="5"],[data-beat="6"],[data-beat="7"],[data-beat="8"],[data-beat="9"])), body.nav-dark) .mobile-nav-btn{
    background:rgba(13,26,32,.55);
    border-color:rgba(251,248,242,.12);
    color:rgba(251,248,242,.88);
    box-shadow:0 12px 32px rgba(0,0,0,.28), inset 0 1px 0 rgba(255,255,255,.08);
  }
}
/* the overlay itself (rendered on every viewport, opened only on mobile
   since its trigger is display:none elsewhere) */
.mobile-nav-overlay{
  position:fixed;
  inset:0;
  z-index:90;
  overflow-y:auto;
  padding:74px 26px 44px;
  background:rgba(13,26,32,.93); /* the tint */
  backdrop-filter:blur(16px) saturate(1.4);
  -webkit-backdrop-filter:blur(16px) saturate(1.4);
  color:var(--paper);
}
.mobile-nav-overlay[hidden]{ display:none; }
.mnav-close{
  position:absolute;
  top:18px;
  right:18px;
  width:42px;
  height:42px;
  border:1px solid rgba(251,248,242,.25);
  border-radius:50%;
  background:transparent;
  color:var(--paper);
  font-size:22px;
  line-height:1;
  cursor:pointer;
}
.mnav-list{ display:flex; flex-direction:column; max-width:420px; margin:0 auto; }
.mnav-heading{
  margin:26px 0 4px;
  font-size:.72rem;
  font-weight:800;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--green);
}
.mnav-heading:first-child{ margin-top:0; }
.mnav-group-label{
  margin:16px 0 2px;
  font-size:.68rem;
  font-weight:700;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:rgba(251,248,242,.45);
}
.mnav-link{
  display:block;
  padding:12px 2px;
  border-bottom:1px solid rgba(251,248,242,.08);
  color:var(--paper);
  text-decoration:none;
  font-size:1.06rem;
  font-weight:600;
}
.mnav-link:active{ color:var(--green); }
.mnav-sub{
  display:block;
  margin-top:2px;
  font-size:.78rem;
  font-weight:400;
  color:rgba(251,248,242,.55);
}
.mnav-cta{ margin-top:30px; justify-content:center; }

/* ---------------- intro hero (before the scrolly story) ----------------
   A plain, static (non-sticky, non-scroll-driven) full-height section that
   introduces PUCAR the organisation, separate from the litigant's
   narrative that begins at beat 0 of .story below. .site-header is
   position:fixed with a transparent background, so it overlays this
   section the same way it already overlays .pin -- no extra top padding
   needed here beyond what already clears the logo comfortably. */
.intro-hero{
  min-height:100vh;
  display:flex;
  align-items:center;
  justify-content:center;
  background:var(--cream);
  padding: clamp(96px,14vh,140px) clamp(20px,5vw,72px) clamp(48px,8vh,96px);
}
/* two columns: copy LEFT-ALIGNED on the left, bulletin board on the right
   (explicit instruction; used to be a single centred column) */
.intro-hero-inner{
  width:100%;
  max-width:1180px;
  display:grid;
  grid-template-columns: 1.05fr .95fr;
  gap: clamp(40px, 6vw, 96px);
  align-items:center;
  text-align:left;
}
.intro-eyebrow{
  display:block;
  font-size:.78rem;
  font-weight:600;
  text-transform:uppercase;
  letter-spacing:.16em;
  color:var(--forest); /* dark-green -- this section is a light bg, see design-system rule in README */
  margin-bottom:18px;
}
.intro-tagline{
  font-family:var(--font-display);
  font-weight:500;
  font-size:clamp(1.9rem, 4.2vw, 3.1rem);
  line-height:1.18;
  margin:0 0 22px;
}
.intro-hook{
  font-size:clamp(1.05rem, 1.6vw, 1.28rem);
  line-height:1.5;
  color:var(--ink-soft);
  max-width:56ch;
  margin:0 0 14px;
}
.intro-skip{
  font-size:.92rem;
  line-height:1.5;
  color:var(--ink-soft); /* --muted only hits 3.5:1 on --cream, fails AA at this size; --ink-soft is 7.7:1 */
  font-style:italic;
  margin:0 0 32px;
}
/* .intro-hero prefix bumps specificity above the plain .cta-row rule
   (defined later in this file) so margin-top:0 actually wins -- .intro-skip
   above already carries its own bottom margin, so .cta-row's usual 28px
   would just double up the gap before the buttons. */
.intro-hero .intro-actions{
  justify-content:flex-start;
  margin-top:0;
}

/* ---------------- bulletin board (hero, right column) ----------------
   Reads like a notice board: a dark forest panel, slightly tilted paper
   notes pinned to it (pin = ::before dot), each note a link into the
   currently active work. Notes straighten and lift on hover. */
.intro-board{
  position:relative;
  display:flex;
  flex-direction:column;
  gap:18px;
  background:var(--forest);
  border-radius:22px;
  padding:clamp(22px, 2.8vw, 36px);
  box-shadow:0 26px 60px rgba(17,31,38,.3);
  rotate:.5deg;
}
.board-eyebrow{
  display:flex;
  align-items:center;
  gap:9px;
  margin:0 0 2px;
  font-size:.78rem;
  font-weight:600;
  text-transform:uppercase;
  letter-spacing:.14em;
  color:var(--paper);
}
.board-live{
  width:9px; height:9px;
  border-radius:50%;
  background:var(--green);
  animation: boardPulse 2s ease-in-out infinite;
}
@keyframes boardPulse{
  0%,100%{ box-shadow:0 0 0 0 rgba(48,207,140,.55); }
  55%    { box-shadow:0 0 0 7px rgba(48,207,140,0); }
}
.board-note{
  position:relative;
  display:flex;
  gap:14px;
  align-items:flex-start;
  background:var(--paper);
  color:var(--ink);
  text-decoration:none;
  padding:20px 18px 16px;
  /* uneven corners: pinned paper, not a UI card */
  border-radius:4px 12px 6px 10px;
  box-shadow:0 10px 22px rgba(0,0,0,.28);
  rotate:-1.3deg;
  /* the notes rock gently in the wind, pivoting around the pin (which
     sits at top-centre, y≈-7px) -- hence the raised transform-origin.
     Amplitude is deliberately tiny (±.7deg around each base tilt) so the
     hover handoff below can't visibly snap. */
  transform-origin:50% -6px;
  animation: boardRockA 3.8s ease-in-out infinite;
  transition: rotate .25s ease, translate .25s ease, box-shadow .25s ease;
}
.board-note + .board-note{
  rotate:1.1deg;
  animation: boardRockB 4.6s ease-in-out infinite .7s;
}
@keyframes boardRockA{
  0%,100%{ rotate:-1.9deg; }
  50%    { rotate:-.6deg;  }
}
@keyframes boardRockB{
  0%,100%{ rotate:.4deg;  }
  50%    { rotate:1.7deg; }
}
.board-note::before{         /* the pin */
  content:"";
  position:absolute;
  top:-7px;
  left:50%;
  translate:-50%;
  width:15px; height:15px;
  border-radius:50%;
  background:radial-gradient(circle at 35% 30%, #F1A6CB, var(--pink) 55%, #8E3A6B);
  box-shadow:0 3px 4px rgba(0,0,0,.35);
}
.board-note:hover{
  animation:none;      /* stop rocking: straight and still, as before */
  rotate:0deg;
  translate:0 -4px;
  box-shadow:0 16px 30px rgba(0,0,0,.32);
}
.board-num{
  font-family:var(--font-display);
  font-size:1.15rem;
  color:var(--forest);
  line-height:1.2;
}
.board-note-title{
  display:block;
  font-weight:600;
  font-size:1.04rem;
  line-height:1.3;
  margin-bottom:5px;
}
.board-note-sub{
  display:block;
  font-size:.83rem;
  line-height:1.45;
  color:var(--ink-soft);
}
/* .btn-primary defaults to styling meant for a dark background (see the
   design-system section of README) -- this section is light, so it's
   folded into the same light-bg override as .job-page/.job-modal-panel
   below (search "job-page .btn-primary" in this file). .btn-ghost has no
   such shared override yet, so it gets its own light-bg variant here. */
.intro-hero .btn-ghost{ border:1px solid rgba(36,30,26,.32); color:var(--ink); }
.intro-hero .btn-ghost:hover{ background:rgba(36,30,26,.06); }

/* buttons that carry a little icon (beacon / arrow) */
.btn-with-icon{ gap:9px; }
/* "Tell me more" arrow: loops downward -- appears at the top, slides down,
   fades out, restarts -- a running "you can scroll" hint */
.btn-arrow{
  display:inline-block;
  animation: arrowLoop 1.6s ease-in-out infinite;
}
@keyframes arrowLoop{
  0%  { translate:0 -5px; opacity:0; }
  30% { translate:0 0;    opacity:1; }
  70% { translate:0 2px;  opacity:1; }
  100%{ translate:0 7px;  opacity:0; }
}
/* the green beacon is shared with the bulletin board's .board-live */

/* mobile/tablet: the board stacks BELOW the copy, full width, tilts eased */
@media (max-width: 900px){
  .intro-hero{ min-height:0; }
  .intro-hero-inner{
    grid-template-columns:1fr;
    gap:44px;
  }
  .intro-board{ rotate:0deg; }
  .board-note{ rotate:-.7deg; }
  .board-note + .board-note{ rotate:.6deg; }
}
@media (max-width: 640px){
  .intro-hero{ padding-top: clamp(84px,16vh,120px); }
  .intro-actions{ flex-direction:column; align-items:stretch; }
  .intro-actions .btn{ text-align:center; justify-content:center; }
}

/* ---------------- story / sticky pin ---------------- */
.story{
  position:relative;
  height:calc(var(--beats) * 100vh);
}

.pin{
  position:sticky;
  top:0;
  height:100vh;
  width:100%;
  overflow:hidden;
  display:grid;
  grid-template-columns: 1fr 1fr;
  align-items:center;
  background: var(--cream);
  transition: background-color .8s ease;
}

/* per-beat backdrop: exactly TWO story colours (explicit instruction with
   swatches, Jul 2026) -- the whole first half up to and including the
   judge is light --cream-deep; everything after him is dark --forest.
   No per-beat tints any more. */
.pin[data-beat="0"]{ background:var(--cream-deep); }
.pin[data-beat="1"]{ background:var(--cream-deep); }
.pin[data-beat="2"]{ background:var(--cream-deep); }
.pin[data-beat="3"]{ background:var(--cream-deep); }
.pin[data-beat="4"]{ background:var(--forest); color:var(--paper); }
.pin[data-beat="5"]{ background:var(--forest); color:var(--paper); }
.pin[data-beat="6"]{ background:var(--forest); color:var(--paper); } /* the film beat */
.pin[data-beat="7"]{ background:var(--forest); color:var(--paper); }
.pin[data-beat="8"]{ background:var(--forest); color:var(--paper); }
.pin[data-beat="9"]{ background:var(--forest); color:var(--paper); }

.pin[data-beat="4"] .beat-body,
.pin[data-beat="5"] .beat-body,
.pin[data-beat="6"] .beat-body,
.pin[data-beat="7"] .beat-body,
.pin[data-beat="8"] .beat-body,
.pin[data-beat="9"] .beat-body{ color:rgba(251,248,242,.78); }
.pin[data-beat="4"] .beat-eyebrow,
.pin[data-beat="5"] .beat-eyebrow,
.pin[data-beat="6"] .beat-eyebrow,
.pin[data-beat="7"] .beat-eyebrow,
.pin[data-beat="8"] .beat-eyebrow,
.pin[data-beat="9"] .beat-eyebrow{ color:var(--gold); }
/* muted footnote placeholders need lifting on the dark half */
.pin[data-beat="4"] .placeholder-tag, .pin[data-beat="4"] sup,
.pin[data-beat="5"] .placeholder-tag, .pin[data-beat="5"] sup,
.pin[data-beat="6"] .placeholder-tag, .pin[data-beat="5"] sup,
.pin[data-beat="7"] .placeholder-tag, .pin[data-beat="7"] sup,
.pin[data-beat="8"] .placeholder-tag, .pin[data-beat="8"] sup,
.pin[data-beat="9"] .placeholder-tag, .pin[data-beat="9"] sup{
  color:rgba(251,248,242,.55);
  border-color:rgba(251,248,242,.25);
}
/* ground dots are ink-coloured -- invisible on the forest half; swap them
   to paper there */
.pin[data-beat="4"] .ground-dots,
.pin[data-beat="5"] .ground-dots,
.pin[data-beat="6"] .ground-dots,
.pin[data-beat="7"] .ground-dots,
.pin[data-beat="8"] .ground-dots,
.pin[data-beat="9"] .ground-dots{
  background-image:radial-gradient(var(--paper) 1.5px, transparent 1.6px);
  opacity:.1;
}

/* ---------------- ground layer ---------------- */
.ground{
  position:absolute;
  inset:0;
  z-index:0;
  opacity:.55;
  pointer-events:none;
}
/* top-down world: an ambient dotted floor that scrolls downward, so the
   litigant (walking "up") reads as moving forward. The literal path line
   lives inside .litigant-stage so it tracks the figure side→centre. */
.ground-line{ display:none; }
.ground-dots{
  position:absolute;
  inset:-50% 0;
  background-image:
    radial-gradient(var(--ink) 1.5px, transparent 1.6px);
  background-size: 64px 64px;
  opacity:.07;
  animation: groundScroll 1.1s linear infinite;
  animation-play-state:paused;
}
.pin.is-walking .ground-dots{ animation-play-state:running; }
/* she walks down → the world recedes upward */
@keyframes groundScroll{
  from{ transform:translateY(0); }
  to{ transform:translateY(-46px); }
}

/* ---------------- litigant stage ---------------- */
.litigant-stage{
  position:relative;
  z-index:5;
  grid-column:1;
  /* grid-row:1 is NOT optional. The judge-stage is explicitly placed at
     (1,1); without an explicit row here, grid auto-placement sees cell
     (1,1) occupied and silently moves this stage (and .beats after it)
     down to a NEW row 2 -- splitting the 100vh pin into two stacked
     half-height rows. That bug shipped once: judge floated in the top
     half, litigant + text sat "at the bottom" on every beat. All three
     stages/columns share row 1 on purpose; overlap is intentional. */
  grid-row:1;
  justify-self:center;
  align-self:center;
  width:clamp(230px, 30vw, 380px);
  /* constant above-the-midline lift (desktop; mobile pins her to the top
     row instead). This used to ride inside the JS-driven transform, but
     the horizontal walk was moved off the stage onto .litigant-walker --
     the stage (and the road inside it) no longer moves at all. */
  translate:0 -12vh;
  /* side→centre position (translate) is set continuously, every frame, by
     script.js as a direct function of scroll position -- NOT by a CSS
     transition triggered on a discrete beat change. A time-based CSS
     transition here used to fire once at the exact scroll pixel where the
     beat flipped from 1→2, animating over a fixed .9s regardless of how
     fast/slow the user kept scrolling, which read as a jump-cut into an
     unrelated animation rather than a motion the scroll itself was driving.
     Inline styles always win over stylesheet rules, so no transform/
     transition is declared here at all -- see updateLitigantPosition() in
     script.js, including its own light easing (lerp) for a settled feel
     once scrolling stops, instead of relying on a CSS transition. */
}

/* what actually travels side->centre: the figure, her shadow, and her
   speech bubble -- NOT the road. Sliding the whole stage moved the road
   along with her, which read as the scene panning rather than her
   walking ("not have the whole thing move from the left to the centre").
   js/script.js writes this element's transform every frame; she walks off
   the road, which stays put on the left and fades (see the road-fade
   rules near the judge block). */
.litigant-walker{
  position:relative;
  will-change:transform;
}

/* ---------------- idle speech bubbles ----------------
   Purely decorative flavour text (aria-hidden). Shown/hidden by
   js/script.js toggling .is-visible -- see startBubbles()/stopBubbles()/
   showSpeechBubble(). Positioned relative to .litigant-stage, anchored
   near the head (the figure's head sits roughly in the upper half of the
   viewBox, just left of centre), with a small tail pointing down toward it.

   Hand-drawn/Excalidraw-style treatment: the visible shape (fill, ink
   border, shadow) lives entirely on ::before, a separate layer behind the
   text, with an irregular (not equal-cornered) border-radius for a
   slightly lumpy "drawn by hand" outline, a couple of degrees of rotation,
   and the #speechWobble SVG filter (feTurbulence + feDisplacementMap,
   defined once in index.html right after <body>) applied ONLY to that
   layer. Keeping the filter off .speech-bubble itself means the turbulence
   distorts the sketchy outline/fill but never the text sitting on top of
   it -- if the filter were on the element with the text, the type would
   wobble and blur along with the border, which reads as broken rendering
   rather than a hand-drawn effect. */
.speech-bubble{
  position:absolute;
  top:4%;
  left:52%;
  z-index:6;
  /* width:max-content, NOT auto: an abs-positioned box shrink-wraps to the
     space left inside its containing block (the stage) after the `left`
     offset -- on narrow stages that collapsed the balloon into a one-word-
     per-line sliver. max-content sizes it to its text, capped below. */
  width:max-content;
  max-width:230px;
  padding:13px 17px;
  color:var(--ink);
  font-family:'Comic Relief', var(--font-body);
  font-size:.94rem;
  font-weight:400;
  line-height:1.42;
  text-align:left;
  text-wrap:balance;   /* even out short Comic Relief lines instead of a ragged last word */
  opacity:0;
  /* translate/scale/rotate as independent properties (not one `transform`
     shorthand) on purpose: it lets the position/size transition below
     (translate+scale) coexist with the continuous rotate-only jitter
     animation further down without the two fighting over the same
     `transform` property. --bubble-tilt is a random per-appearance angle
     set by js/script.js each time a bubble is shown (pickBubbleTilt()) --
     the -2deg here is only a fallback for the rare frame before JS has
     set it. */
  translate:-28% 6px;
  scale:.9;
  rotate:var(--bubble-tilt, -2deg);
  transform-origin:22% 100%;
  transition:opacity .3s ease, translate .3s ease, scale .3s ease;
  pointer-events:none;
  will-change:opacity, translate, scale, rotate;
}
.speech-bubble::before{
  content:"";
  position:absolute;
  inset:-4px;
  z-index:-1;
  background:var(--paper);
  border:1.8px solid var(--ink);
  /* the judge's balloon: WRAPPING IS NOT TRUSTED. WebKit repeatedly laid
   the box out one line tall while visually wrapping the text (with
   max-content, with caps, even with fixed width), spilling text past the
   drawn paper. The two lines are now EXPLICIT <br/>-separated spans that
   never wrap, so the box height is line-count * line-height in every
   engine, full stop. */
.judge-bubble{ text-wrap:initial; }
.judge-bubble .jb-line{ white-space:nowrap; }

/* four differently-weighted corners -- a perfect 14px radius all round
     reads as machine-drawn; uneven ones read as a hand-sketched balloon */
  border-radius:255px 15px 225px 20px / 20px 220px 18px 255px;
  box-shadow:0 10px 20px rgba(36,30,26,.16);
  transform:rotate(1deg);
  filter:url(#speechWobble);
}
.speech-bubble::after{
  content:"";
  position:absolute;
  left:22%;
  bottom:-9px;
  width:17px;
  height:17px;
  background:var(--paper);
  border-right:1.8px solid var(--ink);
  border-bottom:1.8px solid var(--ink);
  border-radius:0 0 4px 0;
  transform:rotate(50deg) skew(-6deg, -3deg);
  filter:url(#speechWobble);
}
.speech-bubble.is-visible{
  opacity:1;
  translate:-28% 0;
  scale:1;
  /* rotate itself isn't set here -- bubbleJitter (below) owns it entirely
     while visible, oscillating around --bubble-tilt so the whole thing
     reads as held-by-hand rather than perfectly still. */
  animation:bubbleJitter 2.6s ease-in-out infinite;
}
/* An uneven set of keyframes (not a clean sine wave) reads more like an
   unsteady hand holding a sign than a mechanical wobble. First and last
   keyframes match for a seamless infinite loop. */
@keyframes bubbleJitter{
  0%   { rotate:calc(var(--bubble-tilt, -2deg) - 1.4deg); }
  22%  { rotate:calc(var(--bubble-tilt, -2deg) + 1deg);   }
  48%  { rotate:calc(var(--bubble-tilt, -2deg) - .6deg);  }
  74%  { rotate:calc(var(--bubble-tilt, -2deg) + 1.5deg); }
  100% { rotate:calc(var(--bubble-tilt, -2deg) - 1.4deg); }
}
/* on dark pinned beats (5, 7) the paper bubble still reads fine since it's
   never shown mid-scroll anyway (bubbles only appear while idle, i.e. not
   actively progressing through beats) -- no per-beat override needed. */

/* scrolling "path" behind the figure, follows it side→centre */
.path{
  position:absolute;
  left:50%; top:50%;
  width:70px; height:200vh;
  margin-top:-100vh;   /* centred on the stage → always spans the viewport */
  margin-left:-35px;
  z-index:-1;
  background-image:repeating-linear-gradient(
    to bottom, var(--ink) 0 20px, transparent 20px 46px);
  background-size:6px 46px;
  background-position:center;
  background-repeat:repeat-y;
  opacity:.10;
  /* slow fade used by the entrance (see .pin:not(.is-revealed) .path in the
     entrance block) -- a transition, NOT a keyframe animation, on purpose:
     an animation shorthand here would displace pathScroll and restart it
     from 0 when it ended, snapping the dash background-position -- the
     "road jitters at the end" bug. */
  transition:opacity 2s ease;
  animation: pathScroll 1.1s linear infinite;
  animation-play-state:paused;
}
.pin.is-walking .path{ animation-play-state:running; }
/* she walks down the screen, so the path recedes upward */
@keyframes pathScroll{ from{ background-position-y:0; } to{ background-position-y:-46px; } }

.shadow{
  position:absolute;
  left:50%;
  bottom:6%;
  width:70%;
  height:14%;
  background:radial-gradient(ellipse at center, rgba(0,0,0,.28), transparent 70%);
  transform:translateX(-50%);
  filter:blur(2px);
  /* opacity lives HERE, not in the keyframes: shadowPulse used to animate
     opacity too, which meant the (even paused) animation overrode any
     opacity rule on the element -- making it impossible to hide the shadow
     during the walk-in entrance (it sat visible on the ground before she
     arrived). Keyframes are transform-only now; the pulse reads the same. */
  opacity:.55;
  transition:opacity .7s ease;
  animation: shadowPulse 1.1s ease-in-out infinite;
  animation-play-state:paused;
}
.pin.is-walking .shadow{ animation-play-state:running; }
@keyframes shadowPulse{
  0%,100%{ transform:translateX(-50%) scaleX(1); }
  50%{ transform:translateX(-50%) scaleX(.9); }
}

.litigant{
  display:block;
  width:100%;
  height:auto;
  overflow:visible;
}

/* ---- litigant illustration (uploaded asset; carries its own fills) ----
   Only layout + the walk animation live here. The figure is a top-down
   flat illustration (viewBox 90 140 620 530): dark bun, purple coat, pink
   bag, grey skirt. Animatable groups: .leg-front (the drawn right leg),
   .leg-back (a clone shifted -57px = the left leg), .arm-left/.arm-right
   (the two forearms + hands), all inside .fig.                            */
.litigant .fig,
.litigant .leg-front,
.litigant .leg-back,
.litigant .arm-left,
.litigant .arm-right,
.litigant .head{
  will-change: transform;
  transform-box: view-box;   /* px origins below resolve in viewBox units */
}

/* ---- walk cycle -----------------------------------------------------------
   Top-down stride: each leg lengthens (foot reaching down-screen) then
   foreshortens back under the skirt, in opposite phase. The whole body
   swells/settles (scale) twice per stride — the bob — with a faint
   weight-shift rock. Arms counter-sway a touch. Pivots are in the asset's
   user units: hips sit hidden under the skirt hem (y≈508), body centre
   ≈(400,430). Paused at rest; runs only while the page is scrolling
   (.pin.is-walking, set by js/script.js and cleared ~180ms after the last
   scroll event).                                                          */
.litigant .fig      { animation: figWalk  1s ease-in-out infinite paused; transform-origin:400px 430px; }
.litigant .leg-front{ animation: legFront 1s ease-in-out infinite paused; transform-origin:455px 508px; }
.litigant .leg-back { animation: legBack  1s ease-in-out infinite paused; transform-origin:363px 508px; }
.litigant .arm-left { animation: armLeft  1s ease-in-out infinite paused; transform-origin:150px 430px; }
.litigant .arm-right{ animation: armRight 1s ease-in-out infinite paused; transform-origin:592px 330px; }

.pin.is-walking .litigant .fig,
.pin.is-walking .litigant .leg-front,
.pin.is-walking .litigant .leg-back,
.pin.is-walking .litigant .arm-left,
.pin.is-walking .litigant .arm-right{ animation-play-state:running; }

/* body: subtle expand/contract (bob) on each step + faint rock */
@keyframes figWalk{
  0%,100%{ transform:scale(1)     rotate(-.7deg); }
  25%    { transform:scale(1.016) rotate(0deg);   }
  50%    { transform:scale(1)     rotate(.7deg);  }
  75%    { transform:scale(1.016) rotate(0deg);   }
}
/* legs: extend down-screen ↔ foreshorten under the body, opposite phase */
@keyframes legFront{
  0%,100%{ transform:scaleY(1.02); }
  50%    { transform:scaleY(.62);  }
}
@keyframes legBack{
  0%,100%{ transform:scaleY(.62);  }
  50%    { transform:scaleY(1.02); }
}
/* arms: gentle counter-sway from the elbows */
@keyframes armLeft{
  0%,100%{ transform:rotate(2.4deg);  }
  50%    { transform:rotate(-2.4deg); }
}
@keyframes armRight{
  0%,100%{ transform:rotate(-2.4deg); }
  50%    { transform:rotate(2.4deg);  }
}

/* ---- "running in late" entrance --------------------------------------------
   Every time the active beat becomes 0 (js/script.js's setActiveBeat, after
   the user has scrolled at least once), playLateEntrance() locks scroll for
   ~1.7s, adds .is-entrance + .is-running + .is-walking to #pin, and shows a
   one-off scripted speech bubble. .is-running only speeds up the SAME
   figWalk/legFront/legBack/armLeft/armRight keyframes used for ordinary
   scroll-driven walking (just the animation-duration -- name, timing
   function, and infinite iteration all still come from the base .litigant
   rules above) so the legs/arms move at a hurried, running cadence instead
   of an ordinary stroll. .is-walking (added alongside) is what actually
   flips those animations from paused to running, exactly as it does for
   scroll -- .is-running on its own does nothing without it. */
.pin.is-running .litigant .fig,
.pin.is-running .litigant .leg-front,
.pin.is-running .litigant .leg-back,
.pin.is-running .litigant .arm-left,
.pin.is-running .litigant .arm-right{ animation-duration:.35s; }

/* She's invisible by default -- not present at all until she "arrives."
   .pin.is-revealed (added once, by js/script.js, and never removed again)
   is the only thing that ever makes her visible; .pin.is-entrance layers
   the walk-in animation on top of that reveal, and only while it's active.

   This targets .litigant-stage's OPACITY, not its transform -- .litigant-
   stage's `transform` is exclusively owned by updateLitigantPosition() in
   js/script.js, rewritten inline every animation frame to drive the
   scroll-linked side->centre motion, so a CSS animation/transition on THAT
   property would just get stomped every frame (same reasoning as the
   mobile safety-net comment further down). The vertical drop-in below uses
   the independent `translate` CSS property instead of `transform` for
   exactly the same reason -- `translate` and `transform` compose together
   rather than overriding each other, so this can move her vertically
   without disturbing the JS-driven horizontal position at all. */
.litigant-stage{ opacity:0; }
.pin.is-revealed .litigant-stage{
  opacity:1;
  transition:opacity .4s ease; /* only actually visible for the fallback reveal below -- an active .is-entrance animation overrides this while it's running */
}
/* Fallback: if the very first real scroll skips beat 0 entirely (see
   revealLitigantPlainly() in js/script.js), .is-revealed alone reveals her
   with the plain fade above -- no walk-in, since there's no "arriving at
   beat 0" moment to hang one on. */
.pin.is-entrance #litigant{
  /* #litigant (the original figure), NOT .litigant -- the pendency-queue
     clones share the .litigant class for the walk-cycle rules and must not
     inherit the walk-in translate. */
  /* Targets .litigant (the <svg> figure) and NOT .litigant-stage: the stage
     also contains the dotted road (.path) and the shadow, and animating the
     whole stage made the road slide down WITH her -- reading as "the road
     is moving," not "she's walking in." Only the figure descends; the road
     fades in in place (below) and the shadow stays put on the ground.

     Speed is matched to her FEET, not picked for drama: at desktop size the
     figure renders ~0.6x its viewBox, making each .35s run cycle's stride
     reach ~100px of "ground" -- so a credible ground speed is
     ~100px / .35s ≈ 285px/s. The -70vh travel (~630px on a 900px viewport)
     therefore takes ~2.2s. If you change the run cadence (.is-running
     duration below) or the travel distance, rebalance this duration to
     distance / (stride-per-cycle x cycles-per-second) or she'll read as
     sliding (too fast) or moonwalking (too slow) again. The near-linear
     bezier matters too: her cadence is constant, so a strongly decelerating
     curve makes her feet mismatch at both ends -- this one is ~linear with
     a gentle settle in the last quarter. */
  animation: lateWalkIn 2.2s cubic-bezier(.4,.4,.6,1) both;
}
/* The dotted road doesn't move during the entrance -- it fades in slowly,
   in place, while she walks down over it (opacity 0 pre-reveal, then the
   2s transition declared on .path itself takes it to rest). This used to
   be a keyframe animation on the `animation` shorthand -- which displaced
   pathScroll and RESTARTED it (background-position snapping back to 0)
   the moment the entrance ended: the "road jitters a little at the end"
   bug. A transition + a play-state longhand never touches pathScroll's
   clock. The paused rule below outranks `.pin.is-walking .path` (equal
   specificity) purely by source order -- keep this block after it. */
.pin:not(.is-revealed) .path{ opacity:0; }
.pin.is-entrance .path{ animation-play-state:paused; } /* her motion over a STATIC road is what sells the walk-in */

/* The shadow doesn't exist until she lands: it's her contact with the
   ground, so showing it while she's still mid-air read as "the shadow
   shows up in place before her." It fades in via .shadow's own .7s
   opacity transition the moment .is-entrance comes off (~when she lands).
   Requires shadowPulse to be transform-only -- see .shadow above. */
.pin:not(.is-revealed) .shadow,
.pin.is-entrance .shadow{ opacity:0; }
/* -70vh, not a fixed pixel offset: .litigant-stage sits align-self:center
   inside .pin, which is exactly 100vh tall with overflow:hidden -- so her
   resting position is already ~50vh down from the pin's (clipped) top
   edge. A fixed small offset like -220px barely moved her off that centre
   point and never actually crossed the clipped boundary, so nothing
   visibly left the frame -- it just read as a small in-place nudge, not a
   walk-in. -70vh guarantees she starts at roughly 50vh - 70vh = -20vh
   from the pin's top, i.e. genuinely above and clipped out of the visible
   area, regardless of viewport height.

   EXACTLY TWO KEYFRAMES, on purpose (this fixed the "super jerky" walk-in):
   CSS easing applies PER KEYFRAME SEGMENT, so the earlier 4-stop version
   (-70vh -> -16vh -> +3vh overshoot -> 0) decelerated into and
   re-accelerated out of every intermediate stop -- three visible hitches.
   A single 0%->100% segment gives one continuous, smoothly decelerating
   descent. No opacity in the keyframes at all: she starts fully opaque but
   clipped above the pin's overflow:hidden edge, so she appears by *walking
   into frame* -- and beat 0's greyscale/half-opacity treatment (see the
   "invisible litigant" block below) stays free to own the opacity channel
   even while the walk-in runs. */
@keyframes lateWalkIn{
  0%   { translate:0 -70vh; }
  100% { translate:0 0;     }
}

/* ---- beat 1: "to most courts, the litigant is invisible" -------------------
   (Beat 0 is the intro -- she walks in there in FULL colour; the ghosting
   only begins once this beat arrives, and lifts again as beat 2 begins.)
   Greyscale at half opacity, smooth 1.1s both ways. Scoped to #litigant
   so the queue clones (same class) are unaffected. lateWalkIn deliberately
   carries no opacity keyframes so this rule owns the channel. */
#litigant{ transition: filter 1.1s ease, opacity 1.1s ease; }
.pin[data-beat="1"] #litigant{
  filter:grayscale(1);
  opacity:.5;
}

/* ---- beat 2: the pendency queue ---------------------------------------------
   Four clones of the litigant (built once by js/script.js -- same figure,
   recoloured coat, no ids/defs) queue up in front of (below) and behind
   (above) her along the road, at --q-slot offsets in % of their own
   height. They DON'T slide in from off-screen any more -- the first
   version walked the front clones in from above, which crossed straight
   over her ("person slides in over the litigant"), and the slots were
   tight enough to overlap. Now spacing is a clean figure-plus-gap
   (±105% / ±210%) and each clone just fades in at its own slot with a
   small settling drift (arriving from slightly up-queue, leaving slightly
   down-queue), so nothing ever passes through anyone. The sense of motion
   comes from the loop below instead. */
.queue-fig{
  position:absolute;
  left:0; top:0;
  width:100%;
  opacity:0;
  translate:0 calc(var(--q-slot, 0%) - 12%);   /* just shy of their spot */
  transition: translate 1.2s cubic-bezier(.4,.2,.35,1), opacity .9s ease;
  pointer-events:none;
  will-change: translate, opacity;
}
.pin[data-beat="2"] .queue-fig{
  opacity:1;
  translate:0 var(--q-slot, 0%);               /* standing in line */
}
/* on later beats they drift on down-queue as they fade (beats 0-1 keep
   the arriving-side offset so re-entering beat 2 reads the same way) */
.pin[data-beat="3"] .queue-fig,
.pin[data-beat="4"] .queue-fig,
.pin[data-beat="5"] .queue-fig,
.pin[data-beat="6"] .queue-fig,
.pin[data-beat="7"] .queue-fig,
.pin[data-beat="8"] .queue-fig,
.pin[data-beat="9"] .queue-fig{
  translate:0 calc(var(--q-slot, 0%) + 12%);
}

/* while the beat is active the whole line walks forward in a LOOP:
   every figure's walk cycle runs (hers included) and the world -- ground
   dots, dashed road, shadow pulse -- scrolls past continuously. Nobody
   actually translates, so it loops seamlessly with no wrap-around jump;
   the moving ground is what reads as the queue trudging ahead. These
   outrank the paused/.is-walking rules by specificity (three simple
   selectors vs two). */
.pin[data-beat="2"] .litigant .fig,
.pin[data-beat="2"] .litigant .leg-front,
.pin[data-beat="2"] .litigant .leg-back,
.pin[data-beat="2"] .litigant .arm-left,
.pin[data-beat="2"] .litigant .arm-right,
.pin[data-beat="2"] .ground-dots,
.pin[data-beat="2"] .path,
.pin[data-beat="2"] .shadow{
  animation-play-state:running;
}

/* ---- beat 3: she is left behind; the judge takes the bench ------------------
   The litigant (and her whole stage: road, shadow, queue) fades out -- she
   never walks into this section; the system speaks for itself. Equal
   specificity to `.pin.is-revealed .litigant-stage` (which sets opacity:1),
   so THIS rule must stay later in the file to win. */
.pin[data-beat="3"] .litigant-stage,
.pin[data-beat="6"] .litigant-stage{  /* judge beat / film beat */
  opacity:0;
  transition:opacity .8s ease;
}

.judge-stage{
  position:relative;
  z-index:5;
  grid-column:1;
  grid-row:1;               /* overlaps the litigant's grid cell on purpose */
  justify-self:center;
  align-self:center;
  width:clamp(210px, 24vw, 330px);
  opacity:0;
  translate:0 7vh;
  scale:.94;
  transition: opacity .9s ease, translate .9s cubic-bezier(.3,.6,.3,1), scale .9s cubic-bezier(.3,.6,.3,1);
  pointer-events:none;
}
.pin[data-beat="3"] .judge-stage{
  opacity:1;
  translate:0 0;
  scale:1;
}
.judge{
  display:block;
  width:100%;
  height:auto;
  overflow:visible;
}

/* gavel swing: the two .gavel groups (hand from one source path, head+handle
   from another -- split out of the original compound paths, z-order kept)
   share a pivot at the wrist, same twin-group trick as the litigant's .head.
   Raise, strike, settle, rest -- looping while the beat is active. */
.judge .gavel{
  will-change:transform;
  transform-box:view-box;
  transform-origin:190px 300px;
}
.pin[data-beat="3"] .judge .gavel{
  animation: gavelSwing 2.8s ease-in-out .45s infinite;
}
@keyframes gavelSwing{
  0%   { transform:rotate(0deg);   }
  12%  { transform:rotate(26deg);  }   /* raise */
  20%  { transform:rotate(-16deg); }   /* strike */
  27%  { transform:rotate(-8deg);  }   /* bounce */
  36%  { transform:rotate(0deg);   }   /* settle */
  100% { transform:rotate(0deg);   }   /* rest until the next swing */
}

/* the judge's verdict bubble -- same hand-drawn treatment as hers (shared
   .speech-bubble base: wobble filter, jitter, Comic Relief), shown by the
   beat itself with a delay timed to land just after the first gavel strike
   (.45s animation-delay + ~.7s to the strike keyframe). Leaving beat 3
   drops the rule, and with it the delay, so it hides immediately. */
.judge-bubble{
  /* anchored to the stage's TOP EDGE, not offset by a % of stage height:
     his head sits almost exactly at that edge (viewBox y≈27 of a 20-1000
     crop), so `bottom:calc(100% + gap)` puts the balloon just above his
     head with a constant gap at EVERY screen size -- a % top offset
     scaled with the (very tall) bench artwork and drifted far too high
     on large screens. */
  top:auto;
  bottom:calc(100% + 12px);
  left:38%;
  translate:6% 10px;
}
.pin[data-beat="3"] .judge-bubble{
  opacity:1;
  translate:6% 0;
  scale:1;
  animation:bubbleJitter 2.6s ease-in-out infinite;
  transition-delay:1.2s;
}

/* ---- leaving the judge: dust piles up FAST, then he disintegrates --------
   Scroll-driven, and finished BEFORE the next section arrives: js/script.js
   toggles .is-judge-exit the moment scroll progress passes beatFloat 3.3 --
   still comfortably inside beat 3 (the beat flips at 3.5) -- so the whole
   ~1.1s sequence (dust settles ~.3s, dissolve ~.8s) plays out on HIS
   screen, not bleeding over the next one. Gated by `judgeSeen` in JS so a
   direct landing on a later beat never flashes him. Scrolling back below
   the threshold removes the class and he reassembles via the ordinary
   beat-3 transitions. `forwards` holds him at opacity 0 for as long as the
   class stays on (all beats past 3), so there's no lingering ghost fade. */
/* PRIMARY path -- the Thanos snap. js/script.js rasterises the judge SVG
   into a canvas particle field (prepareJudgeDust/runJudgeDust). There is
   NO hard swap: over the first slice of the scrub the crisp SVG's opacity
   is driven down inline while the grain canvas (drawn on top) is driven
   up, so the artwork FADES INTO the dust -- early flying grains read as
   dust lifting off the still-solid figure. Both opacities are written by
   runJudgeDust as a function of scrub time, so the cross-fade reverses
   with scroll like everything else. Nothing here animates stage opacity,
   or it would fade the grains themselves. */
.judge-dust-canvas{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  pointer-events:none;
  opacity:0; /* runJudgeDust drives this inline during the snap */
}
/* his bubble goes with him the moment the dissolve starts (beat 3 is still
   active at that point, so the [data-beat="3"] show rule above would
   otherwise keep it up over an empty bench) -- same specificity, this
   must stay AFTER that rule in source order */
.pin.is-judge-exit .judge-bubble{
  opacity:0;
  translate:6% 10px;
  scale:.9;
  transition-delay:0s;
}

/* FALLBACK path (canvas prep failed / not ready): the earlier coarse
   turbulence displacement + fade. js/script.js adds the extra class. */
.pin.is-judge-exit-fallback .judge{
  filter:url(#judgeDissolve);
}
.pin.is-judge-exit-fallback .judge-stage{
  animation: judgeDissolveAway .8s ease-in .3s forwards;
}
@keyframes judgeDissolveAway{
  0%  { opacity:1;   translate:0 0;        scale:1;    filter:none; }
  45% { opacity:.8;  translate:-.4vw -1vh; scale:1.01; filter:grayscale(.9) blur(1px); }
  100%{ opacity:0;   translate:-2vw -4vh;  scale:1.04; filter:grayscale(1) blur(6px); }
}

/* the dust itself: small motes that settle onto his head, shoulders, and
   the bench, then stream away on the same wind. Staggered per-particle
   via --dd/--dur. */
.judge-dust{ position:absolute; inset:0; pointer-events:none; }
.judge-dust i{
  position:absolute;
  width:7px; height:7px;
  border-radius:50%;
  background:var(--muted);
  opacity:0;
}
.judge-dust i:nth-child(1){ left:46%; top:2%;  width:5px; --dd:0s;   --dur:1s;   } /* head */
.judge-dust i:nth-child(2){ left:34%; top:11%; width:6px; --dd:.06s; --dur:1.1s; } /* shoulder L */
.judge-dust i:nth-child(3){ left:60%; top:12%;            --dd:.12s; --dur:.95s; } /* shoulder R */
.judge-dust i:nth-child(4){ left:24%; top:36%; width:8px; --dd:.03s; --dur:1.15s;} /* bench top L */
.judge-dust i:nth-child(5){ left:52%; top:34%; width:6px; --dd:.16s; --dur:1s;   } /* bench top C */
.judge-dust i:nth-child(6){ left:74%; top:37%; width:5px; --dd:.09s; --dur:1.05s;} /* by the scales */
.judge-dust i:nth-child(7){ left:38%; top:58%; width:8px; --dd:.18s; --dur:1.15s;} /* panel */
.judge-dust i:nth-child(8){ left:64%; top:66%; width:6px; --dd:.13s; --dur:1.1s; } /* panel R */
.pin.is-judge-exit .judge-dust i{
  animation: dustAway var(--dur, 1s) ease-in var(--dd, 0s) forwards;
}
@keyframes dustAway{
  0%  { opacity:0;   translate:0 -12px;  }
  30% { opacity:.95; translate:0 0;      }  /* lands on him / the desk, fast */
  60% { opacity:.8;  translate:-1.5vw -2vh; }
  100%{ opacity:0;   translate:-6vw -6vh;  } /* scattered up and LEFT with him */
}

/* ---- beats 3+: the road is GONE ---------------------------------------------
   From the judge's section onward there is no road at all. transition:none
   is the point: the road's base 2s opacity fade is for the walk-in reveal,
   and letting it run here meant that when her stage faded back in on beat
   4, the road inside it was caught mid-fade -- briefly visible, then
   fading out ("the road briefly fades in and fades out"). Hidden with no
   transition, it can never be caught in between. Scrolling back to beat 2
   brings it back with the normal soft fade (beat 2 isn't in this list). */
.pin[data-beat="3"] .path,
.pin[data-beat="4"] .path,
.pin[data-beat="5"] .path,
.pin[data-beat="6"] .path,
.pin[data-beat="7"] .path,
.pin[data-beat="8"] .path,
.pin[data-beat="9"] .path{
  opacity:0;
  transition:none;
}

/* ---- beat 4: reimagining justice around the citizen -------------------------
   Concentric circles around her FEET (the orbit centre sits at ~87% of the
   walker's height, where her shoes are), with solid brand-colour dots
   orbiting along the ring paths. Rings + dots live inside the walker so
   they travel with her, and only exist on beat 4. Spinning the ring
   element itself carries its dot around the path; different durations
   and directions keep it feeling alive rather than mechanical. */
.orbits{
  position:absolute;
  left:50%;
  top:87%;
  width:100%;
  aspect-ratio:1;
  translate:-50% -50%;
  /* BEHIND her, not over: being position:absolute would otherwise paint
     this above the static <svg> regardless of DOM order. Negative z-index
     drops it behind the walker's content (the nearest stacking context is
     .litigant-stage at z-index:5, so it still sits above the pin's
     background). Rings and dots now pass behind her body. */
  z-index:-1;
  opacity:0;
  transition:opacity 1s ease .4s;   /* fades in after she lands */
  pointer-events:none;
}
.pin[data-beat="4"] .orbits,
.pin[data-beat="5"] .orbits{ opacity:1; }  /* rings carry on into the Kollam beat */
/* ...but never during her walk-in: the rings appear only once she has
   settled on her spot (equal specificity to the show rule above -- this
   must stay AFTER it; when .is-entrance drops off, the orbit's own
   delayed 1s fade brings the rings in) */
.pin.is-entrance .orbits{ opacity:0; }
.orbit{
  position:absolute;
  left:50%; top:50%;
  translate:-50% -50%;
  aspect-ratio:1;
  border:1px solid rgba(251,248,242,.26);  /* beat 4 is the forest half: paper rings */
  border-radius:50%;
  animation: orbitSpin linear infinite;
}
.orbit-1{ width:52%;  animation-duration:9s;  }
.orbit-2{ width:86%;  animation-duration:15s; animation-direction:reverse; }
.orbit-3{ width:122%; animation-duration:22s; }
@keyframes orbitSpin{ to{ rotate:360deg; } }
.orb{
  position:absolute;
  top:-6px; left:50%;
  margin-left:-6px;
  width:12px; height:12px;
  border-radius:50%;
  box-shadow:0 0 10px rgba(0,0,0,.25);
}
.orbit-2 .orb + .orb{ top:auto; bottom:-6px; }  /* second dot rides the far side */
.orb-green{ background:var(--green); }
.orb-pink { background:var(--pink);  }
.orb-paper{ background:var(--paper); }

/* ---- beat 6: the film break ------------------------------------------------
   REVISED (Jul 2026, "I meant it should be fixed behind"): the video is
   the FIXED lower layer (z-index 2, under the stages at 5 and text at 6),
   and the page scrolls OFF it. js/script.js writes a --curtain custom
   property on the pin (0 at beatFloat 5.5 -> 1 by ~5.95, held, restored
   before beat 7); .film-curtain (a full-bleed forest panel at z-index 3)
   plus the litigant stage and the beats column all translate up by
   --curtain * ~105vh, so the previous section visibly passes over the
   waiting film. When the curtain is fully open (and the approach was
   forward, and the file is actually playable), scroll fixes and the film
   plays; the skip button or the ended event releases and jumps to beat 7,
   where her usual walk-in runs. Missing/broken file = note shown, no
   hold, ever. */
.video-break{
  position:absolute;
  inset:0;
  z-index:2;                /* the fixed underlayer */
  background:var(--forest-deep);
  visibility:hidden;
}
.pin[data-beat="6"] .video-break{ visibility:visible; }
/* ENTRY curtain: slides UP and away (scrolling into the film pulls the
   previous section off the top). It never comes back down -- the exit is
   handled by its own bottom panel below, so leaving the film reads as
   the NEXT section arriving naturally from underneath, not the old one
   dropping back in from above. */
.film-curtain{
  position:absolute;
  inset:0;
  z-index:3;                /* over the video, under stages (5) and text (6) */
  background:var(--forest);
  transform:translateY(calc(var(--curtain, 0) * -102%));
  visibility:hidden;
  pointer-events:none;
}
/* EXIT curtain: parked one viewport BELOW; rises to cover the film as you
   scroll onward (--curtain-exit 0 -> 1 across beatFloat 6.15 -> 6.45). */
.film-curtain-exit{
  position:absolute;
  inset:0;
  z-index:3;
  background:var(--forest);
  transform:translateY(calc((1 - var(--curtain-exit, 0)) * 102%));
  visibility:hidden;
  pointer-events:none;
}
.pin[data-beat="5"] .film-curtain,
.pin[data-beat="6"] .film-curtain,
.pin[data-beat="5"] .film-curtain-exit,
.pin[data-beat="6"] .film-curtain-exit{ visibility:visible; }
/* the page content rides out with the entry curtain (negative vh, up and
   away) and back IN with the exit curtain (from below) -- js writes the
   signed --content-shift in vh; the sign flips while everything is parked
   off-screen, so the jump is never visible */
.litigant-stage,
.beats{
  transform:translateY(calc(var(--content-shift, 0) * 1vh));
}
.video-break video{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:cover;
}
.video-note{
  position:absolute;
  top:50%; left:50%;
  translate:-50% -50%;
  max-width:34ch;
  text-align:center;
  font-size:.9rem;
  font-style:italic;
  color:rgba(251,248,242,.65);
  display:none;
}
.video-break.video-missing .video-note{ display:block; }
.video-break.video-missing video{ display:none; }
.visually-hidden{
  position:absolute;
  width:1px; height:1px;
  overflow:hidden;
  clip-path:inset(50%);
  white-space:nowrap;
}

/* ---- idle look-around ------------------------------------------------------
   After 10s without scrolling js/script.js adds .is-idle to the pin: the two
   .head groups (face skin + hair/bun, split to preserve z-order) turn to
   glance left, then right — "what's going on?" — then rest, repeating
   every cycle. Cleared the moment scrolling resumes.                      */
.litigant .head{ transform-origin:379px 372px; }
.pin.is-idle .litigant .head{ animation: headLook 5.5s ease-in-out infinite; }
@keyframes headLook{
  0%,14%  { transform:rotate(0deg);   }
  24%,38% { transform:rotate(-16deg); }  /* glance left, hold */
  48%     { transform:rotate(0deg);   }
  58%,72% { transform:rotate(16deg);  }  /* glance right, hold */
  82%,100%{ transform:rotate(0deg);   }
}

/* ---- occasional "dread" head-shake -----------------------------------------
   Only while a speech bubble is up, and only sometimes (see DREAD_CHANCE in
   js/script.js -- roughly 1 in 4 bubbles, not every one) js/script.js adds
   .is-dreading to the pin alongside .is-idle: a quick side-to-side shiver,
   as though she's dreading whatever the bubble just said. This selector has
   the same specificity as the headLook rule above (4 classes each) and is
   declared after it, so it wins the moment .is-dreading is present, then
   yields back to the looping headLook once js/script.js removes the class. */
.pin.is-dreading .litigant .head{ animation: headShake .95s ease-in-out; }
@keyframes headShake{
  0%     { transform:rotate(0deg);   }
  14%    { transform:rotate(-9deg);  }
  30%    { transform:rotate(8deg);   }
  46%    { transform:rotate(-7deg);  }
  62%    { transform:rotate(5deg);   }
  78%    { transform:rotate(-3deg);  }
  92%    { transform:rotate(1deg);   }
  100%   { transform:rotate(0deg);   }
}

/* ---------------- text beats ---------------- */
.beats{
  position:relative;
  grid-column:2;
  grid-row:1;  /* same reasoning as .litigant-stage -- see comment there */
  z-index:6;
  height:100%;
  padding: 0 var(--pin-pad) 0 clamp(8px,2vw,24px);
  display:flex;
  align-items:center;
  /* the container spans the whole pin at z-index 6 and was swallowing hover
     meant for the waving heads (z 4) below it. The active beat re-enables
     its own pointer events (.beat.is-active), so links/buttons still work. */
  pointer-events:none;
}
/* once she's centred (beats 2-7, desktop only -- mobile stays single-column
   and untouched), reading text mid-column-2 put it right where she now
   stands. Spanning the full row and pinning to the bottom-left instead
   keeps it clear of her and gives the stat/title room to breathe under her
   raised position above. `.beat`'s own absolute children inherit this via
   the flex container's static-position rules, same mechanism as before. */
@media (min-width: 861px){
  /* beat 2 is NOT in this list: she stays on the left through beats 0-2
     (the judge takes her spot on 2), so the text keeps its right column
     there; the bottom-left treatment starts once she's actually centred. */
  .pin[data-beat="4"] .beats,
  .pin[data-beat="5"] .beats,
  .pin[data-beat="7"] .beats,
  .pin[data-beat="8"] .beats,
  .pin[data-beat="9"] .beats{
    grid-column: 1 / -1;
    align-items: flex-end;
    justify-content: flex-start;
    padding: 0 var(--pin-pad) 9vh clamp(28px, 6vw, 72px);
  }
}
.beat{
  position:absolute;
  max-width: 480px;
  opacity:0;
  transform:translateY(24px);
  transition: opacity .6s ease, transform .6s ease;
  pointer-events:none;
}
.beat.is-active{
  opacity:1;
  transform:translateY(0);
  pointer-events:auto;
}

.beat-eyebrow{
  display:block;
  font-size:.78rem;
  font-weight:600;
  text-transform:uppercase;
  letter-spacing:.12em;
  color:var(--forest); /* dark-green, NOT --green -- bright green fails contrast on light beat backgrounds (0-4,6); see beat 5/7 override below for the dark-bg case */
  margin-bottom:14px;
}
.beat-title{
  font-size:clamp(1.9rem, 3.6vw, 3rem);
  margin-bottom:18px;
}
.beat-stat{
  font-size:clamp(3rem, 8vw, 6.4rem);
  margin-bottom:10px;
  color:var(--forest); /* same reasoning as .beat-eyebrow above */
  font-weight:600;
}
/* Beats 5 & 7 sit on dark (--navy/--forest) backgrounds, so the bright
   --green accent is legible there and gets reinstated explicitly --
   this is the one place in the story where the literal brand green is
   meant to show up, per "only use it on a dark bg". */
/* the dark (forest) half is where the literal brand green belongs */
.pin[data-beat="4"] .beat-stat,
.pin[data-beat="5"] .beat-stat,
.pin[data-beat="6"] .beat-stat,
.pin[data-beat="7"] .beat-stat,
.pin[data-beat="8"] .beat-stat,
.pin[data-beat="9"] .beat-stat{ color:var(--green); }
.beat-body{
  font-size:1.05rem;
  line-height:1.6;
  color:var(--ink-soft);
  max-width:44ch;
}
.placeholder-tag{
  display:inline-block;
  margin-top:8px;
  font-size:.72rem;
  font-style:italic;
  color:var(--muted);
  border-top:1px dashed var(--line);
  padding-top:6px;
}
.scroll-cue{
  margin-top:32px;
  font-size:.85rem;
  font-weight:500;
  color:var(--muted);
  animation: cueBounce 1.6s ease-in-out infinite;
}
@keyframes cueBounce{
  0%,100%{ transform:translateY(0); }
  50%{ transform:translateY(6px); }
}

.values-label{
  margin:26px 0 0;
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:rgba(251,248,242,.55);
}
.value-chips{
  list-style:none;
  display:flex;
  flex-wrap:wrap;
  gap:10px;
  padding:0;
  margin:12px 0 0;
}
.value-chips li{
  padding:9px 16px;
  border-radius:999px;
  border:1px solid rgba(251,248,242,.35);
  font-size:.85rem;
  font-weight:500;
}

.initiative-grid{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:10px;
  margin-top:20px;
  max-width:520px;
}
/* initiative cards live on the story's DARK (forest) half now -- styled
   for it (they were ink-on-light before the two-colour split) */
.initiative-card{
  display:flex;
  flex-direction:column;
  gap:16px;
  padding:16px;
  border-radius:14px;
  background:rgba(251,248,242,.07);
  border:1px solid rgba(251,248,242,.18);
  text-decoration:none;
  color:var(--paper);
  transition:background .2s ease, transform .2s ease;
}
.initiative-card:hover{ background:rgba(251,248,242,.14); transform:translateY(-2px); }
.initiative-sub{
  font-size:.8rem;
  line-height:1.45;
  opacity:.65;
  margin-top:-8px; /* pull closer to the name; card gap is 16px */
}
.initiative-num{ font-family:var(--font-display); font-size:1.1rem; color:var(--green); } /* bright brand green -- dark bg only, per the palette rule */
.initiative-name{ font-weight:600; font-size:.95rem; line-height:1.3; }
.initiative-link{ font-size:.78rem; color:rgba(251,248,242,.55); margin-top:auto; }

.cta-row{ display:flex; gap:14px; margin-top:28px; flex-wrap:wrap; }
/* .btn is designed for <a> but also used on <button>: kill the UA button
   chrome (border, font) and make the cursor behave like a link everywhere.
   .btn-outline re-asserts its border below (button.btn outranks it). */
button.btn{
  border:0;
  cursor:pointer;
  font-family:var(--font-body);
}
button.btn.btn-outline{ border:1px solid var(--line); }
.btn{
  display:inline-flex;
  align-items:center;
  padding:13px 24px;
  border-radius:999px;
  font-weight:600;
  font-size:.92rem;
  text-decoration:none;
  transition:background .2s ease, color .2s ease, border-color .2s ease;
}
/* .btn-primary defaults to the bright --green -- correct as-is for its one
   use on a dark background (the beat 7 CTA, "Get in touch"). Everywhere
   else it's reused on a light surface (job modal, job page), it's
   overridden below to the dark --forest shade instead, per "only use
   [bright green] on a dark bg". Text is --ink, not --paper -- white-on-
   bright-green only hits a 1.9:1 contrast ratio (fails WCAG badly);
   dark ink on the same green hits 8.2:1. */
.btn-primary{ background:var(--green); color:var(--ink); }
.btn-primary:hover{ background:#51D79E; } /* lighter shade of --green, keeps ink legible on hover too (~9:1) */
.job-page .btn-primary,
.job-modal-panel .btn-primary,
.intro-hero .btn-primary{ background:var(--forest); color:var(--paper); } /* dark bg here, so light text -- paper on forest is 12.4:1 */
.job-page .btn-primary:hover,
.job-modal-panel .btn-primary:hover,
.intro-hero .btn-primary:hover{ background:#1C3540; } /* lighter shade of --forest, for hover */
.btn-ghost{ border:1px solid rgba(251,248,242,.4); color:var(--paper); }
.btn-ghost:hover{ background:rgba(251,248,242,.12); }

/* ---------------- progress rail ---------------- */
.skip-journey{
  font-size:.78rem;
  font-weight:600;
  letter-spacing:.04em;
  text-transform:uppercase;
  text-decoration:none;
  color:inherit;
  opacity:.55;
  transition:opacity .2s ease;
  margin-right:6px;
}
.skip-journey:hover{ opacity:1; text-decoration:underline; text-underline-offset:3px; }

/* ---------------- beat jumper (litigant-journey only) ----------------
   Two small chevron buttons pinned to the right edge, vertically centred in
   the text column's right margin. Built by js/journey-nav.js; only shown
   while the story fills the viewport (.is-visible), and slid away during the
   cinematic film beat (body.film-playing), mirroring the progress rail. Dark
   translucent so they read on both the light and dark beat backgrounds. */
.journey-nav{
  position:fixed;
  right:clamp(12px,2vw,26px);
  top:50%;
  transform:translateY(-50%) translateX(14px);
  display:flex;
  flex-direction:column;
  gap:12px;
  z-index:55;
  opacity:0;
  pointer-events:none;
  transition:opacity .35s ease, transform .35s ease;
}
.journey-nav.is-visible{ opacity:1; transform:translateY(-50%); pointer-events:auto; }
body.film-playing .journey-nav{ opacity:0; pointer-events:none; }
.journey-nav-btn{
  width:46px; height:46px;
  border-radius:50%;
  display:grid; place-items:center;
  border:1px solid rgba(246,241,230,.38);
  background:rgba(17,31,38,.72);
  color:var(--paper);
  cursor:pointer;
  box-shadow:0 6px 20px rgba(10,21,26,.28);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  transition:background .2s ease, transform .15s ease, opacity .2s ease, border-color .2s ease;
}
.journey-nav-btn:hover{ background:var(--forest); border-color:rgba(246,241,230,.6); transform:translateY(-1px); }
.journey-nav-btn:active{ transform:scale(.93); }
.journey-nav-btn:focus-visible{ outline:2px solid var(--green); outline-offset:2px; }
.journey-nav-btn:disabled{ opacity:.28; cursor:default; pointer-events:none; box-shadow:none; }
.journey-nav-btn svg{ display:block; }
@media (max-width:600px){
  .journey-nav{ gap:10px; }
  .journey-nav-btn{ width:40px; height:40px; }
}
@media (prefers-reduced-motion: reduce){
  .journey-nav{ transition:opacity .2s ease; }
}
.progress-rail{
  position:absolute;
  right:20px;
  bottom:28px;
  z-index:10;
  /* slides down out of frame while the film plays (body.film-playing),
     mirroring the header's slide-up, and glides back on scroll-away */
  transition: translate .55s cubic-bezier(.4,.1,.3,1), opacity .4s ease;
  display:flex;
  align-items:center;
  gap:10px;
  color:inherit;
}
.progress-track{
  width:120px;
  height:3px;
  background:rgba(36,30,26,.15);
  border-radius:3px;
  overflow:hidden;
}
.pin[data-beat="4"] .progress-track,
.pin[data-beat="5"] .progress-track,
.pin[data-beat="6"] .progress-track,
.pin[data-beat="7"] .progress-track,
.pin[data-beat="8"] .progress-track,
.pin[data-beat="9"] .progress-track{ background:rgba(251,248,242,.25); }
.progress-fill{
  height:100%;
  width:0%;
  background:var(--forest); /* dark-green default -- rail sits over light beat backgrounds most of the time */
  transition:width .15s linear, background-color .3s ease;
}
/* rail is fixed inside .pin, so it overlays beats 5/7's dark background too --
   bright --green is legible there, so it's swapped back in for those beats. */
.pin[data-beat="4"] .progress-fill,
.pin[data-beat="5"] .progress-fill,
.pin[data-beat="6"] .progress-fill,
.pin[data-beat="7"] .progress-fill,
.pin[data-beat="8"] .progress-fill,
.pin[data-beat="9"] .progress-fill{ background:var(--green); }
.progress-count{
  font-size:.75rem;
  font-variant-numeric:tabular-nums;
  color:var(--muted);
  min-width:34px;
}

/* ---------------- collaborate ---------------- */
.collaborate{
  /* deep indigo, client-specified hex (Jul 2026; replaced the short-lived
     teal #11353C) -- distinct from the story's --forest so the board
     reads as its own space. Also inherited by the /sc-ai-policy/
     perspectives section, which shares this class by design. */
  background:#141732;
  color:var(--paper);
  padding: clamp(64px,9vw,110px) clamp(20px,5vw,72px);
}
/* ---- entrance transition -----------------------------------------
   Heading, filters, count line, and job cards all start invisible and
   rise/fade in the first time #collaborate is actually seen -- whether
   that's a normal scroll arrival or an instant cleanJumpTo() landing
   (js/script.js, IntersectionObserver-driven; see comment there). Gated
   behind .js-reveal, which JS only adds when it can also guarantee the
   reveal -- if JS fails or IntersectionObserver isn't supported, none of
   this applies and everything just renders visible immediately.

   Uses `animation` rather than `transition` deliberately: .collab-card
   already owns a `transition` shorthand for its hover state (transform/
   background/border-color/opacity, .25s). A second selector declaring
   `transition` for the same elements would replace that whole shorthand
   for as long as it matched, permanently slowing the hover feedback.
   `animation` doesn't have that collision -- it drives opacity/translate
   only while running, then gets out of the way (`forwards` fill keeps
   the end state), leaving the plain hover transition untouched. */
.collaborate.js-reveal .collab-head,
.collaborate.js-reveal .collab-filters,
.collaborate.js-reveal .collab-count,
.collaborate.js-reveal .collab-grid .collab-card{
  opacity:0;
}
.collaborate.js-reveal.is-in .collab-head{
  animation:collabRiseIn .7s cubic-bezier(.16,.8,.3,1) forwards;
}
.collaborate.js-reveal.is-in .collab-filters,
.collaborate.js-reveal.is-in .collab-count{
  animation:collabRiseIn .7s cubic-bezier(.16,.8,.3,1) .1s forwards;
}
.collaborate.js-reveal.is-in .collab-grid .collab-card{
  animation:collabRiseIn .6s cubic-bezier(.16,.8,.3,1) forwards;
  /* --i is set per-card by JS (capped) so cards cascade in left-to-right,
     top-to-bottom instead of all popping at once. */
  animation-delay:calc(.16s + var(--i, 0) * .06s);
}
@keyframes collabRiseIn{
  from{ opacity:0; translate:0 26px; }
  to  { opacity:1; translate:0 0; }
}
.collab-head{ max-width:640px; margin-bottom:40px; }
.collab-head .beat-eyebrow{ color:var(--gold); }
.collab-title-main{
  font-size:clamp(2rem,4.5vw,3.4rem);
  margin-bottom:16px;
}
.collab-sub{
  color:rgba(251,248,242,.72);
  line-height:1.6;
  font-size:1.02rem;
}
.collab-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(290px, 1fr));
  gap:18px;
  position:relative; /* containing block for the exit-transition's absolute positioning, see collaborate.js */
}
.collab-card{
  position:relative;
  display:flex;
  flex-direction:column;
  gap:12px;
  padding:24px 24px 20px;
  border-radius:22px;
  background:rgba(251,248,242,.06);
  border:1px solid rgba(251,248,242,.14);
  color:var(--paper);
  transition:transform .25s ease, background .25s ease, border-color .25s ease, opacity .25s ease;
}
.collab-card:hover{
  transform:translateY(-4px);
  background:rgba(251,248,242,.1);
  border-color:rgba(251,248,242,.28);
}
/* the filter script toggles the `hidden` attribute to show/hide cards, but
   `.collab-card` above sets `display:flex` with author-stylesheet priority,
   which silently wins over the browser's default `[hidden]{display:none}`
   rule (author styles always beat UA styles, regardless of specificity).
   Without this, cards never actually disappear — this is the fix. */
.collab-card[hidden]{ display:none; }
/* filter transition (see collaborate.js applyFilters): a card leaving the
   result set gets this class while it fades/shrinks in place (pinned via
   inline position:absolute at its last on-screen spot) before being hidden;
   cards staying visible get a FLIP transform to slide smoothly into their
   new grid slot instead of snapping there. */
.collab-card.card-exit{
  opacity:0;
  transform:scale(.95);
  pointer-events:none;
}
/* placeholder that fills the grid when a filter combination matches
   nothing, so the board doesn't suddenly collapse to zero height when
   every card hides -- occupies a full grid cell like a real card would. */
.collab-filter-empty{
  display:flex;
  align-items:center;
  justify-content:center;
  text-align:center;
  min-height:220px;
  padding:24px;
  border-radius:22px;
  border:1px dashed rgba(251,248,242,.3);
  color:rgba(251,248,242,.55);
  font-size:.95rem;
  line-height:1.5;
  grid-column: 1 / -1; /* span the full row so it doesn't just sit in one card-width column */
  opacity:0;
  transition:opacity .25s ease;
}
.collab-filter-empty.is-visible{ opacity:1; }
.collab-filter-empty[hidden]{ display:none; } /* same author-vs-UA precedence note as .collab-card[hidden] above */
/* whole card is clickable via a stretched cover link; the posted-by link
   sits above it */
.collab-cover{ position:absolute; inset:0; z-index:1; border-radius:22px; }
.collab-poster{ position:relative; z-index:2; }
.collab-topline{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:8px;
}
.collab-type{
  font-size:.72rem;
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--gold);
}
/* category + colour-coded difficulty labels */
.collab-cat{
  display:inline-flex;
  align-items:center;
  gap:7px;
  font-size:.7rem;
  font-weight:700;
  letter-spacing:.1em;
  text-transform:uppercase;
  padding:5px 12px 5px 10px;
  border-radius:999px;
  border:1px solid rgba(251,248,242,.2);
  background:rgba(251,248,242,.08);
  border:1px solid rgba(251,248,242,.22);
  /* solid --paper, not a translucent rgba(...,.9) -- the alpha version read
     as a dim, slightly warm/muddy grey against the dark card in practice
     ("the colour is off"), not the crisp near-white it measures as on
     paper. A fully opaque colour removes any ambiguity from how it
     composites against whatever's behind it. */
  color:var(--paper);
}
/* the category's little stroke icon */
.cat-ico{ flex:none; opacity:.8; }

/* icon glyph inside .collab-cat/.collab-status (event cards' location/date-
   time pills, see eventCard() in build-jobs.js) -- inline-flex above lines
   it up with the text on both; harmless everywhere else since text-only
   pills just render as before with no icon child to lay out. Full opacity,
   same reasoning as the text colour above -- a dimmed icon read as washed
   out next to genuinely bright UI elements elsewhere on the page. */
.tag-icon{ flex-shrink:0; }
/* difficulty: quiet tinted OUTLINE pill with a three-bar signal gauge
   (1 bar lit = low, 2 = moderate, 3 = high) instead of the loud solid
   traffic-light pills ("make them look sexier") */
/* difficulty: NAKED text + gauge, no pill chrome ("doesn't need to be
   in a pill") -- the tinted bars + word carry it */
.collab-diff{
  display:inline-flex;
  align-items:center;
  gap:7px;
  font-size:.7rem;
  font-weight:700;
  letter-spacing:.05em;
  text-transform:uppercase;
  padding:5px 0;
}
.diff-bars{ flex:none; }
.diff-bars rect{ fill:currentColor; opacity:.25; }
.diff-low{
  color:#7BD8A0;
}
.diff-low .diff-bars rect:nth-child(1){ opacity:1; }
.diff-moderate{
  color:#E8B45C;
}
.diff-moderate .diff-bars rect:nth-child(-n+2){ opacity:1; }
.diff-high{
  color:#F0937B;
}
.diff-high .diff-bars rect{ opacity:1; }
/* on LIGHT surfaces (job pages + job modal, both render jobMetaHtml into
   .job-meta on paper) the pale dark-band tints wash out: darker inks */
.job-meta .diff-low{ color:#2E7D4F; }
.job-meta .diff-moderate{ color:#9A6A1B; }
.job-meta .diff-high{ color:#B0402F; }
.collab-status{
  display:inline-flex;
  align-items:center;
  gap:5px;
  font-size:.7rem;
  font-weight:700;
  padding:5px 10px;
  border-radius:999px;
  background:rgba(36,30,26,.12);
  color:inherit;
}
/* .collab-status's dark-tint pill above reads fine on the light job/
   contributor pages it was designed for (.job-page, .contrib-jobs already
   fine-tune the exact alpha), but it's nearly invisible on the dark
   .collaborate sections that also use it -- the homepage board's job
   "Assigned/Completed" badge, and now the sc-ai-policy event cards' date/
   time pill. Give it the same light frosted treatment as .collab-cat
   whenever it's inside a dark .collaborate-classed section. */
.collaborate .collab-status{
  background:rgba(251,248,242,.18);
  border:1px solid rgba(251,248,242,.22);
  color:var(--paper);
}
.collab-meta{
  display:flex;
  flex-wrap:wrap;
  gap:6px 16px;
  font-size:.78rem;
  color:rgba(251,248,242,.65);
  /* pin deadline/closes to the bottom of the card as a group with .collab-foot,
     rather than letting it sit wherever the chips/summary above happen to end
     -- otherwise shorter cards (fewer tags, shorter summary) show it higher up
     than taller cards in the same row, which reads as it "jumping around". */
  margin-top:auto;
}
.collab-closes.is-urgent{ color:#F0A28A; font-weight:600; }
.collab-foot{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:10px;
  padding-top:12px;
  border-top:1px solid rgba(251,248,242,.12);
}
/* posted-by: avatar circle + name */
.collab-poster{
  display:inline-flex;
  align-items:center;
  gap:10px;
  text-decoration:none;
  color:inherit;
  border-radius:999px;
}
.collab-poster:hover .poster-name{ text-decoration:underline; }
.avatar{
  width:32px; height:32px;
  border-radius:50%;
  object-fit:cover;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  font-size:.72rem;
  font-weight:700;
  color:#fff;
  letter-spacing:.03em;
  flex:none;
}
.poster-meta{ display:flex; flex-direction:column; line-height:1.25; }
.poster-label{ font-size:.66rem; text-transform:uppercase; letter-spacing:.08em; opacity:.6; }
.poster-name{ font-size:.83rem; font-weight:600; }
.collab-title{
  font-family:var(--font-display);
  font-size:1.35rem;
  line-height:1.15;
}
.collab-summary{
  font-size:.92rem;
  line-height:1.55;
  color:rgba(251,248,242,.72);
}
.collab-chips, .job-chips{
  list-style:none;
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  padding:0;
  margin:2px 0 0;
}
.collab-chips li{
  padding:6px 12px;
  border-radius:999px;
  background:rgba(251,248,242,.1);
  border:1px solid rgba(251,248,242,.16);
  font-size:.75rem;
  font-weight:500;
  color:rgba(251,248,242,.85);
  /* single chips never blow up the row: ellipsise, full text on hover (title) */
  max-width:170px;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
  position:relative;      /* lift above .collab-cover so title tooltips work */
  z-index:2;
}
/* chip rows are clamped to one line by js/collaborate.js: overflowing chips
   hide behind a +N toggle */
.collab-chips li.chip-overflow{ display:none; }
.collab-chips.is-expanded li.chip-overflow{ display:block; }
.collab-chips li.chip-toggle-li{
  padding:0;
  background:none;
  border:none;
  overflow:visible;
  max-width:none;
}
.chip-toggle{
  padding:6px 11px;
  border-radius:999px;
  border:1px dashed rgba(251,248,242,.4);
  background:transparent;
  color:var(--gold);
  font:600 .75rem var(--font-body);
  cursor:pointer;
  transition:border-color .2s ease, background .2s ease;
}
.chip-toggle:hover{ border-color:var(--gold); }
.collab-chips.is-expanded .chip-toggle{
  background:var(--gold);
  border-style:solid;
  border-color:var(--gold);
  color:var(--ink);
  /* the label is just "×" now: a true circle, not a squat oblong pill */
  width:30px;
  height:30px;
  padding:0;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  border-radius:50%;
  line-height:1;
}
.collab-btn{
  margin-top:auto;
  padding:12px 20px;
  border-radius:999px;
  background:var(--paper);
  color:var(--ink);
  font-weight:600;
  font-size:.9rem;
  text-align:center;
  transition:background .2s ease;
}
.collab-card:hover .collab-btn{ background:#fff; }
.collab-btn{ margin-top:0; padding:10px 18px; }
.collab-empty{ color:rgba(251,248,242,.65); }

/* ---------------- collaborate filters ---------------- */
.collab-filters{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:10px;
  margin:0 0 14px;
  /* the entrance animation (opacity keyframes + forwards fill) makes this
     bar a STACKING CONTEXT, so the dropdown menus' z-index:30 only counts
     inside it -- and the cards' chips (z-index:2 at section level) painted
     over the open menus. Lifting the whole bar above the cards' small
     z-indexes fixes it. */
  position:relative;
  z-index:20;
}
.collab-filters[hidden]{ display:none; } /* same author-vs-UA precedence issue as .collab-card */
/* native selects are hidden by JS and replaced with .dd custom dropdowns
   so the open menu matches the site instead of the OS */
.dd{ position:relative; }
.dd-btn{
  position:relative;
  padding:10px 38px 10px 16px;
  border-radius:999px;
  border:1px solid rgba(251,248,242,.25);
  background:rgba(251,248,242,.08);
  color:var(--paper);
  font:500 .84rem var(--font-body);
  cursor:pointer;
  transition:border-color .2s ease, background .2s ease, color .2s ease;
}
.dd-btn::after{           /* chevron */
  content:"";
  position:absolute;
  right:16px; top:50%;
  width:7px; height:7px;
  margin-top:-5px;
  border-right:1.6px solid currentColor;
  border-bottom:1.6px solid currentColor;
  transform:rotate(45deg);
  transition:transform .2s ease, margin-top .2s ease;
}
.dd-btn[aria-expanded="true"]::after{ transform:rotate(225deg); margin-top:-1px; }
.dd-btn:hover{ border-color:rgba(251,248,242,.5); }
.dd-btn.is-set{            /* a filter is active */
  background:var(--gold);
  border-color:var(--gold);
  color:var(--ink);
  font-weight:600;
}
.dd-menu{
  position:absolute;
  top:calc(100% + 8px);
  left:0;
  z-index:30;
  min-width:100%;
  width:max-content;
  margin:0;
  padding:6px;
  list-style:none;
  background:var(--paper);
  color:var(--ink);
  border:1px solid var(--line);
  border-radius:16px;
  box-shadow:0 18px 44px rgba(0,0,0,.35);

  max-height:min(340px, 60vh); /* long org lists scroll INSIDE the menu, not the page */
  overflow-y:auto;
}
.dd-menu li{
  position:relative;
  padding:9px 16px 9px 32px;
  border-radius:10px;
  font-size:.86rem;
  font-weight:500;
  color:var(--ink-soft);
  white-space:nowrap;
  cursor:pointer;
}
.dd-menu li:hover,
.dd-menu li:focus{
  background:var(--cream-deep);
  color:var(--ink);
  outline:none;
}
.dd-menu li[aria-selected="true"]{ color:var(--ink); font-weight:600; }
.dd-menu li[aria-selected="true"]::before{   /* dark-green dot marker -- dd-menu bg is light (--paper) */
  content:"";
  position:absolute;
  left:14px; top:50%;
  width:7px; height:7px;
  transform:translateY(-50%);
  border-radius:50%;
  background:var(--forest);
}
/* flex-basis:100% forces the tag row onto its own line, independent of the
   dropdown row above it -- otherwise picking a shorter option (e.g. "Paid"
   instead of "All streams") changes that dd-btn's width, which reflows
   however many tag chips shared its row and can visibly shift chips from
   one wrapped line to another. Keeping tags on a dedicated row makes their
   own wrapping depend only on their own content, never on the dropdowns. */
.collab-tagbar{ display:flex; flex-wrap:wrap; gap:8px; flex-basis:100%; }
.collab-tag{
  padding:9px 14px;
  border-radius:999px;
  border:1px dashed rgba(251,248,242,.3);
  background:transparent;
  color:rgba(251,248,242,.75);
  font:500 .8rem var(--font-body);
  cursor:pointer;
  transition:background .2s ease, color .2s ease, border-color .2s ease;
}
.collab-tag:hover{ border-color:rgba(251,248,242,.55); }
.collab-tag.is-on{
  background:var(--gold);
  border-style:solid;
  border-color:var(--gold);
  color:var(--ink);
  font-weight:600;
}
.collab-clear{
  padding:9px 14px;
  border-radius:999px;
  border:none;
  background:transparent;
  color:var(--gold);
  font:600 .8rem var(--font-body);
  cursor:pointer;
  text-decoration:underline;
}
.collab-count{
  font-size:.82rem;
  color:rgba(251,248,242,.6);
  margin:0 0 14px;
}

/* ---------------- job/contributor page meta ---------------- */
.job-meta{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:8px;
  margin:2px 0 14px;
}
.job-page .collab-cat, .job-modal-panel .collab-cat{
  background:rgba(36,30,26,.08);
  border-color:rgba(36,30,26,.1); /* reset the dark-section border colour above for this light-bg context */
  color:var(--ink-soft);
}
/* sc-ai-policy's <body> carries the same shared `.job-page` wrapper class
   every generated page uses for its chrome (nav/footer/layout), even though
   the page itself has BOTH a light section (the intro) and dark ones
   (.persp-section, .participate -- both reuse .collaborate wholesale, see
   §3.2/event cards note). The light-bg override above doesn't know that --
   it just matches any `.collab-cat` under `.job-page`, so it was silently
   winning over the dark-section base rule inside the participate event
   cards (2 classes beats 1, regardless of which is "more correct" for that
   spot) and painting the location tag in --ink-soft brown on a dark card.
   This re-override, 3 classes deep, wins back the dark treatment
   specifically when a `.collab-cat` is inside a `.collaborate` section,
   even under a `.job-page` body. */
.job-page .collaborate .collab-cat, .job-modal-panel .collaborate .collab-cat{
  background:rgba(251,248,242,.18);
  border-color:rgba(251,248,242,.22);
  color:var(--paper);
}
.job-page .collab-stream, .job-modal-panel .collab-stream{
  font-size:.7rem;
  font-weight:700;
  letter-spacing:.1em;
  text-transform:uppercase;
  padding:5px 10px;
  border-radius:999px;
  border:1px solid var(--line);
  color:var(--ink-soft);
}
.job-dates{
  display:flex;
  flex-wrap:wrap;
  gap:6px 18px;
  font-size:.85rem;
  color:var(--ink-soft);
  margin:0 0 14px;
}
.job-dates strong{ font-weight:600; color:var(--ink); }
.job-page .collab-closes.is-urgent, .job-modal-panel .collab-closes.is-urgent{ color:#B0402F; }
.collab-poster.on-light{ color:var(--ink); margin:6px 0 4px; }
.btn.is-disabled{ opacity:.55; pointer-events:none; }

/* contributor pages */
.contrib-head{
  display:flex;
  align-items:center;
  gap:22px;
  margin-bottom:18px;
}
.avatar-xl{ width:84px; height:84px; font-size:1.5rem; }
.avatar-lg{ width:56px; height:56px; font-size:1.05rem; }

/* ---------------- contributors index page ---------------- */
.contrib-section .collab-head{ margin-bottom:26px; }
.contrib-filters{
  display:flex;
  flex-wrap:wrap;
  gap:10px;
  align-items:center;
  margin-bottom:18px;
}
.contrib-search{
  padding:10px 18px;
  border-radius:999px;
  border:1px solid rgba(251,248,242,.25);
  background:rgba(251,248,242,.08);
  color:var(--paper);
  font:500 .84rem var(--font-body);
  min-width:min(280px, 100%);
  outline:none;
  transition:border-color .2s ease, background .2s ease;
}
.contrib-search::placeholder{ color:rgba(251,248,242,.55); }
.contrib-search:focus{ border-color:rgba(251,248,242,.6); background:rgba(251,248,242,.12); }
.contrib-grid{
  display:grid;
  /* July 2026: was max-width:1180px + margin:0 auto, which left this
     section visibly narrower/indented than the DRISTI and Policy sections
     above it once all three lived on the same /contributors/ hub page.
     Dropped the cap so it spans the same full-bleed width as .collab-grid. */
  grid-template-columns:repeat(auto-fill, minmax(250px, 1fr));
  gap:14px;
}
/* same translucent card language as .collab-card, just smaller */
.contrib-card{
  display:flex;
  align-items:center;
  gap:14px;
  padding:16px 18px;
  border-radius:18px;
  background:rgba(251,248,242,.06);
  border:1px solid rgba(251,248,242,.14);
  color:var(--paper);
  text-decoration:none;
  transition:transform .25s ease, background .25s ease, border-color .25s ease;
}
.contrib-card:hover{
  transform:translateY(-4px);
  background:rgba(251,248,242,.1);
  border-color:rgba(251,248,242,.28);
}
/* the filter script toggles the `hidden` attribute, but display:flex above
   would silently win over the UA's [hidden]{display:none} -- same gotcha as
   .collab-card. Re-assert it. */
.contrib-card[hidden]{ display:none; }
.contrib-card-text{ display:flex; flex-direction:column; min-width:0; }
.contrib-card-name{
  font-family:var(--font-display);
  font-size:1.02rem;
  font-weight:600;
  line-height:1.25;
}
.contrib-card-role{
  font-size:.78rem;
  line-height:1.35;
  opacity:.75;
  margin-top:2px;
  display:-webkit-box;
  -webkit-line-clamp:2;
  -webkit-box-orient:vertical;
  overflow:hidden;
}
.contrib-card-org{
  font-size:.7rem;
  font-weight:600;
  text-transform:uppercase;
  letter-spacing:.08em;
  opacity:.55;
  margin-top:4px;
}
@media (max-width:640px){
  .contrib-grid{ grid-template-columns:1fr; }
  .contrib-search{ flex:1 1 100%; }
}
.contrib-sub{
  font-size:1.3rem;
  margin:36px 0 12px;
}
.contrib-jobs{
  list-style:none;
  padding:0;
  margin:0;
  display:flex;
  flex-direction:column;
  gap:10px;
}
.contrib-jobs li{
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  gap:10px;
  padding:14px 16px;
  border:1px solid var(--line);
  border-radius:14px;
  background:rgba(36,30,26,.03);
}
.contrib-jobs a{
  font-weight:600;
  color:var(--ink);
  text-decoration:none;
  margin-right:auto;
}
.contrib-jobs a:hover{ text-decoration:underline; }
.contrib-jobs .collab-status{
  background:rgba(36,30,26,.08);
  color:var(--ink-soft);
}

/* Same overflow:hidden trick as the job modal below, reused to hold the
   page in place for the ~1.7s "running in late" entrance -- see
   playLateEntrance() in js/script.js, triggered every time the active
   beat becomes 0. */

/* ---------------- job modal ---------------- */
body.modal-open{ overflow:hidden; }
/* scroll is held while a litigant walk-in plays (beat-0 entrance and the
   post-judge return) -- explicit request; js/script.js adds/removes it
   and every cancel path releases it. */
body.scroll-locked{ overflow:hidden; }
/* THE OVERLAY SCROLLS, NOT THE PANEL. When the rounded panel was its own
   scroll container, macOS rubber-band made WebKit/Blink drop the
   border-radius clip for a frame (square corners flashing) -- layer hacks
   (translateZ, mask) didn't fully cure it. With the scrolling on the
   transparent overlay, the panel just moves bodily during the bounce and
   its corners never clip anything. */
.job-modal{
  position:fixed; inset:0; z-index:100;
  overflow-y:auto;
  overscroll-behavior:contain;
  /* slim, unobtrusive scrollbar (was on the panel) */
  scrollbar-width:thin;
  scrollbar-color:rgba(36,30,26,.22) transparent;
}
.job-modal-backdrop{
  position:fixed; inset:0; /* fixed: keeps covering the viewport while the overlay scrolls */
  background:rgba(24,34,56,.55);
  backdrop-filter:blur(4px);
}
.job-modal-panel{
  position:relative;
  margin:3.5vh auto;
  width:min(860px, calc(100vw - 32px));
  background:var(--paper);
  color:var(--ink);
  border-radius:22px;
  padding:clamp(28px,4.5vw,56px);
  box-shadow:0 30px 80px rgba(0,0,0,.35);
}
.job-modal::-webkit-scrollbar{ width:6px; }        /* Chrome/Safari */
.job-modal::-webkit-scrollbar-track{ background:transparent; margin:22px 0; }
.job-modal::-webkit-scrollbar-thumb{
  background:rgba(36,30,26,.18);
  border-radius:99px;
}
.job-modal::-webkit-scrollbar-thumb:hover{ background:rgba(36,30,26,.32); }
.job-modal-close{
  position:absolute;
  top:16px; right:18px;
  width:38px; height:38px;
  border-radius:50%;
  border:1px solid var(--line);
  background:var(--cream);
  font-size:1.2rem;
  line-height:1;
  cursor:pointer;
  color:var(--ink-soft);
}
.job-modal-close:hover{ background:var(--cream-deep); }

/* ---------------- job page + shared job styles ---------------- */
.job-main{
  max-width:720px;
  margin:0 auto;
  padding:130px clamp(20px,5vw,40px) 90px;
}
.job-title{
  font-size:clamp(1.7rem,3.6vw,2.6rem);
  margin:6px 0 14px;
}
.job-summary{
  font-size:1.08rem;
  line-height:1.6;
  color:var(--ink-soft);
  margin-bottom:16px;
}
.job-chips li{
  padding:6px 12px;
  border-radius:999px;
  background:rgba(36,30,26,.05);
  border:1px solid var(--line);
  font-size:.75rem;
  font-weight:500;
  color:var(--ink-soft);
}
.job-body{ margin-top:22px; }
.job-body h2,.job-body h3,.job-body h4{
  margin:26px 0 10px;
  font-size:1.25rem;
}
.job-body p,.job-body li{
  line-height:1.65;
  color:var(--ink-soft);
  font-size:.98rem;
}
.job-body ul,.job-body ol{ padding-left:22px; margin:10px 0; }
.job-body a{ color:var(--forest); } /* dark-green -- job page/modal are both light-bg surfaces */

/* ---------------- long-form "prose" treatment ----------------
   Editorial pages (about, sc-ai-policy intro) add .prose to .job-body:
   drop cap on the opening paragraph, a larger lede, a calmer measure and
   rhythm, and headings set in the display face with a short rule. */
/* editorial pages get a wider column than job pages (the site already
   leans on :has() elsewhere, so this is safe) */
.job-main:has(.job-body.prose),
.job-main:has(.about-what){ max-width:880px; } /* About's top main lost its .prose block in the mission-statement redesign and collapsed to 720px ("too crammed") */
.job-body.prose{ max-width:none; }
.job-body.prose p{
  font-size:1.05rem;
  line-height:1.8;
  margin:0 0 1.25em;
}
.job-body.prose p:first-of-type{
  font-size:1.16rem;
  line-height:1.75;
  color:var(--ink);
}
.job-body.prose p:first-of-type::first-letter{
  float:left;
  font-family:var(--font-display);
  font-weight:600;
  font-size:3.4em;
  line-height:.82;
  padding:6px 12px 0 0;
  color:var(--forest);
}
.job-body.prose h2{
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.5rem;
  margin:44px 0 14px;
}
.job-body.prose h2::after{
  content:"";
  display:block;
  width:44px;
  height:3px;
  margin-top:10px;
  border-radius:2px;
  background:var(--green);
}
.job-body.prose strong{ color:var(--ink); }
/* the drop cap is a nice opener once per page, not once per <article> --
   About (below) splits its prose into two separate .prose blocks around
   the step-card grid, and a second giant drop cap on a single short
   paragraph ("How we organise") reads as too much. .no-cap opts a later
   block out while keeping everything else about .prose (h2 styling,
   larger lede size, etc). */
.job-body.prose.no-cap p:first-of-type::first-letter{
  all:unset;
}

/* ---------------- About page: stat strip + process cards + photo strip ----
   Jul 2026: the page was a single unbroken prose column ("can use a better
   layout that looks more visual" -- user feedback). These three blocks
   (aboutPage() in build-jobs.js) break it up without inventing new copy. */
/* stats sit in a forest gradient panel (same family as .civis-callout):
   paper numbers pop on dark, and the page gets an early hit of the site's
   dark palette instead of opening as an unbroken cream column */
.about-stats{
  display:flex;
  flex-wrap:wrap;
  gap:28px clamp(36px,6vw,72px);
  margin:18px 0 40px;
  padding:clamp(22px,3.5vw,34px) clamp(24px,4vw,44px);
  border-radius:22px;
  background:
    radial-gradient(120% 160% at 85% -20%, rgba(94,226,160,.25), transparent 55%),
    linear-gradient(135deg, var(--forest), #1C3540);
  box-shadow:0 20px 50px rgba(17,31,38,.22);
}
.about-stat{ display:flex; flex-direction:column; }
.about-stat-num{
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(2rem, 4.2vw, 2.8rem);
  color:var(--paper);
  line-height:1;
}
.about-stat-label{
  margin-top:7px;
  font-size:.75rem;
  font-weight:600;
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--green);
}

/* "What we do" mission statement: display type, no drop cap, distinct from
   every other page's article prose */
.about-what{ margin:14px 0 8px; }
.about-what .beat-eyebrow{ color:var(--forest); }
.about-what-statement{
  margin:14px 0 22px;
  font-family:var(--font-display);
  font-weight:500;
  font-size:clamp(1.45rem,3vw,2.05rem);
  line-height:1.42;
  color:var(--ink);
  /* fills the 880px column: the earlier 26ch cap broke lines every few
     words and read cramped */
}
.about-what-statement em{
  font-style:normal;
  color:var(--forest);
  text-decoration:underline;
  text-decoration-color:var(--green);
  text-decoration-thickness:3px;
  text-underline-offset:5px;
}
.about-what-support{
  margin:0;
  font-size:1.05rem;
  line-height:1.75;
  color:var(--ink-soft);
  max-width:66ch;
}

/* full-bleed "Why PUCAR?" band: cream<->forest rhythm for the About page */
.about-why{
  background:
    radial-gradient(70% 120% at 15% 110%, rgba(94,226,160,.14), transparent 60%),
    var(--forest);
  color:var(--paper);
  padding:clamp(56px,8vw,96px) clamp(20px,5vw,72px);
  /* no margins: the parallax bands sit flush above AND below */
}
.about-why-inner{ max-width:880px; margin:0 auto; }
/* one deliberate hierarchy instead of two competing treatments ("text is
   treated differently for 2 paragraphs, looks odd"): the problem statement
   is a muted lede sharing the same full measure as the quote below, and the
   "Born in 2023" line is the band's single display moment. */
.about-why-lede{
  margin:18px 0 30px;
  font-size:clamp(1.05rem,1.6vw,1.2rem);
  line-height:1.75;
  color:rgba(251,248,242,.78);
}
.about-why-pull{
  margin:0;
  font-family:var(--font-display);
  font-weight:500;
  font-size:clamp(1.35rem,2.6vw,1.85rem);
  line-height:1.45;
}
.about-why-pull em{
  font-style:normal;
  color:var(--green);
}
.about-lower{ padding-top:clamp(40px,6vw,64px); }
/* the heading-only prose wrapper (no <p> inside, see aboutPage()) still
   gets the h2 rule's margin-top -- give it a touch less bottom margin than
   a real prose block since a card grid follows immediately, not a lede
   paragraph that wants breathing room. */
.about-steps-head h2{ margin-bottom:4px; }
.about-steps{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(220px, 1fr));
  gap:18px;
  margin:18px 0 44px;
}
.about-step{
  position:relative;
  padding:26px 22px 22px;
  border-radius:18px;
  background:var(--paper);
  border:1px solid var(--line);
  transition:transform .2s ease, box-shadow .2s ease;
}
.about-step:hover{
  transform:translateY(-3px);
  box-shadow:0 14px 30px rgba(36,30,26,.08);
}
.about-step-num{
  display:block;
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.8rem;
  color:var(--green-soft);
  -webkit-text-stroke:1.5px var(--forest);
  /* Fx/older Safari fallback where text-stroke isn't supported: still a
     legible solid numeral, just without the outlined-numeral flourish. */
  margin-bottom:8px;
}
@supports not (-webkit-text-stroke: 1px black){
  .about-step-num{ color:var(--forest); }
}
.about-step h3{
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.08rem;
  margin-bottom:8px;
  color:var(--ink);
}
.about-step p{
  font-size:.92rem;
  line-height:1.55;
  color:var(--ink-soft);
}
/* reuse the homepage's .collab-strip component wholesale (same fanning
   photo stack, same button) but as a fully-clickable card with rounded
   corners instead of a full-bleed page-width bridge, since here it sits
   inside the contained .job-main column. .strip-btn becomes a <span> (an
   <a> can't nest inside another <a>) and lifts on ANY hover over the card,
   not just its own hover, since the whole thing is now one target. */
/* About-page copy of the strip: compact enough for the 880px column so it
   never wraps into the broken two-row state; a gentler fan that stays
   inside the rounded card; and a proper rounded focus ring instead of the
   UA outline (which traced the transformed heads and looked shattered). */
a.about-strip{
  display:flex;
  border-radius:20px;
  margin:8px 0 40px;
  text-decoration:none;
  padding:16px clamp(18px,3vw,28px);
  gap:12px 20px;
  outline:none;
}
a.about-strip:focus-visible{
  box-shadow:0 0 0 3px var(--green);
}
.about-strip .strip-text{ font-size:.95rem; }
.about-strip .strip-head{ width:38px; height:38px; margin-left:-12px; }
.about-strip .strip-head:first-child{ margin-left:0; }
.about-strip .strip-wave{ font-size:16px; }
.about-strip .strip-btn{ padding:10px 18px; font-size:.88rem; }
.about-strip .strip-group{ gap:14px; flex-wrap:nowrap; }
/* gentler fan: the big homepage distances pushed the first head clean out
   of this card's rounded corner */
.about-strip:hover .strip-head:nth-child(1){ transform:translateX(-24px); }
.about-strip:hover .strip-head:nth-child(2){ transform:translateX(-20px); }
.about-strip:hover .strip-head:nth-child(3){ transform:translateX(-16px); }
.about-strip:hover .strip-head:nth-child(4){ transform:translateX(-12px); }
.about-strip:hover .strip-head:nth-child(5){ transform:translateX(-8px); }
.about-strip:hover .strip-head:nth-child(6){ transform:translateX(-4px); }
.about-strip:hover .strip-btn{
  translate:0 -2px;
  box-shadow:0 12px 26px rgba(94,226,160,.42), inset 0 1px 0 rgba(255,255,255,.35);
}
.job-page{ background:var(--cream); }
/* sticky footer: short pages (e.g. contributor profiles) should never show
   background below the footer -- main stretches, footer hugs the bottom */
.job-page{
  min-height:100vh;
  min-height:100svh;
  display:flex;
  flex-direction:column;
}
.job-page .job-main{ flex:1 0 auto; width:100%; }
.job-page .site-footer{ margin-top:auto; }
.job-page .cta-row{ margin-top:34px; }
.btn-outline{
  border:1px solid var(--line);
  color:var(--ink);
}
.btn-outline:hover{ background:rgba(36,30,26,.06); }

/* ---------------- /sc-ai-policy/ page ----------------
   The perspectives section reuses .collaborate + .collab-card wholesale
   (cards "styled exactly like our collaborate cards"); only additions
   live here: the participate section and its event cards. */
.persp-section .collab-grid{ grid-template-columns:repeat(auto-fill, minmax(300px, 1fr)); }
/* pin the bottom group (tags + divider + button) to the card bottom: the
   auto margin goes on the CHIPS so they hug the divider, not the summary */
.persp-card .collab-chips{ margin-top:auto; }
.persp-card .collab-foot{ justify-content:flex-start; }
/* outlet sits alone on the topline now (the type chip is gone): right-align */
.persp-card .collab-topline{ justify-content:flex-end; }

.participate-title{
  color:var(--paper);
  font-size:clamp(1.8rem,3.8vw,2.9rem);
  margin-bottom:8px;
}
.participate-grid{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(300px, 1fr));
  gap:18px;
  margin-top:28px;
  align-items:stretch;
}
/* event cards: literally .collab-card (frosted panel on the dark section,
   shared hover lift) rendered as ONE BIG LINK; only the extras live here */
a.event-card{ text-decoration:none; }
.event-venue{
  font-size:.82rem;
  font-weight:600;
  color:rgba(251,248,242,.75);
}
.event-card .collab-foot{
  margin-top:auto;
  justify-content:flex-start;
}
.event-card:hover .collab-btn{ background:#fff; }

/* ---------------- footer ---------------- */
.site-footer{
  background:#000;
  color:rgba(251,248,242,.8);
  padding:64px clamp(20px,5vw,72px) 32px;
  /* blurb left, sitemap right, copyright full-width below */
  display:grid;
  grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);
  gap:24px clamp(32px,6vw,96px);
  align-items:start;
}
@media (max-width:860px){
  .site-footer{ grid-template-columns:1fr; }
}
.footer-copy{ grid-column:1 / -1; }
/* a real 2x2 GRID, not flex-wrap: wrapped flex rows re-centre themselves,
   so the second row's columns didn't line up with the first's */
.footer-map{
  display:grid;
  grid-template-columns:repeat(2, minmax(150px, 1fr));
  gap:34px clamp(28px,4vw,56px);
}
@media (max-width:480px){ .footer-map{ grid-template-columns:1fr; } }
.footer-col{ display:flex; flex-direction:column; gap:9px; min-width:130px; }
.footer-col-title{
  margin:0 0 4px;
  font-size:.68rem;
  font-weight:700;
  letter-spacing:.13em;
  text-transform:uppercase;
  color:var(--green);
}
.footer-col a{
  text-decoration:none;
  font-size:.85rem;
  color:rgba(251,248,242,.72);
  transition:color .18s ease;
}
.footer-col a:hover{ color:var(--paper); }
/* live-mission links carry the pulsing green orb */
.footer-live-link{
  display:inline-flex;
  align-items:center;
  gap:8px;
}
.footer-live-link .board-live{ flex:none; width:8px; height:8px; }

.footer-top{ max-width:640px; }
.footer-top .logo{ display:block; height:22px; width:auto; margin-bottom:2px; }
.footer-top .logo-short{ display:none; }
@media (max-width: 640px){
  .footer-top .logo-long{ display:none; }
  .footer-top .logo-short{ display:block; }
}
.footer-top p{ margin-top:14px; font-size:.92rem; line-height:1.6; color:rgba(251,248,242,.6); }
/* social icons under the blurb: GitHub / YouTube / LinkedIn */
.footer-social{ display:flex; gap:10px; margin-top:20px; }
.footer-social a{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:38px;
  height:38px;
  border-radius:50%;
  border:1px solid rgba(251,248,242,.22);
  color:rgba(251,248,242,.72);
  transition:background .2s ease, color .2s ease, border-color .2s ease;
}
.footer-social a:hover{
  background:var(--green);
  border-color:var(--green);
  color:var(--ink);
}
/* .footer-links retired: replaced by the categorised .footer-map sitemap */
.footer-links a:hover{ color:var(--gold); }
.footer-copy{ font-size:.75rem; color:rgba(251,248,242,.4); border-top:1px solid rgba(251,248,242,.12); padding-top:20px; }
/* the Agami/Vayam attribution sits with the copyright, one notch brighter */
.footer-legal{
  display:inline-block;
  margin-bottom:6px;
  color:rgba(251,248,242,.55);
  line-height:1.55;
  max-width:72ch;
}
.footer-legal a{ color:rgba(251,248,242,.78); text-decoration:none; border-bottom:1px solid rgba(251,248,242,.3); }
.footer-legal a:hover{ color:var(--paper); border-color:var(--paper); }

/* ---------------- reduced motion ---------------- */
@media (prefers-reduced-motion: reduce){
  .litigant .fig, .litigant .leg-front, .litigant .leg-back,
  .litigant .arm-left, .litigant .arm-right, .litigant .head,
  .judge .gavel, .speech-bubble,
  .board-note, .board-live, .btn-arrow, .orbit,
  .ground-dots, .path, .shadow, .scroll-cue{ animation:none !important; }
  .queue-fig, .judge-stage, #litigant{ transition:none !important; }
  .pin.is-judge-exit .judge-stage, .judge-dust i{ animation:none !important; }
  /* Collaborate entrance: skip the animation but keep the .js-reveal
     opacity:0 rule from ever winning -- just show everything at rest
     rather than leaving it stuck invisible with nothing to trigger it. */
  .collaborate.js-reveal .collab-head,
  .collaborate.js-reveal .collab-filters,
  .collaborate.js-reveal .collab-count,
  .collaborate.js-reveal .collab-grid .collab-card{ opacity:1; }
  .collaborate.js-reveal.is-in .collab-head,
  .collaborate.js-reveal.is-in .collab-filters,
  .collaborate.js-reveal.is-in .collab-count,
  .collaborate.js-reveal.is-in .collab-grid .collab-card{ animation:none !important; }
}

/* ---------------- mobile ---------------- */
@media (max-width: 860px){
  .pin{
    grid-template-columns:1fr;
    grid-template-rows: auto 1fr;
    padding-top: 90px;
  }
  .litigant-stage{
    grid-column:1;
    grid-row:1;
    width:clamp(110px,30vw,150px);
    align-self:start;
    margin-top:4px;
  }
  .judge-stage{
    grid-column:1;
    grid-row:1;
    width:clamp(120px,32vw,170px);
    align-self:start;
    /* pushed DOWN so his balloon has real headroom above him instead of
       being squashed into (and behind) his head */
    margin-top:104px;
  }
  /* single column on mobile: keep the litigant put, no side→centre slide,
     and no desktop midline lift. NOTE: only `translate` is force-reset on
     the stage now -- its `transform` carries the film-break curtain ride,
     which mobile needs too (the old inline-transform reason for resetting
     it is gone; the walker owns that and keeps its own reset). */
  .pin[data-beat] .litigant-stage{ translate:none !important; }
  .pin[data-beat] .litigant-walker{ transform:none !important; }

  /* speech bubbles: the stage keeps its justify-self:center on mobile, so
     the figure sits mid-viewport -- CENTRE the balloon on the stage
     (= centred on the phone screen; the earlier left-edge anchor ran too
     far right on long lines). Sizing comes from width:max-content on the
     base rule (an abs box would otherwise shrink-wrap to the sliver of
     stage after `left`), capped to the viewport. Both translate STATES
     need overriding (this media block is later in the file, so its
     hidden-state translate would win even while visible). */
  .speech-bubble{
    /* EXPLICIT width on phones, not max-content+cap: Safari lays the box
       out at one-line height when max-content exceeds the cap, spilling
       wrapped text out of the drawn paper (the recurring judge bug) */
    width:min(240px, calc(100vw - 48px));
    max-width:none;
    font-size:.84rem;
    line-height:1.4;
    padding:11px 14px;
    left:50%;
    top:-4px;
    translate:-50% 8px;
  }
  .speech-bubble.is-visible{ translate:-50% 0; }
  /* tail: dead-centre, pointing at the head right below */
  .speech-bubble::after{ left:calc(50% - 9px); }

  /* the judge's bubble: same centring, sitting in the headroom the
     stage's margin-top:72px just opened up. A NARROWER cap on purpose:
     at max-content his one-liner rendered as an unreadable edge-to-edge
     strip -- capping at ~220px wraps it into a proper two-line balloon,
     and the type goes back up to something readable */
  /* the judge's balloon is HIDDEN on phones (explicit call: after four
     rounds of WebKit mis-measuring it, "if you can't fix it on phone,
     just hide it") -- the desktop balloon is untouched */
  .judge-bubble{ display:none !important; }

  /* buttons + pill tags inside the animated story get a frosted
     semi-opaque backing on phones only, so drifting heads and artwork
     behind them never hurt readability (all in-story CTAs/pills sit on
     the dark beats) */
  .pin .btn-ghost,
  .pin .value-chips li{
    background:rgba(10,21,26,.55);
    backdrop-filter:blur(8px);
    -webkit-backdrop-filter:blur(8px);
  }
  .pin .btn-primary{
    box-shadow:0 6px 22px rgba(10,21,26,.45);
  }
  /* the judge's balloon must sit ABOVE his head and hard-wrap inside its
     drawn paper, whatever the engine thinks max-content means */
  .judge-bubble{
    z-index:8;
    box-sizing:border-box;
    white-space:normal;
    overflow-wrap:break-word;
  }
  /* floating heads: decorative only on phones -- never above content,
     never tappable (one sat on the Learn-about button and ate the tap) */
  .hi-stream{ z-index:1; }
  .hi-bubble{ pointer-events:none !important; }
  .beats{
    grid-column:1;
    grid-row:2;  /* mobile really IS two rows (figure above, text below) -- undo the desktop grid-row:1 */
    /* text hugs the BOTTOM whenever the litigant sits on top: top-aligned
       it collided with the figure's animations (walks, bubbles) spilling
       into the lower half */
    align-items:flex-end;
    /* ONE mobile gutter everywhere: 20px, same as .collaborate/.intro-hero
       (was 6vw, which drifted a few px off every other section's edge) */
    padding: 24px 20px 100px;
  }
  .beat{
    position:absolute;
    max-width:none;
  }
  .beat-title{ font-size:clamp(1.6rem,6vw,2.2rem); }
  .beat-stat{ font-size:clamp(2.6rem,14vw,4rem); }
  .initiative-grid{ grid-template-columns:1fr; }
  .progress-rail{ right:16px; bottom:16px; }
  .progress-track{ width:70px; }
}

@media (max-width: 480px){
  .beat-body{ font-size:.95rem; }
}

/* ---------------- cards <-> list view toggle ----------------
   js/view-toggle.js mounts .view-toggle into each section's filter bar
   (or a .view-toggle-rail above the grid) and flips .is-list on the grid.
   Choice persists per grid in localStorage. All grids sit on dark
   sections, so one colour family works everywhere. */
.view-toggle{
  display:inline-flex;
  gap:2px;
  padding:3px;
  border-radius:999px;
  border:1px solid rgba(251,248,242,.25);
  background:rgba(251,248,242,.08);
  margin-left:auto; /* pushes to the right end of the filter bar */
  /* the filter bars are flex rows with default stretch: without this the
     pill stretches to the tallest sibling and the fixed-height buttons
     leave a dead strip at the bottom (and the rounding stops matching) */
  align-self:center;
}
/* on the data section's tab row: lift off the baseline track so the pill
   floats beside the tabs instead of sitting on the underline */
.res-tabbar .view-toggle{ margin-bottom:8px; }
.view-toggle-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:32px; height:28px;
  border:0;
  border-radius:999px;
  background:transparent;
  color:rgba(251,248,242,.6);
  cursor:pointer;
  transition:background .2s ease, color .2s ease;
}
.view-toggle-btn:hover{ color:var(--paper); }
.view-toggle-btn.is-active{
  background:var(--green);
  color:var(--forest);
}
.view-toggle-rail{
  display:flex;
  justify-content:flex-end;
  max-width:1180px;
  margin:0 auto 14px;
}

/* ---- list mode: work + perspective cards become compact rows ---- */
.collab-grid.is-list{
  display:flex;
  flex-direction:column;
  gap:10px;
}
.collab-grid.is-list .collab-card{
  flex-direction:row;
  align-items:center;
  flex-wrap:wrap;
  gap:8px 16px;
  padding:14px 20px;
  border-radius:14px;
}
/* hide the card-only furniture in rows */
.collab-grid.is-list .collab-summary,
.collab-grid.is-list .collab-chips,
.collab-grid.is-list .collab-meta,
.collab-grid.is-list .collab-poster{ display:none; }
.collab-grid.is-list .collab-title{
  order:1;
  flex:1 1 320px;
  min-width:0;
  font-size:1.02rem;
  margin:0;
}
.collab-grid.is-list .collab-type{ order:2; margin:0; }
.collab-grid.is-list .collab-topline{ order:3; margin:0; gap:8px; width:auto; }
.collab-grid.is-list .collab-foot{
  order:4;
  border-top:0;
  padding-top:0;
  margin:0;
  margin-left:auto;
  width:auto;
  flex:none;
}
.collab-grid.is-list .collab-btn{ padding:8px 14px; font-size:.8rem; }

/* ---- list mode: contributors become one full-width row per person ---- */
.contrib-grid.is-list{ grid-template-columns:1fr; gap:8px; }
.contrib-grid.is-list .contrib-card{
  flex-direction:row;
  border-radius:14px;
  padding:10px 18px;
}
.contrib-grid.is-list .contrib-card .avatar-lg{ width:40px; height:40px; font-size:.85rem; }
.contrib-grid.is-list .contrib-card-text{
  flex-direction:row;
  align-items:baseline;
  gap:14px;
  flex:1;
  min-width:0;
}
.contrib-grid.is-list .contrib-card-name{ flex:0 0 220px; }
.contrib-grid.is-list .contrib-card-role{
  -webkit-line-clamp:1;
  margin:0;
  flex:1;
}
.contrib-grid.is-list .contrib-card-org{ margin:0; margin-left:auto; text-align:right; }

@media (max-width:640px){
  /* rows don't fit a phone: quietly fall back to cards */
  .view-toggle{ display:none; }
  .collab-grid.is-list .collab-card{ flex-direction:column; align-items:stretch; }
  .contrib-grid.is-list .contrib-card-text{ flex-direction:column; gap:2px; }
  .contrib-grid.is-list .contrib-card-org{ margin-left:0; text-align:left; }
}

/* ---------------- beat 9: waving contributor heads ----------------
   js/script.js spawns .hi-bubble elements into #hiStream while beat 9 is
   active: each drifts left->right (Web Animations API on the bubble:
   translateX + scale .12 -> 1, so they enter tiny and grow to 100px),
   while the inner .hi-bob adds the sine bob and the emoji waves on loop.
   z-index 4: over the film curtains (3), under the stages (5) and text (6).
   Not interactive by design -- pointer-events:none on the whole layer. */
.hi-stream{
  position:absolute;
  inset:0;
  z-index:4;
  overflow:hidden;
  pointer-events:none;
}
.hi-bubble{
  position:absolute;
  left:0;
  width:100px;
  height:100px;
  will-change:transform;
}
.hi-bob{
  width:100%;
  height:100%;
  position:relative;
  animation:hiBob 2.6s ease-in-out infinite alternate;
}
@keyframes hiBob{
  from{ translate:0 -16px; }
  to{ translate:0 16px; }
}
.hi-bubble img{
  width:100%;
  height:100%;
  border-radius:50%;
  object-fit:cover;
  border:3px solid rgba(251,248,242,.4);
  box-shadow:0 12px 28px rgba(0,0,0,.4);
  display:block;
}
.hi-wave{
  position:absolute;
  left:-10px; /* left of the face: the emoji's palm angle reads as a hand reaching out of the photo */
  bottom:-6px;
  font-size:38px;
  line-height:1;
  transform-origin:70% 85%;
  animation:hiWave .9s ease-in-out infinite;
  filter:drop-shadow(0 2px 4px rgba(0,0,0,.3));
}
/* continuous wave: no rest phase, just a smooth back-and-forth */
@keyframes hiWave{
  0%{ transform:rotate(-8deg); }
  50%{ transform:rotate(26deg); }
  100%{ transform:rotate(-8deg); }
}

/* ---- hover on a waving head: stylised name/org tooltip; the head slows
   down (playbackRate, in js/script.js) but never stops ---- */
.hi-bubble{ pointer-events:auto; cursor:pointer; }
.hi-bubble:hover img,
.hi-bubble:focus-visible img{ border-color:var(--green); }
.hi-bubble:focus-visible{ outline:none; }
.hi-tip{
  position:absolute;
  bottom:calc(100% + 12px);
  left:50%;
  translate:-50% 4px;
  background:var(--paper);
  color:var(--ink);
  border-radius:12px;
  padding:8px 14px;
  white-space:nowrap;
  text-align:center;
  box-shadow:0 14px 30px rgba(0,0,0,.35);
  opacity:0;
  transition:opacity .18s ease, translate .18s ease;
  pointer-events:none;
}
.hi-tip::after{ /* little pointer */
  content:"";
  position:absolute;
  top:100%;
  left:50%;
  translate:-50% 0;
  border:6px solid transparent;
  border-top-color:var(--paper);
}
.hi-tip-name{
  display:block;
  font-weight:700;
  font-size:.86rem;
  line-height:1.3;
}
.hi-tip-org{
  display:block;
  font-size:.7rem;
  font-weight:600;
  text-transform:uppercase;
  letter-spacing:.07em;
  opacity:.6;
}
.hi-bubble.is-hover .hi-tip{ opacity:1; translate:-50% 0; }

/* ---------------- /sc-ai-policy/: CIVIS callout ---------------- */
.civis-callout{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:22px 36px;
  margin-top:40px;
  padding:clamp(26px,4vw,40px);
  border-radius:22px;
  background:
    radial-gradient(120% 160% at 85% -20%, rgba(94,226,160,.28), transparent 55%),
    linear-gradient(135deg, var(--forest), #1C3540);
  color:var(--paper);
  box-shadow:0 24px 60px rgba(17,31,38,.28);
}
.civis-callout-text{ flex:1 1 340px; min-width:0; }
.civis-kicker{
  margin:0 0 6px;
  font-size:.7rem;
  font-weight:700;
  text-transform:uppercase;
  letter-spacing:.14em;
  color:var(--green);
}
.civis-title{
  margin:0 0 10px;
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(1.3rem,2.6vw,1.7rem);
  line-height:1.25;
}
.civis-sub{
  margin:0;
  font-size:.95rem;
  line-height:1.6;
  color:rgba(251,248,242,.8);
  max-width:52ch;
}
.civis-callout-action{ flex:0 0 auto; text-align:center; }
.civis-btn{
  display:inline-flex;
  align-items:center;
  gap:10px;
  padding:16px 30px;
  border-radius:999px;
  background:var(--green);
  color:var(--forest);
  font-weight:700;
  font-size:1.02rem;
  text-decoration:none;
  box-shadow:0 10px 26px rgba(94,226,160,.35), inset 0 1px 0 rgba(255,255,255,.35);
  transition:translate .2s ease, box-shadow .2s ease;
}
.civis-btn:hover{
  translate:0 -2px;
  box-shadow:0 16px 34px rgba(94,226,160,.45), inset 0 1px 0 rgba(255,255,255,.35);
}
.civis-btn-arrow{ transition:translate .2s ease; }
.civis-btn:hover .civis-btn-arrow{ translate:4px 0; }
.civis-count{
  margin:12px 0 0;
  font-size:.82rem;
  color:rgba(251,248,242,.75);
}
.civis-count::before{
  content:"";
  display:inline-block;
  width:7px; height:7px;
  border-radius:50%;
  background:var(--green);
  margin-right:7px;
  vertical-align:1px;
}
@media (max-width:640px){
  .civis-callout-action{ flex:1 1 100%; text-align:left; }
}

/* ---------------- policy section: /contributors/ Policy band ----------------
   A FULL-BLEED dark section (revised: it shipped as a rounded card floating
   in a cream band and the user vetoed that -- "it was supposed to be the
   whole section"). The forest gradient covers the whole band edge to edge;
   the callout inside is just a centered flex layout, no card chrome. */
.policy-band{
  padding:clamp(64px,9vw,110px) clamp(20px,5vw,72px);
  background:
    radial-gradient(120% 160% at 85% -20%, rgba(94,226,160,.28), transparent 55%),
    linear-gradient(135deg, var(--forest), #1C3540);
  color:var(--paper);
}
.policy-callout{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:26px clamp(36px,6vw,84px);
  max-width:1180px;
  margin:0 auto;
}
.policy-callout-text{ flex:1 1 320px; min-width:0; }
.policy-kicker{
  margin:0 0 6px;
  font-size:.7rem;
  font-weight:700;
  text-transform:uppercase;
  letter-spacing:.14em;
  color:var(--green);
}
.policy-title{
  margin:0 0 10px;
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(1.6rem,3.4vw,2.5rem); /* section-scale, not card-scale */
  line-height:1.2;
  max-width:22ch;
}
.policy-sub{
  margin:0 0 18px;
  font-size:.92rem;
  line-height:1.6;
  color:rgba(251,248,242,.78);
  max-width:52ch;
}
.policy-countdown{
  flex:0 0 auto;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:5px;
  min-width:168px;
  padding:20px 26px;
  border-radius:18px;
  background:rgba(251,248,242,.08);
  border:1px solid rgba(251,248,242,.18);
  text-align:center;
}
.policy-countdown.is-urgent{
  background:rgba(240,162,138,.14);
  border-color:rgba(240,162,138,.4);
}
.policy-countdown-num{
  font-family:var(--font-display);
  font-size:clamp(2.2rem,4vw,2.8rem);
  font-weight:700;
  line-height:1;
  color:var(--green);
}
.policy-countdown.is-urgent .policy-countdown-num{ color:#F0A28A; }
.policy-countdown-label{
  font-size:.72rem;
  font-weight:700;
  text-transform:uppercase;
  letter-spacing:.09em;
  color:rgba(251,248,242,.78);
}
.policy-countdown-sub{
  font-size:.74rem;
  color:rgba(251,248,242,.55);
}
@media (max-width:640px){
  .policy-countdown{ flex:1 1 100%; }
}

/* ---------------- collab strip: contributor stack + invite ----------------
   A thin bridge between the story (forest) and the collaborate section
   (indigo). The overlapping heads spread apart on hover and each raises a
   continuously waving 👋 (same hiWave keyframes as the floating heads);
   everything eases back on mouseout. Whole strip links to /contributors/. */
.collab-strip{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:space-between; /* text left, heads + button right */
  gap:14px 26px;
  padding:18px clamp(20px,5vw,72px);
  background:
    radial-gradient(90% 200% at 50% -60%, rgba(94,226,160,.22), transparent 60%),
    linear-gradient(90deg, var(--forest), #141732 78%);
  color:var(--paper);
  text-decoration:none;
  position:relative;
}
.strip-stack{ display:flex; }
.strip-head{
  position:relative;
  width:44px;
  height:44px;
  margin-left:-14px;
  /* spread uses TRANSFORM, not margins: transforms don't affect layout, so
     the button to the right never shifts when the heads fan out */
  transition:transform .3s cubic-bezier(.4,.1,.3,1);
}
.strip-head:first-child{ margin-left:0; }
.strip-head img{
  width:100%;
  height:100%;
  border-radius:50%;
  object-fit:cover;
  border:2px solid var(--paper);
  box-shadow:0 4px 10px rgba(0,0,0,.3);
  display:block;
}
.strip-wave{
  position:absolute;
  left:-7px;
  bottom:-5px;
  font-size:19px;
  line-height:1;
  opacity:0;
  transform-origin:70% 85%;
  transition:opacity .2s ease;
  filter:drop-shadow(0 1px 3px rgba(0,0,0,.3));
}
/* fan out to the LEFT (away from the button): earlier heads travel further */
.collab-strip:hover .strip-head:nth-child(1){ transform:translateX(-78px); }
.collab-strip:hover .strip-head:nth-child(2){ transform:translateX(-65px); }
.collab-strip:hover .strip-head:nth-child(3){ transform:translateX(-52px); }
.collab-strip:hover .strip-head:nth-child(4){ transform:translateX(-39px); }
.collab-strip:hover .strip-head:nth-child(5){ transform:translateX(-26px); }
.collab-strip:hover .strip-head:nth-child(6){ transform:translateX(-13px); }
.collab-strip:hover .strip-wave,
.collab-strip:focus-visible .strip-wave{
  opacity:1;
  animation:hiWave .9s ease-in-out infinite;
}
.strip-text{
  font-size:1rem;
  font-weight:500;
  /* long copy (team page) wraps INSIDE the text block instead of pushing
     the heads+button group onto a second left-aligned row */
  flex:1 1 300px;
  min-width:0;
}
.strip-text strong{
  color:var(--green);
  font-weight:700;
}
/* the team strip's longer copy: cap the measure so the fanned-out heads
   never crowd the text -- wraps onto a second line well clear of them */
.team-strip .strip-text{ max-width:44ch; }
.strip-group{
  display:inline-flex;
  align-items:center;
  gap:18px;
  flex-wrap:wrap;
  justify-content:center;
  margin-left:auto; /* heads + button hug the right, like the homepage */
  flex:0 0 auto;
}
.strip-btn{
  display:inline-flex;
  align-items:center;
  gap:8px;
  padding:11px 22px;
  border-radius:999px;
  background:var(--green);
  color:var(--forest);
  font-weight:700;
  font-size:.92rem;
  text-decoration:none;
  box-shadow:0 8px 20px rgba(94,226,160,.3), inset 0 1px 0 rgba(255,255,255,.35);
  transition:translate .2s ease, box-shadow .2s ease;
}
.strip-btn:hover{
  translate:0 -2px;
  box-shadow:0 12px 26px rgba(94,226,160,.42), inset 0 1px 0 rgba(255,255,255,.35);
}
.strip-arrow{
  display:inline-block;
  transition:translate .2s ease;
}
.strip-btn:hover .strip-arrow{ translate:4px 0; }
/* phones: the stack sits mid-screen (stacked layout), so the left-only
   fan ran heads off the edge -- spread BOTH ways from the middle instead.
   Applies to EVERY use of the strip (homepage, about, team): these rules
   sit after the desktop fans and the about-strip variants, so they win. */
@media (max-width:640px){
  .collab-strip{ justify-content:center; text-align:center; }
  .collab-strip .strip-group{ width:100%; justify-content:center; margin-left:0; }
  .collab-strip:hover .strip-head:nth-child(1){ transform:translateX(-33px); }
  .collab-strip:hover .strip-head:nth-child(2){ transform:translateX(-22px); }
  .collab-strip:hover .strip-head:nth-child(3){ transform:translateX(-11px); }
  .collab-strip:hover .strip-head:nth-child(4){ transform:translateX(0); }
  .collab-strip:hover .strip-head:nth-child(5){ transform:translateX(11px); }
  .collab-strip:hover .strip-head:nth-child(6){ transform:translateX(22px); }
  .collab-strip:hover .strip-head:nth-child(7){ transform:translateX(33px); }
}

/* ---------------- About: funding contributors ----------------
   Static logo wall (explicitly no animation, unlike pucar.org's ticker).
   Logos are self-hosted at assets/funders/ via scripts/mirror-funder-logos.js. */
/* white panel: most funder logos ship with white backgrounds, which read
   as mismatched boxes on the cream page -- on white they melt in. The panel BREAKS OUT of the prose column (width min(1240px, vw minus page pad), margin-left:50% + translateX(-50%)) so the logos flow wide instead of stacking five rows tall */
.about-funders{
  margin:64px 0 16px;
  padding:32px clamp(24px,4vw,52px) 38px;
  background:#fff;
  border:1px solid var(--line);
  border-radius:22px;
  /* BREAK OUT of the narrow prose column: wide panel, logos flow into
     two-ish rows instead of a tall five-row stack */
  width:min(1240px, calc(100vw - 2 * clamp(20px, 5vw, 72px)));
  margin-left:50%;
  transform:translateX(-50%);
}
.about-funders .beat-eyebrow{ color:var(--forest); }
.funder-grid{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:center; /* balanced rows in the wide panel */
  gap:30px clamp(32px,4vw,56px);
  margin-top:22px;
}
.funder-grid img{
  height:42px;
  width:auto;
  max-width:180px;
  object-fit:contain;
}

/* ---------------- About: full-bleed parallax drawing ----------------
   The image layer is taller than its window (inset -20% top/bottom) and
   js/nav.js slides it vertically with scroll position; overflow:hidden
   crops the travel. Falls back to a plain cover image without JS. */
.about-parallax{
  position:relative;
  height:clamp(320px,55vh,560px);
  overflow:hidden;
}
.about-parallax-img{
  position:absolute;
  inset:-20% 0;
  background-size:cover;
  background-position:center;
  will-change:transform;
}

/* ---------------- /resources/ page ---------------- */
.res-section .collab-grid{ margin-top:6px; }
.res-grid{ grid-template-columns:repeat(auto-fill, minmax(300px, 1fr)); }
/* thumbnails bleed to the card edges (cards pad 24px) */
.res-thumb{
  display:block;
  width:calc(100% + 48px);
  margin:-24px -24px 6px;
  height:170px;
  object-fit:cover;
  border-radius:22px 22px 0 0;
}
.res-thumb-wrap{
  position:relative;
  display:block;
  width:calc(100% + 48px);
  margin:-24px -24px 6px;
}
.res-thumb-wrap .res-thumb{ width:100%; margin:0; }
.circle-play{
  position:absolute;
  inset:0;
  display:flex;
  align-items:center;
  justify-content:center;
  font-size:22px;
  color:#fff;
  background:rgba(10,21,26,.25);
  border-radius:inherit;
  transition:background .2s ease, font-size .2s ease;
}
.circle-card:hover .circle-play{ background:rgba(10,21,26,.45); font-size:28px; }
a.res-card, a.res-data-card{ text-decoration:none; }
button.circle-card{
  text-align:left;
  font:inherit;
  cursor:pointer;
  border:1px solid rgba(251,248,242,.14); /* re-assert: UA button border */
}
.res-card .collab-foot, .res-data-card .collab-foot, .circle-card .collab-foot{
  margin-top:auto;
  justify-content:flex-start;
}
/* on cards WITH tag chips the auto margin lives on the CHIPS instead, so
   they hug the divider; a second auto margin on the foot would split the
   slack and float the chips mid-card */
.res-card .collab-foot{ margin-top:0; }
/* data cards lost their chips row (type became the icon label), so the
   foot takes the auto margin back: divider + button pin to the bottom */
.res-data-card .collab-foot{ margin-top:auto; }
/* circle cards have NO chips, so the foot (divider + Watch) takes the auto
   margin back and pins to the card bottom (this must come after the
   margin-top:0 above -- circle cards are also .res-card) */
.circle-card .collab-foot{ margin-top:auto; }
/* "Learning Circle #N": out of its pill -- icon + uppercase label like the
   data cards' type, but in gold so the video sections read differently */
.res-circle-type{ color:var(--gold); }
.res-circle-type svg{ opacity:.85; }

/* ---- show more: sections cap at 2 card-rows (5 rows in list view), the
   rest hide behind a centered ghost button (js/resources.js) ---- */
.res-more{
  display:flex;
  justify-content:center;
  margin:26px 0 0;
}
/* display:flex vs [hidden], again */
.res-more[hidden]{ display:none; }
.res-more-btn{
  padding:11px 26px;
  border-radius:999px;
  border:1px solid rgba(251,248,242,.3);
  background:transparent;
  color:var(--paper);
  font:600 .88rem var(--font-body);
  cursor:pointer;
  transition:background .2s ease, border-color .2s ease, color .2s ease;
}
.res-more-btn:hover{
  background:var(--paper);
  border-color:var(--paper);
  color:var(--forest);
}
/* one-line clamp support: while collapsed, overflowing chips hide and a
   +N chip stands in; hovering it reveals the full set (ul wraps open) */
.res-section .collab-chips .chip-more{
  cursor:default;
  background:rgba(94,226,160,.15);
  border-color:rgba(94,226,160,.45);
  color:var(--green);
  font-weight:700;
}
.res-section .collab-chips.is-expanded .chip-more{ display:none; }

/* tag/tab pills */
.res-tagbar{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  margin:0 0 14px;
}
.res-tab{
  padding:9px 16px;
  border-radius:999px;
  border:1px solid rgba(251,248,242,.25);
  background:rgba(251,248,242,.08);
  color:rgba(251,248,242,.85);
  font:500 .84rem var(--font-body);
  cursor:pointer;
  transition:background .2s ease, color .2s ease, border-color .2s ease;
}
.res-tab:hover{ border-color:rgba(251,248,242,.5); color:var(--paper); }
.res-tab.is-active{
  background:var(--green);
  border-color:var(--green);
  color:var(--forest);
  font-weight:700;
}
/* the data section's initiative switcher reads as REAL TABS: a shared
   baseline with an underline that marks the active one (the pill look is
   kept for the type FILTERS below the description) */
.res-tabbar{
  display:flex;
  flex-wrap:wrap;
  gap:2px;
  margin:0 0 4px;
  border-bottom:1px solid rgba(251,248,242,.16);
}
.res-tabbar .res-tab{
  border:0;
  border-radius:0;
  background:transparent;
  padding:10px 16px 12px;
  margin-bottom:-1px; /* the underline sits ON the track line */
  border-bottom:2px solid transparent;
  color:rgba(251,248,242,.68);
  font:500 .92rem var(--font-body);
}
.res-tabbar .res-tab:hover{
  color:var(--paper);
  border-bottom-color:rgba(251,248,242,.35);
  background:transparent;
}
.res-tabbar .res-tab.is-active{
  background:transparent;
  color:var(--green);
  border-bottom-color:var(--green);
  font-weight:700;
}
/* type filters keep the pill look, with the type's icon inside */
.res-type-pill{
  display:inline-flex;
  align-items:center;
  gap:7px;
}
/* the display:inline-flex above would beat [hidden] (same gotcha as
   .collab-card): pills not present in the current tab must actually hide */
.res-type-pill[hidden]{ display:none; }
.res-type-pill svg{ opacity:.75; flex:none; }
.res-type-pill.is-active svg{ opacity:1; }
/* data cards: the type is an icon + quiet uppercase label (same voice as
   .res-outlet on blog cards), NOT a pill */
.res-type{
  display:inline-flex;
  align-items:center;
  gap:7px;
  font-size:.7rem;
  font-weight:700;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--green);
}
.res-type svg{ flex:none; opacity:.9; }
/* substantive tab description: display serif, big enough to read as the
   tab's own intro rather than a footnote */
.res-tab-desc{
  margin:18px 0 30px;
  max-width:56ch;
  font-family:var(--font-display);
  font-weight:500;
  font-size:clamp(1.15rem,2vw,1.5rem);
  line-height:1.5;
  color:var(--paper);
  border-left:3px solid var(--green);
  padding-left:18px;
}
/* list view (data grid only): hide thumbs/summaries, compact rows */
.res-grid.is-list .res-thumb, .res-grid.is-list .res-thumb-wrap{ display:none; }
/* video modal */
.video-panel{ max-width:820px; }
.video-wrap{
  position:relative;
  width:100%;
  aspect-ratio:16/9;
  border-radius:14px;
  overflow:hidden;
  background:#000;
  margin-top:8px;
}
.video-wrap iframe{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  border:0;
}
.video-title{
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.25rem;
  margin:18px 0 8px;
}
.video-desc{
  margin:0;
  font-size:.95rem;
  line-height:1.65;
  color:var(--ink-soft);
}

/* ---- blog card refinements ---- */
/* long summaries curtail with an ellipsis */
.res-card .collab-summary{
  display:-webkit-box;
  -webkit-line-clamp:3;
  -webkit-box-orient:vertical;
  overflow:hidden;
}
/* outlet: quiet uppercase text, not a pill */
.res-outlet{
  font-size:.7rem;
  font-weight:700;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--green);
}
/* date: plain text with a calendar glyph, not a pill */
.res-date{
  display:inline-flex;
  align-items:center;
  gap:6px;
  font-size:.78rem;
  color:rgba(251,248,242,.65);
}
/* tags hug the bottom divider */
.res-card .collab-chips{ margin-top:auto; }
/* shimmer: a light band sweeps across the thumbnail on hover */
/* the reflection anchors to the CARD (wrap stays static) and the card
   clips it at its own rounded edges */
.res-card, .circle-card{ overflow:hidden; }
.res-thumb-wrap{ position:static; overflow:visible; }
.res-thumb-clip{
  display:block;
  position:relative;
  z-index:1;
  overflow:hidden;
  border-radius:22px 22px 0 0; /* square bottom: the mask feathers it instead */
  /* HEAVY feather: the photo's bottom ~30% dissolves into the card, no
     hard seam ("rounded bottom looked bad") */
  -webkit-mask-image:linear-gradient(to bottom, #000 68%, transparent 100%);
  mask-image:linear-gradient(to bottom, #000 68%, transparent 100%);
}
.res-thumb-clip .res-thumb{
  width:100%;
  margin:0;
  border-radius:0;
}
/* the reflection: the same image mirrored + heavily blurred, stretched
   from under the photo to the BOTTOM of the card -- a notable ambient
   tint across the whole card that fades out downward */
.res-thumb-glow{
  position:absolute;
  left:0;
  right:0;
  top:110px;
  bottom:0;
  width:100%;
  /* explicit: an absolutely-positioned <img> with height:auto resolves to
     its intrinsic height and IGNORES bottom:0, so the glow used to stop
     short on tall cards. This pins it to the card's true bottom edge. */
  height:calc(100% - 110px);
  object-fit:cover;
  transform:scaleY(-1);
  filter:blur(36px) saturate(1.5);
  opacity:.34;
  z-index:0;
  pointer-events:none;
  -webkit-mask-image:linear-gradient(to bottom, #000 0%, rgba(0,0,0,.55) 55%, transparent 100%);
  mask-image:linear-gradient(to bottom, #000 0%, rgba(0,0,0,.55) 55%, transparent 100%);
  transition:opacity .35s ease;
}
.res-card:hover .res-thumb-glow,
.circle-card:hover .res-thumb-glow{ opacity:.5; }
/* keep card text above the glow */
.res-card > *:not(.res-thumb-wrap),
.circle-card > *:not(.res-thumb-wrap){ position:relative; z-index:1; }
.res-shine{
  position:absolute;
  inset:0;
  background:linear-gradient(105deg, transparent 38%, rgba(255,255,255,.32) 50%, transparent 62%);
  transform:translateX(-130%);
  pointer-events:none;
}
.res-card:hover .res-shine{
  transform:translateX(130%);
  transition:transform .85s ease;
}
/* the whole /dristi/ intro runs at content width like the dark bands
   below it (revised: widening only the stat panel looked inconsistent);
   prose paragraphs stay capped at a readable measure inside it */
.dristi-main{
  max-width:1240px; /* keeps job-main's own side padding */
}
.dristi-main .job-body{ max-width:none; } /* paragraphs span the full column, like the title */

/* ---------------- /dristi/ page ----------------
   Intro + five levers reuse the About page components (.about-stats,
   .about-steps). Versions and deployments are dark .collaborate bands.
   State tabs reuse .res-tabbar; disabled states are .tab-soon with a
   "Coming soon" chip. The race is the user-supplied Kaplan-Meier
   visualisation re-themed to the site palette (Plotly, this page only). */
/* intro stat strip: three columns split by hairlines, not the stacked
   left-aligned column the flex default produced with sentence-length labels */
.dristi-hero-stats{
  display:grid;
  grid-template-columns:repeat(3, 1fr); /* three EQUAL thirds, full width */
  gap:clamp(24px,4vw,56px);
  align-items:start;
}
.dristi-hero-stats .about-stat-num{ white-space:nowrap; }
.dristi-hero-stats .about-stat + .about-stat{
  padding-left:clamp(22px,3.5vw,48px);
  border-left:1px solid rgba(251,248,242,.18);
}
/* sentence-case labels: the uppercase micro-type wrapped into ugly
   four-line stacks with sentence-length copy */
.dristi-hero-stats .about-stat-label{
  text-transform:none;
  letter-spacing:0;
  font-size:.95rem;
  font-weight:500;
  line-height:1.5;
  color:rgba(251,248,242,.72);
  max-width:34ch;
}
.dristi-hero-stats .about-stat-label::first-letter{ text-transform:uppercase; }
@media (max-width: 760px){
  .dristi-hero-stats{ grid-template-columns:1fr; }
  .dristi-hero-stats .about-stat + .about-stat{
    padding-left:0;
    border-left:0;
    padding-top:20px;
    border-top:1px solid rgba(251,248,242,.18);
  }
}

/* coming-soon tabs are CLICKABLE now (6 Jul 2026): dimmer than live
   tabs but interactive, and they light up normally when active */
.res-tab.tab-soon{
  opacity:.55;
  cursor:pointer;
  display:inline-flex;
  align-items:center;
  gap:8px;
  transition:opacity .25s ease;
}
.res-tab.tab-soon:hover{ opacity:.85; }
.res-tab.tab-soon.is-active{ opacity:1; }
.soon-chip{
  font-size:.6rem;
  font-weight:800;
  letter-spacing:.1em;
  text-transform:uppercase;
  padding:3px 8px;
  border-radius:999px;
  border:1px solid rgba(251,248,242,.3);
  color:rgba(251,248,242,.7);
}
.district-tagbar{ margin:18px 0 26px; }
/* .res-tagbar's display:flex beats the [hidden] attribute (same gotcha
   as .res-more/.res-type-pill): restate it explicitly */
.district-tagbar[hidden]{ display:none; }
.dristi-panel[hidden]{ display:none; }
/* live tabs carry the homepage's throbbing green orb */
.state-tabbar .res-tab, .district-tagbar .res-tab{
  display:inline-flex;
  align-items:center;
  gap:9px;
}
.state-tabbar .board-live, .district-tagbar .board-live{ flex:none; }
/* the orb stays GREEN everywhere; instead of a solid green active pill
   (which swallowed the orb), the active district is a green-tinted
   OUTLINE pill: green border + green text + visible green orb */
.district-tagbar .res-tab.is-active{
  background:rgba(48,207,140,.12);
  border-color:var(--green);
  color:var(--green);
  font-weight:700;
}

/* ---- 1.0 -> 2.0: a hand-off, not two grey boxes. Each card carries a
   giant translucent version numeral, a live/build status pill, and a
   ticked feature list; 2.0 is the hero (green aura, brighter border)
   with an arrow bridging the two on wide screens. ---- */
.ver-grid{
  display:grid;
  grid-template-columns:1fr auto 1fr;
  gap:18px;
  align-items:stretch;
}
@media (max-width: 900px){
  .ver-grid{ grid-template-columns:1fr; }
  .ver-bridge{ transform:rotate(90deg); justify-self:center; }
}
.ver-card{
  position:relative;
  overflow:hidden;
  display:flex;
  flex-direction:column;
  padding:clamp(26px,3.5vw,40px);
  border-radius:26px;
  border:1px solid rgba(251,248,242,.14);
  background:
    radial-gradient(130% 130% at 85% -10%, rgba(251,248,242,.06), transparent 55%),
    rgba(251,248,242,.05);
}
.ver-card.ver-two{
  border-color:rgba(48,207,140,.45);
  background:
    radial-gradient(130% 130% at 85% -10%, rgba(48,207,140,.16), transparent 55%),
    rgba(48,207,140,.05);
  box-shadow:0 24px 70px rgba(48,207,140,.08), inset 0 1px 0 rgba(48,207,140,.18);
}
.ver-num{
  position:absolute;
  top:-28px;
  right:6px;
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(6rem,11vw,9.5rem);
  line-height:1;
  color:rgba(251,248,242,.05);
  pointer-events:none;
  user-select:none;
}
.ver-two .ver-num{ color:rgba(48,207,140,.1); }
.ver-status{
  display:inline-flex;
  align-items:center;
  gap:8px;
  align-self:flex-start;
  padding:6px 14px;
  border-radius:999px;
  border:1px solid rgba(48,207,140,.4);
  background:rgba(48,207,140,.1);
  font-size:.68rem;
  font-weight:800;
  letter-spacing:.13em;
  text-transform:uppercase;
  color:var(--green);
  margin-bottom:18px;
}
.ver-status.is-build{
  border-color:rgba(218,110,170,.45);
  background:rgba(218,110,170,.1);
  color:var(--pink);
}
.ver-dot{
  width:8px; height:8px;
  border-radius:50%;
  background:currentColor;
  animation:boardPulse 2s ease-in-out infinite;
}
.ver-title{
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(1.5rem,2.6vw,2rem);
  margin:0 0 12px;
}
.ver-body{
  margin:0 0 20px;
  line-height:1.65;
  color:rgba(251,248,242,.75);
  max-width:52ch;
}
.ver-list{
  list-style:none;
  margin:0 0 26px;
  padding:0;
  display:flex;
  flex-direction:column;
  gap:10px;
}
.ver-list li{
  position:relative;
  padding-left:30px;
  line-height:1.5;
  color:rgba(251,248,242,.85);
}
.ver-list li::before{
  content:"";
  position:absolute;
  left:0; top:2px;
  width:18px; height:18px;
  border-radius:50%;
  background:rgba(251,248,242,.1) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M4 8.5 7 11l5-6" fill="none" stroke="%23FBF8F2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>') center/11px no-repeat;
}
.ver-two .ver-list li::before{
  background-color:rgba(48,207,140,.18);
  background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M4 8.5 7 11l5-6" fill="none" stroke="%2330CF8C" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>');
}
.ver-link{
  margin-top:auto;
  align-self:flex-start;
  font-weight:700;
  text-decoration:none;
  color:var(--paper);
  border-bottom:2px solid rgba(251,248,242,.3);
  padding-bottom:2px;
  transition:color .2s ease, border-color .2s ease;
}
.ver-link:hover{ color:var(--green); border-color:var(--green); }
.ver-two .ver-link{ color:var(--green); border-color:rgba(48,207,140,.4); }
.ver-two .ver-link:hover{ border-color:var(--green); }
.ver-bridge{
  align-self:center;
  color:rgba(48,207,140,.6);
  display:flex;
}

.dristi-panel-title{
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(1.5rem,3vw,2.1rem);
  margin:0 0 10px;
}
.dristi-panel-sub{
  max-width:64ch;
  line-height:1.65;
  color:rgba(251,248,242,.75);
  margin:0 0 30px;
}
/* two hero stats on top (span 2 tracks each), four quieter ones below */
.dristi-stat-grid{
  display:grid;
  grid-template-columns:repeat(4, 1fr);
  gap:14px;
}
@media (max-width: 760px){
  .dristi-stat-grid{ grid-template-columns:repeat(2, 1fr); }
  .dristi-stat.is-big{ grid-column:span 2; }
}
.dristi-stat{
  display:flex;
  flex-direction:column;
  gap:6px;
  padding:20px 20px 16px;
  border-radius:18px;
  background:rgba(251,248,242,.06);
  border:1px solid rgba(251,248,242,.14);
}
.dristi-stat.is-big{
  grid-column:span 2;
  padding:30px 30px 24px;
  border-color:rgba(48,207,140,.35);
  background:
    radial-gradient(120% 150% at 80% -20%, rgba(48,207,140,.14), transparent 55%),
    rgba(251,248,242,.05);
}
.dristi-stat-num{
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(1.4rem,2.4vw,1.9rem);
  color:var(--paper);
  line-height:1;
}
.dristi-stat.is-big .dristi-stat-num{
  font-size:clamp(2.6rem,5.5vw,4.2rem);
  color:var(--green);
}
.dristi-stat.is-big .dristi-stat-num em{
  font-style:normal;
  font-size:.55em;
}
.dristi-stat-label{
  font-size:.8rem;
  line-height:1.4;
  color:rgba(251,248,242,.65);
}
.dristi-stat.is-big .dristi-stat-label{
  font-size:.95rem;
  max-width:30ch;
  color:rgba(251,248,242,.78);
}
.dristi-source{
  margin:14px 0 0;
  font-size:.85rem;
  color:rgba(251,248,242,.55);
  max-width:70ch;
}
.dristi-source a{ color:var(--green); }

/* before/after journey rows */
.dristi-journey{
  margin:44px 0 0;
  padding:26px clamp(20px,3vw,34px) 22px;
  border-radius:22px;
  background:rgba(251,248,242,.05);
  border:1px solid rgba(251,248,242,.12);
}
.dristi-journey-head h4{
  font-family:var(--font-display);
  font-size:1.25rem;
  font-weight:600;
  margin:0 0 4px;
}
.dristi-journey-head p{
  margin:0 0 18px;
  font-size:.88rem;
  color:rgba(251,248,242,.6);
}
.dristi-journey-row{
  display:grid;
  grid-template-columns:1fr auto 24px auto;
  align-items:center;
  gap:14px;
  padding:11px 2px;
  border-top:1px solid rgba(251,248,242,.09);
  font-size:.95rem;
}
.dj-stage{ color:rgba(251,248,242,.85); }
.dj-stage-desc{
  display:block;
  margin-top:2px;
  font-style:normal;
  font-weight:400;
  font-size:.78rem;
  line-height:1.45;
  color:rgba(251,248,242,.5);
  max-width:52ch;
}
.dj-old{ font-size:1.1rem; color:rgba(251,248,242,.5); text-decoration:line-through; text-decoration-color:rgba(240,162,138,.7); }
.dj-arrow{ color:rgba(251,248,242,.4); text-align:center; }
.dj-new{ font-size:1.3rem; color:var(--green); font-weight:700; text-align:right; min-width:86px; }
.dristi-journey-row.is-total{
  border-top:2px solid rgba(251,248,242,.25);
  font-weight:700;
}
.dristi-journey-row.is-total .dj-old{ font-size:1.2rem; }
.dristi-journey-row.is-total .dj-new{ font-size:1.55rem; }

/* ===== /careers/: grouped open-role rows on the dark band ===== */
.career-group{ margin:0 0 40px; }
.career-group:last-of-type{ margin-bottom:8px; }
.career-group-head{ margin:0 0 14px; }
.career-group-head h3{
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.4rem;
  margin:0 0 2px;
  color:var(--paper);
}
.career-group-head p{
  margin:0;
  font-size:.9rem;
  color:rgba(251,248,242,.55);
}
.career-row{
  display:grid;
  grid-template-columns:1fr auto 28px;
  align-items:center;
  gap:clamp(16px,3vw,40px);
  padding:18px clamp(16px,2.5vw,26px);
  margin:0 0 10px;
  border-radius:18px;
  border:1px solid rgba(251,248,242,.14);
  background:rgba(251,248,242,.05);
  text-decoration:none;
  color:inherit;
  transition:border-color .25s ease, background .25s ease, transform .25s ease;
}
.career-row:hover{
  border-color:rgba(48,207,140,.5);
  background:rgba(48,207,140,.07);
  transform:translateX(4px);
}
.career-row-main{ display:flex; flex-direction:column; gap:4px; min-width:0; }
.career-row-title{
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.12rem;
  color:var(--paper);
}
.career-row-sum{
  font-size:.88rem;
  line-height:1.5;
  color:rgba(251,248,242,.65);
  max-width:64ch;
}
.career-row-meta{
  display:flex;
  flex-direction:column;
  gap:3px;
  text-align:right;
  font-size:.8rem;
  color:rgba(251,248,242,.55);
  white-space:nowrap;
}
.career-row-arrow{
  color:var(--green);
  font-size:1.2rem;
  transition:transform .25s ease;
}
.career-row:hover .career-row-arrow{ transform:translateX(4px); }

/* redesigned role cards: a responsive grid of proper cards that surface the
   experience + tech tags, with an accent rail and hover lift */
.career-cards{ display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%,380px),1fr)); gap:18px; }
.career-card{ display:flex; flex-direction:column; gap:13px; padding:26px 26px 22px; border-radius:20px;
  border:1px solid rgba(251,248,242,.12); position:relative; overflow:hidden; text-decoration:none; color:inherit;
  background:linear-gradient(180deg, rgba(251,248,242,.055), rgba(251,248,242,.02));
  transition:border-color .25s ease, transform .25s ease, box-shadow .25s ease, background .25s ease; }
.career-card::before{ content:""; position:absolute; left:0; top:0; bottom:0; width:3px; background:var(--green);
  transform:scaleY(0); transform-origin:top; transition:transform .3s ease; }
.career-card:hover{ border-color:rgba(48,207,140,.5); transform:translateY(-3px); box-shadow:0 16px 40px rgba(0,0,0,.32);
  background:linear-gradient(180deg, rgba(48,207,140,.09), rgba(48,207,140,.03)); }
.career-card:hover::before{ transform:scaleY(1); }
.cc-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:12px; flex-wrap:wrap; }
.cc-title{ font-family:var(--font-display); font-weight:600; font-size:1.3rem; line-height:1.14; color:var(--paper); }
.cc-sum{ font-size:.92rem; line-height:1.55; color:rgba(251,248,242,.68); max-width:60ch; }
.cc-facts{ display:flex; flex-wrap:wrap; gap:8px; margin-top:2px; }
.cc-chip{ font-size:.75rem; font-weight:600; color:rgba(251,248,242,.72);
  border:1px solid rgba(251,248,242,.16); border-radius:999px; padding:5px 11px; }
.cc-chip-key{ color:var(--green); border-color:rgba(48,207,140,.5); background:rgba(48,207,140,.09); }
.cc-tags{ display:flex; flex-wrap:wrap; gap:7px; }
.cc-tag{ font-size:.72rem; font-weight:600; letter-spacing:.02em; color:rgba(251,248,242,.6);
  background:rgba(251,248,242,.06); border-radius:8px; padding:4px 9px; }
.cc-cta{ display:inline-flex; align-items:center; gap:7px; margin-top:6px; font-size:.85rem; font-weight:700; color:var(--green); }
.cc-cta svg{ transition:transform .25s ease; }
.career-card:hover .cc-cta svg{ transform:translateX(3px); }
.careers-cta{ margin-top:34px; }
@media (max-width: 700px){
  .career-row{ grid-template-columns:1fr 24px; }
  .career-row-meta{
    grid-column:1 / -1;
    grid-row:2;
    flex-direction:row;
    gap:14px;
    text-align:left;
    white-space:normal;
  }
}

/* ===== /approach/: metric shift + three pillars ===== */
/* the shift table reuses the journey rows but both sides carry full
   sentences, so the columns get real tracks instead of auto-hugging */
.approach-shift{ margin:0 0 34px; }
.approach-shift .dristi-journey-row{
  grid-template-columns:minmax(140px,.7fr) 1fr 24px 1fr;
}
.approach-shift .dristi-journey-row:first-child{ border-top:0; }
.approach-shift .dj-new{ text-align:left; min-width:0; }
/* the shift rows carry SENTENCES, not day counts: keep them at body
   size (the journey's big 1.1/1.3rem numerals would be shouting here) */
.approach-shift .dj-old,
.approach-shift .dj-new{ font-size:.95rem; }
@media (max-width: 760px){
  .approach-shift .dristi-journey-row{
    grid-template-columns:1fr 24px 1fr;
    row-gap:4px;
  }
  .approach-shift .dj-stage{
    grid-column:1 / -1;
    font-size:.78rem;
    letter-spacing:.04em;
    text-transform:uppercase;
    color:rgba(251,248,242,.5);
  }
}
.pillar-grid{
  display:grid;
  grid-template-columns:repeat(3, 1fr);
  gap:18px;
  align-items:stretch;
}
@media (max-width: 900px){
  .pillar-grid{ grid-template-columns:1fr; }
}
.pillar-card{
  position:relative;
  overflow:hidden;
  display:flex;
  flex-direction:column;
  padding:clamp(24px,3vw,34px);
  border-radius:26px;
  border:1px solid rgba(251,248,242,.14);
  background:
    radial-gradient(130% 130% at 85% -10%, rgba(251,248,242,.06), transparent 55%),
    rgba(251,248,242,.05);
}
.pillar-num{
  position:absolute;
  top:-24px;
  right:8px;
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(5rem,9vw,7.5rem);
  line-height:1;
  color:rgba(251,248,242,.05);
  pointer-events:none;
  user-select:none;
}
.pillar-title{
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.45rem;
  margin:0 0 10px;
  color:var(--paper);
}
.pillar-body{
  margin:0 0 22px;
  font-size:.92rem;
  line-height:1.65;
  color:rgba(251,248,242,.72);
}
.pillar-proof{
  margin-top:auto;
  display:flex;
  flex-direction:column;
  gap:5px;
  padding:16px 18px 14px;
  border-radius:16px;
  border:1px solid rgba(48,207,140,.35);
  background:
    radial-gradient(120% 150% at 80% -20%, rgba(48,207,140,.14), transparent 55%),
    rgba(251,248,242,.04);
}
.pillar-proof-num{
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(1.7rem,2.6vw,2.2rem);
  line-height:1;
  color:var(--green);
}
.pillar-proof-cap{
  font-size:.82rem;
  line-height:1.45;
  color:rgba(251,248,242,.65);
}
.approach-note{ margin-top:22px; }

/* State vector map beside the panel intro: active district outlined,
   dot + highlight GLIDE between districts on tab clicks. The map sits
   right after the copy (flex-start), not flushed to the panel edge. */
.dristi-panel-head{
  display:flex;
  align-items:center;
  justify-content:flex-start;
  gap:clamp(32px,6vw,96px);
  flex-wrap:wrap;
  margin-bottom:clamp(36px,5vh,64px); /* room to breathe above the stats */
}
.dristi-panel-copy{ flex:0 1 62ch; min-width:min(100%,340px); }
/* no auto margins: the map hugs the paragraph, gap alone separates them */
.dristi-map{ flex:0 0 auto; width:clamp(200px,26vw,320px); margin-bottom:14px; }
.dristi-map svg{ display:block; width:100%; height:auto; max-height:520px; }
/* Gujarat's outline is a WIDE, short shape (viewBox 576x452) vs the tall
   Kerala/Punjab maps (~656 high). At the shared width it renders far shorter
   and reads small next to the copy, so give the Gujarat panel alone a larger
   width band. Other states keep the rule above. */
[data-state-panel="gujarat"] .dristi-map{ width:clamp(280px,40vw,520px); }
.km-state{
  fill:rgba(251,248,242,.07);
  stroke:rgba(251,248,242,.07); /* same tone bridges simplification gaps */
  stroke-width:2;
  stroke-linejoin:round;
}
.km-d{
  fill:transparent;
  stroke:transparent;
  stroke-width:1.6;
  stroke-linejoin:round;
  transition:fill .6s ease, stroke .6s ease;
}
.km-d.is-active{
  fill:rgba(48,207,140,.16);
  stroke:var(--green);
}
.km-marker{ transition:transform .7s cubic-bezier(.4,0,.2,1); }
/* grey dots: the OTHER districts covered in this state */
.km-other{
  fill:rgba(251,248,242,.4);
  transition:opacity .4s ease;
}
.km-other.is-here{ opacity:0; } /* hides under the green marker */
.km-dot{ fill:var(--green); }
.km-ping{
  fill:none;
  stroke:var(--green);
  stroke-width:2;
  opacity:.8;
  animation:kmPing 2.2s ease-out infinite;
}
@keyframes kmPing{
  0%{ transform:scale(1); opacity:.8; }
  70%{ transform:scale(3.2); opacity:0; }
  100%{ transform:scale(3.2); opacity:0; }
}
@media (prefers-reduced-motion: reduce){
  .km-ping{ animation:none; opacity:.4; }
  .km-marker,.km-d{ transition:none; }
}
/* hover callout: leader line + label, mouse-following (js/dristi.js) */
.km-callout{
  pointer-events:none;
  opacity:0;
  transition:opacity .25s ease;
}
.km-callout.is-on{ opacity:1; }
.km-lead{
  fill:none;
  stroke:var(--green);
  stroke-linejoin:round;
  stroke-linecap:round;
  opacity:.85;
}
.km-tag-bg{
  fill:#111F26;
  fill-opacity:.95;
  stroke:rgba(48,207,140,.5);
}
.km-tag{
  fill:var(--paper);
  font-family:'Source Sans 3', sans-serif;
  font-weight:600;
  dominant-baseline:central;
}
/* phones: no map (and therefore no callout) */
@media (max-width: 700px){
  .dristi-map{ display:none; }
}

.soon-flag{
  display:inline-flex;
  align-items:center;
  margin-top:14px;
  font-size:.62rem;
  font-weight:800;
  letter-spacing:.1em;
  text-transform:uppercase;
  padding:5px 12px;
  border-radius:999px;
  border:1px solid rgba(240,162,138,.5);
  color:#F0A28A;
}
.dristi-soon-note{
  margin:26px 0 4px;
  max-width:64ch;
  font-size:.95rem;
  line-height:1.65;
  color:rgba(251,248,242,.6);
}
.dristi-soon-note a{ color:var(--green); }

/* quarterly filings + disposals panel (same chrome as the journey) */
.dristi-growth{
  margin:44px 0 0;
  padding:26px clamp(20px,3vw,34px) 22px;
  border-radius:22px;
  background:rgba(251,248,242,.05);
  border:1px solid rgba(251,248,242,.12);
}
#growthChart{ width:100%; height:320px; }
@media (max-width: 640px){
  #growthChart{ height:260px; }
}

/* live per-stage medians strip inside the journey panel */
.dj-stages-lead{
  margin:26px 0 14px;
  font-size:.88rem;
  color:rgba(251,248,242,.6);
  max-width:64ch;
}
.dj-stages{
  display:grid;
  grid-template-columns:repeat(6, 1fr);
  gap:10px;
}
@media (max-width: 960px){
  .dj-stages{ grid-template-columns:repeat(3, 1fr); }
}
@media (max-width: 520px){
  .dj-stages{ grid-template-columns:repeat(2, 1fr); }
}
.dj-stage-card{
  display:flex;
  flex-direction:column;
  gap:5px;
  padding:14px 12px 12px;
  border-radius:14px;
  background:rgba(251,248,242,.05);
  border:1px solid rgba(251,248,242,.12);
}
.djs-name{
  font-size:.72rem;
  letter-spacing:.05em;
  text-transform:uppercase;
  color:rgba(251,248,242,.55);
}
.djs-days{
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.2rem;
  line-height:1.1;
  color:var(--green);
}
.djs-hear{
  font-size:.78rem;
  color:rgba(251,248,242,.6);
}
.djs-desc{
  margin-top:4px;
  padding-top:8px;
  border-top:1px solid rgba(251,248,242,.1);
  font-size:.76rem;
  line-height:1.5;
  color:rgba(251,248,242,.55);
}

/* ---- the race ---- */
.race{
  position:relative;
  margin:44px 0 0;
  padding:30px clamp(20px,3vw,36px) 22px;
  border-radius:22px;
  background:rgba(251,248,242,.05);
  border:1px solid rgba(251,248,242,.12);
}
.race-head{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:16px;
  flex-wrap:wrap;
  margin-bottom:20px;
}
.race-title{
  font-family:var(--font-display);
  font-size:clamp(1.25rem,2.4vw,1.6rem);
  font-weight:600;
  margin:0 0 6px;
}
.race-sub{
  margin:0;
  max-width:56ch;
  font-size:.9rem;
  line-height:1.55;
  color:rgba(251,248,242,.65);
}
.race-btn{
  flex:none;
  padding:11px 22px;
  border:0;
  border-radius:999px;
  background:var(--green);
  color:var(--forest);
  font:700 .85rem var(--font-body);
  letter-spacing:.04em;
  text-transform:uppercase;
  cursor:pointer;
  transition:transform .15s ease, box-shadow .15s ease, opacity .2s ease;
}
.race-btn:hover{ transform:scale(1.04); box-shadow:0 0 18px rgba(48,207,140,.35); }
.race-btn:disabled{ opacity:.55; cursor:default; transform:none; box-shadow:none; }
.race-stats{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(180px, 1fr));
  gap:12px;
  margin-bottom:18px;
}
.race-stat{
  padding:16px 18px 13px;
  border-radius:16px;
  background:rgba(17,31,38,.45);
  border:1px solid rgba(251,248,242,.12);
  display:flex;
  flex-direction:column;
  gap:5px;
}
.race-stat.is-hero{ border-color:rgba(48,207,140,.4); }
.race-stat-num{
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.5rem;
  line-height:1;
}
.race-stat.is-hero .race-stat-num{ color:var(--green); }
.race-stat-label{
  font-size:.74rem;
  line-height:1.4;
  text-transform:uppercase;
  letter-spacing:.06em;
  font-weight:600;
  color:rgba(251,248,242,.55);
}
.race-rank{
  display:flex;
  align-items:center;
  gap:12px;
  flex-wrap:wrap;
  padding:11px 16px;
  border-radius:12px;
  background:rgba(10,21,26,.5);
  border:1px solid rgba(251,248,242,.1);
  margin-bottom:14px;
  font-size:.85rem;
}
.race-rank-label{ color:rgba(251,248,242,.55); font-weight:600; }
.race-rank-num{
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.35rem;
  color:var(--green);
}
.race-rank-pips{ flex:1; display:flex; gap:5px; min-width:180px; }
.race-rank-pips i{
  flex:1;
  height:8px;
  border-radius:4px;
  background:rgba(251,248,242,.08);
  transition:background .3s ease;
}
.race-rank-pips i.is-filled{ background:var(--green); }
.race-rank-day{ color:rgba(251,248,242,.6); font-weight:700; }
.race-legend{
  display:flex;
  flex-wrap:wrap;
  gap:8px 16px;
  margin-bottom:8px;
  font-size:.78rem;
  font-weight:600;
  color:rgba(251,248,242,.75);
}
.race-leg{ display:inline-flex; align-items:center; gap:7px; }
.race-leg i{ width:22px; border-radius:2px; display:inline-block; }
#raceChart{ width:100%; height:440px; }
.race-flash{
  position:absolute;
  top:50%; left:50%;
  transform:translate(-50%,-50%) scale(0);
  display:flex;
  flex-direction:column;
  gap:3px;
  text-align:center;
  padding:20px 28px;
  border-radius:18px;
  background:var(--green);
  color:var(--forest);
  opacity:0;
  pointer-events:none;
  z-index:5;
  transition:opacity .25s ease, transform .35s cubic-bezier(.34,1.56,.64,1);
}
.race-flash.show{ opacity:1; transform:translate(-50%,-50%) scale(1); }
/* 3 - 2 - 1 - GO countdown, popped over the emptied grid */
.race-count{
  position:absolute;
  top:55%; left:50%;
  translate:-50% -50%;
  z-index:6;
  font-family:var(--font-display);
  font-weight:600;
  font-size:clamp(4.5rem,10vw,8rem);
  line-height:1;
  color:var(--green);
  text-shadow:0 0 40px rgba(48,207,140,.45);
  opacity:0;
  pointer-events:none;
}
.race-count.is-go{ color:var(--paper); text-shadow:0 0 46px rgba(251,248,242,.5); }
.race-count.is-on{ animation:raceTick .68s cubic-bezier(.3,1.2,.4,1) forwards; }
@keyframes raceTick{
  0%  { opacity:0; scale:.35; }
  22% { opacity:1; scale:1.12; }
  55% { opacity:1; scale:1; }
  100%{ opacity:0; scale:1.7; }
}
.race-flash-tag{ font-size:.62rem; font-weight:800; letter-spacing:.16em; text-transform:uppercase; opacity:.65; }
.race-flash-head{ font-family:var(--font-display); font-weight:600; font-size:1.5rem; line-height:1.1; }
.race-flash-sub{ font-size:.78rem; font-weight:600; opacity:.7; }
.race-note{
  margin:12px 0 0;
  font-size:.78rem;
  color:rgba(251,248,242,.45);
}
/* voices: big drawn quote glyph, display-serif pull-quote type, a soft
   green aura, and a proper attribution block with an initial medallion */
.dristi-voices{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(300px, 1fr));
  gap:16px;
  margin:44px 0 0;
}
.dristi-voice{
  position:relative;
  overflow:hidden;
  margin:0;
  padding:54px 28px 24px;
  border-radius:22px;
  border:1px solid rgba(251,248,242,.14);
  background:
    radial-gradient(120% 120% at 12% -20%, rgba(48,207,140,.13), transparent 55%),
    rgba(251,248,242,.05);
  transition:transform .25s ease, border-color .25s ease;
}
.dristi-voice:hover{ transform:translateY(-4px); border-color:rgba(48,207,140,.4); }
.dristi-voice::before{
  content:"\201C";
  position:absolute;
  top:-14px;
  left:16px;
  font-family:var(--font-display);
  font-weight:600;
  font-size:7rem;
  line-height:1;
  color:rgba(48,207,140,.3);
  pointer-events:none;
}
.dristi-voice p{
  margin:0 0 20px;
  font-family:var(--font-display);
  font-weight:500;
  font-size:clamp(1.1rem,1.8vw,1.3rem);
  line-height:1.5;
  color:var(--paper);
}
.dristi-voice cite{
  display:flex;
  align-items:center;
  gap:12px;
  font-style:normal;
  font-size:.82rem;
  line-height:1.35;
  color:rgba(251,248,242,.6);
}
.dristi-voice cite::before{
  content:attr(data-initial);
  flex:none;
  width:38px;
  height:38px;
  border-radius:50%;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  background:rgba(48,207,140,.16);
  border:1px solid rgba(48,207,140,.4);
  color:var(--green);
  font:700 .95rem var(--font-display);
}
/* CTAs: one glowing primary + quiet pills that fill on hover */
.dristi-links{ margin-top:40px; gap:12px; }
.collab-head-cta{ margin-top:22px; }
/* "About the DRISTI platform ->" link inside board intros */
.collab-dristi-link{
  color:var(--green);
  font-weight:700;
  text-decoration:none;
  border-bottom:1px solid rgba(48,207,140,.4);
  white-space:nowrap;
}
.collab-dristi-link:hover{ border-color:var(--green); }
.dristi-links .btn{
  padding:14px 26px;
  font-weight:700;
}
.dristi-links .btn-primary{
  background:var(--green);
  color:var(--forest);
  box-shadow:0 10px 30px rgba(48,207,140,.3), inset 0 1px 0 rgba(255,255,255,.35);
  transition:translate .2s ease, box-shadow .2s ease;
}
.dristi-links .btn-primary:hover{
  background:#51D79E;
  translate:0 -2px;
  box-shadow:0 16px 40px rgba(48,207,140,.42), inset 0 1px 0 rgba(255,255,255,.35);
}
.dristi-links .btn-ghost{
  border-color:rgba(251,248,242,.3);
  transition:background .2s ease, color .2s ease, border-color .2s ease, translate .2s ease;
}
.dristi-links .btn-ghost:hover{
  background:var(--paper);
  border-color:var(--paper);
  color:var(--forest);
  translate:0 -2px;
}

/* ---------------- /team/ page ----------------
   Portrait wall modelled on opennyai.org/about, re-skinned to PUCAR:
   cards sit on the dark .collaborate band, photos are grayscale until
   hover, then colour in while the name/role rise over a bottom gradient
   and a frosted LinkedIn chip appears mid-card. Touch devices (no hover)
   get colour photos + visible names permanently. */
.team-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(230px, 1fr));
  gap:18px;
}
.team-card{
  position:relative;
  aspect-ratio:3/4;
  border-radius:22px;
  overflow:hidden;
  cursor:pointer;
  background:rgba(251,248,242,.06);
  border:1px solid rgba(251,248,242,.14);
  transition:transform .25s ease, border-color .25s ease;
}
.team-card:hover,
.team-card:focus-visible{
  transform:translateY(-4px);
  border-color:rgba(251,248,242,.3);
}
.team-photo{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:cover;
  filter:grayscale(1);
  transition:filter .35s ease, transform .45s ease;
}
.team-card:hover .team-photo,
.team-card:focus-visible .team-photo{
  filter:none;
  transform:scale(1.045);
}
.team-veil{
  position:absolute;
  left:0; right:0; bottom:0;
  height:58%;
  background:linear-gradient(to top, rgba(10,21,26,.92), rgba(10,21,26,.4) 55%, transparent);
  opacity:0;
  transition:opacity .3s ease;
  pointer-events:none;
}
.team-meta{
  position:absolute;
  left:18px; right:18px; bottom:16px;
  display:flex;
  flex-direction:column;
  gap:3px;
  opacity:0;
  translate:0 10px;
  transition:opacity .3s ease, translate .3s ease;
  pointer-events:none;
}
.team-card:hover .team-veil, .team-card:focus-visible .team-veil{ opacity:1; }
.team-card:hover .team-meta, .team-card:focus-visible .team-meta{ opacity:1; translate:0 0; }
.team-name{
  font-family:var(--font-display);
  font-weight:600;
  font-size:1.3rem;
  line-height:1.2;
  color:var(--paper);
}
.team-role{
  font-size:.7rem;
  font-weight:700;
  letter-spacing:.13em;
  text-transform:uppercase;
  color:var(--green);
}
@media (hover:none){
  /* no hover states on touch: colour photos, names always on */
  .team-photo{ filter:none; }
  .team-veil, .team-meta{ opacity:1; translate:0 0; }
}

/* leave-site warning: deliberately NOT the house modal look -- a compact
   amber-edged strip that reads as a brief warning, not another dialog */
.leave-panel{
  max-width:430px;
  border-left:6px solid #D08700;
  border-radius:16px;
  padding:24px 28px 22px;
}
.leave-head{
  display:flex;
  align-items:center;
  gap:9px;
  margin:0 0 10px;
  font-size:.78rem;
  font-weight:800;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:#8A5A14; /* amber-dark: 6.2:1 on --paper */
}
.leave-head svg{ flex:none; color:#D08700; }
.leave-text{
  font-size:.98rem;
  line-height:1.6;
  color:var(--ink-soft);
  margin:0;
}
.leave-text strong{ color:var(--ink); }
.leave-actions{ margin-top:20px; gap:10px; }
.leave-actions .btn{ padding:10px 20px; font-size:.88rem; }

/* =======================================================================
   MISSION BAND — big centred mission statement + three "doors"
   (Our Journey / About Us / About DRISTI). Light section on --cream,
   editorial Gates-style: Fraunces display, pink italic accents.
   ======================================================================= */
.mission-band{
  background:var(--cream);
  padding:clamp(72px,12vh,140px) clamp(20px,5vw,72px) clamp(64px,10vh,120px);
}
.mission-inner{ max-width:1180px; margin:0 auto; }
.mission-statement{
  position:relative; /* anchor for the hand-inked underline overlay */
  font-family:var(--font-display);
  font-weight:500;
  font-size:clamp(1.9rem,4.4vw,3.4rem);
  line-height:1.16;
  text-align:center;
  color:var(--ink);
  max-width:20ch;
  margin:0 auto;
}
/* pink italic key phrases, echoing the Gates "every / healthy" treatment */
.mission-statement em{ position:relative; z-index:1; font-style:italic; color:var(--pink); }
/* hand-inked underlines drawn by js/mission-underline.js: an absolutely
   positioned SVG layer over the statement, one wobbly stroke per accent
   word (per line box, so it survives wrapping). Sits behind the text,
   never intercepts clicks. */
.mission-ink{
  position:absolute; left:0; top:0;
  width:100%; height:100%;
  overflow:visible;
  pointer-events:none;
  z-index:0;
}
.mission-ink-stroke{
  fill:none;
  stroke:var(--pink);
  stroke-width:4.2;
  stroke-linecap:round;
  stroke-linejoin:round;
}
/* the lighter, offset second pen pass */
.mission-ink-stroke--pass2{ stroke-width:3.2; opacity:.55; }
.mission-cta{ text-align:center; margin-top:clamp(28px,4vh,40px); }

.mission-cards{
  margin-top:clamp(56px,8vh,96px);
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:clamp(28px,3.5vw,52px);
}
.mission-card{ display:flex; flex-direction:column; }
.mission-card-media{
  display:block;
  border-radius:16px;
  overflow:hidden;
  aspect-ratio:4/3;
  background:var(--cream-deep);
  box-shadow:0 18px 40px rgba(17,31,38,.14);
}
.mission-card-media img{
  width:100%; height:100%;
  object-fit:cover;
  display:block;
  transition:transform .5s ease;
}
.mission-card-media:hover img{ transform:scale(1.04); }
.mission-card-title{
  font-family:var(--font-display);
  font-size:clamp(1.35rem,2vw,1.7rem);
  line-height:1.1;
  margin:22px 0 10px;
  color:var(--ink);
}
.mission-card-title strong{ font-weight:600; }
.mission-card-title em{ font-style:italic; font-weight:500; }
.mission-card-body{
  font-size:1.02rem;
  line-height:1.55;
  color:var(--ink-soft);
  margin:0 0 16px;
}
.mission-card-link{
  margin-top:auto;
  align-self:flex-start;
  font-weight:600;
  font-size:.95rem;
  color:var(--forest); /* dark-green stand-in: bright --green fails contrast on light bg */
  text-decoration:none;
  border-bottom:2px solid var(--pink);
  padding-bottom:2px;
  transition:border-color .2s ease, color .2s ease;
}
.mission-card-link:hover{ color:var(--pink); }

@media (max-width:900px){
  .mission-cards{ grid-template-columns:1fr; gap:clamp(32px,5vw,44px); max-width:460px; margin-left:auto; margin-right:auto; }
  .mission-statement{ max-width:none; }
}

/* =======================================================================
   WHERE WE'RE BUILDING — interactive India map (js/india-map.js).
   Dark collaborate-band styling; left rows drive a viewBox zoom on the
   right-hand map. States green, active states brighter, pink court dots.
   ======================================================================= */
.reach{ background:#141732; color:var(--paper); padding:clamp(64px,9vh,120px) 0; overflow:hidden; } /* deep indigo, same as the DRISTI/collaborate band */
.reach-inner{ max-width:1220px; margin:0 auto; padding:0 clamp(20px,5vw,64px); }
.reach-head{ max-width:780px; margin-bottom:clamp(28px,4vh,52px); }
.reach .beat-eyebrow{ color:var(--pink); }
.reach-title{ font-family:var(--font-display); font-size:clamp(1.8rem,3.8vw,3.1rem); line-height:1.04; margin:.25em 0 .35em; color:var(--paper); }
.reach-lead{ color:rgba(251,248,242,.72); font-size:clamp(1rem,1.35vw,1.16rem); max-width:58ch; line-height:1.5; }
.reach-grid{ display:grid; grid-template-columns:minmax(270px,360px) 1fr; gap:clamp(24px,4vw,56px); align-items:center; }
/* phone: stack, with the map on top and sticky so tapping the cards below
   updates it while it stays in view */
@media (max-width:900px){
  .reach{ padding:clamp(44px,7vh,72px) 0; }
  .reach-grid{ grid-template-columns:1fr; gap:18px; align-items:start; }
  .reach-map{ order:-1; position:sticky; top:62px; align-self:start; }
  .reach-svg{ max-height:46vh; }
  .reach-head{ margin-bottom:22px; }
}
@media (max-width:520px){
  .rm-row{ padding:11px 12px; gap:11px; }
  .rm-thumb{ width:44px; height:44px; }
  .rm-row-label{ font-size:.98rem; }
  .rm-dlist{ margin-left:26px; }
}

.reach-list{ display:flex; flex-direction:column; gap:11px; }
.rm-item{ display:flex; flex-direction:column; }
/* Cards: dark inset panel, a state-silhouette thumbnail on the left (same
   map paths), a left accent rail + soft glow when active. */
.rm-row{ display:flex; align-items:center; gap:14px; width:100%; text-align:left;
  padding:13px 15px; border-radius:16px; position:relative; overflow:hidden;
  border:1px solid rgba(251,248,242,.1);
  background:linear-gradient(180deg, rgba(251,248,242,.05), rgba(251,248,242,.015));
  color:var(--paper); cursor:pointer; font:inherit;
  transition:border-color .25s, background .25s, transform .2s, box-shadow .25s; }
.rm-row::before{ content:""; position:absolute; left:0; top:8px; bottom:8px; width:3px; border-radius:0 3px 3px 0;
  background:var(--green); transform:scaleY(0); transform-origin:center; transition:transform .3s ease; }
.rm-row:hover{ border-color:rgba(48,207,140,.42); transform:translateY(-2px); box-shadow:0 12px 28px rgba(0,0,0,.3); }
.rm-item.is-active .rm-row{ border-color:rgba(48,207,140,.55);
  background:linear-gradient(180deg, rgba(48,207,140,.15), rgba(48,207,140,.045));
  box-shadow:0 8px 26px rgba(48,207,140,.13); }
.rm-item.is-active .rm-row::before{ transform:scaleY(1); }
.rm-item.is-all{ margin-bottom:2px; }
/* quick pulse when the row is selected by clicking its state on the map */
.rm-row.is-pinged{ animation:rmCardPulse .55s ease; }
@keyframes rmCardPulse{ 0%{ box-shadow:0 0 0 0 rgba(48,207,140,.45); } 100%{ box-shadow:0 0 0 12px rgba(48,207,140,0); } }

/* accordion: the districts a region's courts are coming up in */
.rm-expand{ display:grid; grid-template-rows:0fr; opacity:0; margin-top:0;
  transition:grid-template-rows .42s cubic-bezier(.4,.1,.2,1), opacity .3s ease, margin-top .3s ease; }
.rm-item.is-active .rm-expand{ grid-template-rows:1fr; opacity:1; margin-top:8px; }
.rm-expand-inner{ min-height:0; overflow:hidden; }
.rm-dlist{ list-style:none; margin:0 0 0 34px; padding:2px 0 2px 14px;
  display:flex; flex-direction:column; gap:1px; border-left:2px solid rgba(48,207,140,.35); }
.rm-ditem{ display:flex; align-items:center; gap:9px; padding:6px 9px; border-radius:9px; font-size:.86rem;
  color:rgba(251,248,242,.82); transition:background .2s; cursor:default; }
.rm-ditem:hover{ background:rgba(48,207,140,.09); }
.rm-ddot{ width:8px; height:8px; border-radius:50%; border:1.5px solid var(--green); box-sizing:border-box; flex:0 0 auto; }
.rm-ddot.is-live{ background:var(--green); }
.rm-dname{ flex:1 1 auto; }
.rm-ditem.is-clickable{ cursor:pointer; }
.rm-dlink{ color:inherit; text-decoration:none; }
.rm-ditem.is-clickable:hover .rm-dlink{ color:var(--green); text-decoration:underline; text-underline-offset:2px; }
.rm-dstatus{ font-size:.64rem; font-weight:700; text-transform:uppercase; letter-spacing:.06em; color:rgba(251,248,242,.45); }
.rm-dstatus.is-live{ color:var(--green); }
.rm-detail{ display:inline-flex; align-items:center; gap:6px; margin:9px 0 3px 34px; font-size:.82rem; font-weight:600;
  color:var(--green); text-decoration:none; transition:gap .2s ease, color .2s ease; }
.rm-detail:hover{ gap:9px; color:#66E0A9; }
.rm-detail svg{ transition:transform .2s ease; }
.rm-detail:hover svg{ transform:translateX(2px); }

.rm-thumb{ width:50px; height:50px; flex:0 0 auto; border-radius:12px; display:flex; align-items:center; justify-content:center;
  background:rgba(10,21,26,.55); border:1px solid rgba(251,248,242,.09); transition:background .25s, border-color .25s; }
.rm-thumb svg{ width:100%; height:100%; padding:7px; box-sizing:border-box; overflow:visible; display:block; }
.rm-th{ fill:rgba(251,248,242,.16); transition:fill .25s; }
.rm-th.is-live{ fill:var(--green); }
.rm-row:hover .rm-thumb{ border-color:rgba(48,207,140,.3); }
.rm-item.is-active .rm-thumb{ background:rgba(48,207,140,.12); border-color:rgba(48,207,140,.4); }

.rm-row-main{ display:flex; flex-direction:column; gap:2px; flex:1 1 auto; min-width:0; }
.rm-row-label{ font-weight:600; font-size:1.04rem; }
.rm-row-sub{ font-size:.8rem; color:rgba(251,248,242,.55); }
.rm-live{ display:inline-flex; align-items:center; gap:6px; font-size:.7rem; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--green); flex:0 0 auto; }
.rm-live-dot{ width:8px; height:8px; border-radius:50%; background:var(--green); animation:rmLive 2.4s infinite; }
.rm-soon{ font-size:.64rem; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:rgba(251,248,242,.62);
  border:1px solid rgba(251,248,242,.2); border-radius:999px; padding:3px 9px; flex:0 0 auto; white-space:nowrap; }
@keyframes rmLive{ 0%{ box-shadow:0 0 0 0 rgba(48,207,140,.5);} 70%{ box-shadow:0 0 0 8px rgba(48,207,140,0);} 100%{ box-shadow:0 0 0 0 rgba(48,207,140,0);} }

/* Map: DRISTI look — ghosted paper silhouette, green outline + faint green
   fill on the active states/districts, green dot + pulsing ping. */
.reach-map{ position:relative; display:flex; justify-content:center; }
.reach-svg{ width:100%; height:auto; max-height:78vh; display:block; overflow:visible; }
.rm-state{ fill:rgba(251,248,242,.055); stroke:rgba(251,248,242,.13); stroke-width:.55; stroke-linejoin:round;
  transition:fill .5s ease, stroke .5s ease, opacity .5s ease; }
.rm-state.is-live{ fill:rgba(48,207,140,.18); stroke:var(--green); stroke-width:1.4; }
.rm-state.is-hover{ fill:rgba(48,207,140,.3); }
.rm-state.is-faded{ opacity:.28; }
.rm-state.is-selected{ fill:rgba(251,248,242,.04); stroke:rgba(251,248,242,.11); stroke-width:.55; }
/* a small beam of light runs around the perimeter of the states / court
   districts we're in. pathLength=100 (set in JS) normalises the dash. */
.rm-beam{ fill:none; stroke:rgba(207,255,236,.5); stroke-width:1.2; stroke-linecap:round; stroke-linejoin:round;
  stroke-dasharray:5 95; transition:opacity .5s ease;
  filter:drop-shadow(0 0 1.5px rgba(48,207,140,.5));
  animation:rmBeam 4.2s linear infinite; }
@keyframes rmBeam{ from{ stroke-dashoffset:0; } to{ stroke-dashoffset:-100; } }
/* multi-state regions: distinguish each member (e.g. Punjab / Haryana /
   Chandigarh UT) with a soft outline + a name label */
.rm-stateline{ fill:none; stroke:rgba(207,255,236,.26); stroke-width:1.1; stroke-linejoin:round; transition:opacity .4s ease; }
.rm-label{ fill:var(--paper); stroke:#141732; stroke-width:3; font-family:'Source Sans 3', sans-serif;
  font-weight:700; letter-spacing:.03em; text-transform:uppercase; pointer-events:none; transition:opacity .4s ease; }
.rm-labelline{ stroke:rgba(251,248,242,.38); stroke-width:1; transition:opacity .4s ease; }
.rm-districts{ transition:opacity .5s ease; }
.rm-district{ fill:rgba(251,248,242,.05); stroke:rgba(251,248,242,.12); stroke-width:.5; stroke-linejoin:round;
  transition:fill .4s ease, stroke .4s ease; pointer-events:none; }   /* inactive districts: no hover */
.rm-district.is-court{ fill:rgba(48,207,140,.2); stroke:var(--green); stroke-width:1.4; pointer-events:auto; cursor:pointer; }
.rm-district.is-court:hover{ fill:rgba(48,207,140,.32); }
.rm-dots{ pointer-events:auto; }
/* green court dots: a DARK radial gradient (rich green core -> near-black
   edge) for a deep, matte bead — a dark shadow lifts it off the map with just
   a soft green glow, no light-reflective sheen. Pulsing green ring. */
.rm-dot{ fill:url(#rmDotGrad); stroke:none; cursor:pointer;
  filter:drop-shadow(0 1.5px 3px rgba(0,0,0,.72)) drop-shadow(0 0 3px rgba(48,207,140,.45)); }
.rm-dot.is-live{ filter:drop-shadow(0 2px 4px rgba(0,0,0,.78)) drop-shadow(0 0 6px rgba(48,207,140,.72)); }
.rm-ping{ fill:none; stroke:var(--green); stroke-width:1.6; opacity:.65; transform-box:fill-box; transform-origin:center;
  animation:rmPing 2.4s ease-out infinite; }
@keyframes rmPing{ 0%{ transform:scale(1); opacity:.8; } 70%{ transform:scale(3.2); opacity:0; } 100%{ transform:scale(3.2); opacity:0; } }

.rm-tip{ position:absolute; transform:translate(-50%,-145%); background:#111F26; color:var(--paper);
  border:1px solid rgba(48,207,140,.5); padding:5px 11px; border-radius:8px; font-size:.8rem; font-weight:600;
  white-space:nowrap; pointer-events:none; opacity:0; transition:opacity .18s; z-index:6; box-shadow:0 6px 20px rgba(0,0,0,.4); }
.rm-tip.is-on{ opacity:1; }
@media (prefers-reduced-motion:reduce){ .rm-live-dot,.rm-ping,.rm-row.is-pinged{ animation:none!important; } .rm-beam{ animation:none!important; opacity:0!important; } }

/* ================= The 10 Unlocks (DRISTI page) ================= */
.unlocks{
  background:#101229;               /* a shade deeper than the #141732 bands it sits between */
  color:var(--paper);
  padding: clamp(64px,9vw,110px) clamp(20px,5vw,72px);
  border-top:1px solid rgba(255,255,255,.06);
  border-bottom:1px solid rgba(255,255,255,.06);
  position:relative;
}
.unlocks-head{ max-width:700px; margin:0 auto 34px; text-align:center; }
.unlocks .beat-eyebrow{ color:var(--green); }
.unlocks-title{ font-size:clamp(2rem,4.5vw,3.2rem); line-height:1.08; margin-bottom:14px; }
.unlocks-sub{ color:rgba(251,248,242,.72); line-height:1.6; font-size:1.02rem; }

/* dashboard: running tally + progress */
.unlocks-dash{
  max-width:960px; margin:0 auto 22px;
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:22px 46px;
  padding:22px 26px; border-radius:18px;
  background:linear-gradient(180deg, rgba(48,207,140,.09), rgba(48,207,140,.02));
  border:1px solid rgba(48,207,140,.22);
}
.unlocks-tally{ display:flex; flex-direction:column; align-items:center; min-width:180px; }
.ut-num{ font-family:var(--font-display); font-weight:600; line-height:1; display:flex; align-items:baseline; gap:8px; color:var(--green); }
.ut-num [data-count]{ font-size:clamp(3rem,7vw,4.6rem); font-variant-numeric:tabular-nums; }
.ut-unit{ font-size:1.1rem; color:rgba(48,207,140,.82); }
.ut-cap{ margin-top:6px; font-size:.86rem; color:rgba(251,248,242,.6); text-align:center; max-width:220px; }
.unlocks-progress{ flex:1 1 320px; max-width:460px; }
.up-label{ font-size:.76rem; font-weight:700; letter-spacing:.05em; text-transform:uppercase; color:rgba(251,248,242,.7); margin-bottom:8px; }
.up-bar{ height:8px; border-radius:99px; background:rgba(255,255,255,.09); overflow:hidden; }
.up-fill{ display:block; height:100%; width:0; border-radius:99px; background:linear-gradient(90deg,#30CF8C,#66E0A9); transition:width .5s cubic-bezier(.16,.8,.3,1); }
.up-actions{ margin-top:12px; display:flex; gap:10px; }
.up-all,.up-reset{ font:inherit; font-size:.82rem; font-weight:600; cursor:pointer; padding:7px 16px; border-radius:99px; border:1px solid rgba(48,207,140,.5); background:transparent; color:var(--paper); transition:background .2s,border-color .2s,color .2s; }
.up-all{ background:var(--green); border-color:var(--green); color:#08281b; }
.up-all:hover{ background:#66E0A9; border-color:#66E0A9; }
.up-reset:hover{ background:rgba(255,255,255,.07); }

/* dimension filters */
.unlocks-filters{ display:flex; flex-wrap:wrap; gap:10px; justify-content:center; margin:0 auto 26px; }
.uf{ font:inherit; font-size:.86rem; font-weight:600; cursor:pointer; padding:8px 18px; border-radius:99px; border:1px solid rgba(255,255,255,.18); background:transparent; color:rgba(251,248,242,.8); transition:border-color .2s,color .2s,background .2s; }
.uf:hover{ border-color:rgba(48,207,140,.6); color:var(--paper); }
.uf.is-active{ background:var(--green); border-color:var(--green); color:#08281b; }

/* card grid */
.unlocks-grid{ max-width:1080px; margin:0 auto; display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); gap:16px; align-items:start; }
.unlock{
  border-radius:16px; overflow:hidden;
  background:rgba(255,255,255,.035);
  border:1px solid rgba(255,255,255,.1);
  transition:border-color .25s, background .25s, transform .25s, box-shadow .25s;
}
.unlock:hover{ transform:translateY(-3px); border-color:rgba(48,207,140,.4); box-shadow:0 14px 34px rgba(0,0,0,.34); }
.unlock.is-open{ background:rgba(48,207,140,.06); border-color:rgba(48,207,140,.5); }

.unlock-face{
  width:100%; text-align:left; cursor:pointer; font:inherit; color:inherit;
  background:none; border:0; padding:18px 18px 16px; display:flex; flex-direction:column; gap:8px;
}
.unlock-top{ display:flex; align-items:center; justify-content:space-between; }
.unlock-no{ font-family:var(--font-display); font-size:1.3rem; font-weight:600; color:rgba(251,248,242,.4); }
.unlock.is-open .unlock-no{ color:var(--green); }
.unlock-lock{ color:rgba(251,248,242,.5); transition:color .3s; overflow:visible; }
.unlock.is-open .unlock-lock{ color:var(--green); }
.unlock-lock .shk{ transform-origin:16px 8px; transition:transform .38s cubic-bezier(.5,-0.4,.3,1.5); }
.unlock.is-open .unlock-lock .shk{ transform:translateY(-2px) rotate(26deg); }
.unlock-dim{ font-size:.66rem; font-weight:700; text-transform:uppercase; letter-spacing:.08em; }
.u-efficiency{ color:#30CF8C; }
.u-predictability{ color:#E9B94A; }
.u-seamlessness{ color:#DA6EAA; }
.unlock-title{ font-family:var(--font-display); font-size:1.35rem; line-height:1.15; font-weight:500; }
.unlock-metric{ align-self:flex-start; display:inline-flex; align-items:center; gap:6px; font-size:.8rem; font-weight:700; color:var(--green); background:rgba(48,207,140,.12); padding:4px 11px; border-radius:99px; }
.unlock-cue{ font-size:.7rem; font-weight:700; text-transform:uppercase; letter-spacing:.06em; color:rgba(251,248,242,.4); }
.unlock-cue .uc-open{ display:none; color:var(--green); }
.unlock.is-open .unlock-cue .uc-lock{ display:none; }
.unlock.is-open .unlock-cue .uc-open{ display:inline; }

/* body reveal (grid-rows 0fr -> 1fr for smooth auto-height) */
.unlock-body{ display:grid; grid-template-rows:0fr; transition:grid-template-rows .4s cubic-bezier(.16,.8,.3,1); }
.unlock.is-open .unlock-body{ grid-template-rows:1fr; }
.ub-inner{ overflow:hidden; }
.ub-cols{ display:grid; gap:10px; padding:0 18px 18px; }
.ub-col{ border-radius:11px; padding:12px 13px; font-size:.86rem; line-height:1.5; }
.ub-before{ background:rgba(255,255,255,.05); color:rgba(251,248,242,.72); }
.ub-after{ background:rgba(48,207,140,.1); color:var(--paper); border:1px solid rgba(48,207,140,.25); }
.ub-tag{ display:block; font-size:.64rem; font-weight:800; text-transform:uppercase; letter-spacing:.08em; margin-bottom:5px; }
.ub-before .ub-tag{ color:rgba(251,248,242,.45); }
.ub-after .ub-tag{ color:var(--green); }

.unlocks-foot{ max-width:780px; margin:34px auto 0; text-align:center; font-size:.92rem; line-height:1.6; color:rgba(251,248,242,.66); }
.unlocks-foot a{ color:var(--green); }

@media (max-width:560px){
  .unlocks-dash{ flex-direction:column; }
  .ut-cap{ max-width:none; }
}
@media (prefers-reduced-motion:reduce){
  .unlock-lock .shk, .unlock-body, .up-fill, .unlock{ transition:none!important; }
}

/* ================= Who benefits (DRISTI page) ================= */
.benefits{
  background:#141732;
  color:var(--paper);
  padding: clamp(64px,9vw,110px) clamp(20px,5vw,72px);
  border-bottom:1px solid rgba(255,255,255,.06);
}
.benefits-head{ max-width:720px; margin:0 auto 30px; text-align:center; }
.benefits .beat-eyebrow{ color:var(--green); }
.benefits-title{ font-size:clamp(2rem,4.5vw,3.2rem); line-height:1.08; margin-bottom:14px; }
.benefits-sub{ color:rgba(251,248,242,.72); line-height:1.6; font-size:1.02rem; }

.benefits-switch{ display:flex; flex-wrap:wrap; justify-content:center; gap:12px; max-width:760px; margin:0 auto 24px; }
.role-btn{ font:inherit; cursor:pointer; display:flex; flex-direction:column; align-items:center; gap:9px; width:124px; padding:16px 10px; border-radius:14px; background:rgba(255,255,255,.04); border:1px solid rgba(255,255,255,.12); color:rgba(251,248,242,.72); transition:border-color .2s,background .2s,color .2s,transform .2s; }
.role-btn:hover{ border-color:rgba(48,207,140,.5); color:var(--paper); transform:translateY(-2px); }
.role-btn.is-active{ background:rgba(48,207,140,.1); border-color:var(--green); color:var(--paper); }
.role-ic{ width:46px; height:46px; border-radius:50%; display:grid; place-items:center; background:rgba(255,255,255,.06); color:rgba(251,248,242,.6); transition:background .2s,color .2s; }
.role-btn.is-active .role-ic{ background:var(--green); color:#08281b; }
.role-ic svg{ width:24px; height:24px; }
.role-name{ font-size:.92rem; font-weight:600; }

.benefits-stage{ max-width:820px; margin:0 auto; }
.role-panel{ display:none; }
.role-panel.is-active{ display:block; animation:benefitIn .45s cubic-bezier(.16,.8,.3,1); }
@keyframes benefitIn{ from{ opacity:0; transform:translateY(14px); } to{ opacity:1; transform:none; } }
.role-card{ display:grid; grid-template-columns:auto 1fr; gap:26px 34px; align-items:center; background:rgba(255,255,255,.035); border:1px solid rgba(48,207,140,.28); border-radius:18px; padding:28px 30px; }
.role-stat{ text-align:center; padding-right:28px; border-right:1px solid rgba(255,255,255,.1); }
.role-stat-num{ font-family:var(--font-display); font-weight:600; font-size:clamp(2.2rem,5vw,3.2rem); color:var(--green); line-height:1; }
.role-stat-cap{ margin-top:8px; font-size:.85rem; color:rgba(251,248,242,.6); max-width:170px; margin-inline:auto; line-height:1.35; }
.role-benefits{ list-style:none; margin:0; padding:0; display:grid; gap:11px; }
.role-benefits li{ position:relative; padding-left:28px; font-size:.98rem; line-height:1.45; color:rgba(251,248,242,.86); }
.role-benefits li::before{ content:""; position:absolute; left:0; top:.15em; width:18px; height:18px; border-radius:50%;
  background:rgba(48,207,140,.16) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.4l2.6 2.6L12 5.2' fill='none' stroke='%2330CF8C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/11px 11px no-repeat; }
@media (max-width:640px){
  .role-card{ grid-template-columns:1fr; gap:18px; }
  .role-stat{ border-right:0; border-bottom:1px solid rgba(255,255,255,.1); padding:0 0 16px; }
}

.dristi-survey{ max-width:960px; margin:6px auto 44px; }
.dristi-survey .beat-eyebrow{ color:var(--green); text-align:center; margin-bottom:22px; }
.survey-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:28px 60px; }
.survey-group{ display:grid; gap:22px; }
.survey-grp-label{ font-size:.8rem; font-weight:700; letter-spacing:.12em; text-transform:uppercase; color:var(--green); margin:0; }
.survey-item{ display:flex; align-items:baseline; gap:18px; }
.survey-num{ font-family:var(--font-display); font-weight:600; font-size:clamp(2.6rem,5.5vw,3.7rem); color:var(--green); min-width:118px; line-height:1; }
.survey-txt{ font-size:1.1rem; color:rgba(251,248,242,.85); line-height:1.35; }
.survey-src{ text-align:center; margin:28px 0 0; font-size:.82rem; color:rgba(251,248,242,.45); }

@media (prefers-reduced-motion:reduce){
  .role-panel.is-active{ animation:none; }
  .role-btn:hover{ transform:none; }
}

/* ================= Careers JD modal ================= */
.about-steps-lead{ margin-top:10px; }
.jdm-overlay{ position:fixed; inset:0; z-index:1000; display:flex; align-items:flex-start; justify-content:center;
  padding:clamp(16px,5vh,64px) 16px; background:rgba(8,10,24,.66); overflow-y:auto; }
.jdm-overlay[hidden]{ display:none; }
body.jdm-open{ overflow:hidden; }
.jdm-dialog{ position:relative; width:min(720px,100%); background:var(--paper); color:var(--ink); border-radius:20px;
  padding:clamp(28px,4vw,46px); box-shadow:0 30px 80px rgba(0,0,0,.5); animation:jdmIn .3s cubic-bezier(.16,.8,.3,1); }
@keyframes jdmIn{ from{ opacity:0; transform:translateY(18px); } to{ opacity:1; transform:none; } }
.jdm-close{ position:absolute; top:14px; right:16px; width:38px; height:38px; border-radius:50%; border:1px solid var(--line);
  background:transparent; color:var(--ink-soft); font-size:1.5rem; line-height:1; cursor:pointer; transition:background .2s,color .2s; }
.jdm-close:hover{ background:var(--cream-deep); color:var(--ink); }
.jdm-eyebrow{ color:var(--green); margin:0 0 10px; }
.jdm-title{ font-family:var(--font-display); font-weight:500; font-size:clamp(1.6rem,3.4vw,2.2rem); line-height:1.1; margin:0 0 12px; padding-right:40px; }
.jdm-summary{ font-size:1.05rem; line-height:1.5; color:var(--ink-soft); margin:0 0 16px; }
.jdm-body .job-chips{ margin:0 0 18px; }
.jdm-body .job-body{ margin-top:4px; }
.jdm-cta{ margin-top:24px; }
.career-row{ cursor:pointer; }
.career-openings{ display:inline-block; vertical-align:middle; font-family:var(--font-body); font-weight:700;
  font-size:.7rem; letter-spacing:.04em; text-transform:uppercase; color:#08281b; background:var(--green);
  padding:3px 10px; border-radius:999px; white-space:nowrap; }
.career-row-title .career-openings{ margin-left:8px; position:relative; top:-1px; }
.jdm-openings{ margin:0 0 12px; }
.job-openings{ margin:0 0 14px; }
/* compact "how hiring works" block embedded inside each role's JD (modal +
   role page) — a vertical 4-step timeline that fits the narrow dialog */
.jd-hiring{ margin:30px 0 6px; padding:22px 24px; border:1px solid rgba(36,30,26,.14); border-radius:16px;
  background:rgba(48,207,140,.06); }
.jd-hiring-eyebrow{ text-transform:uppercase; letter-spacing:.12em; font-size:.72rem; font-weight:700; color:var(--forest); margin:0 0 5px; }
.jd-hiring-title{ font-family:var(--font-display); font-size:1.35rem; line-height:1.12; margin:0 0 18px; }
.jd-hiring-steps{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:14px; }
.jd-hiring-steps li{ display:flex; gap:13px; align-items:flex-start; }
.jhs-node{ flex:0 0 auto; width:27px; height:27px; border-radius:50%; background:var(--green); color:#08281b;
  font-weight:700; font-size:.9rem; display:flex; align-items:center; justify-content:center; }
.jd-hiring-steps li > div{ display:flex; flex-direction:column; gap:2px; }
.jd-hiring-steps strong{ font-size:1rem; color:var(--ink); }
.jd-hiring-steps span{ color:var(--ink-soft); font-size:.92rem; line-height:1.45; }
.jd-hiring-note{ margin:16px 0 0; font-size:.88rem; color:var(--ink-soft); line-height:1.5; }
.jd-hiring-badge{ display:inline-block; background:var(--green); color:#08281b; font-weight:700; font-size:.72rem;
  letter-spacing:.04em; padding:4px 10px; border-radius:999px; margin-right:9px; }
/* careers page with no hero/intro: collapse the empty <main> so the roles
   board sits directly under the header */
main.job-main.careers-lean{ padding:0; min-height:0; }
.careers-board-lead{ padding-top:clamp(84px,10vw,120px); }
@media (prefers-reduced-motion:reduce){ .jdm-dialog{ animation:none; } }

/* ================= Careers hiring process (4-step timeline) ================= */
.hiring{ background:var(--paper); color:var(--ink); padding:clamp(64px,9vw,110px) clamp(20px,5vw,72px); }
.hiring-head{ max-width:720px; margin:0 auto 46px; text-align:center; }
.hiring .beat-eyebrow{ color:var(--forest); }
.hiring-title{ font-size:clamp(2rem,4.5vw,3rem); line-height:1.08; margin-bottom:14px; }
.hiring-sub{ color:var(--ink-soft); line-height:1.6; font-size:1.02rem; }
.hiring-steps{ position:relative; list-style:none; margin:0 auto; padding:0; max-width:1000px;
  display:grid; grid-template-columns:repeat(4,1fr); gap:24px; }
.hiring-steps::before{ content:""; position:absolute; top:31px; left:12.5%; right:12.5%; height:2px;
  background:rgba(36,30,26,.16); z-index:0; }
.hiring-step{ position:relative; z-index:1; text-align:center; padding-top:8px; }
.hs-node{ width:46px; height:46px; border-radius:50%; display:grid; place-items:center; margin:0 auto 16px;
  font-family:var(--font-display); font-weight:600; font-size:1.2rem; color:#08281b; background:var(--green);
  box-shadow:0 0 0 6px var(--paper); }
.hs-title{ font-family:var(--font-display); font-weight:500; font-size:1.1rem; line-height:1.2; margin:0 0 6px; }
.hs-desc{ font-size:.9rem; line-height:1.45; color:var(--ink-soft); max-width:23ch; margin:0 auto; }
.hiring-note{ text-align:center; margin:42px 0 0; font-size:.98rem; color:var(--ink-soft); }
.hiring-badge{ display:inline-block; font-weight:700; font-size:.78rem; letter-spacing:.03em; text-transform:uppercase;
  color:#08281b; background:var(--green); padding:4px 12px; border-radius:999px; margin-right:9px; }
@media (max-width:720px){
  .hiring-steps{ grid-template-columns:1fr; gap:0; max-width:440px; }
  .hiring-steps::before{ display:none; }
  .hiring-step{ text-align:left; display:grid; grid-template-columns:46px 1fr; gap:16px; padding:0 0 26px; }
  .hiring-step::before{ content:""; position:absolute; left:22px; top:46px; bottom:0; width:2px;
    background:rgba(36,30,26,.16); z-index:0; }
  .hiring-step:last-child::before{ display:none; }
  .hs-node{ margin:0; }
  .hs-title{ margin-top:9px; }
  .hs-desc{ max-width:none; margin:0; }
}
