/* =============================================================================
   RadiusXR InspirePRO — splash scroll styles
   -----------------------------------------------------------------------------
   TWO COORDINATE SYSTEMS, ON PURPOSE.
     #bg      the art plane: authored at 1920x1080, positioned in those pixels,
              and scaled as one unit by fit() in splash.js. Nothing inside it
              needs a media query.
     .st-copy the copy and chrome layer: laid out against the VIEWPORT with
              clamp() and vh/vw, so type never scales and never crops.

   Z-ORDER
     1 stage ground · #bg      2 backlight (#glow)    3 dot lattice (#grid)
     4 hero plates (.plate)    5 sequences (.seq)     6 shroud + pulse overlays
     6 copy (.st-copy)         7 rail and scroll cue  8 CTAs   9+ dev chrome

   SECTIONS, in file order
     1  tokens, reset, base black        6  sequence slots + preloader
     2  art plane and its layers         7  section index (dev)
     3  copy layout: keel, columns       8  notes, banners, overlays (dev)
     4  content break (state 05)         9  chrome gate (H / ?chrome=0)
     5  reveal mechanics + CTAs         10  phone (< 768) + per-state overlays

   Development-only rules are marked (dev) and are hidden together by the chrome
   gate near the end of the file.
   ========================================================================== */

*{box-sizing:border-box}
/* ONE BASE BLACK.
   --ink is the page ground and the only place the value lives. The optics run
   (states with black: 1 in the config) drops to pure #000 from splash.js, and
   the six optics modules are rendered on that same black inside their own
   files, so the base never steps at a beat boundary. tools/test.js measures the
   boundaries and fails the build if they drift apart. */
:root{
  --face:"Interval Pro","Helvetica Neue",Helvetica,Arial,sans-serif;
  --ink:#0A0A0A;
  --blue:#00aeef; --mute:#9a9a9a;   /* body copy: was #787878, brought up 2026-09-24 */
}
html{background:var(--ink)}
body{margin:0;background:var(--ink);color:#fff;
     font-family:var(--face);-webkit-font-smoothing:antialiased;overflow-x:hidden}
#stage{position:fixed;inset:0;overflow:hidden;background:var(--ground, var(--ink));z-index:1}
/* COPY VIGNETTE (0.20.81, Fatima 2026-10-06: titles and body hard to read where
   the art runs under the copy column). A left-side ramp of the ink colour under
   the copy layer and above the art: z-index 6 like .st-copy, but ::before paints
   first, so every copy block sits on top of it. Right half of the frame untouched. */
#stage::before{content:""; position:absolute; inset:0; z-index:6; pointer-events:none;
  opacity:var(--vigk,1); transition:opacity .6s ease;   /* per beat: vig: in splash.copy.js */
  background:linear-gradient(in oklab 90deg, rgba(10,10,10,var(--vig)) 0%, rgba(10,10,10,calc(var(--vig) * .74)) 18%, rgba(10,10,10,calc(var(--vig) * .3)) 32%, rgba(10,10,10,0) 44%)}
html.novig #stage::before{display:none}
:root{ --vig:0.65 }   /* Ramiro 2026-10-07, was .46. copy vignette darkness, 0 = off, 1 = black at the left edge */
html.portrait #stage::before{display:none}   /* phone and tablet already fade the floor under the copy (#stage::after, below) */   /* --ground: splash.js sets it while a state with states[].ground is showing (the reveal) */
/* Two layers, two fits.
   #bg      COVERS the viewport — art crops rather than leaving bars. Scaled as
            one unit by fit() in splash.js (SPLASH_CONFIG.tuning.fit).
   .st-copy LAYS OUT AGAINST THE VIEWPORT — copy and chrome never scale, so
            type stays crisp and nothing falls off the edge. */
#bg{position:absolute;left:50%;top:50%;width:1920px;height:1080px;
    transform-origin:center center;z-index:1;overflow:visible}

/* ---- parallax layers: three depths, two either side of the copy ---- */
.px{position:fixed;inset:0;pointer-events:none;overflow:hidden}
#px-far{z-index:0}
#px-mid{z-index:2}
#px-near{z-index:4}
.px i{position:absolute;display:block;will-change:transform}

/* ---- backlight: one element behind the art, moved and sized per state ----
   Lives in the 1920x1080 plane like the plates, so it registers with the
   product at every breakpoint. A soft blue ellipse, blurred, under the art
   (z 2, plates are z 4): it only reads where a plate is transparent, which is
   the point — it is a light BEHIND the headset, not a wash over it. Position,
   size and strength come from states[].glow; on/off from tuning.backlight. */
#glow, #glow2{position:absolute;left:0;top:0;width:1000px;height:1000px;border-radius:50%;pointer-events:none;
      background:radial-gradient(closest-side,#3985dc 0%,rgba(57,133,220,.55) 38%,rgba(2,6,11,0) 100%);
      filter:blur(90px);transform-origin:0 0;will-change:transform,opacity;z-index:2;opacity:0}
/* PHONES (html.low, set by splash.js): no GPU filters anywhere. Two 1000px
   layers under filter:blur(90px), scaled to ~3000px, first rasterised on the
   first scroll, is exactly what crashed iOS Safari ("a problem repeatedly
   occurred", 2026-10-08). The gradient itself carries the falloff instead. */
html.low #glow, html.low #glow2{filter:none; will-change:auto;
      background:radial-gradient(closest-side,rgba(57,133,220,.85) 0%,rgba(57,133,220,.45) 28%,rgba(57,133,220,.14) 60%,rgba(2,6,11,0) 100%)}
html.low .callout .panel, html.low .callout .mid{backdrop-filter:none; -webkit-backdrop-filter:none; background:rgba(14,18,24,.72)}
html.low .seq .ph .pr{filter:none}
html.low .hist-stem{filter:none}

/* ---- persistent dot lattice ---- */
#grid{position:absolute;left:160px;top:69px;width:1600px;height:942px;z-index:3;pointer-events:none}

/* ---- hero plates (the only raster layer) ---- */
/* A state with no still keeps its slot but no src — and Chromium draws a
   src-less <img> with a 1px broken-image frame, which was the faint line
   along the top and bottom of the window on every clip-only beat. */
.plate:not([src]){display:none}
.plate{position:absolute;left:0;top:0;width:1920px;height:1080px;opacity:0;z-index:4;
       will-change:opacity;user-select:none;
       /* CONTAIN, not the browser default of stretch-to-fit. A plate delivered
          at 16:9 renders pixel-identically either way; a plate delivered at the
          wrong aspect now letterboxes instead of silently distorting, which is
          the difference between a bug you can see and a bug you cannot. It also
          makes a plate register exactly the way a clip frame does, since the
          canvas draw uses the same contain fit. */
       object-fit:contain;object-position:center}
/* No edge feathering. The art shows exactly as delivered, top and bottom, so
   what you are judging is the plate itself and not a treatment over it. */

/* ---- dither: kills gradient banding without an image codec ---- */
#tone{position:absolute;inset:0;z-index:5;pointer-events:none;opacity:.05;
      mix-blend-mode:overlay;
      background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E")}


/* =============================================================================
   COPY LAYOUT  (v012)
   -----------------------------------------------------------------------------
   Copy is NOT part of the scaled canvas. It is a real layout, laid out against
   the viewport, so it cannot crop, letterbox or drift at any window shape.

   Three rules govern it:

   1. ONE CONTAINER. Every state uses the same grid: a text column on the left,
      an optional callout on the right, both sitting on the same baseline and
      inside the same gutters. States differ in content, never in position.

   2. ANCHORED TO THE BOTTOM, not to a y coordinate. The block grows upward from
      a fixed distance above the CTAs, so a long description pushes the headline
      up rather than running off the screen.

   3. TYPE SCALES WITH clamp(), not with a transform. It grows with the viewport
      between a readable floor and the Figma size as its ceiling.

   The art behind it still covers the viewport and is still allowed to crop —
   that is the point of separating them.
   ========================================================================== */

:root{
  /* side gutter: 160px at 1920, never below 24px on a phone */
  /* GRID. The page is a 12-column layout and always has been — 8.33vw is one
     twelfth — but the columns were implicit. They are tokens now so the overlay
     (press L) draws the same grid the layout actually uses, not a picture of one. */
  --cols: 12;
  --gutter: clamp(24px, 8.33vw, 160px);   /* = 1 column at 1920 */
  --col-gap: clamp(12px, 1.25vw, 24px);
  --grid-w: min(100vw, var(--shell));
  --col-w: calc((var(--grid-w) - (2 * var(--gutter)) - ((var(--cols) - 1) * var(--col-gap))) / var(--cols));
  /* distance from the bottom of the viewport to the top of the CTA row */
  --floor: clamp(28px, 3.6vh, 39px);      /* Figma page 06: CTA button top 956, height 85, bottom 1041 of 1080 */
  /* the safe band: nothing critical is allowed outside it */
  --shell: 2200px;
}

.st-copy{
  position:fixed; inset:0; z-index:6; pointer-events:none;
  max-width: var(--shell); margin-inline:auto;
}
.st-copy.in{pointer-events:auto}
.st-copy > *{min-width:0}

/* THE KEEL. Figma page 06 puts a 240x1 #676767 rule ("Divider Top") at y705 of
   1080 and hangs every copy block off it: counter and title stack UP from 20
   above the rule, tagline and body stack DOWN from 20 below it. Line counts
   change, the rule never moves — that is what keeps the run from jittering
   section to section. 705/1080 = 65.28vh. */
:root{ --keel: 65.28vh; --keel-gap: clamp(12px, 1.85vh, 20px); }

.col{position:absolute; left:var(--gutter); top:0; bottom:0;
     /* --cwn is the Figma text-box width in px, unitless: exact at 1920, scales below */
     width: clamp(280px, calc(var(--cwn, 512) * 100vw / 1920), calc(var(--cwn, 512) * 1px));
     pointer-events:none}
/* copy.tw: the title keeps the full column (--cwn), tagline and body get their own
   narrower width (--bwn, from copy.w). Without tw, --bwn falls back to --cwn. */
.col .below{right:auto;
     width: clamp(280px, calc(var(--bwn, var(--cwn, 512)) * 100vw / 1920), calc(var(--bwn, var(--cwn, 512)) * 1px))}
.col > *{pointer-events:auto}
.col .rule{position:absolute; left:0; top:var(--keel);
           width:clamp(120px, 12.5vw, 240px); height:1px; background:#676767}
.col .above{position:absolute; left:0; right:0;
            bottom: calc(100% - var(--keel) + var(--keel-gap));
            display:flex; flex-direction:column; align-items:flex-start}
.col .below{position:absolute; left:0; right:0;
            top: calc(var(--keel) + var(--keel-gap));
            display:flex; flex-direction:column; align-items:flex-start}

/* vertical rhythm — Figma page 06 at 1920: counter→title 20, title→tagline 41,
   tagline→desc 20. Browser default h2/p margins are reset so these are the
   only gaps. Scales down with the viewport, never above the Figma value. */
h2,p{margin:0}   /* element-level so .ti/.tg/.de margins below win */
/* spacing here, appearance in the TYPE block below — one rule each */
.pc{margin-bottom: clamp(10px, 1.85vh, 20px)}   /* eyebrow: no longer rendered (7 Oct), rules kept for the section index only */
.tg{margin-bottom: clamp(10px, 1.85vh, 20px)}
.tg:empty,.de:empty{display:none}

/* type scale: floor for legibility, Figma size as the ceiling */
.ti{font-size: clamp(32px, 4.1vw, 64px); line-height:1.0; letter-spacing:.03em;
     margin-bottom:0}   /* the title's bottom edge is the keel, not a margin */
.tg{font-size: clamp(19px, 1.7vw, 26px); line-height:1.42; letter-spacing:.04em}    /* +2 (Fatima/Naeem, 9 Oct): was 17–24 */
.de{font-size: clamp(17px, 1.3vw, 20px); line-height:1.5; letter-spacing:.06em}     /* +4: was 13–16 */
.pcn,.pcl{font-size: clamp(11px, .82vw, 14px)}

/* CTA row sits on the floor, in the same gutters as the copy */
#ctas{position:fixed; left:0; right:0; bottom:var(--floor); z-index:8;
      display:flex; gap:clamp(12px, 1.4vw, 24px); flex-wrap:wrap;
      padding-inline:var(--gutter); max-width:var(--shell); margin-inline:auto;
      transition:opacity .5s}
#ctas .btn{position:static}

/* ---- callout column: the stat panels ---- */
.callout{position:absolute; right:calc(var(--gutter) + clamp(0px,3.5vw,60px)); display:none;
         bottom: calc(100% - var(--keel) + clamp(40px, 7.3vh, 79px))}
.st-copy[data-callout] .callout{display:block}
.callout .panel{--v-drop:clamp(3px, .37vw, 7px);   /* same drop for value, unit and the 'to' pill */
  display:flex; align-items:center; justify-content:center;
  gap:clamp(6px, .8vw, 14px);
  padding:clamp(10px,1.6vh,22px) clamp(14px,1.8vw,30px);
  border-radius:clamp(16px,1.5vw,28px); border:1px solid rgba(255,255,255,.5);   /* Ramiro 2026-09-24: white at 50, was #919191 */
  background:rgba(217,217,217,.06);
  backdrop-filter:blur(28px) saturate(140%);
  -webkit-backdrop-filter:blur(28px) saturate(140%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.12)}
.callout .v{font-size:clamp(48px, 6.2vw, 120px); font-weight:200; line-height:1;
            color:#fff; font-variant-numeric:tabular-nums; white-space:nowrap;
            /* optical, not metric: the light numerals sit high in their box */
            transform:translateY(var(--v-drop))}
/* the separator gets its own air so the value and the unit sit apart, not against it */
.callout .sep{width:1px; align-self:stretch; background:rgba(255,255,255,.5); margin-inline:clamp(4px,.6vw,12px)}
.callout .mid{font-size:clamp(12px,1.1vw,18px); font-weight:400; color:#fff;
              padding:clamp(4px,.6vh,9px) clamp(8px,.8vw,14px);
              border:1px solid rgba(255,255,255,.5); border-radius:9px;
              background:rgba(217,217,217,.06);
              transform:translateY(var(--v-drop))}   /* rides with the values */
.callout .cap{position:static; display:block; text-align:center;
              margin-top:clamp(8px,1.4vh,18px); white-space:normal;
              font-size:clamp(12px,1.06vw,18px); color:#fff; opacity:.85}

/* CONTENT BREAK, WIDE. 05 is not a keel block — it is its own composition, so
   it gets composed as one: the copy and the table sit side by side and the pair
   is centred in the space between the top of the window and the CTA row. It was
   pinned to the top before, which looked right at 900px tall and left a third of
   the screen empty on a tall window. Nothing here is a fixed offset: the bottom
   padding is the CTA row plus its floor, so the block can never run into it. */
/* REVEAL (state 00, Ramiro 2026-09-28). One centred line under the silhouette:
   no keel, no counter, no callout. The plate is centred on the plane, so the
   line sits in the band below the headset — a share of the window on desktop,
   just under the art box on a phone (--art-bottom, written by fit()). */
.st-copy.rv{display:block}
.st-copy.rv .col{position:absolute; left:50%; top:76vh; bottom:auto; transform:translate(-50%,-50%);
                 width:min(92vw, calc(var(--cwn, 900) * 1px)); max-width:none;
                 display:flex; flex-direction:column; align-items:center; text-align:center}
.st-copy.rv .ti{font-size:clamp(24px, 2.6vw, 44px); line-height:1.15; letter-spacing:.05em; font-weight:300}
.st-copy.rv .ti .ln{padding-inline:.04em}   /* the mask clips a light italic's overhang otherwise */
.st-copy.rv .tg{margin-top:clamp(10px, 1.6vh, 18px); margin-bottom:0}
html.portrait .st-copy.rv .col{top:calc(var(--art-bottom, 70vh) + 7vh)}
html.portrait.land .st-copy.rv .col{top:calc(var(--art-bottom, 70vh) + 3vh)}

/* FADE ON (splash.js Boot): the stage is held dark until the reveal plate has
   decoded, then fades up. Video renders wait this out (tools/render.js). */
#stage{transition:opacity 1.4s cubic-bezier(.165,.84,.44,1)}
html.low #stage{transition:none}   /* LOW: no stage fade; the preloader card covers the load instead (2026-10-08) */
/* scroll lock while loading (set by the preloader, cleared after it lets go) */
html.loading, html.loading body{overflow:hidden !important; height:100% !important; touch-action:none; overscroll-behavior:none}
html.boot #stage{opacity:0}
@media (prefers-reduced-motion: reduce){ #stage{transition:none} }

.st-copy.cb{
  /* on the page grid: the stat takes columns 1-6, the copy starts on column 7 (Ramiro, 6 Oct) */
  display:grid; grid-template-columns:calc(6 * var(--col-w) + 5 * var(--col-gap)) minmax(0, 1fr); grid-template-rows:auto auto;
  align-items:center; align-content:center;
  column-gap:var(--col-gap); row-gap:clamp(28px, 7vh, 96px);
  /* top padding is deliberately heavier than the bottom (Ramiro 2026-09-24):
     centred between the window top and the CTA row read as high, so the
     block sits a step lower to feel centred to the eye */
  padding:clamp(90px, 14vh, 200px) var(--gutter)
          calc(var(--floor) + clamp(58px, 7.4vh, 85px) + clamp(28px, 5vh, 64px));
}
.st-copy.cb .stat{grid-column:1; grid-row:1}
.st-copy.cb .col{grid-column:2; grid-row:1; position:static; inset:auto; width:auto; max-width:none}   /* columns 7-12 */
.st-copy.cb .bigstat{margin-bottom:0}
/* the floor bar: fills left to right with the count (--cnt, 0..1, set by Counters) */
.st-copy.cb .bar{grid-column:1 / -1; grid-row:2; position:relative; height:clamp(6px, .8vw, 16px);
                 border-radius:999px; background:rgba(255,255,255,.07); overflow:visible}
.st-copy.cb .bar i{position:absolute; left:0; top:0; bottom:0; width:calc(var(--cnt, 0) * 100%);
                   border-radius:999px; background:linear-gradient(90deg, #0b3b2d, #00c977 55%, #00ff91);
                   box-shadow:0 0 18px rgba(0,255,145,.35), 0 0 48px rgba(0,255,145,.18)}

/* STACKED LAYOUT — below the lg edge (1024) there is not enough width for a
   copy column AND a callout column side by side, so the callout goes above the
   title stack instead. 1024 is the Tailwind lg edge and the width of an iPad Pro
   in portrait; the previous value here was 900, which matched no device.

   Its offset is NOT a guessed number. --above-max is measured by the Keel module
   (the tallest title stack on the page) and published as a custom property, so
   the callout clears the title by a real gap at every size. The old
   clamp(150px,22vh,240px) put it off the top of a phone screen. */
@media (max-width: 1023.98px){
  .callout{right:auto; left:var(--gutter);
           bottom: calc(100% - var(--keel) + var(--above-max, 120px) + clamp(14px, 2.2vh, 26px))}
  .col{width:calc(100vw - 2 * var(--gutter))}
  /* CONTENT BREAK, stacked. 05 does not hang off the keel — it is its own
     composition (big stat, title, body, comparison table). Side by side those
     are two columns; stacked they have to be two ROWS, or the table lands on
     top of the copy. Measured at 390: table 1-321, copy 30-300, straight
     through each other. Taking both out of absolute positioning and letting
     them flow is the fix, not another offset. */
  .st-copy.cb{display:flex; flex-direction:column; justify-content:center;
              gap:clamp(18px, 3vh, 36px);
              padding:clamp(56px,9vh,96px) var(--gutter) calc(var(--floor) + clamp(76px,11vh,120px));
              overflow-y:auto}
  .st-copy.cb .col{position:static; width:100%; max-width:none; inset:auto}
  .st-copy.cb .bar{width:100%; margin-top:clamp(8px,2vh,20px)}
  /* stacked stat (Ramiro, 6 Oct): everything left on the gutter like the body copy,
     the number much larger and growing left to right, "nits" and the arrows on a
     row beneath it */
  .st-copy.cb .stat{width:100%}
  .st-copy.cb .bigstat{flex-wrap:wrap; align-items:center; gap:clamp(6px,1.5vw,14px) clamp(10px,3vw,18px); margin-bottom:clamp(6px,1.5vh,16px)}
  .st-copy.cb .bigstat .n{flex:0 0 100%; min-width:0; text-align:left; font-size:clamp(96px, 30vw, 220px)}
  .st-copy.cb .bigstat .u{font-size:clamp(22px, 6.5vw, 40px); line-height:1}
  .st-copy.cb .bigstat .sig{flex-direction:row; gap:clamp(6px,1.6vw,10px); margin-left:0; transform:none; align-items:center}
}
/* Short windows: pull the floor in so the copy does not collide with the CTAs */
@media (max-height: 700px){
  :root{--floor: clamp(24px, 3.2vh, 34px)}
  .ti{font-size:clamp(28px, 3.4vw, 44px)}
}
/* PHONE, LANDSCAPE (a phone on its side: wide, under 500px tall). There is
   room for the title, one line of tagline and the CTAs — not for a body
   paragraph, a stat panel or a five-row table. Those go; nothing overlaps.
   The art keeps the desktop fit (a 16:9 plane in a 19:9 window is nearly
   full-bleed). Furniture off, same as portrait phones. */
@media (max-height: 500px) and (orientation: landscape){
  :root{--keel: 56vh; --keel-gap: 8px; --floor: 14px}
  #rail, #cue, #pager{display:none}
  #ctas{flex-wrap:nowrap; gap:10px}          /* one row: above 767px wide the desktop wrap rule was stacking them, 85px tall */
  #ctas .btn{flex:0 1 auto; min-width:0}
  .hist{display:none}                         /* beat 22's timeline: no height for it here */
  #ctas .btn{height:40px; border-radius:20px}      /* #ctas: the base .btn{height:85px} is declared later in the file and was winning */
  #ctas .btn.p{min-width:0; padding:0 16px; font-size:14px} #ctas .btn.s{min-width:0; padding:0 14px; font-size:14px}
  .ti{font-size:clamp(24px, 5.5vh, 34px)}
  .tg{font-size:clamp(13px, 3.6vh, 16px); margin-bottom:0}
  .de{display:none}
  .st-copy[data-callout] .callout{display:none}   /* the stat panels: not enough height to stack them */
  .st-copy.cb{padding-top:clamp(24px, 8vh, 40px)}
  .st-copy.cb .de{display:none}
}


.bigstat{display:flex; align-items:baseline; gap:clamp(8px,1.2vw,22px);
         margin-bottom:clamp(14px,2.6vh,38px)}
.bigstat .n{font-size:clamp(72px,11vw,200px); font-weight:200; line-height:.92; color:#c9c9c9;
            font-variant-numeric:tabular-nums;
            /* right-justified in a four-digit box, so the number grows right to left and
               "nits" and the arrows never move while it counts (Ramiro, 6 Oct) */
            display:inline-block; min-width:4ch; text-align:right}
.bigstat .u{font-size:clamp(22px,2.8vw,48px); font-weight:300; color:rgba(255,255,255,.5)}   /* white 50% (Ramiro, 6 Oct) */
.bigstat .sig{--tri-h:clamp(9px,1.2vw,18px); --tri-w:clamp(5px,.68vw,10px);   /* Ramiro 2026-09-24: smaller, more air */
              display:flex; flex-direction:column-reverse; gap:clamp(16px,2.8vh,36px);   /* 28px at a 1000px-tall window; triangles are 18px tall at 2000 wide */
              margin-left:clamp(6px,1vw,18px);
              /* BASELINE FIX. The row is align-items:baseline, and a flex column
                 with no text in it hands the browser its FIRST item's bottom edge
                 as a baseline — which here is the top triangle, so the stack hung
                 below the numeral. Shift it up by its own height less one triangle
                 and the BOTTOM of the stack sits on the baseline, level with the
                 word "nits". Done as a transform so the row's height is still set
                 by the numeral and not by the arrows. Both triangle dimensions are
                 custom properties because the shift has to track the same clamp. */
              transform:translateY(calc(-100% + var(--tri-h)))}
.bigstat .sig i{width:0;height:0;border-left:var(--tri-w) solid transparent;
                border-right:var(--tri-w) solid transparent;
                border-bottom:var(--tri-h) solid #00ff91;opacity:.15}
/* rising signal: the three arrows light in sequence, then rest */
@keyframes sig{0%,62%,100%{opacity:.15} 22%{opacity:1}}
.cb.on .bigstat .sig i{animation:sig 1.8s ease-in-out infinite}
.cb.on .bigstat .sig i:nth-child(2){animation-delay:.22s}
.cb.on .bigstat .sig i:nth-child(3){animation-delay:.44s}
@media (prefers-reduced-motion: reduce){
  .cb.on .bigstat .sig i{animation:none;opacity:.5}
}

.st-copy.cb .ti .b{color:#00ff91}
.st-copy.cb .ti{font-size:clamp(26px,3.1vw,48px); line-height:1.2;
                margin-bottom:clamp(14px,2.4vh,34px)}

/* ---- copy layer: reveal mechanics ---- */
/* A word is measured as one unit while the lines are split, and a hyphen is
   not a place to break: "test-retest" used to come out as "test-" on one line
   and "retest" alone on the next. */
.st-copy w{white-space:nowrap}
.ln{display:block;overflow:hidden;padding-bottom:.08em;margin-bottom:-.08em;white-space:nowrap}
/* DIRECTION IS A VARIABLE, NOT A SECOND SET OF RULES.
   Scrolling forward, a line rises in from below and leaves upward. Scrolling
   back, the whole move mirrors: in from above, out downward — so a reverse
   reads as a reverse, whether it came from the wheel or the pager arrows.
   splash.js writes --enter / --exit on <html> from the sign of the playhead. */
:root{ --enter: 110%; --exit: -110%; }
html.back{ --enter: -110%; --exit: 110%; }
.ln>.li{display:block;transform:translateY(var(--enter));opacity:0;transition:transform var(--reveal,.6s) cubic-bezier(.165,.84,.44,1),opacity calc(var(--reveal,.6s) * .75) ease-out}
.st-copy.in .ln>.li{transform:translateY(0);opacity:1}
.st-copy:not(.in) .ln>.li{transform:translateY(var(--exit));opacity:0;transition-duration:var(--reveal-out,.34s),calc(var(--reveal-out,.34s) * .7)}
/* same title as the state before: title stays put, only sub-copy refreshes */
.st-copy.same-ti .ti .ln>.li,.st-copy.same-ti .pc .ln>.li{transform:translateY(0)!important;opacity:1!important;transition:none!important}
.st-copy.same-ti.in{transition:none}
/* CROSS-FADE IS OPT-IN.
   This used to read "fade every child except <list>", so any new wrapper added
   to a copy block silently joined the fade — which is how a persistent title
   ended up fading out and back in. Now nothing fades unless it is marked
   .fades. Text reveals itself through the .ln masks; only whole extras (the
   callout panel) cross-fade as a unit. tools/test.js fails the build if a
   shared title ever dips below full opacity across a state change. */
.st-copy .fades{opacity:0;transition:opacity .6s cubic-bezier(.165,.84,.44,1)}
.st-copy.in .fades{opacity:1}
/* The frosted panel is NOT a .fades: opacity on it (or on anything above it)
   turns it into its own backdrop root and the blur behind it vanishes until
   the fade ends. It snaps on with the blur in place; its contents fade. */
.st-copy .callout .panel{visibility:hidden}
.st-copy.in .callout .panel{visibility:visible}
.callout .v.dim.fades{opacity:0}
.st-copy.in .callout .v.dim.fades{opacity:.25}

.pc{display:flex;align-items:center;gap:13px;height:14px;white-space:nowrap}
/* size: COPY LAYOUT block */
.pcn{font-weight:500;letter-spacing:5px;color:#e0e8f0;opacity:.7}
/* size: COPY LAYOUT block */
.pcl{font-weight:500;letter-spacing:1px;color:#8c99ad;opacity:.3}

.ti{font-weight:300;color:#fff;text-wrap:balance}    /* size: COPY LAYOUT block */
.ti .b{color:var(--blue)}
.tg{font-weight:300;color:#fff}                      /* size: COPY LAYOUT block */
.de{font-weight:400;color:var(--mute)}                /* size: COPY LAYOUT block */

.btn{height:56px;border-radius:28px;display:inline-flex;align-items:center;gap:14px;
     white-space:nowrap;text-decoration:none;color:#fff;font-weight:400;
     transition:background .25s,border-color .25s}   /* 0.20.81: 85 -> 56 tall, Fatima 2026-10-06 (CTAs too big) */
.btn.p{width:auto;min-width:200px;padding:0 26px 0 28px;font-size:17px;letter-spacing:-.1px;
       background:rgba(0,80,231,.4);border:2px solid #004ee2}
.btn.p:hover{background:rgba(211,211,211,.30);border-color:#fff}
.btn.p:hover svg{transform:translateX(6px)}
.btn svg{transition:transform .26s cubic-bezier(.65,0,.35,1)}
.btn:active{transform:scale(.985)}
.btn.p svg{width:20px;height:17px;flex:none;margin-left:auto}
.btn.s{width:auto;min-width:160px;padding:0 30px;font-size:16px;letter-spacing:-.1px;justify-content:center;border:2px solid rgba(217,217,217,.3)}   /* 2px to match the primary (Ramiro 2026-10-07) */
.btn.s:hover{border-color:rgba(217,217,217,.6)}




/* =============================================================================
   SAFE ZONE GUIDES  —  dev overlay, press S
   Draws where content is actually allowed to sit at the current window size,
   and reports the window and the breakpoint it resolves to. Reads the live
   computed layout rather than repeating numbers, so it can never disagree
   with the CSS.
   ========================================================================== */
#safe{position:fixed;inset:0;z-index:99998;pointer-events:none;display:none;
      font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9.5px;
      letter-spacing:.1em;text-transform:uppercase;color:#00aeef}
#safe.on{display:block}
#safe .ln{position:absolute;background:rgba(0,174,239,.55)}
#safe .ln.h{left:0;right:0;height:1px}
#safe .band{position:absolute;left:0;right:0;background:rgba(0,174,239,.055);
            border-block:1px dashed rgba(0,174,239,.4)}
#safe .side{position:absolute;top:0;bottom:0;background:rgba(255,95,109,.05);
            border-inline:1px dashed rgba(255,95,109,.35)}
#safe var{position:absolute;font-style:normal;background:rgba(6,8,10,.9);
          padding:3px 7px;border-radius:4px;white-space:nowrap}
#safe .meta{left:50%;top:10px;transform:translateX(-50%);color:#d8e1ea;
            border:1px solid rgba(0,174,239,.35)}

/* ---- persistent chrome ---- */
/* right-hand rail: pinned to the viewport edge, vertically centred */
/* height is set by splash.js from the dot count x RAIL_PITCH */
#rail{position:fixed;right:clamp(16px,3.5vw,87px);top:50%;transform:translateY(-50%);
      width:10px;z-index:7}
#rail b{position:absolute;left:0;width:10px;height:10px;border-radius:50%;background:#575757;display:block}
#rail #dot{position:absolute;left:-3.1px;top:-3.1px;width:16.2px;height:16.2px;border-radius:50%;background:var(--blue);transition:transform .42s cubic-bezier(.65,0,.35,1)}
#rail .pulse{position:absolute;left:5px;top:5px;width:0;height:0;pointer-events:none;transition:transform .42s cubic-bezier(.65,0,.35,1)}
#rail .pulse span{position:absolute;left:0;top:0;border-radius:50%;transform:translate(-50%,-50%);border:1px solid var(--blue);display:block}
#rail .ring1{width:55.4px;height:55.4px;opacity:.3;animation:ring 2.6s ease-out infinite}
#rail .ring2{width:97.3px;height:97.3px;opacity:.1;animation:ring 2.6s ease-out infinite .55s}
@keyframes ring{0%{transform:translate(-50%,-50%) scale(.28);opacity:.45}70%{opacity:.06}100%{transform:translate(-50%,-50%) scale(1);opacity:0}}

#cue{position:fixed;right:clamp(12px,2.4vw,46px);bottom:clamp(14px,3vh,34px);
     width:44px;height:46px;z-index:7;text-align:center;transition:opacity .4s}   /* 2026-10-07: same 44px column as the pager so the two centre on each other; the SCROLL word is gone */
#cue .m{width:31.5px;height:45.2px;border:2px solid #fff;border-radius:15.76px;margin:0 auto;
        position:relative}
#cue .m::after{content:"";position:absolute;left:50%;top:8px;width:2px;height:8.1px;
        transform:translateX(-50%);background:#fff;border-radius:1px;animation:wheel 1.9s cubic-bezier(.65,0,.35,1) infinite}
@keyframes wheel{0%{transform:translate(-50%,0);opacity:0}18%{opacity:1}68%{transform:translate(-50%,16px);opacity:0}100%{transform:translate(-50%,16px);opacity:0}}
#cue span{display:none}   /* "SCROLL" removed (Ramiro 2026-10-07) */

/* ---- pager: up / down arrows, right edge, vertically centred (Ramiro 2026-10-07).
   One press plays the next beat through and stops on it; the wheel still
   scrolls freely. Keyboard arrows do the same. Styled like the scroll cue. */
#pager{position:fixed; right:clamp(12px,2.4vw,46px); top:0; bottom:0; margin:auto 0; height:98px;   /* centred without transform: the WP isolation rule below resets transforms */
       z-index:7; display:flex; flex-direction:column; gap:10px; transition:opacity .4s}
#pager .pg{width:44px; height:44px; display:flex; align-items:center; justify-content:center;
           border:2px solid rgba(255,255,255,.5); border-radius:50%; padding:0; cursor:pointer;
           color:rgba(255,255,255,.5); background:transparent;
           transition:border-color .16s, color .16s, opacity .16s}   /* 2px at 50%, 100% on the one in focus (Ramiro 2026-10-07) */
#pager .pg svg{width:16px; height:10px; display:block}
#pager .pg:hover, #pager .pg:focus-visible{border-color:#fff; color:#fff; outline:none}
#pager .pg:disabled{opacity:.25; cursor:default}
html.boot #pager{opacity:0}
html.video #pager{visibility:hidden !important}

/* ---- scroll driver ---- */
#track{position:relative;z-index:0}
#track div{height:100vh}

/* ---- grid density control ---- */
#ctl{position:fixed;left:16px;bottom:16px;z-index:40;display:flex;align-items:center;gap:12px;
     padding:10px 14px;border-radius:999px;background:rgba(18,18,18,.82);
     border:1px solid rgba(255,255,255,.12);backdrop-filter:blur(14px);
     font-size:11px;letter-spacing:1.4px;text-transform:uppercase;color:#8c99ad;
     transition:opacity .3s,transform .3s}
#ctl[hidden]{display:none!important}
#ctl input{width:150px;accent-color:#00aeef}
#ctl output{color:#e0e8f0;font-variant-numeric:tabular-nums;min-width:34px;text-align:right}
#ctl button{background:none;border:0;color:#8c99ad;cursor:pointer;font:inherit;padding:0 2px}
#ctl button:hover{color:#fff}
#ctlOpen{position:fixed;left:16px;bottom:16px;z-index:39;width:34px;height:34px;border-radius:50%;
     background:rgba(18,18,18,.7);border:1px solid rgba(255,255,255,.12);color:#8c99ad;
     cursor:pointer;font-size:13px;line-height:1}
#ctlOpen:hover{color:#fff}
/* ---- backlight tuner (dev, B) ---- */
#bl,#vg{position:fixed;right:16px;bottom:16px;z-index:40;width:360px;display:flex;flex-direction:column;gap:8px;
    padding:14px 16px;border-radius:14px;background:rgba(18,18,18,.86);
    border:1px solid rgba(255,255,255,.12);backdrop-filter:blur(14px);
    font-size:11px;letter-spacing:1.2px;text-transform:uppercase;color:#8c99ad}
#bl[hidden],#vg[hidden]{display:none!important}
#bl .bl-head,#vg .bl-head{display:flex;flex-direction:column;gap:2px;margin-bottom:4px}
#bl .bl-head b,#vg .bl-head b{color:#fff;font-weight:500;font-size:12px;letter-spacing:.6px;text-transform:none}
#bl label,#vg label{display:grid;grid-template-columns:64px 1fr 48px;align-items:center;gap:10px}
#bl input[type=range],#vg input[type=range]{width:100%;accent-color:#00aeef}
#bl output,#vg output{color:#e0e8f0;font-variant-numeric:tabular-nums;text-align:right}
#bl textarea,#vg textarea{width:100%;resize:vertical;margin-top:4px;padding:8px 10px;border-radius:8px;
    background:#0a0a0a;border:1px solid rgba(255,255,255,.1);color:#e0e8f0;
    font:11px/1.5 ui-monospace,Menlo,monospace;text-transform:none;letter-spacing:0}
#bl .bl-foot{display:flex;justify-content:space-between;align-items:center}
#bl button{background:none;border:0;color:#8c99ad;cursor:pointer;font:inherit;padding:0 2px}
#bl button:hover{color:#fff}
#bl.dragging{opacity:.35}

@media (prefers-reduced-motion:reduce){#cue .m::after{animation:none}}

/* ---- sequence slots ---- */
.seq{position:absolute;inset:0;z-index:5;opacity:0;pointer-events:none}
.seq iframe.emb{position:absolute;left:0;top:0;width:1920px;height:1080px;border:0;background:#000;pointer-events:none}
.seq img.emb{position:absolute;left:0;top:0;width:1920px;height:1080px;object-fit:cover;object-position:center;background:#000;pointer-events:none}   /* LOW: the phone's still in place of the module */
html.low #glow, html.low #glow2, html.low #grid{display:none}   /* LOW: no backlight, no lattice */
html.low .plate, html.low .px i{will-change:auto}
/* LOW: the finger never scrolls the document (a swipe is a press, splash.js Pager); no rubber-band either */
html.low, html.low body{overscroll-behavior:none; touch-action:none}
/* LOW timings (Ramiro, 8 Oct): step 250ms (pager.lowMs), settle 100ms, copy in 200ms,
   copy out 200ms, vignette 200ms, callout 200ms, CTAs 150ms */
/* PHONES: NO ANIMATION (Ramiro, 8 Oct). Every transition and keyframe off; the
   only motion is the stage fade the pager drives inline (splash.js fadeStep). */
html.low #stage *, html.low .st-copy, html.low .st-copy *, html.low #ctas, html.low #ctas *, html.low #logo{transition:none !important; animation:none !important}
html.low .ln>.li, html.low .st-copy:not(.in) .ln>.li{transform:none !important}
html.low .st-copy.in .ln>.li{opacity:1 !important}
html.low #ctas, html.low #ctas *, html.low #logo, html.low #pager button{touch-action:manipulation}   /* LOW: no pre-promoted layers; a plate is a layer only while it animates */
.seq canvas.fr{position:absolute;left:0;top:0;width:1920px;height:1080px;display:none;z-index:2}
.seq[data-frames] canvas.fr{display:block}
.seq[data-frames] video:not(.ov){display:none}
.seq video.ov{mix-blend-mode:screen;z-index:1}
.seq video{position:absolute;left:0;top:0;width:1920px;height:1080px;object-fit:contain;object-position:center}
.seq .ph{position:absolute;left:960px;top:400px;transform:translate(-50%,-50%);width:520px;height:520px}
.seq .ph svg{position:absolute;inset:0;width:100%;height:100%;transform:rotate(-90deg)}
.seq .ph circle{fill:none;stroke-width:2}
.seq .ph .tr{stroke:rgba(255,255,255,.08)}
.seq .ph .pr{stroke-dasharray:1571;stroke-dashoffset:1571;filter:drop-shadow(0 0 12px currentColor)}
.seq .ph .lb{position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);text-align:center}
.seq .ph .lb b{display:block;font-size:14px;font-weight:500;letter-spacing:5px;text-transform:uppercase}
.seq .ph .lb i{display:block;font-style:normal;font-size:13px;letter-spacing:1px;color:#8c99ad;margin-top:8px}
.seq .ph .lb em{display:block;font-style:normal;font-size:72px;font-weight:200;margin-top:18px;font-variant-numeric:tabular-nums}
.seq .ph .lb small{display:block;font-size:11px;letter-spacing:3px;text-transform:uppercase;color:#575757;margin-top:14px}

/* ---- preloader ---- */
#preload{position:fixed;inset:0;z-index:100000;background:var(--ink);display:flex;align-items:center;justify-content:center;transition:opacity .6s ease;pointer-events:none}
#preload.out{opacity:0}
#preload .pl-in{text-align:center;color:#8c99ad;font-family:var(--face,'IBM Plex Sans',system-ui,sans-serif);font-weight:300;font-size:14px;letter-spacing:.18em;text-transform:uppercase}
#preload .pl-bar{display:block;width:180px;height:1px;background:#1d232b;margin:18px auto 0;overflow:hidden}
#preload .pl-bar b{display:block;height:100%;width:0;background:#00aeef;transition:width .25s ease}

/* ---- section index -------------------------------------------------------
   ALWAYS ON SCREEN. It lives as a 52px numbered rail inside the page gutter,
   so it never covers the copy column, and widens to show the beat names on
   hover (or pinned with N). A drawer you have to discover is not navigation. */
:root{ --sindex-rail: 52px; --sindex-w: 252px }
#sindex{position:fixed; left:0; top:0; bottom:0; width:var(--sindex-rail); z-index:30;
        background:linear-gradient(90deg,rgba(10,11,13,.78),rgba(10,11,13,.5));
        border-right:1px solid rgba(255,255,255,.07);
        backdrop-filter:blur(14px) saturate(130%); -webkit-backdrop-filter:blur(14px) saturate(130%);
        display:flex; flex-direction:column; overflow:hidden;
        font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
        transition:width .22s cubic-bezier(.4,0,.2,1), background .22s}
#sindex:hover, #sindex.open{width:var(--sindex-w); background:rgba(10,11,13,.93);
        border-right-color:rgba(255,255,255,.12)}

#sindex header{display:flex; align-items:center; justify-content:space-between; gap:6px;
        height:40px; padding:0 10px; flex:none;
        font-size:9px; letter-spacing:.16em; text-transform:uppercase; color:#6f7b8b;
        border-bottom:1px solid rgba(255,255,255,.07); overflow:hidden; white-space:nowrap}
#sindex:hover header span, #sindex.open header span{opacity:1}
#sindex .x{background:none; border:0; color:#6f7b8b; font-size:15px; line-height:1;
        cursor:pointer; padding:2px 5px; border-radius:5px; opacity:0; transition:opacity .18s}
#sindex:hover .x, #sindex.open .x{opacity:1}
#sindex .x:hover{color:#fff; background:rgba(255,255,255,.08)}

#sindex ol{list-style:none; margin:0; padding:4px 0 18px; overflow-y:auto; overflow-x:hidden;
        flex:1; scrollbar-width:none}
#sindex ol::-webkit-scrollbar{display:none}

/* section header: a coloured tick in rail mode, a full label when open */
#sindex .sh{display:flex; align-items:center; gap:7px; height:22px; padding:0 10px;
        margin-top:9px; font-size:8.5px; letter-spacing:.14em; text-transform:uppercase;
        color:var(--c); white-space:nowrap; overflow:hidden; position:relative}
#sindex .sh::before{content:""; width:14px; height:2px; background:var(--c); border-radius:2px; flex:none}
#sindex .sh b{font-weight:700; opacity:0; transition:opacity .18s}
#sindex .sh em{font-style:normal; opacity:0; transition:opacity .18s}
#sindex:hover .sh b, #sindex.open .sh b,
#sindex:hover .sh em, #sindex.open .sh em{opacity:1}

#sindex .bt{display:flex; align-items:center; gap:9px; height:23px; padding:0 10px;
        font-size:11px; color:#78838f; cursor:pointer;
        border-left:2px solid transparent; white-space:nowrap; overflow:hidden;
        transition:background .14s, color .14s, border-color .14s}
#sindex .bt i{width:4px; height:4px; border-radius:50%; background:var(--c); opacity:.4; flex:none}
#sindex .bt b{font-weight:600; font-variant-numeric:tabular-nums; color:#aab4c0; flex:none;
        min-width:17px}
#sindex .bt span{font-size:10.5px; opacity:0; overflow:hidden; text-overflow:ellipsis;
        transition:opacity .18s}
#sindex:hover .bt span, #sindex.open .bt span{opacity:1}
#sindex .bt:hover{background:rgba(255,255,255,.07); color:#e6edf5}
#sindex .bt.on{background:rgba(255,255,255,.10); color:#fff; border-left-color:var(--c)}
#sindex .bt.on i{opacity:1}
#sindex .bt.on b{color:#fff}

/* the pager clears the rail; the rail overlays on hover rather than pushing */
@media (max-width:900px){ :root{--sindex-rail:40px; --sindex-w:210px} }

/* ---- open questions ------------------------------------------------------
   A beat whose art is not decided says so, in red, on the beat itself. It is
   deliberately loud and deliberately outside the keel stack: it is a note to
   us, not part of the composition, and it disappears the moment the `todo` is
   removed from splash.copy.js. */
.st-copy .todo{position:absolute; left:var(--gutter); right:var(--gutter);
  top:clamp(56px,7vh,84px); z-index:6; margin:0; max-width:760px;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:11px; line-height:1.55; letter-spacing:.02em; color:#ff6b72;
  border-left:2px solid #ff3b46; padding:9px 12px; border-radius:0 6px 6px 0;
  background:linear-gradient(90deg,rgba(255,59,70,.14),rgba(255,59,70,.03));
  text-transform:none}
.st-copy .todo b{display:block; font-size:9px; letter-spacing:.2em;
  text-transform:uppercase; color:#ff3b46; margin-bottom:4px}
/* markers: a beat with an open question is flagged wherever beats are listed */
#sindex .bt.q b::after{content:"•"; color:#ff3b46; margin-left:5px; font-size:13px; line-height:0}
#kf tr.q td:first-child::after{content:" •"; color:#ff3b46}

/* ---- missing-clip banner -------------------------------------------------
   Same red language as an open question, but for a transition rather than a
   beat. It names the two states in our numbering and prints the exact folder
   to export into, so there is no guessing where art goes. */
#gap{position:fixed; left:50%; top:clamp(48px,7vh,90px); transform:translate(-50%,-8px);
  z-index:28; opacity:0; pointer-events:none; transition:opacity .18s, transform .18s;
  display:flex; flex-direction:column; gap:3px; align-items:flex-start;
  padding:11px 16px; border-radius:8px; border:1px solid rgba(255,59,70,.5);
  background:rgba(40,8,11,.86); backdrop-filter:blur(14px);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
#gap.on{opacity:1; transform:translate(-50%,0)}
#gap b{font-size:9px; letter-spacing:.2em; text-transform:uppercase; color:#ff3b46}
#gap .w{font-size:15px; color:#fff; letter-spacing:.04em}
#gap .d{font-size:11px; color:#ff9ba0}
#gap .l{font-size:10.5px; color:#c98f93}
#gap code{margin-top:4px; font-size:10px; color:#8d6f72; letter-spacing:.01em}

/* ---- 23 · longitudinal history ----------------------------------------------
   Figma "23 · Continuity" (1:747). One blue baseline across the full width,
   a faint blue wash falling off beneath it, and exam markers standing above
   it on 100px stems. Measured at 1920x1080 the baseline sits 241px above the
   keel; that offset scales with height so it keeps the same relationship to
   the copy at every window shape. Everything is full-bleed, so it is fixed to
   the viewport rather than the copy shell. */
.hist{position:fixed; left:0; right:0; top:0; height:0; z-index:5; pointer-events:none;
  /* Ramiro 2026-09-25: whole thing ~20% stronger — baseline 20% lower, stems 20% taller,
     lines 1.25px, dots/rings 1.2x, text one step brighter */
  --base: calc(var(--keel) - clamp(120px, 17.9vh, 208px));
  --stem: clamp(96px, 12.85vh, 138.6px);        /* Figma node 21:550 x1.2: dot -> baseline */
  --gap:  clamp(200px, 25vw, 480px)}             /* spacing between visits; 200 floor = two visits on a 390 phone */
@media (max-width: 767.98px){ .hist{--gap: clamp(260px, 72vw, 480px)} }   /* 6 Oct: 200 was too tight on a 375 phone, visits ran into each other */
.hist-line{position:absolute; left:0; top:var(--base); width:100vw; height:1.25px; display:block}
.hist-glow{position:absolute; left:0; top:var(--base); width:100vw; height:clamp(320px, 57vh, 617px); display:block;
  -webkit-mask-image:linear-gradient(90deg, transparent 5.5%, #000 31%, rgba(0,0,0,.91) 64%, transparent 91.6%);
          mask-image:linear-gradient(90deg, transparent 5.5%, #000 31%, rgba(0,0,0,.91) 64%, transparent 91.6%)}
/* header — Figma 21:565: 40px Ultra Light, #666, sits ~95px above the node row */
.hist-head{position:absolute; left:calc(var(--gutter) - 11px); top:calc(var(--base) - var(--stem) - 13.5px - clamp(64px, 8.8vh, 95px));
  font-family:var(--face); font-weight:200; font-size:clamp(28px, 2.08vw, 40px); letter-spacing:2px; color:#7d7d7d; white-space:nowrap}
/* markers pass out of view on the left and arrive from the right */
.hist-win{position:absolute; left:0; width:100vw; top:calc(var(--base) - var(--stem) - 13.5px); height:calc(var(--stem) + 20px);
  -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 var(--gutter), #000 80%, transparent 96%);
          mask-image:linear-gradient(90deg, transparent 0, #000 var(--gutter), #000 80%, transparent 96%)}
.hist-track{position:absolute; left:calc(var(--gutter) - 11px); top:0; height:100%; will-change:transform}
/* one visit — Figma group 21:567 */
.hist-ev{position:absolute; top:0; left:calc(var(--i) * var(--gap)); width:var(--gap);
  font-family:var(--face); font-size:14px; line-height:16px; transition:opacity .25s}
.hist-ring{position:absolute; left:0; top:0; width:25px; height:25px; display:block; transform:scale(1.2)}
.hist-dot{position:absolute; left:7.5px; top:7.5px; width:10px; height:10px; display:block; transform:scale(1.2);
  transition:transform .3s cubic-bezier(.165,.84,.44,1)}
.hist-stem{position:absolute; left:12.5px; top:13.5px; width:var(--stem); height:1.25px; display:block; filter:brightness(1.35);
  transform-origin:0 0; transform:rotate(90deg)}
.hist-d {position:absolute; left:39.24px; top:5.5px;  color:#c6c6c6; white-space:nowrap; font-variant-numeric:tabular-nums}
.hist-mv{position:absolute; left:39.24px; top:29.5px; color:#e2e9f1; white-space:nowrap; font-variant-numeric:tabular-nums}
.hist-bar{position:absolute; left:39px; top:50px; width:113px; height:2px; border-radius:1px; overflow:hidden;
  background:rgba(255,255,255,.1)}
.hist-bar b{display:block; height:100%; background:#00aeef}
.hist-t {position:absolute; left:39.24px; top:68px; color:#939393; white-space:nowrap}
.hist-ev.on .hist-dot{transform:scale(1.5)}
.hist-ev.now .hist-d{color:#00aeef}

/* ---- layout overlay (press L) --------------------------------------------
   Draws the real grid: the same tokens the layout is built from, so if a block
   does not sit on a column you can see it rather than argue about it. */
#lay{position:fixed;inset:0;z-index:9998;pointer-events:none;display:none}
html.lay #lay{display:block}
#lay .cols{position:absolute;inset:0;
  padding-inline:var(--gutter); max-width:var(--shell); margin-inline:auto;
  display:grid; grid-template-columns:repeat(var(--cols),1fr); gap:var(--col-gap)}
#lay .cols i{display:block;background:rgba(255,0,90,.085);border-left:1px solid rgba(255,0,90,.22);
  border-right:1px solid rgba(255,0,90,.22)}
#lay .marg{position:absolute;top:0;bottom:0;width:var(--gutter);background:rgba(0,174,239,.07)}
#lay .marg.l{left:max(0px,calc((100vw - min(100vw,var(--shell))) / 2))}
#lay .marg.r{right:max(0px,calc((100vw - min(100vw,var(--shell))) / 2))}
#lay .h{position:absolute;left:0;right:0;height:1px}
#lay .h.keel{top:var(--keel);background:#3ddc97}
#lay .h.floor{bottom:var(--floor);background:rgba(255,184,77,.6)}
#lay .h span{position:absolute;right:8px;top:-14px;font:9px/1 ui-monospace,Menlo,monospace;
  letter-spacing:.14em;text-transform:uppercase;color:inherit}
#lay .h.keel span{color:#3ddc97}
#lay .h.floor span{color:#ffb84d;top:4px}
#lay .read{position:absolute;left:50%;top:14px;transform:translateX(-50%);
  padding:7px 12px;border-radius:7px;background:rgba(6,8,10,.9);border:1px solid #1d232b;
  font:10px/1.6 ui-monospace,Menlo,monospace;letter-spacing:.08em;color:#8c99ad;white-space:nowrap}
#lay .read b{color:#fff;font-weight:600}
#lay .read em{font-style:normal;color:#00aeef}

/* ---- chrome gate (press H, or open with ?chrome=0) -----------------------
   Hides every development instrument at once. All of them are position:fixed
   so they never reflowed the layout, but they do sit over it, and you cannot
   judge spacing through a panel. */
html.video #ctas, html.video #cue{visibility:hidden !important}   /* the video render (tools/render.js): hidden, not removed — the copy keel measures the CTA row */
html.nochrome #sindex,
html.nochrome #kf,
html.nochrome #lay,
html.nochrome #gap,
html.nochrome #safe,
html.nochrome .st-copy .todo{display:none !important}

/* ---- rail: one widget --------------------------------------------------
   Scroll position at the top, beats in the middle, controls at the bottom.
   The pager's buttons moved in here and its vertical text label is gone — the
   list already names every beat, so the label was saying it twice. */
#sindex header .pct{font-size:12px; letter-spacing:0; color:#00aeef; font-weight:600;
  font-variant-numeric:tabular-nums; flex:none}
#sindex header span{flex:1; overflow:hidden; text-overflow:ellipsis;
  opacity:0; transition:opacity .18s}

/* Collapsed the rail is 52px — three buttons in a row do not fit, they clip at
   the edge. Stack them while narrow, lay them out in a row once it widens. */
#sindex .rail-foot{display:flex; flex-direction:column; align-items:center;
  gap:6px; padding:9px 6px; flex:none; border-top:1px solid rgba(255,255,255,.08);
  background:rgba(255,255,255,.02)}
#sindex:hover .rail-foot, #sindex.open .rail-foot{flex-direction:row;
  justify-content:space-between; padding:9px 10px}
#sindex .arrows{display:flex; flex-direction:column; gap:5px}
#sindex:hover .arrows, #sindex.open .arrows{flex-direction:row}
#sindex .rail-foot button{width:29px; height:26px; display:flex; align-items:center;
  justify-content:center; border:1px solid rgba(255,255,255,.18); border-radius:7px;
  background:rgba(217,217,217,.05); color:#9aa6b6; cursor:pointer; padding:0;
  transition:background .16s, border-color .16s, color .16s, opacity .16s}
#sindex .rail-foot button:hover{background:rgba(255,255,255,.12); border-color:#fff; color:#fff}
#sindex .rail-foot button:disabled{opacity:.22; cursor:default}
#sindex .rail-foot button svg{width:15px; height:10px}
#sindex .rail-foot .tl svg{width:14px; height:11px}
#sindex .rail-foot .tl.on{background:#00aeef; border-color:#00aeef; color:#04131a}


/* =============================================================================
   PHONE  (< 768)  — SIMPLIFY, don't shrink
   -----------------------------------------------------------------------------
   The desktop composition has three pieces of furniture that only make sense
   with a pointer and a wide frame: the section rail on the right, the scroll
   cue in the corner, and a CTA pair sized to sit in a 1920 gutter. On a phone
   the rail has nothing to point at, the cue explains a gesture nobody needs
   explained, and the buttons were eating a fifth of the screen.

   So the phone does not get a scaled-down desktop. It gets the same art, the
   same copy, and none of the furniture.
   ========================================================================== */
@media (max-width: 767.98px){

  /* 1. Furniture off. */
  #rail{display:none}
  #cue{display:none}

  /* 2. CTAs: one row, shared evenly, thumb-sized and no larger.
        The desktop min-widths (210 + 168 + gap) are wider than a 390 phone, so
        they were wrapping to two stacked 58px bars. Dropping the minimum and
        letting them share the row is what makes them behave. 46px keeps them
        above the 44px touch-target floor. */
  #ctas{gap:10px; flex-wrap:nowrap}
  #ctas .btn{flex:1 1 0; min-width:0}
  .btn{height:46px; border-radius:23px; gap:8px}
  .btn.p{min-width:0; width:auto; padding:0 16px; font-size:14px; justify-content:center}
  .btn.p svg{width:17px; height:14px; margin-left:6px}
  .btn.s{min-width:0; width:auto; padding:0 14px; font-size:14px}

  /* 3. The CTA row got shorter, so the copy above it gets that height back. */
  :root{--floor: 20px}

  /* 3b. PORTRAIT PHONE: the art owns the top half, so there is no room for a
        body paragraph under title + tagline before the CTAs — it was showing as
        two clipped lines. Title and tagline carry the beat; the body goes.
        The stat panel moves from above the title (where it sat on the art) to
        the strip between the tagline and the CTAs. */
  .st-copy .de{display:none}
  /* 6 Oct (Ramiro): on phones the stat panel is a SMALL tag, top right, under the
     logo line, clear of the art and the copy. It no longer sits in the copy strip. */
  .st-copy[data-callout] .callout{top:clamp(84px, 12vh, 120px); bottom:auto; right:var(--gutter); left:auto;
                                  max-width:calc(100vw - 2 * var(--gutter) - 120px)}
  .callout .v{font-size:clamp(26px, 7.5vw, 36px)}
  .callout .sep{margin-inline:4px}
  .callout .mid{font-size:11px; padding:3px 7px}
  .callout .cap{margin-top:5px; font-size:11px; line-height:1.3; text-align:right; opacity:.75}
  .callout .panel{padding:6px 12px; border-radius:12px; gap:6px; margin-left:auto; width:max-content}

  /* 4. Art top, copy bottom (splash.js fit(), tuning.fit.phone). The plane's
        lower edge lands mid-screen, and a plate with a lit ground (the strap
        shot) shows that edge as a hard line. A short fade to the page ground
        across the seam hides it for every plate; the engine sets --art-bottom
        to where the plane ends. Portrait only — landscape keeps the desktop fit. */
}
/* LANDSCAPE TABLET in the art-top layout (html.land, set in fit()): the art
   band and a full copy stack do not both fit in 820-1024px of height, so the
   body paragraph goes, same as portrait phones. Title, tagline, stat panel,
   buttons stay. Tablet pass 2026-09-25. */
html.portrait.land .st-copy .de{display:none}   /* the keel itself drops too: Keel.measure() in splash.js, LAND_RATIO */

/* 4, continued: the seam fade follows the ENGINE's portrait decision
   (html.portrait, set in fit()), not a width query, so a tablet held upright
   gets it too — the art-top layout runs up to tuning.fit.phone.breakpoint. */
html.portrait #stage::after{content:""; position:absolute; left:0; right:0; bottom:0; z-index:5; pointer-events:none;
   top:calc(var(--art-bottom, 52vh) - 12vh);
   /* solid below the fade: the optics embeds fill the window, and without this
      their art ran on under the copy (tablet pass, 2026-09-25) */
   background:linear-gradient(180deg, transparent 0, var(--ground, var(--ink)) 14vh, var(--ground, var(--ink)) 100%)}

/* optics micro-beats in the rail: same row, no state number, indented under 03 */
#sindex .bt.mb b{width:0; margin:0}
#sindex .bt.mb span{padding-left:10px}

/* ---- production status dots (states[].status in the config) ----
   green = final content, red = art still owed by PIXELKINGS, yellow = almost.
   Declared after the open-question dot so a status wins. */
#sindex .bt.sf b::after, #sindex .bt.sa b::after, #sindex .bt.so b::after{content:"•"; margin-left:5px; font-size:13px; line-height:0}
#sindex .bt.sf b::after{color:#34d17a}
#sindex .bt.sa b::after{color:#ffd23f}
#sindex .bt.so b::after{color:#ff3b46}
#sindex .bt.mb.sf b::after, #sindex .bt.mb.sa b::after, #sindex .bt.mb.so b::after{margin-left:0}

/* ---- shroud: per-state vignette (config states[].shroud) ----
   Above the art (.plate 4, .seq 5), below the copy layer. A canvas the engine
   draws once (dithered, so the soft edge never bands); box set in plane px. */
.shroud{position:absolute;z-index:6;pointer-events:none;opacity:0;visibility:hidden;max-width:none}

/* ---- speaker pulse (config states[].pulse): live rings from the grille ---- */
.pulse-fx{position:absolute;z-index:6;pointer-events:none;opacity:0;visibility:hidden}

/* ---- parallax art (config parallax.sprites), edge-anchored ---- */
.px img.parallax-layer{position:absolute;top:0;width:auto;max-width:none;will-change:transform;pointer-events:none}

/* ===================================================== THEME GUARD ======
   The page is built to own the document, but on WordPress it is dropped
   into a theme that has its own ideas about h2, p, a, img and body. Every
   rule here re-asserts a value the page already sets, at a specificity a
   theme's global styles (.entry-content h2, img{max-width:100%}, a{…})
   cannot beat by accident. Nothing here changes the page on its own; it
   only stops a host page from changing it. (0.20.80, AB integration) */
#stage, #stage *, .st-copy, .st-copy *, #ctas, #ctas *, #cue, #cue *, #pager, #pager *, #preload, #preload *{
  box-sizing:border-box}
#stage, .st-copy, #ctas, #cue, #pager, #preload{
  font-family:var(--face); color:#fff; -webkit-font-smoothing:antialiased; text-transform:none; text-align:left}
.st-copy h2, .st-copy p, .st-copy .ti, .st-copy .tg, .st-copy .de{
  margin:0; padding:0; border:0; background:none; text-shadow:none; font-family:var(--face); text-transform:none}
.st-copy .ti{font-weight:300; color:#fff; font-size:clamp(32px, 4.1vw, 64px); line-height:1.0; letter-spacing:.03em}
.st-copy .ti .b{color:var(--blue); font-weight:inherit}
.st-copy .tg{font-weight:300; color:#fff; font-size:clamp(17px, 1.55vw, 24px); line-height:1.42; letter-spacing:.04em}
.st-copy .de{font-weight:400; color:var(--mute); font-size:clamp(13px, 1.02vw, 16px); line-height:1.5; letter-spacing:.06em}
.st-copy .pcn, .st-copy .pcl{font-size:clamp(11px, .82vw, 14px); font-weight:500; font-family:var(--face)}
.st-copy.rv .ti{font-size:clamp(24px, 2.6vw, 44px); line-height:1.15; letter-spacing:.05em; text-align:center}
@media (max-height: 700px){ .st-copy .ti{font-size:clamp(28px, 3.4vw, 44px)} }
@media (max-height: 500px) and (orientation: landscape){ .st-copy .ti{font-size:clamp(24px, 5.5vh, 34px)} }
.st-copy.cb .ti{font-size:clamp(26px,3.1vw,48px); line-height:1.2}
/* art: a theme's img{max-width:100%;height:auto} would shrink every plate and frame */
#stage img, #stage canvas, #stage video, #stage iframe, .st-copy img{
  max-width:none; max-height:none; border:0; border-radius:0; box-shadow:none; margin:0; padding:0; background:none; vertical-align:top}
#stage iframe.emb{border:0}
/* buttons are <a>: no theme underline, colour, box-shadow or transition on them */
#ctas a.btn, #ctas a.btn:hover, #ctas a.btn:focus, #ctas a.btn:visited{
  text-decoration:none; color:#fff; box-shadow:none; outline-offset:2px; font-family:var(--face); text-transform:none; line-height:1}
#ctas a.btn.p{font-weight:400} #ctas a.btn.s{font-weight:400}
/* the scroll driver reads window scroll: a theme's smooth-scroll must not fight the pager */
html{scroll-behavior:auto !important}
/* the page is the viewport: nothing in a host wrapper may clip or offset it */
#stage, .st-copy, #ctas, #cue, #pager, #preload{transform:none; filter:none; contain:none}

#vgBtn{position:fixed;left:14px;bottom:14px;z-index:99;font:600 12px/1 system-ui,sans-serif;letter-spacing:.04em;color:#ddd;background:rgba(20,20,20,.85);border:1px solid rgba(255,255,255,.25);border-radius:6px;padding:8px 12px;cursor:pointer}
#vgBtn:hover{background:#333}
#vg .vg-on{display:inline-flex;align-items:center;gap:6px;cursor:pointer}

/* InspirePRO(TM) */
sup.tm{font-size:.38em;font-weight:400;vertical-align:top;position:relative;top:.35em;margin-left:.08em;letter-spacing:0}
/* RadiusXR wordmark, top left, escape hatch to the product page */
/* same size and place as the header logo on radiusxr.com: 120x48 at 32,24; phones 93x38 at 16,27 */
#logo{position:fixed;left:32px;top:24px;z-index:30;display:block;line-height:0}
#logo img{display:block;width:120px;height:48px}
@media (max-width:600px){#logo{left:16px;top:27px} #logo img{width:93px;height:38px}}
#logo:hover{opacity:1}
html.boot #logo{opacity:0}
@media (max-width:600px){#vgBtn{display:none}}

/* ---- PHONE PAGE: styled by assets/css/phone.css, which splash.js loads only on
   phones and small tablets (html.phone). Nothing phone-specific lives in this
   file; desktop never downloads phone.css. The #phone markup in index.html is
   hidden here so desktop never shows it and never fetches its lazy images. */
#phone[hidden]{display:none}

 /* production: hide developer warnings */
     #gap{display:none !important}
     .seq .ph .lb b, .seq .ph .lb i, .seq .ph .lb small{display:none !important}

.cky-consent-container{display:none !important}
.uai{display:none !important}
.cky-btn-revisit-wrapper{display:none !important}