/* ---------- self-hosted fonts, not a Google Fonts <link> ----------
   a remote stylesheet fetch + async @font-face swap races any tool that grabs a
   screenshot on the page's load event without waiting for webfonts (confirmed: this
   project's own screenshot.sh -- a bare chrome-headless-shell --screenshot call -- does
   not wait for the swap, even with <link rel=preload> hints added). embedding the two
   Latin-subset weights this shell actually uses (Outfit 400; Manrope 400/500, the
   500 instance is the same variable-font file Google serves for the 400 request)
   as same-origin, long-cache-headered files under site/assets/fonts/ (see .htaccess
   for the cache rule). Paths are relative to this file (site/assets/site.css). */
@font-face{font-family:"Outfit";font-style:normal;font-weight:400;font-display:swap;src:url(fonts/outfit-400.woff2) format("woff2")}
@font-face{font-family:"Manrope";font-style:normal;font-weight:400;font-display:swap;src:url(fonts/manrope-400.woff2) format("woff2")}
@font-face{font-family:"Manrope";font-style:normal;font-weight:500;font-display:swap;src:url(fonts/manrope-400.woff2) format("woff2")}

/* ===== shared: tokens, nav, footer, overlays, panel, chip, glass, scroll (from ease-clear-v2.html) + the login modal (.lmodal*, byte-identical in video/library/time-to-play/exercise.html — hoisted here from video.html so it ships once) ===== */

:root{
  /* palette sampled directly off the third-edition cover */
  --white:#FFFFFF;
  --deep:#24261F;          /* cover charcoal */
  --deep-2:#4A4C45;
  --muted:#7A7C74;
  --yellow:#FFBF00;        /* the ONLY yellow */
  --blue:#0050EF;          /* the blue */
  --blue-pale:#C2D4FF;
  --pink:#B73648;          /* the cover Doppler magenta */
  --grey-1:#EDEDEC;        /* cover light grey */
  --grey-2:#C0C0BF;
  --line:#E4E4E2;

  /* frosted glass: translucency + backdrop blur + a hairline edge.
     no gloss, no sheen, no shadows. */
  --glass-white:rgba(250,251,250,.56);
  --glass-grey:rgba(216,220,216,.56);   /* the clear boxes, a touch darker so they read */
  --glass-dark:rgba(20,22,18,.86);
  --glass-yellow:rgba(255,191,0,.90);   /* punchy again */
  --glass-blue:rgba(0,80,239,.88);
  --glass-pink:rgba(183,54,72,.90);     /* the cover Doppler magenta */
  /* definition: a soft dark hairline reads against white, an inner light hairline
     gives the glass its edge. no shadows involved. */
  --ring:rgba(28,32,26,.16);
  --ring-in:rgba(255,255,255,.85);
  --ring-dark:rgba(255,255,255,.26);
  --blur:saturate(2) blur(40px);
  --blur-sm:saturate(1.8) blur(20px);

  --display:"Outfit",system-ui,sans-serif;   /* headings, regular weight only */
  --sans:"Manrope",system-ui,sans-serif;     /* everything else */

  /* ---------- fluid scale, stage one ----------
     every token is written so its value at 1440 is exactly what it always was.
     below 1440 the floor holds and nothing moves; above 1440 the vw term takes
     over and the whole page — type, padding, gutters, radii — keeps growing
     with the screen instead of sitting in the middle of it. */

  /* ---------- fluid scale, stage two: --ux / --uw ----------
     stage one stops. every clamp above has a ceiling, and those ceilings land at
     eleven different widths between 1600 and 2270 — so on a screen wider than
     that, some elements had stopped growing while their neighbours were still
     going, and past ~2270 the whole design froze into a fixed island floating in
     the middle of the screen. that is what "it breaks at 2030" and "the content
     squeezes together on a big screen" both were.

     these two units carry the growth past the ceilings. both are 0 up to 1728 —
     the width this design was calibrated on — so EVERY size at or below that
     width is arithmetically identical to what it always was. above it, each size
     resumes growing at its own original vw rate (see the `+ N * var(--ux)` terms),
     so the proportions of the design are preserved instead of drifting apart.

       --uw  width only.  drives the content container: a wider screen should hold
             a wider column, even if it is short.
       --ux  the SMALLER of the width and height growth. drives type and spacing:
             on a 3440x1440 ultrawide there is plenty of width but no vertical
             room, so type must not blow up the way raw vw would make it.

     both are calibrated to reach 6px at 3840x2160, which is what turns 19px body
     text into 25px and a 1500px column into 2940px on a 4K screen. */
  --uw:clamp(0px, calc(.2841vw - 4.909px), 9px);
  --ux:clamp(0px, min(calc(.2841vw - 4.909px), calc(.5752vh - 6.425px)), 8px);
  --r:calc(clamp(14px,.97vw,20px) + .97 * var(--ux));
  --r-chip:7px;
  --gap:calc(clamp(18px,1.53vw,34px) + 1.53 * var(--ux));     /* 22px at 1440 */
  --pad:calc(clamp(24px,2.9vw,62px) + 2.9 * var(--ux));      /* 42px at 1440 */
  --pad-lg:calc(clamp(28px,4.9vw,104px) + 4.9 * var(--ux));  /* 70px at 1440, the big slabs */
  --sec:calc(clamp(84px,9vw,196px) + 9 * var(--ux));
  /* the gutter and the two containers are horizontal, so they take --uw: they
     widen on any wide screen, short or tall. --page was the single worst offender
     on big screens — a hard 1500px cap with a GROWING --edge inside it, so the
     usable column got narrower the bigger the screen got (1402px at 1512 down to
     1268px at 3840). it now grows with the screen: the column holds ~80% of the
     viewport at 1728 and ~70% at 4K instead of collapsing to 33%. */
  --edge:calc(clamp(22px,3.25vw,116px) + 3.25 * var(--uw));   /* ~47px at 1440, a touch wider margins */
  --page:calc(1500px + 240 * var(--uw));    /* 1500 to 1728, 2940 at 4K */
  --page-n:calc(1300px + 117 * var(--uw));  /* the narrow measure, 1300 -> 2000 */
  /* the size the full-bleed hero shrinks to when the frame pins. read by the
     scroll choreography, so the card keeps its proportion instead of staying a
     640px postage stamp on a 4K screen. */
  --card-max:calc(640px + 93 * var(--uw));

  /* type. same rule: the 1440 value is the floor. */
  --t-xs:calc(clamp(13px,.903vw,16.5px) + .903 * var(--ux));
  --t-sm:calc(clamp(13.5px,.938vw,17px) + .938 * var(--ux));
  --t-14:calc(clamp(14px,.972vw,17.5px) + .972 * var(--ux));
  --t-145:calc(clamp(14.5px,1.007vw,18px) + 1.007 * var(--ux));
  --t-15:calc(clamp(15px,1.042vw,19px) + 1.042 * var(--ux));
  --t-165:calc(clamp(16.5px,1.146vw,20.5px) + 1.146 * var(--ux));
  --t-17:calc(clamp(17px,1.181vw,21px) + 1.181 * var(--ux));
  --t-19:calc(clamp(19px,1.319vw,24px) + 1.319 * var(--ux));

  --ease:cubic-bezier(.22,1,.36,1);
  --nav-h:64px;

  /* page-level tokens restored from the mockups' own :root blocks (T4-F3):
     each was added by one or more mockups on top of the shared block above,
     then dropped when those mockups' :root blocks were deleted as "duplicate
     selectors" during the site.css merge. Identical value in every mockup
     that defined it, so hoisted here rather than page-scoped. */
  --pad-sm:calc(clamp(14px,.972vw,18px) + .972 * var(--ux));                 /* post, blog, time-to-play, exercise, library.html:86 */
  --rail-w:calc(clamp(270px,18.75vw,300px) + 18.75 * var(--ux));             /* post, blog, time-to-play, exercise, library.html:87 */
  --rail-thumb:calc(clamp(32px,2.222vw,40px) + 2.222 * var(--ux));           /* time-to-play, exercise, library.html:88 */
  --row-thumb:calc(clamp(52px,3.611vw,64px) + 3.611 * var(--ux));            /* time-to-play, exercise, library.html:89 */
  --play-circle:calc(clamp(44px,3.056vw,54px) + 3.056 * var(--ux));         /* video, time-to-play, exercise, library.html:90 */
  --play-lg:calc(clamp(56px,5vw,72px) + 5 * var(--ux));                     /* only video.html's own :root ever defined this,
                                                                                 but render_player() puts .sau-player on every
                                                                                 content page, so it must be a real global now
                                                                                 (T-SHARED-1) — video.html's value, unchanged. */
  --t-22:calc(clamp(22px,1.528vw,28px) + 1.528 * var(--ux));                 /* blog, post.html:87 */
  --t-13:calc(clamp(12.5px,.868vw,16px) + .868 * var(--ux));                 /* blog, post.html:88 */
  --post-thumb-list:calc(clamp(112px,7.778vw,150px) + 7.778 * var(--ux));    /* post, blog.html:92 */
}

*{box-sizing:border-box;margin:0;padding:0}

.amb{position:fixed;inset:-28%;z-index:-1;pointer-events:none}

.amb span{position:absolute;display:block;border-radius:50%}

/* the three cover colours — yellow, blue, pink — turned up so the frosted
   surfaces visibly refract them. this ambient IS the glass look.

   ⚠ THE BLOBS DO NOT DRIFT ON THIS PAGE, DELIBERATELY. 18 elements here carry
   backdrop-filter (.ex-quiz among them), and a backdrop-filter over a MOVING
   backdrop must be re-sampled and re-blurred every single frame. Measured on
   ?e=40: 110ms/frame (~9fps) sitting idle with the drift on, 16.7ms (60fps)
   with it off — which is why clicking a quiz option felt like it was loading.
   The colour is what makes the glass read; the 30-41s drift was imperceptible
   and cost 6.6x the frame budget. Each blob is frozen at its mid-drift
   transform, so the composition is still placed rather than default. */
.amb .b1{width:62vw;height:62vw;left:-10%;top:-12%;transform:translate3d(4vw,3vh,0) scale(1.11);
  background:radial-gradient(circle,rgba(255,191,0,.28) 0%,rgba(255,191,0,.10) 40%,rgba(255,191,0,0) 78%)}

.amb .b2{width:66vw;height:66vw;right:-14%;top:-4%;transform:translate3d(-4vw,4.5vh,0) scale(1.01);
  background:radial-gradient(circle,rgba(0,80,239,.20) 0%,rgba(0,80,239,.07) 40%,rgba(0,80,239,0) 78%)}

.amb .b3{width:58vw;height:58vw;right:4%;top:48%;transform:translate3d(-4.5vw,-3.5vh,0) scale(1.08);
  background:radial-gradient(circle,rgba(183,54,72,.17) 0%,rgba(183,54,72,.06) 40%,rgba(183,54,72,0) 78%)}

.amb .b4{width:50vw;height:50vw;left:6%;bottom:-12%;transform:translate3d(5.5vw,-3.5vh,0) scale(1.03);
  background:radial-gradient(circle,rgba(255,191,0,.19) 0%,rgba(255,191,0,.06) 40%,rgba(255,191,0,0) 78%)}

/* ---------- grain ----------
   a fine film grain over the whole page: an svg turbulence tile, overlay-blended
   so it lives in the material of both the light and the dark sections. the layer
   is 3x the viewport and jumps position in steps, like real grain. */
.grain{position:fixed;inset:-100%;z-index:200;pointer-events:none;opacity:.13;
  will-change:transform;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='280' height='280'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='2.2' intercept='-0.6'/%3E%3CfeFuncG type='linear' slope='2.2' intercept='-0.6'/%3E%3CfeFuncB type='linear' slope='2.2' intercept='-0.6'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 9s steps(10) infinite}

@keyframes grain{
  0%,100%{transform:translate(0,0)}
  10%{transform:translate(-5%,-8%)}
  20%{transform:translate(-13%,4%)}
  30%{transform:translate(6%,-14%)}
  40%{transform:translate(-4%,13%)}
  50%{transform:translate(-12%,-7%)}
  60%{transform:translate(11%,3%)}
  70%{transform:translate(2%,10%)}
  80%{transform:translate(-8%,-2%)}
  90%{transform:translate(9%,-9%)}
}

/* ---------- the echo texture ----------
   past the hero, everything carries the mottled speckle of a b-mode image: a
   coarse, slightly lateral-smeared turbulence cloud, mostly black so difference
   blending leaves only the echo blobs — lightening the dark sections, shading
   the light ones. the fine .grain above completes the ultrasound material. */
.usfx{position:fixed;inset:0;z-index:199;pointer-events:none;opacity:0;mix-blend-mode:difference;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='420' height='420'%3E%3Cfilter id='u'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.42 0.6' numOctaves='2' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='1.3' intercept='-0.65'/%3E%3CfeFuncG type='linear' slope='1.3' intercept='-0.65'/%3E%3CfeFuncB type='linear' slope='1.3' intercept='-0.65'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23u)'/%3E%3C/svg%3E");
  background-size:420px 420px}


/* No global scroll-behavior:smooth: Chrome applies it to cross-document #hash arrivals and
   direct loads too (the FAQ menu item glided down the whole home page). Short same-page
   hops are smoothed by the click handler in site.js instead. */
html{-webkit-text-size-adjust:100%}

body{background:var(--white);color:var(--deep);font-family:var(--sans);font-size:var(--t-15);line-height:1.6;
  -webkit-font-smoothing:antialiased;overflow-x:hidden}

img{display:block;max-width:100%}

a{color:inherit;text-decoration:none}

:focus-visible{outline:2px solid var(--deep);outline-offset:3px}


.dsp{font-family:var(--display);font-weight:400;color:var(--deep);letter-spacing:-.01em;line-height:.98}

.d1{font-size:calc(clamp(2.1rem,4.15vw,5.5rem) + 4.15 * var(--ux))}

.d2{font-size:calc(clamp(1.75rem,3.1vw,4.1rem) + 3.1 * var(--ux));line-height:1.06}

.lede{font-size:var(--t-15);line-height:1.6;color:var(--deep-2);max-width:36em}

.tiny{font-size:var(--t-xs);color:var(--muted)}

h3{font-family:var(--sans);font-size:var(--t-19);font-weight:500;letter-spacing:-.01em;line-height:1.28}


.chip{display:inline-block;background:rgba(255,198,41,.78);color:var(--deep);border-radius:var(--r-chip);
  padding:.5em .93em;font-size:var(--t-14);line-height:1.2;border:1px solid rgba(120,88,0,.24);
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm)}

.chip-b{background:rgba(0,80,239,.72);color:#fff;border-color:transparent}

.chip-w{background:rgba(255,255,255,.62);border-color:rgba(28,32,26,.14)}

.chip-g{background:rgba(233,234,232,.55);border-color:rgba(28,32,26,.14)}


.btn{display:inline-flex;align-items:center;justify-content:space-between;gap:1.38em;border-radius:var(--r);
  padding:.97em 1.45em;font-size:var(--t-145);white-space:nowrap;background:var(--glass-dark);color:var(--white);
  border:1px solid transparent;-webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  transition:background .3s var(--ease),transform .3s var(--ease),color .4s var(--ease)}

.btn:hover{transform:translateY(-2px)}

.btn-y{background:var(--yellow);color:var(--deep)}


/* ---------- button hover: tinted glass ----------
   the glass keeps its blur and translucency; a soft two-colour tint (cover gold
   warming into the Atlas blue) fades in beneath it, so the change reads as light
   moving through the glass rather than a repaint. labels keep their colour. */
.btn,.hero-cta,.box-cta,.foot-cta{position:relative;overflow:hidden;isolation:isolate}

.btn::before,.hero-cta::before,.box-cta::before,.foot-cta::before{
  content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;opacity:0;
  background:linear-gradient(115deg,rgba(255,191,0,.38) 0%,rgba(226,126,46,.30) 42%,rgba(72,90,150,.5) 100%);
  transition:opacity .55s var(--ease)}

.btn:hover::before,.hero-cta:hover::before,.box-cta:hover::before,.foot-cta:hover::before{opacity:1}

/* the solid yellow footer button warms instead of tinting */
.foot-cta::before{background:linear-gradient(115deg,rgba(255,205,52,.9) 0%,rgba(240,142,24,.9) 100%)}


#tokp{position:fixed;left:-9999px;top:0;height:0;width:0;visibility:hidden;pointer-events:none}

.page{max-width:var(--page);margin:0 auto;padding:0 var(--edge)}

.page-n{max-width:var(--page-n);margin:0 auto;padding:0 var(--edge)}

.panel{border-radius:var(--r);padding:var(--pad);position:relative;
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  border:1px solid var(--ring)}

.p-y{background:var(--glass-yellow);border-color:rgba(120,88,0,.22)}

.p-d{background:var(--glass-dark);color:#D5D6D0;border-color:transparent}
 .p-d .dsp,.p-d h3{color:var(--white)}

.p-g{background:var(--glass-grey)}
 .p-b{background:var(--glass-blue);color:#E8ECF6;border-color:transparent}

.p-b .dsp,.p-b h3{color:#fff}

.p-p{background:var(--glass-pink);color:#F7E7EA;border-color:transparent}

.p-p .dsp,.p-p h3{color:#fff}

section{padding:var(--sec) 0}



/* ---------- box definition ----------
   one hairline only: the outer dark one that keeps a box legible against the
   white page. no light inner ring, no shadows, no gloss. */
.panel,.slab,.wb article,.vcell,.vcta,.wave,.hero-cta,.close-cta,.btn,.chip,.story-item{position:relative}



/* ---------- dark run ----------
   from the moment "The method" turns over, until the horizontal explore section.
   everything is driven off tokens, so the mode is a token swap. */
html.dk{
  --white:#0E0F10;
  --deep:#F2F3F1;
  --deep-2:#B4B7B2;
  --muted:#83868180;
  --grey-1:#191B1C;
  --line:#2A2C2D;
  --glass-white:rgba(255,255,255,.07);
  --glass-grey:rgba(255,255,255,.075);
  --glass-dark:rgba(255,255,255,.11);
  --ring:transparent;
  --ring-in:transparent;
  --ring-dark:transparent;
}

html.dk body{background:#0E0F10}

html.dk .muted,html.dk .tiny{color:#8B8E89}

html.dk .amb{opacity:.5}

html.dk .nav{background:rgba(14,15,16,.55);border-bottom-color:rgba(255,255,255,.12)}

/* the yellow panel keeps dark type in both modes, or its copy vanishes */
html.dk .p-y{border-color:rgba(0,0,0,.28)}

html.dk .p-y,html.dk .p-y .dsp,html.dk .p-y h3,html.dk .p-y p,
html.dk .p-y .lede{color:#1A1C18}

html.dk .chip{color:#1A1C18}

html.dk .chip-w{background:rgba(255,255,255,.12);color:#F2F3F1;border-color:transparent}

html.dk .btn,html.dk .hero-cta,html.dk .close-cta,html.dk .vcta{background:rgba(255,255,255,.12);color:#F7F8F6}

html.dk .btn:hover{background:rgba(255,255,255,.18)}


/* ---------- the mode change: ONE interpolation, not one per element ----------
   This used to work by putting `html.tt *,*::before,*::after{transition:… !important}`
   on the page for 700ms around every flip. Toggling a transition onto every element
   and back is the most expensive way to fade a page: measured on a 6x-throttled
   phone, adding .tt cost a 220ms style recalc (58ms without it), and the frame that
   flipped the mode took 708ms — so coming back up from the dark run the page sat
   dark for ~1.2s before the colour even started to move, with the hero's walking
   animals painted over it the whole time. That is the "colour doesn't change fast
   enough" bug, and no duration tuning fixes it: the cost is in the recalc, not the
   fade.

   The themed tokens are registered as real <color> properties instead, and the
   transition lives on ONE element — the root. Changing `dk` re-points twelve
   inherited values; each interpolates as a single animated value and every
   var(--token) on the page follows it in lockstep, on the compositor's own clock,
   with no per-element transition anywhere. It can only ease monotonically from A to
   B, which is also what stopped the old approach's black->white->black flicker on
   the concept page. Verify by sampling getComputedStyle(html).getPropertyValue('--deep')
   across a swap: the luminance must be strictly monotonic. */
@property --white{syntax:'<color>';inherits:true;initial-value:#FFFFFF}
@property --deep{syntax:'<color>';inherits:true;initial-value:#24261F}
@property --deep-2{syntax:'<color>';inherits:true;initial-value:#4A4C45}
@property --muted{syntax:'<color>';inherits:true;initial-value:#7A7C74}
@property --grey-1{syntax:'<color>';inherits:true;initial-value:#EDEDEC}
@property --line{syntax:'<color>';inherits:true;initial-value:#E4E4E2}
@property --glass-white{syntax:'<color>';inherits:true;initial-value:rgba(250,251,250,.56)}
@property --glass-grey{syntax:'<color>';inherits:true;initial-value:rgba(216,220,216,.56)}
@property --glass-dark{syntax:'<color>';inherits:true;initial-value:rgba(20,22,18,.86)}
@property --ring{syntax:'<color>';inherits:true;initial-value:rgba(28,32,26,.16)}
@property --ring-in{syntax:'<color>';inherits:true;initial-value:rgba(255,255,255,.85)}
@property --ring-dark{syntax:'<color>';inherits:true;initial-value:rgba(255,255,255,.26)}

:root{
  --theme-fade:.6s;
  transition:
    --white var(--theme-fade) ease,
    --deep var(--theme-fade) ease,
    --deep-2 var(--theme-fade) ease,
    --muted var(--theme-fade) ease,
    --grey-1 var(--theme-fade) ease,
    --line var(--theme-fade) ease,
    --glass-white var(--theme-fade) ease,
    --glass-grey var(--theme-fade) ease,
    --glass-dark var(--theme-fade) ease,
    --ring var(--theme-fade) ease,
    --ring-in var(--theme-fade) ease,
    --ring-dark var(--theme-fade) ease;
}

/* the handful of surfaces that hard-code a per-mode colour instead of reading a
   token (html.dk .btn, .p-y, .chip-w, .muted …) still need a transition of their
   own, or they would jump while everything else fades. This is the complete list —
   keep it in step with the `html.dk <selector>` rules above and below. */
body,.nav,.panel,.slab,.wb article,.vcell,.wave,.chip,.story-item,
.hero,.hero-stage,.story-stick,
.btn,.hero-cta,.close-cta,.vcta,.p-y,.p-y .dsp,.p-y h3,.p-y p,.p-y .lede,
.chip-w,.muted,.tiny,.seg,.seg button,.nrow ul,.v-unlock,.amb,.rsty .btn{
  transition:background-color var(--theme-fade) ease,color var(--theme-fade) ease,
    border-color var(--theme-fade) ease}

@media (prefers-reduced-motion:reduce){
  :root{--theme-fade:0s}
}


/* ---------- nav ---------- */
.nav{position:sticky;top:0;z-index:60;background:rgba(255,255,255,.38);
  -webkit-backdrop-filter:saturate(2) blur(40px);backdrop-filter:saturate(2) blur(40px);
  border-bottom:1px solid rgba(28,32,26,.13);
  transition:background-color .4s ease,color .4s ease,border-color .4s ease}

/* while it is over the full-bleed video the bar flips to dark glass, or the dark
   logotype sits on a mid-grey frost and stops being readable */
.nav.on-video{background:rgba(16,17,15,.3);border-bottom-color:rgba(255,255,255,.17);color:#F2F3F1}

.nav.on-video .logo i{color:rgba(242,243,241,.6)}

.nrow{max-width:var(--page);margin:0 auto;padding:calc(clamp(12px,.97vw,20px) + .97 * var(--ux)) var(--edge);display:flex;align-items:center;
  gap:calc(clamp(16px,2.08vw,44px) + 2.08 * var(--ux))}

.logo{display:flex;flex-direction:column;line-height:1.05;min-width:0}

.logo b{font-family:var(--display);font-weight:400;font-size:var(--t-19);letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}

.logo i{font-style:normal;font-size:calc(clamp(10px,.69vw,13px) + .69 * var(--ux));letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}

.nrow ul{list-style:none;display:flex;gap:calc(clamp(18px,1.81vw,40px) + 1.81 * var(--ux));margin:0 auto}

.nrow ul a{font-size:var(--t-145);opacity:.82;transition:opacity .25s,color .25s}

.nrow ul a:hover{opacity:1;color:var(--yellow)}

/* The section you are in, marked once: full-strength ink and a short gold rule under
   the label. Gold marks, it doesn't letter — #FCC03C text on white is unreadable, and
   the colour is already spoken for by :hover. Scoped to the desktop bar because below
   1080 the same <a> is a full-width sheet row whose ::after is the arrow (see the
   burger-sheet block), where the active row turns that arrow gold instead. */
@media (min-width:1081px){
  /* Labels stay on one line between 1081 and ~1250, where the bar is tightest — the
     flex gap gives way instead, and the marker below stays under a single line. */
  .nrow ul a{white-space:nowrap}
  .nrow ul a[aria-current="page"]{opacity:1;position:relative}
  .nrow ul a[aria-current="page"]::after{content:"";position:absolute;left:0;right:0;bottom:-7px;
    height:2px;border-radius:2px;background:var(--yellow)}
}
/* The shop has no menu link of its own — on /membership and /checkout the button
   carries the same gold. */
.nrow .btn[aria-current="page"]{box-shadow:inset 0 0 0 2px var(--yellow)}
/* …and the shop row inside the burger sheet only exists where that button doesn't. */
.menu-shop{display:none}

/* right-side actions: a plain Log in link paired with the primary button. the
   link takes colour from the bar, so it reads on white, over the video and in dark */
.nav-act{display:flex;align-items:center;gap:calc(clamp(12px,1.25vw,26px) + 1.25 * var(--ux));flex:0 0 auto;margin-left:auto}

.nav-login{display:inline-flex;align-items:center;gap:.5em;font-size:var(--t-145);opacity:.82;
  white-space:nowrap;transition:opacity .25s,color .25s}

.nav-login:hover{opacity:1;color:var(--yellow)}

.nav-login svg{opacity:.8}

/* The signed-in account menu (2026-09-17). The trigger IS .nav-login — same width, same
   weight as the link it replaced — so the bar cannot wrap the way the reverted inline
   "Sign out" did. <details> supplies open/close with no script, so the menu works, and Log
   out still posts, with JavaScript off; site.js only adds Escape and outside-click. */
.nav-acct{position:relative}
.nav-acct-trigger{cursor:pointer;list-style:none}
.nav-acct-trigger::-webkit-details-marker{display:none}
.nav-acct-caret{opacity:.55;transition:transform .2s var(--ease)}
.nav-acct[open] .nav-acct-trigger{opacity:1;color:var(--yellow)}
.nav-acct[open] .nav-acct-caret{transform:rotate(180deg)}
/* --white/--line/--deep are the theme-aware surface tokens the whole sheet swaps in the dark
   run (html.dk) — NOT --page, which is a WIDTH here (calc(1500px + ...)). background:var(--page)
   parses as invalid and paints nothing, which is how the first version of this menu shipped
   see-through over the hero with two of its three items unreadable. */
.nav-acct-menu{position:absolute;top:calc(100% + .6em);right:0;z-index:60;min-width:11em;
  display:flex;flex-direction:column;padding:.4em;border-radius:12px;
  background:var(--white);border:1px solid var(--line);
  box-shadow:0 12px 34px rgba(0,0,0,.14)}
.nav-acct-menu a,.nav-acct-menu button{display:block;width:100%;text-align:left;
  padding:.62em .8em;border:0;border-radius:8px;background:none;cursor:pointer;
  font:inherit;font-size:var(--t-14);color:var(--deep);white-space:nowrap}
.nav-acct-menu a:hover,.nav-acct-menu button:hover{background:var(--grey-1)}
/* Leaving is not the same kind of action as going somewhere: the rule and the colour say so
   without needing a second click to confirm. */
.nav-acct-menu form{margin:.35em 0 0;padding-top:.35em;border-top:1px solid var(--line)}
.nav-acct-menu button{color:#9a2b2b}
html.dk .nav-acct-menu button{color:#e08b84}   /* #9a2b2b is unreadable on the dark surface */
@media (max-width:640px){
  /* The header collapses to the burger here, and the sheet already carries the account
     links, so the menu would open off the edge of a phone. Anchor it to the right instead. */
  .nav-acct-menu{right:0;left:auto}
}

/* ---------- global search: the Capsule (T14) ----------
   ported from js/sau-global-search.js (chosen 2026-08-17 from search-ideas.html's ten
   designs). The trigger itself is static markup in layout.php's .nav-act now (it used
   to be injected by the mock's own init()); site/assets/sau-global-search.js only wires
   it up and builds the veil/modal. Styles moved here verbatim — the mock injected its
   own <style> tag at runtime, which this shared stylesheet replaces. */
.gs-trigger{display:inline-flex;align-items:center;gap:.5em;font-size:var(--t-145,14.5px);
  font-family:inherit;opacity:.82;color:inherit;background:none;border:0;cursor:pointer;padding:0;
  transition:opacity .25s,color .25s}
.gs-trigger:hover{opacity:1;color:var(--yellow,#FFBF00)}
.gs-trigger svg{opacity:.8;flex:0 0 auto}
.gs-kbd{font-family:var(--sans,system-ui);font-size:11px;line-height:1;padding:3px 5.5px;
  border-radius:5px;box-shadow:0 0 0 1px currentColor inset;opacity:.5}
@media (max-width:1024px){ .gs-kbd{display:none} }
@media (max-width:640px){
  .gs-trigger{width:40px;height:46px;justify-content:center;border-radius:var(--r,14px)}
  .gs-trigger .gs-trigger-label{display:none}
}
/* below ~420px the bar cannot hold logo + search + "Log in" + burger, so the
   Log in wordmark drops to its icon — the same treatment the page itself
   already applies at 360px, pulled up one step because search joined the bar */
@media (max-width:420px){
  .nav-act{gap:8px}
  .gs-trigger{width:34px}
  .nav-login span{display:none}
  .nav-login{padding:10px 11px;gap:0}
}

/* ---- the veil ---------------------------------------------------------
   darker and blurred rather than merely tinted: with no panel to look at
   when search opens, the field only reads as the subject if the page
   behind it stops competing. */
.gs-veil{position:fixed;inset:0;z-index:200;background:rgba(20,22,18,.32);
  -webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);
  display:flex;justify-content:center;align-items:flex-start;
  padding:14vh clamp(12px,2vw,24px) 6vh;
  opacity:0;transition:opacity .28s var(--ease,ease)}
/* REQUIRED: `display:flex` above is a class selector and so outranks the UA
   stylesheet's [hidden]{display:none}. Without this rule the closed veil stays
   laid out — invisible at opacity 0, but still covering the viewport at
   z-index 200 and swallowing every click on the page, search trigger included. */
.gs-veil[hidden]{display:none}
/* second line of defence: only the OPEN veil accepts pointer events, so a
   closed-but-still-laid-out veil (mid fade-out, or if the rule above is ever
   lost) cannot block the page */
.gs-veil{pointer-events:none}
.gs-veil.on{opacity:1;pointer-events:auto}

/* ---- inline mode: results drop down under a field on the page (the home hero) ----
   No dimmed page, no capsule of its own — the page's field IS the capsule. The veil
   lets clicks through; only the panel takes them. Position is set from JS (the
   field's rect, kept in step on scroll/resize). */
.gs-veil.gs-inline{background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none;padding:0;display:block}
.gs-veil.gs-inline.on{pointer-events:none}
.gs-veil.gs-inline .gs-modal{position:fixed;transform:none;pointer-events:auto;max-height:none}
.gs-veil.gs-inline .gs-head{display:none}
.gs-veil.gs-inline[hidden]{display:none}
.gs-veil.gs-inline .gs-panel{box-shadow:0 0 0 1px var(--ring,rgba(28,32,26,.16)),0 18px 50px rgba(0,0,0,.28)}

/* ---- the modal: not a box, two stacked pieces ------------------------- */
/* 660 is the width this was designed at. --uw is the host page's large-screen
   growth unit (0 below 1728, ~6px at 4K); pages that do not define it fall back
   to 0 and keep exactly the 660 they always had. */
.gs-modal{width:min(calc(660px + 55 * var(--uw,0px)),100%);max-height:80vh;display:flex;flex-direction:column;gap:10px;
  font-family:var(--sans,system-ui);color:var(--deep,#24261F);
  transform:translateY(10px);transition:transform .28s var(--ease,ease)}
.gs-veil.on .gs-modal{transform:none}

/* the capsule. it is a capsule until there are results, then it squares
   off to meet the panel — that morph is the whole design. */
.gs-head{flex:0 0 auto;display:flex;align-items:center;gap:15px;padding:19px 26px;
  border-radius:99px;background:rgba(252,252,251,.975);
  -webkit-backdrop-filter:var(--blur,saturate(2) blur(40px));backdrop-filter:var(--blur,saturate(2) blur(40px));
  box-shadow:inset 0 0 0 1px var(--ring-in,rgba(255,255,255,.85)),0 0 0 1px var(--ring,rgba(28,32,26,.16));
  transition:border-radius .4s var(--ease,ease)}
.gs-modal.has .gs-head{border-radius:22px}
.gs-head svg{flex:0 0 auto;color:var(--muted,#7A7C74)}
.gs-input{flex:1;min-width:0;border:0;background:none;outline:0;color:inherit;
  font-family:var(--display,"Outfit",sans-serif);font-weight:300;
  font-size:21px;caret-color:var(--yellow,#FFBF00)}
.gs-input::placeholder{color:inherit;opacity:.42}
/* the capsule stays bare on desktop — click the page to dismiss. On a phone
   the panel fills the screen and there is almost no page left to click, so
   the way out has to be in the capsule. */
.gs-cancel{display:none;flex:0 0 auto;font-family:inherit;font-size:13px;cursor:pointer;
  color:var(--muted,#7A7C74);background:none;border:0;padding:4px 2px}
.gs-cancel:hover{color:var(--deep,#24261F)}

/* the panel that grows underneath */
.gs-panel{border-radius:22px;overflow:hidden;background:rgba(252,252,251,.975);
  -webkit-backdrop-filter:var(--blur,saturate(2) blur(40px));backdrop-filter:var(--blur,saturate(2) blur(40px));
  box-shadow:inset 0 0 0 1px var(--ring-in,rgba(255,255,255,.85)),0 0 0 1px var(--ring,rgba(28,32,26,.16));
  display:flex;flex-direction:column;min-height:0;
  animation:gsGrow .38s var(--ease,ease) both}
/* same [hidden] trap as the veil: the panel is display:flex by class */
.gs-panel[hidden]{display:none}
@keyframes gsGrow{from{opacity:0;transform:translateY(-8px) scaleY(.94);transform-origin:top}
  to{opacity:1;transform:none}}

.gs-body{overflow-y:auto;overscroll-behavior:contain;padding:8px;flex:1;min-height:0}
.gs-body::-webkit-scrollbar{width:9px}
.gs-body::-webkit-scrollbar-thumb{background:rgba(122,124,116,.4);border-radius:9px;
  border:3px solid transparent;background-clip:content-box}

/* group eyebrow: label, count, and — only when the group overflows — the
   way through to the full list. no separate "see all" row. */
.gs-group{display:flex;align-items:baseline;gap:9px;margin:14px 14px 4px}
.gs-group b{font-weight:600;font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--muted,#7A7C74);white-space:nowrap}
.gs-group i{font-style:normal;font-size:10px;color:var(--grey-2,#C0C0BF)}
.gs-group a{margin-left:auto;font-size:11.5px;color:var(--deep-2,#4A4C45);text-decoration:none;
  white-space:nowrap}
.gs-group a:hover{color:var(--deep,#24261F);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--yellow,#FFBF00);text-decoration-thickness:2px}
/* posts' overflow control is a button (expands in place, no navigation) — same look
   as the link above, reset from its native chrome */
.gs-group button.gs-seeall{margin-left:auto;font:inherit;font-size:11.5px;
  color:var(--deep-2,#4A4C45);text-decoration:none;white-space:nowrap;background:none;
  border:0;padding:0;cursor:pointer}
.gs-group button.gs-seeall:hover{color:var(--deep,#24261F);text-decoration:underline;
  text-underline-offset:3px;text-decoration-color:var(--yellow,#FFBF00);text-decoration-thickness:2px}

/* one line per result */
.gs-row{display:flex;align-items:baseline;gap:12px;padding:9px 14px;border-radius:11px;
  text-decoration:none;color:inherit;cursor:pointer}
.gs-row.sel,.gs-row:hover{background:var(--glass-grey,rgba(216,220,216,.56))}
/* the kind mark sits at reading weight, not gold: #FFBF00 on near-white is
   ~1.9:1 and this letter is the only thing naming what a row IS. The gold
   is spent on the row you are on instead, where it does real work. */
.gs-kind{flex:0 0 auto;width:16px;font-family:var(--display,"Outfit",sans-serif);font-size:11.5px;
  font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--deep-2,#4A4C45);
  opacity:.62;transition:color .18s,opacity .18s}
.gs-row.sel .gs-kind,.gs-row:hover .gs-kind{color:var(--deep,#24261F);opacity:1}
.gs-rtitle{flex:1;min-width:0;font-size:var(--t-15,15px);font-weight:500;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gs-rmeta{flex:0 0 auto;font-size:11.5px;color:var(--muted,#7A7C74);white-space:nowrap;
  max-width:40%;overflow:hidden;text-overflow:ellipsis}
.gs-lock{flex:0 0 auto;color:var(--muted,#7A7C74);display:flex;align-self:center;opacity:.6}
/* the marker-wash the site already uses for its brand phrase */
.gs-row mark{background:linear-gradient(180deg,transparent 42%,rgba(255,191,0,.45) 42%,rgba(255,191,0,.45) 96%,transparent 96%);
  color:inherit;padding:0 1px;border-radius:2px}

/* zero state — a sentence, and the one term that would have worked */
.gs-zero{padding:26px 20px 22px;text-align:center;color:var(--muted,#7A7C74);font-size:var(--t-sm,13.5px)}
.gs-zero b{color:var(--deep,#24261F);font-weight:600}
.gs-dym{margin:14px auto 0;display:inline-flex;font-family:inherit;font-size:var(--t-sm,13.5px);
  cursor:pointer;border:0;background:rgba(255,191,0,.22);color:var(--deep,#24261F);
  border-radius:99px;padding:8px 16px}
.gs-dym:hover{background:rgba(255,191,0,.4)}

.gs-foot{flex:0 0 auto;padding:9px 20px;font-size:11px;color:var(--muted,#7A7C74);
  box-shadow:inset 0 1px 0 var(--line,#E4E4E2)}
.gs-foot b{font-weight:600;color:var(--deep,#24261F)}

@media (max-width:640px){
  .gs-veil{padding:9vh 12px 4vh}
  .gs-modal{max-height:86vh}
  .gs-head{padding:16px 20px;gap:12px}
  .gs-input{font-size:17px}
  .gs-rmeta{max-width:34%}
  .gs-cancel{display:block}
}
@media (max-width:400px){ .gs-rmeta{display:none} }
@media (prefers-reduced-motion:reduce){
  .gs-veil,.gs-modal,.gs-head{transition:none}
  .gs-panel{animation:none}
}


/* ---------- hero: the scan is the page, full bleed, boxes floating on it ----------
   the nav is sticky and therefore in flow, so it reserves height at the top. the
   hero is pulled up by exactly that height (--nav-h, measured in JS) so the video
   starts at the very top of the page and runs under the bar. */
/* padding:0 defeats the base `section` rule, which would otherwise inset the
   title by a whole section's worth of space top and bottom */
/* ---------- the hero is ALWAYS light ----------
   It used to ride the --white token so "the dark run fades the WHOLE screen, stage
   included". It bought nothing — the dark run only starts once #begin has reached
   mid-viewport, by which point the hero has scrolled entirely off the top — and it
   cost the one artefact you actually see: the walking cat and dog are drawn with
   mix-blend-mode:multiply, which needs a light ground, so scrolling back UP into the
   hero showed them sitting on the dark page for as long as the fade took. Pinning
   every light token locally (the same trick .rsty uses to stay light) means there is
   no fade to wait for here at all: the hero is simply never dark.
   Two hard-coded html.dk rules reach inside it, so they are undone below. */
.hero{position:relative;margin-top:calc(-1 * var(--nav-h,64px));height:300vh;padding:0;background:var(--white);
  --white:#FFFFFF;--deep:#24261F;--deep-2:#4A4C45;--muted:#7A7C74;
  --grey-1:#EDEDEC;--grey-2:#C0C0BF;--line:#E4E4E2;
  --glass-white:rgba(250,251,250,.56);--glass-grey:rgba(216,220,216,.56);
  --glass-dark:rgba(20,22,18,.86);
  --ring:rgba(28,32,26,.16);--ring-in:rgba(255,255,255,.85);--ring-dark:rgba(255,255,255,.26)}

html.dk .hero .muted,html.dk .hero .tiny{color:#7A7C74}

html.dk .hero .hero-cta,html.dk .hero .btn{background:var(--glass-dark);color:#F7F8F6}

/* the frame: the stage pins while the full-bleed scan shrinks into a framed
   card on the right and the welcome takes the left of the page. */
.hero-stage{position:sticky;top:0;height:100vh;overflow:hidden;display:flex;align-items:center;
  background:var(--white)}

@supports (height:100svh){ .hero-stage{height:100svh} }

.hero-media{position:absolute;left:0;top:0;width:100vw;height:100vh;overflow:hidden;z-index:1;
  box-shadow:0 24px 70px rgba(14,15,16,.18)}

/* ---------- the crossfading figures ----------
   settings carried over from the hero-live-b study, then taken to black: the ground
   is pure black and the scan is held far back — at half opacity it lifted the whole
   centre to a flat grey plateau. so: a quarter opacity, and with the figure that faint
   the softening blurs came off with it, since blur on a near-transparent scan only
   smears it into haze. the sector runs past the frame at 152%, a .5px even blur (just
   enough to kill the pixel edge), a 1px edge blur, and a 0.55 veil. sized in % of .hero-media rather than vh, so the whole ground scales
   with the card as the frame effect shrinks it. */
.hero-media{--i-op:.26;--i-size:152;--i-blur:.5px;--i-rad:1px;--scrim:.55;--i-fade:.9s;
  background:radial-gradient(ellipse 80% 60% at 50% 44%,#0A0A0A,#000 76%)}

/* the gold ground sits BEHIND the figures, so the colour reads up through the
   half-transparent scan instead of being painted over it. kept to a whisper: at
   the old strength the gold mixed with the grey scan and the whole field read
   brown rather than black. */
.hero-wash{position:absolute;inset:0;z-index:0;pointer-events:none;background:
  radial-gradient(ellipse 90% 62% at 18% -8%,rgba(255,191,0,.05),transparent 58%),
  radial-gradient(ellipse 84% 74% at 86% 108%,rgba(255,191,0,.11),transparent 62%)}

.hslide{position:absolute;inset:0;z-index:1;display:flex;align-items:center;justify-content:center;
  opacity:0;transition:opacity var(--i-fade) linear}

.hslide.on{opacity:1}

/* the drift (authors' review, 2026-10-16: "add a little motion"): while a figure shows —
   and through its fade-out — it zooms in a touch and slides, each in its own direction,
   so the three never move in step. A transform only, so it stays on the GPU. --hs-drift
   scales it (0 = still), --hs-dur = hold + both fades; both come from data/hero.json via
   the inline style on #heroMedia, tuned at /?tunehero=1. JS restarts it per slide. */
.hslide{--dx:-1.6%;--dy:-1%}
.hslide + .hslide{--dx:1.4%;--dy:-1.2%}
.hslide + .hslide + .hslide{--dx:-.8%;--dy:1.3%}
.hslide.drift{animation:hsDrift var(--hs-dur,7.4s) linear both}
@keyframes hsDrift{
  from{transform:none}
  to{transform:translate(calc(var(--dx) * var(--hs-drift,1)),calc(var(--dy) * var(--hs-drift,1))) scale(calc(1 + .06 * var(--hs-drift,1)))}
}
@media (prefers-reduced-motion:reduce){ .hslide.drift{animation:none} }

/* the mask holds the sector's own outline; the figure inside is bigger than the
   frame, so its mouth is off the top and its far field off the bottom */
.hslide .hs-mask{position:absolute;left:50%;top:50%;height:calc(var(--i-size) * 1%);
  aspect-ratio:1892/1606;transform:translate(-50%,-50%);opacity:var(--i-op);overflow:hidden;
  -webkit-mask-image:var(--m);mask-image:var(--m);
  -webkit-mask-size:100% 100%;mask-size:100% 100%;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}

.hslide img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}

/* ---------- the edge blur, done with two static copies ----------
   the tuning page gets this from a backdrop-filter, which is free there because
   nothing moves behind it. here the ambient colour blobs drift across the whole
   viewport, so a backdrop-filter re-filtered the screen on every one of their
   frames and cost more than the video it replaced. instead: a soft copy beneath,
   a sharp copy above it masked to the centre. both blurs are static, so they are
   rasterised once and cost nothing to hold. */
.hslide .hs-soft{filter:blur(calc(var(--i-blur) + var(--i-rad) * 3))}

.hslide .hs-sharp{filter:blur(var(--i-blur));
  -webkit-mask-image:radial-gradient(ellipse 64% 58% at 50% 50%,#000 0 34%,transparent 88%);
  mask-image:radial-gradient(ellipse 64% 58% at 50% 50%,#000 0 34%,transparent 88%)}

/* the veil, centre-weighted so it shelters the title without flattening the frame */
.hero-media::after{content:"";position:absolute;inset:0;z-index:3;pointer-events:none;background:
  radial-gradient(ellipse 68% 60% at 50% 50%,
    rgba(0,0,0,calc(.62 * var(--scrim))),
    rgba(0,0,0,calc(.24 * var(--scrim))) 66%,
    rgba(0,0,0,0) 82%),
  linear-gradient(180deg,rgba(0,0,0,calc(.38 * var(--scrim))),rgba(0,0,0,0) 24%)}

/* ---------- the walking pair ----------
   as the frame shrinks the scan into the card, the whole card dissolves and the
   hand-drawn walk cycles condense in its place — no settled square, just a cat
   and a dog walking on the page beside the welcome. it lives in the STAGE, not the card:
   the scan fades out as one element (shadow, veil and all) and the dog is a
   sibling tracked to the same rect. multiply blend melts the video's white
   ground into whatever the page is painting (grain, ambient tint), so the
   drawing has no visible frame; the source is pre-cropped to the drawing, so
   object-fit:contain gives it the whole rect without ever clipping it. */
.hero-dog{position:absolute;left:0;top:0;z-index:2;opacity:0;pointer-events:none}

.hero-dog video{position:absolute;object-fit:contain;mix-blend-mode:multiply}

/* the scene holds BOTH walk cycles — the cat a few paces ahead of the dog, both
   on one ground line. the layer's aspect ratio is the pair's, so these two boxes
   are pure percentages of it: the animals keep their relative size (the cat's
   withers at .44 of the dog's, about life) and their feet stay on the same line
   at every viewport width. the numbers come from the drawings themselves — the
   ground sits at 97.08% of the dog clip and 96.05% of the cat clip. the scene
   also carries a leading margin, because below ~1290px the card's left edge
   already crosses into the welcome column — the margin is what keeps the cat's
   face off the paragraph the way the dog's empty crop used to. */
.hero-dog .wc-dog{left:36.69%;top:0;width:63.31%;height:100%}

.hero-dog .wc-cat{left:3.5%;top:39.35%;width:31.38%;height:60.11%}

/* the credentials sit right under the bar; absolute so the title block below stays
   centred on the viewport rather than being pushed off centre by them */
.hero-top{position:absolute;left:0;right:0;top:calc(var(--nav-h,64px) + calc(clamp(18px,2.4vw,32px) + 2.4 * var(--ux)));
  z-index:3;text-align:center;padding:0 var(--edge)}

.hero-top p{font-size:var(--t-xs);color:rgba(255,255,255,.58);margin-bottom:13px}

.hero-top ul{list-style:none;display:flex;flex-wrap:wrap;justify-content:center;gap:8px calc(clamp(18px,3.2vw,86px) + 3.2 * var(--ux))}

.hero-top li{font-size:calc(clamp(.85rem,1.09vw,1.4rem) + 1.09 * var(--ux));font-weight:500;color:rgba(255,255,255,.84)}


/* the block sits below centre: a translate rather than padding, so it keeps its
   own centring maths and just shifts, and it scales with viewport height */
.hero-float{position:relative;z-index:3;width:100%;text-align:center;
  transform:translateY(clamp(36px,9vh,100px));will-change:transform,opacity}

.hero-eyebrow{font-family:var(--sans);font-weight:500;text-transform:uppercase;
  letter-spacing:.34em;font-size:calc(clamp(11px,.82vw,14px) + .82 * var(--ux));color:rgba(255,255,255,.72);
  margin:0 0 calc(clamp(12px,1.15vw,20px) + 1.15 * var(--ux))}

/* the title in cover gold, at the size and tracking settled in the B study */
.hero-title{font-family:var(--display);font-weight:400;color:var(--yellow);letter-spacing:-.022em;line-height:1.02;
  font-size:calc(calc(clamp(2rem,5.4vw,7.4rem) + 5.4 * var(--ux)) * .91);margin:0 auto;max-width:16em}

/* the title stays centred; the description and the button sit side by side beneath
   it as one centred pair, rather than being pushed out to the container edges */
.hero-row{display:flex;flex-direction:column;align-items:center;
  gap:calc(clamp(26px,3vw,40px) + 3 * var(--ux));margin-top:calc(clamp(30px,3.4vw,48px) + 3.4 * var(--ux));text-align:center}

.hero-lede{margin:0;max-width:44em;font-size:calc(clamp(15px,1.15vw,21px) + 1.15 * var(--ux));color:rgba(255,255,255,.8)}

/* glass button: translucent fill, real blur, no hairline */
.hero-cta{display:inline-flex;align-items:center;gap:1.16em;flex:0 0 auto;white-space:nowrap;
  border-radius:var(--r);padding:1.03em 1.68em;font-size:calc(clamp(15.5px,1.08vw,20px) + 1.08 * var(--ux));color:#fff;
  background:rgba(255,255,255,.15);border:1px solid transparent;
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  transition:background .3s var(--ease),transform .3s var(--ease),color .4s var(--ease)}

.hero-cta:hover{transform:translateY(-2px)}

.hero-cta .arw{transition:transform .35s var(--ease)}

.hero-cta:hover .arw{transform:translateX(6px)}

/* the search field sits above the CTAs: finding a case is the first action the
   hero offers, per the owners — the membership buttons stay, one step down.
   it reads as a field, not a button: hairline edge, muted prompt, text cursor.
   clicking it opens the global search overlay (class gs-open). */
.hero-search{display:inline-flex;align-items:center;gap:.9em;width:min(560px,100%);
  appearance:none;-webkit-appearance:none;cursor:text;font-family:var(--sans);text-align:left;
  border-radius:var(--r);padding:1.03em 1.5em;font-size:calc(clamp(15px,1.08vw,19px) + 1.08 * var(--ux));
  color:rgba(255,255,255,.75);background:rgba(255,255,255,.12);border:1px solid rgba(255,191,0,.62);
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  transition:background .3s var(--ease),color .3s var(--ease)}

.hero-search:hover,.hero-search:focus-visible{background:rgba(255,255,255,.2);color:rgba(255,255,255,.92)}

.hero-search svg{flex:0 0 auto;opacity:.8}

.hero-search span{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* the hero box is a real field now (typed into in place, 2026-10-17) */
.hero-search:focus-within{background:rgba(255,255,255,.2);color:rgba(255,255,255,.92)}
.hero-search-input{flex:1;min-width:0;border:0;outline:0;background:none;padding:0;margin:0;
  font:inherit;color:#fff;caret-color:var(--yellow)}
.hero-search-input::placeholder{color:rgba(255,255,255,.75);opacity:1}
.hero-search-input::-webkit-search-cancel-button{filter:invert(1);opacity:.7;cursor:pointer}

/* two CTAs side by side beneath the lede; the second reads as the quieter option */
.hero-ctas{display:flex;flex-wrap:wrap;justify-content:center;gap:calc(clamp(12px,1vw,18px) + 1 * var(--ux));flex:0 0 auto}

.hero-cta-2{background:rgba(255,255,255,.07);color:rgba(255,255,255,.9)}


/* the welcome inside the frame stage: it takes the left of the white page while
   the scan settles into its card on the right. its reveal is driven by the frame
   progress, and it pins its own light tokens so the dark run can never flip its
   type while the stage is still leaving the screen. */
.hero-welcome{position:absolute;top:50%;transform:translateY(-50%);z-index:2;
  left:calc(max((100vw - var(--page)) / 2, 0px) + var(--edge));
  width:min(48vw,calc(720px + 60 * var(--uw)));opacity:0;will-change:transform,opacity}

.hw-h{font-size:calc(clamp(1.7rem,3.4vw,3.4rem) + 3.4 * var(--ux));letter-spacing:-.015em;line-height:1.06}

.hero-welcome .who-lede{max-width:44em;margin-top:clamp(18px,2.6vh,30px)}

.hero-welcome.go .hl{background-size:100% 56%}

@media (max-width:1080px){
  /* the welcome sits BELOW the settled card, never over it: the frame driver
     sets its top from the same numbers the card animates to. no box. */
  .hero-welcome{width:min(88vw,620px);left:50%;top:auto;bottom:auto;
    transform:translate(-50%,0)}
  .hw-h{font-size:calc(clamp(1.4rem,5.6vw,2.1rem) + 5.6 * var(--ux))}
  .hero-welcome .who-lede{font-size:var(--t-14);line-height:1.55;margin-top:clamp(12px,2vh,20px)}
}


/* ---------- who we are / what we offer ----------
   the orientation block: one screen that answers "who is this" and "what is here"
   before any of the longer sections start. deliberately dense, so it reads as a
   summary rather than competing with the author cards further down. */
/* editorial section-intro: the statement anchors the left, the supporting prose
   balances it on the right at the same top edge, and the authors form a full-width
   credit band beneath a hairline rule so the block uses its whole measure. */
.who{display:block}

/* statement welcome: staged display-scale lines, marker wash on the brand phrase */
.stmt{margin:0 auto}

.stmt .ln{display:block;overflow:hidden}

.stmt .ln.rv:not(.on){transform:translateY(28px)}

.stmt .ln b{display:block;font-family:var(--display);font-weight:400;color:var(--deep);
  letter-spacing:-.015em;line-height:1.06;font-size:calc(clamp(2rem,5.3vw,6.1rem) + 5.3 * var(--ux));overflow-wrap:break-word}

.hl{background-image:linear-gradient(var(--yellow),var(--yellow));
  background-repeat:no-repeat;background-position:0 68%;background-size:0% 56%;
  transition:background-size 1.1s var(--ease) .15s;padding:0 .06em}

.stmt .ln.on .hl{background-size:100% 56%}

.who-head{display:grid;grid-template-columns:1fr;justify-items:center;text-align:center;
  gap:calc(clamp(32px,5vw,110px) + 5 * var(--ux));align-items:start}

.who-title{margin:0 auto;max-width:14em}

.who-lede{margin:0 auto;max-width:38em}

/* the lede sits low against the tall heading; a touch of top pad keeps its cap-line
   from riding above the heading's first line on wide screens */
@media (min-width:1081px){.who-lede{padding-top:calc(clamp(6px,.7vw,14px) + .7 * var(--ux))}}


.who-authors{margin-top:calc(clamp(44px,4.6vw,88px) + 4.6 * var(--ux));padding-top:calc(clamp(24px,2.2vw,44px) + 2.2 * var(--ux));
  border-top:1px solid var(--line);
  display:grid;grid-template-columns:minmax(0,1.08fr) minmax(0,.92fr);
  gap:calc(clamp(8px,5vw,110px) + 5 * var(--ux));align-items:start}

.who-authors-label{font-family:var(--sans);text-transform:uppercase;letter-spacing:.2em;
  font-size:var(--t-xs);color:var(--muted);padding-top:calc(clamp(14px,1.3vw,26px) + 1.3 * var(--ux))}

.who-people{list-style:none;display:grid;grid-template-columns:1fr 1fr;
  gap:calc(clamp(20px,2.6vw,52px) + 2.6 * var(--ux))}

.who-people li{display:flex;align-items:center;gap:calc(clamp(14px,1.11vw,24px) + 1.11 * var(--ux))}

.who-people img{width:calc(clamp(56px,4.2vw,88px) + 4.2 * var(--ux));height:calc(clamp(56px,4.2vw,88px) + 4.2 * var(--ux));
  border-radius:50%;object-fit:cover;object-position:50% 22%;flex:0 0 auto}

.who-people b{display:block;font-family:var(--sans);font-weight:500;font-size:var(--t-165);letter-spacing:-.01em}

.who-people span{display:block;font-size:var(--t-xs);color:var(--muted);margin-top:4px}


/* the who block ends level and the pinned story frame brings its own head-room,
   so who gives up most of its bottom padding */
#who{padding-bottom:calc(var(--sec) * .35)}


/* ---------- problem -> method, sine wave ----------
   one pinned frame holding two states with the same skeleton — chip, heading,
   supporting line, then the substance in a row. because the skeleton is shared,
   the cross-fade reads as the same argument turning over rather than as two
   unrelated screens. state A states the difficulty; state B answers it. */
.story{position:relative}

.story-stick{position:sticky;top:0;height:100vh;min-height:640px;display:flex;align-items:flex-start;
  padding-top:clamp(76px,12.5vh,210px);background:var(--white);overflow:hidden}

.story-inner{max-width:var(--page);margin:0 auto;padding:0 var(--edge);width:100%;position:relative;z-index:2}

.story-a,.story-b{transition:opacity .14s linear}

.story-b{position:absolute;top:0;left:var(--edge);right:var(--edge);opacity:0}

.story-txt{max-width:19em}

.story-chip{margin-bottom:calc(clamp(16px,1.39vw,30px) + 1.39 * var(--ux))}

.story-lede{margin-top:calc(clamp(16px,1.25vw,28px) + 1.25 * var(--ux));max-width:46em;font-size:var(--t-15);color:var(--deep-2)}


.story-grid{display:grid;gap:var(--gap);margin-top:calc(clamp(30px,3.06vw,66px) + 3.06 * var(--ux))}

.story-a .story-grid{grid-template-columns:repeat(3,minmax(0,1fr))}

.story-b .story-grid{grid-template-columns:repeat(3,minmax(0,1fr))}

/* no backdrop-filter (2026-10-17): these cards sit on the section's flat ground and fitSine()
   keeps the wave out from under them, so the blur showed nothing — but it re-blurred on
   every wave frame, six times over, and made the scroll through this section stutter. */
.story-item{border-radius:var(--r);padding:calc(clamp(18px,1.67vw,36px) + 1.67 * var(--ux));background:var(--glass-grey);
  border:1px solid var(--ring)}

.story-item h3{font-size:var(--t-165);margin-bottom:.55em}

.story-item p{font-size:var(--t-14);color:var(--deep-2)}

/* the stages are numbered because the order is the method: you scan in this
   sequence. the conditions in state A are not a sequence, so they carry no index. */
.story-n{display:block;font-family:var(--display);font-weight:400;font-size:var(--t-sm);
  letter-spacing:.16em;color:var(--muted);margin-bottom:.55em}

.story-b .story-n{color:var(--yellow)}

/* each membership names the need it answers, so the pairing doesn't rely on the
   viewer holding a number in their head across the fade */
.story-for{display:block;font-size:var(--t-sm);font-weight:500;color:var(--deep-2);margin-bottom:.5em}


.sine{position:absolute;left:0;right:0;bottom:0;height:38%;z-index:1;pointer-events:none}

.sine svg{width:100%;height:100%}

.sine path{fill:none;stroke:var(--deep);stroke-width:1.3;vector-effect:non-scaling-stroke}


/* ---------- how it works: one glass stage, three signals ----------
   a segmented control picks the visitor's situation; the stage crossfades its
   gradient wash and story. gradients sampled around the cover palette:
   blue -> deep blue, yellow -> orange, pink -> purple. */
.seg{display:flex;gap:6px;justify-content:center;flex-wrap:wrap;padding:6px;border-radius:999px;
  background:rgba(28,32,26,.07);width:max-content;max-width:100%;
  margin:calc(clamp(34px,3.33vw,72px) + 3.33 * var(--ux)) auto 0;
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  transition:background .6s var(--ease)}

.seg button{font:inherit;border:0;cursor:pointer;padding:.68em 1.35em;border-radius:999px;
  font-size:var(--t-14);color:var(--deep-2);background:none;white-space:nowrap;
  transition:background .35s var(--ease),color .35s var(--ease)}

.seg button:hover{color:var(--deep)}

.seg button.on{background:rgba(28,32,26,.1);color:var(--deep)}

html.dk .seg{background:rgba(255,255,255,.07)}

html.dk .seg button.on{background:rgba(255,255,255,.16);color:#fff}

/* phones: the three situations become one full-width glass tray, three equal
   segments side by side — never the ragged two-up-one-under wrap */
@media (max-width:640px){
  #begin .seg{display:grid;grid-template-columns:repeat(3,1fr);gap:4px;width:100%;
    border-radius:var(--r);padding:5px}
  #begin .seg button{white-space:normal;line-height:1.25;text-align:center;
    padding:.72em .3em;font-size:12.5px;font-weight:600;border-radius:calc(var(--r) - 6px)}
}

/* the room answers the choice: a soft glow in the active colour spreads from
   behind the stage into the dark, and the two inactive gradients peek out as a
   deck behind it, so the scene reads as three cards with one brought forward */
#begin .glow{position:absolute;inset:0;pointer-events:none}

#begin .glow i{position:absolute;inset:-15%;opacity:0;transition:opacity .9s var(--ease)}

#begin .glow i.on{opacity:1}

#begin .glow .g-b{background:radial-gradient(ellipse 62% 56% at 50% 62%,rgba(24,120,255,.26),rgba(24,120,255,0) 70%)}

#begin .glow .g-y{background:radial-gradient(ellipse 62% 56% at 50% 62%,rgba(255,191,0,.20),rgba(255,191,0,0) 70%)}

#begin .glow .g-p{background:radial-gradient(ellipse 62% 56% at 50% 62%,rgba(200,62,96,.22),rgba(200,62,96,0) 70%)}

.stage-wrap{position:relative;margin-top:calc(clamp(20px,1.8vw,34px) + 1.8 * var(--ux))}

.stage{position:relative;z-index:1;border-radius:var(--r);overflow:hidden;
  min-height:calc(clamp(340px,26vw,470px) + 26 * var(--ux));-webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur)}

/* the three gradient washes sit stacked; the active one fades up */
.wash{position:absolute;inset:0;opacity:0;transition:opacity .7s var(--ease)}

.wash.g-b{background:linear-gradient(157deg,rgba(24,120,255,.90) 0%,rgba(0,40,150,.94) 100%)}

.wash.g-y{background:linear-gradient(157deg,rgba(255,205,52,.95) 0%,rgba(240,142,24,.95) 100%)}

.wash.g-p{background:linear-gradient(157deg,rgba(200,62,96,.92) 0%,rgba(112,42,126,.94) 100%)}

.wash.on{opacity:1}

.slide{position:absolute;inset:0;padding:var(--pad);display:flex;flex-direction:column;color:#fff;
  opacity:0;transform:translateY(14px);pointer-events:none;
  transition:opacity .5s var(--ease),transform .5s var(--ease)}

.slide.on{opacity:1;transform:none;pointer-events:auto;transition-delay:.15s}

.slide h3{margin-bottom:.5em;color:#fff}

.slide p{font-size:var(--t-145);color:rgba(255,255,255,.92);max-width:44em;margin-bottom:calc(clamp(20px,1.8vw,34px) + 1.8 * var(--ux))}

.slide.s-y,.slide.s-y h3,.slide.s-y p{color:#1A1C18}

.slide.s-y .box-ico{color:#2b2410;background:rgba(255,255,255,.32)}

.slide.s-y .box-cta{color:#1A1C18;background:rgba(255,255,255,.34)}

/* the frosted icon badge and pill action the slides are built from */
.box-ico{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;color:#fff;
  width:calc(clamp(58px,4.6vw,88px) + 4.6 * var(--ux));height:calc(clamp(58px,4.6vw,88px) + 4.6 * var(--ux));border-radius:18px;
  background:rgba(255,255,255,.16);border:1px solid transparent;
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  margin-bottom:calc(clamp(22px,2vw,42px) + 2 * var(--ux))}

.box-ico svg{width:54%;height:54%;display:block}

.box-cta{margin-top:auto;align-self:flex-start;flex-shrink:0;display:inline-flex;align-items:center;gap:.65em;
  padding:.72em 1.35em;border-radius:999px;font-size:var(--t-14);font-weight:600;color:#fff;
  background:rgba(255,255,255,.16);border:1px solid transparent;
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  transition:background .35s var(--ease),transform .35s var(--ease),color .4s var(--ease)}

.box-cta:hover{transform:translateY(-2px)}

.box-cta svg{transition:transform .35s var(--ease)}

.box-cta:hover svg{transform:translateX(5px)}

/* small price anchor above a box CTA */
.box-sub{margin-top:auto;font-size:var(--t-14);opacity:.88;margin-bottom:1em}

.box-sub + .box-cta{margin-top:0}

/* ---------- the boundary: the pulse and its echoes ----------
   the rule that divides the welcome from "how it works" is a single unbroken
   stroke running edge to edge, and the waves are that same stroke doing something.
   one packet of ultrasound crosses the window left to right; a moment later a
   train of echoes crosses back the other way. every packet carries the SAME
   wavelength — it is the same sound throughout — and only the amplitude and the
   length of each one change, because each interface reflects a different share of
   it. both directions move at one speed, since it is one sound in one tissue. */
/* the annotation sits ABOVE the line and the line is the last thing in the block,
   so the stroke lands on the seam between the two sections with clear air under
   it — it reads as the boundary rather than as an exhibit sitting near one. */
.rf{position:relative;padding:calc(clamp(26px,3.2vw,60px) + 3.2 * var(--ux)) 0 0}

.rf-plot{position:relative;width:100%;height:calc(clamp(150px,17vw,250px) + 17 * var(--ux));
  margin-top:calc(clamp(12px,1.2vw,24px) + 1.2 * var(--ux))}

.rf-plot svg{position:absolute;inset:0;width:100%;height:100%;display:block;overflow:visible}

/* ONE stroke for the whole thing. the flat run and the waves are the same path in
   the same weight and colour — the rule does not pass behind the signal, it IS
   the signal with nothing happening to it yet. */
.rf-line{fill:none;stroke:var(--deep);stroke-width:1.6;opacity:.78;
  stroke-linecap:round;stroke-linejoin:round}

.rf-meta{max-width:var(--page);margin:0 auto;padding:0 var(--edge)}

/* the two phase labels share one line and cross-fade, so nothing below them moves */
.rf-phase{position:relative;height:1.7em;margin-top:calc(clamp(14px,1.15vw,24px) + 1.15 * var(--ux))}

.rf-ph{position:absolute;left:0;top:0;white-space:nowrap;
  font-size:var(--t-14);color:var(--deep-2);opacity:0;transition:opacity .5s var(--ease)}

.rf-ph.on{opacity:1}

.rf-ph i{font-style:normal;display:inline-block;width:1.6em;color:var(--muted)}

.rf-cap{margin:calc(clamp(4px,.4vw,10px) + .4 * var(--ux)) 0 0;max-width:46em;
  font-size:var(--t-xs);color:var(--muted);line-height:1.65}

@media (prefers-reduced-motion:reduce){
  .rf-ph{transition:none}
}


/* pulled in from the shared section rule so the space under the line matches the
   space over it — the line has to sit in the middle of the gap, not near its top */
#begin{position:relative;overflow:hidden;padding-top:calc(clamp(50px,5.6vw,120px) + 5.6 * var(--ux))}

#begin>.page-n{position:relative;z-index:2}



/* ---------- pulses: every ring the same radius, evenly staggered and linear,
   so the gap between rings stays equal as they travel ---------- */
/* stay connected is the layer UNDER the curtain: it sticks to the viewport top
   while "about us" rises over it. the wrapper (.cwrap) bounds the stick so it
   can never haunt later sections. nearly a full screen, so the curtain has a
   whole room to cover. */
.pulse-sec{position:sticky;top:0;overflow:hidden;min-height:94vh;display:flex;align-items:center;
  padding:calc(var(--sec)*.5) 0;text-align:center}

.pulse-sec>.page{flex:1 1 auto}

.pulse-fb{margin-top:calc(clamp(24px,2.4vw,44px) + 2.4 * var(--ux));position:relative;z-index:2}

.pulse-sec .page{will-change:transform}

/* the rising about-us sheet dims and settles this section beneath it */
.pulse-dim{position:absolute;inset:0;z-index:3;background:#060707;opacity:0;pointer-events:none}

/* about us is the CURTAIN: rounded shoulders, an up-shadow, its own opaque
   ground, z-index above the stuck layer */
#written{position:relative;z-index:2;background:var(--white);
  border-radius:28px 28px 0 0;box-shadow:0 -30px 80px rgba(14,16,15,.28)}

/* on desktop the whole section fits one viewport: the author cards go
   landscape (photo beside the text), the bios clamp behind Read more.
   #written-prefixed so these outrank the base .wb rules further down. */
@media (min-width:1081px){
  #written{min-height:100vh;display:flex;align-items:center;padding:calc(var(--sec)*.35) 0}
  #written>.page{width:100%}
  #written .wb-head{margin-bottom:calc(clamp(24px,2.5vw,52px) + 2.5 * var(--ux))}
  #written .wb article{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr)}
  #written .wb .ph{aspect-ratio:auto;height:100%;min-height:0;min-width:0}
  #written .wb .bd{padding:calc(clamp(20px,1.9vw,40px) + 1.9 * var(--ux))}
  #written .wb h3{font-size:calc(clamp(1.4rem,1.9vw,2.4rem) + 1.9 * var(--ux))}
  #written .wb .bio{display:-webkit-box;-webkit-line-clamp:6;-webkit-box-orient:vertical;overflow:hidden}
  #written .wb article.x .bio{display:block;overflow:visible}
  #written .bio-more{display:inline-block}
}

/* the heading is the whole section, so it is set larger than a normal one and the
   two emitters are sized as a share of the viewport rather than to a fixed cap —
   at 400px they stayed the same size on a 2560 screen and left a hole in the middle */
.pulse-sec .dsp{font-size:calc(clamp(1.9rem,3.6vw,5.1rem) + 3.6 * var(--ux));max-width:15em;margin:0 auto;position:relative;z-index:2}

.pulse-sub{max-width:46em;margin:calc(clamp(18px,1.53vw,34px) + 1.53 * var(--ux)) auto 0;position:relative;z-index:2;
  font-size:var(--t-15);color:var(--deep-2)}

.pulse{position:absolute;top:50%;transform:translateY(-50%);width:min(36%,820px);aspect-ratio:1/1.9;z-index:1;overflow:visible;will-change:transform}

.pulse.left{left:0}

.pulse.right{right:0;transform:translateY(-50%) scaleX(-1)}

/* desktop hover: the whole fan swells about its emitter point (the ring group is
   scaled from script); overflow stays visible so grown rings clip at the section,
   not at the svg box. non-scaling-stroke keeps the line weight constant. */
.pulse g{transform-box:view-box;transform-origin:0 190px}

.pulse path{fill:none;stroke:var(--deep);stroke-width:1.15;vector-effect:non-scaling-stroke;
  opacity:0;transform-origin:0% 50%;animation:ping 7s linear infinite}

@keyframes ping{
  0%{transform:scale(.06);opacity:0}
  6%{opacity:.5}
  92%{opacity:.5}
  100%{transform:scale(1);opacity:0}
}


/* ---------- explore: pinned horizontal ---------- */
/* ---------- resources: membership · book · time to play ----------
   three standalone sections, each a two-column text + image-cluster layout.
   every cluster is a normal-flow grid — nothing is absolutely positioned, so an
   image can never spill out of its frame the way the old pinned collage did. */
.res .page{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:calc(clamp(30px,4.4vw,92px) + 4.4 * var(--ux));align-items:center}

.res.rev .res-media{order:-1}

.res-h{font-family:var(--display);font-weight:400;letter-spacing:-.01em;color:var(--deep);
  font-size:calc(clamp(1.6rem,2.5vw,3.4rem) + 2.5 * var(--ux));line-height:1.06;margin:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux)) 0 0;max-width:13em}

.res-txt>p{font-size:var(--t-145);color:var(--deep-2);max-width:34em;margin-top:calc(clamp(14px,1.1vw,20px) + 1.1 * var(--ux))}

.res .pills{list-style:none;display:flex;flex-wrap:wrap;gap:8px;margin:calc(clamp(18px,1.53vw,32px) + 1.53 * var(--ux)) 0 0}

.res .pills li{background:rgba(255,255,255,.5);color:var(--deep);border-radius:999px;padding:.54em 1.08em;
  font-size:var(--t-xs);border:1px solid rgba(28,32,26,.14);
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm)}

.res-price{font-size:var(--t-sm);color:var(--deep-2);margin:calc(clamp(20px,1.67vw,34px) + 1.67 * var(--ux)) 0 0;max-width:34em;
  padding-top:calc(clamp(16px,1.25vw,26px) + 1.25 * var(--ux));border-top:1px solid rgba(28,32,26,.14)}

.res .btn{margin-top:calc(clamp(22px,1.9vw,36px) + 1.9 * var(--ux))}


/* membership — a fuller mosaic of the live body-section illustrations, and a touch
   more breathing room at the sides than the other resource sections */
#membership>.page{padding-inline:calc(var(--edge) + calc(clamp(12px,3.2vw,72px) + 3.2 * var(--ux)))}

.tilegrid{display:grid;grid-template-columns:repeat(5,1fr);gap:calc(clamp(8px,.7vw,13px) + .7 * var(--ux))}

/* each tile is a self-contained card: the illustration on grey, a clean label on a
   frosted footer beneath it — the live-site idea, with proper type and no baked-in
   text (and the "GI Tract" typo fixed) */
/* square tiles → the 5×4 block (20 sections) stays compact (a square picture area sits above a
   fixed-height label footer) */
.plate{display:flex;flex-direction:column;aspect-ratio:1/1;border-radius:10px;border:1px solid var(--line);
  background:#E9EBE8;overflow:hidden;transition:transform .25s var(--ease),border-color .25s var(--ease)}

/* the picture fills the space above the footer; min-height:0 stops the flex item from
   growing to the image's intrinsic height, so every tile stays exactly square */
.plate .pic{flex:1 1 auto;min-height:0;min-width:0;display:flex;align-items:center;justify-content:center;padding:calc(clamp(8px,.7vw,14px) + .7 * var(--ux))}

.plate .pic img{max-height:100%;max-width:100%;width:auto;object-fit:contain;mix-blend-mode:multiply;
  transition:filter .35s var(--ease)}

/* hover-capable screens rest the tiles in grayscale and colour them under the
   cursor; touch screens keep the colour, since they have no hover to reveal it */
@media (hover:hover) and (pointer:fine){
  .plate .pic img{filter:grayscale(1)}
  .plate:hover .pic img{filter:none}
}

/* fixed footer height + centred text, so every label sits on the same line whether it
   runs one line or two */
.plate .lbl{min-height:2.9em;display:flex;align-items:center;justify-content:center;text-align:center;
  padding:.35em .55em;background:rgba(255,255,255,.62);border-top:1px solid rgba(28,32,26,.08);
  font-family:var(--sans);font-weight:600;font-size:var(--t-xs);letter-spacing:-.005em;line-height:1.15;color:var(--deep)}

a.plate{color:inherit;text-decoration:none}
a.plate:focus-visible{outline:2px solid var(--deep);outline-offset:2px}
.plate:hover{transform:translateY(-3px);border-color:var(--yellow)}

@media (max-width:560px){ .tilegrid{grid-template-columns:repeat(3,1fr)} }


/* book — the cover shown whole beside two chapter spreads */
.bookgrid{display:grid;grid-template-columns:1.02fr 1fr;grid-template-rows:1fr 1fr;
  gap:calc(clamp(12px,1vw,18px) + 1 * var(--ux));aspect-ratio:11/9}

.bookgrid figure{margin:0;border-radius:12px;overflow:hidden;border:1px solid var(--line);background:#fff}

.bookgrid img{width:100%;height:100%;object-fit:cover}

.bookgrid .cover{grid-row:1 / 3;display:flex;align-items:center;justify-content:center}

.bookgrid .cover img{object-fit:contain;padding:7%}

/* a single portrait page in a landscape cell: show its top, where the chapter title is */
.bookgrid .pg img{object-position:50% 4%}


/* time to play — the episode title card, shown whole */
.playone{margin:0;border-radius:12px;overflow:hidden;border:1px solid var(--line)}

.playone img{width:100%;height:auto;display:block}


/* ---------- resources scrollytelling: one pinned frame, three slides ----------
   the three resource sections share one skeleton, so they share one frame: the
   heading and the rail hold still while scroll scrubs the three slides through
   the stage beneath them. slides are stacked in the same grid cell; opacity and
   a small drift are driven off scroll progress, so the whole thing scrubs. */
/* the resources section is ALWAYS light: it carries its own opaque white
   surface and re-pins every light-mode token locally, so the page's dark run
   cannot flip it. */
.rsty{position:relative;z-index:1;
  --white:#FFFFFF;--deep:#24261F;--deep-2:#4A4C45;--muted:#7A7C74;
  --grey-1:#EDEDEC;--grey-2:#C0C0BF;--line:#E4E4E2;
  --glass-white:rgba(250,251,250,.56);--glass-grey:rgba(216,220,216,.56);
  --ring:rgba(28,32,26,.16);--ring-in:rgba(255,255,255,.85)}

html.dk .rsty .btn{background:rgba(20,22,18,.86);color:#fff}

html.dk .rsty .btn:hover{background:rgba(20,22,18,.86)}

.rsty-stick{position:sticky;top:0;height:100vh;min-height:640px;display:flex;flex-direction:column;
  justify-content:center;overflow:hidden;background:#FFFFFF;
  padding:calc(var(--nav-h,64px) + calc(clamp(14px,1.6vw,30px) + 1.6 * var(--ux))) 0 calc(clamp(14px,1.6vw,30px) + 1.6 * var(--ux))}

@supports (height:100svh){ .rsty-stick{height:100svh} }

.rsty-inner{width:100%;max-width:var(--page);margin:0 auto;padding:0 var(--edge)}

.rsty-head{display:flex;justify-content:space-between;align-items:flex-end;gap:calc(clamp(22px,2vw,44px) + 2 * var(--ux));flex-wrap:wrap}

.rsty-head .dsp{margin-top:calc(clamp(12px,1vw,20px) + 1 * var(--ux))}

/* the rail: three plain wordmarks over one shared progress line. the line scrubs
   with the scroll, so it doubles as a "how much of this is left" answer. */
.rsty-rail{display:flex;flex-direction:column;gap:12px;min-width:calc(clamp(280px,26vw,470px) + 26 * var(--ux));
  padding-bottom:calc(clamp(4px,.5vw,10px) + .5 * var(--ux))}

.rsty-tabs{display:flex;justify-content:space-between;gap:calc(clamp(14px,1.4vw,28px) + 1.4 * var(--ux))}

.rsty-tab{appearance:none;background:none;border:0;cursor:pointer;font-family:var(--sans);
  font-size:var(--t-14);color:var(--muted);padding:.35em 0;transition:color .3s var(--ease);white-space:nowrap}

.rsty-tab:hover{color:var(--deep-2)}

.rsty-tab.on{color:var(--deep)}

/* the track is the full three-colour run — one segment per resource — and the
   <b> is a grey COVER anchored right that retreats as the pin progresses, so
   the revealed part always shows each third in its own colour */
.rsty-line{position:relative;height:2px;border-radius:2px;overflow:hidden;
  background:linear-gradient(90deg,var(--blue) 0 33.4%,var(--yellow) 33.4% 66.7%,var(--pink) 66.7% 100%)}

.rsty-line b{position:absolute;right:0;top:0;bottom:0;width:100%;background:var(--line)}

.rsty-stage{display:grid;margin-top:calc(clamp(24px,2.4vw,50px) + 2.4 * var(--ux))}

.rsty-slide{grid-area:1/1;display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:calc(clamp(30px,4.4vw,92px) + 4.4 * var(--ux));align-items:center;opacity:0;pointer-events:none}

.rsty-slide.lead{opacity:1;pointer-events:auto}

/* the media scrubs with the scroll, but the words switch: only the active slide's
   text is on, with a quick fade, so two paragraphs never read on top of each other */
.rsty-txt{opacity:0;transition:opacity .38s var(--ease)}

.rsty-slide.cur .rsty-txt{opacity:1}

/* the media clusters are tall; each is capped against the viewport so a slide
   always fits the pinned frame whole. the cap scales with the cluster's aspect. */
.rsty-media{display:flex;align-items:center;justify-content:center;min-width:0}

/* The cap keeps a cluster inside the pinned frame, but it was a bare subtraction: on a
   660px-tall window it left the 16-tile grid 300px wide and each tile image rendered at
   14x11px — the authors reported the images "didn't show up", and at that size they may as
   well not have. The floor is what a 4-column tile grid needs to stay legible; below it the
   cluster keeps its size and the frame scrolls, which is far better than a postage stamp. */
.m-tiles{width:min(100%,max(420px,calc(100svh - 360px)))}

.m-book{width:min(100%,max(400px,calc((100svh - 360px)*1.22)))}

.m-play{width:100%}

@media (max-width:1080px){
  /* no viewport to pin into: the frame unpins and the slides simply stack,
     each back to the plain one-column resource layout */
  .rsty{height:auto!important}
  .rsty-stick{position:static;height:auto;min-height:0;overflow:visible;padding:var(--sec) 0 0}
  .rsty-rail{display:none}
  .rsty-stage{display:block;margin-top:calc(clamp(26px,6vw,40px) + 6 * var(--ux))}
  .rsty-slide{grid-template-columns:1fr;gap:calc(clamp(26px,6vw,40px) + 6 * var(--ux));opacity:1!important;pointer-events:auto!important}
  .rsty-slide+.rsty-slide{margin-top:var(--sec)}
  .rsty-txt,.rsty-media{transform:none!important;opacity:1!important}
  .m-tiles,.m-book{width:100%}
}

/* 560 -> 700 (2026-09-13): between those heights the frame pinned but had no room, so the
   media shrank to nothing. Better to hand those windows the honest stacked layout, where
   every cluster is full width, than an animation with invisible pictures. */
@media (max-height:700px){
  .rsty{height:auto!important}
  .rsty-stick{position:static;height:auto;min-height:0;overflow:visible;padding:var(--sec) 0 0}
  .rsty-rail{display:none}
  .rsty-stage{display:block;margin-top:calc(clamp(26px,6vw,40px) + 6 * var(--ux))}
  .rsty-slide{opacity:1!important;pointer-events:auto!important}
  .rsty-slide+.rsty-slide{margin-top:var(--sec)}
  .rsty-txt,.rsty-media{transform:none!important;opacity:1!important}
  .m-tiles,.m-book{width:100%}
}


/* ---------- written by: large ---------- */
.wb-head{display:flex;justify-content:space-between;align-items:flex-end;gap:calc(clamp(22px,1.81vw,40px) + 1.81 * var(--ux));
  flex-wrap:wrap;margin-bottom:calc(clamp(38px,3.89vw,84px) + 3.89 * var(--ux))}

.wb{display:grid;grid-template-columns:1fr 1fr;gap:var(--gap)}

.wb article{border-radius:var(--r);overflow:hidden;background:var(--glass-grey);border:1px solid var(--ring);
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur)}

.wb .ph{aspect-ratio:1/1;overflow:hidden;background:var(--grey-2)}

.wb .ph img{width:100%;height:100%;object-fit:cover;object-position:50% 32%;transition:transform .7s var(--ease)}

.wb article:hover .ph img{transform:scale(1.035)}

.wb .bd{padding:calc(clamp(22px,2.4vw,72px) + 2.4 * var(--ux))}

.wb h3{font-family:var(--display);font-weight:400;font-size:calc(clamp(1.5rem,2.3vw,3.2rem) + 2.3 * var(--ux));letter-spacing:-.02em;margin-bottom:.32em}

.wb .role{font-size:var(--t-14);color:var(--deep-2);margin-bottom:1.14em}

.wb .role b{color:var(--deep);font-weight:500}

.wb .bio{font-size:var(--t-145);color:var(--deep-2);max-width:36em}


/* ---------- faq ----------
   the section rides the page ground and JOINS THE DARK RUN: frame() turns the
   dk tokens on as it fills the viewport (like "How it works"), and the footer
   keeps the dark going below it. no ground of its own, no ornament — the rows
   run the full page width. */
/* Any section reachable by a #hash (home's #faq, #book, #ttp, #membership, the book
   page's #fans) has to clear the sticky bar when jumped to, or its heading lands
   underneath it. --nav-h is published by site.js from the bar's real height. */
main section[id]{scroll-margin-top:calc(var(--nav-h,82px) + 10px)}

.faq-sec{position:relative}

.faq-head{text-align:center}

.faq-head .dsp{max-width:14em;margin:0 auto}

.faq-head .lede{max-width:30em;margin:calc(clamp(14px,1.2vw,24px) + 1.2 * var(--ux)) auto 0}

.faq-list{margin:calc(clamp(26px,2.4vw,50px) + 2.4 * var(--ux)) auto 0}

.faq-item{border-top:1px solid var(--line)}

.faq-item:last-child{border-bottom:1px solid var(--line)}

/* a question is a quiet full-width row: text left, a thin plus right. no
   washes, no badges — the only motions are the ink deepening and the plus
   turning into a cross. */
.faq-q{appearance:none;background:none;border:0;cursor:pointer;width:100%;text-align:left;
  display:flex;align-items:center;justify-content:space-between;gap:calc(clamp(16px,1.5vw,30px) + 1.5 * var(--ux));
  padding:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux)) 0;font-family:var(--sans);font-weight:500;
  font-size:var(--t-15);line-height:1.35;color:var(--deep-2);
  transition:color .3s var(--ease)}

.faq-q:hover,.faq-item.open .faq-q{color:var(--deep)}

.faq-x{flex:0 0 auto;width:15px;height:15px;position:relative;color:inherit;
  transition:transform .45s var(--ease)}

.faq-x::before,.faq-x::after{content:"";position:absolute;left:50%;top:50%;
  background:currentColor;transform:translate(-50%,-50%);border-radius:1px}

.faq-x::before{width:100%;height:1.6px}

.faq-x::after{width:1.6px;height:100%}

.faq-item.open .faq-x{transform:rotate(45deg)}

/* smooth open: the grid-rows trick animates height without measuring */
.faq-a{display:grid;grid-template-rows:0fr;transition:grid-template-rows .5s var(--ease)}

.faq-a>div{overflow:hidden}

.faq-a p{font-size:var(--t-14);color:var(--deep-2);max-width:72em;
  padding:0 0 calc(clamp(20px,1.7vw,30px) + 1.7 * var(--ux));opacity:0;transform:translateY(8px);
  transition:opacity .4s var(--ease) .08s,transform .4s var(--ease) .08s}

.faq-a a{color:var(--deep);text-decoration:underline;text-underline-offset:3px}

.faq-item.open .faq-a{grid-template-rows:1fr}

.faq-item.open .faq-a p{opacity:1;transform:none}

/* the closing line under the list */
.faq-out{text-align:center;font-size:var(--t-14);
  color:var(--deep-2);margin:calc(clamp(26px,2.4vw,48px) + 2.4 * var(--ux)) auto 0;max-width:44em}

.faq-out a{color:var(--deep);text-decoration:underline;text-underline-offset:3px}


/* ---------- footer: dark glass like the navbar ----------
   no gradient of its own — a plain translucent dark pane with a hairline, so
   the coloured ambient behind the page is what glows through the frost. */
.foot-sec{position:relative;color:#ECEDE8;
  padding:calc(clamp(46px,5vw,120px) + 5 * var(--ux)) 0 calc(clamp(30px,2.6vw,58px) + 2.6 * var(--ux));
  background:rgba(14,15,16,.55);
  -webkit-backdrop-filter:saturate(2) blur(40px);backdrop-filter:saturate(2) blur(40px);
  border-top:1px solid rgba(255,255,255,.15)}

.foot{position:relative;z-index:1;max-width:var(--page);margin:0 auto;padding:0 var(--edge)}

.foot-top{display:flex;justify-content:space-between;align-items:flex-end;gap:calc(clamp(24px,3vw,72px) + 3 * var(--ux));
  flex-wrap:wrap;padding-bottom:calc(clamp(28px,3vw,58px) + 3 * var(--ux));border-bottom:1px solid rgba(255,255,255,.15)}

.foot-h{font-family:var(--display);font-weight:400;color:#fff;letter-spacing:-.02em;line-height:1;
  font-size:calc(clamp(1.9rem,3.6vw,4.7rem) + 3.6 * var(--ux));max-width:12em}

.foot-cta{display:inline-flex;align-items:center;gap:1.05em;white-space:nowrap;flex:0 0 auto;
  border-radius:var(--r);padding:1.02em 1.6em;font-size:calc(clamp(15px,1.1vw,20px) + 1.1 * var(--ux));color:#24261F;
  background:var(--yellow);border:1px solid transparent;
  transition:transform .3s var(--ease),background .3s var(--ease),color .4s var(--ease)}

.foot-cta:hover{transform:translateY(-2px)}

.foot-cta .arw{transition:transform .35s var(--ease)}

.foot-cta:hover .arw{transform:translateX(6px)}

.foot-mid{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1.5fr);gap:calc(clamp(30px,4vw,100px) + 4 * var(--ux));
  padding:calc(clamp(34px,3.6vw,72px) + 3.6 * var(--ux)) 0}

.foot-logo b{display:block;font-family:var(--display);font-weight:400;font-size:var(--t-19);color:#fff;letter-spacing:-.01em}

.foot-logo i{font-style:normal;font-size:calc(clamp(10px,.69vw,13px) + .69 * var(--ux));letter-spacing:.16em;text-transform:uppercase;
  color:rgba(255,255,255,.5)}

.foot-note{margin-top:calc(clamp(16px,1.25vw,24px) + 1.25 * var(--ux));font-size:var(--t-145);color:rgba(236,237,232,.7);max-width:28em}

.foot-mail{display:inline-block;margin-top:calc(clamp(16px,1.25vw,24px) + 1.25 * var(--ux));font-size:var(--t-17);color:var(--yellow);
  border-bottom:1px solid rgba(255,191,0,.42);padding-bottom:2px;transition:color .25s,border-color .25s}

.foot-mail:hover{color:#ffd451;border-color:rgba(255,191,0,.85)}

.foot-links{display:grid;grid-template-columns:repeat(3,1fr)}

.foot-links>div{padding-left:calc(clamp(18px,1.8vw,40px) + 1.8 * var(--ux));border-left:1px solid rgba(255,255,255,.14)}

.foot-links>div:first-child{padding-left:0;border-left:0}

.foot-links h4{font-size:var(--t-xs);letter-spacing:.14em;text-transform:uppercase;font-weight:500;
  color:rgba(255,255,255,.5);margin-bottom:calc(clamp(12px,1vw,20px) + 1 * var(--ux))}

.foot-links a{display:block;font-size:var(--t-14);padding:.3em 0;color:rgba(236,237,232,.82);transition:color .25s}

.foot-links a:hover{color:#fff}

.foot-legal{display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;
  padding-top:calc(clamp(24px,2.2vw,42px) + 2.2 * var(--ux));border-top:1px solid rgba(255,255,255,.15);
  font-size:var(--t-xs);color:rgba(236,237,232,.55)}


/* ---------- motion ---------- */
.rv{opacity:0;transform:translateY(16px);transition:opacity .7s var(--ease),transform .7s var(--ease)}

.rv.on{opacity:1;transform:none}


@media (max-width:1080px){
  .wb,.who{grid-template-columns:1fr}
  .res .page{grid-template-columns:1fr;gap:calc(clamp(26px,6vw,40px) + 6 * var(--ux))}
  .res.rev .res-media{order:0}
  .who-head{grid-template-columns:1fr;gap:calc(clamp(16px,4vw,26px) + 4 * var(--ux))}
  .who-authors{grid-template-columns:1fr;gap:calc(clamp(18px,5vw,26px) + 5 * var(--ux))}
  .who-authors-label{padding-top:0}
  .who-people{grid-template-columns:1fr;gap:calc(clamp(20px,5vw,28px) + 5 * var(--ux))}
  /* no room to float the credentials over the title on a phone: the hero becomes a
     column, the credentials take their own space and the title block centres in
     what is left. padding-top/bottom only, or .page's horizontal inset is lost. */
  .hero-stage{flex-direction:column;align-items:stretch;justify-content:flex-start}
  .hero-top{position:static;padding-top:calc(var(--nav-h,64px) + calc(clamp(18px,5vw,28px) + 5 * var(--ux)))}
  /* the column already puts the block below centre, so no extra shift here */
  .hero-float{flex:1 1 auto;display:flex;flex-direction:column;justify-content:center;transform:none;
    padding-top:calc(clamp(28px,7vw,44px) + 7 * var(--ux));padding-bottom:calc(clamp(28px,7vw,44px) + 7 * var(--ux))}
  /* no room to split the row on a phone: it stacks and re-centres under the title */
  .hero-row{flex-direction:column;align-items:center;text-align:center;gap:calc(clamp(22px,5vw,30px) + 5 * var(--ux))}
  .hero-lede{max-width:34em}
  .foot-top{align-items:flex-start}
  .foot-mid{grid-template-columns:1fr;gap:calc(clamp(30px,6vw,52px) + 6 * var(--ux))}
  /* the stage gives up the crossfade stack: slides become plain blocks and only
     the active one is in flow, so the height always fits the content. the deck
     edges have no room on a phone. */
  .stage{min-height:0}
  .slide{position:relative;inset:auto;display:none}
  .slide.on{display:flex}
  .wash{transition:none}
  .nrow ul{display:none}

  /* the rail unpins and the track becomes a column. flex-basis then sizes the
     CROSS axis the other way round — it was setting each card's HEIGHT to 88vw
     and, with flex:0 0, refusing to grow, so every card's content ran out of the
     bottom and over the card below. cards are auto-height blocks down here. */
  .rail-stick{height:auto;min-height:0;position:static;padding:0}
  .track{flex-direction:column;transform:none!important}
  .rail-sec{height:auto!important}
  .slab{flex:0 0 auto;width:100%;grid-template-columns:1fr;height:auto;min-height:0;align-items:start}
  /* the three figures are a stacked composition only when there is room for one.
     in a column they lay out in flow instead of escaping the card. */
  .stack{position:static;height:auto;min-height:0;max-width:none;margin-top:calc(clamp(22px,5vw,32px) + 5 * var(--ux));
    display:grid;grid-template-columns:1fr 1fr;gap:calc(clamp(12px,3vw,16px) + 3 * var(--ux))}
  .stack>*{position:static;width:auto;height:auto}
  .sf3{grid-column:1 / -1}
  .sf1,.sf2{align-self:start}

  /* the pinned story frame: one column, and the boxes give up their glass for
     hairlines so four of them still fit on a phone screen */
  .story-stick{padding-top:clamp(52px,8vh,120px)}
  .story-txt{max-width:none}
  .story-lede{margin-top:14px}
  .story-a .story-grid,.story-b .story-grid{grid-template-columns:1fr;gap:0;
    margin-top:calc(clamp(22px,4.5vw,34px) + 4.5 * var(--ux))}
  .story-item{background:none!important;border:0;border-top:1px solid var(--ring);border-radius:0;
    padding:calc(clamp(11px,2.8vw,16px) + 2.8 * var(--ux)) 0;-webkit-backdrop-filter:none;backdrop-filter:none}
  .story-item::after{display:none}
  .story-item h3{font-size:15.5px;margin-bottom:.25em}
  .story-item p{font-size:13px;line-height:1.45}
  .story-n{font-size:11.5px;margin-bottom:.4em}
  .sine{height:22%}

  .pulse{width:52%;opacity:.5}
  .nrow{gap:14px}
  .logo b{font-size:17px}
  .btn{padding:12px 16px;gap:14px}
}

@media (max-width:640px){
  .dash{display:none}
  .stack{grid-template-columns:1fr}
  .sf3{grid-column:auto}
}

/* a pinned frame can only ever show one viewport, so on a short screen the four
   stages have to be bought space rather than allowed to run off the bottom. the
   supporting line goes first: the heading and the stages themselves carry it. */
@media (max-width:1080px) and (max-height:760px){
  .story-stick{padding-top:clamp(34px,5vh,70px)}
  .story-lede{display:none}
  .story-a .story-grid,.story-b .story-grid{margin-top:16px}
  .story-item{padding:9px 0}
  .story-item p{font-size:12.5px}
  .sine{height:16%}
}

/* below this there is no viewport left to pin into — a landscape phone. the frame
   gives up the pin and the two states simply stack, so nothing is ever clipped. */
@media (max-height:520px){
  .story{height:auto!important}
  .story-stick{position:static;height:auto;min-height:0;padding:clamp(48px,9vh,80px) 0;overflow:visible}
  .story-a,.story-b{opacity:1!important;visibility:visible!important}
  .story-b{position:static;left:auto;right:auto;margin-top:clamp(34px,7vh,56px)}
  .story-lede{display:block}
  .sine{display:none}
  /* no viewport to pin into down here: the curtain gives up its stick and dim */
  .pulse-sec{position:relative}
  .pulse-dim{display:none}
  #written{border-radius:0;box-shadow:none}
  /* same for the frame: no viewport to pin into — the hero is one plain screen
     and the welcome is a plain white block beneath it */
  .hero{height:auto;min-height:100vh}
  .hero-stage{position:relative;height:auto;min-height:100vh}
  .hero-media{width:auto!important;height:auto!important;left:0!important;top:0!important;
    border-radius:0!important;inset:0}
  .hero-welcome{position:relative;left:auto;top:auto;bottom:auto;transform:none!important;
    opacity:1!important;width:auto;padding:clamp(48px,9vh,80px) var(--edge);background:#fff}
  .hero-welcome .hl{background-size:100% 56%}
}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{transition-duration:.01ms!important;animation:none!important}
  .amb{transform:none!important}
  .rv{opacity:1!important;transform:none!important}
  .pulse path{opacity:.3}
}


/* ---------- micro screens (<375px): the bar sheds its login link ---------- */
@media (max-width:374px){
  .nrow{gap:10px}
}

/* phones (was <375 only): the authors' longer "Own the book? Unlock its companion videos"
   ran off both edges of a 375px screen, so a button may wrap on any phone */
@media (max-width:480px){
  .hero-cta{white-space:normal;text-align:left;line-height:1.35;flex-shrink:1;max-width:100%}
}


/* ================= mobile pass (shared) ================= */
/* hamburger: the links move into a dark glass sheet under the bar */
.nav-burger{display:none;appearance:none;background:none;border:0;cursor:pointer;color:inherit;
  width:40px;height:40px;border-radius:10px;align-items:center;justify-content:center}

@media (max-width:1080px){
  /* a taller bar with bigger touch targets on small screens */
  .nrow{padding-top:15px;padding-bottom:15px}
  .nav-burger{display:inline-flex;transition:background .3s var(--ease);width:46px;height:46px}
  .nav.menu-open .nav-burger{background:rgba(128,131,126,.2)}
  .nrow{position:relative;z-index:1}
  /* the sheet is the bar, continued: full bleed, the exact same fill and frost,
     so opening the menu reads as the navbar extending downward */
  .nrow ul{position:absolute;top:100%;left:0;right:0;margin:0;z-index:70;
    height:calc(100vh - var(--nav-h,64px));height:calc(100dvh - var(--nav-h,64px));
    overflow-y:auto;
    display:flex;flex-direction:column;gap:0;
    padding:clamp(14px,3vh,34px) var(--edge) calc(20px + env(safe-area-inset-bottom,0px));
    background:rgba(255,255,255,.38);
    -webkit-backdrop-filter:saturate(2) blur(40px);backdrop-filter:saturate(2) blur(40px);
    border-bottom:1px solid rgba(28,32,26,.13);
    opacity:0;visibility:hidden;transform:translateY(-8px);pointer-events:none;
    transition:opacity .3s var(--ease),transform .3s var(--ease),visibility 0s linear .3s}
  .nav.menu-open .nrow ul{opacity:1;visibility:visible;transform:none;pointer-events:auto;
    transition:opacity .3s var(--ease),transform .3s var(--ease)}
  /* full-screen sheet: the links earn display type */
  .nrow ul a{display:flex;align-items:center;justify-content:space-between;gap:1em;
    padding:.62em 2px;font-family:var(--display);font-weight:400;letter-spacing:-.01em;
    font-size:calc(clamp(26px,6.2vw,34px) + 6.2 * var(--ux));line-height:1.15;color:var(--deep);opacity:1;
    border-top:1px solid var(--ring)}
  .nrow ul li:first-child a{border-top:0}
  /* the house arrow on every row, taking the row's own text colour */
  .nrow ul a::after{content:"";width:26px;height:12px;flex:0 0 auto;opacity:.55;background:currentColor;
    -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 12' fill='none'%3E%3Cpath d='M0 6h23M18 1l5 5-5 5' stroke='%23000' stroke-width='1.4'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 12' fill='none'%3E%3Cpath d='M0 6h23M18 1l5 5-5 5' stroke='%23000' stroke-width='1.4'/%3E%3C/svg%3E") center/contain no-repeat}
  .nrow ul .menu-shop a::after{background:var(--yellow);opacity:.95}
  /* In the sheet the arrow is already gold on the shop row, so "you are here" gets its
     own mark: a gold bar in the gutter, clear of the label so every row stays aligned. */
  .nrow ul a[aria-current="page"]{position:relative}
  .nrow ul a[aria-current="page"]::before{content:"";position:absolute;left:-10px;top:.5em;bottom:.5em;
    width:3px;border-radius:2px;background:var(--yellow)}
}

/* while the sheet is open, the whole page behind it falls into deep frost */
.menu-veil{position:fixed;inset:0;z-index:50;opacity:0;pointer-events:none;
  background:rgba(10,11,9,.22);
  -webkit-backdrop-filter:blur(16px) saturate(1.5);backdrop-filter:blur(16px) saturate(1.5);
  transition:opacity .35s var(--ease)}

.menu-veil.on{opacity:1;pointer-events:auto}

/* browsers without backdrop-filter get a near-solid sheet instead of a see-through one */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .nrow ul{background:rgba(248,249,247,.97)}
}

/* phones: the ambient blobs must be far larger and softer than the screen, or
   they read as circles. pink pulls right back — atmosphere, not a shape. */
@media (max-width:1080px){
  .amb{inset:-70%}
  .amb .b1{width:190vw;height:190vw;left:-55%;top:-35%}
  .amb .b2{width:210vw;height:210vw;right:-70%;top:-15%}
  .amb .b3{width:180vw;height:180vw;right:-45%;top:52%;opacity:.5}
  .amb .b4{width:170vw;height:170vw;left:-45%;bottom:-40%}
}

/* the footer earns its height back on phones: three link columns side by side */
@media (max-width:1080px){
  .nav-act{margin-left:auto}
}

/* tablet: Log in sits dead-centre of the bar; Shop and the burger hold the right */
@media (min-width:641px) and (max-width:1080px){
  .nav-login{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}
}

/* phone: the logotype becomes one clean line, Log in takes the button slot and
   Shop moves into the burger sheet */
@media (max-width:640px){
  .nrow{gap:10px}
  .logo{gap:2px}
  .logo b{font-size:15.5px;white-space:nowrap}
  .logo i{font-size:9.5px;letter-spacing:.14em}
  .nrow .btn{display:none}
  .menu-shop{display:block}
  .nav-login{opacity:1;padding:13px 16px;border-radius:var(--r);
    background:rgba(128,131,126,.2)}
}

@media (max-width:480px){ .logo i{display:none} }

@media (max-width:420px){
  .logo b{font-size:14px}
  .nav-login{padding:10px 12px}
}

@media (max-width:360px){
  .logo b{font-size:13.5px}
  .nav-login span{display:none}
  .nav-login{padding:10px 11px;gap:0}
}

@media (max-width:640px){
  .foot-sec{padding:calc(clamp(30px,8vw,46px) + 8 * var(--ux)) 0 calc(clamp(20px,5vw,30px) + 5 * var(--ux))}
  .foot-top{padding-bottom:calc(clamp(18px,5vw,28px) + 5 * var(--ux))}
  .foot-mid{grid-template-columns:1fr;padding:calc(clamp(22px,6vw,34px) + 6 * var(--ux)) 0;gap:calc(clamp(20px,5vw,30px) + 5 * var(--ux))}
  .foot-links{grid-template-columns:repeat(3,1fr);gap:0 12px}
  .foot-links>div,.foot-links>div+div{border:0;padding:0;margin:0}
  .foot-links h4{font-size:11px;letter-spacing:.12em;margin-bottom:8px}
  .foot-links a{font-size:13px;padding:.3em 0}
  .foot-note{font-size:13.5px;margin-top:12px}
  .foot-mail{font-size:var(--t-14);overflow-wrap:anywhere;max-width:100%;margin-top:12px}
  .foot-h{font-size:calc(clamp(1.9rem,8.5vw,2.6rem) + 8.5 * var(--ux))}
  .foot-legal{padding-top:calc(clamp(14px,4vw,20px) + 4 * var(--ux));font-size:11.5px}
}

@media (max-width:360px){
  .foot-links{grid-template-columns:1fr 1fr;gap:6px 12px}
}

.menu-shop{display:none}

@media (max-width:640px){ .menu-shop{display:list-item} }


/* ================= mobile pass (home) ================= */
/* hero: the block centres in the space BELOW the bar, and the title grows */
@media (max-width:1080px){
  .hero-float{padding-top:calc(var(--nav-h,64px) + calc(clamp(20px,5vw,36px) + 5 * var(--ux)))}
}

@media (max-width:640px){
  .hero-title{font-size:calc(clamp(2.35rem,10.5vw,4rem) + 10.5 * var(--ux))}
}

/* the pinned story clears the bar, and the wave rides a little higher, a little larger */
@media (max-width:1080px){
  .story-stick{padding-top:calc(var(--nav-h,64px) + clamp(18px,4vh,48px))}
  .sine{height:28%;bottom:4%}
}

/* resources on mobile: no tabs, no pin — three COMPACT stacked cards, media
   first and the long paragraph dropped, so each resource reads in one screen
   and the page just scrolls through them */
@media (max-width:1080px){
  .rsty-rail{display:none}
  .rsty-stage{margin-top:calc(clamp(20px,5vw,30px) + 5 * var(--ux))}
  .rsty-slide{display:grid;opacity:1!important;pointer-events:auto!important;
    grid-template-columns:1fr;gap:calc(clamp(16px,4vw,24px) + 4 * var(--ux))}
  .rsty-slide+.rsty-slide{margin-top:calc(clamp(44px,11vw,72px) + 11 * var(--ux))}
  .rsty-media{order:-1}
  .rsty-txt{opacity:1!important}
  .res-txt>p:not(.res-price){display:none}
  .res-h{font-size:calc(clamp(1.35rem,5.8vw,1.8rem) + 5.8 * var(--ux));margin-top:0}
  .res .pills{margin-top:calc(clamp(12px,3vw,18px) + 3 * var(--ux))}
  .res-price{margin-top:calc(clamp(12px,3vw,18px) + 3 * var(--ux));padding-top:calc(clamp(10px,2.5vw,16px) + 2.5 * var(--ux))}
  .res .btn{margin-top:calc(clamp(14px,3.5vw,22px) + 3.5 * var(--ux))}
  /* the 20-tile mosaic becomes a two-row swipe strip instead of a long grid */
  #membership .m-tiles{width:100%}
  #membership .tilegrid{grid-template-columns:none;grid-auto-flow:column;
    grid-template-rows:1fr 1fr;grid-auto-columns:calc(clamp(96px,26vw,120px) + 26 * var(--ux));
    overflow-x:auto;padding-bottom:8px;-webkit-overflow-scrolling:touch}
}

/* about us: shorter portraits, bios clamped behind a Read more */
.bio-more{display:none;margin-top:.7em;font-size:var(--t-sm);font-weight:600;color:var(--deep);
  background:none;border:0;padding:0;cursor:pointer;text-decoration:underline;font-family:inherit}

@media (max-width:1080px){
  .wb .ph{aspect-ratio:16/10}
  .wb .bio{display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden}
  .wb article.x .bio{display:block;overflow:visible}
  .bio-more{display:inline-block}
}


/* the sheet follows the bar's own states: dark over the hero video, dark in the dark run */
@media (max-width:1080px){
  .nav.on-video .nrow ul{background:rgba(16,17,15,.55);border-bottom-color:rgba(255,255,255,.17)}
  .nav.on-video .nrow ul a{color:#F2F3F1;border-top-color:rgba(255,255,255,.12)}
  html.dk .nrow ul{background:rgba(14,15,16,.55);border-bottom-color:rgba(255,255,255,.12)}
}


/* ---------- login modal: small glass dialog, context-preserving ---------- */
.lmodal{position:fixed;inset:0;z-index:130;display:flex;align-items:center;justify-content:center;padding:var(--edge)}

.lmodal[hidden]{display:none}

.lmodal-back{position:absolute;inset:0;background:rgba(14,15,13,.44);
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm)}

.lmodal-card{position:relative;width:min(100%,calc(clamp(350px,27vw,430px) + 27 * var(--ux)));background:rgba(250,251,250,.9);
  border:1px solid var(--ring);border-radius:var(--r);padding:calc(clamp(26px,2.4vw,42px) + 2.4 * var(--ux));
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur)}

.lmodal-card::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--ring-in);mix-blend-mode:overlay}

.lmodal h3{font-family:var(--display);font-weight:400;font-size:calc(clamp(1.35rem,1.6vw,1.9rem) + 1.6 * var(--ux));letter-spacing:-.01em}

.lmodal-close{position:absolute;top:calc(clamp(12px,1.1vw,18px) + 1.1 * var(--ux));right:calc(clamp(12px,1.1vw,18px) + 1.1 * var(--ux));width:2.2em;height:2.2em;
  border-radius:50%;background:rgba(255,255,255,.6);border:1px solid var(--ring);color:var(--deep);
  display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .2s var(--ease)}

.lmodal-close:hover{background:#fff}

.lmodal-remember{display:flex;gap:.6em;align-items:flex-start;margin-top:calc(clamp(12px,1vw,16px) + 1 * var(--ux));
  font-size:var(--t-xs);color:var(--deep-2);line-height:1.45}

.lmodal-remember input{margin-top:.25em}

.lmodal .btn{width:100%;justify-content:center;margin-top:calc(clamp(14px,1.2vw,20px) + 1.2 * var(--ux));
  background:var(--yellow);color:var(--deep);border-color:rgba(120,88,0,.24)}

.lmodal .btn:hover{background:#ffcd3d}

.lmodal-or{display:flex;align-items:center;gap:.9em;margin-top:calc(clamp(14px,1.2vw,20px) + 1.2 * var(--ux));
  color:var(--muted);font-size:var(--t-xs)}

.lmodal-or::before,.lmodal-or::after{content:"";height:1px;background:var(--line);flex:1}

.lmodal-alt{width:100%;display:inline-flex;justify-content:center;margin-top:calc(clamp(12px,1vw,16px) + 1 * var(--ux));
  padding:.85em 1em;border:1px solid var(--ring);border-radius:var(--r);background:rgba(255,255,255,.5);
  font:inherit;font-size:var(--t-145);color:var(--deep);cursor:pointer;transition:background .25s}

.lmodal-alt:hover{background:rgba(255,255,255,.85)}

.lmodal-foot{margin-top:calc(clamp(16px,1.4vw,22px) + 1.4 * var(--ux));padding-top:calc(clamp(12px,1.1vw,18px) + 1.1 * var(--ux));border-top:1px solid var(--line);
  font-size:var(--t-xs);color:var(--muted);display:flex;justify-content:space-between;gap:1em;flex-wrap:wrap}

.lmodal-foot a,.lmodal-forgot{color:var(--deep-2);border-bottom:1px solid var(--grey-2);padding:0 0 1px;
  background:none;border-top:0;border-left:0;border-right:0;font:inherit;font-size:var(--t-xs);cursor:pointer}

.lmodal-foot a:hover,.lmodal-forgot:hover{color:var(--deep)}

.lmodal-note{margin-top:calc(clamp(12px,1.1vw,16px) + 1.1 * var(--ux));font-size:var(--t-xs);color:var(--muted)}

/* ---------- page shell ----------
   restored T4-F1: dropped during the Task 4 port, causing every page (not
   just the eight mockups) to lose its max-width/gutter. */
main{min-height:60vh}
main .sec{max-width:var(--page);margin:0 auto;padding:var(--sec) var(--edge)}

/* ---------- flash bar + auth forms ----------
   not from any of the eight mockups (none of them carry a login/signup/account
   form) — ported as-is from layout.php's own inline <style>, which is what the
   already-shipped /login /signup /account /reset /checkout /thanks /verify
   views have been rendering against; kept in the shared block since it needs
   to ship on every page layout.php can render, mockup or not. */
.flash{max-width:var(--page);margin:0 auto;padding:calc(clamp(12px,1.1vw,18px) + 1.1 * var(--ux)) var(--edge);
  display:flex}
.flash p{width:100%;background:rgba(255,191,0,.14);border:1px solid rgba(255,191,0,.4);
  border-radius:var(--r);padding:.85em 1.2em;font-size:var(--t-145);color:var(--deep);line-height:1.5}
.auth-wrap{max-width:calc(var(--card-max) * .62);margin:0 auto}
.auth-card{background:var(--glass-white);backdrop-filter:var(--blur-sm);-webkit-backdrop-filter:var(--blur-sm);
  border:1px solid var(--ring-in);border-radius:calc(var(--r) * 1.15);
  padding:calc(clamp(28px,3vw,52px) + 3 * var(--ux));box-shadow:0 1px 2px rgba(28,32,26,.05)}
.auth-lede{font-size:var(--t-145);color:var(--deep-2);margin-top:.6em;margin-bottom:calc(clamp(20px,2vw,32px) + 2 * var(--ux))}
.field{display:flex;flex-direction:column;gap:.5em;margin-bottom:calc(clamp(16px,1.5vw,24px) + 1.5 * var(--ux))}
.field label{font-size:var(--t-xs);letter-spacing:.06em;text-transform:uppercase;color:var(--deep-2);font-weight:500}
.field input{font:inherit;font-size:var(--t-15);color:var(--deep);background:#fff;
  border:1px solid var(--line);border-radius:calc(var(--r) * .55);padding:.85em 1em;
  transition:border-color .2s,box-shadow .2s}
.field input:focus-visible{outline:none;border-color:var(--yellow);box-shadow:0 0 0 3px rgba(255,191,0,.25)}
/* The contact form reuses the auth card; its select and textarea need the input's own
   frame, which .field only ever gave to <input>. Values match .field input above. */
.field select,.field textarea{font:inherit;font-size:var(--t-15);color:var(--deep);background:#fff;
  border:1px solid var(--line);border-radius:calc(var(--r) * .55);padding:.85em 1em;
  width:100%;transition:border-color .2s,box-shadow .2s}
.field select:focus-visible,.field textarea:focus-visible{outline:none;border-color:var(--yellow);box-shadow:0 0 0 3px rgba(255,191,0,.25)}
.auth-btn{width:100%;display:inline-flex;align-items:center;justify-content:center;gap:.6em;
  font:inherit;font-size:var(--t-15);cursor:pointer;color:#24261F;background:var(--yellow);
  border:1px solid transparent;border-radius:calc(var(--r) * .55);padding:.9em 1.4em;margin-top:.25em;
  transition:transform .25s var(--ease),background .25s var(--ease)}
.auth-btn:hover{transform:translateY(-1px);background:#ffcc33}
.auth-links{margin-top:calc(clamp(16px,1.5vw,24px) + 1.5 * var(--ux));display:flex;flex-direction:column;gap:.6em;
  font-size:var(--t-145)}
.auth-links a{color:var(--deep-2);border-bottom:1px solid var(--line);padding-bottom:1px;transition:color .2s,border-color .2s}
.auth-links a:hover{color:var(--deep);border-color:var(--grey-2)}
.nav-account-form{display:inline}
.nav-account-form button{font:inherit;font-size:inherit;color:inherit;background:none;border:0;cursor:pointer;
  padding:0;text-decoration:none;opacity:.82;transition:opacity .2s,color .2s}
.nav-account-form button:hover{opacity:1;color:var(--yellow)}
@media (max-width:640px){
  .auth-card{padding:calc(clamp(22px,7vw,30px) + 7 * var(--ux))}
}

/* solid nav/footer on the pages with no ambient layer behind them ----------
   ease-clear-v2.html's nav/.foot-sec are translucent glass that the #amb blobs
   refract — the whole point of the ambient layer. layout.php only renders that
   layer on the eight content pages (see $__showAmb); the pre-existing account/
   checkout/auth views (body[data-page=""], predating T4) have nothing behind
   the bar to filter, and backdrop-filter over plain white reads as flat mid-
   grey instead of near-black — exactly the reasoning layout.php's own inline
   <style> gave for painting them solid before this consolidation. Restored
   here, scoped to those routes only, rather than lost with the inline style. */
body[data-page=""] .nav{background:rgba(255,255,255,.96);backdrop-filter:none;-webkit-backdrop-filter:none}
body[data-page=""] .foot-sec{background:var(--deep);backdrop-filter:none;-webkit-backdrop-filter:none}
body:has(.gold-room) .foot-sec{background:var(--deep);backdrop-filter:none;-webkit-backdrop-filter:none}
body:has(.gold-room) main{background:#1A1C18}

/* the live nav's checkbox-only mobile menu (layout.php's <input#navcheck> +
   <label class="nav-burger">, zero-JS, already proven by the pre-T4 "before"
   screenshots) needs its own :has()-driven rules — ease-clear-v2.html's shared
   block above only covers the OTHER burger pattern (a JS-toggled
   <button class="nav-burger"> + .menu-open, see site.js setMenu()). Both sets
   of rules are inert unless their own markup/state is present, so they coexist
   safely; kept as an addendum rather than folded in so this divergence stays
   visible. */
.nav-check{position:absolute;opacity:0;pointer-events:none}
@media (max-width:1080px){
  .nav:has(.nav-check:checked) .nav-burger{background:rgba(128,131,126,.2)}
  .nav:has(.nav-check:checked) .nrow ul{opacity:1;visibility:visible;transform:none;pointer-events:auto;
    transition:opacity .3s var(--ease),transform .3s var(--ease)}
}

/* ---------- hoisted: shared card/rail components — canonical = library.html's
   versions. These were unscoped and colliding across the post/video/blog/
   time-to-play/exercise page blocks below (equal specificity, last-in-file
   silently won on every page); library.html is the most recent approved
   design of each, so its declaration lives here once and the page blocks
   below only carry the genuine, scoped divergences (T4-F2). ---------- */
.lib-row-sec{padding:calc(clamp(26px,2.6vw,44px) + 2.6 * var(--ux)) 0 0;position:relative;z-index:40}

.lib-layout{display:grid;grid-template-columns:var(--rail-w) minmax(0,1fr);gap:var(--gap);align-items:start}

.lib-rail{position:sticky;align-self:start;overflow-y:auto;overscroll-behavior:contain;
  scrollbar-width:thin;scrollbar-color:var(--grey-2) transparent;
  background:rgba(250,251,250,.5);border:1px solid var(--ring);border-radius:var(--r);
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm)}

.lib-rail-inner{display:flex;flex-direction:column;gap:2px;
  padding:calc(clamp(16px,1.4vw,24px) + 1.4 * var(--ux)) calc(clamp(14px,1.2vw,20px) + 1.2 * var(--ux)) calc(clamp(20px,1.8vw,32px) + 1.8 * var(--ux))}

.lib-rail-label{text-transform:uppercase;letter-spacing:.16em;font-weight:600;margin:.6em 0 .5em}

.lib-search{position:relative;z-index:80;width:100%;display:flex;align-items:center;gap:.7em;
  background:rgba(255,255,255,.62);border:1px solid var(--ring);border-radius:var(--r-chip);
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  padding:.85em 1.1em;margin-bottom:var(--pad-sm)}

.lib-type-pills{display:flex;flex-wrap:wrap;gap:6px;padding:.2em .5em}

.lib-type-pills .chip{cursor:pointer;border-width:1px}

.lib-clear{display:inline-block;margin:.8em .5em 0;text-decoration:underline;text-underline-offset:3px;
  background:none;border:0;cursor:pointer;color:var(--deep-2);padding:0}

@media (max-width:1080px){
  .lib-layout{grid-template-columns:minmax(0,1fr)}
  .lib-rail{position:static;top:auto}
}

.lib-cta-sec{padding:0 0 calc(clamp(20px,2vw,36px) + 2 * var(--ux))}

.lib-cta .btn{margin-top:.4em}

.v-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:var(--gap);
  margin-top:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux))}

.v-card{display:block;transition:transform .35s var(--ease);animation:cardIn .25s var(--ease) both}

.v-thumb{position:relative;aspect-ratio:16/10;border-radius:12px;overflow:hidden;background:#0A0A0B;
  border:1px solid var(--line);transition:border-color .3s var(--ease)}

.v-badge{display:inline-block;background:rgba(20,22,18,.7);-webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  color:#fff;font-size:var(--t-xs);border-radius:7px;padding:.2em .55em;line-height:1.3;white-space:nowrap;
  border:1px solid rgba(255,255,255,.22)}

.v-badge-free{background:var(--yellow);color:var(--deep);border-color:rgba(120,88,0,.28)}

.v-dur{position:absolute;bottom:8px;right:8px;background:rgba(20,22,18,.7);-webkit-backdrop-filter:var(--blur-sm);
  backdrop-filter:var(--blur-sm);color:#fff;font-size:var(--t-xs);border-radius:6px;padding:.2em .55em;z-index:2;
  border:1px solid rgba(255,255,255,.22)}


/* ============ shared: player (render_player()'s partial, site/views/_player.php) ============
   Hoisted out of the video-only page block (T-SHARED-1 fix 1): render_player() is used on
   every content page (video posts, exercises, and later home/atlas), but every rule below —
   including the --play-lg size token itself (now in the shared :root above) — lived only
   under body[data-page="video"], so a locked or entitled .sau-player only rendered right on
   /video/. Elsewhere (e.g. /time-to-play/{n}/, whose .sau-player instances come from the
   same render_player() call) --play-lg was undefined custom-property, so the idle/lock
   button's .v-play-circle had no valid width/height and fell back to its bare SVG at
   intrinsic size, uncentred and unstyled — the "tiny bare lock glyph" bug — and the locked
   poster's cover/round-button treatment (both already unscoped, just physically misfiled)
   never got the chance to matter visually next to it. Values are video.html's, unchanged;
   only the location and the body[data-page="video"] scoping are removed. */
.v-play{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;opacity:0;
  transition:opacity .3s var(--ease);z-index:2}

.v-card:hover .v-play{opacity:1}

.v-play-circle{width:var(--play-circle);height:var(--play-circle);border-radius:50%;background:rgba(255,255,255,.16);
  border:1px solid rgba(255,255,255,.45);-webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  display:flex;align-items:center;justify-content:center}

/* _player.php's <video> has no id (video.html's rule was `video#videoEl{position:absolute;
   inset:0;width:100%;height:100%;background:#000;z-index:4}`, video.html:229) — without a
   class-scoped equivalent it rendered at its intrinsic pixel size (e.g. 1280x720), blowing
   out of the mobile frame box so only a corner of the poster/clip showed. Locked players set
   the poster as an inline background-image on .sau-player--locked itself with nothing sizing
   it (mock's poster is a `.v-still{position:absolute;inset:0;width:100%;height:100%;
   object-fit:cover}` <img> — the background-size/position equivalent below).

   T6-F3 fix 1/2: this rule alone only sized the <video>, never the box around it — only
   .v-frame (the video page's hero wrapper) carried its own position/aspect-ratio/overflow,
   so a second player in a multi-video post (render_player(['class'=>'art-embed']), no
   .v-frame) collapsed to 0 height under an 800px-tall absolutely-positioned <video> (fix 2).
   Worse, the <video> sat at z-index:4 — ABOVE .v-play's z-index:2 — so a pointer click on the
   idle frame hit the bare <video> (no controls yet, video_post.php strips them until 'play')
   instead of the button; nothing happened (fix 1). video.html avoids this because its single
   <video> is [hidden] (display:none) while idle, so it's never in the way (video.html:
   229-230); our <video> stays visible for its poster attribute, so instead the video goes to
   the BOTTOM of the stack and the button/overlay/badges go above it. .sau-player itself now
   carries the 16:9 box every player needs, on every page it appears on, wrapper class or
   not. */
.sau-player{position:relative;aspect-ratio:16/9;overflow:hidden;background:#000}

.sau-player video{position:absolute;inset:0;width:100%;height:100%;background:#000;z-index:1}

.sau-player--locked{background-size:cover;background-position:50% 50%}

/* The entitled player's button (_player.php's <button class="v-play">) reuses the .v-card
   thumbnail's .v-play/.v-play-circle classes above (opacity:0, shown only on
   `.v-card:hover`), which is right for a small hover-reveal icon on a grid card but wrong
   here: the frame's play button must be visible at rest, the way video.html's #idleBtn is.
   Scoped to the player (not the card) so the thumbnail's hover-reveal behaviour is
   untouched; already covers inset:0, so a pointer click ANYWHERE on the idle frame already
   lands on this button — no separate click-anywhere handler needed once it's stacked above
   the <video>. */
.sau-player > .v-play{opacity:1;z-index:3;background:transparent;border:0;cursor:pointer;padding:0}

.sau-player > .v-play[hidden]{display:none}

.sau-player > .v-play .v-play-circle{width:var(--play-lg);height:var(--play-lg);transition:background .3s var(--ease),transform .3s var(--ease)}

.sau-player > .v-play:hover .v-play-circle,.sau-player > .v-play:focus-visible .v-play-circle{background:rgba(255,255,255,.30);transform:scale(1.07)}

/* .v-idle-btn is injected client-side (video_post.php's and exercise.php's own inline
   scripts, both ported from video.html's #idleBtn pattern) into every .sau-player--locked
   on the page — the entitled state's big always-visible button, reused for the locked
   poster. */
.v-idle-btn{position:absolute;inset:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;
  background:transparent;border:0;cursor:pointer;padding:0;z-index:2}

.v-idle-btn .v-play-circle{width:var(--play-lg);height:var(--play-lg);transition:background .3s var(--ease),transform .3s var(--ease)}

.v-idle-btn:hover .v-play-circle,.v-idle-btn:focus-visible .v-play-circle{background:rgba(255,255,255,.30);transform:scale(1.07)}

.v-idle-btn[hidden]{display:none}

/* the membership-gate overlay: _player.php's locked markup renders it permanently `.on`/
   visible so the page works without JS; video_post.php's/exercise.php's inline scripts hide
   it again and reveal it on the idle button's click instead, so it can transition in. */
.v-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;
  padding:var(--pad);background:rgba(9,10,9,.86);-webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  opacity:0;transition:opacity .35s var(--ease);z-index:3}

.v-overlay.on{opacity:1}

.v-overlay[hidden]{display:none}

.v-overlay :focus-visible{outline-color:#fff}

.v-overlay-body{max-width:30em;display:flex;flex-direction:column;align-items:center;gap:1em}

.v-overlay-body h3{color:#fff}

.v-overlay-body p{color:rgba(255,255,255,.74);font-size:var(--t-15);line-height:1.6}

.v-overlay-actions{display:flex;gap:.8em;flex-wrap:wrap;justify-content:center;margin-top:.4em}

.v-overlay-close{position:absolute;top:calc(clamp(12px,1.2vw,20px) + 1.2 * var(--ux));right:calc(clamp(12px,1.2vw,20px) + 1.2 * var(--ux));width:2.3em;height:2.3em;
  border-radius:50%;background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.3);color:#fff;
  display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .2s var(--ease)}

.v-overlay-close:hover{background:rgba(255,255,255,.2)}

/* the overlay's outline "Sign in" button (_player.php, guest only) — only .btn-o's base
   look lived under body[data-page="video"], so on every other page it fell back to .btn's
   default dark-glass fill instead of this transparent/white-outline look. */
.btn-o{background:transparent;color:#fff;border-color:rgba(255,255,255,.4);justify-content:center;gap:0}

.btn-o:hover{background:rgba(255,255,255,.1)}


/* ===== page: post ===== */

body[data-page="post"] .chip[aria-pressed="true"]{background:rgba(255,198,41,.9);border-color:rgba(120,88,0,.4)}

body[data-page="post"] .chip-b[aria-pressed="true"]{background:rgba(0,80,239,.92)}

body[data-page="post"] .chip-g[aria-pressed="true"],body[data-page="post"] .chip-w[aria-pressed="true"]{background:rgba(28,32,26,.16);color:var(--deep);border-color:rgba(28,32,26,.3)}

body[data-page="post"] .btn-y:hover{background:#ffcd3d}


/* ---------- box definition ---------- */
body[data-page="post"] .panel,body[data-page="post"] .btn,body[data-page="post"] .chip,.post-card,.post-row{position:relative}

body[data-page="post"] .panel::after,body[data-page="post"] .btn::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--ring-in);mix-blend-mode:overlay}

.p-d::after,.p-b::after,body[data-page="post"] .btn::after{border-color:rgba(255,255,255,.30);mix-blend-mode:normal}

body[data-page="post"] .nrow ul a.active{opacity:1;border-bottom-color:var(--yellow)}


/* ============ HEADER ROW (merged row, same construction as library.html's current top) ============ */
.lib-row{display:flex;align-items:center;gap:calc(clamp(14px,1.8vw,30px) + 1.8 * var(--ux));flex-wrap:wrap}

.lib-h1{font-size:calc(clamp(22px,2vw,32px) + 2 * var(--ux));flex:0 0 auto}

.lib-row .lib-search{flex:1 1 260px;min-width:220px;width:auto;margin-bottom:0}

.lib-row .lib-count{flex:0 0 auto}


/* ============ BODY LAYOUT (rail conventions borrowed from library.html) ============ */
.blog-body-sec{padding-top:calc(clamp(20px,1.8vw,30px) + 1.8 * var(--ux));padding-bottom:calc(clamp(20px,2vw,32px) + 2 * var(--ux))}

body[data-page="post"] .lib-layout{grid-template-columns:var(--rail-w) 1fr}

.lib-layout>*{min-width:0}


/* ---- rail ---- */
.lib-rail::-webkit-scrollbar{width:8px}

.lib-rail::-webkit-scrollbar-thumb{background:var(--grey-2);border-radius:4px}

.lib-rail::-webkit-scrollbar-track{background:transparent}

body[data-page="post"] .lib-rail-inner{padding-top:calc(clamp(18px,1.6vw,28px) + 1.6 * var(--ux));padding-bottom:calc(clamp(20px,1.8vw,32px) + 1.8 * var(--ux));padding-right:6px}

body[data-page="post"] .lib-rail-label{margin:1.1em 0 .5em}

.lib-rail-label:first-child{margin-top:0}

.lib-divider{height:1px;background:var(--line);margin:.9em 0}

body[data-page="post"] .lib-search{flex:0 0 auto}

.lib-search svg{flex:0 0 auto;opacity:.6}

.lib-search input{border:0;outline:0;background:transparent;font:inherit;font-size:var(--t-145);color:var(--deep);
  width:100%;font-family:var(--sans)}

.lib-search input::placeholder{color:var(--muted)}

.lib-count{white-space:nowrap;flex:0 0 auto}

body[data-page="post"] .lib-type-pills{margin-top:.5em}

body[data-page="post"] .lib-clear{margin:.8em 0 0;font:inherit;font-size:var(--t-xs)}

.lib-clear:hover{color:var(--deep)}

.lib-clear[hidden]{display:none}


/* ---- results column ---- */
.lib-results{min-width:0}

.lib-viewtog{display:flex;gap:6px;flex:0 0 auto}

.viewbtn{width:2.6em;height:2.6em;display:flex;align-items:center;justify-content:center;border-radius:var(--r-chip);
  background:rgba(233,234,232,.55);border:1px solid rgba(28,32,26,.14);cursor:pointer;transition:background .2s var(--ease)}

.viewbtn svg{width:46%;height:46%}

.viewbtn svg path,.viewbtn svg rect{stroke:var(--deep)}

.viewbtn[aria-pressed="true"]{background:var(--yellow);border-color:rgba(120,88,0,.3)}


/* ============ POST GRID (view: grid) ============ */
.post-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:var(--gap)}

.post-card{display:block;min-width:0;transition:transform .35s var(--ease);animation:cardIn .3s var(--ease) both}

.post-card:hover{transform:translateY(-4px)}

@keyframes cardIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}


.post-thumb{position:relative;aspect-ratio:16/10;border-radius:calc(var(--r-chip) + 2px);overflow:hidden;
  background:var(--grey-1);border:1px solid var(--line)}

.post-thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}

.post-thumb img.is-portrait{object-position:50% 18%}

/* grid fallback: contained avatar on a quiet field — full-bleed faces repeat
   too hard at card scale; the small list thumbs keep the full-bleed crop */
.post-thumb.thumb-portrait{background:var(--grey-1)}

.post-thumb.thumb-portrait img{inset:auto;left:50%;top:50%;transform:translate(-50%,-50%);
  width:42%;height:auto;aspect-ratio:1;border-radius:999px;object-position:50% 30%;
  border:1px solid var(--ring)}

.post-badges{position:absolute;top:8px;left:8px;right:8px;display:flex;justify-content:space-between;
  align-items:flex-start;gap:6px;z-index:2}

.post-badge{display:inline-flex;align-items:center;gap:.35em;background:rgba(20,22,18,.7);
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  color:#fff;font-size:var(--t-xs);border-radius:6px;padding:.25em .55em;line-height:1.3;white-space:nowrap}

.post-badge-free{background:var(--yellow);color:var(--deep)}

.post-badge-film{position:absolute;bottom:8px;right:8px;z-index:2}

.post-body{padding-top:.8em;min-width:0}

.post-meta-row{display:flex;align-items:center;gap:.6em;flex-wrap:wrap;margin-bottom:.55em}

.post-kind{font-size:var(--t-xs);padding:.32em .68em}

.post-date{font-size:var(--t-xs);color:var(--muted);text-transform:uppercase;letter-spacing:.07em}

.post-title{font-family:var(--display);font-weight:400;font-size:var(--t-19);letter-spacing:-.01em;
  line-height:1.22;color:var(--deep);display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
  overflow:hidden;overflow-wrap:anywhere}

.post-excerpt{margin-top:.5em;font-size:var(--t-14);color:var(--deep-2);line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}

.post-tag{margin-top:.6em;font-size:var(--t-xs);color:var(--muted);overflow-wrap:anywhere}

.post-card mark,.post-row mark{background:rgba(255,191,0,.35);color:inherit;border-radius:2px;padding:0 1px}


/* ============ POST LIST (view: list, default) ============ */
.post-list{display:flex;flex-direction:column}

.post-row{display:flex;gap:var(--gap);align-items:flex-start;min-width:0;padding:calc(clamp(18px,1.6vw,26px) + 1.6 * var(--ux)) 0;
  border-bottom:1px solid var(--line);transition:background-color .2s var(--ease);
  animation:cardIn .3s var(--ease) both}

.post-row:first-child{padding-top:0}

.post-row:hover{background:rgba(255,255,255,.5)}

.post-row-thumb{flex:0 0 auto;width:var(--post-thumb-list);aspect-ratio:4/3;border-radius:calc(var(--r-chip) + 2px);
  overflow:hidden;background:var(--grey-1);border:1px solid var(--line)}

.post-row-thumb img{width:100%;height:100%;object-fit:cover;display:block}

.post-row-thumb img.is-portrait{object-position:50% 18%}

.post-row-body{flex:1 1 auto;min-width:0}

.post-row-title{font-family:var(--display);font-weight:400;font-size:var(--t-19);letter-spacing:-.01em;
  line-height:1.24;color:var(--deep);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;overflow-wrap:anywhere}

.post-row-meta{display:flex;align-items:center;gap:.55em;flex-wrap:wrap;margin-top:.4em}

.post-gate{font-size:var(--t-xs);padding:.32em .68em}

.post-gate svg{vertical-align:-1px;margin-right:.25em}

.post-film{display:inline-flex;align-items:center;gap:.35em;font-size:var(--t-xs);color:var(--muted)}

.post-row-excerpt{margin-top:.5em;font-size:var(--t-14);color:var(--deep-2);line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}


.post-more{display:flex;justify-content:center;margin-top:calc(clamp(30px,2.8vw,50px) + 2.8 * var(--ux))}

.post-empty{max-width:100%;margin:calc(clamp(20px,2vw,36px) + 2 * var(--ux)) auto 0;text-align:center;
  display:flex;flex-direction:column;align-items:center;gap:1em}

.post-empty .lede{max-width:32em;margin:0 auto}
@media (max-width:1080px) {

  body[data-page="post"] .lib-layout{grid-template-columns:1fr}

  body[data-page="post"] .lib-rail{max-height:none!important;overflow-y:visible}

  .lib-rail-inner{padding-top:0}
}
@media (max-width:640px) {

  .post-row{gap:14px}

  .post-row-thumb{width:calc(clamp(76px,22vw,96px) + 22 * var(--ux))}
}

/* browsers without backdrop-filter get a near-solid sheet instead of a see-through one */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  body[data-page="post"] .nrow ul{background:rgba(248,249,247,.97)}
}


/* ================= ARTICLE PAGE ================= */
/* the reading measure. it was a hard 920px with a GROWING --edge inside it, which
   is the same trap --page was in: the column of text got NARROWER as the screen got
   wider (808px of text at 1728, 650px at 4K). it now grows on --uw, but far more
   slowly than a layout container would — just enough to hold the line length at
   about 80 characters as the type scales up. */
.art-wrap{max-width:calc(920px + 78 * var(--uw));margin:0 auto;padding:0 var(--edge)}

.art-top-sec{padding:calc(clamp(26px,2.6vw,48px) + 2.6 * var(--ux)) 0 0}

.art-back{display:inline-flex;align-items:center;gap:.55em;font-size:var(--t-145);color:var(--deep-2);
  transition:color .25s}

.art-back:hover{color:var(--deep)}

.art-back svg{transition:transform .3s var(--ease)}

.art-back:hover svg{transform:translateX(-4px)}

.art-meta-row{display:flex;align-items:center;gap:.6em;flex-wrap:wrap;margin:calc(clamp(18px,1.8vw,30px) + 1.8 * var(--ux)) 0 .9em}

.art-title{font-size:calc(clamp(1.9rem,3.4vw,4.2rem) + 3.4 * var(--ux));line-height:1.05;letter-spacing:-.015em;overflow-wrap:anywhere}

.art-byline{display:flex;align-items:center;gap:.9em;margin-top:calc(clamp(14px,1.4vw,24px) + 1.4 * var(--ux))}

.art-byline img{width:calc(clamp(38px,2.9vw,46px) + 2.9 * var(--ux));height:calc(clamp(38px,2.9vw,46px) + 2.9 * var(--ux));border-radius:999px;object-fit:cover;
  object-position:50% 30%;border:1px solid var(--ring)}

.art-byline-name{font-size:var(--t-145);font-weight:500;color:var(--deep);line-height:1.3}

.art-byline-sub{font-size:var(--t-xs);color:var(--muted);margin-top:1px}


.art-body-sec{padding:calc(clamp(24px,2.4vw,44px) + 2.4 * var(--ux)) 0 0}

.art-panel{background:rgba(255,255,255,.66);padding:calc(clamp(24px,3.2vw,64px) + 3.2 * var(--ux))}

.art{font-size:var(--t-165);line-height:1.72;color:#3E4039}

.art>*+*{margin-top:1.05em}

.art p{overflow-wrap:anywhere}

.art strong,.art b{color:var(--deep);font-weight:600}

.art h2,.art h3,.art h4{font-family:var(--display);font-weight:400;color:var(--deep);letter-spacing:-.01em;
  line-height:1.15;margin-top:1.7em}

.art h2{font-size:var(--t-22)}
 .art h3{font-size:var(--t-19)}
 .art h4{font-size:var(--t-17)}

.art ul,.art ol{padding-left:1.35em}

.art li{margin:.35em 0}

.art li::marker{color:var(--muted)}

.art a{color:var(--blue);border-bottom:1px solid var(--blue-pale);padding-bottom:1px;transition:border-color .25s}

.art a:hover{border-color:var(--blue)}

.art blockquote{border-left:3px solid var(--yellow);padding:.2em 0 .2em 1.1em;color:var(--deep-2);font-style:italic}

.art img{width:100%;height:auto;border-radius:calc(var(--r-chip) + 3px);border:1px solid var(--line);
  background:var(--grey-1)}

/* WordPress alignment classes carried over from the imported body_html (WXR import —
   ~85 posts/pages, see T-SHARED-2's corpus count). The classic editor puts the class
   straight on <img>; the block editor (wp-block-image) puts it on the wrapping
   <figure> instead — both forms are covered below. Aligned images opt OUT of the
   width:100% full-column rule above so a small figure (often carrying a real WP
   `width` attribute, e.g. width="169" on the book cover) renders near its natural
   size with the surrounding text wrapping, the way the old WP theme showed it,
   instead of stretching to the full ~700px reading column. `is-resized` and
   `wp-image-NNN` ride along on the same element and need no rule of their own. */
.art img.alignleft,.art .alignleft img{float:left;margin:0 1.5em 1em 0;width:auto;max-width:min(45%,100%);height:auto;border-radius:calc(var(--r-chip) + 3px);border:1px solid var(--line);background:var(--grey-1)}
.art img.alignright,.art .alignright img{float:right;margin:0 0 1em 1.5em;width:auto;max-width:min(45%,100%);height:auto;border-radius:calc(var(--r-chip) + 3px);border:1px solid var(--line);background:var(--grey-1)}
.art img.aligncenter,.art .aligncenter img{display:block;margin:1.4em auto;width:auto;max-width:100%;height:auto}
.art img.alignnone,.art .alignnone img{display:inline-block;width:auto;max-width:100%;height:auto}

/* the WP `width`/`height` attributes on <img> size aligned images (see above); when an
   import strips them the float still needs a cap so it can't claim the whole column —
   45% mirrors the max-width already set, so this is a documented no-op unless a future
   import ever drops the attributes. */
.art img[class*="align"]:not([width]){max-width:45%}

.art figure.alignleft,.art figure.alignright,.art figure.aligncenter{margin-top:0;margin-bottom:0}

/* classic-editor `[caption]` shortcode markup (div.wp-caption + p.wp-caption-text) —
   none in the corpus today, kept defensively; figure/figcaption already appears (11
   wp-block-image posts, 1 with a real figcaption). */
.art .wp-caption{max-width:100%}

.art::after{content:"";display:block;clear:both}

.art h2,.art h3{clear:both}

.art figure{margin:calc(clamp(20px,2vw,34px) + 2 * var(--ux)) 0}

.art figure.vid{background:#101110;border-radius:calc(var(--r-chip) + 3px);overflow:hidden;
  border:1px solid rgba(28,32,26,.3)}

.art figure.vid video{display:block;width:100%;max-height:76vh;background:#101110}

.art figcaption,.art .wp-caption-text{font-size:var(--t-sm);color:var(--muted);line-height:1.55;margin-top:.7em}

.art hr{border:0;height:1px;background:var(--line);margin:2em 0}

/* the corpus marks its figure captions as plain paragraphs opening with
   "Figure n:" in bold — detected at render time and set as captions */
.art p.is-caption{font-size:var(--t-sm);color:var(--deep-2);line-height:1.6;
  margin-top:-.4em;padding:0 .2em}

.art p.is-caption strong{font-weight:600}


.art-tags{display:flex;align-items:baseline;gap:.6em .5em;flex-wrap:wrap;
  margin-top:calc(clamp(26px,2.6vw,44px) + 2.6 * var(--ux));padding-top:calc(clamp(18px,1.8vw,28px) + 1.8 * var(--ux));border-top:1px solid var(--line)}

.art-tags .tiny{letter-spacing:.14em;text-transform:uppercase;font-weight:600}

.art-tags .chip{cursor:default}


/* ---- the membership gate (gated posts) ---- */
.gate-excerpt{font-size:var(--t-165);line-height:1.72;color:#3E4039}

.gate-excerpt::after{content:" …"}

.gate{margin-top:calc(clamp(24px,2.4vw,40px) + 2.4 * var(--ux))}

.gate-head{display:flex;align-items:center;gap:1em;margin-bottom:1.1em}

.gate-lock{flex:0 0 auto;width:44px;height:44px;border-radius:999px;display:flex;align-items:center;justify-content:center;
  background:rgba(255,191,0,.16);border:1px solid rgba(255,191,0,.4)}

.gate h3{font-size:var(--t-19)}

.gate .lede{color:rgba(213,214,208,.92);max-width:44em}

.gate-products{list-style:none;margin:1.3em 0 0;display:flex;flex-direction:column;gap:.45em}

.gate-products li{display:flex;align-items:baseline;gap:.7em;font-size:var(--t-145);color:#ECEDE8}

.gate-products svg{flex:0 0 auto;transform:translateY(1px)}

.gate-act{display:flex;align-items:center;gap:1.4em;flex-wrap:wrap;margin-top:1.6em}

.gate-alt{font-size:var(--t-145);color:rgba(236,237,232,.75);text-decoration:underline;
  text-underline-offset:3px;transition:color .25s}

.gate-alt:hover{color:#fff}


/* ---- prev / next ---- */
.art-pn-sec{padding:calc(clamp(28px,2.8vw,52px) + 2.8 * var(--ux)) 0 0}

.art-pn{display:grid;grid-template-columns:1fr 1fr;gap:var(--gap)}

.pn-card{display:flex;flex-direction:column;gap:.55em;padding:calc(clamp(18px,1.8vw,30px) + 1.8 * var(--ux));
  transition:transform .3s var(--ease),background .3s var(--ease)}

.pn-card:hover{transform:translateY(-3px);background:rgba(255,255,255,.72)}

.pn-card.pn-next{text-align:right;align-items:flex-end}

.pn-label{display:inline-flex;align-items:center;gap:.55em;font-size:var(--t-xs);color:var(--muted);
  text-transform:uppercase;letter-spacing:.12em;font-weight:600}

.pn-title{font-family:var(--display);font-weight:400;font-size:var(--t-17);line-height:1.25;color:var(--deep);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}

/* nothing follows the strip when a post has no related articles, so it brings
   its own space before the footer instead of borrowing the related section's */
.art-pn-sec.art-pn-last{padding-bottom:calc(clamp(50px,5vw,96px) + 5 * var(--ux))}


/* ---- related ---- */
.art-rel-sec{padding:calc(clamp(44px,4.4vw,84px) + 4.4 * var(--ux)) 0 calc(clamp(50px,5vw,96px) + 5 * var(--ux))}

.rel-head{display:flex;align-items:baseline;justify-content:space-between;gap:1em;flex-wrap:wrap;
  margin-bottom:calc(clamp(20px,2vw,34px) + 2 * var(--ux))}

.rel-title{font-size:calc(clamp(1.45rem,1.9vw,2.3rem) + 1.9 * var(--ux))}

.rel-all{font-size:var(--t-145);color:var(--deep-2);text-decoration:underline;text-underline-offset:3px}

.rel-all:hover{color:var(--deep)}

.rel-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--gap)}
@media (max-width:900px) {
.rel-grid{grid-template-columns:1fr;max-width:520px}
}
@media (max-width:640px) {

  .art-panel{padding:calc(clamp(18px,5vw,26px) + 5 * var(--ux))}

  .art-pn{grid-template-columns:1fr}

  .pn-card.pn-next{text-align:left;align-items:flex-start}

  .pn-none{display:none}

  /* aligned images stop wrapping text at phone width — floats this narrow leave too
     little room for a readable line next to them, so they drop to centred, modest-size
     blocks instead (the old WP theme had no such behaviour at all). */
  .art img.alignleft,.art .alignleft img,
  .art img.alignright,.art .alignright img{float:none;display:block;margin:1em auto;max-width:70%}
}


/* ---- not-found / loading ---- */
.art-missing{text-align:center;display:flex;flex-direction:column;align-items:center;gap:1em}

.art-missing .lede{margin:0 auto}

/* ===== page: video ===== */

/* --play-lg (only video.html's own :root ever defined it) and .btn-o/.btn-o:hover
   (the overlay's outline "Sign in" button) hoisted to the shared player section below —
   render_player() puts .sau-player on every content page, not just this one (T-SHARED-1). */
body[data-page="video"] .btn-y:hover{background:#ffcd3d}


/* ---------- box definition ---------- */
body[data-page="video"] .panel,body[data-page="video"] .btn,body[data-page="video"] .chip{position:relative}

body[data-page="video"] .panel::after,body[data-page="video"] .btn::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--ring-in);mix-blend-mode:overlay}

.p-d::after,.p-b::after,body[data-page="video"] .btn::after{border-color:rgba(255,255,255,.30);mix-blend-mode:normal}

body[data-page="video"] .nrow ul a.active{opacity:1;border-bottom-color:var(--yellow)}


/* ============ v-card component (reused verbatim for the related row) ============ */
.v-card:hover{transform:translateY(-4px)}

body[data-page="video"] .v-thumb{border-radius:calc(var(--r-chip) + 2px)}

.v-still{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}

.v-cone{position:absolute;inset:0;width:100%;height:100%}

.v-cone path{fill:none;stroke:rgba(255,255,255,.30);stroke-width:1;vector-effect:non-scaling-stroke}

.v-cone path.v-cone-wash{fill:rgba(255,255,255,.045);stroke:none}

.v-badges{position:absolute;top:8px;left:8px;display:flex;flex-direction:column;align-items:flex-start;gap:6px;z-index:2}

body[data-page="video"] .v-badge{border-radius:6px}

.v-badge-new{background:var(--blue);color:#fff}

/* .v-dur's border-radius (6px, video.html's own value) folded into the shared base rule
   instead of overridden here — it was the only page-scoped divergence from the 7px the
   card component's shared .v-dur otherwise used everywhere else (T-SHARED-1). .v-play/
   .v-play-circle (the card hover-play icon) hoisted to the shared player section below —
   was duplicated verbatim here and in the library block. */

.v-body{padding-top:.8em}

.v-title{font-family:var(--sans);font-weight:500;font-size:var(--t-145);line-height:1.35;color:var(--deep);
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}

.v-meta{margin-top:.42em}


/* ============ breadcrumb + title block ============ */
.v-page-head{padding:calc(clamp(22px,2.2vw,36px) + 2.2 * var(--ux)) 0 calc(clamp(20px,2vw,32px) + 2 * var(--ux))}

.v-crumb{margin-top:calc(clamp(6px,.6vw,10px) + .6 * var(--ux))}

.v-crumb a{text-decoration:underline;text-underline-offset:3px;text-decoration-color:rgba(122,124,116,.4)}

.v-crumb a:hover{color:var(--deep)}

.v-crumb-sep{margin:0 .45em;color:var(--grey-2)}

.v-page-head h1{margin-top:calc(clamp(10px,1vw,16px) + 1 * var(--ux));max-width:22em}

.v-meta-row{display:flex;align-items:center;flex-wrap:wrap;gap:.85em;margin-top:calc(clamp(14px,1.3vw,22px) + 1.3 * var(--ux))}

.v-meta-row .v-badge{position:static}


/* ============ player ============ */
.v-player-sec{padding:calc(clamp(8px,.9vw,16px) + .9 * var(--ux)) 0 calc(clamp(30px,2.8vw,48px) + 2.8 * var(--ux))}

/* .v-frame is a page-specific SIZING WRAPPER only (the hero player's own border/radius/
   ring on top of .v-frame rv's reveal-on-scroll animation) — the box, poster-cover,
   play/lock button and gate overlay it wraps all now live on .sau-player itself, in the
   shared player section (T-SHARED-1), so render_player() looks right with or without this
   wrapper class (e.g. exercise.php's own .ex-frame wrapper, or no wrapper at all).
   `background-color`, not the `background` shorthand: the shorthand resets every other
   background sub-property (image/size/position/…) to its initial value, and now that
   .sau-player--locked's background-size:cover/background-position:50% 50% live in the
   shared block above (earlier in the cascade than this page block), a later same-
   specificity `background:` shorthand here would silently win and reset them back to
   auto/0% 0% — the locked poster stops covering the frame (T-SHARED-1 fix 1 follow-up). */
.v-frame{position:relative;aspect-ratio:16/9;border-radius:var(--r);overflow:hidden;background-color:#0A0A0B;
  border:1px solid rgba(255,255,255,.16)}

.v-frame::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid rgba(255,255,255,.30);z-index:5}

/* .sau-player itself (box/poster/button/overlay), .v-idle-btn and .v-overlay* (the gate)
   moved to the shared player section (T-SHARED-1) — see it for the T6-F3 history these
   comments used to carry. #frameBg/video#videoEl/.v-loadring/.v-unavail below are
   video.html-mock-only ids/classes with no real markup emitting them yet (real players use
   site.js's initPlayer()/video_post.php's and exercise.php's own inline scripts instead);
   left in place, unscoped, as before. */
#frameBg{position:absolute;inset:0;cursor:pointer}

.v-unavail{position:absolute;left:50%;bottom:calc(clamp(18px,2vw,28px) + 2 * var(--ux));transform:translateX(-50%);
  color:rgba(255,255,255,.78);background:rgba(10,10,11,.6);border-radius:var(--r-chip);padding:.5em 1em;z-index:2}

.v-unavail[hidden]{display:none}

video#videoEl{position:absolute;inset:0;width:100%;height:100%;background:#000;z-index:4}

video#videoEl[hidden]{display:none}


/* buffering feedback: a thin rotating arc over the frame while the stream spins up —
   without it, the seconds between click and first frame read as a dead click */
.v-loadring{position:absolute;left:50%;top:50%;width:var(--play-lg);height:var(--play-lg);
  margin:calc(var(--play-lg) / -2) 0 0 calc(var(--play-lg) / -2);border-radius:50%;z-index:5;pointer-events:none;
  border:2px solid rgba(255,255,255,.22);border-top-color:rgba(255,255,255,.85);
  animation:vspin .9s linear infinite}

.v-loadring[hidden]{display:none}

@keyframes vspin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce) {

  .v-loadring{animation:none;border-color:rgba(255,255,255,.5)}
}


.v-frame-foot{display:flex;align-items:center;gap:var(--gap);margin-top:calc(clamp(14px,1.3vw,22px) + 1.3 * var(--ux))}

.v-nav-btn{display:inline-flex;align-items:center;gap:.55em;font-size:var(--t-14);color:var(--deep-2);
  transition:color .2s var(--ease);max-width:34%;flex:0 1 auto;min-width:0}

.v-nav-btn svg{flex:0 0 auto}

.v-nav-btn span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}

.v-nav-btn:hover{color:var(--deep)}

.v-nav-btn[hidden]{visibility:hidden}

.v-count{flex:1 1 auto;text-align:right;order:1}

.v-nav-btn.v-prev{order:0}

.v-nav-btn.v-next{order:2}


/* ============ about + facts ============ */
.v-about-sec{padding:calc(clamp(40px,4vw,76px) + 4 * var(--ux)) 0;border-top:1px solid var(--line)}

.v-about-grid{display:grid;grid-template-columns:1.4fr 1fr;gap:var(--gap);align-items:start}

.v-about-l h3{margin-bottom:.7em}

.v-about-l p{margin-top:.9em;max-width:44em;color:var(--deep-2)}

.v-about-l p:first-of-type{margin-top:0}

/* the annotated / narrated note reads as an aside to the case text, not part of it */
.v-about-l p.v-modality{margin-top:1.3em;padding-top:1.1em;border-top:1px solid var(--line);
  color:var(--muted);font-size:.94em}

.v-facts h3{margin-bottom:.7em}

.v-fact-row{display:flex;justify-content:space-between;gap:1em;padding:.75em 0;border-top:1px solid var(--line)}

.v-fact-row:first-of-type{border-top:0}

.v-fact-l{color:var(--muted)}

.v-fact-r{text-align:right;font-weight:500;line-height:1.4}


/* ============ related ============ */
.v-related-sec{padding:0 0 calc(clamp(50px,5vw,96px) + 5 * var(--ux))}

.v-related-head{display:flex;align-items:baseline;gap:.7em;margin-bottom:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux))}

.v-related-head .tiny{flex:1 1 auto;text-align:right}


/* ============ CTA band (reused pattern) ============ */
body[data-page="video"] .lib-cta-sec{padding:0 0 calc(clamp(50px,5vw,96px) + 5 * var(--ux))}

.lib-cta{text-align:center;display:flex;flex-direction:column;align-items:center;gap:.9em}

.lib-cta h3{font-family:var(--display);font-weight:400;font-size:calc(clamp(32px,2.222vw,44px) + 2.222 * var(--ux));letter-spacing:-.01em}

.lib-cta p{max-width:34em;font-size:var(--t-15)}

body[data-page="video"] .foot-sec::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  background:
    radial-gradient(58% 90% at 3% -12%,rgba(255,255,255,.20),rgba(255,255,255,0) 48%),
    radial-gradient(42% 85% at 100% -8%,rgba(255,191,0,.15),rgba(255,191,0,0) 56%),
    radial-gradient(40% 95% at 99% 122%,rgba(0,80,239,.15),rgba(0,80,239,0) 60%);
  mix-blend-mode:screen}
@media (max-width:1080px) {

  .v-about-grid{grid-template-columns:1fr}
}
@media (max-width:640px) {

  /* T16-F1: .v-count (the "Video N of M · <Section>" middle label) has no width cap
     and a long real section name (e.g. "Getting Started with Ultrasound", vs the mock's
     one-word "Spleen") can out-grow .v-prev/.v-next entirely — .v-nav-btn's automatic flex
     min-size already collapses to ~0 via its span's overflow:hidden, so without an explicit
     floor here the next/prev title shrinks past the point text-overflow:ellipsis has room
     to draw its own "…" and renders as one bare, unreadable letter ("D" for "Doppler") with
     no truncation indicator at all. A min-width keeps enough room for the ellipsis to show. */
  .v-nav-btn{max-width:38%;min-width:5.5em}

  .v-related-sec .v-grid{display:flex;gap:var(--gap);overflow-x:auto;padding-bottom:6px;scroll-snap-type:x mandatory;
    -webkit-mask-image:linear-gradient(90deg,transparent,#000 14px,#000 calc(100% - 14px),transparent);
    mask-image:linear-gradient(90deg,transparent,#000 14px,#000 calc(100% - 14px),transparent)}

  .v-related-sec .v-grid .v-card{flex:0 0 68%;scroll-snap-align:start}
}


/* inline free-signup in the gate overlay */
.ov-form{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;width:100%}

.ov-email{flex:1 1 14em;max-width:20em;padding:.85em 1em;font:inherit;font-size:var(--t-145);color:#fff;
  background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.34);border-radius:var(--r-chip)}

.ov-email::placeholder{color:rgba(255,255,255,.55)}

.ov-login-link{margin-top:8px;background:none;border:0;color:rgba(255,255,255,.75);font:inherit;
  font-size:var(--t-xs);border-bottom:1px solid rgba(255,255,255,.3);padding:0 0 1px;cursor:pointer}

.ov-login-link:hover{color:#fff}

.lfield{display:block;width:100%;margin-top:calc(clamp(12px,1vw,16px) + 1 * var(--ux));padding:.85em 1em;font:inherit;
  font-size:var(--t-145);color:var(--deep);background:rgba(255,255,255,.72);
  border:1px solid var(--ring);border-radius:var(--r-chip)}

.lfield::placeholder{color:var(--muted)}

#lmOk h3{margin-bottom:.4em}

#lmOk p{font-size:var(--t-145);color:var(--deep-2)}

#lmOk[hidden]{display:none}

#lmBody[hidden]{display:none}

/* browsers without backdrop-filter get a near-solid sheet instead of a see-through one */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  body[data-page="video"] .nrow ul{background:rgba(248,249,247,.97)}
}

/* ===== page: library ===== */

/* DEVIATION from T4-F3's "copy verbatim" instruction, flagged for review:
   --r-card and --ink are used in library.html's own <style> block (.lib-sug,
   .v-snip, .row-snip) but were NEVER defined there either -- this predates
   the site.css merge and is a pre-existing bug in the standalone mockup, not
   something the consolidation dropped. No mockup source value exists to copy.
   Aliased to the nearest same-purpose token already defined on this page
   (--r, the general card/panel radius; --deep, the page's near-black text
   colour) rather than inventing a new value. */
body[data-page="library"]{--r-card:var(--r);--ink:var(--deep)}

body[data-page="library"] .btn-y:hover{background:#ffcd3d}


/* ---------- box definition ---------- */
body[data-page="library"] .panel,body[data-page="library"] .btn,body[data-page="library"] .chip{position:relative}

body[data-page="library"] .panel::after,body[data-page="library"] .btn::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--ring-in);mix-blend-mode:overlay}

.p-d::after,.p-b::after,body[data-page="library"] .btn::after{border-color:rgba(255,255,255,.30);mix-blend-mode:normal}

body[data-page="library"] .nrow ul a.active{opacity:1;border-bottom-color:var(--yellow)}


/* ---------- plate: shared thumb treatment (rail / section head / list rows) ---------- */
.lib-thumb{width:var(--rail-thumb);height:var(--rail-thumb);border-radius:8px;border:1px solid var(--line);
  background:#E9EBE8;overflow:hidden;flex:0 0 auto;display:flex;align-items:center;justify-content:center;
  transition:transform .25s var(--ease),border-color .25s var(--ease)}

.lib-thumb.lg{width:var(--row-thumb);height:var(--row-thumb)}

.lib-thumb.contain{padding:calc(clamp(4px,.278vw,6px) + .278 * var(--ux))}

.lib-thumb.contain img{max-width:100%;max-height:100%;width:auto;object-fit:contain;mix-blend-mode:multiply}

.lib-thumb.cover img{width:100%;height:100%;object-fit:cover}

.lib-thumb.no-img svg{width:58%;height:58%;opacity:.5}

.lib-thumb.no-img svg path,.lib-thumb.no-img svg line{stroke:var(--deep-2)}

/* list rows carry the video's own still in a small dark frame */
.row-still{flex:0 0 auto;width:calc(clamp(84px,5.84vw,118px) + 5.84 * var(--ux));aspect-ratio:16/10;border-radius:6px;
  background:#0A0A0B;border:1px solid var(--line);overflow:hidden;display:flex;align-items:center;justify-content:center}

.row-still img{width:100%;height:100%;object-fit:cover;display:block}

.row-still.no-g svg{width:46%;height:46%;opacity:.55}

.row-still.no-g svg path{stroke:rgba(255,255,255,.6);fill:none}


/* ============ PAGE HEADER ============ */
.lib-head{padding:calc(clamp(44px,5vw,96px) + 5 * var(--ux)) 0 calc(clamp(22px,2.2vw,40px) + 2.2 * var(--ux))}

.lib-head .chip{margin-bottom:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux))}

.lib-head h1{margin-top:calc(clamp(10px,1vw,18px) + 1 * var(--ux))}

.lib-head .lede{margin-top:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux))}

.lib-head .tiny{margin-top:calc(clamp(14px,1.2vw,20px) + 1.2 * var(--ux))}


/* ============ TOOLBAR ============ */
.lib-toolbar{position:sticky;z-index:45;background:rgba(250,251,250,.5);
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  border-top:1px solid var(--ring);border-bottom:1px solid var(--ring)}

.lib-toolbar-in{display:flex;align-items:center;justify-content:space-between;gap:var(--gap);padding-top:var(--pad-sm);padding-bottom:var(--pad-sm);flex-wrap:wrap}

.lib-search svg{flex:0 0 auto;opacity:.6}

.lib-search input{border:0;outline:0;background:transparent;font:inherit;font-size:var(--t-145);color:var(--deep);
  width:100%;font-family:var(--sans)}

.lib-search input::placeholder{color:var(--muted)}


/* ---- suggestions ---- */
.lib-sug{position:absolute;left:0;right:0;top:calc(100% + 6px);z-index:60;margin:0;padding:.35em;
  list-style:none;background:rgba(252,253,252,.985);border:1px solid var(--ring);
  border-radius:var(--r-card);-webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  box-shadow:0 22px 50px -20px rgba(20,26,24,.5);max-height:48vh;overflow-y:auto}

.lib-sug[hidden]{display:none}

.lib-sug li{padding:.62em .8em;border-radius:calc(var(--r-card) - 5px);cursor:pointer;
  font-size:var(--t-13);color:var(--deep);line-height:1.3;min-height:44px;display:flex;align-items:center}

.lib-sug li.on,.lib-sug li:hover{background:rgba(252,192,60,.24)}


/* ---- description / transcript snippet on a result ---- */
.v-secline{color:var(--muted);margin:.15em 0 .3em}

.v-snip{color:var(--ink);opacity:.86;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;line-height:1.45}

.v-snip mark,.row-snip mark{background:rgba(252,192,60,.4);color:inherit;padding:0 .12em;border-radius:3px}

.row-main{display:flex;flex-direction:column;gap:.15em;min-width:0;flex:1 1 auto}

.row-sec{color:var(--muted)}

.row-snip{color:var(--ink);opacity:.82;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}


/* ---- ranked (flat) results ---- */
.v-grid-flat{margin-top:var(--pad-sm)}


/* ---- zero-result rescue ---- */
.lib-rescue{margin:0 0 var(--pad-sm)}

.lib-rescue h3{margin:0 0 .3em}

.lib-rescue .dym{border:0;background:transparent;font:inherit;color:var(--deep);cursor:pointer;
  border-bottom:2px solid rgba(252,192,60,.85);padding:0 .05em}

.lib-rescue .dym:hover{background:rgba(252,192,60,.24)}

.lib-rescue-note{color:var(--muted)}


.lib-count{white-space:nowrap;flex:0 0 auto}

.lib-viewtog{display:flex;gap:6px;flex:0 0 auto}

.viewbtn{width:2.6em;height:2.6em;display:flex;align-items:center;justify-content:center;border-radius:var(--r-chip);
  background:rgba(233,234,232,.55);border:1px solid rgba(28,32,26,.14);cursor:pointer;transition:background .2s var(--ease)}

.viewbtn svg{width:46%;height:46%}

.viewbtn svg path,.viewbtn svg rect{stroke:var(--deep)}

.viewbtn[aria-pressed="true"]{background:var(--yellow);border-color:rgba(120,88,0,.3)}


/* ============ BODY LAYOUT ============ */
.lib-body-sec{padding-top:calc(clamp(16px,1.6vw,26px) + 1.6 * var(--ux));padding-bottom:calc(clamp(40px,4vw,80px) + 4 * var(--ux))}

/* min-width:0 so a long nowrap snippet in list view cannot blow out the track */
.lib-results{min-width:0}


/* ---- rail ---- */
.lib-rail::-webkit-scrollbar{width:8px}

.lib-rail::-webkit-scrollbar-thumb{background:var(--grey-2);border-radius:4px}

.lib-rail::-webkit-scrollbar-track{background:transparent}

.lib-group-label{text-transform:uppercase;letter-spacing:.16em;font-weight:600;margin:1em 0 .35em;color:var(--muted)}

.lib-sec-list{display:flex;flex-direction:column}

.lib-sec-row{display:flex;align-items:center;gap:.7em;padding:.45em .5em;border-radius:var(--r-chip);
  border:1px solid transparent;background:transparent;text-align:left;cursor:pointer;width:100%;
  font:inherit;color:inherit;transition:background-color .2s var(--ease),border-color .2s var(--ease)}

.lib-sec-row:hover{background:rgba(233,234,232,.5)}

.lib-sec-row.all{font-weight:600;font-size:var(--t-14)}

.lib-sec-name{flex:1 1 auto;font-size:var(--t-14);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.lib-sec-count{flex:0 0 auto}

/* Library page: a wider rail, and section names wrap instead of ending in "…" — the authors
   asked to read the whole name (review, 2026-10-16). Phones keep the stacked layout below. */
@media (min-width:1081px){
  body[data-page="library"] .lib-layout{grid-template-columns:calc(clamp(330px,22.9vw,380px) + 22.9 * var(--ux)) minmax(0,1fr)}
  body[data-page="library"] .lib-sec-name{white-space:normal;overflow:visible;text-overflow:clip;line-height:1.3}
}

.lib-sec-row[aria-pressed="true"]{background:rgba(255,198,41,.78);border-color:rgba(120,88,0,.24)}

.lib-divider{height:1px;background:var(--line);margin:.9em 0}

.lib-check-row{display:flex;align-items:center;gap:.65em;font-size:var(--t-14);cursor:pointer;padding:.4em .5em}

.lib-check-row input{position:absolute;opacity:0;width:1px;height:1px}

.lib-checkbox{width:1.1em;height:1.1em;border-radius:2px;border:1px solid var(--ring);flex:0 0 auto;
  position:relative;background:rgba(255,255,255,.5)}

.lib-check-row input:checked + .lib-checkbox{background:var(--yellow);border-color:rgba(120,88,0,.4)}

.lib-check-row input:checked + .lib-checkbox::after{content:"";position:absolute;left:.28em;top:.06em;
  width:.32em;height:.58em;border:solid var(--deep);border-width:0 2px 2px 0;transform:rotate(40deg)}

.lib-check-row input:focus-visible + .lib-checkbox{outline:2px solid var(--deep);outline-offset:2px}

.lib-type-pills .chip[aria-pressed="true"]{background:rgba(255,198,41,.78);border-color:rgba(120,88,0,.24);color:var(--deep)}

.lib-clear:hover{color:var(--deep)}

.lib-clear[hidden]{display:none}


/* ---- results ---- */
.lib-sec-head{display:flex;align-items:center;gap:.9em;margin-top:calc(clamp(30px,2.6vw,52px) + 2.6 * var(--ux))}

.lib-sec-head:first-child{margin-top:0}

.lib-sec-head h3{white-space:nowrap;flex:0 0 auto;font-family:var(--display);font-weight:400;
  font-size:calc(clamp(19px,1.46vw,25px) + 1.46 * var(--ux));letter-spacing:-.01em}

.lib-sec-head .tiny{white-space:nowrap;flex:0 0 auto}

.lib-sec-rule{flex:1 1 auto;height:1px;background:var(--line)}


.v-card:hover{transform:translateY(-4px)}

.v-card:nth-child(2){animation-delay:20ms}
.v-card:nth-child(3){animation-delay:40ms}

.v-card:nth-child(4){animation-delay:60ms}
.v-card:nth-child(5){animation-delay:80ms}

.v-card:nth-child(6){animation-delay:100ms}
.v-card:nth-child(7){animation-delay:120ms}

.v-card:nth-child(8){animation-delay:140ms}
.v-card:nth-child(n+9){animation-delay:150ms}

@keyframes cardIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}


/* the frame treatment every image on the site carries: outer hairline + a
   soft inner light ring */
.v-thumb::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:3;
  border:1px solid rgba(255,255,255,.12)}

.v-card:hover .v-thumb{border-color:rgba(120,88,0,.42)}

.v-still{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}

.v-cone{position:absolute;inset:0;width:100%;height:100%}

.v-cone path{fill:none;stroke:rgba(255,255,255,.30);stroke-width:1;vector-effect:non-scaling-stroke}

.v-cone path.v-cone-wash{fill:rgba(255,255,255,.045);stroke:none}

.v-badges{position:absolute;top:8px;left:8px;display:flex;flex-direction:column;align-items:flex-start;gap:6px;z-index:2}

.v-badge-new{background:var(--blue);color:#fff}

/* .v-play/.v-play-circle: shared player section above (T-SHARED-1) — was an exact
   duplicate of the video block's copy of the same two rules. */

.v-body{padding-top:.8em}

.v-title{font-family:var(--sans);font-weight:500;font-size:var(--t-145);line-height:1.35;color:var(--deep);
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}

.v-meta{margin-top:.42em}

/* "Your videos" (2026-08-24): the locked-card "In {product}" chip — same quiet tone as
   .chip-g (a muted grey pill), sized down to caption scale so it reads as metadata, not
   another filter control. */
.v-unlock{display:inline-block;margin-top:.4em;font-size:var(--t-xs);color:var(--muted);
  background:rgba(233,234,232,.55);border:1px solid rgba(28,32,26,.14);border-radius:var(--r-chip);
  padding:.2em .65em}

html.dk .v-unlock{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.16);color:#C7C9C4}

.v-card mark,.v-row mark{background:rgba(255,191,0,.35);color:inherit;border-radius:2px;padding:0 1px}


.v-list{margin-top:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux))}

.v-row{display:flex;align-items:center;gap:var(--gap);padding:.8em 0;border-top:1px solid var(--line);
  transition:background-color .2s var(--ease);animation:cardIn .25s var(--ease) both}

.v-row:hover{background:rgba(255,255,255,.5)}

.row-title{flex:1 1 auto;font-family:var(--sans);font-weight:500;font-size:var(--t-145);color:var(--deep);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.row-main>.row-title{flex:0 0 auto;width:100%}

.row-badges{display:flex;gap:6px;flex:0 0 auto}

.row-dur{flex:0 0 auto;min-width:3.4em;text-align:right;color:var(--muted)}

.row-chev{flex:0 0 auto;opacity:.5}


.lib-empty{max-width:var(--page-n);margin:calc(clamp(30px,3vw,60px) + 3 * var(--ux)) auto 0;text-align:center;
  display:flex;flex-direction:column;align-items:center;gap:1em}

.lib-empty .lede{max-width:32em;margin:0 auto}


/* ============ CTA BAND ============ */
.lib-cta{text-align:center;display:flex;flex-direction:column;align-items:center;gap:.9em}

.lib-cta h3{font-family:var(--display);font-weight:400;font-size:calc(clamp(32px,2.222vw,44px) + 2.222 * var(--ux));letter-spacing:-.01em}

.lib-cta p{max-width:34em;font-size:var(--t-15)}

@media (max-width:1080px) {

  .lib-layout>*{min-width:0}

  .lib-rail-inner{padding-top:0}

  .lib-sec-list{flex-direction:row;overflow-x:auto;gap:8px;padding:2px 2px 10px;
    scrollbar-width:none;-ms-overflow-style:none;
    -webkit-mask-image:linear-gradient(90deg,transparent,#000 24px,#000 calc(100% - 24px),transparent);
    mask-image:linear-gradient(90deg,transparent,#000 24px,#000 calc(100% - 24px),transparent)}

  .lib-sec-list::-webkit-scrollbar{display:none}

  .lib-sec-row{flex:0 0 auto;width:auto;border-radius:999px;padding:.5em .9em .5em .5em}

  .lib-sec-row.all{padding:.5em .9em}

  .lib-sec-name{white-space:nowrap}

  .lib-sec-count{margin-left:.2em}

  .lib-group-label{flex:0 0 auto;display:flex;align-items:center;white-space:nowrap;margin:0 2px}

  .lib-divider{display:none}

  .lib-sec-head h3{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis}

  .lib-sec-rule{flex:0 0 18px}

  /* library.html's own mobile rail hides its rail-section labels ("Sections",
     "Show only", "Type" — mock line 430); blog.html never hides its own
     ("Content type"/"Access"/"Body system" — no such rule in that mock at all),
     so this rule must not leak onto body[data-page="blog"] via the shared
     .lib-rail-inner/.lib-rail-label class names (T14 fixlet 2). */
  body[data-page="library"] .lib-rail-inner>.lib-rail-label{display:none}

  .lib-toggles{display:flex;flex-wrap:wrap;align-items:center;gap:4px 22px;margin-top:6px}

  .lib-toggles .lib-rail-label{width:100%;margin:.3em 0 0}
}
@media (max-width:640px) {

  .lib-toolbar-in{gap:12px}
}

.lfield{display:block;width:100%;margin-top:calc(clamp(12px,1vw,16px) + 1 * var(--ux));padding:.85em 1em;font:inherit;
  font-size:var(--t-145);color:var(--deep);background:rgba(255,255,255,.72);
  border:1px solid var(--ring);border-radius:var(--r-chip)}

.lfield::placeholder{color:var(--muted)}

#lmOk h3{margin-bottom:.4em}

#lmOk p{font-size:var(--t-145);color:var(--deep-2)}

#lmOk[hidden]{display:none}

#lmBody[hidden]{display:none}

/* browsers without backdrop-filter get a near-solid sheet instead of a see-through one */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  body[data-page="library"] .nrow ul{background:rgba(248,249,247,.97)}
}


/* ============ HEADER ROW (chosen layout C) ============ */
.lib-row{display:flex;align-items:center;gap:calc(clamp(14px,1.8vw,30px) + 1.8 * var(--ux));flex-wrap:wrap}

.lib-h1{font-size:calc(clamp(22px,2vw,32px) + 2 * var(--ux));flex:0 0 auto}

.lib-row .lib-search{flex:1 1 260px;min-width:220px;width:auto;margin-bottom:0}

.lib-row .lib-count{flex:0 0 auto}

/* ===== page: blog ===== */

body[data-page="blog"] .chip[aria-pressed="true"]{background:rgba(255,198,41,.9);border-color:rgba(120,88,0,.4)}

body[data-page="blog"] .chip-b[aria-pressed="true"]{background:rgba(0,80,239,.92)}

body[data-page="blog"] .chip-g[aria-pressed="true"],body[data-page="blog"] .chip-w[aria-pressed="true"]{background:rgba(28,32,26,.16);color:var(--deep);border-color:rgba(28,32,26,.3)}

body[data-page="blog"] .btn-y:hover{background:#ffcd3d}


/* ---------- box definition ---------- */
body[data-page="blog"] .panel,body[data-page="blog"] .btn,body[data-page="blog"] .chip,.post-card,.post-row{position:relative}

body[data-page="blog"] .panel::after,body[data-page="blog"] .btn::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--ring-in);mix-blend-mode:overlay}

.p-d::after,.p-b::after,body[data-page="blog"] .btn::after{border-color:rgba(255,255,255,.30);mix-blend-mode:normal}

body[data-page="blog"] .nrow ul a.active{opacity:1;border-bottom-color:var(--yellow)}


/* ============ HEADER ROW (merged row, same construction as library.html's current top) ============ */
.lib-row{display:flex;align-items:center;gap:calc(clamp(14px,1.8vw,30px) + 1.8 * var(--ux));flex-wrap:wrap}

.lib-h1{font-size:calc(clamp(22px,2vw,32px) + 2 * var(--ux));flex:0 0 auto}

/* T10-F1: this toolbar search (`.lib-row .lib-search`, the search box in the header row) is
   the ONLY .lib-search on /blog/ — unlike post.php/library.html, blog's rail has no search
   field of its own. There must be no `body[data-page="blog"] .lib-search{flex:0 0 auto}`
   rail-search override here (post.php has one, at site.css:1805, for its own rail search):
   that selector's [data-page] attribute outranks this plain `.lib-row .lib-search`
   (0,2,1 vs 0,2,0), so it silently overrode this rule's flex:1 1 260px on the ONLY search
   box blog has, collapsing the toolbar search to its ~240px intrinsic width regardless of
   width:auto (placeholder truncated). Removed; do not re-add it for blog. */
.lib-row .lib-search{flex:1 1 260px;min-width:220px;width:auto;margin-bottom:0}

.lib-row .lib-count{flex:0 0 auto}


/* ============ BODY LAYOUT (rail conventions borrowed from library.html) ============ */
.blog-body-sec{padding-top:calc(clamp(20px,1.8vw,30px) + 1.8 * var(--ux));padding-bottom:calc(clamp(20px,2vw,32px) + 2 * var(--ux))}

body[data-page="blog"] .lib-layout{grid-template-columns:var(--rail-w) 1fr}

.lib-layout>*{min-width:0}


/* ---- rail ---- */
.lib-rail::-webkit-scrollbar{width:8px}

.lib-rail::-webkit-scrollbar-thumb{background:var(--grey-2);border-radius:4px}

.lib-rail::-webkit-scrollbar-track{background:transparent}

/* T10-F1: the shared .lib-rail above (site.css:1699-1702) carries library.html's glass-panel
   treatment (background/border/backdrop-filter) — blog.html's own .lib-rail (blog.html:
   197-201) never declared any of those three properties, i.e. a plain, unboxed rail with no
   inner scrollbar chrome (its overflow-y:auto only ever engages via #rail's JS-set
   max-height, same mechanism as library.html, but with nothing to visually box it in).
   Reset them here so blog stays plain while library.html (which depends on the shared
   values) is untouched. */
body[data-page="blog"] .lib-rail{background:none;border:0;border-radius:0;
  -webkit-backdrop-filter:none;backdrop-filter:none}

/* blog.html:202-203's .lib-rail-inner sets only padding-top/-bottom/-right — no left/right
   base padding the way the shared rule (site.css:1704-1705, a 3-value shorthand) does, so
   the chips sit flush with the rail's left edge instead of inset inside the (now-removed)
   panel. */
body[data-page="blog"] .lib-rail-inner{padding-top:calc(clamp(18px,1.6vw,28px) + 1.6 * var(--ux));padding-bottom:calc(clamp(20px,1.8vw,32px) + 1.8 * var(--ux));padding-right:6px;padding-left:0}

body[data-page="blog"] .lib-rail-label{margin:1.1em 0 .5em}

.lib-rail-label:first-child{margin-top:0}

.lib-divider{height:1px;background:var(--line);margin:.9em 0}

.lib-search svg{flex:0 0 auto;opacity:.6}

.lib-search input{border:0;outline:0;background:transparent;font:inherit;font-size:var(--t-145);color:var(--deep);
  width:100%;font-family:var(--sans)}

.lib-search input::placeholder{color:var(--muted)}

.lib-count{white-space:nowrap;flex:0 0 auto}

body[data-page="blog"] .lib-type-pills{margin-top:.5em}

body[data-page="blog"] .lib-clear{margin:.8em 0 0;font:inherit;font-size:var(--t-xs)}

.lib-clear:hover{color:var(--deep)}

.lib-clear[hidden]{display:none}


/* ---- results column ---- */
.lib-results{min-width:0}

.lib-viewtog{display:flex;gap:6px;flex:0 0 auto}

.viewbtn{width:2.6em;height:2.6em;display:flex;align-items:center;justify-content:center;border-radius:var(--r-chip);
  background:rgba(233,234,232,.55);border:1px solid rgba(28,32,26,.14);cursor:pointer;transition:background .2s var(--ease)}

.viewbtn svg{width:46%;height:46%}

.viewbtn svg path,.viewbtn svg rect{stroke:var(--deep)}

.viewbtn[aria-pressed="true"]{background:var(--yellow);border-color:rgba(120,88,0,.3)}


/* ============ POST GRID (view: grid) ============ */
.post-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:var(--gap)}

.post-card{display:block;min-width:0;transition:transform .35s var(--ease);animation:cardIn .3s var(--ease) both}

.post-card:hover{transform:translateY(-4px)}

@keyframes cardIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}


.post-thumb{position:relative;aspect-ratio:16/10;border-radius:calc(var(--r-chip) + 2px);overflow:hidden;
  background:var(--grey-1);border:1px solid var(--line)}

.post-thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}

.post-thumb img.is-portrait{object-position:50% 18%}

/* grid fallback: contained avatar on a quiet field — full-bleed faces repeat
   too hard at card scale; the small list thumbs keep the full-bleed crop */
.post-thumb.thumb-portrait{background:var(--grey-1)}

.post-thumb.thumb-portrait img{inset:auto;left:50%;top:50%;transform:translate(-50%,-50%);
  width:42%;height:auto;aspect-ratio:1;border-radius:999px;object-position:50% 30%;
  border:1px solid var(--ring)}

.post-badges{position:absolute;top:8px;left:8px;right:8px;display:flex;justify-content:space-between;
  align-items:flex-start;gap:6px;z-index:2}

.post-badge{display:inline-flex;align-items:center;gap:.35em;background:rgba(20,22,18,.7);
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  color:#fff;font-size:var(--t-xs);border-radius:6px;padding:.25em .55em;line-height:1.3;white-space:nowrap}

.post-badge-free{background:var(--yellow);color:var(--deep)}

.post-badge-film{position:absolute;bottom:8px;right:8px;z-index:2}

.post-body{padding-top:.8em;min-width:0}

.post-meta-row{display:flex;align-items:center;gap:.6em;flex-wrap:wrap;margin-bottom:.55em}

.post-kind{font-size:var(--t-xs);padding:.32em .68em}

.post-date{font-size:var(--t-xs);color:var(--muted);text-transform:uppercase;letter-spacing:.07em}

.post-title{font-family:var(--display);font-weight:400;font-size:var(--t-19);letter-spacing:-.01em;
  line-height:1.22;color:var(--deep);display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
  overflow:hidden;overflow-wrap:anywhere}

.post-excerpt{margin-top:.5em;font-size:var(--t-14);color:var(--deep-2);line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}

.post-tag{margin-top:.6em;font-size:var(--t-xs);color:var(--muted);overflow-wrap:anywhere}

.post-card mark,.post-row mark{background:rgba(255,191,0,.35);color:inherit;border-radius:2px;padding:0 1px}


/* ============ POST LIST (view: list, default) ============ */
.post-list{display:flex;flex-direction:column}

.post-row{display:flex;gap:var(--gap);align-items:flex-start;min-width:0;padding:calc(clamp(18px,1.6vw,26px) + 1.6 * var(--ux)) 0;
  border-bottom:1px solid var(--line);transition:background-color .2s var(--ease);
  animation:cardIn .3s var(--ease) both}

.post-row:first-child{padding-top:0}

.post-row:hover{background:rgba(255,255,255,.5)}

.post-row-thumb{flex:0 0 auto;width:var(--post-thumb-list);aspect-ratio:4/3;border-radius:calc(var(--r-chip) + 2px);
  overflow:hidden;background:var(--grey-1);border:1px solid var(--line)}

.post-row-thumb img{width:100%;height:100%;object-fit:cover;display:block}

.post-row-thumb img.is-portrait{object-position:50% 18%}

.post-row-body{flex:1 1 auto;min-width:0}

.post-row-title{font-family:var(--display);font-weight:400;font-size:var(--t-19);letter-spacing:-.01em;
  line-height:1.24;color:var(--deep);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;overflow-wrap:anywhere}

.post-row-meta{display:flex;align-items:center;gap:.55em;flex-wrap:wrap;margin-top:.4em}

.post-gate{font-size:var(--t-xs);padding:.32em .68em}

.post-gate svg{vertical-align:-1px;margin-right:.25em}

.post-film{display:inline-flex;align-items:center;gap:.35em;font-size:var(--t-xs);color:var(--muted)}

.post-row-excerpt{margin-top:.5em;font-size:var(--t-14);color:var(--deep-2);line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}


.post-more{display:flex;justify-content:center;margin-top:calc(clamp(30px,2.8vw,50px) + 2.8 * var(--ux))}

.post-empty{max-width:100%;margin:calc(clamp(20px,2vw,36px) + 2 * var(--ux)) auto 0;text-align:center;
  display:flex;flex-direction:column;align-items:center;gap:1em}

.post-empty .lede{max-width:32em;margin:0 auto}
@media (max-width:1080px) {

  body[data-page="blog"] .lib-layout{grid-template-columns:1fr}

  body[data-page="blog"] .lib-rail{max-height:none!important;overflow-y:visible}

  .lib-rail-inner{padding-top:0}
}
@media (max-width:640px) {

  .post-row{gap:14px}

  .post-row-thumb{width:calc(clamp(76px,22vw,96px) + 22 * var(--ux))}
}

/* browsers without backdrop-filter get a near-solid sheet instead of a see-through one */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  body[data-page="blog"] .nrow ul{background:rgba(248,249,247,.97)}
}

/* ===== page: time-to-play ===== */

body[data-page="time-to-play"] .btn-y:hover{background:#ffcd3d}


/* ---------- box definition ---------- */
body[data-page="time-to-play"] .panel,body[data-page="time-to-play"] .btn,body[data-page="time-to-play"] .chip{position:relative}

body[data-page="time-to-play"] .panel::after,body[data-page="time-to-play"] .btn::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--ring-in);mix-blend-mode:overlay}

.p-d::after,.p-b::after,body[data-page="time-to-play"] .btn::after{border-color:rgba(255,255,255,.30);mix-blend-mode:normal}

body[data-page="time-to-play"] .nrow ul a.active{opacity:1;border-bottom-color:var(--yellow)}

/* T14 fixlet 1: time-to-play.html has exactly one .lib-search (the archive toolbar's,
   inside .ttp-tools, already flex:1 1 260px below) and no flex:0 0 auto override of its
   own anywhere in the mock — this stray rule (same pattern as post.php's/exercise.php's
   own SIDEBAR search override, wrongly copied here) pinned it to its content width
   (~241px) instead of filling the toolbar row. Removed rather than rescoped: there is
   no other .lib-search on this page for it to apply to. */

.lib-search svg{flex:0 0 auto;opacity:.6}

.lib-search input{border:0;outline:0;background:transparent;font:inherit;font-size:var(--t-145);color:var(--deep);
  width:100%;font-family:var(--sans)}

.lib-search input::placeholder{color:var(--muted)}

.lib-count{white-space:nowrap;flex:0 0 auto}

.lfield{display:block;width:100%;margin-top:calc(clamp(12px,1vw,16px) + 1 * var(--ux));padding:.85em 1em;font:inherit;
  font-size:var(--t-145);color:var(--deep);background:rgba(255,255,255,.72);
  border:1px solid var(--ring);border-radius:var(--r-chip)}

.lfield::placeholder{color:var(--muted)}

#lmOk h3{margin-bottom:.4em}

#lmOk p{font-size:var(--t-145);color:var(--deep-2)}

#lmOk[hidden]{display:none}

#lmBody[hidden]{display:none}

/* browsers without backdrop-filter get a near-solid sheet instead of a see-through one */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  body[data-page="time-to-play"] .nrow ul{background:rgba(248,249,247,.97)}
}


/* ============================================================
   TIME TO PLAY
   The exercises are questions, so the question IS the tile: set
   in the display face at reading size, with the exercise number
   as its index marker. No imagery is available for the archive
   (only 2 of 40 posts carry a picture), so type does the work.
   ============================================================ */

/* ---------- head ---------- */
.ttp-head{padding:calc(clamp(40px,4.4vw,86px) + 4.4 * var(--ux)) 0 calc(clamp(24px,2.2vw,42px) + 2.2 * var(--ux))}

.ttp-head h1{max-width:14em}

.ttp-head .lede{margin-top:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux));max-width:44em}

.ttp-head .tiny{margin-top:calc(clamp(12px,1vw,18px) + 1 * var(--ux))}


/* ---------- the latest exercise ---------- */
.ttp-now-sec{padding:0 0 calc(clamp(40px,4vw,84px) + 4 * var(--ux))}

.ttp-now{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.08fr);
  gap:calc(clamp(22px,2.4vw,52px) + 2.4 * var(--ux));align-items:center}

.ttp-eyebrow{display:flex;align-items:center;gap:.85em;margin-bottom:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux))}

.ttp-eyebrow .tiny{text-transform:uppercase;letter-spacing:.16em;font-weight:600;color:var(--deep-2);white-space:nowrap}

.ttp-eyebrow .ttp-rule{flex:1 1 auto;height:1px;background:var(--line)}

/* the number sits above the question as its index, the way a plate is
   numbered in the atlas */
.ttp-now-num{font-family:var(--display);font-weight:400;line-height:1;letter-spacing:-.02em;
  font-size:calc(clamp(30px,2.64vw,46px) + 2.64 * var(--ux));color:var(--yellow)}

.ttp-now-q{font-family:var(--display);font-weight:400;letter-spacing:-.015em;line-height:1.02;
  font-size:calc(clamp(1.9rem,3.05vw,4rem) + 3.05 * var(--ux));margin-top:.12em;max-width:11em}

.ttp-now-meta{margin-top:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux))}

.ttp-now p{margin-top:calc(clamp(12px,1vw,18px) + 1 * var(--ux));color:var(--deep-2);max-width:38em}

.ttp-now .btn{margin-top:calc(clamp(20px,1.8vw,32px) + 1.8 * var(--ux))}

.ttp-now-media{position:relative;border-radius:var(--r);overflow:hidden;background:#0A0A0B;
  border:1px solid var(--line);aspect-ratio:16/10}

.ttp-now-media::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid rgba(255,255,255,.12)}

.ttp-now-media img{width:100%;height:100%;object-fit:cover}

.ttp-now-play{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;z-index:2}

.ttp-play-circle{width:calc(clamp(52px,4.2vw,74px) + 4.2 * var(--ux));height:calc(clamp(52px,4.2vw,74px) + 4.2 * var(--ux));border-radius:50%;
  background:rgba(255,255,255,.18);border:1px solid rgba(255,255,255,.5);
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  display:flex;align-items:center;justify-content:center;
  transition:background .3s var(--ease),transform .3s var(--ease)}

.ttp-now-media:hover .ttp-play-circle{background:rgba(255,255,255,.3);transform:scale(1.06)}


/* ---------- the archive ---------- */
.ttp-arch-sec{padding:0 0 calc(clamp(30px,3vw,60px) + 3 * var(--ux))}

.ttp-arch-head{padding-top:calc(clamp(26px,2.6vw,50px) + 2.6 * var(--ux));border-top:1px solid var(--line)}

.ttp-arch-head h2{font-family:var(--display);font-weight:400;letter-spacing:-.01em;line-height:1.04;
  font-size:calc(clamp(1.75rem,2.5vw,3.1rem) + 2.5 * var(--ux))}

.ttp-arch-head .lede{margin-top:calc(clamp(12px,1vw,18px) + 1 * var(--ux))}

.ttp-tools{display:flex;align-items:center;gap:calc(clamp(12px,1.5vw,26px) + 1.5 * var(--ux));flex-wrap:wrap;
  margin-top:calc(clamp(20px,1.8vw,34px) + 1.8 * var(--ux))}

.ttp-tools .lib-search{flex:1 1 260px;min-width:220px;width:auto;margin-bottom:0}

.ttp-tools .tiny{flex:0 0 auto;white-space:nowrap}

.ttp-sort{display:flex;gap:6px;flex:0 0 auto}

.ttp-sort .chip{cursor:pointer}

.ttp-sort .chip[aria-pressed="false"]{background:rgba(233,234,232,.55);border-color:rgba(28,32,26,.14)}


.ttp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(calc(clamp(232px,16.5vw,278px) + 16.5 * var(--ux)),1fr));
  gap:var(--gap);margin-top:calc(clamp(20px,1.8vw,34px) + 1.8 * var(--ux))}

/* Each card is grounded in a frame from its own case clip, so the card is dark and
   the type sits over the scan. No backdrop-filter here any more: an opaque image
   covers the card, so blurring what is behind it is 39 surfaces of wasted work. */
.ttp-card{--cardpad:calc(clamp(17px,1.25vw,24px) + 1.25 * var(--ux));
  position:relative;display:flex;flex-direction:column;overflow:hidden;
  min-height:calc(clamp(184px,13.2vw,214px) + 13.2 * var(--ux));border-radius:var(--r);
  padding:var(--cardpad);
  background:#0E0F0D;border:1px solid rgba(255,255,255,.17);
  transition:transform .35s var(--ease),border-color .35s var(--ease);
  animation:cardIn .25s var(--ease) both}

.ttp-card::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid rgba(255,255,255,.13);z-index:2}

.ttp-card:hover{transform:translateY(-4px);border-color:rgba(255,191,0,.55)}

@keyframes cardIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

.ttp-card-top{display:flex;align-items:flex-start;justify-content:space-between;gap:.8em}

/* on the card the body is transparent to the flex column; on phones it becomes
   the middle cell of a row */
.ttp-card-body{display:contents}

.ttp-num{font-family:var(--display);font-weight:400;line-height:1;letter-spacing:-.02em;
  font-size:calc(clamp(24px,1.94vw,34px) + 1.94 * var(--ux));color:var(--yellow)}

.ttp-lock{flex:0 0 auto;opacity:.42;transition:opacity .3s var(--ease)}

.ttp-card:hover .ttp-lock{opacity:.75}

.ttp-lock svg path,.ttp-lock svg rect{stroke:var(--deep)}

.ttp-q{font-family:var(--display);font-weight:400;letter-spacing:-.01em;line-height:1.14;
  font-size:calc(clamp(18px,1.32vw,23px) + 1.32 * var(--ux));color:var(--deep);margin-top:.5em;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}

.ttp-meta{margin-top:auto;padding-top:1em}

.ttp-card mark{background:rgba(255,191,0,.42);color:#0E0F0D;border-radius:2px;padding:0 1px}

.ttp-free{background:var(--yellow);color:var(--deep);border-color:rgba(120,88,0,.28)}


/* ---------- the case frame behind each card ----------
   Always the QUESTION clip. The answer posters carry Penninck's own captions
   ("Ureterocele"), so they can never appear on an index page. */
.ttp-thumb{position:absolute;inset:0;border-radius:inherit;overflow:hidden;z-index:0;background:#0A0A0B}

.ttp-thumb img{width:100%;height:100%;object-fit:cover;display:block}

/* the number and question sit at the TOP of the card, so the scrim is heaviest
   there and clears through the lower middle — a bottom-up gradient (the video
   poster reflex) would darken exactly the part with nothing written on it */
.ttp-thumb::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(10,10,11,.88) 0%,rgba(10,10,11,.80) 34%,
    rgba(10,10,11,.34) 62%,rgba(10,10,11,.72) 100%)}

.ttp-thumb .tcone{position:absolute;inset:0;width:100%;height:100%}

.ttp-thumb .tcone path{fill:none;stroke:rgba(255,255,255,.32);stroke-width:1;vector-effect:non-scaling-stroke}

.ttp-thumb .tcone path.w{fill:rgba(255,255,255,.05);stroke:none}

/* exercises 1 and 2 were published as stills with no clip — the cone is all they get */
.ttp-card.has-img .tcone{display:none}


/* Stack the CHILDREN, not the wrapper: at ≤640px .ttp-card-top becomes
   display:contents, which discards its position and z-index — and the exercise
   number then paints underneath the frame and disappears. */
.ttp-card-top,.ttp-q,.ttp-meta,.ttp-num,.ttp-lock,.ttp-card .chip{position:relative;z-index:1}

.ttp-q{color:#F4F5F2}

.ttp-meta{color:rgba(244,245,242,.70)}

.ttp-lock{opacity:.85}

.ttp-lock svg path,.ttp-lock svg rect{stroke:#fff}


.ttp-empty{margin:calc(clamp(30px,3vw,60px) + 3 * var(--ux)) 0 0;text-align:center;
  display:flex;flex-direction:column;align-items:center;gap:1em}

.ttp-empty .lede{max-width:32em;margin:0 auto}

.ttp-empty[hidden]{display:none}


/* ---------- closing CTA ---------- */
.ttp-cta-sec{padding:0 0 calc(clamp(20px,2vw,36px) + 2 * var(--ux))}

.ttp-cta{text-align:center;display:flex;flex-direction:column;align-items:center;gap:.9em}

.ttp-cta h3{font-family:var(--display);font-weight:400;font-size:calc(clamp(30px,2.15vw,42px) + 2.15 * var(--ux));letter-spacing:-.01em}

.ttp-cta p{max-width:36em;font-size:var(--t-15)}

.ttp-cta .btn{margin-top:.4em}
@media (max-width:1080px) {

  .ttp-now{grid-template-columns:1fr;gap:calc(clamp(20px,3vw,34px) + 3 * var(--ux))}

  .ttp-now-media{order:-1}
}
@media (max-width:640px) {

  .ttp-head{padding-top:calc(clamp(28px,7vw,44px) + 7 * var(--ux))}

  .ttp-now-q{font-size:calc(clamp(1.75rem,8.4vw,2.5rem) + 8.4 * var(--ux))}

  .ttp-eyebrow{flex-wrap:wrap;row-gap:.7em}

  .ttp-eyebrow .chip{white-space:nowrap}

  
  .ttp-grid{grid-template-columns:1fr;gap:8px;margin-top:14px}

  
  .ttp-card{flex-direction:row;align-items:center;gap:14px;min-height:0;
    padding:15px 14px;border-radius:12px}

  .ttp-card::after{display:none}

  .ttp-card:hover{transform:none;border-color:rgba(255,255,255,.17)}

  
  .ttp-card-top{display:contents}

  .ttp-num{order:1;flex:0 0 auto;min-width:1.5em;font-size:23px}

  .ttp-card-body{display:block;order:2;flex:1 1 auto;min-width:0}

  .ttp-lock{order:3;flex:0 0 auto}

  .ttp-card .chip{order:3;flex:0 0 auto}

  .ttp-q{font-size:16.5px;margin-top:0;-webkit-line-clamp:2}

  .ttp-meta{margin-top:.3em;padding-top:0}

  .ttp-tools{gap:10px}
}

/* ===== page: exercise ===== */

body[data-page="exercise"] .btn-y:hover{background:#ffcd3d}


/* ---------- box definition ---------- */
body[data-page="exercise"] .panel,body[data-page="exercise"] .btn,body[data-page="exercise"] .chip{position:relative}

body[data-page="exercise"] .panel::after,body[data-page="exercise"] .btn::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--ring-in);mix-blend-mode:overlay}

.p-d::after,.p-b::after,body[data-page="exercise"] .btn::after{border-color:rgba(255,255,255,.30);mix-blend-mode:normal}

body[data-page="exercise"] .nrow ul a.active{opacity:1;border-bottom-color:var(--yellow)}

body[data-page="exercise"] .lib-search{flex:0 0 auto}

.lib-search svg{flex:0 0 auto;opacity:.6}

.lib-search input{border:0;outline:0;background:transparent;font:inherit;font-size:var(--t-145);color:var(--deep);
  width:100%;font-family:var(--sans)}

.lib-search input::placeholder{color:var(--muted)}

.lib-count{white-space:nowrap;flex:0 0 auto}

.lfield{display:block;width:100%;margin-top:calc(clamp(12px,1vw,16px) + 1 * var(--ux));padding:.85em 1em;font:inherit;
  font-size:var(--t-145);color:var(--deep);background:rgba(255,255,255,.72);
  border:1px solid var(--ring);border-radius:var(--r-chip)}

.lfield::placeholder{color:var(--muted)}

#lmOk h3{margin-bottom:.4em}

#lmOk p{font-size:var(--t-145);color:var(--deep-2)}

#lmOk[hidden]{display:none}

#lmBody[hidden]{display:none}

/* browsers without backdrop-filter get a near-solid sheet instead of a see-through one */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  body[data-page="exercise"] .nrow ul{background:rgba(248,249,247,.97)}
}


/* ============================================================
   ONE EXERCISE — three acts: the case, your answer, the answer.
   The middle act is the point: you commit to a reading before the
   worked answer opens, and your committed choice stays pinned at
   the top of the reveal so you read the explanation against it.
   ============================================================ */

.ex-wrap{padding:calc(clamp(26px,2.6vw,46px) + 2.6 * var(--ux)) 0 0}


/* ---------- breadcrumb + head ---------- */
.ex-crumb{display:flex;align-items:center;gap:.55em;flex-wrap:wrap;color:var(--muted);font-size:var(--t-xs)}

.ex-crumb a{border-bottom:1px solid transparent;transition:border-color .25s}

.ex-crumb a:hover{border-bottom-color:var(--grey-2)}

.ex-crumb-sep{opacity:.5}


.ex-head{margin-top:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux))}

.ex-num{font-family:var(--display);font-weight:400;line-height:1;letter-spacing:-.02em;
  font-size:calc(clamp(30px,2.64vw,46px) + 2.64 * var(--ux));color:var(--yellow)}

.ex-title{font-family:var(--display);font-weight:400;letter-spacing:-.015em;line-height:1.02;
  font-size:calc(clamp(1.9rem,3.05vw,4rem) + 3.05 * var(--ux));margin-top:.1em;max-width:15em}

.ex-meta{display:flex;align-items:center;gap:.7em;flex-wrap:wrap;margin-top:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux))}


/* ---------- step rail: a real sequence, so it is numbered ---------- */
.ex-steps{display:flex;align-items:stretch;gap:0;margin-top:calc(clamp(22px,2vw,38px) + 2 * var(--ux));
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}

.ex-step{flex:1 1 0;display:flex;align-items:center;gap:.7em;padding:calc(clamp(12px,1vw,17px) + 1 * var(--ux)) 0;
  border-left:1px solid var(--line);padding-left:calc(clamp(12px,1.1vw,20px) + 1.1 * var(--ux));
  color:var(--muted);font-size:var(--t-14);background:none;border-top:0;border-right:0;border-bottom:0;
  font-family:inherit;text-align:left;cursor:pointer;transition:color .3s var(--ease)}

.ex-step:first-child{border-left:0;padding-left:0}

/* display:flex above would otherwise defeat the hidden attribute — the rail drops
   to two steps on the exercises that carry no multiple choice */
.ex-step[hidden]{display:none}

.ex-step:hover{color:var(--deep-2)}

.ex-step-n{flex:0 0 auto;width:1.85em;height:1.85em;border-radius:50%;display:flex;align-items:center;
  justify-content:center;border:1px solid var(--ring);font-size:var(--t-xs);
  transition:background-color .3s var(--ease),border-color .3s var(--ease),color .3s var(--ease)}

.ex-step[data-state="now"]{color:var(--deep)}

.ex-step[data-state="now"] .ex-step-n{background:var(--yellow);border-color:rgba(120,88,0,.3);color:var(--deep);font-weight:600}

.ex-step[data-state="done"]{color:var(--deep-2)}

.ex-step[data-state="done"] .ex-step-n{background:rgba(255,191,0,.22);border-color:rgba(120,88,0,.24);color:var(--deep)}


/* ---------- act sections ---------- */
.ex-act{padding:calc(clamp(30px,3vw,60px) + 3 * var(--ux)) 0 0}

.ex-act-head{display:flex;align-items:baseline;gap:.85em;margin-bottom:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux))}

.ex-act-head .tiny{text-transform:uppercase;letter-spacing:.16em;font-weight:600;color:var(--deep-2);white-space:nowrap}

.ex-act-rule{flex:1 1 auto;height:1px;background:var(--line)}

.ex-prose p{margin-top:.9em;color:var(--deep-2);max-width:46em}

.ex-prose p:first-child{margin-top:0}

/* still images inside an exercise's text (migration 046, ttp_figures()) */
.ex-figs{display:grid;gap:var(--t-12,12px);margin:1.4em 0;max-width:62em;grid-template-columns:1fr}
.ex-figs[data-n="2"],.ex-figs[data-n="3"]{grid-template-columns:repeat(auto-fit,minmax(min(100%,18em),1fr))}
.ex-prose .ex-figs:first-child{margin-top:0}
.ex-fig{margin:0}
.ex-fig a{display:block;border-radius:var(--r);overflow:hidden;background:#0A0A0B;border:1px solid var(--line)}
.ex-fig img{display:block;width:100%;height:auto;max-height:70vh;object-fit:contain}
.ex-figs[data-n="1"] .ex-fig img{width:auto;max-width:100%;margin:0 auto}
.ex-figs[data-n="1"] .ex-fig a{display:inline-block;max-width:100%}
.ex-fig figcaption{margin-top:.5em;font-size:.88em;color:var(--deep-2)}
.ex-fig a:focus-visible{outline:2px solid var(--gold,#FCC03C);outline-offset:3px}


/* ---------- player ---------- */
/* .ex-frame is render_player()'s wrapper class on this page (same role as the video page's
   .v-frame) — `background-color`, not `background`, for the same cascade-order reason
   documented on .v-frame (T-SHARED-1 fix 1 follow-up). */
.ex-frame{position:relative;border-radius:var(--r);overflow:hidden;background-color:#0A0A0B;
  border:1px solid var(--line);aspect-ratio:16/9}

.ex-frame::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:4;
  border:1px solid rgba(255,255,255,.12)}

.ex-frame video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:#0A0A0B;z-index:2}

.ex-frame video[hidden]{display:none}

/* a real frame lifted from the clip itself, so no two exercises look alike.
   object-fit matches the video's, so the swap to playback does not reframe. */
.ex-still{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;z-index:1}

.ex-still[hidden]{display:none}

/* just enough scrim for the play control to read over a bright scan */
.ex-scrim{position:absolute;inset:0;z-index:2;pointer-events:none;
  background:radial-gradient(ellipse at center,rgba(10,10,11,.42) 0%,rgba(10,10,11,.14) 55%,rgba(10,10,11,.3) 100%)}

.ex-scrim[hidden]{display:none}

.ex-cone{position:absolute;inset:0;width:100%;height:100%}

.ex-cone path{fill:none;stroke:rgba(255,255,255,.30);stroke-width:1;vector-effect:non-scaling-stroke}

.ex-cone path.ex-cone-wash{fill:rgba(255,255,255,.045);stroke:none}

.ex-idle{position:absolute;inset:0;z-index:3;display:flex;align-items:center;justify-content:center;
  background:none;border:0;cursor:pointer;color:#fff}

.ex-idle[hidden]{display:none}

.ex-idle-circle{width:calc(clamp(52px,4.2vw,74px) + 4.2 * var(--ux));height:calc(clamp(52px,4.2vw,74px) + 4.2 * var(--ux));border-radius:50%;
  background:rgba(255,255,255,.18);border:1px solid rgba(255,255,255,.5);
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  display:flex;align-items:center;justify-content:center;
  transition:background .3s var(--ease),transform .3s var(--ease)}

.ex-idle:hover .ex-idle-circle{background:rgba(255,255,255,.3);transform:scale(1.06)}

.ex-nomedia{position:absolute;inset:0;z-index:3;display:flex;align-items:center;justify-content:center;
  text-align:center;padding:var(--pad);color:rgba(255,255,255,.62);font-size:var(--t-14)}

/* display:flex on these would otherwise defeat the hidden attribute */
.ex-nomedia[hidden],.ex-yours[hidden],.ex-related[hidden],.ex-nav-btn[hidden]{display:none}

.ex-cap{margin-top:.8em}


/* ---------- act 2: the quiz ---------- */
.ex-quiz{border-radius:var(--r);padding:var(--pad);position:relative;
  background:rgba(250,251,250,.5);border:1px solid var(--ring);
  -webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm)}

.ex-quiz::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--ring-in);mix-blend-mode:overlay}

.ex-stem{font-family:var(--display);font-weight:400;letter-spacing:-.01em;line-height:1.14;
  font-size:calc(clamp(20px,1.6vw,28px) + 1.6 * var(--ux));color:var(--deep);max-width:22em}

.ex-opts{display:flex;flex-direction:column;gap:10px;margin-top:calc(clamp(18px,1.6vw,30px) + 1.6 * var(--ux))}

.ex-opt{display:flex;align-items:flex-start;gap:.85em;width:100%;text-align:left;cursor:pointer;
  font:inherit;font-size:var(--t-145);color:var(--deep);
  padding:calc(clamp(13px,1.05vw,18px) + 1.05 * var(--ux)) calc(clamp(14px,1.1vw,20px) + 1.1 * var(--ux));
  background:rgba(255,255,255,.55);border:1px solid var(--ring);border-radius:var(--r-chip);
  transition:background-color .25s var(--ease),border-color .25s var(--ease),transform .25s var(--ease)}

.ex-opt:hover:not(:disabled){background:rgba(255,255,255,.9);transform:translateX(2px)}

.ex-opt:disabled{cursor:default}

.ex-opt-k{flex:0 0 auto;width:1.7em;height:1.7em;border-radius:50%;display:flex;align-items:center;
  justify-content:center;border:1px solid var(--ring);background:rgba(255,255,255,.7);
  font-size:var(--t-xs);font-weight:600;line-height:1;
  transition:background-color .25s var(--ease),border-color .25s var(--ease)}

.ex-opt-t{flex:1 1 auto;line-height:1.4}

.ex-opt-w{display:block;margin-top:.4em;font-size:var(--t-xs);color:var(--muted);line-height:1.5}

.ex-opt[aria-pressed="true"]{background:rgba(255,255,255,.95);border-color:rgba(120,88,0,.5)}

.ex-opt[aria-pressed="true"] .ex-opt-k{background:var(--yellow);border-color:rgba(120,88,0,.4)}

/* after committing: correct in brand gold, your wrong pick in the cover's red */
.ex-opt.is-right{background:rgba(255,191,0,.16);border-color:rgba(120,88,0,.45)}

.ex-opt.is-right .ex-opt-k{background:var(--yellow);border-color:rgba(120,88,0,.4)}

.ex-opt.is-wrong{background:rgba(183,54,72,.09);border-color:rgba(183,54,72,.42)}

.ex-opt.is-wrong .ex-opt-k{background:var(--pink);border-color:rgba(183,54,72,.5);color:#fff}

.ex-opt.is-muted{opacity:.72}

.ex-opt-tag{flex:0 0 auto;font-size:var(--t-xs);color:var(--muted);white-space:nowrap;padding-top:.15em}


.ex-quiz-foot{display:flex;align-items:center;gap:1.1em;flex-wrap:wrap;margin-top:calc(clamp(18px,1.6vw,28px) + 1.6 * var(--ux))}

/* the open-state "you answered / reveal date" note in site.js's renderQuiz()
   gets its own layout rather than reusing .ex-open (built for #openHere's
   single-button case): two stacked rows — the committed-choice line, then a
   second row pairing the .tiny reveal note with "Clear my answer"
   (right-aligned via space-between). The compound selector outranks the plain
   .ex-quiz-foot{display:flex} above regardless of source order (specificity). */
.ex-quiz-foot.ex-quiz-foot--open{display:flex;flex-direction:column;align-items:stretch;gap:.5em}

.ex-open-ans{margin:0}

.ex-open-foot{display:flex;align-items:center;justify-content:space-between;gap:1em;flex-wrap:wrap}

.ex-check:disabled{opacity:.42;cursor:not-allowed;transform:none}

.ex-skip{background:none;border:0;font:inherit;font-size:var(--t-14);color:var(--deep-2);cursor:pointer;
  text-decoration:underline;text-underline-offset:3px;padding:0}

.ex-skip:hover{color:var(--deep)}

.ex-verdict{display:flex;align-items:center;gap:.6em;font-size:var(--t-145);font-weight:500}

.ex-verdict.ok{color:#7A5A00}

.ex-verdict.no{color:var(--pink)}

/* the way through for an exercise with no multiple choice: no panel, no
   apology for the missing question — just the one thing there is to do */
.ex-open{display:flex;margin-top:calc(clamp(20px,1.8vw,32px) + 1.8 * var(--ux))}

.ex-open[hidden]{display:none}


/* ---------- act 3: the reveal ---------- */
.ex-reveal[hidden]{display:none}

.ex-yours{display:flex;align-items:flex-start;gap:.8em;flex-wrap:wrap;
  padding:calc(clamp(13px,1.05vw,18px) + 1.05 * var(--ux)) calc(clamp(14px,1.1vw,20px) + 1.1 * var(--ux));border-radius:var(--r-chip);
  background:rgba(233,234,232,.55);border:1px solid var(--ring);margin-bottom:calc(clamp(18px,1.6vw,28px) + 1.6 * var(--ux));
  font-size:var(--t-14)}

.ex-yours b{font-weight:600}

.ex-related{display:inline-flex;align-items:center;gap:.6em;margin-top:calc(clamp(16px,1.4vw,24px) + 1.4 * var(--ux));
  font-size:var(--t-145);border-bottom:1px solid var(--grey-2);padding-bottom:2px}

.ex-related:hover{border-bottom-color:var(--deep)}


/* ---------- comments ---------- */
.ex-comments{padding-top:calc(clamp(26px,2.4vw,44px) + 2.4 * var(--ux));margin-top:calc(clamp(30px,3vw,58px) + 3 * var(--ux));border-top:1px solid var(--line)}

.ex-comments h3{font-family:var(--display);font-weight:400;letter-spacing:-.01em;
  font-size:calc(clamp(20px,1.6vw,27px) + 1.6 * var(--ux))}

.ex-comments .lede{margin-top:.6em}

.ex-cbox{margin-top:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux));max-width:44em}

.ex-cbox textarea{width:100%;min-height:6.5em;resize:vertical;font:inherit;font-size:var(--t-145);
  color:var(--deep);background:rgba(255,255,255,.62);border:1px solid var(--ring);
  border-radius:var(--r-chip);padding:.9em 1.05em}

.ex-cbox textarea::placeholder{color:var(--muted)}

.ex-cbox-foot{display:flex;align-items:center;gap:1em;flex-wrap:wrap;margin-top:12px}

.ex-cempty{margin-top:calc(clamp(16px,1.4vw,24px) + 1.4 * var(--ux));font-size:var(--t-14);color:var(--muted)}

/* comment thread list + guest login line */
.ex-comments .ex-cthread{margin-top:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux));max-width:44em;
  display:flex;flex-direction:column;gap:calc(clamp(18px,1.6vw,26px) + 1.6 * var(--ux))}

.ex-comments .ex-citem{padding-bottom:calc(clamp(14px,1.2vw,20px) + 1.2 * var(--ux));
  border-bottom:1px solid var(--line)}

.ex-comments .ex-citem:last-child{border-bottom:0;padding-bottom:0}

.ex-comments .ex-cmeta{display:flex;align-items:baseline;gap:.6em;flex-wrap:wrap;font-size:var(--t-14)}

.ex-comments .ex-cmeta b{font-weight:600;color:var(--deep)}

.ex-comments .ex-cbody p{margin-top:.4em;color:var(--deep-2)}

.ex-comments .ex-cbody p:first-child{margin-top:.35em}

.ex-comments .ex-creplies{margin-top:calc(clamp(14px,1.2vw,20px) + 1.2 * var(--ux));
  margin-left:calc(clamp(18px,1.6vw,30px) + 1.6 * var(--ux));
  display:flex;flex-direction:column;gap:calc(clamp(14px,1.2vw,20px) + 1.2 * var(--ux))}

.ex-comments .ex-clogin{margin-top:calc(clamp(16px,1.4vw,24px) + 1.4 * var(--ux));
  font-size:var(--t-14);color:var(--deep-2)}

.ex-comments .ex-clogin a{color:var(--deep);border-bottom:1px solid var(--grey-2);padding-bottom:1px}

.ex-comments .ex-clogin a:hover{border-bottom-color:var(--deep)}

/* discussions (2026-09-11): what the shared partial adds to the .ex-comments layout */
.dq-author{display:inline-block;font-size:var(--t-xs);font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  color:var(--deep);background:var(--yellow);border-radius:var(--r-chip);padding:.1em .55em;vertical-align:middle}
.dq-pending{border-left:3px solid var(--yellow);padding-left:.9em}
.dq-status{margin-top:.5em;color:var(--muted)}
.dq-gone{font-weight:400;color:var(--muted);font-style:italic}
.dq-to{color:var(--muted)}
.dq-acts{display:flex;align-items:center;gap:1.1em;flex-wrap:wrap;margin-top:.55em;font-size:var(--t-14)}
.dq-acts form{display:inline;margin:0}
.dq-act{font:inherit;color:var(--deep-2);background:none;border:0;padding:.35em 0;cursor:pointer;
  border-bottom:1px solid var(--grey-2);min-height:44px;display:inline-flex;align-items:center}
.dq-act:hover,.dq-act[aria-expanded="true"]{color:var(--deep);border-bottom-color:var(--deep)}
.dq-label{display:block;margin-bottom:.45em;color:var(--deep-2)}
.dq-replying{margin-bottom:.6em;color:var(--deep-2)}
.dq-replying a,.dq-replying button{font:inherit;color:var(--deep);background:none;border:0;padding:0;cursor:pointer;border-bottom:1px solid var(--grey-2)}
.dq-hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.dq-note{color:var(--muted)}
.ex-citem .ex-cbox{margin-top:1em}
.dq:target{background:rgba(252,192,60,.10);border-radius:var(--r-chip);padding:.6em .8em;margin:0 -.8em}

/* ---------- gated state ----------
   A locked exercise renders in FULL — the case clip's poster frame, her question
   text, the stem and all four options. Only the acts-3 reveal is withheld. The
   lock is stated quietly (this bar + a padlock on the play control) and the offer
   itself is deferred to the gate dialog, which fires on the first blocked click. */
.ex-lockbar{display:flex;align-items:center;gap:.75em;flex-wrap:wrap;
  margin-top:calc(clamp(16px,1.4vw,24px) + 1.4 * var(--ux));padding:calc(clamp(11px,.95vw,15px) + .95 * var(--ux)) calc(clamp(13px,1.1vw,18px) + 1.1 * var(--ux));
  border:1px solid var(--ring);border-radius:var(--r-chip);background:rgba(255,191,0,.10);
  font-size:var(--t-14);color:var(--deep-2)}

.ex-lockbar[hidden]{display:none}

.ex-lockbar svg{flex:0 0 auto;color:var(--deep)}

/* padlock and sentence are ONE flex item, so the icon can never be stranded on a
   line of its own when the sentence wraps */
.ex-lockbar-msg{display:flex;align-items:flex-start;gap:.7em;flex:1 1 12em;min-width:0}

.ex-lockbar-msg svg{margin-top:.15em}

.ex-lockbar b{font-weight:600;color:var(--deep)}

.ex-lockbar a{color:var(--deep);border-bottom:1px solid var(--grey-2);padding-bottom:1px}

.ex-lockbar a:hover{border-bottom-color:var(--deep)}

.ex-lockbar-cta{margin-left:auto;font-size:var(--t-14);color:var(--deep);white-space:nowrap;
  border-bottom:1px solid var(--grey-2);padding-bottom:1px;background:none;border-top:0;border-left:0;
  border-right:0;font-family:inherit;cursor:pointer}

.ex-lockbar-cta:hover{border-bottom-color:var(--deep)}
@media (max-width:620px) {

  .ex-lockbar-msg{flex:1 1 100%}

  .ex-lockbar-cta{margin-left:0;margin-top:.55em}
}


/* ---------- prev / next ---------- */
.ex-nav{display:flex;align-items:stretch;gap:var(--gap);margin-top:calc(clamp(34px,3.2vw,64px) + 3.2 * var(--ux));
  padding-top:calc(clamp(20px,1.8vw,32px) + 1.8 * var(--ux));border-top:1px solid var(--line)}

.ex-nav-btn{flex:1 1 0;display:flex;flex-direction:column;gap:.3em;min-width:0;
  font-size:var(--t-14);color:var(--deep-2);transition:color .25s}

.ex-nav-btn:hover{color:var(--deep)}

.ex-nav-btn.next{text-align:right;align-items:flex-end}

.ex-nav-btn[hidden]{display:none}

.ex-nav-q{font-family:var(--display);font-size:var(--t-165);color:var(--deep);letter-spacing:-.01em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}


/* ---------- gate dialog ---------- */
.gmodal h3{padding-right:2.6em}

.gmodal-actions{display:flex;flex-direction:column;gap:10px;margin-top:calc(clamp(16px,1.4vw,24px) + 1.4 * var(--ux))}

.gmodal-actions .btn{width:100%;justify-content:center;margin-top:0}

.gmodal-actions .btn-o{background:rgba(255,255,255,.5);color:var(--deep);border-color:var(--ring)}

.gmodal-actions .btn-o:hover{background:rgba(255,255,255,.85)}

.gmodal p{font-size:var(--t-145);color:var(--deep-2);margin-top:.55em}

.gmodal-form{display:flex;gap:8px;margin-top:calc(clamp(14px,1.2vw,20px) + 1.2 * var(--ux))}

.gmodal-form .lfield{margin-top:0;flex:1 1 auto;min-width:0}

.gmodal-form .btn{margin-top:0;flex:0 0 auto;width:auto}

.gmodal-link{display:block;width:100%;margin-top:calc(clamp(12px,1vw,16px) + 1 * var(--ux));background:none;border:0;
  font:inherit;font-size:var(--t-xs);color:var(--deep-2);cursor:pointer;text-align:center;
  text-decoration:underline;text-underline-offset:3px}

.gmodal-link:hover{color:var(--deep)}
@media (max-width:640px) {

  .ex-title{font-size:calc(clamp(1.75rem,8.4vw,2.5rem) + 8.4 * var(--ux))}

  .ex-steps{flex-direction:column}

  .ex-step{border-left:0;padding-left:0;border-top:1px solid var(--line);padding-top:11px;padding-bottom:11px}

  .ex-step:first-child{border-top:0}

  .ex-quiz{padding:18px 15px}

  .ex-opt{padding:12px 13px;font-size:15px}

  .ex-nav{flex-direction:column;gap:16px}

  .ex-nav-btn.next{text-align:left;align-items:flex-start}
}

/* ===== page: book ===== */

/* page-level token restored from book.html's own :root (T4-F3): only
   book.html defines it, so scoped here rather than hoisted to shared. */
body[data-page="book"]{--on-yellow:#1A1C18}

body[data-page="book"] .btn .arw{transition:transform .35s var(--ease)}

body[data-page="book"] .btn:hover .arw{transform:translateX(6px)}

/* the quiet option beside a solid button: glass fill, hairline, no colour */
body[data-page="book"] .btn-g{background:rgba(255,255,255,.42);color:var(--deep);border-color:var(--ring)}

body[data-page="book"] .btn-g:hover{background:rgba(255,255,255,.62)}


/* ---------- button hover: tinted glass ----------
   the home page's hover, carried over intact: the glass keeps its blur and
   translucency and a soft gold-into-Atlas-blue tint fades in beneath it, so the
   change reads as light moving through the glass rather than a repaint. */
body[data-page="book"] .btn,body[data-page="book"] .foot-cta{position:relative;overflow:hidden;isolation:isolate}

body[data-page="book"] .btn::before,body[data-page="book"] .foot-cta::before{
  content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;opacity:0;
  background:linear-gradient(115deg,rgba(255,191,0,.38) 0%,rgba(226,126,46,.30) 42%,rgba(72,90,150,.5) 100%);
  transition:opacity .55s var(--ease)}

body[data-page="book"] .btn:hover::before,body[data-page="book"] .foot-cta:hover::before{opacity:1}

body[data-page="book"] .p-y,body[data-page="book"] .p-y .dsp,body[data-page="book"] .p-y h3,body[data-page="book"] .p-y p,body[data-page="book"] .p-y footer{color:var(--on-yellow)}


/* ---------- box definition ----------
   the home page's rule: one hairline only, the outer dark one that keeps a box
   legible against the white page. no light inner ring, no shadows, no gloss. */
body[data-page="book"] .panel,body[data-page="book"] .btn,body[data-page="book"] .chip,.stat,.aq,.fan-refund{position:relative}

/* over the black hero the bar flips to dark glass, or the dark logotype sits on
   a mid-grey frost and stops being readable */
body[data-page="book"] .nav.on-dark{background:rgba(16,17,15,.3);border-bottom-color:rgba(255,255,255,.17);color:#F2F3F1}

body[data-page="book"] .nav.on-dark .logo i{color:rgba(242,243,241,.6)}

body[data-page="book"] .nav.on-dark .btn{background:rgba(255,255,255,.12);color:#F7F8F6}

body[data-page="book"] .nrow ul a.act{opacity:1;font-weight:600}


/* ---------- hero: the black opening, the cover as the object ----------
   the home page opens on a full-bleed black frame with a gold display title, and
   this page now opens the same way — same ground, same gold, same glass buttons —
   so the two read as one site. the difference is the object: there it is a scan,
   here it is the book itself, which is the whole point of the page.

   the dark tokens are scoped to the section rather than the document, so this band
   is dark whatever the page mode is doing, and every child (chip, lede, plate,
   buttons) picks the dark values up by inheritance. */
.bhero{
  --white:#0E0F10; --deep:#F2F3F1; --deep-2:#B4B7B2; --muted:#8B8E89;
  --grey-1:#191B1C; --grey-2:#2E3031; --line:#2A2C2D;
  --glass-white:rgba(255,255,255,.07); --glass-grey:rgba(255,255,255,.075);
  --glass-dark:rgba(255,255,255,.11);
  --ring:transparent; --ring-in:transparent; --ring-dark:transparent;
  color:var(--deep);position:relative;
  /* the home hero's exact ground: true black, with the cover gold washing in from
     the top-left and bottom-right corners */
  background:
    radial-gradient(ellipse 90% 62% at 18% -8%,rgba(255,191,0,.10),transparent 62%),
    radial-gradient(ellipse 84% 74% at 86% 108%,rgba(255,191,0,.17),transparent 66%),
    radial-gradient(ellipse 80% 60% at 50% 44%,#0A0A0A,#000 76%);
  /* the bar is sticky and in flow, so the band is pulled up by exactly its height
     and the black starts at the very top of the page, as it does on the home page */
  margin-top:calc(-1 * var(--nav-h,64px));
  padding:calc(var(--nav-h,64px) + clamp(56px,7.5vw,150px) + 7.5 * var(--ux)) 0 var(--sec)}

/* the title in cover gold, at the home hero's tracking */
.bhero h1{color:var(--yellow);letter-spacing:-.022em;line-height:1.02}

/* the dark-ground button values, matching html.dk on the home page */
.bhero .btn{background:rgba(255,255,255,.12);color:#F7F8F6}

.bhero .btn:hover{background:rgba(255,255,255,.18)}

.bhero .btn-y{background:var(--yellow);color:var(--on-yellow)}

.bhero .btn-y:hover{background:#ffcd3d}

.bhero .btn-g{background:rgba(255,255,255,.07);color:var(--deep)}

.bhero .btn-g:hover{background:rgba(255,255,255,.12)}

.bhero .chip{color:var(--on-yellow)}

.bhero-grid{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:calc(clamp(34px,5vw,110px) + 5 * var(--ux));align-items:center}

.bhero-ed{display:block;font-family:var(--sans);font-weight:500;text-transform:uppercase;
  letter-spacing:.3em;font-size:calc(clamp(11px,.82vw,14px) + .82 * var(--ux));color:var(--muted);
  margin:calc(clamp(18px,1.6vw,30px) + 1.6 * var(--ux)) 0 calc(clamp(12px,1.15vw,20px) + 1.15 * var(--ux))}

.bhero h1{max-width:9.2em}

.bhero .lede{margin-top:calc(clamp(18px,1.6vw,30px) + 1.6 * var(--ux));max-width:34em}

.bhero-ctas{display:flex;flex-wrap:wrap;gap:calc(clamp(12px,1vw,18px) + 1 * var(--ux));margin-top:calc(clamp(26px,2.4vw,48px) + 2.4 * var(--ux))}

.bhero-note{margin-top:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux));font-size:var(--t-xs);color:var(--muted);max-width:32em}

/* the plate: grey glass, generous inset, the cover shown whole. the object gets
   a slow float so the page breathes without anything else moving. */
.bhero-plate{padding:calc(clamp(30px,3.4vw,72px) + 3.4 * var(--ux))}

.bhero-plate img{width:min(100%,calc(clamp(300px,26vw,520px) + 26 * var(--ux)));margin:0 auto;
  animation:cov 9s ease-in-out infinite alternate}

@keyframes cov{from{transform:translateY(0)}to{transform:translateY(-14px)}}


/* ---------- stats: the hairline band, poured in glass ----------
   the original layout — one band, hairline separators, no boxes — but the band
   itself is a full-bleed frosted pane over the coloured ambient. */
.bstats{border-top:1px solid var(--ring);border-bottom:1px solid var(--ring);
  padding:calc(clamp(30px,3vw,64px) + 3 * var(--ux)) 0;background:var(--glass-white);
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  transition:background-color .6s ease,border-color .6s ease}

.bstats-row{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--gap)}

.stat b{display:block;font-family:var(--display);font-weight:400;letter-spacing:-.03em;line-height:1;
  font-size:calc(clamp(2rem,3.4vw,4.6rem) + 3.4 * var(--ux))}

.stat span{display:block;margin-top:.6em;font-size:var(--t-14);color:var(--muted);max-width:14em}

.stat{padding-left:calc(clamp(18px,1.8vw,40px) + 1.8 * var(--ux));border-left:1px solid var(--ring)}

.stat::after{display:none}

.stat:first-child{padding-left:0;border-left:0}


/* ---------- inside: all six spreads laid out on one glass desk ----------
   everything visible at once, no interaction required. the desk is a single
   frosted pane; each spread is a page resting on it. */
.inside-head{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:calc(clamp(30px,5vw,110px) + 5 * var(--ux));align-items:end;margin-bottom:calc(clamp(44px,4.6vw,96px) + 4.6 * var(--ux))}

.inside-head .dsp{margin-top:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux));max-width:13em}

.inside-head .lede{max-width:36em}

.desk{padding:calc(clamp(18px,1.9vw,40px) + 1.9 * var(--ux))}

/* eight single pages of the 3rd edition (from the authors, 2026-10-17), four to a row */
.desk-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:calc(clamp(12px,1.2vw,24px) + 1.2 * var(--ux))}
@media (max-width:1080px){ .desk-grid{grid-template-columns:repeat(2,1fr)} }

.desk-grid img{width:100%;height:auto;border-radius:10px;border:1px solid var(--line);
  background:#fff;transition:transform .35s var(--ease)}

.desk-grid img:hover{transform:translateY(-5px) scale(1.02)}


/* ---------- the vault: your copy holds the password ----------
   one full-bleed frosted pane — no boxes inside, just type and the two actions
   resting on the glass. token-built, because this stretch of the page turns
   LIGHT while it holds the viewport (the .lt swap below) and back to dark on
   the way out; the frost shows the coloured ambient on both grounds. */
.vault{position:relative;padding:calc(var(--sec)*1.05) 0;
  border-top:1px solid var(--ring);border-bottom:1px solid var(--ring);
  background:var(--glass-white);
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  transition:background-color .6s ease,border-color .6s ease}

.vault .page-n{position:relative;z-index:1;text-align:center}

.vault h2{color:var(--deep);max-width:13em;margin:calc(clamp(18px,1.6vw,30px) + 1.6 * var(--ux)) auto 0}

.vault .lede{color:var(--deep-2);margin:calc(clamp(18px,1.6vw,30px) + 1.6 * var(--ux)) auto 0;max-width:42em}

.vault-ctas{display:flex;flex-wrap:wrap;justify-content:center;gap:calc(clamp(12px,1vw,18px) + 1 * var(--ux));
  margin-top:calc(clamp(28px,2.6vw,52px) + 2.6 * var(--ux))}

/* the password line: plain words on the glass, no box */
.vault-key{display:inline-flex;align-items:center;gap:.7em;margin-top:calc(clamp(26px,2.4vw,46px) + 2.4 * var(--ux));
  font-size:var(--t-sm);color:var(--deep-2);transition:color .6s ease}

.vault-key svg{flex:0 0 auto;opacity:.75}



/* ---------- hall of fans ----------
   the wall of readers is the section. a big unboxed pull-quote sets it up, the
   photo strips carry it, and one glass band beneath makes the refund offer. */
.fans-head{display:flex;justify-content:space-between;align-items:flex-end;gap:calc(clamp(22px,1.81vw,40px) + 1.81 * var(--ux));
  flex-wrap:wrap;margin-bottom:calc(clamp(30px,3vw,64px) + 3 * var(--ux))}

.fans-head .dsp{margin-top:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux));max-width:16em}

/* the editors' line, set free of any box: a gold rule, display type, a credit */
.fan-pull{max-width:34em;margin:0}

.fan-pull::before{content:"";display:block;width:calc(clamp(44px,4vw,76px) + 4 * var(--ux));height:3px;
  background:var(--yellow);border-radius:2px;margin-bottom:calc(clamp(18px,1.6vw,30px) + 1.6 * var(--ux))}

.fan-pull p{font-family:var(--display);font-weight:400;color:var(--deep);letter-spacing:-.01em;
  font-size:calc(clamp(1.3rem,2.1vw,2.6rem) + 2.1 * var(--ux));line-height:1.32}

.fan-pull cite{display:block;font-style:normal;margin-top:calc(clamp(14px,1.25vw,24px) + 1.25 * var(--ux));
  font-size:var(--t-sm);color:var(--muted)}

/* the refund, told in one glass band: claim -> steps -> action */
.fan-refund{margin-top:calc(clamp(40px,4vw,84px) + 4 * var(--ux));border-radius:var(--r);padding:calc(clamp(24px,2.4vw,50px) + 2.4 * var(--ux));
  background:var(--glass-grey);border:1px solid var(--ring);
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.6fr) auto;
  gap:calc(clamp(24px,2.6vw,56px) + 2.6 * var(--ux));align-items:center;position:relative}

.fan-refund::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--ring-in);mix-blend-mode:overlay}

.fan-refund h3{font-family:var(--display);font-weight:400;font-size:calc(clamp(1.3rem,1.9vw,2.5rem) + 1.9 * var(--ux));
  letter-spacing:-.01em;line-height:1.15}

.fan-refund ol{list-style:none;counter-reset:st;display:grid;grid-template-columns:repeat(3,1fr);
  gap:calc(clamp(16px,1.6vw,34px) + 1.6 * var(--ux))}

.fan-refund li{counter-increment:st;font-size:var(--t-14);color:var(--deep-2);
  padding-left:calc(clamp(12px,1.1vw,20px) + 1.1 * var(--ux));border-left:1px solid var(--ring)}

.fan-refund li::before{content:counter(st,decimal-leading-zero);display:block;
  font-family:var(--display);font-size:var(--t-sm);letter-spacing:.16em;color:var(--muted);
  margin-bottom:.4em}

.fan-refund li b{color:var(--deep);font-weight:500;display:block}

.fan-refund .btn{justify-self:end}


/* ---------- the wall: every reader picture, two counter-drifting film strips ----------
   uniform height, natural widths. each track holds the set twice; translating the
   track by exactly half its width loops seamlessly. the second half is decorative,
   so it is hidden from assistive tech. */
.fanwall{margin-top:calc(clamp(40px,4vw,84px) + 4 * var(--ux));display:flex;flex-direction:column;gap:var(--gap);
  overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}

.fanrow{overflow:hidden}

.fantrack{display:flex;width:max-content;will-change:transform;animation:fanmove 130s linear infinite}

.fantrack.one{animation-duration:280s}

.fantrack.rev{animation-name:fanmove-r;animation-duration:150s}

.fanwall:hover .fantrack{animation-play-state:paused}

@keyframes fanmove{from{transform:translateX(0)}to{transform:translateX(-50%)}}

@keyframes fanmove-r{from{transform:translateX(-50%)}to{transform:translateX(0)}}

/* padding-right on the set stands in for the seam gap, so -50% lands exactly on
   the start of the duplicate and the loop never jumps */
.fanset{display:flex;gap:calc(clamp(12px,1.1vw,20px) + 1.1 * var(--ux));padding-right:calc(clamp(12px,1.1vw,20px) + 1.1 * var(--ux))}

/* every picture cut to the same 3:4 portrait: the mixed phone-photo shapes are
   what made the wall untidy. a light shared grade calms the colour casts, and
   each print gets the full hairline-frame treatment. */
.fanset img{height:calc(clamp(200px,16.5vw,310px) + 16.5 * var(--ux));aspect-ratio:3/4;width:auto;object-fit:cover;
  border-radius:12px;border:1px solid var(--line);flex:0 0 auto;background:var(--grey-1);
  filter:saturate(.86) contrast(1.02);
  transition:transform .4s var(--ease),filter .4s var(--ease),border-color .6s ease}

.fanset img:hover{transform:translateY(-4px) scale(1.02);filter:saturate(1.05) contrast(1.02)}
@media (prefers-reduced-motion:reduce) {

  .fantrack{animation:none!important}

  .fanrow{overflow-x:auto}
}


/* ---------- authors: 24 names given air ---------- */
.auth-head{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:calc(clamp(30px,5vw,110px) + 5 * var(--ux));align-items:end;margin-bottom:calc(clamp(40px,4vw,84px) + 4 * var(--ux))}

.auth-head .dsp{margin-top:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux));max-width:13em}

.auth-head .lede{max-width:34em}

.authors{list-style:none;columns:3;column-gap:calc(clamp(28px,3vw,64px) + 3 * var(--ux))}

.authors li{break-inside:avoid;padding:calc(clamp(11px,1vw,18px) + 1 * var(--ux)) 0;border-top:1px solid var(--line)}

.authors b{display:block;font-weight:500;font-size:var(--t-165);letter-spacing:-.01em}

.authors span{display:block;margin-top:3px;font-size:var(--t-xs);color:var(--muted)}

.ed-tag{display:inline-block;font-style:normal;margin-left:.6em;vertical-align:2px;font-size:calc(clamp(10px,.7vw,13px) + .7 * var(--ux));
  font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--on-yellow);
  background:rgba(255,198,41,.78);border:1px solid rgba(120,88,0,.24);border-radius:5px;padding:.2em .55em}
@media (max-width:1080px) {

  .bhero{padding-top:calc(clamp(36px,6vw,60px) + 6 * var(--ux))}

  .bhero-grid{grid-template-columns:1fr;gap:calc(clamp(30px,7vw,48px) + 7 * var(--ux))}

  .bhero-plate{order:2}

  .bstats-row{grid-template-columns:1fr 1fr;gap:calc(clamp(24px,5vw,40px) + 5 * var(--ux))}

  .stat{padding-left:0;border-left:0}

  .inside-head,.auth-head{grid-template-columns:1fr;gap:calc(clamp(16px,4vw,26px) + 4 * var(--ux));align-items:start}

  .fan-refund{grid-template-columns:1fr;gap:calc(clamp(20px,5vw,32px) + 5 * var(--ux))}

  .fan-refund .btn{justify-self:start}

  .authors{columns:2}
}
@media (max-width:640px) {

  .authors{columns:1}

  .fan-refund ol{grid-template-columns:1fr;gap:calc(clamp(12px,3.5vw,20px) + 3.5 * var(--ux))}

  .desk-grid{grid-template-columns:1fr}

  .bstats-row{grid-template-columns:1fr 1fr}
}

/* browsers without backdrop-filter get a near-solid sheet instead of a see-through one */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  body[data-page="book"] .nrow ul{background:rgba(248,249,247,.97)}
}
@media (max-width:1080px) {

  body[data-page="book"] .nav.on-dark .nrow ul{background:rgba(16,17,15,.55);border-bottom-color:rgba(255,255,255,.17)}

  body[data-page="book"] .nav.on-dark .nrow ul a{color:#F2F3F1;border-top-color:rgba(255,255,255,.12)}
}


/* ================= mobile length pass (book) ================= */
.auth-more{display:none;margin-top:18px;appearance:none;cursor:pointer;font-family:inherit;
  align-items:center;gap:1em;border-radius:var(--r);padding:.9em 1.35em;font-size:var(--t-145);
  background:rgba(255,255,255,.12);color:#F7F8F6;border:1px solid var(--ring-dark);
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur)}
@media (max-width:640px) {

  
  section{padding:calc(clamp(52px,13vw,64px) + 13 * var(--ux)) 0}

  .vault{padding:calc(clamp(60px,15vw,76px) + 15 * var(--ux)) 0}

  .fanwall{margin-top:calc(clamp(28px,7vw,40px) + 7 * var(--ux))}

  .fan-refund{margin-top:calc(clamp(28px,7vw,40px) + 7 * var(--ux))}

  
  .desk{padding:12px}

  .desk-grid{display:flex;overflow-x:auto;gap:10px;scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;scrollbar-width:none}

  .desk-grid::-webkit-scrollbar{display:none}

  .desk-grid img{flex:0 0 86%;width:86%;scroll-snap-align:center}

  
  .authors li:nth-child(n+9){display:none}

  .authors.open li:nth-child(n+9){display:list-item}

  .auth-more{display:inline-flex}
}

/* T4 fixlet: /whats-new/'s intro (site/views/whats_new.php) sat flush against the
   "latest exercise" eyebrow/rule at every width — .lib-row-sec only carries TOP padding
   (it's normally the page's very first section), and .ttp-now-sec that follows it here
   carries none of its own (it depends on .ttp-head's BOTTOM padding for that gap on
   time_to_play.php, which this page doesn't have). Same token as .ttp-head's own
   bottom padding (site.css:3350) — not a new value — so the two pages read as one
   spacing system. */
.wn-intro{padding-bottom:calc(clamp(24px,2.2vw,42px) + 2.2 * var(--ux))}

/* Section header — one component, two grounds (2026-09-10). Replaces seven separate
   implementations (.wn-head, .art-top-sec, .ttp-head, …) that between them used four title
   sizes and four eyebrow conventions. The ground is the only variable, stored per page in
   data/page-heads.json and switchable live at /<page>?tuneheader=1:
     A (default) — light, the page opens white and a hairline hands over to the content
     B (--ink)   — the ink band with a gold title, the same object as the account and
                   sign-in headers; suits a page that opens on text rather than on
                   content carrying its own images. */
/* .82 -> .38 (2026-09-17). The light ground has no band to give the title presence, so it
   was given air instead — but that put the title 203px under the nav on a 4K screen (127 at
   1280), against 102 for the same head on the ink band, and it read as a header that had
   lost its page. .38 brings the two grounds into the same rhythm: membership 76/117 against
   the band's 73/102, FAQ 44/74. The ink band overrides this padding outright, so nothing on
   it moves. Reported three times by Stéphane before it was measured properly. */
.page-head{padding:calc(var(--sec) * .38) 0 0}
.page-head-in{max-width:var(--ph-measure,var(--page-n));margin:0 auto;padding:0 var(--edge);
  display:flex;align-items:baseline;justify-content:space-between;gap:var(--gap);flex-wrap:wrap}
.page-head-txt{min-width:0}
.page-head-eyebrow{font-size:var(--t-xs);letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin-bottom:calc(clamp(10px,.9vw,16px) + .9 * var(--ux))}
.page-head h1{max-width:14em}
.page-head-lede{margin-top:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux))}
.page-head-aside{font-size:var(--t-14);color:var(--muted);font-variant-numeric:tabular-nums}
/* A closes with a hairline, so the head hands over to the content instead of just stopping */
.page-head:not(.page-head--ink) .page-head-in{padding-bottom:calc(clamp(26px,2.4vw,44px) + 2.4 * var(--ux));
  border-bottom:1px solid var(--line)}

/* Compact — for a page that is a tool rather than a document (the library). Same type,
   same measure, same alignment as every other section; a third of the height, because
   everything above the search field on that page is a cost paid at the point of care. */
.page-head--compact{padding-top:calc(clamp(28px,2.6vw,52px) + 2.6 * var(--ux))}
.page-head--compact .page-head-in{padding-bottom:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux))}
.page-head--compact .page-head-eyebrow{margin-bottom:calc(clamp(6px,.5vw,10px) + .5 * var(--ux))}
.page-head--compact.page-head--ink{padding:calc(clamp(22px,2vw,38px) + 2 * var(--ux)) 0}

.page-head--ink{background:var(--deep);color:rgba(236,237,232,.78);
  padding:calc(clamp(34px,3.4vw,64px) + 3.4 * var(--ux)) 0}
.page-head--ink .page-head-eyebrow{color:rgba(236,237,232,.5);letter-spacing:.3em;font-weight:500;
  font-size:calc(clamp(11px,.82vw,14px) + .82 * var(--ux))}
.page-head--ink h1{color:var(--yellow)}
.page-head--ink .page-head-lede{color:rgba(236,237,232,.72)}
.page-head--ink .page-head-aside{color:rgba(236,237,232,.55)}
/* the body that follows an ink head starts its own spacing, since the band already has some */
.page-head--ink + .sec,.page-head--ink + section{padding-top:calc(clamp(26px,2.4vw,44px) + 2.4 * var(--ux))}

/* What's new — "wide rows" (2026-09-09). Replaces the three stacked blocks (latest
   exercise / case grid / recent news) with one dated stream: still on the left, the title
   and its own description side by side, the author named with their photo. It is a grid
   rather than a stack of cards precisely so the titles line up down the page and the
   descriptions form a column of their own. The old version is kept in git and at
   .bak-whats-new-20260909/. */
.wn-wrap{max-width:var(--page-n);margin:0 auto}
.wn-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--gap);flex-wrap:wrap;
  padding-bottom:calc(clamp(20px,1.8vw,32px) + 1.8 * var(--ux));border-bottom:1px solid var(--line)}
.wn-eyebrow{font-size:var(--t-xs);letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
  margin-bottom:.5em}
.wn-updated{font-size:var(--t-14);color:var(--muted);font-variant-numeric:tabular-nums}
.wn-empty{margin-top:var(--gap)}

/* The last row's rule had nothing after it but 130px of air, which reads as a list cut off
   rather than a list ending (2026-09-13). */
.wn-row:last-child{border-bottom:0}
.wn-row{display:grid;grid-template-columns:16.5em minmax(0,1fr) minmax(0,1.15fr) 13em;
  gap:calc(var(--gap) * 1.2);align-items:center;
  padding:calc(clamp(22px,2vw,36px) + 2 * var(--ux)) 0;border-bottom:1px solid var(--line)}
.wn-row:hover .wn-title{color:var(--blue)}
.wn-thumb{position:relative;aspect-ratio:16/10;background:var(--grey-1);overflow:hidden;
  border-radius:calc(var(--r) * .8)}
.wn-thumb img{width:100%;height:100%;object-fit:cover}
.wn-num{position:absolute;left:0;bottom:0;padding:.15em .5em;font-family:var(--display);
  font-size:calc(clamp(1.6rem,2.2vw,2.6rem) + 2.2 * var(--ux));line-height:1;color:#1A1C18;
  background:var(--yellow)}
.wn-kind{display:inline-flex;align-items:center;font-size:11.5px;letter-spacing:.04em;font-weight:500;
  padding:.35em .7em;border-radius:999px;white-space:nowrap}
.wn-k-exercise{background:rgba(255,198,41,.28);color:#6b5200}
.wn-k-case{background:rgba(72,90,150,.14);color:#2f3f74}
.wn-k-notice{background:rgba(28,32,26,.08);color:var(--deep-2)}
.wn-title{font-family:var(--display);font-weight:400;font-size:var(--t-22);line-height:1.18;
  letter-spacing:-.01em;margin-top:.3em;transition:color .2s}
.wn-meta{display:flex;align-items:center;gap:.8em;flex-wrap:wrap;margin-top:.55em}
.wn-date{font-size:var(--t-14);color:var(--muted);font-variant-numeric:tabular-nums}
.wn-state{font-size:11.5px;color:var(--muted)}
/* three lines, so a long excerpt cannot set the height of every row */
.wn-text{color:var(--deep-2);font-size:var(--t-145);line-height:1.6;display:-webkit-box;
  -webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.wn-who{display:flex;align-items:center;gap:.7em}
.wn-who img{width:calc(clamp(38px,2.9vw,52px) + 2.9 * var(--ux));
  height:calc(clamp(38px,2.9vw,52px) + 2.9 * var(--ux));border-radius:50%;object-fit:cover;
  flex:0 0 auto;background:var(--grey-1)}
.wn-who b{display:block;font-weight:500;font-size:var(--t-14);line-height:1.25;white-space:nowrap}
/* A jointly signed piece shows both faces: the second overlaps the first by a third, which
   reads as "these two together" rather than as two separate rows, and costs no extra width
   worth reclaiming. The ring is the page ground, so the overlap stays legible on the tinted
   notice row as well as on white. */
.art-faces,.wn-faces{display:inline-flex;align-items:center;flex:0 0 auto}
.art-faces img+img,.wn-faces img+img{margin-left:-.9em}
.art-faces img,.wn-faces img{box-shadow:0 0 0 2px var(--white);position:relative}
.art-faces img+img,.wn-faces img+img{z-index:1}

.wn-who span span{font-size:11.5px;color:var(--muted)}

/* A notice keeps the grid so the titles stay in line, but loses the photo slot: the date
   sits where the still would be, and the band BLEEDS LEFT — a negative margin equal to its
   own border and padding — so its content box lands exactly where every other row's does.
   Indenting it instead pushed its title out of the column, which is the one thing this
   layout is for. */
/* The notice panel bleeds on BOTH sides. It used to bleed left and stop flush against the
   content on the right, so the tint had no right margin at all — invisible while the last
   thing in the row was the "Read it" pill (its own padding stood in for the gap) or a short
   single name, and plain to see the moment a signed notice carried two names: "Penninck &
   d'Anjou" ended 2px from the edge and read as overflowing the box. Mirroring the left keeps
   the gap correct for any name, and makes the panel look intentional rather than cropped. */
.wn-row.is-notice{--wn-bleed:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux));
  background:rgba(255,191,0,.10);border-left:3px solid var(--yellow);
  border-bottom-color:rgba(255,191,0,.35);
  margin-left:calc(-1 * var(--wn-bleed) - 3px);padding-left:var(--wn-bleed);
  margin-right:calc(-1 * var(--wn-bleed));padding-right:var(--wn-bleed);
  padding-top:var(--wn-bleed);padding-bottom:var(--wn-bleed)}
.wn-row.is-notice .wn-slot{display:flex;align-items:center}
.wn-when{font-family:var(--display);font-size:var(--t-22);line-height:1.1;color:#6b5200}
.wn-when small{display:block;font-size:var(--t-14);font-family:var(--sans);color:var(--muted);margin-top:.2em}
.wn-read{display:inline-flex;align-items:center;gap:.55em;padding:.6em 1.15em;border-radius:999px;
  background:var(--deep);color:#fff;font-size:var(--t-14);white-space:nowrap;transition:background .25s var(--ease)}
.wn-row.is-notice:hover .wn-read{background:#000}

@media (max-width:1180px){
  .wn-row{grid-template-columns:14em minmax(0,1fr) 12em;gap:var(--gap);align-items:start}
  .wn-text{grid-column:2 / -1;margin-top:-.2em}
}
@media (max-width:760px){
  .wn-row{grid-template-columns:1fr;gap:.7em}
  .wn-thumb{aspect-ratio:16/9}
  .wn-text{grid-column:auto;margin-top:0}
  .wn-who{margin-top:.2em}
  .wn-row.is-notice{--wn-bleed:calc(clamp(12px,1.1vw,18px) + 1.1 * var(--ux))}
  .wn-row.is-notice .wn-slot{order:-1}
}

/* Contact page — layout tuning tokens (2026-09-09). Same contract as the membership
   block above: multipliers on the expressions the rules already carry, so a change holds
   at 375px, 1440px and 4K alike. --c-box-w and --c-area are raw em lengths, not
   multipliers. Machine-written between the sentinels by /contact/?tune=1 — keep the
   one-token-per-line shape and put nothing else inside.

   As built 2026-09-09, before any tuning: every multiplier 1, --c-box-w 32, --c-area 9.
   (The icon badge and its --c-ico token were removed the same day.) */
/* tune:defaults:contact:start */
:root{
  --c-top:0.62;
  --c-eyebrow:1.26;
  --c-eyebrow-gap:1;
  --c-h1:1.08;
  --c-box-gap:1;
  --c-box-w:39;
  --c-box-pad:0.74;
  --c-radius:0.94;
  --c-gap:1.1;
  --c-label:1.04;
  --c-field:0.88;
  --c-field-pad:1.04;
  --c-area:9;
  --c-check:0.94;
  --c-btn:0.98;
  --c-btn-pad:0.96;
  --c-foot:1;
  --c-bot:1.26;
}
/* tune:defaults:contact:end */

/* The "gold box" (2026-09-09) — the home page's "How it works" stage (#begin) rebuilt as
   a form: a dark room, a radial glow behind, and one gold card. Introduced for /contact/
   and shared since with /login; both keep an empty data-page so .foot-sec stays solid.
   Note the box width follows the CONTACT tuning token (--c-box-w), deliberately: the two
   pages are meant to be the same object. Split the token if that ever stops being true. The
   gradient is the same one .wash.g-y carries there, solid here because it sits on ink
   rather than over the stage's frosted backdrop.
   Two things invert on gold, and both are the reason this block exists rather than
   reusing .auth-card: the primary action becomes ink (a gold button on a gold card is
   invisible) and the focus ring becomes ink too (the site's gold ring disappears). */
.gold-room{position:relative;background:#1A1C18;overflow:hidden}
.gb-glow{position:absolute;inset:-15%;pointer-events:none;
  background:radial-gradient(ellipse 62% 56% at 50% 55%,rgba(255,191,0,.22),rgba(255,191,0,0) 70%)}
.gold-room .sec{position:relative;z-index:1;padding-top:calc(var(--sec) * .8 * var(--c-top,1));
  padding-bottom:calc(var(--sec) * .8 * var(--c-bot,1))}
.gb-head{text-align:center;max-width:30em;margin:0 auto}
.gb-eyebrow{font-size:calc(var(--t-xs) * var(--c-eyebrow,1));letter-spacing:.14em;text-transform:uppercase;
  color:var(--yellow);margin-bottom:calc(.7em * var(--c-eyebrow-gap,1))}
/* restates .d2's own size so the tuning token can scale it without touching the shared
   display scale every other page uses */
.gb-head h1{color:#fff;font-size:calc((clamp(1.75rem,3.1vw,4.1rem) + 3.1 * var(--ux)) * var(--c-h1,1))}

.gb-box{max-width:calc(var(--c-box-w,32) * 1em);
  margin:calc((clamp(26px,2.2vw,44px) + 2.2 * var(--ux)) * var(--c-box-gap,1)) auto 0;
  border-radius:calc(var(--r) * 1.3 * var(--c-radius,1));padding:calc(var(--pad) * var(--c-box-pad,1));color:#1A1C18;
  background:linear-gradient(157deg,#FFCD34 0%,#F08E18 100%);
  box-shadow:0 30px 70px rgba(0,0,0,.36);
  display:flex;flex-direction:column;gap:calc((clamp(14px,1.2vw,20px) + 1.2 * var(--ux)) * var(--c-gap,1))}
.gb-row{display:flex;flex-direction:column;gap:.45em}
.gb-row label{font-size:calc(var(--t-14) * var(--c-label,1));color:rgba(26,28,24,.72)}
.gb-row input,.gb-row select,.gb-row textarea{width:100%;font:inherit;
  font-size:calc(var(--t-145) * var(--c-field,1));
  color:#1A1C18;background:rgba(255,255,255,.62);border:1px solid rgba(26,28,24,.18);
  border-radius:var(--r);padding:calc(.85em * var(--c-field-pad,1)) calc(1em * var(--c-field-pad,1));
  transition:border-color .2s}
.gb-row input:hover,.gb-row select:hover,.gb-row textarea:hover{border-color:rgba(26,28,24,.38)}
.gb-row input:focus,.gb-row select:focus,.gb-row textarea:focus{outline:2px solid #1A1C18;
  outline-offset:1px;border-color:transparent}
.gb-row textarea{min-height:calc(var(--c-area,9) * 1em);resize:vertical}
.gb-hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* the FAQ acknowledgement gates the action, so it sits directly above it */
.gb-check{display:flex;gap:.7em;align-items:flex-start;font-size:calc(var(--t-14) * var(--c-check,1));line-height:1.5;
  color:rgba(26,28,24,.86);cursor:pointer}
.gb-check input{margin-top:.25em;flex:0 0 auto;width:17px;height:17px;accent-color:#1A1C18;cursor:pointer}
.gb-check a{color:#1A1C18;border-bottom:1px solid rgba(26,28,24,.45);padding-bottom:1px}
.gb-check a:hover{border-color:#1A1C18}

.gb-btn{width:100%;border:1px solid transparent;border-radius:var(--r);
  padding:calc(1em * var(--c-btn-pad,1)) calc(1.65em * var(--c-btn-pad,1));
  font:inherit;font-size:calc(var(--t-145) * var(--c-btn,1));font-weight:500;background:#1A1C18;color:#fff;cursor:pointer;
  transition:transform .25s var(--ease),background .25s var(--ease)}
.gb-btn:hover:not([disabled]){transform:translateY(-2px);background:#000}
/* a muddy fill on gold reads as broken; an outline reads as "not yet" */
.gb-btn[disabled]{background:transparent;border-color:rgba(26,28,24,.32);color:rgba(26,28,24,.55);
  cursor:not-allowed}
/* the head's supporting line, on the dark room rather than in the card */
.gb-lede{font-size:var(--t-15);line-height:1.6;color:rgba(213,214,208,.82);
  margin:calc(clamp(12px,1vw,18px) + 1 * var(--ux)) auto 0;max-width:34em}
/* a card that carries a message and a way on, rather than a form to fill */
.gb-box-quiet{align-items:center;text-align:center}
.gb-box-quiet .gb-btn{width:auto;min-width:14em;text-decoration:none}
.gb-note{font-size:var(--t-145);color:rgba(26,28,24,.82)}

/* the quiet second option under a gold box (2026-09-10): a member whose membership
   already opens the Atlas videos still gets the password field, one click away, because
   registering the book keeps them after the membership ends. */
.gb-more{max-width:calc(var(--c-box-w,32) * 1em);margin:1.1em auto 0;text-align:center}
.gb-more summary{cursor:pointer;font-size:var(--t-14);color:rgba(236,237,232,.72);
  list-style:none;display:inline-block;border-bottom:1px solid rgba(236,237,232,.35);padding-bottom:2px}
.gb-more summary::-webkit-details-marker{display:none}
.gb-more summary:hover{color:#fff;border-bottom-color:#fff}
.gb-more[open] summary{margin-bottom:1.1em}
.gb-more .gb-box{text-align:left}

/* show/hide password — the button sits inside the field's right edge, and the input
   reserves room for it so a long password never runs underneath. site.js injects it. */
.gb-row--pw{position:relative}
.gb-row--pw input{padding-right:4.6em}
.gb-eye{position:absolute;right:.8em;bottom:.55em;font:inherit;font-size:var(--t-14);
  color:rgba(26,28,24,.7);background:transparent;border:0;padding:.25em .35em;cursor:pointer;
  border-bottom:1px solid rgba(26,28,24,.35);line-height:1.2;transition:color .2s,border-color .2s}
.gb-eye:hover{color:#1A1C18;border-color:#1A1C18}
.gb-eye:focus-visible{outline:2px solid #1A1C18;outline-offset:2px}

/* email sign-in (2026-09-22): the second way in sits under Sign in, quieter */
.gb-btn-alt{margin-top:calc(10px + .6 * var(--ux));background:transparent;color:inherit;border-color:currentColor}
.gb-btn-alt:hover:not([disabled]){background:rgba(26,28,24,.08)}
.gb-opt{font-weight:400;opacity:.7}
.gb-code{letter-spacing:.3em;font-variant-numeric:tabular-nums}
.gb-linkbtn{background:none;border:0;padding:0;font:inherit;color:inherit;text-decoration:underline;cursor:pointer}
/* returning members (2026-11-03) */
.gb-returning{text-align:center}
/* the way out when no sign-in email arrives */
.gb-help{font-size:var(--t-14);color:rgba(26,28,24,.78);margin-top:.9em;line-height:1.5}
.gb-help a,.gb-box-quiet a{color:inherit;text-decoration:underline;text-underline-offset:3px}
.gb-lede a{color:#FFBF00;text-decoration:underline;text-underline-offset:3px}
.gb-lede a:hover{color:#fff}

/* the sign-in card's two ways out; ink on gold, never the site's blue link colour */
.gb-links{display:flex;flex-wrap:wrap;gap:.5em 1.6em;justify-content:space-between;
  font-size:var(--t-14)}
.gb-links a{color:rgba(26,28,24,.86);border-bottom:1px solid rgba(26,28,24,.35);padding-bottom:1px;
  transition:color .2s,border-color .2s}
.gb-links a:hover{color:#1A1C18;border-color:#1A1C18}

.gb-foot{text-align:center;font-size:calc(var(--t-14) * var(--c-foot,1));color:rgba(26,28,24,.6)}

/* Membership page — layout tuning tokens (2026-09-09).
   Every token below is a MULTIPLIER on the expression it scales (1 = the page exactly
   as designed on 2026-08-29), except --m-h1-lh (a line-height) and --m-intro-w (a
   width in em). Multipliers, not px, because this page is built on the --ux fluid
   scale: scaling the whole clamp() keeps a value correct at 375px, 1440px and 4K
   instead of pinning one width and breaking the others.

   The live tuning panel — /membership?tune=1, site/assets/tune.js, spec in
   site/app/tune.php — writes these on <html> to preview, and its "Make these the
   defaults" button rewrites the :root block below (backups in
   site/assets/.tune-backup/). So THIS BLOCK IS MACHINE-WRITTEN between the sentinel
   comments: keep the one-token-per-line shape, and put nothing else inside it.

   As built 2026-09-09, before any tuning: every multiplier 1, --m-h1-lh 1.06,
   --m-intro-w 38. Restore those numbers to get the original design back. */
/* tune:defaults:membership:start */
:root{
  --m-sec:0.44;
  --m-gap:0.9;
  --m-bot:1;
  --m-big-pad:0.98;
  --m-eyebrow:1;
  --m-eyebrow-gap:1;
  --m-name:1;
  --m-price-gap:1;
  --m-price:0.96;
  --m-list-gap:0.82;
  --m-list:1;
  --m-body:1;
  --m-sub-h2:1;
  --m-card-pad:1;
  --m-card-h3:1;
  --m-card-price:1;
}
/* tune:defaults:membership:end */

/* Membership page (2026-08-28, migration 015: Getting started + PREMIUM as two large
   cards in row 1, three section cards — Head and Neck / Thorax / MSK and Neuro — in
   row 2). Previously all inline in site/views/membership.php; moved here per this
   task's write set. .mship-big is a new shared "big card" component used by BOTH
   row-1 products (replaces the old single .mship-hero, which only ever rendered
   PREMIUM) so the two cards read as one component at equal visual weight; .sec-card
   below is unchanged from before this task. */
.mship-chip{display:inline-block;background:rgba(255,198,41,.82);color:var(--deep);border-radius:var(--r-chip,7px);
  padding:.5em .93em;font-size:var(--t-14);line-height:1.2;border:1px solid rgba(120,88,0,.24)}
.mship-btn{display:inline-flex;align-items:center;justify-content:center;gap:.85em;white-space:nowrap;
  border-radius:var(--r);padding:1em 1.65em;font-size:var(--t-145);cursor:pointer;
  transition:transform .25s var(--ease),background .25s var(--ease)}
.mship-btn:hover{transform:translateY(-2px)}
.mship-btn-y{background:var(--yellow);color:var(--deep);border:1px solid transparent}
.mship-btn-y:hover{background:#ffcc33}
.mship-btn-o{background:transparent;color:var(--deep);border:1px solid var(--ring)}
.mship-btn-o:hover{background:rgba(28,32,26,.05)}
/* Big cards live on a dark surface (.mship-big) — the outline button there needs a
   light border/text, unlike its light-surface use elsewhere (mship-teams). */
.mship-big .mship-btn-o{color:#fff;border-color:rgba(255,255,255,.4)}
.mship-big .mship-btn-o:hover{background:rgba(255,255,255,.08)}

/* The membership page's own .sec — its top/bottom air is tunable (--m-top/--m-bot)
   where every other page takes the shared --sec. */
/* No padding-top: the shared section header brings its own (the same 94px every other
   light-ground page gets), and keeping the section's meant the two stacked — 141px here
   against FAQ's 94px on an identical head. The `top` slider that drove it went with it;
   the head owns its own spacing now, exactly as it does on the six pages that adopted it
   before this one. */
main .sec.mship-sec{padding-top:0;
  padding-bottom:calc(var(--sec)*var(--m-bot,1))}
/* .mship-intro's rules lived here — the page's own head, replaced by the shared section
   header (site/views/_page_head.php) on 2026-09-17. Removed rather than left behind: the
   markup they styled is gone, and the --m-chip/--m-h1/--m-lede/--m-intro-w tokens they
   multiplied went with the tuner sliders that drove them. */

.mship-row1{margin-top:calc(var(--sec)*var(--m-sec,1));display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:calc(var(--gap)*var(--m-gap,1));align-items:stretch}
/* Single column (2026-08-28 fix): a two-column card inside a two-column row left the
   "What's included" prose ~120px wide. Everything now stacks in reading order —
   eyebrow, name, term, price, checklist, description, the collapsible section
   breakdown, then the button pinned to the bottom of the flex column. */
.mship-big{border-radius:calc(var(--r)*1.15);background:var(--deep);color:#D5D6D0;
  padding:calc(var(--pad-lg)*var(--m-big-pad,1));display:flex;flex-direction:column}
.mship-big .dsp{color:#fff}
.mship-eyebrow{display:inline-block;font-size:calc(var(--t-xs)*var(--m-eyebrow,1));letter-spacing:.14em;text-transform:uppercase;
  color:var(--yellow);font-weight:500;margin-bottom:calc((clamp(10px,1vw,16px) + 1*var(--ux))*var(--m-eyebrow-gap,1))}
.mship-name{font-size:calc((clamp(1.6rem,2.3vw,2.9rem) + 2.3*var(--ux))*var(--m-name,1))}
.mship-term{margin-top:.6em;font-size:calc(var(--t-145)*var(--m-body,1));color:rgba(213,214,208,.8)}
.mship-price-row{display:flex;align-items:baseline;gap:.5em;margin-top:calc((clamp(24px,2.2vw,40px) + 2.2*var(--ux))*var(--m-price-gap,1))}
.mship-price{font-family:var(--display);font-weight:400;letter-spacing:-.01em;color:#fff;
  font-size:calc((clamp(2.4rem,4vw,5rem) + 4*var(--ux))*var(--m-price,1));line-height:1}
.mship-price-sub{font-size:calc(var(--t-145)*var(--m-body,1));color:rgba(213,214,208,.72)}
.mship-list{list-style:none;margin-top:calc((clamp(22px,2vw,36px) + 2*var(--ux))*var(--m-list-gap,1));display:flex;flex-direction:column;
  gap:.75em}
.mship-list li{display:flex;align-items:flex-start;gap:.7em;font-size:calc(var(--t-145)*var(--m-list,1));color:#D5D6D0}
.mship-list svg{flex:0 0 auto;margin-top:.28em;color:var(--yellow)}
.mship-big .mship-desc{margin-top:calc(clamp(18px,1.6vw,28px) + 1.6*var(--ux));max-width:38em}
/* Pushed to the bottom of the flex column so the two row-1 cards' buttons line up
   regardless of how many list items or how long the description runs. */
.mship-big .mship-btn{align-self:flex-start;margin-top:auto;padding-top:1em}

.mship-inc{margin-top:calc(clamp(14px,1.2vw,20px) + 1.2*var(--ux));margin-bottom:.9em}
.mship-inc summary{cursor:pointer;font-size:var(--t-14);font-weight:600;list-style:none;
  display:inline-flex;align-items:center;gap:.6em;padding:.45em 1em .45em .55em;border-radius:999px;
  border:1px solid currentColor;transition:color .2s,background-color .2s,border-color .2s}
.mship-inc summary::-webkit-details-marker{display:none}
.mship-inc summary::before{content:"+";flex:0 0 auto;width:1.45em;height:1.45em;border-radius:50%;
  display:inline-flex;align-items:center;justify-content:center;font-size:1em;font-weight:700;line-height:1;
  background:var(--yellow);color:#24261F;transition:transform .2s}
.mship-inc[open] summary::before{content:"\2212"}
.mship-inc summary:focus-visible{outline:2px solid var(--yellow);outline-offset:3px}
.mship-inc > ul{list-style:none;margin-top:.8em;display:flex;flex-direction:column;gap:.6em}
.mship-inc-sec{font-size:var(--t-13);font-weight:500}
.mship-inc-titles{list-style:none;margin-top:.3em;display:flex;flex-direction:column;gap:.25em}
.mship-inc-titles li{font-size:var(--t-13);font-weight:600;padding-left:.9em;position:relative}
.mship-inc-titles li::before{content:"\2013";position:absolute;left:0}
/* dark big-card variant */
.mship-big .mship-inc summary{color:#fff;border-color:rgba(255,255,255,.45)}
.mship-big .mship-inc summary:hover{border-color:var(--yellow);background:rgba(252,192,60,.12)}
.mship-big .mship-inc-sec{color:rgba(213,214,208,.9)}
.mship-big .mship-inc-titles li{color:rgba(213,214,208,.9)}
/* light card variant */
.sec-card .mship-inc summary{color:var(--deep);border-color:var(--deep-2)}
.sec-card .mship-inc summary:hover{border-color:var(--deep);background:rgba(128,128,120,.12)}
.sec-card .mship-inc-sec{color:var(--deep-2)}
.sec-card .mship-inc-titles li{color:var(--deep)}
/* .mship-desc is shared by the section cards and the big cards (mship-big rule above
   sets the dark-surface color + spacing; this sets the shared type + the light-surface
   color/spacing for .sec-card). */
.mship-desc{font-size:calc(var(--t-14)*var(--m-body,1));line-height:1.6}
.sec-card .mship-desc{color:var(--deep-2);
  margin-top:calc(clamp(8px,.7vw,12px) + .7*var(--ux))}
.mship-big .mship-desc{color:rgba(213,214,208,.78)}

.mship-sub{margin-top:calc(var(--sec)*var(--m-sec,1))}
/* Size lived inline on the <h2> in views/membership.php until 2026-09-09 — moved here
   so the tuning token can win (an inline style outranks any stylesheet rule). */
.mship-sub h2{max-width:24em;font-size:calc((clamp(1.6rem,2.2vw,2.6rem) + 2.2*var(--ux))*var(--m-sub-h2,1))}
.mship-sub .lede{margin-top:.6em}
.mship-grid{margin-top:calc(clamp(28px,2.6vw,44px) + 2.6*var(--ux));display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));gap:calc(var(--gap)*var(--m-gap,1))}
.sec-card{display:flex;flex-direction:column;border-radius:var(--r);border:1px solid var(--line);
  background:var(--white);padding:calc((clamp(20px,1.7vw,32px) + 1.7*var(--ux))*var(--m-card-pad,1));
  transition:transform .3s var(--ease),border-color .3s var(--ease),box-shadow .3s var(--ease)}
.sec-card:hover{transform:translateY(-3px);border-color:var(--grey-2);box-shadow:0 10px 24px rgba(28,32,26,.08)}
.sec-card h3{font-size:calc(var(--t-165)*var(--m-card-h3,1));min-height:2.6em}
.sec-card .sec-term{margin-top:.5em;font-size:var(--t-sm);color:var(--muted)}
.sec-card .sec-price{margin-top:calc(clamp(14px,1.2vw,20px) + 1.2*var(--ux));font-family:var(--display);
  font-weight:400;letter-spacing:-.01em;color:var(--deep);font-size:calc((clamp(1.5rem,1.8vw,2.1rem) + 1.8*var(--ux))*var(--m-card-price,1))}
.sec-card .sec-cta{margin-top:auto;padding-top:calc(clamp(16px,1.4vw,24px) + 1.4*var(--ux));display:flex;
  align-items:center;gap:.6em;font-size:var(--t-145);color:var(--deep);border-top:1px solid var(--line);
  padding-top:calc(clamp(14px,1.2vw,20px) + 1.2*var(--ux));transition:color .25s}
.sec-card .sec-cta svg{transition:transform .3s var(--ease)}
.sec-card:hover .sec-cta{color:var(--blue)}
.sec-card:hover .sec-cta svg{transform:translateX(4px)}

.mship-teams{margin-top:calc(var(--sec)*var(--m-sec,1));border-radius:var(--r);border:1px solid var(--line);background:var(--grey-1);
  padding:var(--pad);display:flex;justify-content:space-between;align-items:center;gap:calc(var(--gap)*var(--m-gap,1));flex-wrap:wrap}
.mship-teams-txt h3{font-size:var(--t-19)}
.mship-teams-txt p{margin-top:.6em;font-size:var(--t-145);color:var(--deep-2);max-width:34em}
.mship-teams .teams-price{margin-top:.75em;font-family:var(--display);font-weight:400;color:var(--deep);
  font-size:var(--t-19)}
.mship-teams .mship-btn{flex:0 0 auto}

.mship-notes{margin-top:calc(var(--sec)*var(--m-sec,1));padding-top:calc(clamp(28px,2.6vw,44px) + 2.6*var(--ux));
  border-top:1px solid var(--line)}
.mship-notes ul{list-style:none;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:calc(var(--gap)*var(--m-gap,1))}
.mship-notes li{font-size:var(--t-14);color:var(--deep-2);line-height:1.6;padding-left:1.4em;position:relative}
.mship-notes li::before{content:"";position:absolute;left:0;top:.55em;width:6px;height:6px;border-radius:50%;
  background:var(--yellow)}

@media (max-width:1080px){
  .mship-row1{grid-template-columns:1fr}
  .mship-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .mship-notes ul{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:640px){
  .mship-big{padding:calc((clamp(24px,7vw,32px) + 7*var(--ux))*var(--m-big-pad,1))}
  .mship-price{font-size:calc((clamp(2.1rem,10vw,2.6rem) + 10*var(--ux))*var(--m-price,1))}
  .mship-grid{grid-template-columns:1fr}
  .mship-teams{flex-direction:column;align-items:flex-start}
  .mship-notes ul{grid-template-columns:1fr}
}

/* Membership page — PREMIUM on its own row (2026-10-29). Side by side with Getting started
   (first, labelled "Start here"), the cheap package read as the way in; PREMIUM now spans
   the page alone and every other package, Getting started included, sits in one grid
   below. The wide card splits in two: what it is and the button on the left, what it
   contains on the right, so the button stays in the first screenful. */
.mship-row1{grid-template-columns:1fr}
.mship-feature{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,6fr);
  column-gap:calc(clamp(40px,4.5vw,96px) + 4.5*var(--ux))}
.mship-feature-a{display:flex;flex-direction:column;align-items:flex-start}
.mship-feature-a .mship-btn{margin-top:calc(clamp(28px,2.6vw,44px) + 2.6*var(--ux))}
.mship-feature-b{border-left:1px solid rgba(255,255,255,.14);
  padding-left:calc(clamp(40px,4.5vw,96px) + 4.5*var(--ux))}
.mship-feature-b .mship-list{margin-top:0}
.mship-feature .mship-name{max-width:14em}
@media (min-width:1181px){
  .mship-grid{grid-template-columns:repeat(4,minmax(0,1fr))}
}
@media (max-width:900px){
  .mship-feature{grid-template-columns:1fr}
  .mship-feature-b{border-left:0;padding-left:0;border-top:1px solid rgba(255,255,255,.14);
    margin-top:calc(clamp(28px,2.6vw,44px) + 2.6*var(--ux));padding-top:calc(clamp(28px,2.6vw,44px) + 2.6*var(--ux))}
}

/* Membership page — owned-package awareness (2026-08-29, checkout-basket §4). An owned
   card gets a muted "You have this until …" line above its button (button text becomes
   Renew, same href — fulfilment extends rather than re-grants); a PREMIUM holder sees
   "Included in your PREMIUM" in place of a section/Getting-started card's button, with
   its price muted (still visible, per spec, just de-emphasised); a section-pack holder
   without PREMIUM sees the PREMIUM card's eyebrow swap to "Upgrade to full access". */
/* Both .mship-big and .sec-card are flex columns whose button (.mship-btn / .sec-cta)
   carries its own margin-top:auto to sit flush at the card's bottom regardless of how
   much text runs above it. When an owned card's "You have this…" line is present, THAT
   line takes over the auto margin instead (pushing itself + the now-adjacent button down
   together) and the button's own auto margin is cancelled via the adjacent-sibling
   override below it — same specificity (two classes) so source order decides, and this
   block is appended after the original .mship-btn/.sec-cta rules. */
.mship-owned{font-size:var(--t-14);color:rgba(213,214,208,.72)}
.mship-big .mship-owned{margin-top:auto}
.mship-owned + .mship-btn{margin-top:.6em}
.sec-card .mship-owned{color:var(--muted)}
.sec-card .mship-owned{margin-top:auto}
.mship-owned + .sec-cta{margin-top:.6em;padding-top:calc(clamp(14px,1.2vw,20px) + 1.2*var(--ux))}

.mship-included{margin-top:auto;padding-top:1em;font-size:var(--t-145);color:rgba(213,214,208,.72)}
.sec-card .mship-included{margin-top:auto;padding-top:calc(clamp(14px,1.2vw,20px) + 1.2*var(--ux));
  border-top:1px solid var(--line);color:var(--muted);font-size:var(--t-145)}

.mship-price-row-muted .mship-price{color:rgba(255,255,255,.55)}
.mship-price-row-muted .mship-price-sub{color:rgba(213,214,208,.45)}
.sec-price-muted{color:var(--muted)}

/* ---------- About us — profile cards (2026-09-10) ----------
   /about/ is three things, not one column: the ink band (the shared section header,
   ground B), one card per person, then the bibliography. The cards sit on the page's own
   light ground — an earlier version put them on ink with the band, which made the two of
   them the page's subject but asked a reader to take two long bios off a dark ground
   (`git show 5c7defc^` has it). Content and structure come out of the stored page —
   site/app/about.php.

   Both sections are full-bleed <section>s (the base section{padding:var(--sec) 0}), not
   `.sec` — main .sec caps its width at --page. The measure comes from .page-n inside. */
/* the band above carries its own padding, and nothing changes ground between the cards
   and the bibliography — so this section keeps a fraction of the standard --sec at both
   ends instead of leaving a hole above and below the two boxes */
.page-head + .ab-who{padding-top:calc(var(--sec) * .33);padding-bottom:calc(var(--sec) * .28)}
.ab-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:calc(var(--gap) * 1.6)}
.ab-card{background:var(--white);border:1px solid var(--line);
  border-radius:calc(var(--r) * 1.15);padding:var(--pad)}
.ab-face{width:calc(clamp(84px,7vw,120px) + 7 * var(--ux));height:auto;aspect-ratio:1;
  object-fit:cover;object-position:50% 30%;border-radius:50%;background:var(--grey-1)}
.ab-name{font-family:var(--display);font-weight:400;font-size:var(--t-22);color:var(--deep);
  margin-top:.8em;letter-spacing:-.01em}
.ab-role{font-size:var(--t-14);color:var(--muted);margin-top:.25em}
.ab-creds{display:flex;flex-wrap:wrap;gap:6px;margin-top:1em;list-style:none;padding:0}
.ab-creds li{font-size:calc(clamp(11.5px,.8vw,14px) + .8 * var(--ux));letter-spacing:.03em;
  padding:.4em .8em;border-radius:999px;background:var(--grey-1);color:var(--deep-2)}
.ab-bio{margin-top:1.2em}
.ab-bio p{color:#3E4039;font-size:var(--t-145);line-height:1.62}
.ab-bio strong,.ab-bio b{color:var(--deep);font-weight:600}
.ab-bio a{color:var(--blue);border-bottom:1px solid var(--blue-pale);padding-bottom:1px;
  transition:border-color .25s}
.ab-bio a:hover{border-color:var(--blue)}

/* the bibliography: a year rail instead of 35 paragraphs that all start the same way */
.ab-pubs{padding-top:calc(var(--sec) * .28)}
.ab-pubs-h{font-size:var(--t-22)}
.ab-pubs-lede{font-size:var(--t-14);color:var(--muted);margin-top:.4em}
.ab-pub-list{list-style:none;padding:0;max-width:calc(920px + 78 * var(--uw));
  margin-top:calc(clamp(20px,1.8vw,32px) + 1.8 * var(--ux));
  border-top:1px solid var(--line)}
.ab-pub{display:grid;grid-template-columns:4.5em minmax(0,1fr);gap:1.4em;
  padding:calc(clamp(14px,1.1vw,20px) + 1.1 * var(--ux)) 0;border-bottom:1px solid var(--line)}
.ab-pub-yr{font-variant-numeric:tabular-nums;font-size:var(--t-14);color:var(--muted)}
/* the title carries the link (PubMed or DOI) on 32 of the 35. It keeps the site's link
   affordance — the pale blue rule — but not the blue text: 35 blue headlines in a row
   would read as a menu rather than as a bibliography. */
.ab-pub-t{display:block;font-size:var(--t-145);line-height:1.45;color:var(--deep)}
a.ab-pub-t{display:inline;text-decoration:underline;text-decoration-color:var(--blue-pale);
  text-decoration-thickness:1px;text-underline-offset:3px;transition:color .25s,text-decoration-color .25s}
a.ab-pub-t:hover{color:var(--blue);text-decoration-color:var(--blue)}
.ab-pub-cite{font-size:var(--t-14);line-height:1.55;color:var(--muted);margin-top:.3em}
.ab-pub-cite a{color:var(--muted);border-bottom:1px solid var(--line);word-break:break-word}
.ab-pub-cite a:hover{color:var(--blue)}

@media (max-width:860px){
  .ab-grid{grid-template-columns:1fr}
}
@media (max-width:640px){
  /* no room for a rail on a phone, and the year is in the citation anyway */
  .ab-pub{grid-template-columns:1fr}
  .ab-pub-yr{display:none}
}

/* ---------- Atlas companion list (/book/atlas/, 2026-09-10) ----------
   The book's loops have no page of their own, so this list is where they are watched. Each
   row is a button that unfolds a full-width player beneath it — it used to render a live
   player inside the row's own 84px thumbnail slot, 141 of them, none big enough to watch. */
/* the row is a button, and the save control sits beside it inside the shared .v-line */
.atl-row{appearance:none;flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:var(--gap);
  background:none;border:0;font:inherit;color:inherit;text-align:left;cursor:pointer;
  padding:.8em 0}
.atl-row:hover .row-title{color:var(--blue)}
.atl-still{position:relative}
.atl-glyph{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  background:rgba(10,10,11,.34);transition:background-color .2s var(--ease)}
.atl-row:hover .atl-glyph{background:rgba(10,10,11,.12)}
.atl-item.on .atl-glyph{background:rgba(10,10,11,.55)}
.atl-play{padding:calc(clamp(10px,.9vw,16px) + .9 * var(--ux)) 0
          calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux));
  max-width:calc(760px + 92 * var(--uw))}
.atl-play .sau-player{border-radius:var(--r);overflow:hidden}
.atl-item.on .atl-line{background:rgba(255,255,255,.5)}
@media (max-width:640px){
  .atl-row .row-dur{display:none}
  .atl-play{max-width:100%}
}

/* ---------- Save to your list (2026-09-11) ----------
   One control, four homes: the video page, an exercise, an Atlas row, and the library's
   cards and rows. It is a real form (no-JS posts and comes back), and site.js redraws it
   in place when JavaScript is there. Signed out, pressing it goes to sign-in and returns. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.sv-form{display:inline-flex;margin:0}
.sv{display:inline-flex;align-items:center;gap:.45em;font:inherit;font-size:var(--t-14);
  color:var(--deep-2);background:rgba(255,255,255,.6);border:1px solid var(--line);
  border-radius:999px;padding:.42em .9em;cursor:pointer;line-height:1.2;
  transition:color .2s var(--ease),border-color .2s var(--ease),background-color .2s var(--ease)}
.sv:hover{color:var(--deep);border-color:var(--grey-2)}
.sv .sv-ico{display:flex}
.sv .sv-ico svg path{transition:fill .2s var(--ease)}
.sv.on{color:var(--deep);border-color:rgba(255,191,0,.75);background:rgba(255,191,0,.16)}
.sv.on .sv-ico svg path{fill:var(--yellow);stroke:var(--yellow)}
.sv[disabled]{opacity:.55;cursor:default}

/* over a thumbnail: no label, dark glass, only as loud as it needs to be. Top RIGHT —
   the free-preview badge owns the top left, the duration the bottom right. */
.sv-card{position:absolute;top:8px;right:8px;z-index:3}
.sv-card .sv{background:rgba(20,22,18,.66);-webkit-backdrop-filter:var(--blur-sm);backdrop-filter:var(--blur-sm);
  border-color:rgba(255,255,255,.22);color:#fff;padding:.45em .5em}
.sv-card .sv:hover{border-color:rgba(255,255,255,.6)}
.sv-card .sv.on{background:rgba(255,191,0,.92);border-color:transparent;color:var(--deep)}
.sv-card .sv.on .sv-ico svg path{fill:var(--deep);stroke:var(--deep)}

/* on a dark ground (the article header, an exercise) */
.sv-ink .sv{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.22);color:rgba(236,237,232,.8)}
.sv-ink .sv:hover{color:#fff;border-color:rgba(255,255,255,.5)}
.sv-ink .sv.on{background:rgba(255,191,0,.18);border-color:rgba(255,191,0,.7);color:#F5D98B}
.sv-ink .sv.on .sv-ico svg path{fill:var(--yellow);stroke:var(--yellow)}

/* a card and its save control share a cell; the control is a sibling of the link, never
   inside it (one interactive element cannot contain another) */
.v-cell{position:relative}
.v-line{display:flex;align-items:center;border-top:1px solid var(--line)}
.v-line:hover{background:rgba(255,255,255,.5)}
.v-line > .v-row{flex:1 1 auto;min-width:0;border-top:0}
.v-line > .v-row:hover{background:none}
.v-line .sv-row{flex:0 0 auto;margin-left:.9em;margin-right:.2em}

/* the saved list in the account console */
.acct-n{display:inline-block;min-width:1.5em;padding:0 .35em;margin-left:.45em;border-radius:999px;
  background:var(--grey-1);color:var(--deep-2);font-size:var(--t-xs);text-align:center;line-height:1.6}
.sv-list{margin-top:calc(clamp(14px,1.2vw,22px) + 1.2 * var(--ux))}
.sv-item{display:flex;align-items:center;gap:var(--gap);padding:.75em 0;border-top:1px solid var(--line)}
.sv-item:last-child{border-bottom:1px solid var(--line)}
.sv-go{display:flex;align-items:center;gap:var(--gap);flex:1 1 auto;min-width:0}
.sv-thumb{flex:0 0 auto;width:calc(74px + 5 * var(--uw));aspect-ratio:16/10;border-radius:6px;
  overflow:hidden;background:#0A0A0B;border:1px solid var(--line)}
.sv-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.sv-thumb-x{background:var(--grey-1);display:flex;align-items:center;justify-content:center}
.sv-n{font-family:var(--display);font-size:var(--t-165);color:var(--deep-2)}
.sv-main{display:flex;flex-direction:column;gap:.15em;min-width:0}
.sv-t{font-size:var(--t-145);font-weight:500;color:var(--deep);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sv-go:hover .sv-t{color:var(--blue)}
.sv-sub{color:var(--muted)}
.sv-lock{color:var(--deep-2)}
@media (max-width:640px){ .sv-t{white-space:normal} }

/* the saved shortlist as a rail filter: a sibling of the section list, not one of its
   rows — it cuts across every section (2026-09-11) */
.lib-saved-row{width:100%}
.lib-saved-ico{flex:0 0 auto;display:flex;color:var(--muted);margin-right:.1em}
.lib-saved-row[aria-pressed="true"] .lib-saved-ico{color:var(--deep)}
.lib-saved-row[aria-pressed="true"] .lib-saved-ico svg path{fill:var(--yellow);stroke:var(--yellow)}
.lib-saved-more{margin-top:calc(clamp(16px,1.4vw,26px) + 1.4 * var(--ux));color:var(--muted)}
.lib-saved-more a{color:var(--deep);text-decoration:underline;text-underline-offset:3px}

/* the Atlas page's own toolbar: the same search field as the library, and the book's
   chapter numbering restored beside each chapter title (2026-09-11) */
.atl-tools-sec{padding:0 0 calc(clamp(6px,.5vw,10px) + .5 * var(--ux))}
.atl-tools{display:flex;align-items:center;gap:var(--gap)}
.atl-search{flex:1 1 auto}
.atl-ch{color:var(--muted);font-family:var(--sans);font-size:var(--t-14);font-weight:500;
  letter-spacing:.02em;margin-right:.5em;white-space:nowrap}
.atl-empty{color:var(--muted);padding:calc(clamp(18px,1.6vw,28px) + 1.6 * var(--ux)) 0}
.atl-clear{font:inherit;font-size:inherit;background:none;border:0;color:var(--deep);cursor:pointer;
  text-decoration:underline;text-underline-offset:3px;padding:0}
@media (max-width:640px){
  .atl-tools{flex-direction:column;align-items:stretch;gap:.6em}
  .atl-tools .lib-count{text-align:right}
  /* on a phone the title is the row, and the chapter name is the heading: let both wrap
     rather than ellipsing away the words that identify them */
  .atl-chapter .lib-sec-head h3{white-space:normal;overflow:visible}
  .atl-line .row-title{white-space:normal}
}

/* A library card revealed by its own #v{id} link — the only way to point at a video that
   has no page of its own. Brief, so it says "this one" without becoming decoration. */
.v-flash{animation:vflash 1.6s var(--ease)}
@keyframes vflash{0%,100%{box-shadow:0 0 0 0 rgba(255,191,0,0)}
  18%{box-shadow:0 0 0 4px rgba(255,191,0,.55)}
  70%{box-shadow:0 0 0 4px rgba(255,191,0,.35)}}
@media (prefers-reduced-motion:reduce){.v-flash{animation:none;outline:3px solid var(--yellow);outline-offset:3px}}

/* ---------- the section header's entrance ----------
   The site already has one way of showing a signal: a single unbroken stroke that does
   something (see .rf, the boundary above "how it works"). The header borrows it rather than
   inventing a second language — a hairline enters at the left edge of the viewport, crosses
   the head, and the title follows it in.

   The finished state is the DEFAULT: title and lede are at rest, fully legible, and the
   keyframes only play from a displaced start. Nothing here can leave text hidden — if the
   animation never runs, the header is simply a header. */
.page-head{position:relative;overflow:hidden}

.ph-sweep{position:absolute;left:0;top:0;bottom:0;width:100%;pointer-events:none;z-index:0}
.ph-sweep::before{content:"";position:absolute;top:0;bottom:0;left:0;width:38%;
  /* the travelling head is gold and tight; the tail fades back to the hairline colour */
  background:linear-gradient(90deg,transparent 0%,var(--line) 62%,var(--yellow) 97%,transparent 100%);
  opacity:.9;transform:translate3d(-110%,0,0);
  /* linear, like the pulse below the welcome: it is one sound in one tissue, so it does not
     accelerate. An ease-out here put the stroke off the right edge by 240ms of a 1050ms
     animation — it flashed past before the title had begun to arrive. */
  animation:ph-cross 1.25s linear both}
.page-head--ink .ph-sweep::before{
  background:linear-gradient(90deg,transparent 0%,rgba(236,237,232,.22) 62%,var(--yellow) 97%,transparent 100%)}

/* the title is carried in by the stroke: it starts a little behind and to the left, and
   settles as the stroke leaves. 90ms of overlap is what makes it read as "brought", not
   "faded in near". */
.page-head-txt>*{animation:ph-rise .62s cubic-bezier(.22,1,.36,1) both}
.page-head-eyebrow{animation-delay:.18s}
.page-head h1{animation-delay:.30s}
.page-head-lede{animation-delay:.42s}
.page-head-aside{animation:ph-rise .62s cubic-bezier(.22,1,.36,1) .48s both}

/* The band is 38% of the head, and a transform percentage is a percentage of the ELEMENT,
   not of its container: to clear the right edge its left edge must reach 100% of the head,
   which is 100/38 = 263% of itself. Ending at 140% parked it with its trailing edge at 91%
   — on a 4K header that stall is unmistakable, and it reads as the animation freezing.
   275% carries it fully off; the duration rises with the distance so the speed is unchanged. */
@keyframes ph-cross{
  0%{transform:translate3d(-105%,0,0)}
  100%{transform:translate3d(275%,0,0)}
}
@keyframes ph-rise{
  0%{opacity:0;transform:translate3d(-14px,0,0)}
  100%{opacity:1;transform:none}
}

/* Asked for less motion: no stroke, no staggered arrival, nothing to wait for. */
@media (prefers-reduced-motion:reduce){
  .ph-sweep{display:none}
  .page-head-txt>*,.page-head-aside{animation:none}
}

/* $100 off PREMIUM for a book holder (2026-09-16). The old price stays visible, struck
   through, so the reader can see what the book is worth rather than just a lower number. */
.mship-price-was{text-decoration:line-through;opacity:.45;margin-right:.45em;font-weight:500}
.mship-book-off{margin:.35em 0 0;font-size:.82em;line-height:1.4;opacity:.8}

/* returning members (2026-11-03): the thin notice above the top menu, signed-out visitors only */
.rn-bar{position:relative;z-index:61;background:#1A1C18;color:rgba(236,237,232,.88);
  font-size:var(--t-14);line-height:1.45;border-bottom:1px solid rgba(255,191,0,.35)}
.rn-bar p{max-width:var(--page);margin:0 auto;padding:.7em calc(var(--edge) + 2.4em) .7em var(--edge);text-align:center}
.rn-bar a{color:#FFBF00;font-weight:500;text-decoration:underline;text-underline-offset:3px;margin-left:.35em;white-space:nowrap}
.rn-bar a:hover{color:#fff}
.rn-bar a:focus-visible,.rn-x:focus-visible{outline:2px solid #FFBF00;outline-offset:2px}
.rn-x{position:absolute;right:calc(var(--edge) * .6);top:50%;transform:translateY(-50%);
  background:none;border:0;color:inherit;padding:.6em;cursor:pointer;line-height:0}
.rn-x:hover{color:#fff}
