/* ============================================================
   LIFEMAXXING (the file keeps its protocol.css name) — v3 · black,
   fluid, iOS surfaces, brand typography
   Brand bible v2.1 + the 2026-07-26 aesthetic redesign.
   Semantic colour is --verified and --fail ONLY. Path hues are
   identity-by-slot and never sit where a state could be read.
   ============================================================ */
:root{
  /* completely black, per the redesign */
  --bg:#000000;
  --s-1:rgba(255,255,255,.035);   /* card */
  --s-2:rgba(255,255,255,.055);   /* raised row */
  --s-3:rgba(255,255,255,.08);    /* pressed / hover */
  --line:rgba(255,255,255,.10);
  --line-strong:rgba(255,255,255,.20);
  /* the inner rule — separators INSIDE a panel are lighter than the panel's own
     edge, otherwise a seven-row card reads as a table and not as one object.
     Was written three times as a raw rgba; it is a token now. */
  --line-soft:rgba(255,255,255,.055);

  --text:#F5F6F8;
  --text-2:#A6AAB4;
  --text-3:#7E838F;

  --verified:#30D158;  --verified-dim:rgba(48,209,88,.14);
  --fail:#FF453A;      --fail-dim:rgba(255,69,58,.14);

  /* Pillar accents. DECORATIVE ONLY — none of them may sit where a reader
     could read it as a state. Green and red stay semantic and are not in here.
     The six live pillars (21 Sep 2026) are life, health, attraction,
     performer, aesthetic, social; the landing cards read --p-<id>. --p-looks
     and --p-redpill belong to the two retired pillars (now inside Attraction)
     and are kept only so an old stored id still resolves to a colour. */
  --p-health:#E8845A; --p-aesthetic:#E0A458; --p-looks:#E87FA6;
  --p-redpill:#9D8DF1; --p-performer:#7ED4FF; --p-social:#5FD3C4;
  --p-life:#E9D29A; --p-attraction:#E87FA6;
  /* The room is not a chapter, so it takes the site's own decorative accent
     rather than a seventh chapter colour that would imply it is one. */
  --p-community:#7ED4FF;

  --sans:"Geist",-apple-system,BlinkMacSystemFont,"SF Pro Display",Inter,system-ui,sans-serif;
  --mono:"Geist Mono","SF Mono","JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace;

  --w:1080px; --measure:62ch;

  /* iOS rounding — generous. The raw scale: */
  --r-1:12px; --r-2:18px; --r-3:24px; --r-4:32px; --r-5:44px; --r-pill:999px;
  /* …and what each step MEANS. Always reach for a named one; the numbers exist
     so the names have somewhere to point.

     The rule is nesting depth, the way iOS does it: a surface inside another
     surface always takes the next step DOWN, so corners stay concentric instead
     of a 32px box holding a 32px box. Sheet > panel > card > tile > field.

     ⚠️ There is no --r-l / --r-m / --r-s. Two components shipped square because
     they asked for tokens that never existed and `border-radius:var(--undefined)`
     silently computes to 0 (2026-08-19). If you invent a name, define it here. */
  --r-sheet:var(--r-5);   /* full-bleed sheet, modal, takeover        44 */
  --r-panel:var(--r-4);   /* a top-level panel spanning the column    32 */
  --r-card:var(--r-3);    /* a card inside a grid                     24 */
  --r-tile:var(--r-2);    /* a block nested inside a card             18 */
  --r-field:var(--r-1);   /* input, chip, the innermost thing         12 */

  /* The ice-blue decorative accent from the brand bible. It was READ in five
     places and DECLARED in none, which is the --r-l bug again with a worse
     consequence: `outline:2px solid var(--glow)` on an undefined token does not
     fall back, it computes to `outline-style:none` — and because
     .pcard:focus-visible (0,2,0) outranks the global :focus-visible (0,1,0), it
     erased the working ring instead of inheriting it. Six chapter cards and the
     video scrubber had no keyboard focus indicator at all. */
  --glow:#7ED4FF;
  /* Named separately so intent is legible: --glow is decorative (ordinals,
     tick marks), --focus is functional. They share a value today; if the
     accent ever changes, the focus ring should not silently follow it. */
  --focus:var(--glow);

  --ease:cubic-bezier(.22,1,.36,1);
  --d-tint:130ms; --d-control:260ms; --d-element:380ms; --d-seq:620ms; --d-reveal:900ms;
  /* A card opening. One notch slower than an element because the whole grid
     row moves with it, and it was read four times while declared nowhere —
     every use carried its own hardcoded 380ms fallback. */
  --d-panel:420ms;

  /* Every page ships viewport-fit=cover, so in landscape on a notched phone the
     display cutout eats into the gutter. max() keeps the token's own value on
     every normal device and only grows it where the hardware demands it. */
  --pad-x:max(clamp(20px,5vw,40px), env(safe-area-inset-left), env(safe-area-inset-right));
  --pad-sec:clamp(72px,10vw,132px);

  /* The sticky nav's height, measured: 13px inset x2 + a 40px min-height row +
     a 1px rule = 70px. It exists as a token because anything that sticks below
     the nav, or scrolls a heading into view under it, has to know this number —
     and two stylesheets were already using `var(--nav-h)`, which was never
     defined anywhere, so every calc() naming it silently voided the whole
     declaration. An undefined custom property does not fall back; it takes the
     property to its initial value, which for `top` is `auto` and for `padding`
     is `0`. That is a bug you cannot see on a desktop and cannot miss on a
     phone, where the legal pages had text touching both bezels. */
  --nav-h:70px;

  /* ---- ONE component padding scale ----
     Every card, panel and row on the site draws its inset from these four
     values and nothing else. Before this, five variants each carried their own
     hand-picked number (18/20/22/24/26) and the family read as five families. */
  --pad-row:14px;   /* a row's vertical inset */
  --pad-head:16px;  /* a panel header's vertical inset */
  --pad-in:22px;    /* the horizontal inset shared by every panel */
  --pad-body:24px;  /* a panel body's vertical inset */

  /* ---- the emoji layer (§7) — three sizes, and only three ---- */
  --em-mark:17px;   /* a marker inside its leading well */
  --em-label:15px;  /* a marker opening a mono label, sized up off the 12px line */
  --em-solo:24px;   /* a marker standing alone in an empty state */
  --well:34px;      /* the leading icon well on a row */

  /* ---- elevation (§5.5) — a surface step plus a hairline does the work;
     the shadow only seats the object and never fakes depth. This IS the
     ceiling the brand permits, written once. ---- */
  --seat:0 1px 2px rgba(0,0,0,.4), 0 8px 32px -12px rgba(0,0,0,.6);
  --toplight:inset 0 1px 0 rgba(255,255,255,.045);
}
*{box-sizing:border-box}
/* The UA's own `[hidden]{display:none}` is specificity 0,1,0 and loses to any
   class rule that sets `display` — so a component styled `display:flex` stays
   on screen while every script on the page believes it is hidden. That has now
   cost this project twice: the dial-code selector showed for every contact
   method, and the Pathway's gate overlay covered the working member area with
   "this page opens with your own link". This is the general fix; it must stay
   above every component sheet and must keep the !important. */
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;background:var(--bg)}
/* only the about page carries a sticky nav, so only it owes an anchor offset */
html:has(nav){scroll-padding-top:88px}
body{
  margin:0;background:var(--bg);color:var(--text);font-family:var(--sans);
  font-size:17px;line-height:1.6;-webkit-font-smoothing:antialiased;
  font-variant-numeric:tabular-nums;overflow-x:hidden;
}
h1,h2,h3{margin:0;font-weight:600;letter-spacing:-.032em;line-height:1.05;text-wrap:balance}
h1{font-size:clamp(40px,7vw,84px)}
h2{font-size:clamp(28px,4.4vw,50px)}
h3{font-size:clamp(18px,2vw,22px);letter-spacing:-.02em;line-height:1.25}
p{margin:0}
a{color:inherit}
img,video{max-width:100%;display:block}
::selection{background:rgba(255,255,255,.18)}

/* ---- FOCUS IS A LAW, NOT A STYLE (brand §5.5) ----
   White ring on everything focusable. Never green, never red — a focus ring is
   not a verdict. The old rule also set `border-radius:4px` on whatever had
   focus, which squared off every pill it touched mid-interaction; the ring now
   follows the element's own radius instead of imposing one. */
:focus-visible{outline:2px solid var(--text);outline-offset:3px}
/* things with no radius of their own still get a rounded ring rather than a box */
a:not([class]):focus-visible,.tlink:focus-visible,summary:focus-visible{border-radius:6px}
/* a control living inside an `overflow:hidden` panel would have its ring
   clipped, so it wears the ring on the inside */
.row:focus-visible,.ctl:focus-visible,.veil:focus-visible,.days .day:focus-visible{outline-offset:-3px}

/* ---- HIT TARGETS ----
   ≥44px on touch, per brand §5.5. Scoped to coarse pointers so a mouse-driven
   1440px layout is not padded out to phone proportions to satisfy a phone rule.
   Static chips are labels, not controls, so they are deliberately not in here.
   This block is a FLOOR: it is written at a specificity that per-component
   tuning further down the file cannot accidentally undercut, because a control
   that shrinks below the target size on the one device that is all touch is
   backwards. */
@media(pointer:coarse){
  .toc a,.nav-l a,.foot .tlink,.stepback{min-height:44px;display:inline-flex;align-items:center}
  .slots .slot,.days .day{min-height:48px}
  .controls .ctl{min-width:44px;height:44px}
}

/* ---- the fluid stage ----
   #fluid is POSITIONED, so it paints above static in-flow content, not behind
   it — a positioned z-index:0 box beats an unpositioned sibling no matter what
   the source order says. Anything not lifted over it is invisible with nothing
   wrong in the DOM to find: correct geometry, opacity 1, checkVisibility()
   true, and a blank screen. The Pathway's entire <main> was buried this way
   until 2026-08-09, because it is the one page with no .page wrapper.
   `body>main` catches it without touching the doc pages, whose <main> already
   sits inside .page. Any new top-level container needs the lift too. */
#fluid{position:fixed;inset:0;width:100%;height:100%;z-index:0;pointer-events:none;display:block}
.page,body>main{position:relative;z-index:1}

/* ---- the tap glow (touch devices only) ----
   What phones get instead of the cursor fluid: a soft light where the finger
   lands, then nothing. Two layers make it read as light rather than as a
   circle — a wide, very faint bloom and a small brighter core, both blurred,
   both leaving no edge behind. It sits UNDER .page, so it lights the page
   from behind rather than washing over the text.

   Deliberately not a "ripple": a ring reads as a Material touch state, i.e. as
   UI feedback promising something happened. Nothing happens here — it is
   ambience, and it should look like light, not like a control. */
.tapglow{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;contain:strict}
.tapglow-d{
  position:absolute;
  /* A radial gradient, NOT stacked box-shadows. Shadows spread OUTWARD from the
     element's edge, so the element's own middle ends up dimmer than the ring
     around it and the glow renders as a faint donut. A gradient is brightest at
     the centre by construction, which is what light actually does. */
  width:300px;height:300px;border-radius:50%;
  background:radial-gradient(circle closest-side,
    rgba(255,255,255,.20) 0%,
    rgba(255,255,255,.13) 18%,
    rgba(255,255,255,.055) 40%,
    rgba(255,255,255,.018) 62%,
    transparent 78%);
  transform:translate(-50%,-50%) scale(.35);
  opacity:0;
  animation:tapbloom 1150ms cubic-bezier(.19,1,.32,1) forwards;
  will-change:transform,opacity;
}
@keyframes tapbloom{
  0%  {opacity:0;   transform:translate(-50%,-50%) scale(.35)}
  14% {opacity:1;   transform:translate(-50%,-50%) scale(.92)}
  100%{opacity:0;   transform:translate(-50%,-50%) scale(1.55)}
}
@media(prefers-reduced-motion:reduce){.tapglow{display:none}}

/* ---- mono law: if it is a fact, it is mono ----
   Sizes and tracking now follow the §6.1 table exactly rather than approximately.
   The tracking law: uppercase mono ≤12px tracks .12–.14em; 13–14px tracks
   .08–.10em; LOWERCASE mono data never tracks above .02em, because a tracked-out
   log line reads as a label pretending to be a fact. Every one of these was off
   by enough to make the mono layer look like an afterthought next to the sans. */
.lab{
  font-family:var(--mono);font-size:12px;font-weight:500;text-transform:uppercase;
  letter-spacing:.14em;color:var(--text-3);line-height:1.15;display:block;
}
.dat{font-family:var(--mono);font-size:13px;letter-spacing:.02em;color:var(--text-2);font-variant-numeric:tabular-nums}
.dat b{color:var(--text);font-weight:500}
.dat.sm{font-size:11px;text-transform:uppercase;letter-spacing:.12em;color:var(--text-3)}
.lead{font-size:clamp(16.5px,1.7vw,19.5px);color:var(--text-2);max-width:var(--measure);text-wrap:pretty}

/* ============================================================
   THE EMOJI LAYER — brand §7
   Emoji are the only drawn illustration system, used as a locked icon set.
   They are STATUS AND SECTION MARKERS: never inside a headline, never inside a
   sentence, never more than one per line, always from the approved set.
   There are exactly three slots, and a marker outside them is a defect:
     1. the leading well on a grouped row .......... .row .ic
     2. the opening character of a mono label ...... .lab, .card-head .t, .pwhen
     3. a marker standing alone in an empty state
   Apple glyphs are square, sit optically high, and render at the font-size of
   the run they are in — which means a 12px uppercase label renders a 12px emoji
   that reads as lint. Each slot therefore pays an explicit optical correction
   rather than being left on the baseline.
   ============================================================ */
/* Slot 2: size the marker up off the label's own size and buy it a gap. The
   label's line-height is raised to 1.15 above so the taller glyph does not
   clip. Scoped to labels whose first character is always a marker. */
.lab::first-letter,.card-head .t::first-letter{
  font-size:var(--em-label);letter-spacing:.34em;
}

.chip{
  display:inline-flex;align-items:center;gap:7px;font-family:var(--mono);font-size:11px;font-weight:500;
  text-transform:uppercase;letter-spacing:.12em;padding:0 12px;height:27px;border:1px solid var(--line);
  border-radius:var(--r-pill);color:var(--text-3);white-space:nowrap;line-height:1;background:var(--s-1);
  font-variant-numeric:tabular-nums;
  /* uppercase mono has no descenders, so padding-centring always sits it low;
     a flex box centres the cap-height instead */
}
/* an empty status chip is not a status. The markup ships blank rather than
   ships "loading…", so with no JS the card never claims to be fetching. */
.chip:empty{display:none}
.chip.ok{color:var(--verified);border-color:rgba(48,209,88,.4);background:var(--verified-dim)}
.chip.no{color:var(--fail);border-color:rgba(255,69,58,.4);background:var(--fail-dim)}

/* ---- iOS controls ---- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  font-family:var(--sans);font-size:16.5px;font-weight:600;letter-spacing:-.01em;
  padding:17px 32px;border-radius:var(--r-pill);border:1px solid transparent;
  background:var(--text);color:#000;text-decoration:none;cursor:pointer;
  transition:transform var(--d-control) var(--ease),opacity var(--d-tint) ease;
}
.btn:hover{transform:translateY(-1.5px)}
.btn:active{transform:scale(.975)}
.btn.ghost{background:var(--s-2);color:var(--text);border-color:var(--line);backdrop-filter:blur(20px)}
.btn.ghost:hover{background:var(--s-3)}
.btn[disabled]{opacity:.4;cursor:not-allowed;transform:none}
.tlink{
  font-family:var(--sans);font-size:15.5px;color:var(--text-2);text-decoration:none;
  border-bottom:1px solid var(--line-strong);padding-bottom:2px;background:none;border-left:0;border-right:0;border-top:0;cursor:pointer;
  transition:color var(--d-tint) var(--ease),border-color var(--d-tint) var(--ease);
}
.tlink:hover{color:var(--text);border-color:var(--text)}

/* ---- about page contents index ---- */
.toc{display:flex;flex-wrap:wrap;gap:8px;margin-top:26px}
.toc a{
  display:inline-flex;align-items:center;min-height:38px;
  font-family:var(--mono);font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.12em;
  padding:0 15px;border:1px solid var(--line);border-radius:var(--r-pill);
  color:var(--text-3);text-decoration:none;background:var(--s-1);
  transition:color var(--d-tint) ease,background var(--d-tint) ease,border-color var(--d-tint) ease;
}
.toc a:hover{color:var(--text);background:var(--s-2);border-color:var(--line-strong)}

/* ---- nav ---- */
nav{position:sticky;top:0;z-index:60;background:rgba(0,0,0,.55);backdrop-filter:blur(28px) saturate(1.4);border-bottom:1px solid var(--line)}
.nav-in{max-width:var(--w);margin:0 auto;padding:13px var(--pad-x);display:flex;align-items:center;gap:22px}
.wm{font-family:var(--mono);font-size:13.5px;font-weight:500;letter-spacing:.3em;text-transform:uppercase;text-decoration:none;margin-right:auto}
.nav-l{display:flex;gap:8px}
.nav-l a{
  display:inline-flex;align-items:center;min-height:40px;
  font-size:15px;color:var(--text-2);text-decoration:none;padding:0 14px;border-radius:var(--r-pill);
  transition:color var(--d-tint) ease,background var(--d-tint) ease;
}
.nav-l a:hover{color:var(--text);background:var(--s-2)}
.nav-l a[aria-current="page"]{color:var(--text);background:var(--s-2)}
.nav-cta{padding:10px 20px;font-size:15px}
@media(max-width:720px){.nav-l a{padding:8px 11px;font-size:14px}.nav-cta{padding:9px 16px;font-size:14px}}
/* Below 560 the row cannot hold wordmark + two links + a three-word pill: the
   CTA wrapped to three lines, took the bar to 114px against an 88px anchor
   offset, and pushed itself to 1px off the viewport edge. The wordmark already
   links home, so the pair goes and the CTA stays on one line. */
@media(max-width:560px){
  .nav-in{gap:12px}
  .nav-l{display:none}
  .nav-cta{white-space:nowrap;padding:11px 16px}
}
/* LIFEMAX CLUB is four characters longer than PROTOCOL and, unlike it, has a
   space in it — so the wordmark can now BREAK, not just crowd. Measured at
   320px on about.html beside the widest CTA ("Join or book a call", 154px): it
   folded to "LIFEMAX / CLUB" and took the bar to 72px. nowrap keeps it one
   line; the tracking tightens in steps rather than the word shrinking (it is
   the name, so it keeps its size and gives up air), and under 360 the CTA
   gives up a few px of padding so the pair fits a 280px row. */
.wm{white-space:nowrap}
@media(max-width:560px){.wm{letter-spacing:.22em}}
@media(max-width:360px){.wm{letter-spacing:.11em}.nav-cta{padding:11px 12px}}

/* ---- layout ---- */
.wrap{max-width:var(--w);margin:0 auto;padding:0 var(--pad-x)}
.sec{padding:var(--pad-sec) 0;position:relative}
/* The rule between sections fades out at both ends rather than butting into the
   gutter. A hairline that stops dead is the loudest thing on a black page. */
.sec + .sec{border-top:0}
.sec + .sec:before{
  content:"";position:absolute;top:0;left:0;right:0;height:1px;background:var(--line);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent);
}
.head{display:flex;flex-direction:column;gap:16px;margin-bottom:38px;max-width:var(--measure)}
.head .lab{margin-bottom:-2px}
/* The authored line breaks in these headings are set for a wide measure. Below
   620px they fight the wrap and leave one-word lines ("you", "alone,",
   "included."), so they go inert and text-wrap:balance takes over. */
/* Author line breaks are dropped on narrow screens so the heading reflows to
   the column instead of breaking where a desktop measure wanted it.
   ⚠️ REQUIRES A SPACE AFTER THE <br> IN THE MARKUP — `A.<br>B` renders as "A.B"
   once the break is gone, because there is no whitespace left between the two
   text nodes. Write `A.<br> B`. Four headings shipped fused before this was
   noticed (2026-08-19). */
@media(max-width:620px){.head h1 br,.head h2 br{display:none}}
/* The About page's opening heading is an <h1> for the document outline, and it
   is meant to sit at section scale, not hero scale — the hero on that page is
   the page itself. Semantics changed; the design did not. */
body.about .head h1{font-size:clamp(28px,4.4vw,50px)}

/* ---- the founding places ----
   A real count from the worker, or nothing at all. See index.html and site.js:
   this element ships `hidden` and is only ever revealed by a successful fetch,
   so a page that cannot reach the server shows no number rather than a made-up
   one. It is the difference between scarcity and a scarcity trick. */
.places{width:100%;display:flex;flex-direction:column;gap:7px;margin:2px 0 4px}
.places-bar{
  height:4px;border-radius:var(--r-pill);background:var(--s-3);overflow:hidden;
}
.places-bar i{
  display:block;height:100%;width:0;border-radius:var(--r-pill);
  background:linear-gradient(90deg,rgba(245,246,248,.5),var(--text));
  transition:width var(--d-seq) var(--ease);
}
#placesTxt{letter-spacing:.1em;color:var(--text-3);font-size:10px}
#placesTxt b{color:var(--text);font-weight:500}
@media(prefers-reduced-motion:reduce){.places-bar i{transition:none}}

/* The one piece of fine print left on the landing page. It sits under the pay
   button because that is the only place it is load-bearing — everything else
   moved to /legal, which is what "clean" meant. */
.door-fine{
  display:block;margin-top:10px;
  font-size:12px;line-height:1.5;color:var(--text-3);text-wrap:pretty;
}
.door-fine a{color:var(--text-2);text-decoration:underline;text-underline-offset:2px;text-decoration-color:var(--line-strong)}
.door-fine a:hover{color:var(--text)}


/* Visually hidden, still announced. Lived only in pathway.css, which the
   landing page does not load — so a label marked sr-only on index.html
   rendered as ordinary text above the field it was meant to name. A utility
   class used across pages belongs in the file every page has. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

/* ============================================================
   THE WAITING LIST — one strip
   Was a <label>Email</label> above a bare input inside a card: the label sat
   beside the field at desktop width, the field was half the width of the button
   under it, and the whole thing read like a form somebody forgot to style. The
   ask is one address, so it is one row — field and button sharing a rim, the
   way a search bar does, which is the pattern everybody already knows how to
   use. It stacks below 560px rather than squeezing a 20-character field next
   to a 200px button.
   ============================================================ */
.waitstrip{max-width:min(640px,100%);margin:0 auto 30px;width:100%}
/* Inside a door it is a field in a card, not a band across the page: full
   width of its column, no auto-centring, and the fine print reads left with
   the paragraph above it rather than floating in the middle. */
.door .waitstrip{margin:2px 0 0}
.door .waitstrip-fine{text-align:left;margin-left:2px}
.waitstrip-row{
  display:flex;gap:8px;align-items:center;
  background:var(--s-1);border:1px solid var(--line-strong);
  border-radius:var(--r-pill);padding:7px 7px 7px 8px;
  backdrop-filter:blur(24px) saturate(1.25);
  box-shadow:var(--seat),var(--toplight);
  transition:border-color var(--d-tint) ease,background var(--d-tint) ease;
}
/* The rim lights on focus, not each control — the row is the control. */
.waitstrip-row:focus-within{border-color:rgba(255,255,255,.34);background:var(--s-2)}
.waitstrip-row input{
  flex:1;min-width:0;background:none;border:0;outline:none;
  color:var(--text);font:inherit;font-size:16px;padding:12px 14px;
}
.waitstrip-row input::placeholder{color:var(--text-3)}
.waitstrip-row .btn{flex:none;padding:14px 24px;font-size:15px;white-space:nowrap}
.waitstrip-fine{
  margin:11px 2px 0;font-size:12.5px;line-height:1.5;color:var(--text-3);text-align:center;
}
/* Said by the worker, in its own voice, once something has actually happened. */
.waitstrip-fine.ok{color:var(--verified)}
.waitstrip-fine.no{color:var(--fail)}

@media (max-width:560px){
  .waitstrip-row{flex-direction:column;align-items:stretch;border-radius:var(--r-3);padding:8px;gap:8px}
  .waitstrip-row input{padding:14px 12px;text-align:center}
  .waitstrip-row .btn{width:100%;justify-content:center}
  .waitstrip-fine{text-align:center}
}

/* ============================================================
   THE LAST WORD — the closing beat on the landing page
   Not another ask. Somebody who has read the whole page and pressed neither
   door wants to know whether the person teaching it is worth an hour a week,
   and the free way to find that out is the last thing they should see.
   ============================================================ */
.endcard{
  display:flex;flex-direction:column;align-items:center;text-align:center;gap:14px;
  padding:clamp(34px,5vw,56px) clamp(20px,4vw,44px);
  border:1px solid var(--line);border-radius:var(--r-4);
  background:var(--s-1);box-shadow:var(--seat),var(--toplight);
  backdrop-filter:blur(24px) saturate(1.25);
}
.endcard .lab{color:var(--text-3)}
.endcard h2{font-size:clamp(26px,4vw,44px)}
.endcard .lead{max-width:52ch;margin:0}
.endacts{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:14px 22px;margin-top:10px;
}
@media(max-width:520px){
  .endacts{flex-direction:column;align-items:stretch;width:100%}
  .endacts .btn{width:100%;justify-content:center}
  .endacts .tlink{text-align:center}
}

/* ---- the legal row in the site footer ----
   Lives here, not in legal.css: index.html and about.html carry this footer and
   never load that stylesheet, so the links shipped completely unstyled. */
.foot .legal{display:flex;flex-wrap:wrap;gap:6px 16px;align-items:center}
.foot .legal a{
  color:var(--text-3);text-decoration:none;font-size:13px;
  display:inline-flex;align-items:center;min-height:32px;
}
.foot .legal a:hover{color:var(--text-2)}
@media(pointer:coarse){.foot .legal a{min-height:44px}}

/* ============================================================
   THE SURFACE FAMILY
   Every panel on this site is the same object at a different size: one surface
   step, one hairline, one seat shadow, one top-light. Before this each variant
   carried its own background, its own border and its own blur, which is why
   five components read as five families instead of one system.
   Only two things vary, and both come off a scale:
     radius  — --r-4 for a full-width panel, --r-3 for a card inside a grid
     padding — --pad-in horizontally, everywhere, without exception
   ============================================================ */
.card,.verd,.rows,.price{
  position:relative;overflow:hidden;background:var(--s-1);
  border:1px solid var(--line);
  backdrop-filter:blur(24px) saturate(1.25);
  box-shadow:var(--seat),var(--toplight);
}
.card,.verd{border-radius:var(--r-panel)}
.rows,.price{border-radius:var(--r-card)}

/* One header treatment, shared by .card and .verd. It is a distinct surface
   step from the body so the panel reads as titled rather than merely bordered. */
.card-head{
  display:flex;align-items:center;gap:10px 12px;flex-wrap:wrap;
  padding:var(--pad-head) var(--pad-in);
  border-bottom:1px solid var(--line);
  background:rgba(255,255,255,.022);
}
/* .t is a real <h2> on the Pathway so the page has a document outline; the
   reset keeps it looking exactly like the mono label it has always been. */
.card-head .t{margin:0;font-family:var(--mono);font-size:12px;font-weight:500;text-transform:uppercase;letter-spacing:.14em;color:var(--text-3);line-height:1.2}
.card-head .r{margin-left:auto}
@media(max-width:600px){.card-head{padding:14px 16px;gap:8px}}

/* ============================================================
   THE GROUPED LIST — the workhorse. It carries the offer on the landing and
   most of the about page, so it is held to the standard of a well-made iOS
   grouped list rather than a bordered <ul>.
   ============================================================ */
.rows{--row-px:var(--pad-in);--row-gap:16px}
.row{
  position:relative;
  display:grid;grid-template-columns:var(--well) 1fr auto;
  column-gap:var(--row-gap);align-items:center;
  padding:var(--pad-row) var(--row-px);
  transition:background var(--d-tint) ease;
}
/* iOS separator inset: the hairline begins where the TEXT begins, not at the
   panel edge, so the icon column reads as a rail running down the card. It is
   drawn on the row below rather than as a border, so the last row needs no
   override and no row can ever double up a rule. */
.row + .row:before{
  content:"";position:absolute;top:0;right:0;height:1px;background:var(--line-soft);
  left:calc(var(--row-px) + var(--well) + var(--row-gap));
}

/* the leading marker sits in a well — a real object with a surface step and a
   hairline, which is what stops a bare emoji reading as a stray character */
.row .ic{
  width:var(--well);height:var(--well);border-radius:10px;
  display:flex;align-items:center;justify-content:center;
  font-size:var(--em-mark);line-height:1;
  background:var(--s-2);border:1px solid var(--line);box-shadow:var(--toplight);
  /* Apple glyphs carry their own internal padding and sit high in the em box */
  padding-top:1px;
}

/* title and sub are one optical unit: the sub hangs off the title on a tight
   3px gap and both share the title's left edge, so the eye reads one block
   against the trailing value rather than three separate things */
.row .tx{min-width:0;display:flex;flex-direction:column;gap:3px}
/* direct children only — the landing has a <span id="tzname"> nested INSIDE a
   title, and the old descendant selector turned it into a block-level sub,
   breaking that sentence across two lines in the wrong colour */
.row .tx > b{font-weight:600;font-size:16px;letter-spacing:-.012em;line-height:1.3}
.row .tx > span{color:var(--text-2);font-size:14.5px;line-height:1.45;text-wrap:pretty}
.row .tx > b span{font:inherit;color:inherit;display:inline}

/* the trailing value is a fact, so it is mono, right-aligned and tabular —
   lowercase mono data never tracks above .02em (§6.1), and .05em was wrong */
.row .v{
  font-family:var(--mono);font-size:12.5px;letter-spacing:.02em;color:var(--text-3);
  white-space:nowrap;font-variant-numeric:tabular-nums;justify-self:end;text-align:right;
}
/* an empty value is not a value — the filter rows ship blank rather than
   inventing a status for a row that has none */
.row .v:empty{display:none}

/* A sealed row recedes by identity, not by opacity. A blanket .55 dimmed the
   hairline and the text together and pushed the sub below AA; the row is now
   legible and still plainly secondary. */
.row.locked .ic{background:transparent;border-color:rgba(255,255,255,.06);opacity:.65}
.row.locked .tx > b{color:var(--text-2);font-weight:500}
.row.locked .tx > span{color:var(--text-3)}

/* A row is INERT unless it is genuinely a link or a button. The hover tint is
   the only thing that says "pressable", so it never appears on a row that is
   not — the site currently ships none, and the day one does it will already
   look and behave right. */
a.row,button.row{
  width:100%;text-align:left;font:inherit;color:inherit;text-decoration:none;
  border:0;background:transparent;cursor:pointer;padding-right:calc(var(--row-px) + 16px);
}
a.row:hover,button.row:hover{background:var(--s-2)}
a.row:active,button.row:active{background:var(--s-3)}
a.row:after,button.row:after{
  content:"";position:absolute;right:var(--row-px);top:50%;width:7px;height:7px;
  border-right:1.5px solid var(--text-3);border-top:1.5px solid var(--text-3);
  transform:translateY(-50%) rotate(45deg);
}

@media(max-width:600px){
  .rows{--row-px:16px;--row-gap:13px;--well:30px}
  /* The trailing value drops under the text here, which makes a row up to
     200px tall. Centred, the marker floated 20–65px below the title it labels,
     so it top-aligns to the title's cap height instead. */
  .row{padding:13px var(--row-px);grid-template-columns:var(--well) 1fr;align-items:start}
  .row .ic{border-radius:9px;font-size:15.5px;margin-top:-1px}
  .row .v{grid-column:2;justify-self:start;text-align:left;margin-top:5px}
}

/* ---- reveal / first-load entrance ---- */
/* SCROLL reveals stay retired (2026-08-04). What exists here instead is a
   one-time entrance on first load (2026-08-05, Reo's call), built the only
   safe way round:

     content is visible BY DEFAULT, and the entrance is an animation FROM a
     faded, offset state TO the natural one.

   If `html.enter` is never added, or the animation never runs, the page is
   already correct. The opposite shape — hide, then reveal on an event — cost
   this file three separate "content is invisible" bugs (a background-tab
   load, a zero-height viewport, and an observer that never fired). Nothing
   here may ever make visibility depend on a frame, an observer or a timer. */
.rv{opacity:1;transform:none;transition:none}

html.enter .rv{animation:riseIn .62s cubic-bezier(.22,1,.36,1) backwards}
@keyframes riseIn{from{opacity:0;transform:translateY(14px)}}

/* A short stagger down the hero so it arrives as one movement rather than six
   things appearing at once. The delays are deliberately small — a landing page
   that makes you wait to read it is a slow page wearing a costume. */
html.enter .hero .wm{animation-delay:.02s}
html.enter .hero h1{animation-delay:.09s}
html.enter .hero .lead{animation-delay:.16s}
html.enter .player{animation-delay:.23s}
html.enter .herofoot{animation-delay:.31s}
html.enter main .rv{animation-delay:.35s}

/* the fluid field comes up under everything rather than snapping on */
html.enter #fluid{animation:fluidIn 1.2s ease-out backwards}
@keyframes fluidIn{from{opacity:0}}

@media(prefers-reduced-motion:reduce){
  .rv{opacity:1!important;transform:none!important;transition:none!important}
  html{scroll-behavior:auto}
  #fluid{display:none}
  *{animation:none!important}
  /* The gate is the most aggressive motion on the site, so it is the part that
     most owes this setting. The information survives — the lock message still
     appears and the gate still unlocks — only the movement and the red flood go.
     `animation:none` alone did not touch these, because they are transitions. */
}

/* ============================================================
   HOME — the gate
   ============================================================ */
/* The whole hero fits one screen and the VIDEO is the point. The text block
   is budgeted at --hero-text and the player takes what is left, so the full
   16:9 frame is always visible without scrolling. */
.hero{
  /* MEASURED, not guessed. This is everything in the hero that is not the
     player: padding, wordmark, h1, lead, price line, the player's own top
     margin, the lockbar, and the reserved 76px herofoot. At 1440 it comes to
     493px in the LOCKED state, which is the state a first-time visitor sees.
     The old 352px was 141px short, so the hero overflowed the viewport by 9px
     at every height and the peek below was NEGATIVE — the exact opposite of
     what the two variables below are for. */
  /* MEASURED at 1440×900 against the live page: wordmark 40 · h1 109 ·
     two-line lead 78 · player top margin 26 · lockbar 34 · herofoot 76 ·
     hero padding 48+34. The old 494 was a LOCKED-state budget that included a
     three-line lead and a separate price row, both now gone, and it was
     over-reserving ~160px — which the 900px cap then compounded, leaving the
     player at 487px on a 1440 screen. */
  --hero-text:263px;
  /* Enough of the blurred content shows below the fold that a visitor can see
     there IS something behind the gate — the reason to sit through the video.
     Trimmed with the same care: this is the only thing still competing with
     the frame for height. */
  /* Down to a sliver. The blurred content still breaks the fold line, which is
     all it needed to do — the frame wanted the rest. */
  --peek:8px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:clamp(14px,1.7vh,22px) var(--pad-x) clamp(10px,1.3vh,15px);text-align:center;position:relative;
}
/* the wordmark — the landing has no nav, so this is the only place the thing
   a stranger is being asked to spend four minutes on is actually named */
.hero .wm{margin:0 0 9px;color:var(--text-2)}
/* Marker highlight — a warm white-to-yellow wash (Reo, 2026-08-05).
   It was flat white on the rule that a hue here could be mistaken for a state.
   Yellow is safe on that test: the semantic pair is green = verified and
   red = locked/failed, and yellow is neither, so it reads as emphasis rather
   than as a verdict. It stays the ONLY hue in the hero. */
.hl{
  background:linear-gradient(100deg,#FFFFFF 0%,#FDF3C7 42%,#FCE38A 100%);
  color:#000;padding:0 .14em;border-radius:6px;
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
}
/* line-height overrides the global 1.05: with a hard <br> between "Fix your
   habits," and "fix your life." the two lines were nearly touching, and the
   highlight box on the first line made the collision obvious. */
.hero h1{max-width:17ch;margin-inline:auto;font-size:clamp(26px,3.1vw,41px);letter-spacing:-.035em;line-height:1.22}
/* Two lines, deliberately larger than body copy — this is the instruction that
   makes the gate make sense, so it is sized to be read, not skimmed. The price
   line it replaced said the same thing twice; the offer is stated once now. */
.hero .lead{
  margin:10px auto 0;text-align:center;max-width:48ch;
  font-size:clamp(15px,1.38vw,19.5px);line-height:1.34;font-weight:500;
  letter-spacing:-.015em;color:var(--text);
}
.hero .lead .lead-2{color:var(--text-2)}
/* One fixed-height slot holding both hero-foot states stacked in the same grid
   cell. Nothing reflows when the gate opens, so the frame the visitor is still
   watching does not jump, and the landing spends the row only once. */
.herofoot{display:grid;place-items:center;margin-top:8px;min-height:38px}
.herofoot > *{grid-area:1/1}
/* Two live doors, side by side. The stacked single-cell layout above existed so
   the lockbar and the post-unlock nudge could occupy the same 38px without the
   hero reflowing when the gate opened; there is no gate and no second state, so
   the doors get their own flow row. */
.herodoors{display:flex;grid-auto-flow:column;gap:12px;flex-wrap:wrap;justify-content:center;margin-top:18px;min-height:0}
.herodoors > *{grid-area:auto}
.herodoors .btn{min-width:216px}
@media (max-width:520px){
  .herodoors{width:100%;flex-direction:column;gap:10px}
  .herodoors .btn{width:100%;min-width:0}
}
/* Phone: the h1 drops to ~30px and the lead to ~17px, so the text block is
   genuinely shorter. Peek also shrinks — on a 390×844 screen the old 104px
   cost ~185px of frame width, which is the difference between a video you
   watch and a thumbnail you scroll past. */
@media(max-width:720px){.hero{--hero-text:246px;--peek:72px}}

/* ---- desktop: the wordmark stops charging the stack ----
   It is the only place the landing names itself, so it stays on screen — but
   centred in the flow it cost 30.6px of hero height, and every pixel of hero
   chrome is 1.78px of 16:9 video width. Lifted into the corner it costs zero.
   Only above 1000px: below that the player is pinned by the min(100%,…) term
   and this would buy nothing while crowding a narrow header. */
@media(min-width:1000px){
  .hero .wm{position:absolute;top:clamp(14px,1.7vh,22px);left:var(--pad-x);margin:0}
}

.player{
  position:relative;margin:clamp(9px,1.3vh,14px) auto 0;border:0;
  /* Width derived from the height left over, so the 16:9 frame always fits.
     max() floors it — a short or not-yet-measured viewport must never be able
     to collapse the player to nothing. */
  /* The 900px cap was the binding constraint on any screen taller than ~1030px
     and made the frame the smallest thing in the hero. 1180px lets it run to
     roughly the reference's proportions (a 1000px frame on a 1440×900 screen)
     while the height term still guarantees the whole 16:9 fits the fold. */
  width:min(100%, 1600px, max(300px, calc((100svh - var(--hero-text) - var(--peek)) * 1.7778)));
  /* Close to a raw video frame: modest rounding, no border, no shadow. A
     bordered, heavily-rounded, shadowed card reads as a widget; the point of
     this element is that it is the film. */
  border-radius:var(--r-2);background:#000;
  /* NOT overflow:hidden — the control chrome is absolutely positioned inside
     .player-body, which owns the clip. */
  overflow:visible;
}
.player-body{position:relative;aspect-ratio:16/9;background:#000;border-radius:var(--r-2);overflow:hidden}
.player-body video{width:100%;height:100%;object-fit:cover}
.veil{
  position:absolute;inset:0;z-index:3;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;
  background:rgba(0,0,0,.34);border:0;cursor:pointer;color:var(--text);
  font-family:var(--sans);backdrop-filter:blur(2px);
}
/* No circle, no label — the mark alone. A play triangle is the most legible
   glyph in software and needs neither a chrome ring nor a sentence telling a
   visitor what it does. */
.veil-play{
  width:clamp(44px,7vw,60px);height:auto;fill:var(--text);
  filter:drop-shadow(0 2px 18px rgba(0,0,0,.55));
  animation:veil-breathe 2600ms var(--ease) infinite;
  transition:transform var(--d-control) var(--ease);
}
/* The third and last sanctioned loop (brand §10.2). Like the scroll nudge it is
   an idle affordance, not decoration: it stops permanently the moment it is
   used, and it never scales beyond a hair so it reads as breathing rather than
   throbbing. */
@keyframes veil-breathe{
  0%,100%{transform:scale(1);opacity:.95}
  50%{transform:scale(1.045);opacity:1}
}
/* The wrapper survives the removal of the pulse rings (Reo, 2026-08-05 — the
   rings read as a notification, not an invitation). It still earns its place:
   it gives the mark a fixed square box to be centred in, so the glyph does not
   shift by a pixel when the veil's other children change. */
.veil-mark{position:relative;display:grid;place-items:center;width:clamp(64px,10vw,86px);height:clamp(64px,10vw,86px)}
.veil-mark .veil-play{position:relative;z-index:1}

.veil:hover .veil-play{transform:scale(1.08);animation:none}
.veil:active .veil-play{transform:scale(.97);animation:none}
@media(prefers-reduced-motion:reduce){.veil-play{animation:none}}
/* the duration is read off the file, never written by hand — a hardcoded
   "4 min" over a 0:20 video is the cheapest way to teach a visitor that the
   numbers here are decorative. */
.veil .dat:empty{display:none}
/* With no JS the veil cannot be dismissed, so it must not sit over the video.
   The markup's native `controls` then carry playback and there is no gate — and
   the five custom buttons go with the veil, because nothing is listening to
   them. (The `controls` attribute is on the element; site.js turns it off.) */
html.no-js .veil{display:none}
html.no-js .controls-wrap{display:none}
/* the fail-open state: no play mark, because there is nothing to play */
.veil[disabled]{cursor:default;background:rgba(0,0,0,.62)}
.veil[disabled] .veil-mark{display:none}
.veil-fail{font-family:var(--sans);font-size:15px;font-weight:400;color:var(--text-2);max-width:44ch;line-height:1.5}

/* ---- the nudge: appears once the briefing is done and points at the call ----
   This is the one sanctioned looping animation besides the terminal cursor
   (brand §10.2 amended 2026-08-03). It is a wayfinding affordance, not
   decoration: without it a man who just finished the video has no signal that
   anything exists below. It stops the moment he scrolls. */
/* The lock message that fades over the video on a blocked scroll. It sits in
   the empty lower band of the frame: centred it would cover the play button —
   badly on a phone — and a message that says "watch the briefing" must never
   obstruct the only control that starts it. */
/* On a phone the frame is ~190px tall, so the message and the play circle have
   to be sized to coexist rather than stacked and hoped for. */
@media(max-width:560px){
  /* On a 188px-tall frame the overlaid control chrome takes the bottom third,
     and a centred play mark landed ON the progress line. The veil centres in
     what is left instead, so the mark and the bar never touch. */
  .veil{gap:12px;padding-bottom:48px}
  .veil-mark{width:58px;height:58px}
  .veil-play{width:40px}
}

/* THE BLUR LOCK went here (added 2026-08-03, removed 2026-08-19). Everything
   below the video was blurred and `inert` until the briefing ran out, with a
   lockbar explaining why and a nudge that brightened when a visitor scrolled
   into the fog. The page is open, so all of it is gone — see
   PROTOCOL_OPEN_MODEL.md §4. */

/* ---- custom player controls ----
   The bar is now a SCRUBBER (2026-08-19). It was a report and nothing else for
   as long as the gate forbade seeking ahead; with the gate gone that is just a
   worse video player, so it takes a grab handle, a hover growth and a
   pointer affordance — an element that looks draggable and refuses to be
   dragged teaches a visitor that this site's controls lie. */
/* The progress line runs the full width of the bar, above the buttons. */
.player-bar{
  position:relative;height:3px;margin:0 4px 10px;border-radius:var(--r-pill);
  background:rgba(255,255,255,.22);cursor:pointer;touch-action:none;
  transition:opacity var(--d-element) var(--ease),height 120ms var(--ease);
}
/* The visible line is 3px; the TARGET is 18px. A 3px pointer target fails
   WCAG and fails a thumb, and growing the visible line to meet it would put a
   slab across the bottom of the film. The hit area is invisible and centred on
   the line, so the bar is as easy to grab as it looks delicate.
   `touch-action:none` above is what lets a touch DRAG scrub instead of the
   gesture being stolen by the page scroller mid-drag. */
.player-bar:before{
  content:"";position:absolute;left:0;right:0;top:50%;
  height:18px;transform:translateY(-50%);
}
.player-bar:hover,.player-bar:focus-visible,.player-bar.scrubbing{height:5px}
.player-bar:focus-visible{outline:2px solid var(--focus);outline-offset:4px}
.player-bar i{
  display:block;height:100%;width:0;background:#fff;border-radius:var(--r-pill);
  /* linear, and just longer than the 250ms `timeupdate` cadence, so the fill
     glides instead of stepping. */
  transition:width 300ms linear;
}
/* The handle. Only while the bar is being used — a permanent dot on a 3px line
   reads as a defect, and its absence at rest is why the bar still disappears
   cleanly under a playing film. */
.player-bar i:after{
  content:"";position:absolute;right:0;top:50%;width:11px;height:11px;
  transform:translate(50%,-50%) scale(0);border-radius:50%;background:#fff;
  transition:transform 120ms var(--ease);
}
.player-bar:hover i:after,.player-bar:focus-visible i:after,.player-bar.scrubbing i:after{transform:translate(50%,-50%) scale(1)}
/* A drag sets the width every pointermove. The 300ms glide that makes playback
   smooth would make a drag lag the finger by a third of a second, so it is
   suspended for exactly as long as the finger is down. */
.player-bar.scrubbing i{transition:none}
@media(prefers-reduced-motion:reduce){.player-bar i,.player-bar i:after{transition:none}}

.controls{display:flex;align-items:center;gap:10px}
/* Buttons live in dark pill clusters, not loose on the bar. */
.ctlgroup{
  display:inline-flex;align-items:center;gap:2px;padding:4px;
  background:rgba(0,0,0,.55);backdrop-filter:blur(20px) saturate(1.2);
  border-radius:var(--r-pill);
}
.ctl{
  position:relative;display:inline-flex;align-items:center;justify-content:center;
  width:42px;height:42px;border-radius:var(--r-pill);border:0;background:transparent;
  color:#fff;cursor:pointer;
  transition:background var(--d-tint) ease,transform var(--d-control) var(--ease);
}
.ctl:hover{background:rgba(255,255,255,.14)}
.ctl:active{transform:scale(.93)}
.ctl svg{width:21px;height:21px;fill:currentColor}
.ctl[disabled]{opacity:.35;cursor:not-allowed;transform:none}
.ctl[disabled]:hover{background:transparent}
.ctl-play svg{width:23px;height:23px}
/* The swap the class was always for. Same shape as .ctl-mute below: one icon
   is display:none until the state flips. */
.ctl-play .ico-pause{display:none}
.ctl-play.is-playing .ico-play{display:none}
.ctl-play.is-playing .ico-pause{display:block}
/* The play triangle's mass sits right of the geometric centre and the pause
   bars' does not, so only the play state is nudged back. */
/* A triangle looks off-centre in a circle because its mass sits left of its
   bounding box. Keyed to the icon rather than the aria-label, which was doing
   the same job by coincidence and would have nudged the pause bars the moment
   the label stopped being the state. */
.ctl-play .ico-play{transform:translateX(-1px)}
/* one glyph or the other, never both */
.ctl-mute .ico-muted,.ctl-mute[aria-pressed="true"] .ico-vol{display:none}
.ctl-mute[aria-pressed="true"] .ico-muted{display:block}
/* The rewind glyph is drawn as a stroked arc with the numeral set inside it,
   rather than a filled arrow with a label stacked on top — at 21px the filled
   version collapsed into a blob and the "10" fought the arrowhead. */
.ctl-back svg{width:23px;height:23px;fill:none}
.ctl-back svg text{font-family:var(--mono);letter-spacing:-.02em;fill:currentColor}
.ctl-back:active svg{transform:rotate(-14deg);transition:transform var(--d-control) var(--ease)}
/* The timecode is gone (2026-08-04, Reo's call): the video's length is not
   disclosed before it is watched. The spacer holds the CC toggle right. */
.ctl-spacer{flex:1 1 auto}

/* ---- the control bar ----
   Overlaid across the bottom of the frame: a translucent dark bar with the
   progress line across its top and the buttons grouped into pill clusters.
   Playing hides it; pause, hover and keyboard focus bring it back. */
.controls-wrap{
  position:absolute;left:0;right:0;bottom:0;z-index:4;
  padding:0 clamp(8px,1.4%,14px) clamp(8px,1.4%,12px);
  background:linear-gradient(to top,rgba(0,0,0,.72),rgba(0,0,0,.34) 62%,transparent);
  transition:opacity var(--d-element) var(--ease),transform var(--d-element) var(--ease);
}
.player.playing .controls-wrap{opacity:0;transform:translateY(8px);pointer-events:none}
.player.playing .player-bar{opacity:0}
/* ...unless a keyboard user is standing on one of those controls. The idle
   timer does not know about focus, so without this the button a man just
   tabbed to — and its focus ring — fade out from under him after 2.2s and stop
   accepting clicks. Focus stays reachable and visible, everywhere. */
.player:focus-within .controls-wrap{opacity:1;transform:none;pointer-events:auto}
.player:focus-within .player-bar{opacity:1}
@media(prefers-reduced-motion:reduce){
  .player.playing .controls-wrap{opacity:1;transform:none;pointer-events:auto}
  .player.playing .player-bar{opacity:1}
}

/* ---- a taken slot ----
   Shown, struck, and unclickable. Omitting booked slots makes a busy week look
   like a quiet one; showing them is the same fact told honestly. These are only
   ever REAL bookings — nothing on this page is seeded. */
/* UNAVAILABLE — booked by someone, or held by Reo. Deliberately identical:
   to a visitor both facts are the same fact, and only the label distinguishes
   them. It has to READ unavailable at a glance, so the strike runs through the
   time, a padlock sits beside it, and the tile is hatched rather than merely
   faded — opacity alone made it look like a loading state (Reo, 2026-08-05). */
.slot.off{
  color:var(--text-3);cursor:not-allowed;background:
    repeating-linear-gradient(-45deg,
      rgba(255,255,255,.045) 0 5px, transparent 5px 11px);
  border-color:var(--line);border-style:dashed;
  text-decoration:line-through 1.5px;
  text-decoration-color:rgba(255,255,255,.55);
  gap:6px;
}
/* the padlock is decorative — the accessible fact is in aria-label */
.slot.off:before{content:"🔒";font-size:10px;line-height:1;opacity:.75;text-decoration:none}
.slot.off:hover{background-color:transparent;color:var(--text-3);border-color:var(--line);transform:none}

/* The weekly all-member call, sitting in a diary of private slots. It is
   unbookable exactly like a hold and means the opposite of one, so it drops the
   padlock and the strike-through: nothing here is shut to this member, and a
   door he is invited through should not be drawn barred. Struck out it looked
   like a slot he had missed. */
.slot.is-comm{
  border-style:solid;text-decoration:none;
  color:var(--text-2);
  border-color:color-mix(in srgb,var(--verified) 30%,var(--line));
  background:color-mix(in srgb,var(--verified) 6%,transparent);
}
.slot.is-comm:before{content:"📞";opacity:.9}
/* border-color is restated deliberately: `.slot.off:hover` is 0-3-0 and this
   rule is 0-2-0, so without it the hold's grey rim wins on hover and the
   community tile becomes indistinguishable from a closed door at the exact
   moment the member is pointing at it. */
.slot.is-comm:hover{
  background:color-mix(in srgb,var(--verified) 6%,transparent);
  color:var(--text-2);
  border-color:color-mix(in srgb,var(--verified) 30%,var(--line));
}

/* THE WAY BACK UP went here (removed 2026-08-19). A pill that appeared once a
   visitor scrolled into the blurred section and carried him back to the video
   that would clear it. Nothing is blurred, so there is nothing to go back for. */


/* ============================================================
   THE BOOKING CARD — the one thing on this page that has to be taken
   The whole funnel converges here, so it is the only surface on the site that
   is allowed to sit higher than the family default: a wider rim light, a
   spotlight behind it, and a brighter top edge. Everything it adds is LIGHT —
   no new hue, no border colour, nothing that could be read as a state.
   ============================================================ */
.callcard{
  /* Jumped to from both doors. Without this the card lands flush against the
     top edge of the window, which reads as the page having overshot. */
  scroll-margin-top:clamp(16px,4vh,40px);
  border-color:rgba(255,255,255,.17);
  box-shadow:
    0 1px 2px rgba(0,0,0,.5),
    0 30px 90px -30px rgba(0,0,0,.85),
    inset 0 1px 0 rgba(255,255,255,.075);
}
/* the spotlight — a soft pool of light behind the card, so it lifts off the
   black rather than sitting on it. Sized in % so it scales with the card. */
.callcard::after{
  content:"";position:absolute;inset:-1px;border-radius:inherit;pointer-events:none;
  background:radial-gradient(120% 70% at 50% 0%, rgba(255,255,255,.055) 0%, transparent 62%);
}
/* a brighter hairline across the very top edge, brightest in the middle */
.callcard::before{
  content:"";position:absolute;top:0;left:12%;right:12%;height:1px;pointer-events:none;z-index:1;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.42),transparent);
}
.callcard .card-head{background:rgba(255,255,255,.04)}
.callcard .card-head .t{color:var(--text-2)}

/* the step number reads as a step, not a bullet */
.callcard .stepn{
  width:24px;height:24px;background:var(--text);color:#000;font-weight:600;
  box-shadow:0 0 0 4px rgba(255,255,255,.07);
}
.callcard .steplab{font-size:12px;color:var(--text-2)}

/* the commit button carries the section — full width on its own line below
   ~640px, and never the same weight as a secondary control */
.callcard .formfoot{margin-top:26px;padding-top:22px;border-top:1px solid var(--line-soft)}
@media(max-width:640px){
  .callcard .formfoot{flex-direction:column;align-items:stretch;gap:12px}
  .callcard #bksubmit{width:100%}
  .callcard .formfoot .dat{text-align:center}
}

/* ============================================================
   COUNTRY COMBOBOX — a search field over a real <select>
   The select stays in the DOM as the value holder so validation and every
   downstream listener keep working; it is just never shown. The input is
   what a visitor actually touches.
   ============================================================ */
.combo{position:relative;display:block}
/* The native control is hidden from sight and from the a11y tree, but it is
   NOT display:none — a display:none control is skipped by form validation, and
   this one is `required`. */
.combo-native{
  position:absolute;width:1px;height:1px;padding:0;margin:0;
  border:0;clip-path:inset(50%);overflow:hidden;pointer-events:none;
}
.combo > input{width:100%}
/* the chevron sits on the combo, matching every other select on the form */
.combo:after{
  content:"";position:absolute;right:15px;top:50%;width:8px;height:8px;
  border-right:2px solid var(--text-3);border-bottom:2px solid var(--text-3);
  transform:translateY(-70%) rotate(45deg);pointer-events:none;border-radius:1px;
  transition:transform var(--d-control) var(--ease);
}
.combo.open:after{transform:translateY(-25%) rotate(-135deg)}

.combo-list{
  position:absolute;z-index:12;left:0;right:0;top:calc(100% + 6px);
  margin:0;padding:6px;list-style:none;max-height:264px;overflow-y:auto;
  background:rgba(14,14,16,.96);backdrop-filter:blur(28px) saturate(1.3);
  border:1px solid var(--line-strong);border-radius:var(--r-2);
  box-shadow:var(--seat);overscroll-behavior:contain;
}
.combo-list li{
  padding:10px 12px;border-radius:10px;cursor:pointer;
  font-size:15.5px;color:var(--text-2);
  display:flex;align-items:baseline;gap:10px;
}
.combo-list li .cdial{margin-left:auto;font-family:var(--mono);font-size:11.5px;color:var(--text-3)}
.combo-list li[aria-selected="true"],.combo-list li:hover{background:var(--s-3);color:var(--text)}
.combo-list li.none{cursor:default;color:var(--text-3);font-size:14px}
.combo-list li.none:hover{background:none}
@media(max-width:560px){.combo-list{max-height:210px}}

/* ---- the photograph on each path card ----
   The same four images as the Pathway's placement screen, held right down so
   they sit UNDER the words rather than competing with them. `--h` is already
   on every card as its path hue; the wash pushes the photo toward it, which is
   what makes four different photographs read as one set.

   background-image rather than an <img>: these are decorative, the text is
   real text over the top, and a background cannot be dragged out or picked up
   by an image search. */
/* The photo treatment went here. It layered a greyscale-dimmed path photograph
   behind each card via --photo, brightened it on hover and crushed it on open.
   Only four images ever existed (one per dead path) and two of the six chapters
   have none, so the whole block went with the paths on 2026-08-19. The cards
   are built from hue, numeral and glyph instead — see THE CHAPTER CARD below.
   Restore this only when six real images exist. */

/* THE RUN went here (removed 2026-08-19) — a nine-stop rail of lesson cards
   with padlocks, a key turning between the first two, and six sealed stops
   ahead. ~310 lines of CSS, all of it teaching a gated spine that no longer
   exists. Replaced by .states below.
   ============================================================
   THE TWO STATES

   Three example chapter cards, side by side, static. They exist to make one
   distinction visible in a single glance: the bar is self-reported and cheap,
   the green is verified and permanent.

   `.is-ok` is the ONLY place green appears on this page, which is the rule the
   whole component is here to teach — green means a human checked, everywhere,
   without exception.
   ============================================================ */
.states{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;align-items:start}
@media(max-width:860px){.states{grid-template-columns:1fr}}
.states .state{
  background:var(--s-1);border:1px solid var(--line);border-radius:var(--r-card);
  padding:20px 20px 22px;display:flex;flex-direction:column;gap:11px;
}
.state-h{display:flex;align-items:baseline;gap:9px}
.state-n{font-size:11px;letter-spacing:.1em;color:var(--glow);opacity:.6}
.state-t{font-size:16px;font-weight:600;letter-spacing:-.015em}
.state-bar{
  position:relative;height:6px;border-radius:var(--r-pill);
  background:rgba(255,255,255,.1);overflow:hidden;
}
.state-bar i{display:block;height:100%;background:var(--text-3);border-radius:var(--r-pill)}
/* Mono, because it is a fact. Deliberately NOT red when unverified — a man who
   has not filed yet has not failed at anything (CANON_CARD law 3). */
.state-m{font-size:11px;letter-spacing:.07em;color:var(--text-3)}
.state-d{font-size:13.5px;line-height:1.5;color:var(--text-2)}
.state.is-ok{border-color:rgba(48,209,88,.32);background:rgba(48,209,88,.05)}
.state.is-ok .state-bar i{background:var(--verified)}
.state.is-ok .state-m{color:var(--verified)}

/* ============================================================
   CLICK TO UNMUTE

   A browser will autoplay a MUTED video and refuse an unmuted one. So the
   briefing starts silently and this is the one tap that gives it sound.

   It exists only while the video is genuinely playing AND genuinely muted —
   site.js drives it off the video's own `play`/`pause`/`volumechange` events,
   never off a timer — so it can never sit over a paused video telling somebody
   it is playing.
   ============================================================ */
.unmute{
  position:absolute;inset:0;z-index:4;
  display:grid;place-items:center;
  border:0;background:rgba(0,0,0,.28);
  cursor:pointer;padding:0;color:var(--text);
  -webkit-backdrop-filter:blur(1.5px);backdrop-filter:blur(1.5px);
  animation:unmuteIn var(--d-control) var(--ease) both;
}
.unmute-in{
  display:flex;flex-direction:column;align-items:center;gap:clamp(12px,1.6vw,20px);
  padding:clamp(22px,3vw,38px) clamp(30px,4vw,56px);
  border-radius:var(--r-4);
  background:rgba(255,255,255,.055);
  border:1px solid rgba(255,255,255,.1);
  -webkit-backdrop-filter:blur(18px) saturate(1.3);backdrop-filter:blur(18px) saturate(1.3);
  box-shadow:0 20px 60px -20px rgba(0,0,0,.7), inset 0 1px 0 rgba(255,255,255,.09);
  transition:transform var(--d-control) var(--ease),background var(--d-tint) ease;
}
.unmute-ico{
  width:clamp(38px,4.6vw,60px);height:clamp(38px,4.6vw,60px);
  fill:currentColor;display:block;
  filter:drop-shadow(0 2px 10px rgba(0,0,0,.5));
}
.unmute-t{
  display:flex;flex-direction:column;align-items:center;gap:2px;
  font-size:clamp(19px,2.4vw,31px);font-weight:600;letter-spacing:-.025em;
  line-height:1.2;text-align:center;text-shadow:0 2px 14px rgba(0,0,0,.55);
}
.unmute-t b{font-weight:600}

@media(hover:hover){
  .unmute:hover .unmute-in{transform:scale(1.03);background:rgba(255,255,255,.08)}
}
.unmute:focus-visible{outline:2px solid var(--text);outline-offset:-6px}

@keyframes unmuteIn{from{opacity:0}to{opacity:1}}
@media(prefers-reduced-motion:reduce){.unmute{animation:none}.unmute-in{transition:none}}

/* it never covers the controls — those stay reachable while it is up */
.controls-wrap{z-index:5}

/* ============================================================
   THE TWO DOORS — join now, or talk first
   Deliberately equal in weight. Making "join" loud and "call" quiet would be
   the funnel move this page spends the rest of its length disavowing; making
   the call loud would hide the fact that a ready buyer can just buy. Same size,
   same padding, one filled button and one ghost.
   ============================================================ */
/* Two columns at EVERY width. auto-fit/minmax(280px) collapsed them to one
   column under 600px, which stacked the two choices and made the second one
   look like an afterthought below the fold. They are meant to be read as a
   pair, so they stay a pair and shrink instead. */
.doors{
  display:grid;
  /* minmax(0,1fr), NOT 1fr. A bare `1fr` is `minmax(auto,1fr)`, so a track
     refuses to shrink below its content's min-content width — and the waiting
     list's email input has a wide intrinsic minimum. On a 375px phone the two
     tracks resolved to 124px and 281px: the join door crushed to a ribbon, the
     second door overflowing the page by 58px. Zero as the floor lets both
     tracks actually share the row. */
  grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:14px;margin-bottom:30px;
}
.door{
  display:flex;flex-direction:column;align-items:flex-start;gap:9px;
  padding:clamp(16px,2.4vw,26px);border-radius:var(--r-3);
  background:var(--s-1);border:1px solid var(--line);
  backdrop-filter:blur(24px) saturate(1.25);box-shadow:var(--seat),var(--toplight);
}
/* the ready door carries a touch more light — not a colour, just presence */
.door-join{border-color:rgba(255,255,255,.17);background:rgba(255,255,255,.05)}
.door-tag{letter-spacing:.14em}
.door h3{font-size:clamp(17px,2vw,23px);letter-spacing:-.02em}
.door p{font-size:clamp(13px,1.15vw,15px);line-height:1.5;color:var(--text-2);margin-bottom:2px}
/* the three-line proof strip inside each door */
/* .door-list was removed with the door bullets — the doors carry one line each now. */
.door-list li{
  position:relative;padding-left:20px;font-size:14.5px;line-height:1.45;color:var(--text-2);
}
.door-list li:before{
  content:"";position:absolute;left:2px;top:.52em;width:7px;height:7px;border-radius:50%;
  background:var(--text-3);
}
.door-join .door-list li:before{background:var(--text)}
/* DIRECT CHILD ONLY. This is the door's own call to action — the one that sits
   at the bottom of the card and spans it. As `.door .btn` it also caught the
   submit button inside the waiting-list strip, which is nested two levels
   deeper: same specificity, later in the file, so width:100% won and the strip
   collapsed to a 28px input beside a 433px button. The child combinator says
   what was always meant. */
.door > .btn{margin-top:auto;width:100%}
/* The second door has content BELOW its button — the OR and the waiting list —
   so the auto margin above would shove that whole group to the card's floor.
   Its button is mid-card by design, not the last word. */
.door-call > .btn{margin-top:0}
/* The hairline OR. Two rules and a word, so the two ways of not paying today
   read as alternatives rather than as one instruction followed by another.

   Written as `.door .door-or` (0,2,0) rather than `.door-or` (0,1,0), because
   `.door p` is (0,1,1) and beats a bare class — the divider rendered at 14.7px
   in text-2, the size and colour of body copy, which is not what a hairline
   label is. Same collision that crushed the waiting-list input; the doors are
   full of element selectors, so anything added inside one needs two classes. */
.door .door-or{
  display:flex;align-items:center;gap:12px;width:100%;
  margin:9px 0 2px;font-size:11px;letter-spacing:.16em;color:var(--text-3);
}
.door .door-or:before,.door .door-or:after{content:"";flex:1;height:1px;background:var(--line)}
.door .door-wait{font-size:13px;line-height:1.5;color:var(--text-3)}
/* Waiting on checkout. Deliberately not `opacity:.4` — a ghosted white pill
   reads as a rendering fault rather than a state. It is a real surface that
   plainly is not ready yet, and it carries no href, so it is unclickable and
   out of the tab order. */
.door .btn.is-waiting{
  background:var(--s-2);color:var(--text-3);border-color:var(--line);
  box-shadow:var(--toplight);cursor:default;
}
.door .btn.is-waiting:hover{transform:none;background:var(--s-2)}

/* ---- the doors on a phone ----
   Side by side down to the smallest screen, so the choice reads as a choice. */
@media(max-width:560px){
  /* ONE COLUMN on a phone. Two doors side by side was already tight at 560px;
     the second one now carries a paragraph, a button, a rule and an email form,
     and none of that survives a 170px track. Stacked, each door gets the full
     width and the join stays first, which is the order that matters. */
  .doors{grid-template-columns:1fr;gap:9px}
  .door{padding:14px 13px;gap:7px;border-radius:var(--r-2)}
  .door-tag{font-size:9px;letter-spacing:.1em}
  .door h3{font-size:16px}
  .door p{font-size:12.5px;line-height:1.45}
  .door .btn{font-size:13px;padding:12px 10px;text-align:center;justify-content:center}
  .door-fine{font-size:10px}
}
@media(max-width:380px){
  .door h3{font-size:15px}
  .door .btn{font-size:12px;padding:11px 6px}
}
@media(max-width:600px){.door{padding:20px}}

/* ---- the time-zone line, above the calendar ----
   Every time in the calendar is rendered in this zone, so it is stated before
   the grid rather than tucked under it. A visitor who books an 8pm slot and
   discovers it meant 8pm somewhere else has been misled by omission. */
.tzline{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin:0 0 18px;font-family:var(--mono);font-size:11.5px;
  text-transform:uppercase;letter-spacing:.11em;color:var(--text-3);
}
.tzem{font-size:13px;line-height:1}
.tzstatic{color:var(--text-2);font-weight:500}
.selwrap-tz{display:inline-block;min-width:0}
.selwrap-tz select{
  font-family:var(--mono);font-size:11.5px;letter-spacing:.11em;text-transform:uppercase;
  padding:7px 30px 7px 11px;min-height:0;color:var(--text-2);
}
@media(max-width:560px){.tzline{font-size:10.5px;gap:6px;margin-bottom:14px}}

/* ---- the two steps ---- */
.steplab{
  display:flex;align-items:center;gap:11px;margin:0 0 18px;
  font-family:var(--mono);font-size:11.5px;text-transform:uppercase;letter-spacing:.13em;color:var(--text-3);
}
.stepn{
  display:inline-grid;place-items:center;width:22px;height:22px;border-radius:50%;
  background:var(--s-3);color:var(--text);font-size:11px;letter-spacing:0;
}
.stepback{
  margin-left:auto;background:none;border:0;padding:0;cursor:pointer;
  font-family:var(--sans);font-size:13.5px;letter-spacing:0;text-transform:none;
  color:var(--text-3);border-bottom:1px solid var(--line-strong);
}
.stepback:hover{color:var(--text);border-color:var(--text)}

/* ---- selects ----
   A native select renders its own white control on macOS and its own blue
   highlight on Windows, which is the light bubble that kept appearing in the
   middle of a black form. `appearance:none` removes the control entirely and
   the chevron is drawn back on. The dropdown LIST itself is OS-owned and
   cannot be styled, so `color-scheme:dark` is what makes it open dark. */
.selwrap{position:relative;display:block}
/* `display:block` above beats the UA's `[hidden]{display:none}`, so the dial
   code showed for every contact method. It must lose to `hidden`. */
.selwrap[hidden]{display:none}
.selwrap:after{
  content:"";position:absolute;right:15px;top:50%;width:8px;height:8px;
  border-right:2px solid var(--text-3);border-bottom:2px solid var(--text-3);
  transform:translateY(-70%) rotate(45deg);pointer-events:none;border-radius:1px;
}
.selwrap select{
  -webkit-appearance:none;appearance:none;width:100%;
  padding-right:38px;background-image:none;color-scheme:dark;
}
.selwrap select::-ms-expand{display:none}
.selwrap select:invalid{color:var(--text-3)}
.selwrap select option{background:#111;color:var(--text)}

/* phone: dial code and number sit on one line */
.valrow{display:flex;gap:8px;align-items:stretch}
.selwrap-dial{flex:0 0 auto;width:132px}
.selwrap-dial select{font-family:var(--mono);font-size:15px}
.selwrap-dial:after{right:12px}
.valrow input{flex:1 1 auto;min-width:0}
@media(max-width:520px){.selwrap-dial{width:110px}.selwrap-dial select{font-size:14px}}

/* ---- the four paths, as a 2×2 ----
   Each card is a button: tap or focus expands the detail. The hue is identity
   only — a spine, a glyph and a wash — never a state. Availability is not a
   verification, so the open fact is carried by the word and by white, exactly
   as it is on the about page. */
/* align-items:stretch so a row stays LEVEL when one card is opened. Grid rows
   size to their tallest item, but a flex-column child left to its own content
   height leaves the other card in the row short — the row reads as broken
   rather than as one card being open. */
/* ============================================================
   THE CHAPTER CARD

   Six of these carry the whole product on the landing page, and the earlier
   version was six dark rectangles with a 3px stripe, a small floating emoji
   and "TAP TO OPEN" printed six times. Three things fixed:

   1. THE HUE IS ACTUALLY PRESENT. Each chapter's accent was a hairline nobody
      saw. It is now a corner glow, a tinted glyph tile and a hover border, so
      the six read as six things rather than one thing listed six times.
      Decorative throughout — never green, never red, never a state.
   2. THE NUMERAL IS THE ART. A large mono figure sits in the card, low-alpha
      and hue-tinted. It gives each card an identity without an image, which
      matters because there are no images and inventing some would be filler.
   3. "TAP TO OPEN" IS GONE, replaced by the lesson count. Six copies of an
      instruction cost the same space as six real facts, and it was wrong on a
      desktop anyway. The chevron carries the affordance instead.
   ============================================================ */
.chapgrid{display:grid;gap:14px;align-items:stretch;grid-template-columns:repeat(3,1fr)}
/* Six cards: three up reads as two clean rows. Two up gives three rows and an
   uncomfortably tall section; four up leaves a widowed pair on the second. */
.chapgrid > .pcard{height:100%}
@media(max-width:1000px){.chapgrid{grid-template-columns:1fr 1fr}}
@media(max-width:620px){.chapgrid{grid-template-columns:1fr}}

.pcard{
  position:relative;isolation:isolate;overflow:hidden;
  display:flex;flex-direction:column;align-items:flex-start;
  background:var(--s-1);border:1px solid var(--line);border-radius:var(--r-card);
  padding:20px 20px 17px;text-align:left;color:inherit;font:inherit;cursor:pointer;
  transition:transform var(--d-element) var(--ease),border-color var(--d-element) var(--ease),
             background var(--d-element) var(--ease);
}
.pcard > *{position:relative;z-index:3}

/* ---- THE PHOTOGRAPH, TINTED ----
   One shot, six chapters. It is greyscaled first so the tint has neutral
   material to work on, then `mix-blend-mode:color` paints the chapter's own
   --h through it. That is the colour coding: it is driven by the SAME token as
   the glow, the glyph tile and the hover border, so a chapter's colour can
   never disagree with itself.

   The card sets `isolation:isolate`, which is what keeps the blend inside the
   card instead of reaching the page behind it.

   To swap in six real photographs later: change the <img src> per card. The
   tint, the scrim and the crop all keep working untouched. */
.pshot{
  position:absolute;z-index:0;inset:0 0 0 auto;width:40%;
  overflow:hidden;pointer-events:none;
  /* The panel narrows to 34% when the card opens and had NO transition on
     width, so it snapped to its new size in one frame while the text beneath
     it eased over 380ms. That mismatch is the glitch: the eye reads the jump,
     not the ease. Same duration and curve as the panel it belongs to. */
  transition:width var(--d-panel) var(--ease);
}
.pshot img{
  width:100%;height:100%;object-fit:cover;object-position:52% 20%;display:block;
  filter:grayscale(1) contrast(1.1) brightness(.58);
  transition:filter var(--d-element) var(--ease),transform var(--d-element) var(--ease);
}
.pshot:before{
  content:"";position:absolute;z-index:1;inset:0;
  background:var(--h);mix-blend-mode:color;opacity:.8;
}
/* THE SCRIM SPANS THE WHOLE CARD, not the photo panel.
   It lived inside .pshot first, which meant the ramp was only ever as wide as
   the panel — 126px on a phone — so the fade finished almost as soon as it
   started and left a hard vertical seam down every card. Across the full width
   the same gradient has three or four times the distance to travel, and the
   photograph emerges instead of beginning. */
.pcard:after{
  content:"";position:absolute;z-index:1;inset:0;pointer-events:none;
  background:linear-gradient(90deg,
    rgba(9,9,10,.96) 34%,
    rgba(10,10,11,.88) 54%,
    rgba(10,10,11,.42) 76%,
    rgba(0,0,0,0) 100%);
}
.pcard:hover .pshot img{filter:grayscale(1) contrast(1.1) brightness(.76);transform:scale(1.03)}

/* the corner glow — the same hue, on the text side */
.pwash{
  position:absolute;z-index:1;inset:0;pointer-events:none;
  background:radial-gradient(72% 58% at 0% 0%,var(--h),transparent 70%);
  opacity:.14;transition:opacity var(--d-element) var(--ease);
  z-index:2;   /* above the scrim, so the glow is not flattened by it */
}
.pcard:hover .pwash{opacity:.24}

.pcard:before{content:"";position:absolute;z-index:4;left:0;top:0;bottom:0;width:3px;background:var(--h);opacity:.75}
.pcard:hover{background:var(--s-2);border-color:color-mix(in srgb,var(--h) 34%,var(--line));transform:translateY(-3px)}
.pcard:active{transform:translateY(-1px) scale(.995)}
.pcard:focus-visible{outline:2px solid var(--focus);outline-offset:3px}

/* An iOS-style tinted tile — the surface language the rest of the site speaks. */
.pglyph{
  width:42px;height:42px;flex:none;display:grid;place-items:center;
  font-size:21px;line-height:1;border-radius:var(--r-field);margin-bottom:15px;
  background:color-mix(in srgb,var(--h) 15%,transparent);
  border:1px solid color-mix(in srgb,var(--h) 22%,transparent);
}
.cnum{display:none}

/* Held clear of the photograph so a long name never runs into his face. */
.pname{font-size:clamp(17px,1.45vw,19.5px);font-weight:600;letter-spacing:-.025em;line-height:1.2;margin-bottom:6px;max-width:68%;text-wrap:balance}
.pkw{color:var(--text-3);font-size:12.5px;line-height:1.45;max-width:66%}

.pmore{
  display:grid;grid-template-rows:0fr;opacity:0;width:100%;
  transition:grid-template-rows var(--d-panel) var(--ease),opacity var(--d-panel) var(--ease),
             margin var(--d-panel) var(--ease);
}
.pmore-l{overflow:hidden;display:block;color:var(--text-2);font-size:13.5px;line-height:1.55}
.pcard[aria-expanded="true"] .pmore{grid-template-rows:1fr;opacity:1;margin-top:13px}
/* Open, the words need the whole card, so the photograph steps back. */
.pcard[aria-expanded="true"] .pshot{width:34%}
.pname,.pkw{transition:max-width var(--d-panel) var(--ease)}
/* 100%, NOT none. `none` is not an animatable value, so the text box jumped to
   full width in one frame and every line re-wrapped at once underneath a
   photograph that was still moving. */
.pcard[aria-expanded="true"] .pname,
.pcard[aria-expanded="true"] .pkw{max-width:100%}

.pfoot{display:flex;align-items:center;justify-content:space-between;width:100%;margin-top:auto;padding-top:15px;gap:10px}
.pmeta{font-size:10.5px;letter-spacing:.1em;color:var(--text-3)}
.pcard:hover .pmeta{color:var(--text-2)}

/* Drawn, not an emoji, because it points and emoji drift. */
.pchev{
  width:7px;height:7px;flex:none;
  border-right:1.6px solid var(--text-3);border-bottom:1.6px solid var(--text-3);
  transform:rotate(45deg);
  transition:transform var(--d-element) var(--ease),border-color var(--d-element) var(--ease);
}
.pcard:hover .pchev{border-color:var(--h)}
.pcard[aria-expanded="true"] .pchev{transform:rotate(-135deg)}

/* A card that grows, narrows its photograph and re-wraps its text is exactly
   the movement this setting exists to stop. The card still opens — the content
   is the point — it simply arrives rather than travels. */
@media(prefers-reduced-motion:reduce){
  .pshot,.pname,.pkw,.pmore,.pchev{transition:none}
}

/* ---- THE ROOM ----
   Wide, below the six, and not a card in the grid — it has no lessons, nothing
   about it is verified, and giving it a seventh cell would both widow the row
   and quietly claim it is a seventh chapter. */
.commcard{
  position:relative;isolation:isolate;overflow:hidden;margin-top:14px;
  background:var(--s-1);border:1px solid var(--line);border-radius:var(--r-card);
  padding:24px 26px 26px;
}
/* The photo, its wash and the gradient that made text readable over it all
   went together. Keeping the 90deg scrim over a plain background would have
   left a dark band down the right of the card with nothing underneath it. */
.commcard:before{content:"";position:absolute;z-index:4;left:0;top:0;bottom:0;width:3px;background:var(--h);opacity:.75}
/* Was max-width:64%, which existed to keep the copy clear of the portrait.
   With no portrait it is just a short measure and a wide empty right-hand
   side, so the text takes the card — capped at a readable line length rather
   than running the full width of a desktop. */
.comm-in{position:relative;z-index:3;max-width:min(72ch,100%)}
.commcard .pglyph{margin-bottom:14px}
.comm-t{font-size:clamp(19px,1.9vw,23px);font-weight:600;letter-spacing:-.025em;margin-bottom:9px}
.comm-p{color:var(--text-2);font-size:14px;line-height:1.6}
.comm-meta{display:block;margin-top:15px;font-size:10.5px;letter-spacing:.1em;color:var(--text-3)}

@media(max-width:620px){
  /* On one column the photograph is a strip down the side rather than half the
     card, so the name keeps a sensible measure. */
  .pshot{width:38%}
  .pname,.pkw{max-width:64%}
  .commcard{padding:20px 20px 22px}
  .comm-in{max-width:100%}
  .commcard .pshot{width:0;display:none}
}

@media(prefers-reduced-motion:reduce){
  .pcard,.pwash,.pfig,.pchev,.pmore,.pshot img{transition:none}
  .pcard:hover{transform:none}
  .pcard:hover .pshot img{transform:none}
}

.pathfoot{margin-top:18px;color:var(--text-3);font-size:12.5px;text-align:center}

/* ============================================================
   WHO'S TEACHING THIS

   The page's only photograph, and the only place a face appears before
   the call. It sits left and sticky on a wide screen so the portrait
   holds while the four answers scroll past it — the eye contact is
   doing the work the copy cannot.
   ============================================================ */
.mewrap{display:grid;grid-template-columns:minmax(0,420px) minmax(0,1fr);gap:clamp(24px,4vw,52px);align-items:start}

.mefig{margin:0;position:sticky;top:calc(var(--nav-h) + 28px)}
/* `.mebody > .lead` (0,2,0) outranked `.melast` (0,1,0), so the closing
   paragraph lost its 26px of air and sat hard against the rows above it. */
.mebody > .lead.melast{margin-top:26px}
.mefig img{
  display:block;width:100%;height:auto;border-radius:var(--r-3);
  border:1px solid var(--line);
  /* held a stop under the page so it reads as part of the dark rather than
     a bright rectangle punched into it */
  filter:brightness(.94) contrast(1.03) saturate(.95);
}
.mefig figcaption{
  margin-top:12px;letter-spacing:.16em;color:var(--text-3);
  display:flex;align-items:center;gap:9px;
}
.mefig figcaption:before{content:"";width:16px;height:1px;background:var(--line-strong);flex:none}

.mebody > .lead{margin-top:0}
.merows{margin-top:26px}
.melast{margin-top:26px}
.meacts{display:flex;flex-wrap:wrap;align-items:center;gap:14px 20px;margin-top:26px}

/* The actual YouTube mark, inline so it inherits colour and never costs a
   request. It sits on the baseline of the label rather than floating above it. */
.btn.yt{display:inline-flex;align-items:center;gap:10px}
.btn.yt svg{
  width:20px;height:20px;flex:none;display:block;
  fill:#FF0000;                     /* the brand mark keeps its own colour */
}
@media(hover:hover){.btn.yt:hover svg{fill:#FF0000}}

@media(max-width:900px){
  /* Stacked, and the sticky comes off — a sticky portrait on a phone
     eats the viewport the copy needs. */
  .mewrap{grid-template-columns:1fr;gap:26px}
  .mefig{position:static;max-width:340px}
  .mefig img{aspect-ratio:4/5;object-fit:cover}
}
@media(max-width:560px){
  .mefig{max-width:none}
}
@media(prefers-reduced-motion:reduce){
  .pcard,.pwash,.pmore{transition:none}
  .pcard:hover{transform:none}
}

/* ---- the receipt ---- */
.booked{padding:30px 24px 26px;text-align:center}
.booked-mark{font-size:34px;margin:0 0 12px;line-height:1}
.booked h3{margin-bottom:10px}
.booked .lead{margin:0 auto 22px;text-align:center}
.booked .rows{text-align:left}
.booked-foot{margin-top:16px;color:var(--text-3);font-size:12.5px}
/* No border declarations here: `.ctl` sets `border:0`, so a bare border-color
   can never draw, and the whole cluster is borderless by design — the pill
   group behind it is what separates these from the frame. */
.ctl-cc{
  width:auto;min-width:48px;padding:0 12px;font-family:var(--mono);font-size:11.5px;
  font-weight:500;letter-spacing:.1em;color:var(--text-3);
}
.ctl-cc:hover{color:var(--text);background:var(--s-2)}
/* Pressed is a full inversion, not a tint — white, never a hue, because a
   coloured toggle here would sit where a state could be read. */
.ctl-cc[aria-pressed="true"]{background:var(--text);color:#000}
.ctl-cc[aria-pressed="true"]:hover{background:var(--text);color:#000}
@media(max-width:560px){
  .controls{gap:5px}
  .ctl-play{width:44px;height:44px}
  .ctl-cc{min-width:44px;padding:0 10px;font-size:11px;letter-spacing:.08em}
}
/* Native cue rendering, restyled to the brand rather than left as system default. */
#briefing::cue{
  background:rgba(0,0,0,.78);color:var(--text);
  font-family:var(--sans);font-size:.95em;line-height:1.45;
}

/* ---- the Log artifact ---- */
.log-row{
  display:grid;grid-template-columns:auto 1fr auto;gap:16px;align-items:baseline;
  padding:11.5px var(--pad-in);border-bottom:1px solid var(--line-soft);
  font-family:var(--mono);font-size:13px;letter-spacing:.015em;color:var(--text-2);
  font-variant-numeric:tabular-nums;
}
.log-row:last-child{border-bottom:0}
.log-row .t{color:var(--text-3);white-space:nowrap}
.log-row .s{font-size:10.5px;font-weight:500;text-transform:uppercase;letter-spacing:.13em;color:var(--text-3);white-space:nowrap}
.log-row.miss .e{color:var(--text-3)}
/* the verdict is the one green on the surface and it is data, not decoration —
   it gets a left edge as well as a wash so it survives monochrome */
.log-row.verdict{
  background:var(--verified-dim);color:var(--verified);padding-top:16px;padding-bottom:16px;
  box-shadow:inset 2px 0 0 var(--verified);
}
.log-row.verdict .t,.log-row.verdict .s{color:var(--verified)}
.note{padding:8px var(--pad-in) var(--pad-body);display:grid;grid-template-columns:auto 1fr;gap:14px}
.note .em{width:18px;height:1px;background:var(--line-strong);margin-top:13px}
.note p{font-size:16px;line-height:1.55;color:var(--text);max-width:58ch;text-wrap:pretty}
.note .sig{margin-top:10px;font-family:var(--mono);font-size:10.5px;font-weight:500;text-transform:uppercase;letter-spacing:.13em;color:var(--text-3)}
@media(max-width:640px){
  .log-row{grid-template-columns:1fr;gap:3px;padding:12px 16px}
  .log-row .s{justify-self:start}
  .note{padding:8px 16px 20px}
}

/* ---- testimonials, honestly empty ----
   Surface, border and radius come from the family rule above; only the layout
   is local. A reserved slot is deliberately NOT seated with a shadow — an empty
   state that reads as a solid object is an empty state pretending to be full. */
.tgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px}
/* Slot 3 of the emoji layer: a marker standing alone gets a ring rather than
   floating as a loose character in the middle of a dashed box. */

/* ============================================================
   BOOKING — the only interactive surface on the landing
   Two labelled steps (day, then time), then a grouped iOS form, then a
   confirmation. Every state the worker can put on screen — loading, days,
   fully booked, unreachable — has a drawn treatment here; none of them is a
   spinner, because a spinner is not a status.
   ============================================================ */
.card-body{--cardpad:var(--pad-in);padding:var(--pad-body) var(--pad-in)}
@media(max-width:600px){.card-body{--cardpad:16px;padding:18px 16px}}

.calrow{display:grid;gap:11px}
/* The hairline is the whole relationship: the day rail sits above it, the times
   it produced sit below it, and the selected day's tick points down at it. */
.calrow-time{margin-top:4px;padding-top:18px;border-top:1px solid var(--line-soft)}
/* These two labels are step markers, not status markers, so they are the one
   place a mono label legitimately opens with a letter — the ::first-letter
   emoji correction on .lab would set that letter at 15px and .34em. */
.callab{
  font-family:var(--mono);font-size:12px;font-weight:500;text-transform:uppercase;
  letter-spacing:.14em;color:var(--text-3);line-height:1.15;display:block;
}

/* The rail runs to the card's edges rather than stopping inside its padding,
   and the trailing fade is what says "this continues". A fade is honest here
   because it only ever dims something: with three days there is nothing under
   it and it is invisible, with eleven there is, and it reads as scrollable. */
.days{
  display:flex;gap:10px;overflow-x:auto;overscroll-behavior-x:contain;
  padding:3px var(--cardpad) 14px;margin-inline:calc(var(--cardpad) * -1);
  scroll-snap-type:x proximity;scroll-padding-inline:var(--cardpad);
  -webkit-overflow-scrolling:touch;scrollbar-width:none;
  -webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 34px),transparent calc(100% - 3px));
  mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 34px),transparent calc(100% - 3px));
}
.days::-webkit-scrollbar{display:none}
/* Emptied by the worker's own failure paths — fully booked, or unreachable.
   The row and its label go with it rather than leaving a labelled void. */
.days:empty,.slots:empty{display:none}
.cal:has(.days:empty) .calrow-day{display:none}
.cal:has(.slots > .lead) .calrow-time > .callab{display:none}
/* A day tile is a two-fact object — weekday label above, date numeral below —
   so it is built as a centred flex column on a fixed height rather than as a
   padded box whose height drifts with its contents. */
.day{
  position:relative;flex:0 0 auto;min-width:80px;height:64px;padding:0 14px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
  border:1px solid var(--line);border-radius:var(--r-2);scroll-snap-align:start;
  background:var(--s-1);cursor:pointer;text-align:center;backdrop-filter:blur(20px);
  box-shadow:var(--toplight);
  transition:background var(--d-tint) ease,border-color var(--d-tint) ease,transform var(--d-control) var(--ease);
}
.day:hover{background:var(--s-2);border-color:var(--line-strong)}
.day:active{transform:scale(.97)}
/* Selected is a full inversion — white, never a hue, because a coloured
   selection here would sit where a state could be read. */
.day[aria-pressed="true"]{background:var(--text);border-color:var(--text);box-shadow:var(--seat)}
.day[aria-pressed="true"]:hover{background:var(--text)}
.day[aria-pressed="true"] .dw{color:rgba(0,0,0,.62)}
.day[aria-pressed="true"] .dd{color:#000}
/* The tick that ties the rail to the times below it. It lives inside the
   rail's own bottom padding so the scroll container cannot clip it, and it
   points at the hairline that opens the time step. */
.day[aria-pressed="true"]::after{
  content:"";position:absolute;left:50%;bottom:-9px;width:22px;height:3px;
  border-radius:var(--r-pill);background:var(--text);transform:translateX(-50%);
}
.day .dw{font-family:var(--mono);font-size:10.5px;font-weight:500;text-transform:uppercase;letter-spacing:.12em;color:var(--text-3);line-height:1}
.day .dd{font-family:var(--mono);font-size:19px;font-weight:500;color:var(--text);letter-spacing:-.01em;line-height:1;font-variant-numeric:tabular-nums}
.slots{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:10px}
.slot{
  position:relative;min-height:48px;display:flex;align-items:center;justify-content:center;
  padding:0 8px;border:1px solid var(--line);border-radius:var(--r-2);background:var(--s-1);cursor:pointer;
  font-family:var(--mono);font-size:13px;letter-spacing:.02em;color:var(--text-2);text-align:center;
  backdrop-filter:blur(20px);box-shadow:var(--toplight);font-variant-numeric:tabular-nums;
  transition:background var(--d-tint) ease,color var(--d-tint) ease,
             border-color var(--d-tint) ease,transform var(--d-control) var(--ease);
}
.slot:hover{background:var(--s-2);color:var(--text);border-color:var(--line-strong)}
.slot:active{transform:scale(.97)}
.slot[aria-pressed="true"]{background:var(--text);color:#000;border-color:var(--text);font-weight:500;box-shadow:var(--seat)}
.slot[aria-pressed="true"]:hover{background:var(--text);color:#000}
/* The honest no-slots and scheduler-down messages land inside this grid, so
   they are told to span it instead of being crushed into one 112px column. */
.slots > .lead{grid-column:1/-1;margin:0;font-size:16px;max-width:56ch}

/* ---- the loading state ----
   Drawn placeholders at the exact size of the thing that will replace them, so
   the panel does not jump when the worker answers. Dashed and inert: a solid
   tile would read as a day you could press. Nothing pulses — a shimmer is a
   loop, and the only two loops in this brand are the cursor and the nudge. */
.sk{border:1px dashed var(--line);border-radius:var(--r-2);background:rgba(255,255,255,.014)}
.sk-day{flex:0 0 auto;min-width:80px;height:64px}
.sk-slot{min-height:48px}
html.no-js .sk{display:none}

/* ---- the form: an iOS grouped list, not four floating boxes ----
   One inset panel, hairline-separated rows, the field itself borderless inside
   its row. The group carries the edge; the row carries the state. */
.fields{
  display:grid;grid-template-columns:1fr 1fr;margin-top:24px;
  background:var(--s-1);border:1px solid var(--line);border-radius:var(--r-3);
  overflow:hidden;backdrop-filter:blur(24px);box-shadow:var(--toplight);
}
/* Doubled class on purpose: declared here, after `.fields`, and at a
   specificity that a future reorder cannot silently undercut. It used to sit
   265 lines above `.fields` at equal specificity and therefore never applied. */
.fields.fields-one{grid-template-columns:1fr}
.f{
  position:relative;display:flex;flex-direction:column;justify-content:center;gap:6px;
  min-height:78px;padding:13px var(--pad-in) 14px;border-top:1px solid var(--line-soft);
  transition:background var(--d-tint) ease;
}
/* Row 1 is name | country, and only row 1 sits against the panel's own top
   edge, so only those two clear their hairline. Every row after them draws one.
   This was written as `#f-name,#f-method`, which put a half-width rule 1px
   inside the panel's top border and left the row-1/row-2 boundary undrawn. */
#f-name,#f-country{border-top:0}
#f-name{border-right:1px solid var(--line-soft)}
/* A row is either a 2-up pair or the full width. `#f-value` has to be full
   width (dial code plus number), which orphaned `#f-method` in a half row with
   dead panel beside it and no separator; it takes the full width too. */
#f-method,#f-value,#f-note{grid-column:1/-1}
/* The active row lifts a step, the way a focused cell does in Settings. */
.f:focus-within{background:var(--s-2)}
.f label{font-size:13px;color:var(--text-3);letter-spacing:.005em;line-height:1.2}
.f .opt{color:var(--text-3);opacity:.7}
.f input,.f select,.f textarea{
  background:transparent;border:0;border-radius:6px;color:var(--text);
  font-family:var(--sans);font-size:16.5px;line-height:1.35;padding:0;width:100%;
  -webkit-appearance:none;appearance:none;
}
/* 16.5px is not a taste call — anything under 16px makes iOS Safari zoom the
   page on focus and the man loses the calendar he was just looking at. */
.f input::placeholder,.f textarea::placeholder{color:var(--text-3)}
.f textarea{min-height:66px;resize:vertical;padding-top:2px}
/* No ring on form fields.
   A text input matches :focus-visible on CLICK as well as on keyboard — that is
   spec, not a bug — so the global white ring fired every single time a man
   tapped a field, and it read as an error box drawn around his own typing.
   The row itself is the focus indicator instead: it lifts a surface step and
   grows a white edge on its left. That is visible to a keyboard user, quiet to
   a mouse user, and it is still white — a focus indicator is never a verdict,
   so it is never green and never red. */
.f :focus-visible{outline:none}
.f:before{
  content:"";position:absolute;left:0;top:8px;bottom:8px;width:2px;border-radius:var(--r-pill);
  background:var(--text);opacity:0;transform:scaleY(.4);transform-origin:center;
  transition:opacity var(--d-tint) ease,transform var(--d-control) var(--ease);
}
.f:focus-within:before{opacity:1;transform:scaleY(1)}
/* A field in error keeps its red edge, which outranks the focus edge — the
   verdict on the value beats the indicator of where the cursor is. */
.f.bad:before{background:var(--fail);opacity:1;transform:scaleY(1)}
@media(prefers-reduced-motion:reduce){.f:before{transition:none}}
/* Every select on this site lives in a `.selwrap`, which draws the one chevron
   and reserves 38px for it. This rule used to paint a SECOND chevron as a
   background-image and cut the reserve to 24px, so every select on the landing
   rendered "⌄⌄". It owns the cursor and the reserve, nothing else.
   The 38px is repeated from `.selwrap select` because the shared
   `.f input,.f select,.f textarea{padding:0}` rule above sits between them at
   equal specificity and would otherwise zero it. */
.f select{cursor:pointer;padding-right:38px}
/* ---- the error state: red, and only ever on a failure ---- */
.f.bad{background:var(--fail-dim)}
.f.bad label{color:var(--fail)}
.err{font-size:13px;color:var(--fail);display:none;line-height:1.3}
.f.bad .err{display:block}
@media(max-width:620px){
  .fields{grid-template-columns:1fr}
  /* stacked, country is no longer beside the name — it is the second row */
  #f-country{border-top:1px solid var(--line-soft)}
  #f-name{border-right:0}
  .f{padding:13px 16px 14px}
}

.formfoot{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:22px}
#bksubmit{min-width:196px}
/* Disabled is a real state with its own surface, not the live button at 40%
   opacity — a ghosted white pill reads as a rendering fault. */
#bksubmit[disabled]{
  opacity:1;background:var(--s-2);color:var(--text-3);
  border-color:var(--line);box-shadow:var(--toplight);
}
/* The picked slot is a fact, so it is mono, and the rule beside it separates
   it from the control without pretending to be a status dot. */
#bkpick{display:inline-flex;align-items:center;gap:12px;font-size:12.5px;color:var(--text-3);letter-spacing:.03em}
#bkpick::before{content:"";width:1px;height:15px;background:var(--line-strong);flex:0 0 auto}
@media(max-width:620px){#bkpick::before{display:none}#bksubmit{width:100%}}

/* ---- the result: a receipt, not an alert ----
   The verdict word is mono and carries the colour; the sentence stays white.
   Green appears once, on a booking a human will actually keep, and red only on
   a booking that did not happen. Neither is decoration and neither pulses. */
.result{
  position:relative;display:none;margin-top:20px;padding:17px 20px 18px 22px;
  border-radius:var(--r-3);font-size:15.5px;line-height:1.55;color:var(--text);gap:7px;
  overflow:hidden;box-shadow:var(--toplight);
}
.result.ok,.result.no{display:grid}
.result::before{
  font-family:var(--mono);font-size:11px;font-weight:500;text-transform:uppercase;
  letter-spacing:.14em;line-height:1;
}
.result::after{content:"";position:absolute;left:0;top:0;bottom:0;width:3px}
.result.ok{background:var(--verified-dim);border:1px solid rgba(48,209,88,.34)}
.result.ok::before{content:"Confirmed";color:var(--verified)}
.result.ok::after{background:var(--verified)}
.result.no{background:var(--fail-dim);border:1px solid rgba(255,69,58,.34)}
.result.no::before{content:"Not booked";color:var(--fail)}
.result.no::after{background:var(--fail)}

/* ---- about page bits ---- */
.paths{display:grid;gap:14px}
/* the path spine — identity by slot, never a state. Masked at both ends so it
   does not collide with the panel's rounded corners. */
.path:before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--h);
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 16%,#000 84%,transparent);
          mask-image:linear-gradient(180deg,transparent,#000 16%,#000 84%,transparent);
}

/* ---- the verdict panel ---- */
.verd-word{
  font-family:var(--mono);font-size:clamp(36px,5.6vw,58px);font-weight:500;line-height:1;
  letter-spacing:-.01em;padding:var(--pad-body) var(--pad-in) 18px;
}
.verd.held .verd-word{color:var(--fail)}
.verd.clr .verd-word{color:var(--verified)}
.dl{display:grid;grid-template-columns:150px 1fr}
.dl dt{
  font-family:var(--mono);font-size:10.5px;font-weight:500;text-transform:uppercase;letter-spacing:.13em;
  color:var(--text-3);padding:15px 0 15px var(--pad-in);border-top:1px solid var(--line-soft);line-height:1.5;
}
.dl dd{margin:0;padding:15px var(--pad-in) 15px 0;border-top:1px solid var(--line-soft);color:var(--text-2);font-size:15.5px;line-height:1.55;text-wrap:pretty}
.dl dd.dat{font-size:13px}
.dl dd b{color:var(--text);font-weight:600}
@media(max-width:620px){.dl{grid-template-columns:1fr}.dl dt{padding:14px 16px 3px}.dl dd{padding:0 16px 14px;border-top:0}}

/* ---- price panels — three of the same object, one of them raised a step ---- */
.prices{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-bottom:16px}
@media(max-width:700px){.prices{grid-template-columns:1fr}}
.price{padding:var(--pad-body) var(--pad-in)}
/* the visual default is carried by a surface step and a stronger hairline —
   never by a colour, which on this page would read as a state */
.price.main{border-color:var(--line-strong);background:var(--s-2)}
.price .p{
  font-family:var(--mono);font-size:38px;font-weight:500;line-height:1;margin:12px 0 7px;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;
}
.price .n{font-family:var(--mono);font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.12em;color:var(--text-3);line-height:1.3}

footer{border-top:1px solid var(--line);position:relative;z-index:1}
.foot{max-width:var(--w);margin:0 auto;padding:40px var(--pad-x);display:flex;gap:18px;align-items:center;flex-wrap:wrap;color:var(--text-3);font-size:14.5px}
.foot .sp{margin-left:auto}
.foot .wm{margin-right:0}

/* ============================================================
   ABOUT — the richness pass (2026-08-04)
   Everything here is scoped to `body.about`. The landing shares
   .card / .rows / .row / .ic / .v with this page and must not
   move, so nothing below is allowed to reach it.
   ============================================================ */

/* ---- scroll progress, welded to the bottom edge of the nav ----
   White, 2px, no hue: this reports position, not a state. */
.prog{position:absolute;left:0;right:0;bottom:-1px;height:2px;pointer-events:none;overflow:hidden}
.prog i{
  display:block;height:100%;width:100%;background:var(--text);opacity:.8;
  transform:scaleX(0);transform-origin:0 50%;
}
@media(prefers-reduced-motion:reduce){.prog{display:none}}

/* ---- the section rail: where you are in a long page ----
   Desktop only, and only where there is real gutter for it. Below
   1300px the .toc pills in the hero remain the whole affordance. */
.rail{
  position:fixed;top:50%;transform:translateY(-50%);z-index:50;display:none;flex-direction:column;gap:1px;
  right:clamp(16px,calc((100vw - var(--w))/2 - 96px),64px);
}
@media(min-width:1300px){html.js .rail{display:flex}}
.rail a{
  display:flex;align-items:center;justify-content:flex-end;gap:11px;padding:6px 0;text-decoration:none;
  font-family:var(--mono);font-size:10px;text-transform:uppercase;letter-spacing:.13em;line-height:1;color:var(--text-3);
  transition:color var(--d-tint) ease;
}
.rail .lbl{
  opacity:0;transform:translateX(5px);white-space:nowrap;
  transition:opacity var(--d-control) var(--ease),transform var(--d-control) var(--ease);
}
.rail .pip{
  width:20px;height:2px;border-radius:2px;background:var(--line-strong);flex:0 0 auto;
  transition:width var(--d-control) var(--ease),background var(--d-tint) ease;
}
.rail a:hover{color:var(--text-2)}
.rail a:hover .pip{background:var(--text-2)}
.rail a:hover .lbl{opacity:1;transform:none}
.rail a[aria-current="true"]{color:var(--text)}
.rail a[aria-current="true"] .pip{width:34px;background:var(--text)}
.rail a[aria-current="true"] .lbl{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){.rail .lbl{opacity:1;transform:none}}

/* the hero index tracks too, so the affordance exists before the rail does */
body.about .toc a[aria-current="true"]{color:var(--text);background:var(--s-2);border-color:var(--line-strong)}

/* NOTE: .rows / .row / .ic / .v / .card / .card-head are the shared component
   family and are deliberately NOT touched here. They were rebuilt in the same
   cut as this pass and the landing depends on them; anything below that wanted
   to re-tint a row or re-seat an icon was deleted rather than scoped. */

/* ---- the Log artifact, sharpened ----
   Log lines never animate (§10.3). Everything below is typography,
   surface and hover — the record typesets like a printed record. */
/* the run strip: three facts, tabular, on their own baseline */
.runstrip{display:flex;align-items:center;gap:16px;margin-left:auto;flex-wrap:wrap}
.runstat{display:flex;align-items:baseline;gap:6px;font-family:var(--mono);line-height:1}
.runstat i{font-style:normal;font-size:10px;text-transform:uppercase;letter-spacing:.13em;color:var(--text-3)}
.runstat b{font-size:16px;font-weight:500;color:var(--text);letter-spacing:-.01em;font-variant-numeric:tabular-nums}
.runstat u{text-decoration:none;font-size:11px;color:var(--text-3)}
/* the gutter index — an append-only record has row numbers */
body.about .log-row{grid-template-columns:26px auto 1fr auto;transition:background var(--d-tint) ease}
body.about .log-row:hover{background:rgba(255,255,255,.03)}
body.about .log-row .n{color:var(--text-3);font-size:11px;letter-spacing:.06em;opacity:.55}
body.about .log-row .e{color:var(--text-2)}
body.about .log-row.miss{background:rgba(255,255,255,.015)}
/* the verdict beat: the last line is the product, so it gets the weight */
body.about .log-row.verdict{
  grid-template-columns:26px auto 1fr auto;padding-top:19px;padding-bottom:19px;
  border-top:1px solid rgba(48,209,88,.34);
  box-shadow:inset 0 1px 0 rgba(48,209,88,.10);
}
body.about .log-row.verdict .e{font-size:15px;font-weight:500;letter-spacing:.06em;color:var(--verified)}
body.about .log-row.verdict .n{color:var(--verified);opacity:.7}
body.about .log-row.verdict:hover{background:var(--verified-dim)}
/* the footer of the record: what kind of object this is */
.card-foot{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  padding:13px var(--pad-in);border-top:1px solid var(--line);background:rgba(0,0,0,.25);
  font-family:var(--mono);font-size:10.5px;text-transform:uppercase;letter-spacing:.12em;color:var(--text-3);
}
.card-foot .r{margin-left:auto}
body.about .note{padding:20px var(--pad-in) var(--pad-body);border-top:1px solid var(--line)}
body.about .note .em{width:22px;margin-top:12px}
@media(max-width:640px){
  body.about .log-row{grid-template-columns:1fr}
  body.about .log-row .n{display:none}
  body.about .log-row.verdict{grid-template-columns:1fr}
  .card-foot{padding:12px 16px;gap:10px}
  .runstrip{gap:12px;width:100%;margin-left:0}
}

/* ---- 56 days, drawn as elapsed time ---- */
.elapsed{display:grid;grid-template-columns:34px 1fr;gap:0 20px;padding:30px 0 30px 6px;align-items:stretch}
.el-rail{position:relative;width:34px;display:flex;flex-direction:column;align-items:center}
.el-rail:before{content:"";position:absolute;top:0;bottom:0;left:50%;width:1px;background:var(--line)}
/* Ships drawn. It used to start at scaleY(0) and wait for a reveal class that
   nothing applies any more, so the rail's ticks rendered and the line between
   them never did. */
.el-fill{
  position:absolute;top:0;bottom:0;left:50%;width:1px;background:var(--line-strong);
}
/* eight ticks, because 56 days is eight weeks — the marks are the arithmetic */
.el-tick{position:absolute;left:50%;width:11px;height:1px;background:var(--line);transform:translateX(-50%)}
.el-body{display:flex;flex-direction:column;justify-content:space-between;gap:16px;min-height:172px}
.el-n{display:flex;align-items:baseline;gap:9px;font-family:var(--mono)}
.el-n b{font-size:clamp(30px,4vw,42px);font-weight:500;line-height:1;color:var(--text);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.el-n i{font-style:normal;font-size:12px;text-transform:uppercase;letter-spacing:.13em;color:var(--text-3)}
.el-sub{font-size:15px;color:var(--text-2);max-width:46ch;margin-top:9px}
.el-cap{font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.12em;color:var(--text-3)}
@media(max-width:620px){.elapsed{gap:0 14px;padding:22px 0}.el-body{min-height:150px}}

/* ---- THE LADDER — eight modules, three bands, one spine ---- */
.ladder{display:flex;flex-direction:column;gap:14px}
.lgroup{
  position:relative;background:var(--s-1);border:1px solid var(--line);border-radius:var(--r-3);
  backdrop-filter:blur(24px);overflow:hidden;
  box-shadow:0 1px 2px rgba(0,0,0,.4),0 8px 32px -12px rgba(0,0,0,.6);
}
.lgroup-head{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:13px 20px;border-bottom:1px solid var(--line);background:var(--s-2);
  font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.13em;
}
.lgroup-head .g{color:var(--text)}
.lgroup-head .s{color:var(--text-3);letter-spacing:.1em}
.lgroup-head .w{margin-left:auto;color:var(--text-3);font-variant-numeric:tabular-nums}
.lrungs{position:relative}
/* the spine, inset to the first and last node centre */
.lrungs:before{content:"";position:absolute;left:38px;top:34px;bottom:34px;width:1px;background:var(--line)}
.rung{
  position:relative;display:grid;grid-template-columns:36px 1fr auto;gap:16px;align-items:center;
  padding:15px 20px;border-bottom:1px solid var(--line);transition:background var(--d-tint) ease;
}
.rung:last-child{border-bottom:0}
.rung:hover{background:var(--s-2)}
.node{
  position:relative;z-index:1;display:flex;align-items:center;justify-content:center;
  width:36px;height:36px;border-radius:50%;border:1px solid var(--line);background:#000;
  font-family:var(--mono);font-size:12px;font-weight:500;color:var(--text-3);letter-spacing:.02em;
  transition:border-color var(--d-tint) ease,color var(--d-tint) ease,background var(--d-tint) ease;
}
.rung.open .node{border-color:var(--line-strong);color:var(--text);background:var(--s-3)}
.rung:hover .node{border-color:var(--line-strong)}
.rung .lx{min-width:0}
.rung .lx b{display:flex;align-items:center;gap:9px;font-weight:600;font-size:16.5px;letter-spacing:-.01em}
.rung .lx b .cn{font-family:var(--mono);font-size:10.5px;font-weight:500;text-transform:uppercase;letter-spacing:.13em;color:var(--text-3);padding:3px 8px;border:1px solid var(--line);border-radius:var(--r-pill)}
.rung .lx span{display:block;color:var(--text-2);font-size:14.5px;margin-top:3px}
.rung.sealed .lx b{color:var(--text-2)}
.rung .rt{display:flex;align-items:center;gap:12px;justify-self:end}
.rung .wk{font-family:var(--mono);font-size:12.5px;color:var(--text-3);white-space:nowrap;font-variant-numeric:tabular-nums}
.rung .wk b{color:var(--text-2);font-weight:500}
.rung .st{
  display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:var(--r-pill);
  border:1px solid var(--line);background:var(--s-1);white-space:nowrap;
  font-family:var(--mono);font-size:10.5px;font-weight:500;text-transform:uppercase;letter-spacing:.12em;color:var(--text-3);
}
.rung.open .st{color:var(--text);border-color:var(--line-strong)}
/* the terminal band — shipping is not a module, so it is not a rung */
/* The legend that makes the weeks column honest. It is three SENTENCES, so it
   is sans — mono is for facts, and a paragraph set in tracked-out uppercase
   mono is a label pretending to be a record. */
.lnote{
  margin-bottom:14px;max-width:74ch;
  font-size:14.5px;color:var(--text-3);line-height:1.6;
}
@media(max-width:680px){
  .rung{grid-template-columns:32px 1fr;gap:12px;padding:14px 16px}
  .lrungs:before{left:32px}
  .node{width:32px;height:32px;font-size:11px}
  .rung .rt{grid-column:2;justify-self:start;margin-top:6px}
  .lgroup-head{padding:12px 16px;font-size:10.5px}
}

/* ---- THE PATHS — one open, three waiting ---- */
body.about .paths{display:flex;flex-direction:column;gap:14px}
.plocked{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
@media(max-width:860px){.plocked{grid-template-columns:1fr}}
/* availability is not a verification, so it is never green — white carries open */
.pst{
  display:inline-flex;align-items:center;gap:7px;margin-left:auto;padding:6px 12px;border-radius:var(--r-pill);
  border:1px solid var(--line);background:var(--s-1);white-space:nowrap;
  font-family:var(--mono);font-size:10.5px;font-weight:500;text-transform:uppercase;letter-spacing:.12em;color:var(--text-3);
}
.pst.on{color:var(--text);border-color:var(--line-strong);background:var(--s-3)}
/* the floors, printed on every path — anticipation with arithmetic behind it */
.pfacts{display:flex;gap:0;flex-wrap:wrap;margin-top:18px;border-top:1px solid var(--line);padding-top:14px}
.pfacts div{display:flex;flex-direction:column;gap:5px;padding-right:26px;margin-right:26px;border-right:1px solid var(--line)}
.pfacts div:last-child{border-right:0;padding-right:0;margin-right:0}
.pfacts dt{font-family:var(--mono);font-size:10px;text-transform:uppercase;letter-spacing:.13em;color:var(--text-3)}
.pfacts dd{margin:0;font-family:var(--mono);font-size:14px;color:var(--text-2);font-variant-numeric:tabular-nums}
.pfacts dd b{color:var(--text);font-weight:500}
.plocked .pfacts{margin-top:16px;flex-wrap:nowrap}
/* `:not(:last-child)` matters: the plain `.plocked .pfacts div` form sat AFTER
   the `:last-child` reset at equal specificity and put the trailing 32px back
   on the last item, which is what pushed these two facts onto a second row and
   left the first one's divider hanging in mid-air. */
.plocked .pfacts div:not(:last-child){padding-right:16px;margin-right:16px}
.pwhen{
  margin-top:16px;
  font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.11em;color:var(--text-3);line-height:1.6;
}
/* slot 2 of the emoji layer — a marker opening a mono label pays the same
   optical correction .lab does, or the 🔒 renders at 11px and reads as lint */
.pwhen::first-letter{font-size:var(--em-label);letter-spacing:.34em}
@media(max-width:620px){
  /* A wrapping flex row cannot know which item ends a line, so the last item
     of every row but the last kept a divider with nothing beside it. On a
     phone the facts become a plain two-up grid and the dividers go entirely. */
  .pfacts{display:grid;grid-template-columns:1fr 1fr;gap:14px 18px}
  .pfacts div,.plocked .pfacts div:not(:last-child){
    padding-right:0;margin-right:0;border-right:0;
  }
}

/* ---- reserved testimonial slots, numbered ---- */

/* ---- prices, with the arithmetic shown ---- */
body.about .price{
  position:relative;display:flex;flex-direction:column;
  transition:background var(--d-tint) ease,border-color var(--d-tint) ease;
  box-shadow:0 1px 2px rgba(0,0,0,.4),0 8px 32px -12px rgba(0,0,0,.6);
}
body.about .price:hover{border-color:var(--line-strong);background:var(--s-2)}
body.about .price .p{font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.price .tag{
  position:absolute;top:18px;right:18px;padding:4px 10px;border-radius:var(--r-pill);
  border:1px solid var(--line-strong);background:var(--s-3);
  font-family:var(--mono);font-size:9.5px;font-weight:500;text-transform:uppercase;letter-spacing:.13em;color:var(--text);
}
.price .eq{
  margin-top:auto;padding-top:14px;border-top:1px solid var(--line);
  font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;color:var(--text-3);font-variant-numeric:tabular-nums;
}
.price .eq b{color:var(--text-2);font-weight:500}
/* Busy without .disabled — see the note in site.js. */
[data-busy="1"]{opacity:.5;pointer-events:none}

/* The briefing, when the file itself will not load. The poster otherwise sits
   there looking like a player waiting to be pressed, and every press does
   nothing — which is exactly how the unwired version felt for weeks. */
.player-dead{
  position:absolute;inset:auto 0 0;margin:0;padding:16px 20px;
  font-size:13.5px;line-height:1.5;color:var(--text-2);
  background:var(--s-2);border-top:1px solid var(--line);text-align:center;
}
/* The bar is a real slider now; it needs a hit area and a focus ring. */
.player-bar{cursor:pointer;touch-action:none}
.player-bar:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
.ctl.is-on{color:var(--text);background:var(--s-3)}
