/* ============ THE LANDING PAGE (2026-10-13, the owner's order) ============
   drec.live opens here before any app: one stage built around D-REC's reel. Scrolling turns the reel and lights the
   row of stations under the button while the visitor stays still; everything a visitor can do (get D-REC on any device, sign in,
   buy Pro, open the recorder in the browser) happens on this stage. Contract: the landing DESIGN-SPEC v1, with its v2
   addendum (2026-10-13: the eight stations as they are now, and the media slots).

   HOW THE WORK IS SPLIT. This file owns every look and the first-frame geometry; home.js measures the real panel
   heights and overwrites the geometry (--cx --cy --r --ytop --label-y --cta-y --pips-y --pips-x) on .stage, so the numbers below are
   close approximations whose only job is a first frame that does not jump. Never `transition: all`, never the
   default `ease`: every curve is the app's own (out, in-out, drawer, wipe). */

/* bundled type, the recorder's own files at the recorder's own URLs, so the cache is shared with /?web */
@font-face{font-family:"Archivo";font-style:normal;font-weight:100 900;font-stretch:62% 125%;font-display:swap;src:url(/fonts/archivo-300-900.woff2?rev=8707b13214f5) format("woff2")}
/* DREC Mono is IBM Plex Mono renamed; under the OFL the family may never carry the reserved name */
@font-face{font-family:"DREC Mono";font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/drec-mono-400.woff2?rev=2d8eb58acf63) format("woff2")}
@font-face{font-family:"DREC Mono";font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/drec-mono-500.woff2?rev=1f81144c0f3e) format("woff2")}
@font-face{font-family:"DREC Mono";font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/drec-mono-600.woff2?rev=f5dff07e9ae3) format("woff2")}

/* REGISTERED, SO THEY MOVE. --tint is the station's colour and has to INTERPOLATE between stations (an unregistered
   property flips at the halfway mark); --wdth is the headline's width axis, which the station roll animates from
   62% to 125%; --pad, --pips-h and the side safe areas are read back by home.js as resolved pixels. */
@property --tint{syntax:"<color>";inherits:true;initial-value:#e2440e}
@property --wdth{syntax:"<percentage>";inherits:true;initial-value:125%}
@property --pad{syntax:"<length>";inherits:true;initial-value:16px}
@property --pips-h{syntax:"<length>";inherits:true;initial-value:28px}
@property --safe-l{syntax:"<length>";inherits:true;initial-value:0px}
@property --safe-r{syntax:"<length>";inherits:true;initial-value:0px}

/* ------------------------------------------------------------------ tokens --- */
html:root{
  color-scheme:dark;
  --chassis-hi:#dcdfe0;--chassis-lo:#c3c6c8;--chassis-ink:#2b2e30;
  --stage:#030404;--stage-2:#0d0f10;
  --line:rgba(255,255,255,.08);--line-strong:rgba(255,255,255,.16);
  --ink:#f4f5f5;--ink-soft:#a7abae;--ink-faint:#6d7276;
  /* --ink-faint measures 4.2:1 on the stage, under AA for small type; the footer's 12-13 px lines use this one (5.4:1) */
  --ink-small:#888d91;
  --accent:#e2440e;--accent-hi:#ff6a33;--rec:#ff2d2d;
  --ease-out:cubic-bezier(.22,1,.36,1);--ease-in-out:cubic-bezier(.77,0,.175,1);
  --ease-drawer:cubic-bezier(.32,.72,0,1);--ease-wipe:cubic-bezier(.87,0,.13,1);
  --ease-expo:cubic-bezier(.16,1,.3,1);--ease-in:cubic-bezier(.4,0,1,1);
  --font-ui:"Archivo",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-mono:"DREC Mono","Cascadia Mono","SF Mono",ui-monospace,Menlo,monospace;
  --focus:var(--accent-hi);
  --safe-t:env(safe-area-inset-top,0px);--safe-r:env(safe-area-inset-right,0px);
  --safe-b:env(safe-area-inset-bottom,0px);--safe-l:env(safe-area-inset-left,0px);
  --fade:.32s;
  /* (the account card's own tokens are not here: home/account.css declares them on #acctModal itself) */

  /* FIRST-FRAME GEOMETRY, phones first (the narrow layout). The reel sits under two nav rows, its groove ring (7% of
     the radius outside the reel, .groove) clears them, and the headline, the body, the button and the row of station
     squares own the bottom third, where a thumb reaches. --ytop is the top of the groove; nothing is kept above it
     since the ring of tiles went (2026-10-16). */
  --bezel:0px;--stage-r:0px;
  --pad:clamp(16px,4.6vw,28px);
  --h1:clamp(2rem,9.6vw,2.6rem);
  --cta-h:50px;
  --pips-h:28px;--pips-gap:4px;
  --pad-b:calc(max(12px,var(--safe-b)) + 6px);
  --nav-h:calc(100px + var(--safe-t));
  --stage-h:100vh;--stage-h:100svh;
  --band-est:calc(1.8 * var(--h1) + 4.3rem + var(--cta-h) + 26px + var(--pips-h) + var(--pips-gap) + var(--pad-b));
  --below:30px;
  --ytop0:calc(var(--nav-h) + 8px);
  --r:clamp(56px,min(32vw,(var(--stage-h) - var(--ytop0) - var(--band-est) - var(--below)) / 2.14),260px);
  --slack:max(0px,var(--stage-h) - var(--ytop0) - var(--band-est) - var(--below) - 2.14 * var(--r));
  --ytop:calc(var(--ytop0) + var(--slack) * .35);
  --cx:50%;
  --cy:calc(var(--ytop) + 1.07 * var(--r));
  --label-y:calc(var(--cy) + 1.07 * var(--r) + 10px);
  --cta-y:calc(var(--label-y) + 38px);
  --pips-y:calc(var(--cta-y) + var(--cta-h) + 8px);
  --oled-w:168px;
  /* a clip's frame takes the stage's radius (the spec's 22 px on a phone, where the stage itself is full bleed) */
  --clip-r:22px;
}

/* ------------------------------------------------------------------ base --- */
*,*::before,*::after{box-sizing:border-box}
/* NO PULL TO REFRESH (2026-10-16, the owner's report from a phone): a finger turning the reel at the top of the deck
   pulled the whole page down into the browser's refresh. The page never overscrolls; the footer and the deck still
   scroll normally. */
html{background:var(--stage);-webkit-text-size-adjust:100%;text-size-adjust:100%;overflow-x:clip;overscroll-behavior-y:none}
body{margin:0;font:450 1.0625rem/1.55 var(--font-ui);color:var(--ink);background:transparent;overflow-x:clip;overscroll-behavior-y:none;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
[hidden]{display:none!important}
/* THE RESETS STOP AT THE ACCOUNT CARD. #acctModal is the recorder's own markup, styled by home/account.css as the
   recorder styles it; an element rule here would reach into it (an icon made a block, a button's background taken).
   :where() adds no weight, so inside the page these keep an element selector's specificity. */
:where(.page) img,:where(.page) svg{display:block}
:where(.page) a{color:inherit;-webkit-tap-highlight-color:transparent}
:where(.page) button{font:inherit;color:inherit;background:none;border:0;padding:0;margin:0;cursor:pointer;-webkit-tap-highlight-color:transparent}
:where(.page) :focus-visible{outline:2px solid var(--focus);outline-offset:3px}
::selection{background:var(--accent);color:#fff}
.vh{position:absolute!important;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
/* boot.js is handing the page to the recorder: nothing of this page should flash first */
.leaving body{visibility:hidden}
.nojs-only{display:none!important}

/* THE BEZEL. On a wide screen the page is the device: a brushed-silver frame (the chassis colours of the app's SILVER)
   with the black stage set into it. It is a fixed layer on the root, so it costs one paint, and it waits for the intro:
   the frame is the last thing to arrive. */
html::before{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:0;
  background:repeating-linear-gradient(0deg,rgba(255,255,255,.07) 0 1px,rgba(20,22,24,.035) 1px 2px,transparent 2px 3px),
    linear-gradient(180deg,var(--chassis-hi) 0%,#d0d3d5 52%,var(--chassis-lo) 100%);
  transition:opacity .7s var(--ease-out)}

/* ------------------------------------------------------------------ the deck --- */
.deck{position:relative;height:calc(8 * 100vh);height:calc(8 * 100svh)}
.stops{position:absolute;inset:0;pointer-events:none}
.stop{position:absolute;left:0;top:calc(var(--i) * 100vh);top:calc(var(--i) * 100svh);width:1px;height:1px}
.stage-wrap{position:sticky;top:0;z-index:1;height:100vh;height:100svh;padding:var(--bezel)}
.stage{position:relative;height:100%;overflow:hidden;isolation:isolate;border-radius:var(--stage-r);
  --tint:#e2440e;transition:--tint .8s var(--ease-out);
  background:linear-gradient(180deg,var(--stage-2) 0%,var(--stage) 46%,var(--stage) 100%);
  box-shadow:0 0 0 1px rgba(0,0,0,.55),inset 0 1px 0 rgba(255,255,255,.06),inset 0 0 0 1px rgba(255,255,255,.03)}

/* ------------------------------------------------------------------ nav --- */
.nav{position:absolute;z-index:6;left:0;right:0;top:0;display:grid;align-items:center;
  grid-template-columns:minmax(0,1fr) auto;grid-template-rows:42px 40px;grid-template-areas:"brand act" "plat plat";row-gap:8px;column-gap:12px;
  padding:calc(8px + var(--safe-t)) calc(var(--pad) + var(--safe-r)) 0 calc(var(--pad) + var(--safe-l))}
.brand{grid-area:brand;justify-self:start;display:inline-flex;align-items:center;gap:9px;min-height:44px;padding:0 2px;border-radius:8px;
  text-decoration:none;font-weight:800;font-stretch:112%;letter-spacing:.06em;font-size:15px;line-height:1;color:var(--ink)}
.brand-mark{display:inline-block;flex:none;width:9px;height:9px;border-radius:2px;background:var(--accent);box-shadow:0 0 10px rgba(226,68,14,.5)}

/* THE PLATFORMS, ALWAYS IN VIEW. Each one goes to the Get station; the visitor's own (boot.js puts os-* on <html>
   before the first frame) carries a lit LED and, for a screen reader, the words "this device". Hairlines separate
   them, not middle dots. */
.plat{grid-area:plat;justify-self:stretch;display:flex;align-items:center;height:40px;padding:0 3px;border-radius:999px;
  border:1px solid var(--line-strong);background:rgba(13,15,16,.66);
  -webkit-backdrop-filter:blur(14px) saturate(1.2);backdrop-filter:blur(14px) saturate(1.2)}
.plat a{position:relative;flex:1 1 0;display:inline-flex;align-items:center;justify-content:center;gap:6px;height:32px;padding:0 4px;border-radius:999px;
  font-size:12.5px;font-weight:560;letter-spacing:.005em;line-height:1;color:var(--ink-soft);text-decoration:none;white-space:nowrap;
  transition:color .2s var(--ease-out),background-color .2s var(--ease-out)}
.plat a + a::before{content:"";position:absolute;left:0;top:10px;bottom:10px;width:1px;background:var(--line);pointer-events:none}
.led{display:none;flex:none;width:5px;height:5px;border-radius:50%;background:var(--accent-hi);box-shadow:0 0 6px 1px rgba(255,106,51,.75)}
.mine-note{display:none}
.plat a.is-mine,.os-ios .plat a[data-os="ios"],.os-android .plat a[data-os="android"],.os-mac .plat a[data-os="mac"],
.os-windows .plat a[data-os="windows"],.os-web .plat a[data-os="web"]{color:var(--ink)}
.plat a.is-mine .led,.os-ios .plat a[data-os="ios"] .led,.os-android .plat a[data-os="android"] .led,.os-mac .plat a[data-os="mac"] .led,
.os-windows .plat a[data-os="windows"] .led,.os-web .plat a[data-os="web"] .led,
.plat a.is-mine .mine-note,.os-ios .plat a[data-os="ios"] .mine-note,.os-android .plat a[data-os="android"] .mine-note,
.os-mac .plat a[data-os="mac"] .mine-note,.os-windows .plat a[data-os="windows"] .mine-note,.os-web .plat a[data-os="web"] .mine-note{display:inline-block}
/* the lit LED would push its own platform's name off the middle of its cell, so an empty twin of it balances the
   other side (2026-10-16, the owner's centring note) */
.plat a.is-mine::after,.os-ios .plat a[data-os="ios"]::after,.os-android .plat a[data-os="android"]::after,.os-mac .plat a[data-os="mac"]::after,
.os-windows .plat a[data-os="windows"]::after,.os-web .plat a[data-os="web"]::after{content:"";flex:none;width:5px;height:5px}

.nav-act{grid-area:act;justify-self:end;display:flex;align-items:center;gap:8px}
/* the account chip: account.js writes SIGN IN / FREE / TRIAL nD / PRO / OWNER into it, so it is set in the machine's
   own label type (mono, small capitals) and the markup's "Sign in" reads the same before and after */
.nav .chip{position:relative;display:inline-flex;align-items:center;justify-content:center;height:36px;min-width:44px;padding:0 14px;border-radius:999px;
  border:1px solid var(--line-strong);font:600 11.5px/1 var(--font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft);white-space:nowrap;
  transition:color .2s var(--ease-out),border-color .2s var(--ease-out),background-color .2s var(--ease-out)}
.nav .chip.is-pro{color:var(--accent-hi);border-color:rgba(226,68,14,.6)}
/* busy while account.js loads: dimmed, but in the small-type ink (--ink-faint is 4.0:1 here, under AA at 11.5 px) */
.nav .chip[aria-busy="true"]{color:var(--ink-small)}
.nav-pro{display:none;position:relative;align-items:center;gap:8px;height:36px;padding:0 16px 0 14px;border-radius:999px;
  border:1px solid rgba(226,68,14,.5);font-size:13.5px;font-weight:650;line-height:1;color:var(--ink);text-decoration:none;white-space:nowrap;
  transition:border-color .2s var(--ease-out),box-shadow .2s var(--ease-out)}
.nav-pro .led{display:inline-block;border-radius:1.5px}
@media (hover:hover) and (pointer:fine){
  .plat a:hover{color:var(--ink);background:rgba(255,255,255,.05)}
  .nav .chip:hover{color:var(--ink);border-color:rgba(255,255,255,.34)}
  .nav-pro:hover{border-color:var(--accent);box-shadow:0 0 0 1px rgba(226,68,14,.35),0 0 18px -4px rgba(226,68,14,.7)}
  .brand:hover .brand-mark{box-shadow:0 0 14px 2px rgba(226,68,14,.7)}
}
/* under a finger every control is at least 44 px each way; the drawing stays the same size */
@media (pointer:coarse){
  .nav .chip::after,.nav-pro::after{content:"";position:absolute;inset:-4px -2px}
}

/* ------------------------------------------------------------------ the wheel --- */
/* the wheel is one group so it can step back as a whole on the stations that need the room, and step aside for a clip
   on a wide screen (home.js scales it about the top of the groove and slides it sideways) */
.wheel{position:absolute;inset:0;z-index:1;transform-origin:var(--cx) var(--ytop);pointer-events:none}
.wheel > *{pointer-events:auto}
.glow{position:absolute;left:var(--cx);top:var(--cy);width:calc(var(--r) * 5.6);aspect-ratio:1;translate:-50% -50%;border-radius:50%;pointer-events:none!important;
  background:radial-gradient(closest-side,color-mix(in oklab,var(--tint) 22%,transparent) 0%,color-mix(in oklab,var(--tint) 8%,transparent) 48%,transparent 100%)}

/* THE REEL: the colorway's rotor art as the platter, the hub art as the button, a sheen that holds still while the
   platter turns under it, two ghost copies for the app's motion blur, and a thin groove ring around it all.
   A FINGER TURNS IT (2026-10-16, the owner's report from a phone): it used to keep the browser's vertical pan, so a
   finger meant to turn the wheel slid the page instead and, at the top, pulled it to refresh. The browser now leaves
   every touch on the reel to home.js, which turns it as it does for a mouse; the page still scrolls everywhere else. */
.reel{position:absolute;z-index:2;left:calc(var(--cx) - var(--r));top:calc(var(--cy) - var(--r));width:calc(var(--r) * 2);height:calc(var(--r) * 2);
  border-radius:50%;touch-action:none;-webkit-user-select:none;user-select:none}
.reel::before{content:"";position:absolute;inset:1.5%;border-radius:50%;pointer-events:none;
  box-shadow:0 calc(var(--r) * .1) calc(var(--r) * .34) rgba(0,0,0,.78),0 2px 6px rgba(0,0,0,.65)}
.platter,.ghost,.sheen,.sweep{position:absolute;inset:0;border-radius:50%}
.platter{will-change:transform}
.skin{position:absolute;inset:0;width:100%;height:100%;border-radius:50%;opacity:0;transition:opacity .42s var(--ease-out);-webkit-user-drag:none}
.skin.is-in{opacity:1;z-index:2}
.skin.is-under{opacity:1;z-index:1;transition:none}
.ghost{width:100%;height:100%;opacity:0;pointer-events:none;will-change:transform,opacity;-webkit-user-drag:none}
.sheen{pointer-events:none;overflow:hidden}
.sheen i{position:absolute;inset:0;border-radius:50%;
  background:conic-gradient(from 210deg,transparent 0deg,rgba(255,255,255,.10) 40deg,transparent 95deg,transparent 200deg,rgba(255,255,255,.05) 250deg,transparent 300deg);
  animation:sheen-drift 24s linear infinite}
@keyframes sheen-drift{to{transform:rotate(360deg)}}
/* one specular pass across the platter when the real reel takes over from the intro */
.sweep{pointer-events:none;overflow:hidden;opacity:0}
.sweep i{position:absolute;top:-20%;bottom:-20%;left:-70%;width:240%;
  background:linear-gradient(105deg,transparent 40%,rgba(255,255,255,.28) 50%,transparent 60%);transform:translateX(-45%)}
.sweep.is-on{opacity:1}
.sweep.is-on i{animation:sweep .95s var(--ease-out) forwards}
@keyframes sweep{to{transform:translateX(45%)}}
.groove{position:absolute;inset:calc(var(--r) * -.07);border-radius:50%;border:1px solid var(--line);pointer-events:none}
.groove::after{content:"";position:absolute;inset:-1px;border-radius:50%;border-top:1px solid rgba(255,255,255,.06);border-bottom:1px solid rgba(0,0,0,.4)}
/* on a phone a station's clip takes the reel's place at its size, and the reel fades behind it (home.js also takes it
   out of the tab order; the button under it still opens the recorder) */
.reel.is-covered{opacity:0}
@media (hover:hover) and (pointer:fine){
  .reel{cursor:grab}
  .is-dragging,.is-dragging *{cursor:grabbing!important}
}

/* THE HUB IS THE BUTTON. On hover, a 2 px accent ring with a 6 px glow and a play glyph on a dark lens (the hubs run
   from black to bright silver, so the glyph brings its own ground); on press, the app's key travel. A finger always
   gets at least 72 px, whatever the drawing's size. */
.hub{position:absolute;z-index:5;left:35%;top:35%;width:30%;height:30%;border-radius:50%;display:block;outline:none;
  transition:transform .1s var(--ease-out)}
.hub::before{content:"";position:absolute;left:50%;top:50%;width:max(100%,calc(72px / var(--ke,1)));height:max(100%,calc(72px / var(--ke,1)));translate:-50% -50%;border-radius:50%}
.hub::after{content:"";position:absolute;inset:-3px;border-radius:50%;pointer-events:none;opacity:0;
  box-shadow:0 0 0 2px var(--accent),0 0 6px 2px rgba(226,68,14,.55);transition:opacity .2s var(--ease-out)}
.cap{position:absolute;inset:0;width:100%;height:100%;border-radius:50%;opacity:0;transition:opacity .42s var(--ease-out);-webkit-user-drag:none}
.cap.is-in{opacity:1;z-index:2}
.cap.is-under{opacity:1;z-index:1;transition:none}
.hub .go{position:absolute;z-index:3;inset:27%;display:grid;place-items:center;border-radius:50%;background:rgba(0,0,0,.58);
  opacity:0;scale:.86;transition:opacity .2s var(--ease-out),scale .25s var(--ease-out)}
.hub .go svg{width:46%;height:46%;translate:3% 0;fill:#fff}
.hub:focus-visible::after,.hub:focus-visible .go{opacity:1}
.hub:focus-visible .go{scale:1}
@media (hover:hover) and (pointer:fine){
  .hub:hover::after,.hub:hover .go{opacity:1}
  .hub:hover .go{scale:1}
}
.hub:active{transform:translateY(2px) scale(.985);transition-duration:.1s}

/* ------------------------------------------------------------------ under the reel --- */
/* the station's name with its chapter in the display's mono: eight labels stacked in one cell, so the line never
   changes width, and only the current one shows */
.label{position:absolute;z-index:3;left:0;right:0;top:var(--label-y);margin:0;display:grid;justify-items:center;pointer-events:none;will-change:transform}
.lb{grid-area:1/1;display:inline-flex;align-items:baseline;gap:.75em;visibility:hidden;white-space:nowrap;
  font-weight:700;font-stretch:112%;font-size:clamp(1.05rem,1.4vw,1.35rem);line-height:1.15;letter-spacing:.02em;color:var(--ink)}
.lb.is-on,.lb.is-leaving{visibility:visible}
.lb .ch{font:500 12px/1 var(--font-mono);letter-spacing:.06em;font-variant-numeric:tabular-nums;color:var(--ink-soft);font-stretch:normal}
.lb .wd-mask{padding:.12em 0 .18em;margin:-.12em 0 -.18em}

/* the launch, under the reel on a wide screen and in the thumb zone on a phone. The light pill is the one solid
   button on the stage; the accent square is D-REC's own mark, not an arrow. */
.cta{position:absolute;z-index:4;display:inline-flex;align-items:center;justify-content:center;gap:11px;height:var(--cta-h);padding:0 24px 0 20px;border-radius:999px;
  background:var(--ink);color:#08090a;font-size:15.5px;font-weight:650;line-height:1;letter-spacing:.005em;white-space:nowrap;text-decoration:none;
  box-shadow:0 14px 34px -14px rgba(0,0,0,.9),inset 0 -1px 0 rgba(0,0,0,.16);
  transition:background-color .2s var(--ease-out),box-shadow .2s var(--ease-out),scale .1s var(--ease-out);will-change:transform}
.cta-mark{flex:none;width:8px;height:8px;border-radius:2px;background:var(--accent);box-shadow:0 0 8px rgba(226,68,14,.65)}
@media (hover:hover) and (pointer:fine){.cta:hover{background:#fff;box-shadow:0 18px 40px -14px rgba(0,0,0,.95),0 0 0 4px rgba(255,255,255,.08)}}
.cta:active{scale:.985;transition-duration:.06s}
/* A PHONE GETS ITS STORE FIRST (2026-10-24, the owner's order): on iOS and Android the pill is the App Store or Google
   Play, and "open in your browser instead" is a small underlined line under it, never a second pill. --alt-h is the
   room that line takes between the button and the row of squares (0 everywhere else). */
:root{--alt-h:0px}
html.os-ios,html.os-android{--alt-h:30px}
.cta-store,.cta-alt{display:none}
.os-ios #cta,.os-android #cta{display:none}
.os-ios #cta-ios,.os-android #cta-android{display:inline-flex}
.os-ios .cta-alt,.os-android .cta-alt{display:flex}
.cta-alt{position:absolute;z-index:4;align-items:center;justify-content:center;height:var(--alt-h);margin:0 auto;padding:0 8px;
  left:calc(var(--pad) + var(--safe-l));right:calc(var(--pad) + var(--safe-r));bottom:calc(var(--pad-b) + var(--pips-h) + var(--pips-gap));
  width:max-content;max-width:calc(100% - 2 * var(--pad));font-size:13px;font-weight:500;line-height:1;white-space:nowrap;
  color:var(--ink-soft);text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px;-webkit-tap-highlight-color:transparent;will-change:transform}
@media (hover:hover) and (pointer:fine){.cta-alt:hover{color:var(--ink)}}

/* THE STATIONS, A ROW OF SQUARES (2026-10-16, the owner's order: "a straight line underneath the open D-REC in browser
   thing ... the squares without the circles but in the design of each circle ... small boxes really tiny ... highlight
   when we're on it"). Straight under the button and centred on it (home.js writes --pips-x from the button's own
   centre, and on a wide screen moves the row with it). Each square is the plain material at the left edge of its
   colorway's tile art (the image scaled so 64 x 64 of its 200 x 128 pixels fill it: no reel is drawn there), the
   others dimmed and smaller, the current one full size with a hairline in the station's tint. The visible square is
   tiny; the link around it is 26 x 28 px, so it stays an easy target. */
.pips{position:absolute;z-index:4;left:var(--pips-x,50%);bottom:var(--pad-b);translate:-50% 0;display:flex;align-items:center;justify-content:center;
  height:var(--pips-h);margin:0;padding:0;will-change:transform}
.pip{position:relative;display:grid;place-items:center;width:26px;height:var(--pips-h);border-radius:7px;-webkit-tap-highlight-color:transparent}
.pip:focus-visible{outline-offset:-3px}
.pip-sq{position:relative;display:block;width:9px;height:9px;border-radius:2px;overflow:hidden;background:#141617;opacity:.5;
  box-shadow:0 0 0 1px rgba(255,255,255,.14);transition:width .25s var(--ease-out),height .25s var(--ease-out),opacity .25s var(--ease-out),box-shadow .25s var(--ease-out)}
.pip-art{position:absolute;left:0;top:-50%;width:312.5%;height:200%;max-width:none;-webkit-user-drag:none}
.pip.is-selected .pip-sq{width:13px;height:13px;border-radius:3px;opacity:1;box-shadow:0 0 0 1.5px var(--stage),0 0 0 2.5px var(--tint),0 0 10px -2px var(--tint)}
@media (hover:hover) and (pointer:fine){.pip:not(.is-selected):hover .pip-sq{opacity:.85}}

/* ------------------------------------------------------------------ panels --- */
.panels{position:absolute;z-index:3;display:grid;pointer-events:none}
.panel{grid-area:1/1;align-self:end;min-width:0;visibility:hidden;pointer-events:none}
.panel.is-on{visibility:visible;pointer-events:auto}
.panel.is-leaving{visibility:visible}
/* THE ONE LOUD THING: Archivo at its widest and heaviest. The station roll animates --wdth from 62% to 125% while the
   letters rise, so every headline arrives condensed and opens to full width. */
.headline{margin:0;font-family:var(--font-ui);font-weight:800;font-stretch:var(--wdth);font-size:var(--h1);line-height:.9;letter-spacing:-.028em;
  color:var(--ink);text-wrap:balance}
/* a line's clip leaves room for descenders and accents, which a .9 line-height would otherwise cut */
.headline .ln-mask{padding:.08em 0 .18em;margin:-.08em 0 -.18em}
.panel:focus{outline:none}
/* THE WORDS GET THEIR AIR (2026-10-16, the owner's spacing note): Archivo's word spaces run narrow at this weight, so
   the words take a little more space between them, and the headline (line-height .9, descenders below it) a little
   more room above them */
.body{margin:16px 0 0;max-width:46ch;font-size:1.0625rem;font-weight:450;font-stretch:100%;line-height:1.55;letter-spacing:.006em;word-spacing:.05em;color:var(--ink-soft);text-wrap:pretty}
/* a station's small print under its words (Private's offline line, the account lines on Get and Pro): small, but in the
   secondary ink, never the faint one */
.words{min-width:0}
.note{margin:10px 0 0;max-width:46ch;font-size:13px;line-height:1.45;letter-spacing:.006em;word-spacing:.04em;color:var(--ink-soft);text-wrap:pretty}
/* the words, the trays and the clips follow the headline in; a tray only ever fades (it may hold store badges) */
.panel .body,.panel .tray,.panel > .note,.words > .note,.panel .clip{opacity:0;transition:opacity var(--fade) var(--ease-out)}
.panel .body{translate:0 8px;transition:opacity var(--fade) var(--ease-out),translate .5s var(--ease-out)}
.panel.is-on .body,.panel.is-on .tray,.panel.is-on > .note,.panel.is-on .words > .note,.panel.is-on .clip{opacity:1;transition-delay:.12s}
.panel.is-on .body{translate:none}
/* without the letter roll (no script library, or reduced motion) the headline crossfades with the rest */
.no-roll .panel .headline{opacity:0;transition:opacity var(--fade) var(--ease-out)}
.no-roll .panel.is-on .headline{opacity:1}

/* THE TRAY: the Get list and the Pro plans. When the stage is too short for all of it, home.js gives it a height and
   it scrolls on its own, with a soft edge that says there is more. */
.tray{min-width:0;max-height:var(--tray-max,none);overflow:auto;padding:10px 6px 6px;margin:-10px -6px -6px;overscroll-behavior:auto;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.18) transparent}
.tray.is-scroll{scroll-padding-block-end:28px;-webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 28px),transparent);mask-image:linear-gradient(180deg,#000 calc(100% - 28px),transparent)}
/* at the end there is no more, so the edge lifts and the last line (Pro's account line) reads at full ink; a control
   reached by Tab is scrolled clear of the edge, outline and all (home.js trayEnd, 2026-10-13) */
.tray.is-scroll.is-end{-webkit-mask-image:none;mask-image:none}

/* GET */
.get-list{list-style:none;margin:0;padding:0;display:flex;gap:10px}
/* a card's badge and its line sit on the card's centre line (2026-10-16, the owner's centring note: badges of four
   different widths left-aligned left uneven gaps), and the "For this device" tag sits centred on its top edge */
.get-row{position:relative;display:grid;align-content:start;justify-items:center;text-align:center;gap:9px;padding:15px 12px 12px;border-radius:16px;min-width:0;
  background:rgba(255,255,255,.025);border:1px solid var(--line);transition:border-color .25s var(--ease-out),background-color .25s var(--ease-out)}
/* .get-cap, not .cap: .cap is the hub's two image layers (absolute, transparent until .is-in), and a caption
   wearing it was laid invisibly over its own store badge, taking the badge's clicks */
.get-row .get-cap{margin:0;font-size:13px;line-height:1.4;color:var(--ink-soft)}
.get-row .alt{display:inline-block;margin-top:3px;color:var(--ink);text-decoration:underline;text-decoration-color:rgba(255,255,255,.35);text-underline-offset:3px}
.mine-tag{display:none;position:absolute;top:-9px;left:50%;translate:-50% 0;align-items:center;gap:7px;padding:4px 7px 3px;border-radius:6px;border:1px solid rgba(226,68,14,.6);
  background:var(--stage);font:600 10px/1 var(--font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--accent-hi)}
.mine-tag::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--accent-hi);box-shadow:0 0 6px 1px rgba(255,106,51,.75)}
.get-row.is-mine,.os-ios .get-row[data-os="ios"],.os-android .get-row[data-os="android"],.os-mac .get-row[data-os="mac"],
.os-windows .get-row[data-os="windows"],.os-web .get-row[data-os="web"]{border-color:rgba(226,68,14,.55);background:rgba(226,68,14,.045)}
.get-row.is-mine .mine-tag,.os-ios .get-row[data-os="ios"] .mine-tag,.os-android .get-row[data-os="android"] .mine-tag,.os-mac .get-row[data-os="mac"] .mine-tag,
.os-windows .get-row[data-os="windows"] .mine-tag,.os-web .get-row[data-os="web"] .mine-tag{display:inline-flex}
.get-row.is-pointed{border-color:rgba(255,255,255,.5)}
/* store badges: Apple 40 px, Google Play 46 px, Microsoft 44 px, never resized, angled or recoloured. Only the ring
   around a badge ever lights. */
.badge{display:inline-block;line-height:0;border-radius:9px;transition:box-shadow .18s var(--ease-out)}
.badge-apple svg{width:auto;height:40px}
.badge-play{border-radius:7px}
.badge-play img{width:auto;height:46px}
.badge-ms{border-radius:6px}
.badge-ms img{width:auto;height:44px}
.dl-btn{display:inline-flex;align-items:center;height:44px;padding:0 18px;border-radius:12px;background:#000;border:1px solid rgba(255,255,255,.3);
  color:#fff;font-size:14px;font-weight:650;line-height:1;white-space:nowrap;text-decoration:none;transition:border-color .2s var(--ease-out),scale .1s var(--ease-out)}
@media (hover:hover) and (pointer:fine){
  .get-row:hover{border-color:var(--line-strong);background:rgba(255,255,255,.04)}
  .badge:hover{box-shadow:0 0 0 3px var(--stage),0 0 0 5px rgba(244,245,245,.45)}
  .dl-btn:hover{border-color:rgba(255,255,255,.7)}
  .get-row .alt:hover{text-decoration-color:currentColor}
}
.badge:active{box-shadow:0 0 0 3px var(--stage),0 0 0 5px var(--accent-hi)}
.dl-btn:active{scale:.985}

/* PRO */
.pro-state{display:flex;align-items:center;gap:8px;margin:0 0 12px;font:600 11.5px/1 var(--font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--accent-hi)}
.pro-state::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--accent-hi);box-shadow:0 0 6px 1px rgba(255,106,51,.75)}
.plans{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.plan{position:relative;display:grid;align-content:start;justify-items:start;gap:3px;min-height:80px;padding:13px 14px 12px;border-radius:12px;text-align:left;
  border:1px solid var(--line-strong);background:rgba(255,255,255,.03);color:var(--ink);
  transition:border-color .2s var(--ease-out),background-color .2s var(--ease-out),scale .1s var(--ease-out)}
.plan.is-lit{border-color:rgba(226,68,14,.62);background:rgba(226,68,14,.05)}
.plan-name{font-size:13.5px;font-weight:650;line-height:1.2}
.plan-price{min-height:1.15em;font-size:21px;font-weight:800;font-stretch:112%;line-height:1.15;letter-spacing:-.01em;font-variant-numeric:tabular-nums}
.plan-per{font-size:12.5px;line-height:1.3;color:var(--ink-soft)}
.plan-save{position:absolute;top:-9px;right:10px;padding:4px 6px 3px;border-radius:6px;border:1px solid rgba(226,68,14,.7);background:#1a0c06;
  font:600 10px/1 var(--font-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--accent-hi)}
@media (hover:hover) and (pointer:fine){
  .plan:hover{border-color:rgba(255,255,255,.4);background:rgba(255,255,255,.05)}
  .plan.is-lit:hover{border-color:var(--accent)}
}
.plan:active{scale:.985;transition-duration:.06s}
/* THE SKELETON: no price is ever guessed or cached into the page; the space is held by a shimmer until the API answers */
.plan-price:empty::before,.offer .sk{content:"";display:block;height:.62em;margin-top:.3em;border-radius:4px;
  background:linear-gradient(90deg,rgba(255,255,255,.06) 0%,rgba(255,255,255,.13) 50%,rgba(255,255,255,.06) 100%) 0 0/200% 100%;
  animation:skel 1.3s linear infinite}
.plan-price:empty::before{width:3.4em}
.offer .sk{height:.78em;margin:.42em 0}
.offer .sk.is-short{width:62%}
@keyframes skel{to{background-position:-200% 0}}
.plans[aria-busy="false"] .plan-price:empty::before{animation:none;opacity:.5}
.offer,.renew{margin:12px 0 0;max-width:62ch;font-size:15px;line-height:1.5;color:var(--ink-soft)}
.renew{margin-top:4px}
.plan-fail{margin:10px 0 0;font-size:14px;color:var(--ink)}
.plan-retry{margin-left:6px;color:var(--accent-hi);text-decoration:underline;text-underline-offset:3px}
.pro-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 18px;margin-top:12px}
.legal{display:flex;gap:18px;margin:0;font-size:14px}
.legal a,.made a{color:var(--ink);text-decoration:underline;text-decoration-color:rgba(255,255,255,.3);text-underline-offset:3px}
.ghost-btn{display:inline-flex;align-items:center;height:44px;padding:0 18px;border-radius:999px;border:1px solid var(--line-strong);
  font-size:14.5px;font-weight:600;line-height:1;color:var(--ink);text-decoration:none;transition:border-color .2s var(--ease-out),scale .1s var(--ease-out)}
@media (hover:hover) and (pointer:fine){.ghost-btn:hover{border-color:rgba(255,255,255,.45)}.legal a:hover,.made a:hover{text-decoration-color:currentColor}}
.ghost-btn:active{scale:.985}
/* the account line, right under the sign-in button's row: the account holds the email and the plan, not recordings */
.pro-foot .note{flex:1 0 100%;margin:0}

/* ------------------------------------------------------------------ the clips --- */
/* THE MEDIA SLOT (v2, 2026-10-13): real phone footage of the app, portrait, in a 1 px hairline frame with the stage's
   radius. No device drawn around it and no interface drawn on it. home.js sizes and places each one from the reel (at
   the reel's height: beside it on a wide screen, over it on a phone) through --clip-l, --clip-b, --clip-w and --clip-h,
   measured from the panels' bottom edge, because a clip lives in its station's panel and is inert with it. It stays
   hidden until its file exists (home.js MEDIA). The radius never passes 14% of the frame's width, about a phone
   screen's own corner, so a narrow frame does not turn into a pill. */
.clip{position:absolute;z-index:2;margin:0;left:var(--clip-l,0px);bottom:var(--clip-b,0px);width:var(--clip-w,0px);height:var(--clip-h,0px);
  border-radius:min(var(--clip-r),calc(var(--clip-w,0px) * .14));background:#000;box-shadow:0 18px 40px -18px rgba(0,0,0,.9)}
.clip::after{content:"";position:absolute;inset:0;border-radius:inherit;border:1px solid var(--line);pointer-events:none}
.clip-v{display:block;width:100%;height:100%;border-radius:inherit;object-fit:cover;background:#000;-webkit-user-select:none;user-select:none}
/* THE ONE CONTROL. Every clip is a muted loop (2026-10-16, the owner's order: no clip on the page has sound): pause and
   play, small, inside the frame's corner (a loop has to be stoppable); on reduced motion the loop waits on its poster
   and this is a play button in its middle. */
.clip-btn{position:absolute;z-index:1;right:10px;bottom:10px;display:inline-flex;align-items:center;justify-content:center;gap:8px;
  width:36px;height:36px;padding:0;border-radius:999px;border:1px solid var(--line-strong);background:rgba(0,0,0,.62);color:var(--ink);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);opacity:.8;
  transition:opacity .2s var(--ease-out),background-color .2s var(--ease-out),border-color .2s var(--ease-out),scale .1s var(--ease-out)}
.clip-btn svg{flex:none;width:12px;height:12px;fill:currentColor}
.clip-btn .i-pause,.clip[data-state="on"] .clip-btn .i-play{display:none}
.clip[data-state="on"] .clip-btn .i-pause{display:inline}
.clip[data-state="still"] .clip-btn{right:auto;bottom:auto;left:50%;top:50%;translate:-50% -50%;width:56px;height:56px;opacity:1}
.clip[data-state="still"] .clip-btn svg{width:18px;height:18px;translate:3% 0}
.clip-btn:focus-visible{opacity:1}
@media (hover:hover) and (pointer:fine){
  .clip-v{cursor:pointer}
  .clip:hover .clip-btn{opacity:1}
  .clip-btn:hover{background:rgba(0,0,0,.82);border-color:rgba(255,255,255,.34)}
}
.clip-btn:active{scale:.96}

/* ------------------------------------------------------------------ the OLED strip --- */
/* decoration in the display's own language: a timecode that runs with the scroll (5 minutes a station, the length
   of one D-REC chapter) and the chapter number. Hidden from assistive tech. */
.oled{position:absolute;z-index:3;right:calc(var(--pad) + var(--safe-r));bottom:var(--pad-b);display:none;align-items:center;gap:12px;height:34px;padding:0 14px;
  border-radius:999px;background:#000;border:1px solid var(--line);font:500 12.5px/1 var(--font-mono);letter-spacing:.06em;font-variant-numeric:tabular-nums;
  color:var(--ink);white-space:nowrap;pointer-events:none}
.oled-ch{color:var(--ink-soft)}

/* ------------------------------------------------------------------ footer --- */
.foot{position:relative;z-index:2;margin:var(--bezel);margin-top:0;padding:clamp(48px,7vw,96px) calc(var(--pad) + var(--safe-r)) calc(28px + var(--safe-b)) calc(var(--pad) + var(--safe-l));
  border-radius:var(--stage-r);background:var(--stage);box-shadow:0 0 0 1px rgba(0,0,0,.55),inset 0 1px 0 rgba(255,255,255,.05);font-size:15px;line-height:1.5}
.foot-top{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:40px 24px}
.foot-brand{grid-column:1/-1}
.foot-word{display:flex;align-items:center;gap:10px;margin:0;font-weight:800;font-stretch:112%;letter-spacing:.06em;font-size:20px;line-height:1}
.foot-word .brand-mark{width:10px;height:10px}
.foot-tag{margin:12px 0 0;color:var(--ink-soft)}
.foot-h{margin:0 0 12px;font-size:13px;font-weight:600;letter-spacing:.01em;color:var(--ink-small)}
.foot-col ul{list-style:none;margin:0;padding:0;display:grid;gap:2px}
.foot-col a{display:inline-flex;align-items:center;min-height:32px;color:var(--ink-soft);text-decoration:none;transition:color .2s var(--ease-out)}
.foot-col a[href^="mailto"]{overflow-wrap:anywhere}
.foot-base{margin-top:clamp(40px,6vw,72px);padding-top:24px;border-top:1px solid var(--line);display:grid;gap:12px}
.made{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:0;color:var(--ink-soft)}
.knight{display:inline-flex;align-items:center;gap:8px;text-decoration:none!important}
/* the Knight AI+AV helm, the maker's mark: a mask so it takes the ink, and the accent with a glow on hover */
.helm{display:inline-block;width:18px;height:18px;background:var(--ink-faint);-webkit-mask:url(/helm-mask.png) center/contain no-repeat;mask:url(/helm-mask.png) center/contain no-repeat;
  transition:background-color .25s var(--ease-out),filter .25s var(--ease-out)}
.tm,.copy{margin:0;max-width:90ch;font-size:12px;line-height:1.55;color:var(--ink-small)}
@media (hover:hover) and (pointer:fine){
  .foot-col a:hover{color:var(--ink)}
  .knight:hover .helm{background:var(--accent);filter:drop-shadow(0 0 6px rgba(226,68,14,.7))}
}
.knight:focus-visible .helm{background:var(--accent)}

/* ------------------------------------------------------------------ the intro --- */
/* THE OVERLAY, NOT THE PAGE (2026-10-14, found in the browser pass). boot.js puts the class "intro" on <html> too, so
   a bare .intro{display:none} hid the whole document for the length of the intro: nothing was ever on screen until the
   class came off (first paint 2.2 to 3.1 s, measured; computed display:none on <html> at 0.6 s). Scoped under body, the
   rule reaches only the overlay, and .js.intro .intro (higher specificity) still shows it while the intro plays. */
body .intro{display:none}
.js.intro .intro{display:block;position:fixed;inset:0;z-index:90;background:#000;pointer-events:auto;cursor:default;
  animation:intro-failsafe .45s linear 4.2s forwards}
/* the frame waits for the intro (and, on a wide screen, comes back on the same timer if nothing ever lifts it) */
html.intro::before{opacity:0}
body .intro{--mx:50%;--my:calc(var(--bezel) + var(--cy))}
.intro-gl{position:absolute;inset:0;width:100%;height:100%;display:block;transition:opacity .34s var(--ease-out)}
.intro-mark{position:absolute;left:var(--mx,50%);top:var(--my,46%);width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:2.5px;fill:var(--accent);overflow:visible;
  animation:mark-in .9s var(--ease-out) both;transition:opacity .22s var(--ease-out),left .3s var(--ease-out),top .3s var(--ease-out)}
@keyframes mark-in{
  0%{opacity:1;transform:scale(.6);box-shadow:0 0 0 0 rgba(226,68,14,0)}
  30%{transform:scale(1)}
  62%{transform:scale(1.25);box-shadow:0 0 24px 6px rgba(226,68,14,.55)}
  100%{opacity:1;transform:scale(1);box-shadow:0 0 14px 2px rgba(226,68,14,.4)}
}
.intro-tc{position:absolute;left:var(--mx,50%);top:calc(var(--my,46%) + 30px);translate:-50% 0;display:inline-flex;align-items:center;gap:8px;
  font:500 12px/1 var(--font-mono);letter-spacing:.08em;font-variant-numeric:tabular-nums;color:var(--ink-soft);opacity:.55;transition:opacity .3s var(--ease-out)}
.intro-tc.is-on{opacity:1}
.intro-tc.is-off{opacity:0}
/* THE FIRST FRAME IS ALREADY THE DECK (2026-10-14): the mark starts visible (it only grows in) and the deck's zeros sit dim
   under it from the first frame, so the black is never empty, even before the scripts arrive. */
.intro-rec{width:7px;height:7px;border-radius:50%;background:var(--rec);box-shadow:0 0 8px rgba(255,45,45,.75);animation:rec-blink 1s steps(2,jump-none) infinite}
@keyframes rec-blink{50%{opacity:.35}}
/* WITHOUT WEBGL2: the same idea in CSS. Two fields of rings, each turning about a point a few pixels off the centre in
   opposite directions, differenced against each other, which is a moire; both turns run on the compositor. */
.intro-css{position:absolute;inset:0;overflow:hidden;clip-path:circle(var(--iris,150vmax) at var(--mx,50%) var(--my,46%))}
.moire{position:absolute;left:var(--mx,50%);top:var(--my,46%);width:0;height:0;animation:moire-turn 1.7s linear infinite}
.moire.is-b{animation-duration:2.3s;animation-direction:reverse;mix-blend-mode:difference}
.moire i{position:absolute;left:-150vmax;top:-150vmax;width:300vmax;height:300vmax;translate:var(--o,9px) 0;transition:translate .4s var(--ease-in-out);
  background:repeating-radial-gradient(circle at 50% 50%,rgba(220,223,224,.5) 0 1px,transparent 1.5px 6px)}
.moire.is-b i{translate:calc(-1 * var(--o,9px)) 0}
@keyframes moire-turn{to{transform:rotate(360deg)}}
/* the explosion: the black goes, the canvas fades over the real reel, and the page opens outward from the reel */
.js.intro.is-exploding .intro{background:transparent;pointer-events:none}   /* must outrank .js.intro .intro's black, or the whole explosion plays behind it */
.is-exploding .intro-gl,.is-exploding .intro-css{opacity:0;transition:opacity .34s var(--ease-out)}
.is-exploding .intro-tc{opacity:0}
.js.intro.is-exploding .intro-mark{animation:none;opacity:0}   /* mark-in's fill holds opacity at 1; dropping the animation lets the mark fade */
@keyframes intro-failsafe{to{opacity:0;visibility:hidden}}
@keyframes bezel-failsafe{to{opacity:1}}

/* ------------------------------------------------------------------ grain --- */
.grain{position:fixed;inset:0;z-index:40;pointer-events:none;background:url(/ob-grain.webp) 0 0/256px 256px;opacity:.05;mix-blend-mode:overlay}

/* ================================================================== LAYOUTS ===
   home.js reads --layout and solves the same geometry: narrow (phones and portrait tablets, the default above),
   wide (a desktop window), split (any landscape screen shorter than 600 px, where a centred reel cannot fit). */
.stage{--layout:narrow}
/* phones and upright tablets: from the bottom up, the row of station squares, the button, then the words, all on the
   stage's centre line under the centred reel (2026-10-16, the owner's centring note: the words used to hug the left) */
.panels{left:calc(var(--pad) + var(--safe-l));right:calc(var(--pad) + var(--safe-r));bottom:calc(var(--pad-b) + var(--pips-h) + var(--pips-gap) + var(--alt-h) + var(--cta-h) + 14px)}
.cta{left:calc(var(--pad) + var(--safe-l));right:calc(var(--pad) + var(--safe-r));bottom:calc(var(--pad-b) + var(--pips-h) + var(--pips-gap) + var(--alt-h));max-width:440px;margin-inline:auto}
.headline,.body,.note,.offer,.renew,.plan-fail{text-align:center}
.body,.note,.offer,.renew{margin-inline:auto}
.pro-state,.pro-foot{justify-content:center}
/* a phone's Get list is a strip that swipes sideways (a swipe across a strip is expected; a page turning sideways
   under a vertical swipe is not), so the five platforms take one row of the thumb zone */
.panel-tall .tray{margin-top:4px}
#getTray{overflow-x:auto;overflow-y:hidden;max-height:none;scroll-snap-type:x mandatory;scroll-padding-inline:calc(var(--pad) + var(--safe-l));
  margin:4px calc(-1 * (var(--pad) + var(--safe-r))) -6px calc(-1 * (var(--pad) + var(--safe-l)));
  padding:10px calc(var(--pad) + var(--safe-r)) 6px calc(var(--pad) + var(--safe-l));scrollbar-width:none}
#getTray::-webkit-scrollbar{display:none}
.get-row{flex:0 0 auto;width:min(236px,72vw);scroll-snap-align:start}
.body{font-size:15px;line-height:1.5}
.plan{padding:12px 11px 11px}
.plan-price{font-size:18px;font-stretch:100%}
@media (max-width:359.98px){.plat a{font-size:11.5px;padding:0 2px}.plan{padding:11px 9px 10px}.plan-price{font-size:16.5px}.plan-name{font-size:12.5px}}
@media (min-width:600px) and (max-width:899.98px){
  html:root{--h1:clamp(2.4rem,6.2vw,3.6rem);--band-est:calc(1.8 * var(--h1) + 4.5rem + var(--cta-h) + 26px + var(--pips-h) + var(--pips-gap) + var(--pad-b))}
  .plat{justify-self:center;padding:0 4px}
  .plat a{flex:none;padding:0 12px;font-size:13.5px}
  .cta{left:50%;right:auto;width:max-content;translate:-50% 0;margin:0}
  .body{font-size:1rem}
}
@media (min-width:600px){.foot-top{grid-template-columns:repeat(3,minmax(0,1fr))}}
/* a short phone held upright (an iPhone SE with Safari's bars): the label under the reel goes, so the reel keeps its
   size; the lit square in the row and the headline already say where you are */
@media (orientation:portrait) and (max-height:619.98px){html:root{--below:0px}.label{display:none}}
@media (orientation:portrait) and (max-height:519.98px){
  html:root{--nav-h:calc(50px + var(--safe-t));--cta-h:44px}
  .nav{grid-template-rows:42px;grid-template-areas:"brand act"}
  .plat{display:none}
}
/* a tablet held upright has room for the OLED beside the button */
@media (min-width:720px) and (max-width:899.98px){.oled{display:inline-flex;bottom:calc(var(--pad-b) + var(--pips-h) + var(--pips-gap) + 8px)}}

@media (min-width:900px) and (min-height:600px){
  html:root{
    --bezel:clamp(10px,1.25vw,18px);--stage-r:28px;
    --pad:clamp(24px,3.2vw,56px);--pad-b:var(--pad);
    --h1:clamp(2.4rem,min(6.6vw,8.6svh),7rem);
    --nav-h:72px;
    --pips-h:26px;--pips-gap:0px;
    --stage-h:calc(100vh - 2 * var(--bezel));--stage-h:calc(100svh - 2 * var(--bezel));
    --band-est:calc(1.8 * var(--h1) + var(--pad));
    --below:147px;
    --ytop0:calc(var(--nav-h) + 12px);
    --r:clamp(60px,(var(--stage-h) - var(--ytop0) - var(--band-est) - var(--below)) / 2.14,min(23svh,17vw));
    --slack:max(0px,var(--stage-h) - var(--ytop0) - var(--band-est) - var(--below) - 2.14 * var(--r));
    --ytop:calc(var(--ytop0) + var(--slack) * .5);
    --label-y:calc(var(--cy) + 1.07 * var(--r) + 12px);
    --cta-y:calc(var(--label-y) + 38px);
    --pips-y:calc(var(--cta-y) + var(--cta-h) + 6px);
  }
  html::before{opacity:1}
  html.intro::before{opacity:0;animation:bezel-failsafe .5s linear 4.2s forwards}
  .stage{--layout:wide}
  .nav{grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);grid-template-rows:72px;grid-template-areas:"brand plat act";padding-top:0}
  .plat{justify-self:center;height:42px;padding:0 4px}
  .plat a{flex:none;height:34px;padding:0 14px;font-size:13.5px}
  .nav-pro{display:inline-flex}
  .cta{left:50%;right:auto;bottom:auto;top:var(--cta-y);translate:-50% 0;margin:0;max-width:none}
  .cta-alt{left:50%;right:auto;bottom:auto;top:calc(var(--cta-y) + var(--cta-h) + 2px);translate:-50% 0;margin:0;max-width:none}
  .pips{top:var(--pips-y);bottom:auto}
  .panels{left:calc(var(--pad) + var(--safe-l));right:calc(var(--pad) + var(--safe-r));bottom:var(--pad)}
  /* the spread: the words keep their own edge here, beside each other, not on the centre line */
  .headline,.body,.note,.offer,.renew,.plan-fail{text-align:start}
  .body,.note,.offer,.renew{margin-inline:0}
  .pro-state{justify-content:flex-start}
  .pro-foot{justify-content:space-between}
  /* the headline and the words side by side, like a spread, their last lines on one baseline */
  .panel:not(.panel-tall){display:grid;grid-template-columns:minmax(0,1fr) minmax(13rem,min(24rem,32%));column-gap:clamp(24px,3.2vw,56px);align-items:end;align-items:last baseline}
  .panel:not(.panel-tall) .body{margin:0}
  .body{font-size:1rem;line-height:1.55}
  .plan{padding:13px 14px 12px}
  .plan-price{font-size:21px;font-stretch:112%}
  .foot-top{grid-template-columns:minmax(0,1.5fr) repeat(3,minmax(0,1fr))}
  .foot-brand{grid-column:auto}
  /* the two stations with something to do: headline and words on the left, the tray on the right, and the OLED
     steps aside (home.js fades it as the reel steps back) */
  .panel-tall{padding-right:0;display:grid;grid-template-columns:minmax(0,1fr) minmax(0,var(--tray-w));grid-template-rows:1fr auto;
    grid-template-areas:"h tray" "p tray";column-gap:clamp(24px,3vw,48px);align-items:end;--tray-w:clamp(24rem,46vw,38rem)}
  /* Get's account line stands under its tray, in the tray's column (both columns end on the panel's bottom edge) */
  #p-get{--tray-w:clamp(35.6rem,46vw,38rem);grid-template-rows:1fr auto auto;grid-template-areas:"h tray" "p tray" "p note"}
  #p-get > .note{grid-area:note;margin-top:10px}
  .panel-tall .headline{grid-area:h}
  .panel-tall .body{grid-area:p;margin-top:18px}
  .panel-tall .tray{grid-area:tray;align-self:end;margin:-10px -6px -6px;container-type:inline-size}
  /* here the Get tray scrolls up and down like Pro's, so it takes home.js's height cap again: the phone's rule above
     (an id, so it outranks .tray) sets none, and without the cap a short window put the button over the badges */
  #getTray{overflow:auto;max-height:var(--tray-max,none);scroll-snap-type:none;margin:-10px -6px -6px;padding:10px 6px 6px;scrollbar-width:thin}
  /* the cards wrap on the tray's centre line, so a short last row is centred instead of leaving a hole at its end, and
     the rows stand far enough apart that a card's "For this device" tag never touches the card above (2026-10-16) */
  .get-list{display:flex;flex-wrap:wrap;justify-content:center;gap:18px 10px}
  .get-row{width:auto;flex:0 0 calc((100% - 10px) / 2)}
  html:root{--clip-r:28px}
}
/* room for the OLED strip in the bottom-right corner, and for the words at their full size */
@media (min-width:1200px) and (min-height:600px){
  .oled{display:inline-flex;bottom:var(--pad)}
  .panel:not(.panel-tall){padding-right:calc(var(--oled-w) + 24px)}
  .body{font-size:1.0625rem}
}
/* three across whenever each card can still hold the 161 px Microsoft badge: two rows instead of three is what keeps
   the Get station from scrolling on an iPad held sideways */
@container (min-width:34.8rem){.get-row{flex-basis:calc((100% - 20px) / 3);padding-inline:8px}}

/* SPLIT: a landscape phone or a short window. The reel moves to the right two thirds and the words take the left
   column, top to bottom; nothing steps back, a tray scrolls if it must. */
@media (orientation:landscape) and (max-height:599.98px){
  html:root{
    --bezel:0px;--stage-r:0px;
    --pad:clamp(14px,3vw,28px);--pad-b:calc(max(10px,var(--safe-b)) + 4px);
    --h1:clamp(1.55rem,min(4.2vw,8.4svh),2.4rem);
    --nav-h:calc(50px + var(--safe-t));
    --stage-h:100vh;--stage-h:100svh;
    --ytop0:calc(var(--nav-h) + 4px);
    --below:30px;
    --r:clamp(48px,(var(--stage-h) - var(--ytop0) - var(--below) - var(--pad-b)) / 2.14,34svh);
    --slack:0px;--ytop:var(--ytop0);
    --cx:68%;
    --label-y:calc(var(--cy) + 1.07 * var(--r) + 8px);
  }
  html::before{opacity:0}
  .stage{--layout:split}
  .nav{grid-template-columns:auto minmax(0,1fr) auto;grid-template-rows:50px;grid-template-areas:"brand plat act";padding-top:var(--safe-t)}
  .plat{justify-self:center;height:36px;max-width:min(470px,100%)}
  .plat a{flex:none;height:28px;padding:0 9px;font-size:12px}
  .panels{left:calc(var(--pad) + var(--safe-l));right:auto;width:min(46%,30rem);top:calc(var(--nav-h) + 6px);bottom:calc(var(--pad-b) + var(--pips-h) + var(--pips-gap) + var(--alt-h) + 44px + 10px);align-content:end}
  .cta{left:calc(var(--pad) + var(--safe-l));right:auto;width:max-content;max-width:min(46%,30rem);height:44px;bottom:calc(var(--pad-b) + var(--pips-h) + var(--pips-gap) + var(--alt-h));margin:0;translate:none;font-size:14.5px}
  .cta-alt{right:auto;margin:0;padding:0 2px}
  /* the words are a column beside the reel here, so they keep their own edge; the label stands on the reel's own
     centre line, not the stage's (2026-10-16: it sat under the words column) */
  .headline,.body,.note,.offer,.renew,.plan-fail{text-align:start}
  .body,.note,.offer,.renew{margin-inline:0}
  .pro-state{justify-content:flex-start}
  .pro-foot{justify-content:space-between}
  .label{left:var(--cx);right:auto;translate:-50% 0}
  .body{font-size:14px;line-height:1.45}
  .panel-tall .tray{margin-top:0}
  #getTray{margin:0 -6px -6px;padding:10px 6px 6px;overflow-x:auto;scroll-padding-inline:6px}
  .get-row{width:210px}
  .oled{display:none}
  .label .lb{font-size:1rem}
}

/* ------------------------------------------------------------------ JavaScript states --- */
/* the row of squares appears when home.js has lit the right one and placed it under the button; the reel and the
   label wait for it too when the page opens on a station other than the first (a /get link), so the first frame
   never shows the wrong colorway or the wrong square */
.js .pips{opacity:0}
.ready .pips{opacity:1;transition:opacity .45s var(--ease-out)}
.js[data-at] .reel,.js[data-at] .label{opacity:0}
@media (min-width:900px) and (min-height:600px){.js[data-at] .cta,.js[data-at] .cta-alt{opacity:0}}
.ready .reel,.ready .cta,.ready .cta-alt{transition:opacity .35s var(--ease-out)}
/* OPENED ON A STATION: the right panel shows from the first frame, before any script has run (station ids, v2) */
.js[data-at="wheel"] #p-moment,.js[data-at="transcript"] #p-moment,.js[data-at="original"] #p-moment,.js[data-at="get"] #p-moment,
.js[data-at="private"] #p-moment,.js[data-at="chapters"] #p-moment,.js[data-at="pro"] #p-moment{visibility:hidden}
.js[data-at="wheel"] #p-wheel,.js[data-at="transcript"] #p-transcript,.js[data-at="original"] #p-original,.js[data-at="get"] #p-get,
.js[data-at="private"] #p-private,.js[data-at="chapters"] #p-chapters,.js[data-at="pro"] #p-pro{visibility:visible;pointer-events:auto}
.js[data-at="wheel"] #p-wheel :is(.body,.tray,.note),.js[data-at="transcript"] #p-transcript :is(.body,.tray,.note),
.js[data-at="original"] #p-original :is(.body,.tray,.note),.js[data-at="get"] #p-get :is(.body,.tray,.note),
.js[data-at="private"] #p-private :is(.body,.tray,.note),.js[data-at="chapters"] #p-chapters :is(.body,.tray,.note),
.js[data-at="pro"] #p-pro :is(.body,.tray,.note){opacity:1;translate:none}
/* while the page is being dragged by the reel, nothing under the pointer selects */
.is-dragging{-webkit-user-select:none;user-select:none}

/* Lenis (desktop wheel smoothing): the three rules its stylesheet carries that matter here */
html.lenis,html.lenis body{height:auto}
.lenis.lenis-stopped{overflow:clip}
.lenis.lenis-smooth iframe{pointer-events:none}
/* the account door scrolls on its own and never hands a scroll to the page behind it */
#acctModal{overscroll-behavior:contain}

/* ================================================================== PREFERENCES === */
/* REDUCED MOTION: no intro, no spin, no drift, no letter roll; a station changes as a 150 ms crossfade */
@media (prefers-reduced-motion:reduce){
  html:root{--fade:.15s}
  .js.intro .intro{display:none}
  html.intro::before{opacity:1;animation:none}
  .sheen i,.intro-rec,.plan-price:empty::before,.offer .sk{animation:none}
  .skin,.cap{transition-duration:.15s}
  .panel .body{translate:none;transition:opacity .15s var(--ease-out)}
  .stage{transition-duration:.15s}
  .cta,.hub,.plan,.dl-btn,.ghost-btn,.clip-btn,.pip-sq{transition-duration:0s}
  .hub:active,.clip-btn:active{transform:none;scale:none}
}
/* REDUCED TRANSPARENCY: no grain, solid surfaces */
@media (prefers-reduced-transparency:reduce){
  .grain{display:none}
  .plat{background:#0d0f10;-webkit-backdrop-filter:none;backdrop-filter:none}
  .hub .go{background:#000}
  .clip-btn{background:#000;-webkit-backdrop-filter:none;backdrop-filter:none}
}
/* MORE CONTRAST: brighter secondary ink, firmer hairlines, no grain */
@media (prefers-contrast:more){
  html:root{--ink-soft:#d2d5d7;--ink-faint:#a9adb0;--line:rgba(255,255,255,.24);--line-strong:rgba(255,255,255,.4)}
  .grain{display:none}
  .pip-sq{opacity:.8}
}
/* FORCED COLOURS: the system paints; the lit square and the visitor's platform keep a shape, not only a colour */
@media (forced-colors:active){
  .pip.is-selected .pip-sq{outline:2px solid Highlight;outline-offset:2px}
  .get-row.is-mine{border:3px solid Highlight}
  .cta,.dl-btn,.plan,.ghost-btn,.nav .chip,.nav-pro,.clip-btn{border:2px solid ButtonText}
  .clip::after{border-color:CanvasText}
  .grain,.glow{display:none}
}

/* ================================================================== WITHOUT JAVASCRIPT ===
   A plain, readable document: the nav, one still reel, every station's words in order, the platforms and the footer.
   Nothing here is sticky, hidden or waiting for a script. The station anchors (.stops) go with the row of squares, so
   a station link (a platform, Get Pro) does not jump in this mode; the words it would land on are all on the page. */
.no-js .deck{height:auto}
.no-js .stops,.no-js .pips,.no-js .label,.no-js .oled,.no-js .ghost,.no-js .sheen,.no-js .plans,.no-js .offer,.no-js #proSignIn{display:none}
.no-js .nojs-only{display:inline-flex!important}
.no-js .stage-wrap{position:static;height:auto}
.no-js .stage{height:auto;overflow:visible;display:flex;flex-direction:column;align-items:stretch;padding-bottom:48px}
.no-js .nav{position:relative}
.no-js .wheel{position:relative;inset:auto;height:auto;padding:24px 0}
.no-js .reel{position:relative;left:auto;top:auto;margin:0 auto;width:min(64vw,360px);height:auto;aspect-ratio:1}
.no-js .glow{display:none}
.no-js .cta{position:relative;inset:auto;translate:none;align-self:center;margin:8px auto 32px;width:max-content;max-width:calc(100% - 32px)}
.no-js .cta-alt{position:relative;inset:auto;translate:none;align-self:center;margin:-20px auto 32px}
.no-js .panels{position:relative;inset:auto;display:grid;gap:56px;padding:0 calc(var(--pad) + var(--safe-r)) 0 calc(var(--pad) + var(--safe-l))}
.no-js .panel{grid-area:auto;visibility:visible;pointer-events:auto;padding-right:0}
.no-js .panel .body,.no-js .panel .tray,.no-js .panel .note{opacity:1;translate:none}
.no-js .body{margin-top:14px}
.no-js #getTray{margin:8px 0 0;padding:0;overflow:visible}
.no-js .get-list{flex-wrap:wrap}
