/* ==========================================================================
   ShiftWren — marketing site
   Design tokens lifted from the ShiftWren product design system.
   ========================================================================== */

:root{
  /* Brand */
  --ink:#1E1E1E;
  --paper:#F0F0F0;
  /* The tile surface. --paper is a NEUTRAL grey; the page ground is a
     lavender-tinted white (--sky-1). Wherever a full-width tile in --paper met
     the ground, the mismatch showed as a grey band with a hard edge — both a
     value step and a hue step. --surface is the same family as the ground. */
  --surface:#F4F4FB;
  --white:#fff;
  --blue:#2663EB;
  --blue-deep:#1B4BC4;
  --yellow:#E1EB26;
  --red:#EB2626;
  /* Same red, taken down far enough to pass AA at label sizes on a light
     ground. Use it for small red TEXT; --red stays the brand fill. */
  --red-ink:#C81E1E;
  /* The same red lifted for a DARK ground: #EB2626 is 4.13:1 on the #15171C
     panels, which carries large display text but not a label beside it. */
  --red-on-dark:#F04444;
  /* Text on the red footer. #1E1E1E is 3.84:1 on #EB2626 and near-black is
     the only thing that clears 4.5 — the red is the brand fill and does not
     move, so the ink does. Visually indistinguishable from --ink. */
  --ink-on-red:#0A0A0A;
  /* Bright enough to clear 3:1 against the blue card fill, which the product
     UI's success green (#067647) does not — that one is built for white. */
  --tick:#5BF0A5;

  /* Ink opacities */
  --ink-72:rgba(30,30,30,.72);
  --ink-68:rgba(30,30,30,.68);
  --ink-65:rgba(30,30,30,.65);
  --ink-62:rgba(30,30,30,.62);
  /* .55 reads 3.76:1 on the paper and 3.66:1 on the tinted surfaces — below
     AA everywhere it is drawn, and it carries the eyebrows, section numbers
     and meta labels across the whole page. .62 is the lowest alpha that
     clears 4.5:1 on all four grounds (paper, white, surface, sky), so this
     token is now the floor rather than a shade below it. */
  --ink-55:rgba(30,30,30,.62);
  --ink-18:rgba(30,30,30,.18);
  --ink-16:rgba(30,30,30,.16);
  --ink-14:rgba(30,30,30,.14);
  --ink-12:rgba(30,30,30,.12);
  --ink-10:rgba(30,30,30,.10);

  /* Product-UI palette (used inside app mocks only) */
  --ui-ink:#16181D;
  --ui-body:#3B424E;
  --ui-muted:#5B6270;
  /* 4.76:1 on the tinted roster panels (#F1F3F6, #EFF4FF) and 5.3:1 on white.
     Was #8A9099 (3.1:1 on white), then #6B7280 — which cleared AA on white at
     4.83:1 but only reached 4.35:1 on the tinted panels this is mostly used
     on, so it still failed where it was actually drawn. */
  --ui-dim:#656C77;
  --ui-line:#E7E9EE;
  --ui-line-2:#F1F3F6;
  --ui-bg:#F6F7F9;
  --ui-bg-2:#FCFCFD;
  --ui-blue:#2563EB;
  --ui-blue-bg:#EFF4FF;
  --ui-blue-br:#C7D9FE;
  --ok:#067647; --ok-bg:#ECFDF3; --ok-br:#ABEFC6;
  --warn:#B54708; --warn-bg:#FFFAEB; --warn-br:#FEDF89;
  --bad:#B42318; --bad-bg:#FEF3F2; --bad-br:#FECDCA;
  /* The same three states on a DARK panel. --ok/--warn/--bad are sized for
     tinted light chips and are close to unreadable on the comparison matrix,
     which is nearly black. */
  --ok-lite:#4FD584; --warn-lite:#F5B544; --bad-lite:#FF8A8A;

  /* Type */
  /* Three roles, following the pattern on the award sites this was studied
     against: a characterful DISPLAY face carrying the headlines, a neutral
     sans doing the reading, and a mono for labels and figures.
       lamalama  Suisse BP Intl  + Sometype Mono
       bombon    akina           + system sans
     Both buy a bespoke display. Bricolage Grotesque is the closest thing on
     Google Fonts with real character — variable on optical size AND weight,
     so one file covers 12px labels to 92px hero type and the letterforms
     tighten as they grow, which is what a bespoke display does by hand.
     To swap it, change --display only; nothing else references it. */
  --display:"Bricolage Grotesque","Geist","Geist Fallback",system-ui,sans-serif;
  --sans:Geist,"Geist Fallback",system-ui,-apple-system,"Segoe UI",sans-serif;
  --mono:"Geist Mono",ui-monospace,SFMono-Regular,Menlo,monospace;

  /* Motion */
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-out-expo:cubic-bezier(.16,1,.3,1);

  /* Layout */
  --headerH:86px;
  --max:1240px;
  --pad:clamp(22px,5vw,60px);
  /* One measure for running text. Nothing that is meant to be READ should
     cross this, whatever the column it sits in can afford. A 1240px line of
     16px type is about 150 characters; the eye loses its place returning from
     the end of one line to the start of the next somewhere past 75. */
  --measure:66ch;
  /* The single vertical rhythm unit. Every section's top and bottom padding is
     this value, so the gap between any two sections is exactly 2 x --sec-y and
     the page reads at one cadence. Re-declared (not overridden per rule) at the
     two breakpoints below — change it in those three places and nowhere else,
     or the cadence stops being one cadence.

     Raised ~20% from 8.4vw/116 max: about 218px between sections on a 1300px
     screen became about 265px. Sections on this page are long and each makes a
     single argument, so they need a gap that reads as "new thought" rather
     than "next paragraph". */
  --sec-y:clamp(84px,10.2vw,140px);
  --radius:20px;
}

*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
/* The pinned tour counter-translates a section to hold it still. Chrome's scroll
   anchoring reads that as content shifting above the viewport and "corrects"
   the scroll position, dragging the page mid-transition. */
body{overflow-anchor:none}
body{
  background:var(--paper);color:var(--ink);
  font-family:var(--sans);
  font-feature-settings:'cv11','ss01';
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:clip;
}
a{color:var(--blue);text-decoration:none;transition:color .2s var(--ease),background .2s var(--ease),border-color .2s var(--ease),transform .2s var(--ease)}

@media (hover: hover) and (pointer: fine){a:hover{color:var(--blue-deep)}}
img,svg{max-width:100%;display:block}
button{font-family:inherit}
::selection{background:var(--yellow);color:var(--ink)}
:focus-visible{outline:3px solid var(--blue);outline-offset:3px;border-radius:4px}

.wrap{max-width:var(--max);margin:0 auto}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* A skip link has to BECOME VISIBLE when it takes focus, or the first thing a
   keyboard user tabs to is an invisible control. Ours stayed 1x1 at all times,
   which fails the one job it has. */
a.sr-only:focus{
  position:fixed;top:12px;left:12px;z-index:10000;
  width:auto;height:auto;margin:0;clip:auto;overflow:visible;
  padding:12px 18px;border-radius:10px;
  background:var(--ink);color:#fff;font-size:14px;font-weight:500;text-decoration:none;
  box-shadow:0 10px 30px -12px rgba(0,0,0,.5);outline:2px solid var(--blue);outline-offset:2px;
}

/* ==========================================================================
   Film grain + scroll progress (AWWWARDS layer)
   ========================================================================== */
.grain{
  position:fixed;inset:-25%;z-index:9990;pointer-events:none;opacity:.035;
  contain:strict;backface-visibility:hidden;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/></filter><rect width='200' height='200' filter='url(%23n)'/></svg>");
  animation:grainShift 1.8s steps(4) infinite;
  will-change:transform;
}
@keyframes grainShift{
  0%{transform:translate(0,0)}33%{transform:translate(-2%,1%)}66%{transform:translate(1%,-2%)}100%{transform:translate(0,0)}
}
/* One solid bar. The old blue→yellow gradient had such a hard colour break
   that a part-filled bar read as two separate bars. */
.progress{
  position:fixed;top:0;left:0;height:3px;width:100%;z-index:9999;transform-origin:0 50%;
  transform:scaleX(0);background:var(--yellow);pointer-events:none;
  will-change:transform;
}

/* ==========================================================================
   Cursor — a ring that reports what it is over

   Lags behind the pointer, stretches along the direction of travel, expands
   over anything interactive and names the action inside itself. Inverts on
   dark ground via [data-cursor-dark].
   ========================================================================== */
/* the masks live here; nothing in this svg is painted directly */
.cursor-svg{position:fixed;top:0;left:0;width:0;height:0;overflow:visible;pointer-events:none;z-index:-1}

/* Two lens layers, masked to the liquid body and to its rim. No blend mode —
   the liquid is purely refractive, so it behaves the same on any background. */
.cursor-layer{
  position:fixed;top:0;left:0;z-index:9996;pointer-events:none;
  width:320px;height:320px;will-change:transform;transition:opacity .3s;
  -webkit-mask-image:url(#wm-mask-body);mask-image:url(#wm-mask-body);
  -webkit-backdrop-filter:url(#wm-lens);backdrop-filter:url(#wm-lens);
}
/* where backdrop-filter cannot take an SVG filter, fall back to plain glass */
.cursor-layer.is-lite{
  -webkit-backdrop-filter:blur(1.6px) saturate(1.7) brightness(1.06);
  backdrop-filter:blur(1.6px) saturate(1.7) brightness(1.06);
}

/* Arrow — the true pointer. Arrowhead only, no tail, brand dot on the tip. */
.cursor-arrow{
  position:fixed;top:0;left:0;z-index:9998;pointer-events:none;
  width:46px;height:46px;margin:-16px 0 0 -16px;   /* tip (16,16) on the hotspot */
  will-change:transform;transition:opacity .3s;
  filter:drop-shadow(0 3px 6px rgba(10,20,50,.42));
}
.cursor-arrow svg{
  overflow:visible;transform-origin:16px 16px;
  transition:transform .26s var(--ease-out-expo);
}
.cursor-arrow.is-hot svg{transform:scale(1.24)}
.cursor-arrow__body{
  fill:url(#wm-arrow-l);stroke:#fff;stroke-width:2.4;
  stroke-linejoin:round;stroke-linecap:round;paint-order:stroke fill;
  transition:fill .25s var(--ease),stroke .25s var(--ease);
}
.cursor-arrow.is-dark .cursor-arrow__body{fill:url(#wm-arrow-d);stroke:rgba(12,22,48,.55)}
.cursor-arrow.is-hot .cursor-arrow__body{fill:var(--blue)}
.cursor-arrow.is-hot.is-dark .cursor-arrow__body{fill:var(--yellow);stroke:rgba(12,22,48,.5)}

/* action label, carried beside the arrow */
.cursor-tag{
  position:fixed;top:0;left:0;z-index:9998;pointer-events:none;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;
  background:var(--ink);color:#fff;padding:5px 9px;border-radius:999px;white-space:nowrap;
  opacity:0;transform-origin:0 0;transition:opacity .2s var(--ease);
  box-shadow:0 4px 14px -6px rgba(10,20,50,.6);
}
.cursor-tag.is-on{opacity:1}
.cursor-tag.is-dark{background:#fff;color:var(--ink)}
body.cursor-ready{cursor:none}
body.cursor-ready a,body.cursor-ready button,body.cursor-ready input,body.cursor-ready label{cursor:none}
@media (hover:none),(max-width:1024px){.cursor-layer,.cursor-arrow,.cursor-tag,.cursor-svg{display:none!important}body.cursor-ready{cursor:auto}}

/* ==========================================================================
   Loading screen — the working day, run at speed

   The clock counts 9:00 up to 4:58 while the page boots, landing on the exact
   moment the hero's headline talks about. On exit the panel leaves as six
   staggered slats rather than one block.
   ========================================================================== */
.loader{position:fixed;inset:0;z-index:10000;pointer-events:none;overflow:hidden}
.loader__slats{position:absolute;inset:0;display:flex}
.loader__slats span{
  flex:1;background:linear-gradient(180deg,#175FD2,#2472DE);transform:translateY(0);
  transition:transform 1.05s var(--ease-out-expo);
}
.loader.is-out .loader__slats span{transform:translateY(-101%)}
.loader__slats span:nth-child(1){transition-delay:0ms}
.loader__slats span:nth-child(2){transition-delay:60ms}
.loader__slats span:nth-child(3){transition-delay:120ms}
.loader__slats span:nth-child(4){transition-delay:180ms}
.loader__slats span:nth-child(5){transition-delay:240ms}
.loader__slats span:nth-child(6){transition-delay:300ms}

/* Backdrop: a drifting ledger grid, a breathing glow and a slow sheen — enough
   motion that the wait feels like something is being assembled. */
.loader__bg{position:absolute;inset:0;overflow:hidden;z-index:0;pointer-events:none;transition:opacity .4s var(--ease)}
.loader.is-out .loader__bg{opacity:0}
/* The hero's gradient, so the loader is the page arriving rather than a
   separate screen in front of it. Grid removed. */
.loader__bg{
  background:
    radial-gradient(ellipse 62% 46% at 50% -6%,rgba(255,255,255,.42),transparent 62%),
    radial-gradient(ellipse 52% 40% at 86% 24%,rgba(154,204,255,.34),transparent 68%),
    radial-gradient(ellipse 70% 52% at 14% 84%,rgba(214,235,255,.3),transparent 66%),
    radial-gradient(ellipse 80% 60% at 50% 118%,rgba(12,52,140,.28),transparent 70%),
    linear-gradient(180deg,#175FD2 0%,#1E68D8 50%,#2472DE 100%);
}
.loader__bg::after{
  content:"";position:absolute;left:50%;top:50%;width:150vmax;height:150vmax;
  transform:translate(-50%,-50%);
  background:radial-gradient(circle,rgba(255,255,255,.14),rgba(255,255,255,0) 42%);
  animation:lbreathe 3.4s ease-in-out infinite;
}
.loader__sheen{
  position:absolute;top:-60%;left:-40%;width:38%;height:220%;pointer-events:none;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.07),transparent);
  transform:rotate(14deg);animation:lsheen 2.8s ease-in-out infinite;
}
@keyframes ldrift{from{transform:translate3d(0,0,0)}to{transform:translate3d(64px,64px,0)}}
@keyframes lbreathe{0%,100%{opacity:.55;transform:translate(-50%,-50%) scale(.92)}50%{opacity:1;transform:translate(-50%,-50%) scale(1.06)}}
@keyframes lsheen{0%{left:-45%}60%,100%{left:115%}}

/* the running commentary, and the line it pays off on */
.loader__status{
  font-family:var(--mono);font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;
  color:rgba(255,255,255,.5);min-height:1.2em;
  transition:color .3s var(--ease),opacity .22s var(--ease),transform .22s var(--ease);
}
.loader__status.is-swap{opacity:0;transform:translateY(6px)}
.loader__status.is-done{color:var(--yellow);letter-spacing:.2em}

.loader__inner{
  position:relative;z-index:1;height:100%;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:clamp(18px,3vh,30px);
  padding:0 var(--pad);
  transition:opacity .45s var(--ease),transform .45s var(--ease);
}
.loader.is-out .loader__inner{opacity:0;transform:translateY(-16px)}
.loader__mark{position:relative;z-index:1;font-size:17px;letter-spacing:-.03em;color:rgba(255,255,255,.72)}
.loader__mark .wm{--wm-eye:var(--blue)}
.loader__clock{
  font-family:var(--mono);font-weight:500;
  font-size:clamp(58px,14vw,168px);line-height:.86;letter-spacing:-.06em;color:#fff;
  font-variant-numeric:tabular-nums;display:flex;align-items:baseline;
}
.loader__clock i{font-style:normal;color:var(--blue);margin:0 .04em;animation:blink 1s steps(1) infinite}
.loader__rail{width:min(360px,64vw);height:2px;background:rgba(255,255,255,.16);overflow:hidden}
.loader__rail i{display:block;height:100%;width:0;background:var(--yellow)}
/*
 * Centred, not spread.
 *
 * The status and the percentage were pushed to opposite ends of a 360px rail
 * under a centred wordmark and a centred clock — the only two things on the
 * loading screen that were not on the centre line. Together in the middle
 * they read as one caption under the bar.
 *
 * This used to be declared twice: once here and once again as an inline
 * style on the element, which repeated the font, the size, the tracking and
 * the casing verbatim and silently won over this rule. The inline copy is
 * gone, so there is one place to change it.
 */
.loader__meta{
  display:flex;align-items:center;justify-content:center;gap:12px;
  width:min(360px,64vw);
  font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:rgba(255,255,255,.5);
}
.loader__meta span:last-child{color:var(--yellow)}

/* ==========================================================================
   Reveal / motion primitives
   ========================================================================== */
[data-reveal]{opacity:0;transform:translateY(24px);transition:opacity .8s var(--ease),transform .8s var(--ease)}
[data-reveal].in{opacity:1;transform:none}
[data-reveal="scale"]{transform:translateY(28px) scale(.97)}
[data-reveal="scale"].in{transform:none}
[data-reveal="left"]{transform:translateX(-28px)}
[data-reveal="left"].in{transform:none}

/* word-by-word headline reveal */
.split .word{display:inline-block;overflow:hidden;vertical-align:top}
.split .word>span{display:inline-block;transform:translateY(105%);transition:transform .9s var(--ease-out-expo)}
.split.in .word>span{transform:none}

/* clip-wipe for media */
[data-clip]{clip-path:inset(0 0 100% 0);transition:clip-path 1.1s var(--ease-out-expo)}
[data-clip].in{clip-path:inset(0 0 0 0)}

.magnetic{will-change:transform;transition:transform .35s var(--ease)}
.tilt{transition:transform .5s var(--ease),border-color .3s,background .3s,box-shadow .4s}

@keyframes marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@keyframes pulse{0%,100%{opacity:.28}50%{opacity:.9}}
@keyframes floaty{0%,100%{transform:translateY(0)}50%{transform:translateY(-9px)}}
@keyframes blink{0%,49%{opacity:1}50%,100%{opacity:0}}

/* ==========================================================================
   Header / navigation
   ========================================================================== */
.header{
  position:sticky;top:0;z-index:60;padding:clamp(12px,2.4vw,18px) var(--pad);
  display:flex;align-items:center;justify-content:space-between;gap:14px;pointer-events:none;
}
.logo{
  pointer-events:auto;display:flex;align-items:center;gap:2px;background:var(--white);
  border-radius:12px;padding:11px 17px;font-size:16px;letter-spacing:-.03em;line-height:1;
  color:var(--ink);box-shadow:0 4px 18px -6px rgba(30,30,30,.28);
}

@media (hover: hover) and (pointer: fine){.logo:hover{color:var(--ink);transform:translateY(-1px)}}

/* The ShiftWren logo (26 September 2026): the wren, then the name in Space
   Grotesk 700 at -0.05em. The bird is currentColor, so it takes the ink of
   whatever holds it; the eye is lime on light grounds and blue on dark ones,
   as the logo sheet sets them. */
.wm{display:inline-flex;align-items:center;gap:.32em;line-height:1;white-space:nowrap}
.wm__bird{width:1.3em;height:1.3em;flex:none;overflow:visible}
.wm__eye{fill:var(--wm-eye,#E1EB26)}
.wm__name{font-family:'Space Grotesk',system-ui,sans-serif;font-weight:700;letter-spacing:-.05em}

.navpill{
  pointer-events:auto;display:flex;align-items:center;gap:4px;background:var(--ink);
  border-radius:14px;padding:6px;box-shadow:0 8px 26px -10px rgba(30,30,30,.5);
  /* Two edges, not one: a hairline on the outside so the pill has a rim
     against a pale page, and an inset one just within it so the dark field
     reads as a recessed tray the items sit in rather than a flat blob. */
  border:1px solid rgba(255,255,255,.16);
  box-shadow:0 8px 26px -10px rgba(30,30,30,.5),
             inset 0 0 0 1px rgba(255,255,255,.05);
}
/* Direct children only. .navpill a would also catch every link inside the
   Product dropdown, which is a white panel and wants none of this. */
.navpill > a,.navpill > .has-drop > a{
  color:rgba(255,255,255,.66);font-size:14px;font-weight:500;border-radius:9px;
  /* 9/14 + a 1px border is the 10/15 this used to be: the outline is drawn
     without moving a single item. */
  padding:9px 14px;
  border:1px solid rgba(255,255,255,.12);
  transition:color .16s var(--ease),background .16s var(--ease),border-color .16s var(--ease);
}

@media (hover: hover) and (pointer: fine){.navpill > a:hover,.navpill > .has-drop > a:hover{
  color:#fff;background:rgba(255,255,255,.1);border-color:rgba(255,255,255,.28);
}}
/* The page you are on. Yellow, but stated as an outline and a tint rather
   than a solid fill — there is already one solid yellow in this header, the
   trial button, and it should stay the only thing shouting. */
.navpill > a.is-active,.navpill > .has-drop > a.is-active{
  color:var(--yellow);
  background:rgba(225,235,38,.13);
  border-color:rgba(225,235,38,.55);
}

@media (hover: hover) and (pointer: fine){.navpill > a.is-active:hover,.navpill > .has-drop > a.is-active:hover{
  color:var(--yellow);background:rgba(225,235,38,.2);border-color:var(--yellow);
}}

.header__right{pointer-events:auto;display:flex;align-items:center;gap:10px}
/* The header's trial button is the same offer as every trial button on the
   page, so it is now the same colour: yellow on the black edge the rest of
   the button system uses. It was ink with a white rim, which made the one
   thing the header is for look like a piece of the header. */
.btn-join{
  background:var(--yellow);color:var(--ink);font-size:13.5px;font-weight:700;letter-spacing:.05em;
  padding:12px 20px;border-radius:12px;display:inline-flex;align-items:center;
  border:1.5px solid var(--ink);
  box-shadow:0 6px 20px -8px rgba(8,22,60,.45);white-space:nowrap;
}

@media (hover: hover) and (pointer: fine){.btn-join:hover{background:#fff;color:var(--ink);border-color:var(--ink);transform:translateY(-1px)}}
.btn-join__narrow{display:none}
.menubtn{
  display:none;align-items:center;justify-content:center;width:48px;height:48px;border-radius:12px;
  background:var(--ink);color:#fff;font-size:18px;cursor:pointer;border:0;
  box-shadow:0 8px 26px -10px rgba(30,30,30,.5);
}
.mobilepanel{
  position:absolute;top:calc(100% - 2px);left:var(--pad);right:var(--pad);pointer-events:auto;
  display:none;flex-direction:column;gap:2px;background:var(--ink);border-radius:16px;padding:10px;
  box-shadow:0 20px 44px -18px rgba(30,30,30,.65);
}
.mobilepanel.is-open{display:flex}
.mobilepanel a{color:rgba(255,255,255,.82);font-size:15px;font-weight:500;padding:14px 16px;border-radius:9px}

@media (hover: hover) and (pointer: fine){.mobilepanel a:hover{color:#fff;background:rgba(255,255,255,.1)}}

/* ==========================================================================
   Buttons
   ========================================================================== */
.btn{
  height:46px;padding:0 22px;border-radius:10px;display:inline-flex;align-items:center;gap:9px;
  font-size:15px;font-weight:600;white-space:nowrap;border:0;cursor:pointer;
}
.btn .arw{font-family:var(--mono);transition:transform .3s var(--ease)}

@media (hover: hover) and (pointer: fine){.btn:hover .arw{transform:translateX(4px)}}
/* Primary is blue on a black edge; secondary is yellow on the same edge.
   The border is the constant, so the two read as one family at a glance and
   the colour is the only thing carrying the rank. --ink, not #000: pure black
   against this page's off-white is harder than anything else on it. */
.btn--primary{background:var(--blue);color:#fff;border:1.5px solid var(--ink);box-shadow:0 2px 0 rgba(30,30,30,.9)}

@media (hover: hover) and (pointer: fine){.btn--primary:hover{background:var(--blue-deep);color:#fff;transform:translateY(1px);box-shadow:0 1px 0 rgba(30,30,30,.9)}}
.btn--ink{background:var(--ink);color:#fff}

@media (hover: hover) and (pointer: fine){.btn--ink:hover{background:var(--blue);color:#fff}}
/* .btn--yellow is the older name for the same thing and still in the markup;
   both selectors stay so nothing has to be renamed to get the border. */
.btn--secondary,.btn--yellow{background:var(--yellow);color:var(--ink);border:1.5px solid var(--ink)}

@media (hover: hover) and (pointer: fine){.btn--secondary:hover,.btn--yellow:hover{background:#fff;color:var(--ink)}}
.btn--ghost{background:var(--white);color:var(--ink);border:1px solid var(--ink-18);font-weight:500}

@media (hover: hover) and (pointer: fine){.btn--ghost:hover{border-color:var(--ink);color:var(--ink)}}
.btn--ghost-dark{border:1px solid rgba(255,255,255,.45);color:#fff;font-weight:500;background:transparent}

@media (hover: hover) and (pointer: fine){.btn--ghost-dark:hover{background:rgba(255,255,255,.12);color:#fff}}
.btn--ghost-ink{border:1px solid rgba(30,30,30,.35);color:var(--ink);font-weight:500;background:transparent}

@media (hover: hover) and (pointer: fine){.btn--ghost-ink:hover{background:rgba(30,30,30,.08);color:var(--ink)}}
.btn--lg{height:54px;padding:0 28px;font-size:16px}

/* store buttons */
.stores{display:flex;flex-wrap:wrap;gap:10px}
.store{
  display:inline-flex;align-items:center;gap:10px;height:52px;padding:0 18px;border-radius:12px;
  background:var(--ink);color:#fff;border:1px solid var(--ink);
}

@media (hover: hover) and (pointer: fine){.store:hover{background:var(--blue);border-color:var(--blue);color:#fff;transform:translateY(-2px)}}
.store svg{width:20px;height:20px;flex:none;fill:currentColor}
.store span{display:flex;flex-direction:column;line-height:1.15;text-align:left}
.store b{font-size:14px;font-weight:600;letter-spacing:-.01em}
.store i{font-style:normal;font-size:10px;font-family:var(--mono);letter-spacing:.1em;text-transform:uppercase;opacity:.65}
.store--light{background:var(--white);color:var(--ink);border-color:var(--ink-18)}

@media (hover: hover) and (pointer: fine){.store--light:hover{background:var(--ink);color:#fff;border-color:var(--ink)}}

/* sticky bottom CTA */
.stickycta{
  position:fixed;left:50%;bottom:18px;transform:translate(-50%,140%);z-index:70;
  display:flex;align-items:center;gap:14px;background:var(--ink);color:#fff;
  padding:10px 12px 10px 20px;border-radius:16px;box-shadow:0 22px 50px -22px rgba(30,30,30,.8);
  transition:transform .6s var(--ease-out-expo);max-width:calc(100vw - 24px);
}
.stickycta.is-up{transform:translate(-50%,0)}
.stickycta{will-change:transform;backface-visibility:hidden}
.stickycta p{font-size:14px;font-weight:500;line-height:1.3}
.stickycta p span{display:block;font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:rgba(255,255,255,.55);margin-top:2px}
.stickycta .btn{height:40px;font-size:14px;padding:0 16px}
.stickycta__x{background:none;border:0;color:rgba(255,255,255,.5);font-size:18px;cursor:pointer;padding:0 4px}

@media (hover: hover) and (pointer: fine){.stickycta__x:hover{color:#fff}}
@media(max-width:620px){.stickycta p span{display:none}.stickycta{gap:10px;padding:8px 10px 8px 14px}}

/* ==========================================================================
   Shared section furniture
   ========================================================================== */
.section{padding:var(--sec-y) var(--pad)}
/* --tight used to zero the top padding, which made the whole lower half of the
   home page (numbers, pricing, FAQ, CTA) run at 92px between sections while the
   upper half ran at 184px. It is now an alias, kept only so the markup on four
   pages does not have to churn. */
.section--tight{padding:var(--sec-y) var(--pad)}
.eyebrow{
  display:flex;align-items:baseline;gap:14px;margin-bottom:22px;
}
.eyebrow span:first-child{
  font-family:var(--mono);font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--blue);
}
.eyebrow .rule{flex:1;height:1px;background:var(--ink-16)}
.eyebrow--red span:first-child{color:var(--red-ink)}
.eyebrow--yellow span:first-child{color:var(--yellow)}
.eyebrow--yellow .rule,.eyebrow--dark .rule{background:rgba(255,255,255,.2)}

h1,h2,h3{text-wrap:balance}
.h-xl{font-size:clamp(38px,6.2vw,82px);line-height:.92;letter-spacing:-.045em;font-weight:600}
.h-lg{font-size:clamp(34px,5.4vw,72px);line-height:.94;letter-spacing:-.045em;font-weight:600}
.h-md{font-size:clamp(26px,3.5vw,46px);line-height:.98;letter-spacing:-.04em;font-weight:600}
.h-sm{font-size:clamp(25px,3.2vw,40px);line-height:1;letter-spacing:-.04em;font-weight:600}
.lede{font-size:16px;line-height:1.65;color:var(--ink-65);max-width:var(--measure)}
.mono-note{font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-62)}

.panel{border-radius:var(--radius);padding:clamp(40px,6vw,88px);position:relative;overflow:hidden}
.panel--blue{background:var(--blue);color:#fff}
.panel--ink{background:var(--ink);color:#fff}
.panel--yellow{background:var(--yellow);color:var(--ink)}
.blob{position:absolute;border-radius:50%;pointer-events:none}

/* ==========================================================================
   Hero
   ========================================================================== */
.hero{position:relative;padding:clamp(44px,6.4vw,84px) var(--pad) 0;overflow:hidden}
/* .grid-bg removed: the ruled overlay was the last thing on any page still
   drawing straight lines across the ground. */

.hero__inner{position:relative;max-width:var(--max);margin:0 auto;text-align:center}
.pill{
  display:inline-flex;align-items:center;gap:10px;background:var(--white);border:1px solid var(--ink-14);
  border-radius:999px;padding:5px 5px 5px 14px;font-size:12.5px;font-weight:500;margin-bottom:30px;
  white-space:nowrap;max-width:100%;
}
.pill .dot{width:7px;height:7px;border-radius:50%;background:var(--blue);animation:pulse 2.4s ease-in-out infinite;flex:none}
.pill .tag{background:var(--yellow);border-radius:999px;padding:4px 10px;font-family:var(--mono);font-size:11px;font-weight:600;letter-spacing:.04em}
.hero h1{margin:0 auto;max-width:15ch}
.hero h1 .blue{color:var(--blue)}
.hero__sub{margin:34px auto 0;max-width:56ch;font-size:clamp(15px,1.1vw,17px);line-height:1.6;color:var(--ink-68);text-wrap:pretty}
.hero__cta{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;margin-top:40px}
.hero__trust{margin-top:18px}
.hero__mock{margin-top:72px;position:relative}
.hero__glow{position:absolute;left:50%;top:-24px;transform:translateX(-50%);width:82%;height:60px;background:var(--blue);filter:blur(48px);opacity:.35}

/* clock ticker in hero pill */
.tick{font-variant-numeric:tabular-nums}
.tick .colon{animation:blink 1.1s steps(1) infinite}

/* ==========================================================================
   App mock chrome (product UI replica)
   ========================================================================== */
.mock{
  position:relative;background:var(--white);border:1px solid var(--ink-16);overflow:hidden;
  box-shadow:0 -1px 0 rgba(30,30,30,.06),0 40px 80px -40px rgba(30,30,30,.4);
}
.mock--hero{border-radius:16px 16px 0 0}
.mock--tour{border-radius:14px;box-shadow:0 24px 60px -34px rgba(30,30,30,.42)}
.mock__bar{
  height:40px;border-bottom:1px solid var(--ui-line);display:flex;align-items:center;gap:8px;
  padding:0 14px;background:var(--ui-bg-2);
}
.mock__bar i{width:10px;height:10px;border-radius:50%;display:block}
.mock__bar i:nth-child(1){background:var(--red);opacity:.8}
.mock__bar i:nth-child(2){background:var(--yellow)}
.mock__bar i:nth-child(3){background:var(--blue);opacity:.8}
.mock__url{margin:0 auto;font-family:var(--mono);font-size:11.5px;color:var(--ui-dim)}
.mock__body{display:grid;grid-template-columns:214px minmax(0,1fr);min-height:520px;background:var(--ui-bg);text-align:left;width:100%}
.mock__side{border-right:1px solid var(--ui-line);background:#fff;padding:16px 12px;display:flex;flex-direction:column;gap:2px}
.mock__brand{display:flex;align-items:center;gap:9px;padding:6px 8px 18px}
.mock__brand .sq{width:26px;height:26px;border-radius:7px;background:#E1EB26;color:#1E1E1E;display:flex;align-items:center;justify-content:center}
.mock__brand .sq svg{width:18px;height:18px}
.mock__brand .sq .wm__eye{fill:#E1EB26}
.mock__brand .nm{font-family:'Space Grotesk',system-ui,sans-serif;font-weight:700;font-size:15px;letter-spacing:-.05em;color:var(--ui-ink)}
.mock__nav{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:8px;font-size:13.5px;color:var(--ui-muted)}
.mock__nav .ic{width:16px;height:16px;border-radius:4px;border:1.5px solid currentColor;opacity:.5;flex:none}
.mock__nav.is-on{color:var(--ui-ink);font-weight:500;background:var(--ui-blue-bg);border:1px solid var(--ui-blue-br);margin-top:2px}
.mock__nav.is-on .ic{border-color:var(--ui-blue);opacity:1}
.mock__main{padding:22px 26px;min-width:0}
.mock__head{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;margin-bottom:20px;flex-wrap:wrap}
.mock__kicker{font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ui-dim);margin-bottom:6px}
.mock__title{font-size:24px;font-weight:600;letter-spacing:-.025em;color:var(--ui-ink)}
.ui-btn{height:36px;padding:0 15px;border-radius:8px;border:1px solid #D5D9E0;background:#fff;display:inline-flex;align-items:center;font-size:14px;color:var(--ui-ink)}
.ui-btn--p{background:var(--ui-blue);color:#fff;border-color:var(--ui-blue);font-weight:500}
.ui-btn--sm{height:32px;font-size:12.5px;padding:0 12px;border-radius:7px}
.ui-btn--dark{background:var(--ui-ink);color:#fff;border-color:var(--ui-ink);font-weight:500}
.mock__kpis{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-bottom:18px}
.kpi{background:#fff;border:1px solid var(--ui-line);border-radius:10px;padding:14px}
.kpi__l{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ui-dim);margin-bottom:8px}
.kpi__v{font-size:21px;font-weight:600;letter-spacing:-.03em;color:var(--ui-ink);font-variant-numeric:tabular-nums}
.kpi__n{font-size:12px;color:var(--ok);margin-top:4px}
.tbl{background:#fff;border:1px solid var(--ui-line);border-radius:10px;overflow:hidden}
.tbl__h,.tbl__r{display:grid;gap:12px;align-items:center}
.tbl__h{padding:11px 16px;border-bottom:1px solid var(--ui-line);background:var(--ui-line-2);font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ui-muted)}
.tbl__r{padding:12px 16px;border-bottom:1px solid var(--ui-line-2);font-size:13.5px;color:var(--ui-body)}
.tbl--pay .tbl__h,.tbl--pay .tbl__r{grid-template-columns:1.6fr 1fr 1fr 1fr .8fr}
.tbl--att .tbl__h,.tbl--att .tbl__r{grid-template-columns:1.5fr .9fr .9fr 1fr .8fr .8fr .8fr .9fr;font-size:12.5px;gap:10px;padding-left:16px;padding-right:16px}
.num{font-variant-numeric:tabular-nums}
.who{display:flex;align-items:center;gap:9px;min-width:0}
.av{width:24px;height:24px;border-radius:50%;background:var(--ui-blue-bg);border:1px solid var(--ui-blue-br);color:var(--ui-blue);display:inline-flex;align-items:center;justify-content:center;font-size:10.5px;font-weight:600;flex:none}
.who b{color:var(--ui-ink);font-weight:500}
.who em{font-style:normal;font-family:var(--mono);font-size:10px;color:var(--ui-dim);display:block}
.badge{font-size:11.5px;font-weight:500;padding:3px 9px;border-radius:999px;display:inline-block;white-space:nowrap}
.badge--ok{background:var(--ok-bg);color:var(--ok);border:1px solid var(--ok-br)}
.badge--warn{background:var(--warn-bg);color:var(--warn);border:1px solid var(--warn-br)}
.badge--bad{background:var(--bad-bg);color:var(--bad);border:1px solid var(--bad-br)}
.badge--info{background:var(--ui-blue-bg);color:var(--ui-blue);border:1px solid var(--ui-blue-br)}

/* ==========================================================================
   Sky zone — the hero band

   The top of the page carries the brand gradient; it resolves to the page
   ground at the very bottom so the hand-off into 01 — The problem has no seam.
   ========================================================================== */
.skyzone{
  position:relative;z-index:0;
  /* Pulled up under the sticky header, with the hero's top padding making up
     the difference — so the gradient, the grid and the hero light all run to
     the very top of the page rather than starting below a flat strip. */
  margin-top:calc(-1 * var(--headerH));
  /* The tail fades to NOTHING, not to a colour.

     It used to end on an opaque --sky-1 — the page's ground colour, which
     sounds seamless and is not. body paints --sky-1 plus four lavender
     radials at background-attachment:fixed, so the ground is only pure
     --sky-1 where no radial reaches. An opaque tail covers those radials for
     the whole height of the sky zone and then stops dead at the seam, where
     they reappear at whatever strength they happen to have. Worse, because
     they are fixed to the viewport rather than the page, that strength
     changes as you scroll: the line is not just visible, it breathes.

     Ending at alpha 0 means the last inch of sky zone is the body wash and
     nothing else, which is exactly what the section below it is. There is no
     step left to see because there is no longer a boundary between two
     different paintings — only one painting, with the blue lifted off it.

     (The colour ramp is unchanged, and the extra stops in the last 20% still
     spread it over more levels, which is what keeps the pale tail from
     banding. Alpha now rides down that same ramp.) */
  background:linear-gradient(180deg,
    #175FD2 0%,#2A78E4 16%,#4C95EE 40%,#77B2F3 64%,
    #A8CDF8 80%,#C6DCF9 87%,
    rgba(220,232,251,.88) 91%,
    rgba(234,240,252,.62) 94.5%,
    rgba(244,246,253,.30) 97%,
    rgba(251,251,254,0) 100%);
}
.skyzone .hero{padding-top:calc(var(--headerH) + clamp(44px,6.4vw,84px))}

/* Layered light in the hero: a high sun, a warm lift toward the horizon and a
   deeper corner, so the sky has depth instead of reading as one flat fill. */
.skyzone .hero::after{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(ellipse 62% 46% at 50% -6%,rgba(255,255,255,.42),transparent 62%),
    radial-gradient(ellipse 52% 40% at 86% 24%,rgba(154,204,255,.34),transparent 68%),
    radial-gradient(ellipse 70% 52% at 14% 84%,rgba(214,235,255,.3),transparent 66%),
    radial-gradient(ellipse 80% 60% at 50% 118%,rgba(12,52,140,.28),transparent 70%);
}
.skyzone .hero__inner{position:relative;z-index:1}
.skyzone .hero__glow{display:none}
.skyzone .hero h1{color:#fff}
.skyzone .hero h1 .blue{color:var(--yellow)}
.skyzone .hero__sub{color:rgba(255,255,255,.86)}
.skyzone .hero__trust{color:rgba(255,255,255,.74)}
/* The hero used to flip primary to ink, because a blue button on a blue sky
   had nothing to separate it from the sky. The black border does that job now,
   so primary stays blue here like everywhere else — one rule, no exception. */
.skyzone .btn--ghost{background:rgba(255,255,255,.16);color:#fff;border-color:rgba(255,255,255,.55)}

@media (hover: hover) and (pointer: fine){.skyzone .btn--ghost:hover{background:rgba(255,255,255,.28);border-color:#fff;color:#fff}}

/* the marquee keeps its dark band — a hard cut through the sky, by design */
.skyzone .marquee{border-top:0;border-bottom:0}

/* Metrics: a light glass rail on the sky, each stat centred — number and
   label share one axis instead of hanging off a left edge. */
/* Inside the sky the card keeps the same white surface as everywhere else —
   it just leans on a stronger shadow to lift off the blue. It used to invert
   to white-on-translucent here, which is why its own numbers were unreadable
   at the pale end of the gradient. */
.skyzone .metrics{
  border-color:rgba(255,255,255,.55);
  box-shadow:0 34px 76px -40px rgba(10,34,92,.55),0 2px 4px rgba(10,34,92,.08);
}
.skyzone .section{border-bottom-color:transparent!important}
@media(max-width:900px){
  .metrics,.statband{grid-template-columns:repeat(2,minmax(0,1fr))}
  .metric,.statband > div{border-bottom:1px solid var(--ink-10)}
  .metric:nth-child(2n),.statband > div:nth-child(2n){border-right:0}
  .metrics .metric:last-child{grid-column:1 / -1;border-bottom:0}
  .statband > div:last-child{border-bottom:0}
}

/* ==========================================================================
   Marquee
   ========================================================================== */
.marquee{background:var(--ink);color:#fff;padding:26px 0;overflow:hidden;border-top:1px solid var(--ink)}
.marquee__track{display:flex;width:max-content;animation:marquee 38s linear infinite}
.marquee__track span{
  display:inline-flex;align-items:center;gap:40px;padding-right:40px;
  font-size:clamp(17px,1.9vw,26px);font-weight:600;letter-spacing:-.03em;white-space:nowrap;color:rgba(255,255,255,.62);
}
.marquee__track span i{width:7px;height:7px;border-radius:50%;background:var(--yellow);flex:none;display:block}
.marquee__note{text-align:center;margin-top:22px;font-family:var(--mono);font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.62);padding:0 var(--pad)}

@media (hover: hover) and (pointer: fine){.marquee:hover .marquee__track{animation-play-state:paused}}

/* ==========================================================================
   Metric strip
   ========================================================================== */
/* ---- Stat band -----------------------------------------------------------
   One component, used by the home metrics and the About facts. Three attempts
   at a dark slab here were all wrong for the same reason: a heavy dark box in
   the middle of a white-majority page fights the page. What was actually
   broken was the CONTRAST, not the lightness — white text on the pale tail of
   the sky measured 1.33:1. The fix is a white card with ink numbers, which is
   what every other surface on this site already is, and reads at 16:1.
   -------------------------------------------------------------------------- */
.metrics,.statband{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(186px,1fr));
  gap:0;background:#fff;
  border:1px solid var(--ink-10);border-radius:20px;overflow:hidden;
  box-shadow:0 30px 64px -46px rgba(12,30,80,.45),0 1px 2px rgba(12,30,80,.05);
}
.metric,.statband > div{
  background:transparent;
  padding:clamp(26px,3vw,38px) clamp(16px,2vw,26px);
  text-align:center;
  display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:11px;
  border-right:1px solid var(--ink-10);
}
.metric:last-child,.statband > div:last-child{border-right:0}
.metric__v,.statband b{
  display:block;font-size:clamp(27px,3vw,40px);font-weight:600;letter-spacing:-.045em;
  line-height:1;font-variant-numeric:tabular-nums;color:var(--ink);margin:0;
}
.metric__l,.statband span{
  display:block;margin:0;font-family:var(--mono);font-size:10.5px;letter-spacing:.13em;
  /* --ink-65, not --ink-55: at 10.5px these are small text and need 4.5:1.
     --ink-55 composites to rgb(132,132,132) on white = 3.74:1, which fails. */
  text-transform:uppercase;color:var(--ink-65);max-width:18ch;line-height:1.5;
}

/* ==========================================================================
   Card grids
   ========================================================================== */
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:20px}
.card{
  background:var(--white);border:1px solid var(--ink-14);border-radius:14px;padding:28px;
  display:flex;flex-direction:column;gap:14px;min-height:250px;
}

@media (hover: hover) and (pointer: fine){.card:hover{border-color:var(--ink);transform:translateY(-4px);box-shadow:0 26px 50px -34px rgba(30,30,30,.5)}}
.card__top{display:flex;align-items:center;justify-content:space-between;gap:10px}
.card__num{font-family:var(--mono);font-size:11px;letter-spacing:.12em;color:var(--ink-62)}
.card__cost{
  font-family:var(--mono);font-size:10.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  background:#FDECEC;color:var(--red);border:1px solid rgba(235,38,38,.28);padding:4px 9px;border-radius:999px;
}
.card h3{font-size:18px;font-weight:600;letter-spacing:-.02em;line-height:1.18}
.card p{font-size:14px;line-height:1.6;color:var(--ink-62);flex:1}
.card__fix{display:flex;align-items:center;gap:10px;padding-top:14px;border-top:1px solid var(--ink-10)}
.card__fix i{width:20px;height:20px;border-radius:50%;background:var(--blue);color:#fff;display:inline-flex;align-items:center;justify-content:center;font-size:12px;flex:none;font-style:normal}
.card__fix span{font-size:13.5px;font-weight:500;color:var(--ink)}

/* hairline grid (features / principles / faq) */
.hairgrid{display:grid;gap:1px;background:var(--ink-14);border:1px solid var(--ink-14);border-radius:16px;overflow:hidden}
.hairgrid--3{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.hcell{background:var(--white);padding:36px 32px;min-height:232px;display:flex;flex-direction:column;gap:15px;transition:background .3s var(--ease),color .3s var(--ease)}
.hcell__top{display:flex;align-items:center;justify-content:space-between}
.hcell__ic{width:34px;height:34px;border-radius:9px;border:1px solid currentColor;opacity:.28;display:flex;align-items:center;justify-content:center;transition:opacity .3s}
.hcell__tag{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;opacity:.45}
.hcell h3{font-size:19px;font-weight:600;letter-spacing:-.02em;margin-top:4px}
.hcell p{font-size:14px;line-height:1.6;opacity:.68}

@media (hover: hover) and (pointer: fine){.hcell:hover{background:var(--blue);color:#fff}}

@media (hover: hover) and (pointer: fine){.hcell:hover .hcell__ic{opacity:.6}}

/* ==========================================================================
   Product tour — pinned horizontal filmstrip

   Vertical scroll is remapped onto horizontal travel across four full-size
   screens. Each screen carries its own dark caption plate, so the screenshot
   stays the hero and the copy travels with it. JS interpolates the strip
   offset, per-slide depth and the rail continuously — nothing steps.
   ========================================================================== */
/* No background and no border: the tour sits ON the page ground like every
   other section. A --paper fill here was a grey block with a 1px rule above it. */
.tour{position:relative;height:520vh}
.tour__pin{
  position:sticky;top:0;height:100vh;overflow:hidden;
  display:flex;flex-direction:column;
  padding:clamp(56px,8vh,86px) 0 clamp(14px,2.4vh,24px);
}
.tour__head{flex:none;padding:0 var(--pad)}
.tour__title{font-size:clamp(23px,2.7vw,36px);line-height:1.02;letter-spacing:-.04em;font-weight:600;max-width:20ch}
.tour__counter{font-family:var(--mono);font-size:11px;letter-spacing:.12em;color:var(--ink-62);flex:none}

.strip{position:relative;flex:1;min-height:0;margin-top:clamp(10px,2.2vh,24px)}
.strip__track{
  position:absolute;top:0;left:0;height:100%;display:flex;align-items:stretch;
  gap:clamp(18px,2.6vw,44px);will-change:transform;backface-visibility:hidden;
}
.slide{position:relative;flex:none;height:100%;width:min(1180px,86vw)}
.slide__ghost{
  position:absolute;right:-.04em;top:-.42em;z-index:0;pointer-events:none;
  font-size:clamp(110px,24vh,240px);font-weight:700;letter-spacing:-.06em;line-height:1;
  color:rgba(30,30,30,.06);
}
.slide__stage{position:relative;z-index:1;width:100%;height:100%;will-change:transform;backface-visibility:hidden}

.mock--slide{
  height:100%;display:flex;flex-direction:column;border-radius:16px;background:#fff;
  border:1px solid var(--ink-16);overflow:hidden;
  box-shadow:0 44px 90px -52px rgba(30,30,30,.6);
}
.mock--slide .mock__bar{flex:none;height:42px}
.mock__screen{
  flex:1;min-height:0;overflow:hidden;background:var(--ui-bg);
  -webkit-mask-image:linear-gradient(#000 calc(100% - 64px),transparent);
  mask-image:linear-gradient(#000 calc(100% - 64px),transparent);
}
.screen{background:var(--ui-bg)}
.screen__pad{padding:22px 24px}
.screen h3{font-size:20px;font-weight:600;letter-spacing:-.025em;color:var(--ui-ink)}

/* caption plate — travels with its screenshot */
.plate{
  position:absolute;left:clamp(16px,2.2vw,32px);bottom:clamp(16px,2.2vw,32px);z-index:2;
  width:min(420px,44%);background:var(--ink);color:#fff;border-radius:16px;
  padding:clamp(18px,2vw,26px);box-shadow:0 30px 64px -26px rgba(30,30,30,.8);
  display:flex;flex-direction:column;gap:9px;will-change:transform,opacity;
}
.plate__meta{
  display:flex;align-items:center;gap:10px;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.5);
}
.plate__meta b{color:var(--yellow);font-weight:500}
.plate h3{font-size:clamp(17px,1.4vw,22px);line-height:1.15;letter-spacing:-.028em;font-weight:600;color:#fff}
.plate p{font-size:13.5px;line-height:1.58;color:rgba(255,255,255,.62)}
.chips{display:flex;flex-wrap:wrap;gap:7px;margin-top:4px}
.chip{border:1px solid var(--ink-16);background:var(--white);border-radius:999px;padding:5px 11px;font-size:12px;color:var(--ink-72);white-space:nowrap}
.chips--plate .chip{background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.18);color:rgba(255,255,255,.7)}

/* rail */
.rail{flex:none;padding:clamp(10px,1.8vh,18px) var(--pad) 0}
.rail__in{display:flex;align-items:flex-end;gap:clamp(10px,1.6vw,28px)}
.rail__item{
  flex:1;min-width:0;background:none;border:0;padding:0;cursor:pointer;text-align:left;
  display:flex;flex-direction:column;gap:7px;
}
.rail__n{font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;color:var(--ink-55);transition:color .3s var(--ease)}
.rail__l{font-size:13.5px;font-weight:500;color:var(--ink-55);transition:color .3s var(--ease);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rail__bar{display:block;height:2px;background:var(--ink-14);position:relative;overflow:hidden}
.rail__bar i{position:absolute;top:0;left:0;bottom:0;width:0;background:var(--blue);display:block}

@media (hover: hover) and (pointer: fine){.rail__item:hover .rail__l{color:var(--ink)}}
.rail__item.is-on .rail__n{color:var(--blue)}
.rail__item.is-on .rail__l{color:var(--ink);font-weight:600}
.rail__hint{
  flex:none;font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--ink-55);padding-bottom:3px;white-space:nowrap;
}
@media(max-width:1100px){.rail__hint span{display:none}}

/* schedule board */
.seg{display:flex;background:var(--ui-line-2);border:1px solid var(--ui-line);border-radius:8px;padding:2px}
.seg span{padding:5px 12px;border-radius:6px;font-size:12.5px;color:var(--ui-muted)}
.seg span.is-on{background:#fff;color:var(--ui-ink);font-weight:500;box-shadow:0 1px 2px rgba(16,24,40,.06)}
.board{background:#fff;border:1px solid var(--ui-line);border-radius:10px;overflow:hidden}
.board__head,.board__row{display:grid;grid-template-columns:minmax(120px,150px) repeat(7,minmax(0,1fr))}
.board__head{background:var(--ui-line-2);border-bottom:1px solid var(--ui-line)}
.board__toggle{padding:10px 14px;display:flex;align-items:center;gap:8px}
.board__toggle .sw{width:28px;height:16px;border-radius:999px;background:var(--ui-blue);position:relative;flex:none;display:block}
.board__toggle .sw::after{content:"";position:absolute;top:2px;right:2px;width:12px;height:12px;border-radius:50%;background:#fff}
.board__toggle em{font-style:normal;font-size:11.5px;color:var(--ui-muted)}
.board__day{padding:9px 10px;border-left:1px solid var(--ui-line);display:flex;align-items:center;gap:7px;background:var(--ui-line-2)}
.board__day.is-today{background:var(--ui-blue-bg)}
.board__day b{font-size:16px;font-weight:600;color:var(--ui-ink)}
.board__day span{display:flex;flex-direction:column;line-height:1.15;font-family:var(--mono);font-size:9.5px;letter-spacing:.08em;color:var(--ui-muted)}
.board__day span i{font-style:normal;color:var(--ui-dim)}
.board__row{border-bottom:1px solid var(--ui-line-2)}
.board__who{padding:11px 14px;display:flex;align-items:center;gap:9px}
.board__who .av{width:28px;height:28px;font-size:11px}
.board__who b{display:block;font-size:13px;font-weight:500;color:var(--ui-ink)}
.board__who em{display:flex;align-items:center;gap:5px;font-style:normal;font-size:11px}
.board__who em i{width:6px;height:6px;border-radius:50%;display:block;background:currentColor}
.cell{border-left:1px solid var(--ui-line-2);padding:6px;min-height:56px;background:#fff}
.cell--past{background:var(--ui-bg-2)}
.shift{display:flex;flex-direction:column;gap:2px;background:var(--ui-blue-bg);border:1px solid var(--ui-blue-br);border-radius:6px;padding:6px 8px}
.shift b{font-size:10.5px;font-weight:600;color:var(--ui-ink);white-space:nowrap}
.shift em{font-style:normal;font-family:var(--mono);font-size:9px;letter-spacing:-.01em;color:var(--ui-body);white-space:nowrap}
.shift--past{background:var(--ui-line-2);border-color:var(--ui-line)}
.shift--past b{color:var(--ui-muted)}
.shift--past em{color:var(--ui-dim)}
.shift--leave{background:var(--warn-bg);border-color:var(--warn-br)}
.shift--leave b,.shift--leave em{color:var(--warn)}

/* attendance / invoice bits */
.mini{background:#fff;border:1px solid var(--ui-line);border-radius:10px;padding:14px}
.mini__l{font-size:12px;color:var(--ui-muted);margin-bottom:7px}
.mini__v{display:flex;align-items:baseline;gap:9px}
.mini__v b{font-size:22px;font-weight:600;letter-spacing:-.03em;color:var(--ui-ink)}
.mini__v em{font-style:normal;font-size:11.5px;font-weight:500}
.field__l{font-size:11.5px;color:var(--ui-muted);margin-bottom:5px}
.field__v{height:34px;border:1px solid #D5D9E0;border-radius:8px;background:#fff;display:flex;align-items:center;padding:0 11px;font-size:13px;color:var(--ui-ink)}
.pane{background:#fff;border:1px solid var(--ui-line);border-radius:10px;padding:16px}
.pane__t{font-size:13.5px;font-weight:600;color:var(--ui-ink);margin-bottom:14px}
.sumrow{display:flex;justify-content:space-between;align-items:center;padding:9px 0;border-bottom:1px solid var(--ui-line-2);font-size:13px;color:var(--ui-body)}
.sumrow--total{color:var(--ui-ink);font-weight:600}

/* ==========================================================================
   Compare / calculator
   ========================================================================== */
.compare{background:var(--ink);color:#fff;padding:var(--sec-y) var(--pad)}
.compare h2{color:#fff;max-width:19ch}
.calc{display:grid;grid-template-columns:minmax(0,1fr) minmax(320px,420px);gap:52px;margin-top:56px;align-items:start}
.calc__head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:26px;flex-wrap:wrap}
.calc__head .lbl{font-family:var(--mono);font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.5)}
.calc__slider{display:flex;align-items:center;gap:14px}
.calc__slider span{font-size:13px;color:rgba(255,255,255,.55)}
.calc__slider output{font-family:var(--mono);font-size:14px;font-weight:600;color:var(--yellow);min-width:34px;text-align:right}
input[type=range]{width:min(190px,44vw);height:28px;accent-color:var(--yellow);cursor:pointer}
.bars{display:flex;flex-direction:column;gap:14px}
.bar__top{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:7px}
.bar__top b{font-size:15px;font-weight:500;color:rgba(255,255,255,.72)}
.bar__top i{font-style:normal;font-family:var(--mono);font-size:14px;font-variant-numeric:tabular-nums;color:rgba(255,255,255,.72)}
.bar__rail{height:12px;background:rgba(255,255,255,.07);border-radius:4px;overflow:hidden}
.bar__fill{display:block;height:100%;width:0;background:rgba(255,255,255,.26);border-radius:4px;transition:width .7s var(--ease)}
.bar__note{font-size:12.5px;color:rgba(255,255,255,.62);margin-top:6px}
.bar--total .bar__rail{height:22px}
.bar--total .bar__fill{background:var(--red)}
.bar--total .bar__top b,.bar--total .bar__top i{color:#fff}
.bar--us .bar__rail{height:22px}
.bar--us .bar__fill{background:var(--yellow)}
.bar--us .bar__top b,.bar--us .bar__top i{color:var(--yellow)}
.calc__fine{margin-top:24px;font-size:12px;line-height:1.6;color:rgba(255,255,255,.72);max-width:70ch}
.savings{background:var(--blue);border-radius:18px;padding:34px;position:relative;overflow:hidden}
.savings__v{font-size:clamp(32px,3.8vw,48px);font-weight:600;letter-spacing:-.045em;line-height:1;margin:10px 0 6px;color:#fff;font-variant-numeric:tabular-nums}
.savings__s{font-size:15px;color:#fff;margin-bottom:26px}
.savings__list{border-top:1px solid rgba(255,255,255,.24)}
.savings__list div{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:13px 0;border-bottom:1px solid rgba(255,255,255,.16);font-size:14px;color:rgba(255,255,255,.95)}
.savings__list b{color:#fff;font-weight:600;font-family:var(--mono)}
.savings .btn{margin-top:22px;width:100%;justify-content:center}

.matrix{margin-top:clamp(48px,7vw,76px);border:1px solid rgba(255,255,255,.18);border-radius:16px;overflow:hidden}
.matrix__head,.matrix__row{display:grid;grid-template-columns:minmax(200px,1.6fr) repeat(5,minmax(92px,1fr))}
.matrix__head{background:rgba(255,255,255,.05)}
.matrix__head .lead{padding:20px 24px;font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.55)}
.matrix__head .col{padding:18px 12px;text-align:center;font-size:13px;font-weight:600;color:rgba(255,255,255,.75);border-left:1px solid rgba(255,255,255,.12)}
.matrix__head .col span{display:block;font-weight:400;font-size:11px;color:rgba(255,255,255,.62);margin-top:3px}
.matrix__head .col--us{color:var(--yellow)}
.matrix__row{border-top:1px solid rgba(255,255,255,.12);transition:background .18s var(--ease)}
.matrix__row .lead{padding:19px 24px;font-size:14.5px;color:rgba(255,255,255,.88);transition:color .18s var(--ease)}
.matrix__row .c{padding:19px 12px;text-align:center;font-size:15px;border-left:1px solid rgba(255,255,255,.12);color:rgba(255,255,255,.66);transition:color .18s var(--ease),background .18s var(--ease)}

/* Three states, three colours, so a row can be read without going back to the
   legend: green is in the plan, amber costs extra, red is not offered at all.

   These are .matrix__row-prefixed on purpose. They used to be bare .c--y /
   .c--us / .c--n, which lose to .matrix__row .c on specificity — two classes
   against one — so every dot in the table rendered the same grey and the
   legend named three colours that were not on screen. */
.matrix__row .c--y{color:var(--ok-lite)}
.matrix__row .c--p{color:var(--warn-lite)}
.matrix__row .c--n{color:var(--bad-lite)}
.matrix__row .c--us{color:var(--yellow);background:rgba(225,235,38,.07)}

/* Hover: the row a cursor is on lifts out of the table. Ten rows of five
   near-identical glyphs is exactly the kind of grid where the eye loses its
   line between the label on the left and the mark on the right. */

@media (hover: hover) and (pointer: fine){.matrix__row:hover{background:rgba(255,255,255,.055)}}

@media (hover: hover) and (pointer: fine){.matrix__row:hover .lead{color:#fff}}

@media (hover: hover) and (pointer: fine){.matrix__row:hover .c{color:rgba(255,255,255,.82)}}

@media (hover: hover) and (pointer: fine){.matrix__row:hover .c--y{color:#7BE8AA}}

@media (hover: hover) and (pointer: fine){.matrix__row:hover .c--p{color:#FFC969}}

@media (hover: hover) and (pointer: fine){.matrix__row:hover .c--n{color:#FFA7A7}}

@media (hover: hover) and (pointer: fine){.matrix__row:hover .c--us{color:var(--yellow);background:rgba(225,235,38,.13)}}
@media(hover:none){ .matrix__row:hover{background:none} }
.matrix__legend{margin-top:18px;font-size:13px;color:rgba(255,255,255,.62)}
/* The legend takes its colours from the same four variables the cells do, so
   it cannot drift from the table it explains — which is how it ended up
   naming a yellow dot for "included" that the table never drew. */
.matrix__legend .lg{font-weight:400;font-style:normal}
.matrix__legend .lg--y{color:var(--ok-lite)}
.matrix__legend .lg--p{color:var(--warn-lite)}
.matrix__legend .lg--n{color:var(--bad-lite)}
.matrix__legend .lg--us{color:var(--yellow)}

/* ==========================================================================
   Security
   ========================================================================== */
.sec{position:relative;display:grid;grid-template-columns:minmax(0,1fr) minmax(300px,460px);gap:52px;align-items:start}
.sec__hatch{position:absolute;inset:0;background-image:repeating-linear-gradient(135deg,rgba(30,30,30,.055) 0 2px,transparent 2px 11px);pointer-events:none}
.badges{display:flex;flex-wrap:wrap;gap:10px;margin-top:32px}
.badges span{background:var(--ink);color:#fff;font-family:var(--mono);font-size:11.5px;font-weight:500;letter-spacing:.06em;text-transform:uppercase;padding:9px 15px;border-radius:999px}
.seclist{background:var(--ink);border-radius:16px;padding:8px}
.seclist div{padding:18px 20px;border-bottom:1px solid rgba(255,255,255,.1)}
.seclist div:last-child{border-bottom:0}
.seclist b{font-size:14.5px;font-weight:600;color:#fff;display:flex;align-items:center;gap:10px;margin-bottom:6px}
.seclist b i{width:6px;height:6px;border-radius:50%;background:var(--yellow);flex:none;display:block}
.seclist p{font-size:13.5px;line-height:1.55;color:rgba(255,255,255,.58);padding-left:16px}

/* ==========================================================================
   Pricing
   ========================================================================== */
.prices{display:grid;grid-template-columns:repeat(auto-fit,minmax(290px,1fr));gap:20px;align-items:stretch}
.price{background:var(--white);border:1px solid var(--ink-14);border-radius:16px;padding:32px;display:flex;flex-direction:column}
.price__k{font-family:var(--mono);font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-62)}
.price__v{font-size:38px;font-weight:600;letter-spacing:-.04em;margin:14px 0 4px;display:flex;align-items:baseline;gap:8px}
.price__v small{font-size:17px;font-weight:400;color:var(--ink-55)}
.price p{font-size:14px;line-height:1.6;color:var(--ink-62);flex:1}
.price--hero{background:var(--ink);color:#fff;border-color:var(--ink);position:relative;overflow:hidden}
.price--hero .price__k{color:rgba(255,255,255,.55)}
.price--hero .price__v{color:#fff}
.price--hero .price__v small{color:rgba(255,255,255,.55)}
.price--hero p{color:rgba(255,255,255,.6)}
.price__flag{position:absolute;top:18px;right:18px;background:var(--yellow);color:var(--ink);font-family:var(--mono);font-size:10.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;padding:5px 10px;border-radius:999px}
.price .btn{margin-top:22px;justify-content:center;width:100%}
.price__blue{color:var(--blue)}

/* ==========================================================================
   FAQ accordion
   Two INDEPENDENT columns, not a grid: in a grid, opening one answer stretches
   every cell in that row, so the neighbours grow tall and empty. Each column
   is its own stack, so an open answer only moves the items below it.
   ========================================================================== */
.faq{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px;align-items:start}
.faq__col{background:var(--white);border:1px solid var(--ink-14);border-radius:16px;overflow:hidden}
.faq__item{border-bottom:1px solid var(--ink-12)}
.faq__col .faq__item:last-child{border-bottom:0}
.faq__q{
  width:100%;background:none;border:0;text-align:left;padding:26px 24px;display:flex;
  align-items:flex-start;gap:14px;cursor:pointer;font-size:16px;font-weight:600;
  letter-spacing:-.018em;line-height:1.35;color:var(--ink);
  transition:background .25s var(--ease);
}

@media (hover: hover) and (pointer: fine){.faq__q:hover{background:rgba(30,30,30,.035)}}
.faq__item.is-open .faq__q{background:rgba(38,99,235,.045)}
.faq__n{
  font-family:var(--mono);font-size:11px;font-weight:500;letter-spacing:.1em;color:var(--ink-55);
  flex:none;padding-top:4px;width:20px;transition:color .25s var(--ease);
}
.faq__item.is-open .faq__n{color:var(--blue)}
.faq__t{flex:1;min-width:0}
.faq__q i{
  font-style:normal;font-family:var(--mono);font-size:17px;line-height:1;color:var(--blue);
  flex:none;width:26px;height:26px;border-radius:50%;border:1px solid rgba(38,99,235,.3);
  display:flex;align-items:center;justify-content:center;
  transition:transform .4s var(--ease),background .3s var(--ease),color .3s var(--ease);
}
.faq__item.is-open .faq__q i{transform:rotate(135deg);background:var(--blue);color:#fff;border-color:var(--blue)}
/* Opened by animating a grid row from 0fr to 1fr rather than by animating
   max-height. max-height meant JavaScript had to measure the answer, pin a
   pixel height, guard against re-pinning mid-transition and recompute the
   lot on every resize and font swap — and it relayouts on each frame. The
   row fraction needs none of that and the browser knows the real height.
   Where the fraction is not animatable the panel simply opens at once. */
.faq__a{display:grid;grid-template-rows:0fr;overflow:hidden;opacity:0;
  transition:grid-template-rows .45s var(--ease),opacity .3s var(--ease)}
/* The clipping layer. The padding lives inside it, so at 0fr the row really
   is zero — padding on a direct grid child cannot collapse and left a 22px
   gap under every closed question. */
.faq__aBody{overflow:hidden;min-height:0}
.faq__item.is-open .faq__a{grid-template-rows:1fr;opacity:1}
.faq__a p{font-size:14.5px;line-height:1.65;color:rgba(30,30,30,.64);padding:0 22px 22px 56px}
@media(max-width:860px){
  .faq{grid-template-columns:minmax(0,1fr)}
  .faq__a p{padding-left:22px}
}

/* ==========================================================================
   Testimonial / proof strip
   ========================================================================== */
.quotes{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:20px}
.quote{background:var(--white);border:1px solid var(--ink-14);border-radius:16px;padding:30px;display:flex;flex-direction:column;gap:18px}
.quote p{font-size:16px;line-height:1.55;letter-spacing:-.01em;flex:1}
.quote p b{background:linear-gradient(transparent 62%,rgba(225,235,38,.85) 62%);font-weight:600}
.quote footer{display:flex;align-items:center;gap:12px;border-top:1px solid var(--ink-10);padding-top:16px}
.quote footer .av{width:36px;height:36px;font-size:12px}
.quote footer b{display:block;font-size:14px;font-weight:600}
.quote footer span{font-size:12.5px;color:var(--ink-62)}

/* big number / stat band */

/* ==========================================================================
   CTA
   ========================================================================== */
.cta{
  max-width:var(--max);margin:0 auto;background:var(--blue);border-radius:22px;
  padding:clamp(48px,7vw,110px) clamp(32px,5vw,72px);text-align:center;position:relative;overflow:hidden;
}
.cta__grid{
  position:absolute;inset:0;pointer-events:none;
  background-image:linear-gradient(rgba(255,255,255,.07) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.07) 1px,transparent 1px);
  background-size:56px 56px;
}
.cta h2{font-size:clamp(28px,4vw,54px);line-height:.96;letter-spacing:-.045em;font-weight:600;color:#fff;max-width:17ch;margin:0 auto}
.cta p{margin:26px auto 0;max-width:52ch;font-size:16px;line-height:1.65;color:rgba(255,255,255,.82)}
.cta__row{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;margin-top:38px}
.cta__fine{margin-top:20px;font-family:var(--mono);font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.62)}

.splitcta{
  max-width:var(--max);margin:0 auto;background:var(--yellow);border-radius:var(--radius);
  padding:clamp(40px,6vw,80px);display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));
  gap:40px;align-items:center;
}
.splitcta h2{max-width:15ch}
.splitcta p{margin-top:18px;max-width:46ch;font-size:14px;line-height:1.65;color:var(--ink-72)}
.splitcta__btns{display:flex;flex-wrap:wrap;gap:12px;justify-content:flex-end}

/* ==========================================================================
   Footer
   ========================================================================== */
/* Everything in the footer is drawn on the brand red, where the page's
   normal ink is 3.84:1 — below AA. The red is the brand fill and does not
   move, so the ink tokens are rescoped here instead, once, rather than
   overriding a dozen individual rules that each say var(--ink). */
.footer{
  padding:0 clamp(10px,2.4vw,18px) clamp(10px,2.4vw,18px);
  --ink:#0A0A0A;
  --ink-72:rgba(10,10,10,.95);
  --ink-68:rgba(10,10,10,.95);
  --ink-65:rgba(10,10,10,.95);
  --ink-62:rgba(10,10,10,.95);
  /* Solid, not dimmed: at .92 the placeholder links read 4.37:1. The dotted
     underline is what says "not a link yet" — the opacity was saying it a
     second time, and paying for it in legibility. */
  --ink-55:#0A0A0A;
  --ink-18:rgba(10,10,10,.34);
}
.footer__in{
  background:var(--red);border-radius:var(--radius);padding:clamp(30px,5vw,52px) clamp(20px,4vw,48px) 26px;
  position:relative;overflow:hidden;color:var(--ink);
}
.footer__blob{position:absolute;right:-18%;top:-30%;width:78%;aspect-ratio:1;border-radius:50%;background:rgba(30,30,30,.05)}
.footer__rel{position:relative}
.footer__top{display:flex;align-items:flex-start;justify-content:space-between;gap:24px}
.footer__top div{font-size:clamp(19px,2vw,28px);line-height:1.1;letter-spacing:-.02em;font-weight:400;text-transform:uppercase}
.footer__up{width:50px;height:50px;border-radius:12px;background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;font-size:19px;flex:none}

@media (hover: hover) and (pointer: fine){.footer__up:hover{background:var(--blue);color:#fff}}
.footer__grid{display:grid;grid-template-columns:minmax(220px,1fr) minmax(300px,1.5fr) minmax(220px,1fr);gap:40px;margin-top:clamp(40px,7vw,120px)}
.footer__h{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;margin-bottom:20px}
.footer__p{font-size:13.5px;line-height:1.75;letter-spacing:.03em;text-transform:uppercase;color:var(--ink-on-red)}
.regions{display:flex;flex-wrap:wrap;gap:7px;margin-top:20px}
.regions span{border:1px solid rgba(30,30,30,.4);border-radius:999px;padding:5px 12px;font-size:11.5px;letter-spacing:.06em;text-transform:uppercase}
.footer__cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:18px 24px}
.footer__cols div{display:flex;flex-direction:column;gap:11px}
.footer__cols a{font-size:13.5px;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-on-red)}

@media (hover: hover) and (pointer: fine){.footer__cols a:hover{color:#fff}}
.footer__cols a[data-todo],.footer__legal a[data-todo]{opacity:.78}
.footer__word{
  margin-top:clamp(24px,4vw,56px);font-size:clamp(40px,16.4vw,268px);line-height:.8;letter-spacing:-.05em;
  font-weight:700;color:var(--ink);white-space:nowrap;text-align:center;
}
.footer__legal{
  margin-top:22px;border:1px solid rgba(30,30,30,.55);border-radius:12px;padding:16px 22px;
  display:flex;flex-wrap:wrap;gap:16px;align-items:center;justify-content:space-between;
}
.footer__legal .c{display:flex;flex-wrap:wrap;align-items:baseline;gap:20px}
.footer__legal .c b{font-size:13px;font-weight:700;letter-spacing:.05em;text-transform:uppercase}
.footer__legal .c span{font-size:12px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-on-red)}
.footer__legal nav{display:flex;gap:18px;font-size:13px;letter-spacing:.05em;text-transform:uppercase}
.footer__legal nav a{color:var(--ink-on-red)}

@media (hover: hover) and (pointer: fine){.footer__legal nav a:hover{color:#fff}}

/* ==========================================================================
   Tutorials page
   ========================================================================== */
.split2{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(280px,.65fr);gap:48px;align-items:end}
.feature-video{background:var(--ink);border-radius:var(--radius);overflow:hidden;display:grid;grid-template-columns:minmax(0,1.5fr) minmax(300px,.9fr)}
.vidslot{
  position:relative;aspect-ratio:16/9;background:linear-gradient(135deg,#16181D,#232733);
  display:flex;align-items:center;justify-content:center;border-right:1px solid rgba(255,255,255,.1);
}
.vidslot__grid{position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,.05) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.05) 1px,transparent 1px);background-size:44px 44px}
.vidslot__c{position:relative;display:flex;flex-direction:column;align-items:center;gap:18px}
.play{
  width:84px;height:84px;border-radius:50%;background:var(--yellow);display:flex;align-items:center;
  justify-content:center;font-size:26px;color:var(--ink);border:0;cursor:pointer;
  transition:transform .35s var(--ease),box-shadow .35s;
}

@media (hover: hover) and (pointer: fine){.play:hover{transform:scale(1.08);box-shadow:0 0 0 18px rgba(225,235,38,.14)}}
.vidslot__n{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:rgba(255,255,255,.5)}
.vidslot__time{position:absolute;bottom:16px;right:18px;font-family:var(--mono);font-size:12px;color:rgba(255,255,255,.6);background:rgba(0,0,0,.4);padding:5px 10px;border-radius:6px}
.feature-video__side{padding:40px 38px;display:flex;flex-direction:column;justify-content:center;gap:16px}
.feature-video__side h2{font-size:clamp(21px,2vw,28px);line-height:1.08;letter-spacing:-.032em;font-weight:600;color:#fff}
.feature-video__side p{font-size:14px;line-height:1.65;color:rgba(255,255,255,.6)}
.tagpill{align-self:flex-start;background:var(--blue);color:#fff;font-family:var(--mono);font-size:10.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;padding:6px 12px;border-radius:999px}
.chips--dark .chip{border-color:rgba(255,255,255,.22);background:transparent;color:rgba(255,255,255,.7)}

.filters{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:20px;padding-bottom:22px;border-bottom:1px solid var(--ink-16)}
.filters__btns{display:flex;flex-wrap:wrap;gap:8px}
.fbtn{border:1px solid var(--ink-18);background:#fff;color:var(--ink);height:44px;padding:0 18px;border-radius:999px;font-size:14.5px;font-weight:500;cursor:pointer;transition:all .25s var(--ease)}

@media (hover: hover) and (pointer: fine){.fbtn:hover{border-color:var(--ink)}}
.fbtn.is-on{background:var(--ink);color:#fff;border-color:var(--ink)}
.vidgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(330px,1fr));gap:24px;padding-top:36px}
.vid{background:#fff;border:1px solid var(--ink-14);border-radius:16px;overflow:hidden;display:flex;flex-direction:column}

@media (hover: hover) and (pointer: fine){.vid:hover{border-color:var(--ink);transform:translateY(-4px);box-shadow:0 26px 50px -34px rgba(30,30,30,.5)}}
.vid__thumb{position:relative;aspect-ratio:16/9;display:flex;align-items:center;justify-content:center;border-bottom:1px solid var(--ink-12)}
.vid__thumb::before{content:"";position:absolute;inset:0;background-image:repeating-linear-gradient(135deg,rgba(30,30,30,.05) 0 2px,transparent 2px 10px)}
.vid__play{position:relative;width:56px;height:56px;border-radius:50%;background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;font-size:17px;transition:transform .3s var(--ease)}

@media (hover: hover) and (pointer: fine){.vid:hover .vid__play{transform:scale(1.12);background:var(--blue)}}
.vid__slot{position:absolute;bottom:10px;left:12px;font-family:var(--mono);font-size:10.5px;letter-spacing:.08em;color:var(--ink-62)}
.vid__dur{position:absolute;bottom:10px;right:12px;font-family:var(--mono);font-size:11.5px;background:var(--ink);color:#fff;padding:3px 8px;border-radius:5px}
.vid__body{padding:22px;display:flex;flex-direction:column;gap:10px;flex:1}
.vid__meta{display:flex;align-items:center;justify-content:space-between;gap:10px;font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase}
.vid__meta b{color:var(--blue);font-weight:400}
.vid__meta span{color:rgba(30,30,30,.38)}
.vid h3{font-size:17px;font-weight:600;letter-spacing:-.018em;line-height:1.2}
.vid p{font-size:14px;line-height:1.6;color:var(--ink-62);flex:1}
.vid__chaps{display:flex;flex-wrap:wrap;gap:6px;padding-top:12px;border-top:1px solid var(--ink-10)}
.vid__chaps span{font-size:12px;color:var(--ink-55);background:var(--surface);border-radius:6px;padding:4px 9px}
/*
 * A chapter that covers the employee phone app, which is not built.
 *
 * The page listed four of these as though they were recorded and waiting.
 * They are real planned chapters, so deleting them would understate the plan —
 * but presenting them as available is a claim the product cannot meet, and the
 * first person to click one finds that out the hard way. Marked instead, in
 * words rather than only in colour, so the distinction survives greyscale,
 * a screen reader and a colour-blind reader alike.
 */
.vid__chaps span.is-soon{color:var(--ink-40,var(--ink-55));background:transparent;border:1px dashed var(--ink-20,var(--ink-10))}
.vid__chaps span.is-soon::after{content:" · soon";font-weight:600;letter-spacing:.02em}
.is-hidden{display:none!important}

.path{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:1px;background:rgba(255,255,255,.16);margin-top:48px;border:1px solid rgba(255,255,255,.16)}
.path div{background:var(--ink);padding:30px 26px;display:flex;flex-direction:column;gap:12px;min-height:210px}
.path b{font-family:var(--mono);font-size:12px;color:var(--yellow);letter-spacing:.1em;font-weight:400}
.path h3{font-size:17px;font-weight:600;letter-spacing:-.018em;color:#fff}
.path p{font-size:14px;line-height:1.6;color:rgba(255,255,255,.58);flex:1}
.path em{font-style:normal;font-size:12.5px;color:rgba(255,255,255,.62);font-family:var(--mono)}

/* ==========================================================================
   About page
   ========================================================================== */
.mission__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:36px;margin-top:52px;max-width:1000px}
.mission__grid p{font-size:16px;line-height:1.658;color:var(--ink-72)}
.principles .hcell{min-height:250px;gap:14px}

@media (hover: hover) and (pointer: fine){.principles .hcell:hover{background:#fff;color:var(--ink);transform:translateY(-3px)}}
.principles .hcell h3{font-size:18px;line-height:1.16}
.principles .hcell p{color:var(--ink-62);opacity:1;flex:1}
.principles .hcell em{font-style:italic;font-size:13px;color:var(--blue)}
.timeline{margin-top:56px}
.tl{display:grid;grid-template-columns:minmax(120px,160px) 24px minmax(0,1fr);gap:22px;align-items:start;padding-bottom:34px}
.tl__date{font-family:var(--mono);font-size:13px;letter-spacing:.08em;color:rgba(255,255,255,.45);padding-top:2px}
.tl__line{position:relative;display:flex;justify-content:center;padding-top:6px}
.tl__line i{width:11px;height:11px;border-radius:50%;background:rgba(255,255,255,.4);flex:none;z-index:1;display:block}
.tl__line::after{content:"";position:absolute;top:16px;bottom:-40px;width:1px;background:rgba(255,255,255,.16)}
.tl:last-child .tl__line::after{display:none}
.tl h3{font-size:17px;font-weight:600;letter-spacing:-.018em;color:#fff;margin-bottom:7px}
.tl p{font-size:14px;line-height:1.65;color:rgba(255,255,255,.58);max-width:62ch}
.tl--now .tl__date{color:var(--yellow)}
.tl--now .tl__line i{background:var(--yellow)}
.tl--next .tl__date{color:var(--blue)}
.tl--next .tl__line i{background:var(--blue)}

/* ==========================================================================
   Responsive
   ========================================================================== */
@media(max-width:1180px) and (min-width:901px){
  .mock__body{grid-template-columns:180px minmax(0,1fr)}
}
@media(max-width:1024px){
  .navpill{display:none}
  .menubtn{display:inline-flex}
}
@media(max-width:900px){
  .split2,.calc,.sec,.feature-video{grid-template-columns:minmax(0,1fr)!important;gap:32px!important}
  .scrollx{overflow-x:auto}
  .scrollx>*{min-width:720px}
  .appmock{overflow-x:auto}
  .appmock>*{min-width:940px}
  /* Tour unpins: the filmstrip becomes a plain vertical stack of screenshots,
     each with its caption below it. Screens keep their own horizontal scroll. */
  .tour{height:auto}
  .tour__pin{position:static;height:auto;overflow:visible;padding:clamp(48px,7vw,72px) 0}
  .tour__head{padding:0 var(--pad)}
  .strip{position:static;height:auto;margin-top:30px}
  .strip__track{
    position:static;height:auto;flex-direction:column;gap:clamp(30px,6vw,46px);
    padding:0 var(--pad);transform:none!important;
  }
  .slide{width:100%;height:auto;opacity:1!important}
  .slide__ghost{display:none}
  .slide__stage{height:auto;transform:none!important}
  .mock--slide{height:auto}
  .mock__screen{-webkit-mask-image:none;mask-image:none;overflow-x:auto;-webkit-overflow-scrolling:touch}
  .mock__screen>.screen{min-width:940px}
  .plate{
    position:static;width:auto;margin-top:14px;box-shadow:none;
    transform:none!important;opacity:1!important;
  }
  .rail{display:none}
  .mock__body{grid-template-columns:minmax(0,1fr)}
  .mock__side{display:none}
  .mock__kpis{grid-template-columns:repeat(2,minmax(0,1fr))}
  .splitcta__btns{justify-content:flex-start}
  .feature-video .vidslot{border-right:0;border-bottom:1px solid rgba(255,255,255,.1)}
}
@media(max-width:600px){
  /* the full label does not fit beside the logo and the menu button */
  .btn-join__wide{display:none}
  .btn-join__narrow{display:inline}
  .btn-join{padding:12px 16px;font-size:13px}
  .header{gap:10px;padding-left:16px;padding-right:16px}
  .logo{padding:15px 15px;font-size:15px}   /* 46px tall — a real tap target */
  .menubtn{width:46px;height:46px}
}
@media(max-width:720px){
  /* premium mobile rhythm: tighter headings, roomier blocks, full-width controls */
  .hero h1{line-height:1.02;letter-spacing:-.038em}
  .h-xl{font-size:clamp(36px,9vw,82px)}
  .h-lg{font-size:clamp(34px,8.6vw,72px)}
  .h-md{font-size:clamp(27px,7.4vw,46px);line-height:1.04}
  .h-sm{font-size:clamp(24px,6.6vw,40px);line-height:1.06}
  .hero__sub{font-size:16px;line-height:1.62;max-width:34ch}
  .lede{font-size:15.5px;line-height:1.68}
  :root{--sec-y:clamp(72px,12vw,116px)}
  .btn{height:50px;font-size:15.5px;padding:0 20px}
  .btn--lg{height:54px;font-size:16px}
  .cards{gap:16px}
  .card{min-height:0;padding:24px 22px}
  .hcell{min-height:0;padding:26px 22px}
  .prices{gap:16px}
  .price{padding:26px 22px}
  .quotes{gap:16px}
  .quote{padding:26px 22px}
  .eyebrow{margin-bottom:12px}
  .splitcta{padding:32px 24px;gap:26px}
  .cta{padding:48px 24px;border-radius:18px}
  .cta__row{gap:10px}
  .footer__legal{padding:16px}
  .pill{white-space:normal;border-radius:16px;padding:8px 10px 8px 14px;font-size:12px;line-height:1.35;text-align:left;gap:8px}
  .pill .tag{flex:none}
  .footer__grid{grid-template-columns:minmax(0,1fr);gap:30px}
  .tl{grid-template-columns:minmax(0,1fr);gap:8px}
  .tl__line{display:none}
  .metrics{grid-template-columns:repeat(2,minmax(0,1fr))}
  .hero__cta .btn,.cta__row .btn{width:100%;justify-content:center}
  .filters{flex-direction:column;align-items:flex-start}
}
@media(max-width:520px){
  :root{--headerH:72px}
  .vidgrid{grid-template-columns:minmax(0,1fr)}
  .footer__legal{flex-direction:column;align-items:flex-start}
}

/* ==========================================================================
   Reduced motion
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
  [data-reveal]{opacity:1;transform:none}
  .split .word>span{transform:none}
  [data-clip]{clip-path:none}
  .loader{display:none}
  .grain{display:none}
  /* No horizontal remap: the strip falls back to a readable vertical stack. */
  .tour{height:auto!important}
  .tour__pin{position:static;height:auto;overflow:visible}
  .strip{position:static;height:auto}
  .strip__track{position:static;height:auto;flex-direction:column;gap:40px;padding:0 var(--pad);transform:none!important}
  .slide{width:100%;height:auto;opacity:1!important}
  .slide__stage{height:auto;transform:none!important}
  .mock--slide{height:auto}
  .mock__screen{-webkit-mask-image:none;mask-image:none;overflow-x:auto}
  .plate{position:static;width:auto;margin-top:14px;transform:none!important;opacity:1!important}
  .slide__ghost{display:none}
  .rail{display:none}
}

/* Print */
@media print{
  .header,.stickycta,.grain,.progress,.cursor-layer,.cursor-arrow,.cursor-tag,.loader{display:none!important}
  body{background:#fff}
}

/* ==========================================================================
   Atmosphere — the seamless white-majority sky
   ==========================================================================
   Studied from bombon.rs. Three techniques carried across:

   1. WHITE-MAJORITY GROUND WITH A BRAND TINT. Their page is #ECE7F2 — a
      near-white washed with their brand lavender — never a saturated fill.
      Ours is white washed with --blue. The hero keeps its blue sky; from the
      hero down the page is white with blue in the air, not on it.

   2. WELD STRIPS INSTEAD OF RULES. Every section boundary of theirs is a
      gradient band fading tint -> transparent, so no seam is ever visible.
      Our 1px --ink-12 rules were doing the exact opposite.
   ========================================================================== */
:root{
  /* Lavender-blue, not sky-blue: hue ~238 with very low saturation, so the
     ground reads as a tinted white rather than as a coloured page. White still
     carries every surface that holds content. */
  --lav:122,138,240;  /* the one wash colour, as an rgb triplet */
  --sky-1:#FBFBFE;   /* faintest — barely off white */
  --sky-2:#F3F3FC;   /* the working ground tint */
  --sky-3:#E8E9F8;   /* deepest end of a card or panel gradient */
  --sky-4:#DADCF3;   /* deepest the page ever goes */
}

/* The ground. White dominates; the blue is a wash that drifts in and out down
   the page so no two screens are quite the same flat colour. */
body{
  background:var(--sky-1);
  background-image:
    radial-gradient(ellipse 90% 34% at 82% 6%,rgba(var(--lav),.13),transparent 62%),
    radial-gradient(ellipse 76% 26% at 10% 34%,rgba(var(--lav),.10),transparent 64%),
    radial-gradient(ellipse 92% 30% at 88% 62%,rgba(var(--lav),.12),transparent 64%),
    radial-gradient(ellipse 80% 26% at 16% 88%,rgba(var(--lav),.09),transparent 66%);
  background-attachment:fixed;
}

/* ---- Section boundaries ----------------------------------------------------
   There is no weld element any more. A weld was a section-local tinted band
   (--sky-3) laid over the seam, and it had two problems the page is better off
   without: its ramp ends were still visible as soft bars on a near-white
   ground, and once it was given negative margins to stop it adding height, it
   painted 46px of pale grey straight over the top of the black compare section.
   The body wash is one fixed, page-wide gradient, so a seam needs nothing drawn
   on it at all — the ground is already continuous across it.
   ========================================================================== */

/* ---- Four gradient styles, so the blue never repeats itself ---------------
   1. tide   — a long vertical deepening across a whole section
   2. bloom  — an off-centre radial, the light source of the section
   3. tile   — soft two-stop fills on cards (bombon's category tiles)
   4. beam   — a wide low-angle linear sweep */
.g-tide{background-image:linear-gradient(180deg,transparent 0%,var(--sky-2) 38%,var(--sky-3) 78%,transparent 100%)}
.g-bloom{position:relative}
.g-bloom::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  /* Every ellipse terminates INSIDE the box: 22%±19% = 3..41, 74%±17% = 57..91.
     The old values (18%±31% and 82%±28%) ran to -13% and 110%, so the layer was
     clipped at the box edge while still carrying colour — that hard cut was the
     line visible under the FAQ. */
  background:
    radial-gradient(ellipse 58% 38% at 78% 22%,rgba(122,138,240,.13),transparent 70%),
    radial-gradient(ellipse 64% 34% at 12% 74%,rgba(122,138,240,.10),transparent 72%);
  /* Belt and braces: fade the whole layer out at all four edges, so any future
     gradient that overshoots still cannot produce an edge. */
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 12%,#000 88%,transparent 100%);
  mask-image:linear-gradient(180deg,transparent 0,#000 12%,#000 88%,transparent 100%);
}
.g-tile{background-image:linear-gradient(152deg,#fff 0%,var(--sky-2) 58%,var(--sky-3) 100%)}
.g-beam{background-image:linear-gradient(104deg,transparent 0%,rgba(var(--lav),.09) 32%,rgba(var(--lav),.14) 54%,transparent 86%)}

/* ---- Zig-zag: two vertical axes instead of one ----------------------------
   Every section on this page started its title at the same x. Eight of those
   in a row is a column of type, and a column of type with no variation in it
   is read as one undifferentiated block — which is most of what "cluttered"
   means when the spacing is already generous.

   So alternating sections step their TITLE BLOCK in, and only the title
   block: the content beneath keeps the full column. That is the whole trick.
   Moving the content too would give the page two layouts; moving just the
   label and the headline gives it a rhythm, and the eye gets a reason to
   travel rather than scanning one straight edge from top to bottom.

   Off below 900px, where a column this narrow has no room to give away.
   ========================================================================== */
.stagger > .wrap > .eyebrow,
.stagger > .wrap > h2,
.stagger > .wrap > .lede,
.stagger > .wrap > p{
  margin-left:clamp(0px,13vw,200px);
}
@media(max-width:900px){
  .stagger > .wrap > .eyebrow,
  .stagger > .wrap > h2,
  .stagger > .wrap > .lede,
  .stagger > .wrap > p{margin-left:0}
}

/* Sections stop cutting themselves off from each other. */
.section,.section--tight{position:relative;border-bottom:0!important}
.skyzone .section{border-bottom:0!important}

/* ---- Scroll-scrubbed heading: type sets itself, letter by letter ----------
   Each glyph is hinged on its own baseline and swings up into place behind the
   mask of its word box, in a wave that runs along the reading order. Driven by
   the shared rAF, not a transition, so it tracks the scrubbing both ways.

   This replaced a random scatter-and-blur. That version threw every letter to
   a seeded offset with up to 9px of blur, so a heading mid-scroll was a pile
   of overlapping characters — unreadable exactly while the reader was trying
   to read it, and blur on live text is the most expensive thing on the page.
   Here the word never breaks: glyphs only ever travel vertically, inside their
   own word, and the line stays legible the whole way up. */
.scrub{display:block}
.scrub .chw{
  display:inline-block;white-space:nowrap;
  /* The mask each glyph rises out of. The padding buys room for descenders and
     the matching negative margin gives that room back to the layout, so adding
     the mask does not move the text by a single pixel. */
  overflow:hidden;vertical-align:bottom;
  /* Measured, not guessed: a descender ('y' at the hero size) reached 9.93px
     below the box against .22em = 10.12px of room — 0.19px of clearance. .30em
     gives it real headroom at every clamp size. */
  padding:.18em 0 .30em;margin:-.18em 0 -.30em;
}
.scrub .ch{
  display:inline-block;white-space:pre;
  transform-origin:50% 100%;      /* the hinge: each glyph's own baseline */
  will-change:transform;
  backface-visibility:hidden;
}
@media(max-width:760px){
  /* a fixed background on iOS Safari repaints the whole page per frame */
  body{background-attachment:scroll}
}

/* ==========================================================================
   Phone — accessibility corrections

   Measured at 375x812 against WCAG 2.1 AA, not guessed at. Every number below
   replaces one that was audited and failed.
   ========================================================================== */
@media(max-width:760px){

  /* ---- 1. The hero, which fails on a phone for a reason that does not exist
     on a desktop: the hero is TALLER relative to the sky zone, so its text sits
     further down a gradient that is getting lighter, and white type runs out of
     contrast on the way. Measured: sub-heading 3.31:1, trust line 2.37:1,
     both against 4.5 required.

     The fix is the ground, not the type — hold the dark blue further down the
     zone so the text keeps the background it was designed against. Same
     colours, same order, later stops. */
  .skyzone{
    background:linear-gradient(180deg,
      #175FD2 0%,#2159CF 24%,#2670DE 44%,#4C95EE 64%,
      #77B2F3 76%,#A8CDF8 85%,#C6DCF9 90%,
      rgba(220,232,251,.88) 93.5%,
      rgba(234,240,252,.62) 96%,
      rgba(244,246,253,.30) 98%,
      rgba(251,251,254,0) 100%);
  }
  /* and stop spending contrast on transparency that buys nothing at this size */
  .hero__sub{color:#fff}
  .skyzone .hero__sub{color:rgba(255,255,255,.97)}
  /* pure white, not 94%: at this size every percent of transparency is
     contrast spent on nothing anybody can see. */
  .skyzone .hero__trust{color:#fff;font-size:12.5px}

  /* ---- 2. The secondary hero button was LIGHTENING its background on a light
     blue, which is the wrong direction: white text needs something to sit on.
     A dark veil gives it a base and keeps it obviously secondary. */
  .skyzone .btn--ghost-dark,.skyzone .btn--ghost{
    background:rgba(9,28,74,.42);border-color:rgba(255,255,255,.72);color:#fff;
  }

  /* ---- 3. Touch targets. WCAG 2.5.5 asks for 44x44; these measured 40–42.
     Inline links inside a sentence are exempt and are left alone — padding
     them to 44 would space the prose out like a list. */
  .mobilepanel a{min-height:50px;display:flex;align-items:center}

  /* ---- The trial button leaves the header on a phone.

     Three things were competing for 375px of header — a logo, a yellow button
     and a hamburger — and the button is the widest of them. It moves into the
     menu, where it already had an entry.

     But it cannot go in as the seventh grey link in a list, or the one thing
     the site is for becomes the least visible item on the screen. It is the
     same yellow button it is everywhere else, held apart from the navigation
     by a rule, so the menu reads as "here is where you can go" and then
     "here is what you came to do". */
  /* Keyed on the hamburger, not the panel. The panel lives INSIDE the header
     on index/about/tutorials and immediately AFTER it on the four legal
     pages, so :has(.mobilepanel) matched three pages and silently missed
     four. The menu BUTTON is inside the header on every page that has a menu,
     and 404 — which has neither — keeps its trial button. */
  .header:has(.menubtn) .btn-join{display:none}

  .mobilepanel a[data-cta="menu_trial"],
  .mobilepanel a[href*="app.shiftwren.com"]{
    margin-top:12px;
    justify-content:center;
    min-height:50px;
    background:var(--yellow);
    color:var(--ink);
    border:1.5px solid var(--ink);
    border-radius:11px;
    font-size:15px;font-weight:700;letter-spacing:.04em;
  }
  .mobilepanel a[data-cta="menu_trial"]:hover,
  .mobilepanel a[href*="app.shiftwren.com"]:hover{background:#fff;color:var(--ink)}
  .stickycta .btn{height:44px}
  .stickycta__x{min-width:44px;min-height:44px;display:inline-flex;align-items:center;justify-content:center}
  a.sr-only:focus{min-height:44px;display:inline-flex;align-items:center}
  .footer__cols a,.footer__legal nav a{min-height:44px;display:inline-flex;align-items:center;padding:11px 0}

  /* The legal row burst its own container: .footer__legal is 299px wide and
     its first child measured 377px. A flex ITEM defaults to min-width:auto,
     which refuses to shrink below its content, so the row never wrapped — it
     just ran off the right edge, taking PRIVACY and COOKIES with it where
     nothing could scroll them back. Most visible on 404, which has no other
     navigation at all.

     min-width:0 lets the items shrink, at which point the flex-wrap they
     already carry does the job it was always meant to. */
  .footer__legal > *{min-width:0}

  /* On a phone this row was still trying to be a row: space-between across
     two wrapped children, each of which wrapped again inside itself, so the
     copyright, the email and the country list all broke at different points
     and the eye got three ragged left edges instead of one.

     It becomes a stack. One left edge, one gap between blocks, and each piece
     of information on its own line — which is what a footer on a 375px screen
     is: a list, not a layout. */
  .footer__legal{flex-direction:column;align-items:stretch;justify-content:flex-start;gap:20px}
  .footer__legal .c{flex-direction:column;align-items:flex-start;gap:5px}
  .footer__legal .c > *{display:block}
  /* "support@shiftwren.com · India · Canada · USA" is one string, so it broke
     wherever it ran out of room — leaving "· CANADA · USA" alone on a second
     line like an afterthought. balance splits it evenly instead, which is the
     difference between a wrapped line and a broken one. */
  .footer__legal .c span{text-wrap:balance;line-height:1.5}

  /* The links keep their 44px targets, so the spacing between rows has to
     come OUT of the gap or the two rows drift apart and stop reading as one
     block. row-gap 0, column-gap 18. */
  .footer__legal nav{flex-wrap:wrap;gap:0 18px;align-items:center}

  /* ---- 4. iOS Safari zooms the whole page when a focused field is under 16px.
     The form was 15px, so every tap on it punched the layout out of view and
     left the reader to pinch back. This is the entire fix. */
  input,select,textarea,.sel__btn{font-size:16px}   /* .fld fields are set at the end of this file, after their own rule */

  /* ---- 5. Nothing that is page text drops below 12px on a phone. The app
     mock keeps its own smaller type: it is a picture of a product, and scaling
     its insides would stop it looking like one. */
  .marquee__note,.mono-note,.hero__trust,.badge{font-size:12px}
  /* The uppercase mono labels are a deliberate device and they stay small —
     but 9.5–10.5px of letter-spaced caps on a phone held at arm's length is
     past legible and into decorative. A floor of 11.5px, which is the size
     the same device already uses elsewhere, so nothing changes proportionally.
     WCAG sets no minimum type size; this one is judgment, and the judgment is
     that a label nobody can read is not a label. */
  .metric__l,.ba__tag,.hcell__tag,.hcell__more,.numcard__label,.pricebox__flag,
  .pricebox__fine,.pfact__k,.tour__counter,.row__cost,.matrix__head .lead{font-size:11.5px}

  /* ---- 6. The tutorial player, which was the worst of it: every transport
     control measured 34x34 and the captions toggle 30x19, on the one screen
     where a person is most likely to be one-handed on a moving train.

     The bar is 303px wide and holds seven controls; making each one 44px of
     VISIBLE button needs 308px and would not fit. So the target grows and the
     button does not — a centred 44x44 pseudo-element over each control. WCAG
     2.5.5 measures the area that responds to a tap, not the area that is
     painted, and this is exactly the case the distinction exists for. */
  .player__btn{position:relative}
  .player__btn::after{
    content:"";position:absolute;left:50%;top:50%;
    transform:translate(-50%,-50%);
    width:44px;height:44px;border-radius:50%;
  }
  /* The seek bar was 18px tall. A scrub you cannot land on is a scrub you
     scroll the page with by accident. */
  /* the seek bar and volume are sized in the 600px block below, which
     lands later in the file and would otherwise win on order. */
}

@media (prefers-reduced-motion:reduce){
  .scrub .ch{transform:none!important;filter:none!important;opacity:1!important}
  body{background-attachment:scroll}
}

/* ==========================================================================
   Hairline rules — studied from lamalama.com

   Their hero's bottom border is a 1px full-bleed rule with a mono label row
   sitting on it. Read straight off the element:

     .js-line { height:1px; background:currentColor;
                transform-origin:0px 0.5px; transform:scaleX(1) -> scaleX(0) }

   As the hero scrolls the rule RETRACTS left-to-right and the labels on it
   wipe out — the border un-draws itself rather than sliding away. Theirs is a
   threshold trigger with `transition:all` (it holds at scaleX 1 until ~110px,
   then runs to 0 by ~220px). Ours is scrubbed off the shared rAF instead, so
   it tracks the scroll position both ways and reverses when you scroll back
   up, which a threshold cannot do.
   ========================================================================== */
.hairbar{position:relative;padding-top:16px;margin-top:clamp(28px,4.6vw,52px)}
.hairbar__line{
  position:absolute;left:0;right:0;top:0;height:1px;
  background:currentColor;opacity:.3;
  /* left edge, exactly as lamalama anchors it */
  transform-origin:0 50%;transform:scaleX(0);
  will-change:transform;
}
.hairbar__row{display:flex;flex-wrap:wrap;gap:10px clamp(18px,3.6vw,48px);align-items:flex-start}
/* The label wipes by collapsing its own clip box, which is what their
   js-text-container does (height 18px -> 0). Animating height on a 16px box
   costs nothing; it is not in the compositing path of anything else. */
.hairbar__cell{display:block;overflow:hidden;height:16px;will-change:height}
.hairbar__cell>span{
  display:block;line-height:16px;white-space:nowrap;
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  opacity:.72;
}
.hairbar__cell--key>span{opacity:1}
.skyzone .hairbar{color:#fff}
.skyzone .hairbar__line{opacity:.42}

@media(max-width:600px){
  .hairbar__row{gap:8px 18px}
  .hairbar__cell>span{font-size:10px;letter-spacing:.1em}
  /* three mono labels will not fit beside each other at 375px */
  .hairbar__cell--drop{display:none}
}
@media (prefers-reduced-motion:reduce){
  .hairbar__line{transform:scaleX(1)!important}
  .hairbar__cell{height:16px!important}
}

/* ==========================================================================
   Four mechanisms studied from mindmarket.com
   ==========================================================================
   Read off their live DOM, not guessed:

   1. NUMBER CARD STACK ("A few numbers behind the insights we deliver")
      .c-numbers-stack_list_item { position:sticky; top:136.5px }
      with an incrementing translateY per card: 59.5, 119, 178.5 — i.e. i*59.5.
      Cards are border-radius:50px solid colour blocks. The stacking itself is
      pure CSS sticky; no JS runs it. Each card parks 59.5px lower than the one
      before, so the pile shows every card's top edge.

   4. MENU
      .c-menu-desktop_dropdown_inner {
        transform: translateY(17px) -> 0;
        opacity: 0 -> 1;
        transition: transform .2s cubic-bezier(.5,0,0,1),
                    opacity .1s cubic-bezier(.5,0,0,1) }
      .c-menu-desktop_dropdown { transition: visibility 0s .2s }  (delayed out)
      cubic-bezier(.5,0,0,1) is the signature easing of the whole site.
   ========================================================================== */
:root{
  --mm-ease:cubic-bezier(.5,0,0,1);
  --stack-step:60px;      /* their 59.5 */
  --panel-r:50px;
}

/* ---- 1. Number card stack ------------------------------------------------ */
.numstack{position:relative}
.numstack__grid{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,440px);
  gap:clamp(28px,5vw,80px);
  /* stretch, not start: the heading column has to be as tall as the card list
     or its sticky child has nothing left to stick within and releases early. */
  align-items:stretch;
}
.numstack__col{position:relative;height:100%}
.numstack__sticky{position:sticky;top:calc(var(--headerH) + 60px)}
.numstack__text{max-width:38ch;color:var(--ink-65);font-size:15.5px;line-height:1.62;margin-top:22px}
.numstack__list{display:flex;flex-direction:column}
/* The whole mechanism. Each card sticks one step lower than the last, so the
   pile keeps every card's top edge visible instead of hiding them. */
.numstack__item{
  position:sticky;
  top:calc(var(--headerH) + 40px + var(--i,0) * var(--stack-step));
  padding-bottom:clamp(40px,6vw,90px);
}
.numcard{
  border-radius:var(--panel-r);padding:clamp(28px,3.4vw,44px);
  min-height:clamp(320px,34vw,420px);
  display:flex;flex-direction:column;
  box-shadow:0 30px 70px -40px rgba(8,22,60,.42);
}
.numcard__icon{
  width:46px;height:46px;border-radius:50%;display:grid;place-items:center;
  font-family:var(--mono);font-size:12px;font-weight:700;margin-left:auto;
}
.numcard__stat{font-size:clamp(54px,7.4vw,96px);line-height:.94;letter-spacing:-.05em;font-weight:600;margin-top:auto}
.numcard__label{font-family:var(--mono);font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;margin-top:18px}
.numcard__desc{font-size:15px;line-height:1.6;margin-top:14px;max-width:34ch}
.numcard--white{background:#fff;color:var(--ink)}
.numcard--white .numcard__stat{color:var(--blue)}
.numcard--white .numcard__icon{background:var(--blue);color:#fff}
.numcard--blue{background:var(--blue);color:#fff}
.numcard--blue .numcard__icon{background:rgba(255,255,255,.22);color:#fff}
.numcard--blue .numcard__desc,.numcard--blue .numcard__label{color:#fff}
.numcard--ink{background:var(--ink);color:#fff}
.numcard--ink .numcard__stat{color:var(--yellow)}
.numcard--ink .numcard__icon{background:var(--yellow);color:var(--ink)}
.numcard--ink .numcard__desc,.numcard--ink .numcard__label{color:rgba(255,255,255,.95)}
.numcard--paper{background:var(--sky-3);color:var(--ink)}
.numcard--paper .numcard__stat{color:var(--blue-deep)}
.numcard--paper .numcard__icon{background:var(--ink);color:#fff}

@media(max-width:900px){
  .numstack__grid{grid-template-columns:minmax(0,1fr)}
  .numstack__sticky{position:static}
  /* Sticky stacking inside a single column just pins cards over the heading;
     on a phone the pile becomes a plain stack. */
  .numstack__item{position:static;padding-bottom:18px}
  /* 50px of corner on a 335px-wide card eats the copy's margins */
  .numcard{min-height:0;border-radius:34px}
}

/* ---- 4. Menu ------------------------------------------------------------- */
.navpill{position:relative}
/* inline-flex so the caret sits beside the label instead of wrapping under it
   (the anchor clips its overflow for the swap, so a wrapped caret vanishes) */
.navpill a{position:relative;display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
/* The label swaps for a copy of itself rising from below — the hover reads as
   the word being replaced rather than merely recoloured. */
.nav-swap{display:block;position:relative;overflow:hidden;height:1.25em;line-height:1.25em}
.nav-swap span{display:block;transition:transform .34s var(--mm-ease)}
.nav-swap span:last-child{position:absolute;left:0;top:100%;width:100%}

@media (hover: hover) and (pointer: fine){.navpill a:hover .nav-swap span{transform:translateY(-100%)}}

.navdrop{
  position:absolute;left:50%;top:calc(100% + 14px);transform:translateX(-50%);
  visibility:hidden;
  /* delayed on the way out so the inner has time to fade first */
  transition:visibility 0s .2s;
  z-index:40;
}
.navpill .has-drop.is-open .navdrop{visibility:visible;transition-delay:0s}
.navdrop__inner{
  opacity:0;transform:translateY(17px);
  transition:transform .2s var(--mm-ease),opacity .1s var(--mm-ease);
  background:#fff;border-radius:20px;padding:18px;
  min-width:min(560px,86vw);
  box-shadow:0 30px 80px -34px rgba(8,22,60,.5),0 0 0 1px var(--ink-10);
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:4px;
}
.navpill .has-drop.is-open .navdrop__inner{opacity:1;transform:translateY(0)}
.navdrop__inner a{
  display:block;padding:12px 14px;border-radius:12px;
  color:var(--ink);font-size:14px;font-weight:500;background:transparent;
}

@media (hover: hover) and (pointer: fine){.navdrop__inner a:hover{background:var(--sky-2);color:var(--blue-deep)}}
.navdrop__inner a small{display:block;font-size:12px;color:var(--ink-55);margin-top:3px;font-weight:400}
.has-drop{display:flex;align-items:center}
.has-drop .caret{margin-left:5px;font-size:9px;transition:transform .25s var(--mm-ease);display:inline-block}
.has-drop.is-open .caret{transform:rotate(180deg)}
@media(max-width:980px){.navdrop{display:none}}
@media (prefers-reduced-motion:reduce){
  .nav-swap span,.navdrop__inner,.has-drop .caret{transition:none!important}
}

/* ==========================================================================
   01 — The problem, as a ledger
   A sticky title column beside numbered rows that light as they pass. The
   five-card grid it replaced made every drift look equally weighted; a ledger
   reads as a running tally, which is what the section is actually arguing.
   ========================================================================== */
.ledger__grid{display:grid;grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr);gap:clamp(28px,5vw,88px);align-items:stretch}
.ledger__col{position:relative}
.ledger__sticky{position:sticky;top:calc(var(--headerH) + 56px)}
.ledger__tally{
  margin-top:36px;padding-top:22px;border-top:1px solid var(--ink-12);
  font-family:var(--mono);font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-55);
}
.ledger__tally b{display:block;font-family:var(--sans);font-size:clamp(30px,3.6vw,46px);
  letter-spacing:-.04em;color:var(--ink);margin-top:8px;font-weight:600}
.ledger__list{display:flex;flex-direction:column}
.row{
  position:relative;display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  gap:clamp(14px,2vw,28px);align-items:start;
  padding:clamp(24px,3vw,34px) 0;
  border-top:1px solid var(--ink-12);
  opacity:.42;transition:opacity .5s var(--ease);
}
.row:last-child{border-bottom:1px solid var(--ink-12)}
.row.is-lit{opacity:1}
.row__n{font-family:var(--mono);font-size:12px;color:var(--ink-55);padding-top:6px;min-width:2.4ch}
.row__b h3{font-size:clamp(19px,2.1vw,25px);letter-spacing:-.025em;font-weight:600;margin-bottom:10px}
.row__b p{font-size:15px;line-height:1.62;color:var(--ink-65);max-width:48ch}
.row__fix{
  display:inline-flex;align-items:center;gap:8px;margin-top:16px;
  font-size:13.5px;color:var(--blue-deep);font-weight:500;
}
.row__fix i{
  width:18px;height:18px;border-radius:50%;background:var(--blue);color:#fff;
  display:grid;place-items:center;font-size:10px;font-style:normal;flex:none;
}
.row__cost{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--red-ink);background:rgba(235,38,38,.08);border:1px solid rgba(235,38,38,.2);
  padding:6px 10px;border-radius:999px;white-space:nowrap;margin-top:4px;
}
/* the bar that fills as the row lights — the tally made visible */
.row__meter{position:absolute;left:0;top:-1px;height:1px;background:var(--blue);
  transform-origin:0 50%;transform:scaleX(0);transition:transform .7s var(--ease-out-expo);width:100%}
.row.is-lit .row__meter{transform:scaleX(1)}

@media(max-width:900px){
  .ledger__grid{grid-template-columns:minmax(0,1fr);gap:34px}
  .ledger__sticky{position:static}
  .row{grid-template-columns:auto minmax(0,1fr);padding:22px 0}
  .row__cost{grid-column:2;justify-self:start;margin-top:12px}
  /* On a phone every row is "current" — dimming them just makes the page
     look broken while you read the one in front of you. */
  .row{opacity:1}
}

/* ==========================================================================
   04 — What changes: a before/after Friday
   A drag handle wipes between two renderings of the same afternoon. The three
   quotes it replaced were placeholder testimonials doing the persuading; this
   argues from the product instead, which is both stronger and honest.
   ========================================================================== */
.ba{position:relative;border-radius:var(--radius);overflow:hidden;background:var(--ink);
  box-shadow:0 40px 90px -50px rgba(8,22,60,.55);touch-action:pan-y;user-select:none;
  /* so .ba__in can be sized against THIS box rather than the viewport — see
     the width note below, which is what makes the handle do anything. */
  container-type:inline-size}
/* A true split, not a clip-path wipe. Wiping works for images because the
   content fills the frame; with text you would read the left half of one
   column and the right half of the other. Here each panel is a real flex
   child whose width the handle drives, and its content is anchored to the
   edge that stays on screen — so whichever side you favour is fully legible. */
.ba__pane{display:flex;align-items:stretch;min-height:clamp(430px,46vw,548px)}
.ba__side{position:relative;overflow:hidden;min-width:0;display:flex}
.ba__side--before{flex:0 0 var(--split,50%);background:#15171C;color:#fff;justify-content:flex-start}
.ba__side--after{flex:1 1 auto;background:linear-gradient(152deg,#fff 0%,var(--sky-2) 100%);color:var(--ink);justify-content:flex-end}
.ba__in{
  /* Exactly half the comparator, so at rest each column fills its own side
     edge to edge and the very first pixel of drag covers something.

     This was min(30rem,42vw) — a fixed 480px column inside a ~650px side on a
     desktop screen. Both columns therefore fitted with 170px to spare, and
     nothing was covered until the split passed 37% or 63%: a 26-point dead
     band centred exactly where the handle sits at rest. You could grab it,
     wiggle it, and watch nothing happen, which is precisely what it looked
     like — broken. Sized against the box, there is no dead band at all. */
  width:50cqw;flex:none;
  padding:clamp(26px,3.4vw,52px);
  display:flex;flex-direction:column;
}
.ba__tag{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.15em;text-transform:uppercase;
  padding:6px 11px;border-radius:999px;align-self:flex-start;margin-bottom:auto;white-space:nowrap;
}
.ba__side--before .ba__tag{background:rgba(235,38,38,.18);color:#FF8A8A;border:1px solid rgba(235,38,38,.35)}
.ba__side--after .ba__tag{background:rgba(38,99,235,.1);color:var(--blue-deep);border:1px solid rgba(38,99,235,.25)}
.ba__clock{font-family:var(--mono);font-size:clamp(34px,5vw,60px);letter-spacing:-.03em;line-height:1;margin:26px 0 14px;white-space:nowrap}
.ba__side--before .ba__clock{color:var(--red-on-dark)}
.ba__side--after .ba__clock{color:var(--blue)}
.ba__h{font-size:clamp(19px,2.3vw,28px);letter-spacing:-.03em;font-weight:600;max-width:17ch;margin-bottom:14px}
.ba__list{list-style:none;display:flex;flex-direction:column;gap:9px;font-size:14.5px;line-height:1.5}
.ba__list li{display:flex;gap:10px;align-items:flex-start}
.ba__list i{flex:none;width:16px;height:16px;border-radius:50%;display:grid;place-items:center;font-size:9px;font-style:normal;margin-top:3px}
.ba__side--before .ba__list{color:rgba(255,255,255,.72)}
.ba__side--before .ba__list i{background:rgba(235,38,38,.22);color:#FF8A8A}
.ba__side--after .ba__list{color:var(--ink-65)}
.ba__side--after .ba__list i{background:var(--blue);color:#fff}
.ba__bar{position:absolute;top:0;bottom:0;left:var(--split,50%);width:2px;background:#fff;
  transform:translateX(-1px);box-shadow:0 0 0 1px rgba(8,22,60,.18);z-index:3;pointer-events:none}
.ba__grip{
  position:absolute;top:50%;left:var(--split,50%);transform:translate(-50%,-50%);z-index:4;
  width:54px;height:54px;border-radius:50%;background:#fff;border:0;cursor:ew-resize;
  display:grid;place-items:center;
  box-shadow:0 10px 30px -8px rgba(8,22,60,.5);color:var(--ink);
  font-size:15px;letter-spacing:-.1em;
}
.ba__grip:active{cursor:grabbing}
.ba__grip:focus-visible{outline:3px solid var(--blue);outline-offset:3px}
.ba__hint{
  position:absolute;left:50%;bottom:14px;transform:translateX(-50%);z-index:4;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:#fff;background:rgba(8,22,60,.55);padding:7px 13px;border-radius:999px;
  transition:opacity .4s var(--ease);pointer-events:none;
}
.ba.is-touched .ba__hint{opacity:0}
/* Under 760px the two panels stack. A draggable divider across a 335px
   viewport leaves ~160px a side, which fits neither column's text. */
@media(max-width:760px){
  .ba{touch-action:auto}
  .ba__pane{flex-direction:column;min-height:0}
  .ba__side--before,.ba__side--after{flex:1 1 auto;justify-content:flex-start}
  .ba__in{width:100%;padding:24px 20px}   /* overrides 50cqw: stacked, full width */
  .ba__clock{font-size:38px;margin:16px 0 10px}
  .ba__bar,.ba__grip,.ba__hint{display:none}
}

/* ==========================================================================
   08 — Pricing: one number you drive yourself
   Three static cards made the reader do the seat maths in their head. This
   does it in front of them, which is the whole objection handled.
   ========================================================================== */
.pricing__grid{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);gap:clamp(26px,4vw,64px);align-items:start}
.pricebox{
  position:relative;border-radius:26px;padding:clamp(26px,3.4vw,46px);
  background:var(--ink);color:#fff;overflow:hidden;
  box-shadow:0 40px 90px -50px rgba(8,22,60,.6);
}
.pricebox__flag{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--yellow);background:rgba(225,235,38,.12);border:1px solid rgba(225,235,38,.3);
  padding:6px 12px;border-radius:999px;display:inline-block;margin-bottom:26px;
}
/* Billing term. Two buttons rather than a switch: a switch has to be labelled
   to say which way is which, and "Annual / Monthly" says it without the label. */
.pricebox__terms{display:inline-flex;gap:4px;padding:4px;margin-bottom:22px;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.14);border-radius:999px}
.pricebox__term{
  font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  color:rgba(255,255,255,.62);background:none;border:0;border-radius:999px;
  padding:8px 16px;cursor:pointer;transition:color .18s ease,background-color .18s ease;
}

@media (hover: hover) and (pointer: fine){.pricebox__term:hover{color:#fff}}
.pricebox__term.is-on{background:var(--yellow);color:#000;font-weight:600}
.pricebox__term:focus-visible{outline:2px solid var(--yellow);outline-offset:2px}
@media (prefers-reduced-motion:reduce){.pricebox__term{transition:none}}
.pricebox__v{display:flex;align-items:flex-end;gap:10px;flex-wrap:wrap}
.pricebox__n{font-size:clamp(48px,7vw,86px);line-height:.92;letter-spacing:-.05em;font-weight:600;font-variant-numeric:tabular-nums}
.pricebox__per{font-family:var(--mono);font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:rgba(255,255,255,.62);padding-bottom:10px}
.pricebox__sub{font-size:14.5px;color:rgba(255,255,255,.7);margin-top:14px;min-height:2.6em}
.pricebox__sub b{color:var(--yellow);font-weight:600}
.pricebox__slider{margin-top:30px}
.pricebox__row{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:12px;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.6)}
.pricebox__row b{font-family:var(--sans);font-size:20px;letter-spacing:-.02em;color:#fff;font-weight:600;font-variant-numeric:tabular-nums}
.pricebox input[type=range]{
  -webkit-appearance:none;appearance:none;width:100%;height:4px;border-radius:4px;
  background:rgba(255,255,255,.2);outline:none;cursor:pointer;
}
.pricebox input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:26px;height:26px;border-radius:50%;
  background:var(--yellow);border:3px solid var(--ink);cursor:grab;
  box-shadow:0 4px 14px -4px rgba(0,0,0,.6);
}
.pricebox input[type=range]::-moz-range-thumb{
  width:26px;height:26px;border-radius:50%;background:var(--yellow);
  border:3px solid var(--ink);cursor:grab;
}
.pricebox input[type=range]:focus-visible{outline:3px solid var(--yellow);outline-offset:4px}
.pricebox__cta{margin-top:28px;display:flex;gap:12px;flex-wrap:wrap;align-items:center}
.pricebox__fine{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:rgba(255,255,255,.52);margin-top:18px}

.pfacts{display:flex;flex-direction:column;gap:2px}
.pfact{padding:22px 0;border-top:1px solid var(--ink-12);display:grid;grid-template-columns:auto minmax(0,1fr);gap:18px;align-items:start}
.pfact:last-child{border-bottom:1px solid var(--ink-12)}
.pfact__k{font-family:var(--mono);font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-55);padding-top:4px;min-width:8ch}
.pfact__b h4{font-size:17px;letter-spacing:-.02em;font-weight:600;margin-bottom:6px}
.pfact__b p{font-size:14.5px;line-height:1.6;color:var(--ink-65);max-width:44ch}
@media(max-width:900px){
  .pricing__grid{grid-template-columns:minmax(0,1fr)}
  .pfact{grid-template-columns:minmax(0,1fr);gap:6px}
  .pfact__k{padding-top:0}
}

/* ==========================================================================
   Media player (tutorials)
   Real transport — play/pause, scrub, seek, speed, chapters, fullscreen,
   keyboard — driving a deterministic canvas screencast. See site.js for why
   the source is a canvas rather than an <video src>, and how to swap it.
   ========================================================================== */
.player{
  position:relative;border-radius:var(--radius);overflow:hidden;background:#0E1014;
  box-shadow:0 50px 110px -60px rgba(8,22,60,.6);
  --bar:#2663EB;
}
.player__stage{position:relative;display:block;width:100%;aspect-ratio:16/9;background:#0E1014}
.player__canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.player__big{
  position:absolute;inset:0;display:grid;place-items:center;border:0;background:transparent;
  cursor:pointer;z-index:2;color:#fff;
}
.player__big span{
  width:clamp(58px,7vw,86px);aspect-ratio:1;border-radius:50%;
  background:rgba(255,255,255,.94);color:var(--ink);
  display:grid;place-items:center;font-size:clamp(18px,2.2vw,26px);padding-left:5px;
  box-shadow:0 16px 46px -12px rgba(0,0,0,.7);
  transition:transform .3s var(--ease-out-expo),opacity .25s var(--ease);
}

@media (hover: hover) and (pointer: fine){.player__big:hover span{transform:scale(1.07)}}
.player.is-playing .player__big span{opacity:0;transform:scale(.7)}
.player.is-playing .player__big{cursor:inherit}

.player__bar{
  position:absolute;left:0;right:0;bottom:0;z-index:3;
  padding:38px clamp(12px,1.6vw,20px) clamp(10px,1.4vw,14px);
  background:linear-gradient(0deg,rgba(6,10,20,.92) 0%,rgba(6,10,20,.6) 52%,transparent 100%);
  opacity:1;transition:opacity .3s var(--ease);
}

@media (hover: hover) and (pointer: fine){.player.is-playing:not(:hover):not(:focus-within) .player__bar{opacity:0}}
.player__scrub{
  position:relative;height:16px;display:flex;align-items:center;cursor:pointer;
  margin-bottom:6px;touch-action:none;
}
.player__track{position:relative;height:4px;width:100%;border-radius:4px;background:rgba(255,255,255,.24);overflow:visible}
.player__fill{position:absolute;inset:0 auto 0 0;width:0;border-radius:4px;background:var(--bar)}
.player__knob{
  position:absolute;top:50%;left:0;width:13px;height:13px;border-radius:50%;background:#fff;
  transform:translate(-50%,-50%) scale(.55);transition:transform .2s var(--ease);
  box-shadow:0 2px 8px rgba(0,0,0,.5);
}

@media (hover: hover) and (pointer: fine){.player__scrub:hover .player__knob,.player__scrub:focus-visible .player__knob{transform:translate(-50%,-50%) scale(1)}}
.player__scrub:focus-visible{outline:2px solid #fff;outline-offset:4px;border-radius:4px}
/* chapter ticks sit on the track so the structure is visible before you play */
.player__tick{position:absolute;top:50%;width:2px;height:10px;transform:translate(-50%,-50%);background:rgba(255,255,255,.55);border-radius:1px;pointer-events:none}

.player__ctrls{display:flex;align-items:center;gap:clamp(6px,1vw,12px);color:#fff}
.player__btn{
  background:transparent;border:0;color:#fff;cursor:pointer;padding:7px;border-radius:9px;
  display:grid;place-items:center;font-size:14px;line-height:1;min-width:34px;min-height:34px;
}

@media (hover: hover) and (pointer: fine){.player__btn:hover{background:rgba(255,255,255,.14)}}
.player__btn:focus-visible{outline:2px solid #fff;outline-offset:2px}
.player__t{font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;color:rgba(255,255,255,.86);white-space:nowrap;font-variant-numeric:tabular-nums}
.player__sp{margin-left:auto;font-family:var(--mono);font-size:11px;letter-spacing:.08em}
.player__chap{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  color:rgba(255,255,255,.72);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  max-width:min(34ch,34vw);
}

/* the chapter list beside the player */
.player__wrap{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,300px);gap:clamp(18px,2.4vw,30px);align-items:start}
.chaps{display:flex;flex-direction:column;gap:2px}
.chaps__h{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-55);margin-bottom:12px}
.chap{
  display:grid;grid-template-columns:auto minmax(0,1fr);gap:12px;align-items:baseline;
  padding:12px 14px;border-radius:12px;border:0;background:transparent;cursor:pointer;
  text-align:left;font:inherit;color:var(--ink);width:100%;
  transition:background .25s var(--ease);
}

@media (hover: hover) and (pointer: fine){.chap:hover{background:var(--sky-2)}}
.chap.is-on{background:var(--sky-3)}
.chap.is-on .chap__t{color:var(--blue-deep);font-weight:600}
.chap:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.chap__time{font-family:var(--mono);font-size:11.5px;color:var(--ink-55);font-variant-numeric:tabular-nums}
.chap__t{font-size:14.5px;line-height:1.4}
@media(max-width:900px){
  .player__wrap{grid-template-columns:minmax(0,1fr)}
  .chaps{flex-direction:row;overflow-x:auto;gap:8px;padding-bottom:4px;-webkit-overflow-scrolling:touch}
  .chap{flex:none;width:auto;grid-template-columns:auto;gap:2px;background:var(--sky-2);min-width:150px}
  .chaps__h{display:none}
}
@media(max-width:600px){
  .player__t{font-size:10.5px}
  .player__chap{display:none}
  .player__btn{min-width:38px;min-height:38px}
}

/* ==========================================================================
   About — editorial treatment
   Reuses the ledger rows from 01 and the hairbar from the hero, so the two
   pages read as one system rather than two designs.
   ========================================================================== */
.about-hero{position:relative;padding-top:calc(var(--headerH) + clamp(40px,6vw,84px))}
.about-hero h1{max-width:15ch;font-size:clamp(38px,6.4vw,92px);line-height:.94;letter-spacing:-.05em}
.about-lead{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:clamp(20px,3vw,48px);margin-top:clamp(30px,4vw,56px)}
.about-lead p{font-size:16px;line-height:1.66;color:var(--ink-65)}
.about-lead p:first-child{font-size:18.5px;line-height:1.56;color:var(--ink)}

/* a full-bleed statement that holds the viewport for a beat */
/* No vertical padding of its own: the section around it already supplies the
   rhythm, and adding 140px to it was what made this page feel empty. */
.credo{position:relative;padding:0;text-align:center}
.credo__q{
  font-size:clamp(28px,5.4vw,74px);line-height:1.04;letter-spacing:-.05em;font-weight:600;
  max-width:17ch;margin:0 auto;text-wrap:balance;
}
.credo__q em{font-style:normal;color:var(--blue)}
.credo__sub{margin:clamp(22px,3vw,38px) auto 0;max-width:56ch;font-size:15.5px;line-height:1.66;color:var(--ink-65)}

/* ==========================================================================
   Milestones — a timeline that draws itself
   The connector is not one long line: each row owns the segment below its own
   dot and scales it from 0 to 1 when the row lights. Lighting is one-way (see
   milestones() in site.js), so the line stays drawn once you have passed it,
   which is what a timeline means. All geometry hangs off the two column tokens
   below, so the rail can never drift away from the dots.
   ========================================================================== */
.miles{
  --mileW:clamp(58px,7.4vw,104px);   /* the date column                     */
  --mileRail:clamp(26px,3vw,40px);   /* the connector column                */
  --mileGap:clamp(16px,2vw,26px);    /* vertical space between rows         */
  position:relative;
}
.mile{
  position:relative;display:grid;align-items:start;
  grid-template-columns:var(--mileW) var(--mileRail) minmax(0,1fr);
  column-gap:clamp(10px,1.4vw,18px);padding-bottom:var(--mileGap);
}
.mile:last-child{padding-bottom:0}

/* --- the date ----------------------------------------------------------- */
.mile__when{display:flex;flex-direction:column;gap:1px;padding-top:9px;text-align:right;align-items:flex-end}
.mile__when b{font-family:var(--mono);font-size:clamp(15px,1.5vw,19px);font-weight:500;letter-spacing:-.02em;
  color:var(--ink);line-height:1;font-variant-numeric:tabular-nums}
.mile__when span{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-55)}
.mile.is-now .mile__when b{color:var(--blue)}
.mile.is-next .mile__when b{color:var(--red);font-size:clamp(13px,1.2vw,15px)}

/* --- the connector ------------------------------------------------------ */
.mile__rail{position:relative;align-self:stretch;display:flex;justify-content:center;padding-top:7px}
.mile__rail::before{                      /* the segment this row owns */
  content:"";position:absolute;left:50%;width:2px;margin-left:-1px;
  top:22px;bottom:calc(-1 * var(--mileGap));
  background:linear-gradient(180deg,var(--blue),rgba(38,99,235,.3));
  transform:scaleY(0);transform-origin:top;
  transition:transform .62s var(--ease);
}
.mile.is-lit .mile__rail::before{transform:scaleY(1)}
.mile:last-child .mile__rail::before{display:none}
.mile__dot{
  position:relative;z-index:1;flex:none;width:14px;height:14px;border-radius:50%;
  background:#fff;border:2px solid var(--ink-16);
  transform:scale(.72);transition:transform .5s var(--ease-out-expo),border-color .4s var(--ease),background .4s var(--ease);
}
.mile.is-lit .mile__dot{transform:scale(1);border-color:var(--blue);background:var(--blue)}
.mile.is-now .mile__dot,.mile.is-next .mile__dot{background:#fff}
.mile.is-now.is-lit .mile__dot{border-color:var(--blue);box-shadow:0 0 0 5px rgba(38,99,235,.14)}
.mile.is-next .mile__dot{border-style:dashed}
.mile.is-next.is-lit .mile__dot{border-color:var(--red);box-shadow:none}
/* the live row breathes, once, on a long cycle — enough to read as "now" */
@keyframes milePulse{0%,100%{box-shadow:0 0 0 5px rgba(38,99,235,.14)}50%{box-shadow:0 0 0 10px rgba(38,99,235,0)}}
.mile.is-now.is-lit .mile__dot{animation:milePulse 2.8s var(--ease) infinite}

/* --- the card ----------------------------------------------------------- */
.mile__card{
  position:relative;border-radius:16px;padding:clamp(16px,1.8vw,24px) clamp(16px,2vw,28px);
  border:1px solid var(--ink-10);background:#fff;overflow:hidden;
  opacity:.5;transform:translateY(10px);
  transition:opacity .5s var(--ease),transform .6s var(--ease-out-expo),
             border-color .35s var(--ease),box-shadow .35s var(--ease);
}
/* the lavender wash from the feature cards, so the two pages share one language */
.mile__card::before{
  content:"";position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .45s var(--ease);
  background:
    radial-gradient(ellipse 60% 120% at 100% 0%,rgba(var(--lav),.13),transparent 64%),
    linear-gradient(180deg,rgba(var(--lav),.05),transparent 58%);
}
.mile.is-lit .mile__card{opacity:1;transform:none}
.mile.is-lit .mile__card::before{opacity:1}

@media (hover: hover) and (pointer: fine){.mile__card:hover{border-color:rgba(38,99,235,.28);box-shadow:0 22px 44px -30px rgba(12,30,80,.42)}}
.mile.is-now .mile__card{border-color:rgba(38,99,235,.26)}
.mile.is-now .mile__card::before{
  background:
    radial-gradient(ellipse 64% 130% at 100% 0%,rgba(38,99,235,.13),transparent 66%),
    linear-gradient(180deg,rgba(var(--lav),.07),transparent 60%);
}
.mile h3{position:relative;font-size:clamp(17px,1.9vw,22px);letter-spacing:-.026em;font-weight:600;margin-bottom:7px}
.mile p{position:relative;font-size:14.6px;line-height:1.62;color:var(--ink-65);max-width:58ch}
.mile__chip{display:inline-block;margin-left:10px;font-family:var(--mono);font-size:10px;letter-spacing:.12em;
  text-transform:uppercase;padding:4px 9px;border-radius:999px;vertical-align:middle;white-space:nowrap}
.mile.is-now .mile__chip{background:rgba(38,99,235,.1);color:var(--blue-deep);border:1px solid rgba(38,99,235,.24)}
.mile.is-next .mile__chip{background:rgba(235,38,38,.08);color:var(--red);border:1px solid rgba(235,38,38,.2)}

@media(max-width:760px){
  /* The date moves above the title and the rail keeps its column, so the
     connector still reads as one line down the left edge on a phone. */
  .miles{--mileW:0px;--mileRail:24px}
  .mile{grid-template-columns:var(--mileRail) minmax(0,1fr);column-gap:12px}
  .mile__when{grid-row:1;grid-column:2;flex-direction:row;align-items:baseline;gap:8px;
    text-align:left;padding:0 0 8px}
  .mile__rail{grid-row:1 / span 2;grid-column:1;padding-top:4px}
  .mile__rail::before{top:18px}
  .mile__card{grid-column:2}
  .mile.is-next .mile__when b{font-size:15px}
  .about-lead p:first-child{font-size:17px}
}
@media(prefers-reduced-motion:reduce){
  .mile__card,.mile__dot,.mile__rail::before{transition:none}
  .mile.is-now.is-lit .mile__dot{animation:none}
}

/* ==========================================================================
   Mobile pass
   Driven by an audit at 375px: every element wider than the viewport, and
   every interactive target under 40x40. Numbers in the comments are measured,
   not guessed.
   ========================================================================== */

/* --- Range inputs -------------------------------------------------------
   The pricing slider measured 283x4: the visible track WAS the hit area, so
   the finger had a 4px-tall target. The input is now 44px tall and fully
   transparent; the 4px bar is painted by the track pseudo-element instead. */
.pricebox input[type=range],
.calc input[type=range]{
  height:44px;background:transparent;
}
.pricebox input[type=range]::-webkit-slider-runnable-track,
.calc input[type=range]::-webkit-slider-runnable-track{
  height:4px;border-radius:4px;background:rgba(255,255,255,.2);
}
.calc input[type=range]::-webkit-slider-runnable-track{background:var(--ink-12)}
.pricebox input[type=range]::-moz-range-track,
.calc input[type=range]::-moz-range-track{
  height:4px;border-radius:4px;background:rgba(255,255,255,.2);
}
.calc input[type=range]::-moz-range-track{background:var(--ink-12)}
/* Chrome centres the thumb on the track only if you offset it yourself once
   the track no longer fills the input box. */
.pricebox input[type=range]::-webkit-slider-thumb,
.calc input[type=range]::-webkit-slider-thumb{margin-top:-11px}

@media(max-width:760px){
  /* --- The hero product mock measured 940px inside a 375px viewport. It was
     clipped by an ancestor rather than overflowing the page, so it read as a
     sliced-off slab. Scaled down it reads as a device preview instead. */
  /* The mock is authored at 940x715. A fixed scale factor only fits one
     viewport width, so the factor is derived from the viewport itself and the
     wrapper takes the same ratio — the scaled mock then lands exactly inside
     it at any width, with no dead space and nothing clipped. */
  /* --mock-s is written by site.js: CSS cannot divide a length by a length,
     so calc((100vw - 2*pad) / 940) produces a length and scale() silently
     ignores it. The measure pass sets the real ratio instead. */
  .hero__mock{overflow:hidden;border-radius:16px;aspect-ratio:940/715}
  .mock--hero{width:940px;transform:scale(var(--mock-s,.356));transform-origin:0 0}

  /* --- Footer links measured 43x17 .. 146x18. Padding lifts every one of
     them past 44px without changing the visual rhythm much. */
  .footer__cols a,.footer__legal nav a{display:inline-block;padding:13px 0;line-height:1.2}
  .footer__cols div{display:flex;flex-direction:column}

  /* --- The sticky-CTA dismiss measured 22x24. */
  .stickycta__x{width:44px;height:44px;flex:none;display:grid;place-items:center}

  /* The tutorials and about headings were running under the fixed header,
     whose own height is a token — so clear exactly that, not a guess. */
  .hero{padding-top:calc(var(--headerH) + 26px)!important}

  /* --- Type and rhythm ------------------------------------------------- */
  .h-md{font-size:clamp(26px,7.4vw,34px);line-height:1.06}
  .h-sm{font-size:clamp(22px,6.4vw,28px)}
  .lede{font-size:15.5px;line-height:1.62}
  :root{--sec-y:clamp(64px,14vw,92px)}
  .numstack__text{font-size:15px}

  /* the ledger rows: the cost chip was colliding with the heading */
  .row{gap:10px 14px}
  .row__n{font-size:11px;padding-top:3px}
  .row__b h3{font-size:19px}
}

@media(max-width:600px){
  /* the nav pill and the trial button cannot share a 375px row with the logo */
  .navpill{display:none}
  .player__wrap{gap:14px}
  .pricebox{padding:22px 18px}
  .pricebox__n{font-size:clamp(38px,12vw,52px)}
  .ba__in{padding:22px 18px}
}

/* Placeholder destinations that do not exist yet are NOT links. An <a href="#">
   is a dead link to a crawler and a broken promise to a reader; a span with the
   same styling is neither. Swap each one back to an <a href="..."> as the real
   URL lands — the list is in the README. */
.lnk-soon{
  color:var(--ink-55);cursor:inherit;
  text-decoration:underline;text-decoration-style:dotted;
  text-underline-offset:3px;text-decoration-color:var(--ink-18);
}
.footer__cols .lnk-soon,.footer__legal nav .lnk-soon{display:inline-block}
@media(max-width:760px){
  .footer__cols .lnk-soon,.footer__legal nav .lnk-soon{padding:13px 0;line-height:1.2}
}

/* ==========================================================================
   The closer — 07 "Get it" folded into the final CTA
   One panel does the asking now: the argument, the buttons, the app badges
   and the phone. Two separate dark panels in a row was one ask too many.
   ========================================================================== */
.closer{
  position:relative;overflow:hidden;border-radius:26px;
  background:var(--ink);color:#fff;padding:clamp(30px,4.4vw,68px);
  box-shadow:0 50px 110px -60px rgba(8,22,60,.6);
}
.closer__grid{
  position:relative;z-index:1;
  display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:clamp(26px,4vw,64px);align-items:center;
}
.closer__copy h2{font-size:clamp(28px,4.4vw,58px);line-height:1.02;letter-spacing:-.045em;font-weight:600;max-width:17ch}
.closer__copy > p{margin-top:20px;max-width:52ch;font-size:15.5px;line-height:1.66;color:rgba(255,255,255,.68)}
.closer .cta__row{margin-top:30px;display:flex;flex-wrap:wrap;gap:12px}
.closer__apps{margin-top:clamp(26px,3vw,40px)}
.closer__rule{height:1px;background:rgba(255,255,255,.16);margin-bottom:22px}
.closer__appnote{font-size:14px;line-height:1.6;color:rgba(255,255,255,.56);max-width:50ch;margin-bottom:18px}
.closer .stores{display:flex;flex-wrap:wrap;gap:10px}
.closer__fine{margin-top:18px;color:rgba(255,255,255,.46)}
.closer__phone{display:flex;justify-content:center}
@media(max-width:900px){
  .closer__grid{grid-template-columns:minmax(0,1fr);gap:32px}
  /* the phone leads on a phone — it is the thing being described */
  .closer__phone{order:-1}
}

/* ==========================================================================
   05 — module cards: pointer spotlight + a fill that wipes up
   The old hover was an instant background swap, which read as a state change
   rather than as a response. --mx/--my are written by site.js.
   ========================================================================== */
/* No `cursor` here: a value applied directly to the element would beat the
   inherited `cursor:none` from body.cursor-ready and show the system arrow
   on top of the custom one. */
.hcell{position:relative;isolation:isolate;overflow:hidden}
/* the fill, anchored to the bottom edge so it rises into the card */
.hcell::before{
  content:"";position:absolute;inset:0;z-index:-2;background:var(--blue);
  transform:translateY(101%);
  transition:transform .52s var(--ease-out-expo);
}
/* :focus-visible, not :focus-within. The dialog returns focus to the card it
   was opened from; with :focus-within that left the card stuck lit after a
   mouse click. :focus-visible only matches when the browser decides the focus
   should be shown — i.e. keyboard — so keyboard users still see the state. */

@media (hover: hover) and (pointer: fine){.hcell:hover::before,.hcell:focus-visible::before{transform:translateY(0)}}
/* the spotlight, which only exists while the pointer is inside the card */
.hcell::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;opacity:0;
  transition:opacity .35s var(--ease);
  background:radial-gradient(240px circle at var(--mx,50%) var(--my,50%),
             rgba(255,255,255,.16),transparent 70%);
}

@media (hover: hover) and (pointer: fine){.hcell:hover::after{opacity:1}}

@media (hover: hover) and (pointer: fine){.hcell:hover{background:var(--white);color:#fff}}
.hcell h3,.hcell p,.hcell .hcell__tag,.hcell .hcell__ic{transition:transform .45s var(--ease-out-expo),opacity .3s var(--ease)}

@media (hover: hover) and (pointer: fine){.hcell:hover h3{transform:translateX(4px)}}

@media (hover: hover) and (pointer: fine){.hcell:hover .hcell__ic{opacity:.9;transform:rotate(-90deg) scale(1.04)}}

@media (hover: hover) and (pointer: fine){.hcell:hover .hcell__tag{opacity:.8}}
@media(hover:none){
  /* no pointer, no spotlight — and never leave a card stuck in hover */
  .hcell::before,.hcell::after{display:none}
  .hcell:hover{background:var(--white);color:var(--ink)}
}

/* ==========================================================================
   06 — Security: a scan pass and rows that arm on hover
   ========================================================================== */
.seclist{position:relative;overflow:hidden}
/* a slow scan line, the visual grammar of something being checked */
.seclist::after{
  content:"";position:absolute;left:0;right:0;top:0;height:120px;pointer-events:none;z-index:2;
  background:linear-gradient(180deg,transparent,rgba(225,235,38,.09) 45%,rgba(225,235,38,.16) 50%,rgba(225,235,38,.09) 55%,transparent);
  transform:translateY(-140px);
}
.seclist.is-scanning::after{animation:secscan 3.4s var(--ease) 1}
@keyframes secscan{
  0%{transform:translateY(-140px);opacity:0}
  8%{opacity:1}
  92%{opacity:1}
  100%{transform:translateY(var(--scanTo,760px));opacity:0}
}
/* The row's content slides right on hover. Transformed rather than padded:
   animating padding-left relayouts the row on every frame, and this list sits
   in a section people scroll past on a phone. */
.seclist > div{position:relative;transition:background .3s var(--ease)}
.seclist > div > *{transition:transform .35s var(--ease-out-expo)}
/* the accent bar grows from the row's own dot */
.seclist > div::before{
  content:"";position:absolute;left:0;top:18px;bottom:18px;width:2px;border-radius:2px;
  background:var(--yellow);transform:scaleY(0);transform-origin:50% 0;
  transition:transform .4s var(--ease-out-expo);
}

@media (hover: hover) and (pointer: fine){.seclist > div:hover{background:rgba(255,255,255,.05)}}

@media (hover: hover) and (pointer: fine){.seclist > div:hover > *{transform:translateX(12px)}}

@media (hover: hover) and (pointer: fine){.seclist > div:hover::before{transform:scaleY(1)}}
.seclist b i{transition:transform .4s var(--ease-out-expo),box-shadow .4s var(--ease)}

@media (hover: hover) and (pointer: fine){.seclist > div:hover b i{transform:scale(1.55);box-shadow:0 0 0 4px rgba(225,235,38,.18)}}

/* the badges count themselves in rather than all appearing at once */
.badges span{
  opacity:0;transform:translateY(8px) scale(.96);
  transition:opacity .45s var(--ease),transform .45s var(--ease-out-expo);
}
.badges.in span{opacity:1;transform:none}
.badges.in span:nth-child(1){transition-delay:.00s}
.badges.in span:nth-child(2){transition-delay:.07s}
.badges.in span:nth-child(3){transition-delay:.14s}
.badges.in span:nth-child(4){transition-delay:.21s}
.badges.in span:nth-child(5){transition-delay:.28s}
.badges span{position:relative;overflow:hidden}
.badges span::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 38%,rgba(225,235,38,.42) 50%,transparent 62%);
  transform:translateX(-130%);
}

@media (hover: hover) and (pointer: fine){.badges.in span:hover::after{animation:badgesheen .7s var(--ease) 1}}
@keyframes badgesheen{to{transform:translateX(130%)}}

@media (prefers-reduced-motion:reduce){
  .hcell::before,.hcell::after{transition:none}
  .seclist.is-scanning::after{animation:none}
  .badges span{opacity:1;transform:none;transition:none}
  .badges.in span:hover::after{animation:none}
}

/* ==========================================================================
   Closer — button pairing, ground, store buttons, device
   ========================================================================== */

/* --- 1. The button pair --------------------------------------------------
   The two were the same 54px box but did not read as a pair: the ghost had a
   1px border (so a 52px content box against the yellow's 54) and font-weight
   500 against 600. The border is now an inset shadow, which paints in the
   same place but takes no layout space, so both buttons have an identical
   content box and identical text metrics. */
.closer .cta__row{align-items:center}
.closer .cta__row .btn{height:54px;font-size:16px;font-weight:600;border:0}
/* Secondary keeps its black edge here too, but painted as an inset shadow
   for the same reason the ghost's is: a real border would take layout space
   and the two buttons in this row have to share one content box. */
.closer .cta__row .btn--primary,.closer .cta__row .btn--secondary,.closer .cta__row .btn--yellow{box-shadow:inset 0 0 0 1.5px var(--ink)}
.closer .btn--ghost-dark{
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.45);
  background:transparent;
}

@media (hover: hover) and (pointer: fine){.closer .btn--ghost-dark:hover{
  background:rgba(255,255,255,.12);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.9);
}}
@media(min-width:761px){
  /* Flush left, each button sized to its own label. The shared min-width that
     was here centred both labels inside padded boxes, which pushed them off
     the copy's left edge — the box model fix above is what makes the pair
     read as a pair, so the width no longer has to. */
  .closer .cta__row{justify-content:flex-start}
  .closer .cta__row .btn{justify-content:center}
}
@media(max-width:760px){
  .closer .cta__row{flex-direction:column;align-items:stretch}
  .closer .cta__row .btn{width:100%;justify-content:center}
}

/* --- 2. Ground: gradient, no grid --------------------------------------- */
.closer .cta__grid{display:none}
/* The hero's gradient, verbatim: the same four radial light layers over the
   same linear ramp. The ramp is cut at the hero's 40% stop (#4C95EE) rather
   than run to its pale end — the hero resolves to paper because the page
   continues underneath it, but a card has to keep white text legible all the
   way to its bottom edge. */
.closer{
  background:
    radial-gradient(ellipse 62% 46% at 50% -6%,rgba(255,255,255,.42),transparent 62%),
    radial-gradient(ellipse 52% 40% at 86% 24%,rgba(154,204,255,.34),transparent 68%),
    radial-gradient(ellipse 70% 52% at 14% 84%,rgba(214,235,255,.3),transparent 66%),
    radial-gradient(ellipse 80% 60% at 50% 118%,rgba(12,52,140,.28),transparent 70%),
    linear-gradient(180deg,#175FD2 0%,#1E68D8 50%,#2472DE 100%);
}
/* The ramp stops at #2472DE rather than running on to the hero's #4C95EE.
   Measured over the painted gradient, the hero's lighter half put this card's
   11.5px fine print at 2.57:1 and its body copy at 3.96:1 — both under AA.
   The hero gets away with that range because the only thing sitting on it is
   58px display type. Held in the hero's deep-blue range, with the muted greys
   taken to solid white, every string here clears 4.5:1. */
.closer .closer__copy > p{color:#fff}
.closer .closer__appnote{color:#fff;opacity:.96}
/* solid white: at 11.5px this is the string with the least headroom, and any
   opacity at all drops it under 4.5:1 against the bottom of the ramp */
.closer .closer__fine{color:#fff;opacity:1}
.closer .closer__rule{background:rgba(255,255,255,.3)}
.closer .btn--ghost-dark{box-shadow:inset 0 0 0 1px rgba(255,255,255,.7)}

@media (hover: hover) and (pointer: fine){.closer .btn--ghost-dark:hover{box-shadow:inset 0 0 0 1px #fff;background:rgba(255,255,255,.18)}}
.closer .store{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.5)}

@media (hover: hover) and (pointer: fine){.closer .store:hover{background:rgba(255,255,255,.24);border-color:#fff}}

/* --- 3. Store buttons: visible edges on a dark panel --------------------- */
.closer .store{
  background:rgba(255,255,255,.05);
  border:1px solid rgba(255,255,255,.3);
  backdrop-filter:blur(2px);
  transition:background .25s var(--ease),border-color .25s var(--ease),transform .25s var(--ease);
}

@media (hover: hover) and (pointer: fine){.closer .store:hover{
  background:rgba(255,255,255,.13);
  border-color:rgba(255,255,255,.72);
  transform:translateY(-2px);
}}
.closer .store--light{
  background:var(--white);color:var(--ink);border-color:var(--white);
}

@media (hover: hover) and (pointer: fine){.closer .store--light:hover{background:#fff;border-color:#fff;color:var(--ink)}}

/* --- 4. The device -------------------------------------------------------
   A real handset silhouette: titanium rail, dynamic island, status bar, home
   indicator, side buttons and a glass sheen. The old version was a white
   rounded rectangle, which reads as a card, not a phone. */
.device{
  position:relative;width:clamp(232px,20vw,274px);aspect-ratio:390/844;
  border-radius:clamp(34px,3.2vw,44px);
  background:linear-gradient(150deg,#6E7482 0%,#2B2F38 16%,#1A1D24 50%,#3A3F49 86%,#7A8090 100%);
  padding:3px;
  box-shadow:
    0 2px 0 rgba(255,255,255,.22) inset,
    0 46px 90px -34px rgba(0,0,0,.85),
    0 10px 28px -12px rgba(0,0,0,.7);
  animation:floaty 6.5s ease-in-out infinite;
}
.device__screen{
  position:relative;height:100%;width:100%;overflow:hidden;
  border-radius:clamp(31px,2.9vw,41px);
  background:var(--ui-bg);
  display:flex;flex-direction:column;
}
/* dynamic island */
.device__island{
  position:absolute;top:9px;left:50%;transform:translateX(-50%);z-index:5;
  width:32%;height:24px;border-radius:999px;background:#07080B;
}
.device__island::after{
  content:"";position:absolute;right:9px;top:50%;transform:translateY(-50%);
  width:7px;height:7px;border-radius:50%;
  background:radial-gradient(circle at 32% 32%,#2F3A52,#0B0E15 70%);
}
/* status bar */
.device__status{
  position:relative;z-index:4;display:flex;align-items:center;justify-content:space-between;
  padding:11px 20px 0;font-size:11.5px;font-weight:600;color:#fff;
  font-variant-numeric:tabular-nums;letter-spacing:-.01em;
}
.device__status .sig{display:flex;align-items:center;gap:4px}
.device__status .bars{display:flex;align-items:flex-end;gap:1.5px;height:9px}
.device__status .bars i{width:2.5px;background:#fff;border-radius:1px;display:block}
.device__status .bars i:nth-child(1){height:35%}
.device__status .bars i:nth-child(2){height:58%}
.device__status .bars i:nth-child(3){height:80%}
.device__status .bars i:nth-child(4){height:100%}
.device__batt{
  width:22px;height:11px;border-radius:3px;border:1.2px solid rgba(255,255,255,.7);
  padding:1.4px;position:relative;
}
.device__batt::after{content:"";position:absolute;right:-3px;top:50%;transform:translateY(-50%);
  width:1.6px;height:4px;border-radius:0 1px 1px 0;background:rgba(255,255,255,.7)}
.device__batt i{display:block;height:100%;width:78%;border-radius:1.5px;background:#fff}
/* app chrome */
.device__head{background:var(--ui-ink);color:#fff;padding:6px 18px 20px}
.device__body{flex:1;padding:14px;display:flex;flex-direction:column;gap:10px;overflow:hidden}
.device__home{
  position:absolute;left:50%;bottom:7px;transform:translateX(-50%);z-index:5;
  width:36%;height:4.5px;border-radius:999px;background:rgba(255,255,255,.9);
  mix-blend-mode:difference;
}
/* glass: one specular streak across the panel */
.device__glass{
  position:absolute;inset:0;z-index:6;pointer-events:none;border-radius:inherit;
  background:linear-gradient(118deg,rgba(255,255,255,.16) 0%,rgba(255,255,255,.05) 22%,transparent 42%);
}
/* side buttons on the rail */
.device__btn{position:absolute;background:linear-gradient(180deg,#7C8290,#30343D);border-radius:2px;z-index:-1}
.device__btn--vol-up{left:-2.5px;top:20%;width:3px;height:7%}
.device__btn--vol-dn{left:-2.5px;top:29.5%;width:3px;height:7%}
.device__btn--silent{left:-2.5px;top:13.5%;width:3px;height:4%}
.device__btn--power{right:-2.5px;top:23%;width:3px;height:11%}

@media(max-width:900px){.device{width:clamp(228px,62vw,262px)}}
@media (prefers-reduced-motion:reduce){.device{animation:none}}

/* The app's tab bar. Also fills the lower third of the screen, which was
   empty white and made the device read as a cropped screenshot. */
.device__tabs{
  position:relative;z-index:4;margin-top:auto;
  display:grid;grid-template-columns:repeat(4,1fr);
  padding:9px 6px 18px;
  background:rgba(255,255,255,.92);
  backdrop-filter:blur(8px);
  border-top:1px solid var(--ui-line);
}
.device__tabs span{display:flex;flex-direction:column;align-items:center;gap:3px;color:var(--ui-dim)}
.device__tabs span.is-on{color:var(--ui-blue)}
.device__tabs svg{width:17px;height:17px;fill:currentColor}
.device__tabs i{font-style:normal;font-size:8.5px;font-weight:600;letter-spacing:.01em}


/* The closer sits directly above the footer, so it takes the footer's own
   gutter and radius — mismatched by even a few pixels they read as two
   unrelated cards rather than as a pair closing the page. */
#cta{padding-left:clamp(10px,2.4vw,18px);padding-right:clamp(10px,2.4vw,18px)}
.closer{border-radius:var(--radius)}

/* --- The tick inside each module card's square ---------------------------
   The square was empty, so hovering only changed its opacity. Now a check
   draws itself along its own path: stroke-dasharray is set to the path length
   (19.8 units, rounded up to 22) and the offset runs to zero, so the stroke
   is revealed from its start rather than faded in. */
.hcell__ic{
  position:relative;
  transition:opacity .3s var(--ease),border-color .3s var(--ease),
             background .3s var(--ease),transform .55s var(--ease-out-expo);
}
/* The box turns a quarter as before. The tick counter-rotates by exactly the
   same amount, so it draws upright while the box travels around it — rotating
   the check along with the box would leave it lying on its side. */
.hcell:hover .hcell__ic,
.hcell:focus-visible .hcell__ic{
  opacity:1;transform:rotate(-90deg) scale(1.06);
  background:rgba(255,255,255,.16);border-color:rgba(255,255,255,.9);
}
.hcell__tick{
  width:18px;height:18px;display:block;
  fill:none;stroke:var(--tick);stroke-width:2.6;
  stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:22;stroke-dashoffset:22;
  transform:rotate(0deg) scale(.8);
  transform-origin:50% 50%;
  transition:stroke-dashoffset .46s var(--ease-out-expo) .1s,
             transform .55s var(--ease-out-expo);
}
.hcell:hover .hcell__tick,
.hcell:focus-visible .hcell__tick{
  stroke-dashoffset:0;
  transform:rotate(90deg) scale(1);
}
@media (prefers-reduced-motion:reduce){
  .hcell__ic,.hcell__tick{transition:none}
  .hcell:hover .hcell__ic{transform:none}
  .hcell:hover .hcell__tick{stroke-dashoffset:0;transform:none}
}

/* --- Custom-cursor integrity -------------------------------------------
   `cursor` applied directly to an element always beats the `cursor:none`
   inherited from body.cursor-ready, so any component that sets its own
   cursor punches a hole in the custom one and the system arrow shows through.
   This sweeps the ones that do, at a specificity high enough to win, and only
   while the custom cursor is actually active — under (hover:none) or at
   <=1024px body.cursor-ready reverts to `cursor:auto` and these stop applying,
   so touch and small screens keep their normal cursors. */
body.cursor-ready input[type=range],
body.cursor-ready input[type=range]::-webkit-slider-thumb,
body.cursor-ready .player__scrub,
body.cursor-ready .ba__grip,
body.cursor-ready .hcell,
body.cursor-ready .lnk-soon{cursor:none}

/* ==========================================================================
   Module dialog — opens from a card in 05
   Native <dialog>, so the platform supplies focus trapping, Escape, and page
   inertness. Blue ground, matching the hero's ramp.
   ========================================================================== */
.mdl{
  border:0;padding:0;background:transparent;max-width:none;max-height:none;
  width:100%;height:100%;overflow:visible;color:#fff;
}
.mdl::backdrop{
  background:rgba(8,18,44,.62);
  backdrop-filter:blur(5px);
  opacity:0;transition:opacity .3s var(--ease);
}
.mdl[open]::backdrop{opacity:1}
.mdl__card{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%) scale(.965);
  width:min(940px,calc(100vw - 2 * var(--pad)));
  max-height:min(86vh,880px);overflow:auto;overscroll-behavior:contain;
  border-radius:24px;padding:clamp(26px,3.6vw,52px);
  opacity:0;transition:opacity .28s var(--ease),transform .42s var(--ease-out-expo);
  background:
    radial-gradient(ellipse 62% 46% at 50% -6%,rgba(255,255,255,.42),transparent 62%),
    radial-gradient(ellipse 52% 40% at 86% 24%,rgba(154,204,255,.34),transparent 68%),
    radial-gradient(ellipse 70% 52% at 14% 84%,rgba(214,235,255,.3),transparent 66%),
    radial-gradient(ellipse 80% 60% at 50% 118%,rgba(12,52,140,.28),transparent 70%),
    linear-gradient(180deg,#175FD2 0%,#1E68D8 50%,#2472DE 100%);
  box-shadow:0 60px 140px -60px rgba(4,12,34,.9);
}
.mdl.is-in .mdl__card{opacity:1;transform:translate(-50%,-50%) scale(1)}
.mdl__x{
  position:absolute;top:14px;right:14px;z-index:3;
  width:44px;height:44px;border-radius:50%;border:1px solid rgba(255,255,255,.4);
  background:rgba(255,255,255,.1);color:#fff;font-size:22px;line-height:1;
  display:grid;place-items:center;
}

@media (hover: hover) and (pointer: fine){.mdl__x:hover{background:rgba(255,255,255,.24);border-color:#fff}}
.mdl__tag{
  display:inline-block;font-family:var(--mono);font-size:10.5px;letter-spacing:.15em;
  text-transform:uppercase;padding:6px 12px;border-radius:999px;
  background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.34);margin-bottom:18px;
}
.mdl__head h2{font-size:clamp(26px,3.8vw,46px);line-height:1.03;letter-spacing:-.04em;font-weight:600;max-width:18ch}
.mdl__lead{margin-top:14px;font-size:16px;line-height:1.62;color:#fff;max-width:60ch}
.mdl__body{
  display:grid;grid-template-columns:minmax(0,1.3fr) minmax(0,.7fr);
  gap:clamp(20px,3vw,44px);margin-top:clamp(24px,3vw,38px);align-items:start;
}
.mdl__list{list-style:none;display:flex;flex-direction:column;gap:2px}
.mdl__list li{
  display:grid;grid-template-columns:auto minmax(0,1fr);gap:13px;align-items:start;
  padding:14px 0;border-top:1px solid rgba(255,255,255,.2);
}
.mdl__list li:last-child{border-bottom:1px solid rgba(255,255,255,.2)}
.mdl__list svg{
  width:19px;height:19px;margin-top:1px;flex:none;
  fill:none;stroke:var(--tick);stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:22;stroke-dashoffset:22;
}
.mdl.is-in .mdl__list svg{animation:mdltick .5s var(--ease-out-expo) forwards}
@keyframes mdltick{to{stroke-dashoffset:0}}
.mdl__list b{display:block;font-size:15.5px;font-weight:600;letter-spacing:-.01em;margin-bottom:3px}
.mdl__list span{font-size:14px;line-height:1.55;color:#fff;opacity:.86}
.mdl__aside{
  background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.26);
  border-radius:18px;padding:22px;
}
.mdl__stat b{display:block;font-size:clamp(30px,3.6vw,44px);line-height:1;letter-spacing:-.04em;font-weight:600}
.mdl__stat span{display:block;font-family:var(--mono);font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;opacity:.85;margin-top:8px}
.mdl__note{margin:18px 0 20px;font-size:14px;line-height:1.58;opacity:.94}
.mdl__aside .btn{width:100%;justify-content:center}
.mdl__fine{margin-top:12px;font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;opacity:.8;text-align:center}
/* the "See features" affordance on the card itself */
.hcell{text-align:left;font:inherit;color:inherit;border:0;width:100%}
.hcell__more{
  display:flex;align-items:center;gap:7px;margin-top:auto;padding-top:14px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  opacity:0;transform:translateY(6px);
  transition:opacity .3s var(--ease),transform .4s var(--ease-out-expo);
}

@media (hover: hover) and (pointer: fine){.hcell:hover .hcell__more,.hcell:focus-visible .hcell__more{opacity:.9;transform:none}}
.hcell__more i{font-style:normal;transition:transform .3s var(--ease)}

@media (hover: hover) and (pointer: fine){.hcell:hover .hcell__more i{transform:translateX(4px)}}
@media(max-width:820px){
  .mdl__body{grid-template-columns:minmax(0,1fr)}
  .mdl__card{width:calc(100vw - 20px);max-height:88vh;padding:24px 20px 26px;border-radius:20px}
  .mdl__x{top:10px;right:10px}
  /* touch has no hover, so the affordance is always on */
  .hcell__more{opacity:.75;transform:none}
}
@media (prefers-reduced-motion:reduce){
  .mdl__card,.mdl::backdrop{transition:none}
  .mdl.is-in .mdl__list svg{animation:none;stroke-dashoffset:0}
}


/* The card is a button; give it a real focus ring, since the lit state is now
   the keyboard-only cue and must not be the *sole* indicator. */
.hcell:focus-visible{outline:3px solid var(--blue);outline-offset:-3px;z-index:1}
.hcell:focus-visible .hcell__more{opacity:.9;transform:none}


/* ==========================================================================
   Display type
   Only the headlines. Everything that is read in quantity — body copy, UI,
   tables, the product mocks — stays in Geist, because a display face with
   personality is a liability at 14px.
   ========================================================================== */
h1,h2,
.h-xl,.h-lg,.h-md,.h-sm,
.closer__copy h2,.credo__q,.mdl__head h2,
.numcard__stat,.pricebox__n,.ba__h,
.loader__mark{
  font-family:var(--display);
  font-optical-sizing:auto;
  letter-spacing:-.035em;
  font-weight:600;
}
/* The optical-size axis already tightens the forms as they grow; pulling the
   tracking in further at display sizes is what makes it read as set rather
   than as typed. */
.h-xl,.h-lg{letter-spacing:-.05em}
.h-md,.closer__copy h2,.credo__q{letter-spacing:-.045em}
.numcard__stat,.pricebox__n{letter-spacing:-.05em;font-weight:700}


/* ==========================================================================
   Loading screen — anticipation
   The old screen ran 1.8s of status lines nobody could finish reading. This
   one holds ONE hook long enough to land, then trades it for the next.
   ========================================================================== */
.loader__hook{
  position:relative;z-index:1;
  max-width:22ch;text-align:center;
  font-family:var(--display);font-optical-sizing:auto;
  font-size:clamp(26px,5.2vw,60px);line-height:1.04;letter-spacing:-.045em;
  font-weight:600;color:#fff;text-wrap:balance;
  /* Grid, not flex: the outgoing hook and the incoming one overlap for ~340ms
     and a flex row would sit them side by side, shunting both off centre
     mid-crossfade. Stacked in one cell they cross over in place. */
  min-height:2.4em;display:grid;place-items:center;
}
.loader__hook span{
  grid-area:1/1;display:block;
  opacity:0;transform:translateY(14px);
  transition:opacity .5s var(--ease),transform .6s var(--ease-out-expo);
}
.loader__hook span.is-in{opacity:1;transform:none}
.loader__hook span.is-out{opacity:0;transform:translateY(-12px);transition-duration:.32s}
.loader__hook em{font-style:normal;color:var(--yellow)}
/* the payoff line sits bigger and brighter than the ones that set it up */
.loader__hook.is-final{font-size:clamp(30px,6vw,72px)}

.loader__mark{
  position:absolute;top:clamp(22px,4vh,40px);left:50%;transform:translateX(-50%);
  z-index:1;font-size:16px;letter-spacing:-.03em;color:rgba(255,255,255,.82);
}
.loader__mark .wm{--wm-eye:var(--blue);color:#fff}
.loader__foot{
  position:absolute;left:50%;bottom:clamp(22px,4vh,40px);transform:translateX(-50%);
  z-index:1;width:min(420px,78vw);display:flex;flex-direction:column;gap:12px;align-items:center;
}
.loader__clock{
  font-family:var(--mono);font-weight:500;
  font-size:clamp(15px,2.2vw,19px);line-height:1;letter-spacing:.02em;color:rgba(255,255,255,.9);
  font-variant-numeric:tabular-nums;display:flex;align-items:baseline;
}
.loader__clock i{font-style:normal;color:var(--yellow);margin:0 .04em;animation:blink 1s steps(1) infinite}
.loader__rail{width:100%;height:2px;background:rgba(255,255,255,.24);overflow:hidden;border-radius:2px}
.loader__rail i{display:block;height:100%;width:0;background:var(--yellow);border-radius:2px}
.loader__meta{
  width:100%;color:rgba(255,255,255,.72);
}
.loader__status{color:rgba(255,255,255,.8)}
.loader__status.is-done{color:var(--yellow)}
@media(max-width:600px){
  .loader__hook{max-width:16ch;font-size:clamp(24px,8vw,34px)}
  .loader__hook.is-final{font-size:clamp(27px,9vw,38px)}
}
@media (prefers-reduced-motion:reduce){
  .loader__hook span{transition:none;opacity:1;transform:none}
}

/* ==========================================================================
   Page transition — an iris from the click

   The panel is clipped to a circle centred on the point that was clicked, and
   that circle grows until it covers the viewport. The next document picks the
   same point up out of sessionStorage and contracts its circle back into it,
   so two separate page loads read as one movement that started under the
   reader's own cursor.

   --pt-x / --pt-y are the origin; --pt-r is the radius. Only the radius
   animates, and clip-path on a basic shape is composited, so this is one
   cheap property on one element.
   ========================================================================== */
.pt{
  /* Below the cursor (9996) and the progress bar, above everything else:
     losing the pointer for the length of a navigation is exactly the problem
     that the dialog's top-layer fix was about. */
  position:fixed;inset:0;z-index:9994;pointer-events:none;
  display:grid;place-items:center;
  visibility:hidden;
  background:
    radial-gradient(ellipse 62% 46% at 50% -6%,rgba(255,255,255,.34),transparent 62%),
    radial-gradient(ellipse 80% 60% at 50% 118%,rgba(12,52,140,.3),transparent 70%),
    linear-gradient(180deg,#175FD2 0%,#1E68D8 50%,#2472DE 100%);
  -webkit-clip-path:circle(0px at var(--pt-x,50%) var(--pt-y,50%));
  clip-path:circle(0px at var(--pt-x,50%) var(--pt-y,50%));
  will-change:clip-path;
}
.pt.is-cover,.pt.is-reveal{visibility:visible}

.pt__mark{
  font-family:var(--display);font-optical-sizing:auto;
  font-size:clamp(20px,3vw,30px);letter-spacing:-.03em;color:#fff;
  opacity:0;transform:scale(.92);
}
.pt__mark .wm{--wm-eye:var(--blue)}

/* ---- leaving: the circle opens out of the click ------------------------ */
.pt.is-cover{
  -webkit-clip-path:circle(var(--pt-r,150vmax) at var(--pt-x,50%) var(--pt-y,50%));
  clip-path:circle(var(--pt-r,150vmax) at var(--pt-x,50%) var(--pt-y,50%));
  transition:-webkit-clip-path .78s var(--ease-out-expo),clip-path .78s var(--ease-out-expo);
}
/* the mark only appears once the circle is big enough to hold it */
.pt.is-cover .pt__mark{
  opacity:1;transform:none;
  transition:opacity .34s var(--ease) .34s,transform .5s var(--ease-out-expo) .34s;
}

/* ---- arriving: fully covering, then closes back into the same point ---- */
.pt.is-reveal{
  -webkit-clip-path:circle(var(--pt-r,150vmax) at var(--pt-x,50%) var(--pt-y,50%));
  clip-path:circle(var(--pt-r,150vmax) at var(--pt-x,50%) var(--pt-y,50%));
}
.pt.is-reveal.is-go{
  -webkit-clip-path:circle(0px at var(--pt-x,50%) var(--pt-y,50%));
  clip-path:circle(0px at var(--pt-x,50%) var(--pt-y,50%));
  transition:-webkit-clip-path .86s var(--ease-out-expo),clip-path .86s var(--ease-out-expo);
}
.pt.is-reveal .pt__mark{opacity:1;transform:none}
.pt.is-reveal.is-go .pt__mark{opacity:0;transform:scale(.94);transition:opacity .26s var(--ease),transform .4s var(--ease)}

/* the page underneath still pushes back, which is what gives the circle
   somewhere to open into rather than sitting flat on top of the layout */
.pt-shell{transform-origin:50% 0;will-change:transform,filter}
body.is-leaving .pt-shell{
  transform:scale(.94) translateY(-16px);
  border-radius:22px;
  filter:brightness(.72);
  transition:transform .8s var(--ease-out-expo),filter .6s var(--ease),border-radius .4s var(--ease);
}
body.is-arriving .pt-shell{transform:scale(.955) translateY(12px);border-radius:22px}
body.is-arriving.is-settled .pt-shell{
  transform:none;border-radius:0;
  transition:transform .86s var(--ease-out-expo),border-radius .5s var(--ease) .25s;
}
body.is-leaving{overflow:hidden}

@media (prefers-reduced-motion:reduce){
  .pt{display:none}
  .pt-shell,body.is-leaving .pt-shell,body.is-arriving .pt-shell{transform:none!important;filter:none!important;border-radius:0!important;transition:none!important}
}

/* ==========================================================================
   Player — fuller control set
   ========================================================================== */
.player__btn i{
  font-style:normal;font-size:8px;font-weight:700;
  position:absolute;left:50%;top:54%;transform:translate(-50%,-50%);
  pointer-events:none;
}
.player__btn{position:relative}
.player__cc{
  font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:.04em;
  border:1px solid rgba(255,255,255,.5);border-radius:5px;min-width:30px;min-height:20px;padding:2px 5px;
}
.player__cc.is-off{opacity:.45;border-color:rgba(255,255,255,.24)}
/* Captions sit above the control bar and out of the way of the big play
   button; they are a real line, not decoration — see site.js. */
.player__caption{
  position:absolute;left:50%;bottom:76px;transform:translateX(-50%);z-index:2;
  max-width:min(80%,54ch);text-align:center;pointer-events:none;
  font-size:clamp(13px,1.5vw,16px);line-height:1.4;color:#fff;
  background:rgba(6,10,20,.72);padding:7px 14px;border-radius:8px;
  text-shadow:0 1px 2px rgba(0,0,0,.6);
}
.player.is-fs{border-radius:0}
.player.is-fs .player__stage{aspect-ratio:auto;height:100vh}
.player.is-fs .player__canvas{object-fit:contain}
.player.is-fs .player__caption{bottom:104px;font-size:clamp(15px,1.8vw,22px)}
.player.is-fs .player__bar{padding-bottom:22px}
@media(max-width:600px){
  .player__caption{bottom:66px;font-size:12.5px;padding:5px 10px;max-width:88%}
}

/* ==========================================================================
   Tutorial dialog
   ========================================================================== */
.tdlg{border:0;padding:0;background:transparent;max-width:none;max-height:none;width:100%;height:100%;overflow:visible}
.tdlg::backdrop{background:rgba(8,18,44,.68);backdrop-filter:blur(5px);opacity:0;transition:opacity .3s var(--ease)}
.tdlg[open]::backdrop{opacity:1}
.tdlg__card{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%) scale(.965);
  width:min(1060px,calc(100vw - 2 * var(--pad)));
  max-height:min(92vh,940px);overflow:auto;overscroll-behavior:contain;
  background:var(--sky-1);border-radius:22px;padding:clamp(18px,2.2vw,26px);
  opacity:0;transition:opacity .28s var(--ease),transform .42s var(--ease-out-expo);
  box-shadow:0 60px 140px -60px rgba(4,12,34,.85);
}
.tdlg.is-in .tdlg__card{opacity:1;transform:translate(-50%,-50%) scale(1)}
.tdlg__head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:16px}
.tdlg__tag{
  display:inline-block;font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--blue-deep);background:rgba(38,99,235,.1);border:1px solid rgba(38,99,235,.24);
  padding:5px 11px;border-radius:999px;margin-bottom:10px;
}
.tdlg__head h2{font-size:clamp(20px,2.6vw,30px);letter-spacing:-.035em;font-weight:600;max-width:26ch}
.tdlg__x{
  flex:none;width:44px;height:44px;border-radius:50%;border:1px solid var(--ink-14);
  background:#fff;color:var(--ink);font-size:22px;line-height:1;display:grid;place-items:center;
}

@media (hover: hover) and (pointer: fine){.tdlg__x:hover{background:var(--ink);color:#fff;border-color:var(--ink)}}
.tdlg__foot{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);gap:clamp(16px,2.4vw,32px);margin-top:18px;align-items:start}
.tdlg__foot p{font-size:14.5px;line-height:1.6;color:var(--ink-65)}
.tdlg__chaps{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:4px}
@media(max-width:820px){
  .tdlg__card{width:calc(100vw - 16px);max-height:94vh;padding:14px;border-radius:18px}
  .tdlg__foot{grid-template-columns:minmax(0,1fr)}
  .tdlg__head h2{font-size:19px}
}

/* the library cards are buttons now */
.vid{
  display:flex;flex-direction:column;text-align:left;font:inherit;color:inherit;
  border:0;background:transparent;width:100%;padding:0;
}
.vid__thumb{position:relative;cursor:inherit}
.vid:focus-visible{outline:3px solid var(--blue);outline-offset:3px;border-radius:14px}

@media (hover: hover) and (pointer: fine){.vid:hover .vid__play,.vid:focus-visible .vid__play{transform:scale(1.12);background:var(--blue);color:#fff}}
.vid__play{transition:transform .35s var(--ease-out-expo),background .3s var(--ease),color .3s var(--ease)}

/* Player controls on a phone. Measured at 375px: the buttons came out 38x38
   and the CC box 30x20, and the row overflowed so the fullscreen button was
   clipped at the right edge. Targets go to 44; the CC keeps its small visual
   box but pads its hit area out to match. */
@media(max-width:600px){
  /* was flex-wrap:nowrap, which is what pushed three controls off the right
     edge of a 375px phone with no way to scroll them back. Wrapping is the
     only honest answer when the contents do not fit. */
  .player__ctrls{gap:2px;flex-wrap:wrap;row-gap:6px;justify-content:center}
  .player__btn{min-width:44px;min-height:44px;padding:4px}
  .player__cc{
    min-width:44px;min-height:44px;border:0;padding:0;
    display:grid;place-items:center;
  }
  .player__cc::before{
    content:"CC";display:grid;place-items:center;
    width:30px;height:20px;border:1px solid rgba(255,255,255,.5);border-radius:5px;
    font-family:var(--mono);font-size:10px;font-weight:700;
  }
  .player__cc{font-size:0}
  .player__cc.is-off::before{opacity:.45;border-color:rgba(255,255,255,.24)}
  .player__t{font-size:10px;margin-left:2px;margin-right:auto}
  .player__sp{margin-left:0}
  .player__bar{padding-left:6px;padding-right:6px}
  /* Measured at 375px: six 44px targets plus a 73px time readout sum to 351
     in a 319px row, so the fullscreen button was pushed off the right edge.
     Playback speed is the one control nobody reaches for on a phone, so it
     goes rather than shrinking every target below the 44px minimum. It is
     still there at 601px and up, and the keyboard path is unaffected. */
  .player__sp{display:none}
}

/* ==========================================================================
   Player — control bar, sound, fullscreen
   ========================================================================== */

/* The stage carries the brand gradient, so an unstarted player reads as part
   of the site rather than as a black hole in the middle of the page. */
.player{
  background:
    radial-gradient(ellipse 62% 46% at 50% -6%,rgba(255,255,255,.28),transparent 62%),
    radial-gradient(ellipse 80% 60% at 50% 118%,rgba(12,52,140,.34),transparent 70%),
    linear-gradient(180deg,#175FD2 0%,#1E68D8 50%,#2472DE 100%);
}
.player__stage{background:transparent}

/* ---- the bar ------------------------------------------------------------
   Was a loose row of glyphs on a gradient. Now a single grouped control
   surface: one rounded bar, dividers between the clusters, consistent 34px
   icon buttons and a real focus ring. */
.player__bar{
  background:linear-gradient(0deg,rgba(6,10,20,.94) 0%,rgba(6,10,20,.72) 58%,transparent 100%);
  padding:44px clamp(10px,1.4vw,16px) clamp(10px,1.4vw,14px);
}
.player__ctrls{
  display:flex;align-items:center;gap:4px;color:#fff;
  background:rgba(255,255,255,.08);
  border:1px solid rgba(255,255,255,.14);
  border-radius:14px;
  padding:5px 8px;
  backdrop-filter:blur(10px);
}
.player__btn{
  width:34px;height:34px;min-width:34px;min-height:34px;padding:0;
  border-radius:9px;display:grid;place-items:center;
  background:transparent;border:0;color:#fff;font-size:14px;line-height:1;
  transition:background .2s var(--ease),transform .2s var(--ease);
}

@media (hover: hover) and (pointer: fine){.player__btn:hover{background:rgba(255,255,255,.16)}}
.player__btn:active{transform:scale(.94)}
.player__btn:focus-visible{outline:2px solid #fff;outline-offset:2px}
.player__btn svg{width:17px;height:17px;fill:currentColor}
/* the 10 inside the skip arrows */
.player__btn i{font-size:7.5px;font-weight:700;top:56%}

/* dividers group the clusters without drawing boxes round them */
.player__t{
  padding:0 10px;margin:0;font-size:11.5px;
  border-left:1px solid rgba(255,255,255,.16);
  border-right:1px solid rgba(255,255,255,.16);
}
.player__chap{padding-left:10px;opacity:.72}
.player__vol{margin-left:auto}
/* input.player__volin, not .player__volin: there is an input[type="range"]
   rule setting 28px, and an attribute selector outranks a bare class. The
   tag prefix buys the one point of specificity needed to win it. */
input.player__volin{
  -webkit-appearance:none;appearance:none;
  width:74px;height:44px;background:transparent;cursor:pointer;margin:0 4px 0 0;
}
.player__volin::-webkit-slider-runnable-track{height:3px;border-radius:3px;background:rgba(255,255,255,.3)}
.player__volin::-moz-range-track{height:3px;border-radius:3px;background:rgba(255,255,255,.3)}
.player__volin::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:12px;height:12px;border-radius:50%;
  background:#fff;margin-top:-4.5px;box-shadow:0 1px 4px rgba(0,0,0,.5);
}
.player__volin::-moz-range-thumb{width:12px;height:12px;border-radius:50%;background:#fff;border:0}
.player__volin:focus-visible{outline:2px solid #fff;outline-offset:2px;border-radius:6px}
.player__vol.is-off{opacity:.5}
.player__cc{
  font-family:var(--mono);font-size:9.5px;font-weight:700;letter-spacing:.02em;
  border:1px solid rgba(255,255,255,.55);border-radius:5px;
  width:auto;min-width:30px;height:19px;min-height:19px;padding:0 5px;margin:0 2px;
}
.player__sp{font-family:var(--mono);font-size:11px;width:auto;min-width:34px;padding:0 6px}

/* The control bar did not fit. Measured on a 375px phone: 466px of controls
   in a 281px bar, which put the captions toggle, the speed control and
   fullscreen past the right edge with nothing to scroll them into view. Three
   of the nine controls were simply unreachable, and the two that most need to
   be reachable on a phone — captions and fullscreen — were two of them.

   Two changes buy it back. The volume SLIDER goes, because a phone has volume
   buttons on its side and every native player drops the slider for exactly
   this reason; the Mute button stays, so nothing is lost that the hardware
   does not already do better. And the bar is allowed to wrap, so the fit can
   never silently fail again at a width nobody tested. */
.player__ctrls{flex-wrap:wrap;row-gap:6px;justify-content:center}
input.player__volin{display:none}

/* the scrub sits above the bar, full width */
/* 34px, not 18: a seek bar you cannot land on is one you scroll the page
   with by accident. The visible track stays 3px — only the target grew. */
.player__scrub{margin-bottom:10px;height:34px}
.player__track{height:3px}
.player.is-playing .player__track{height:3px}

/* ---- fullscreen ---------------------------------------------------------
   .is-fs covers BOTH paths: native (where the element is already promoted)
   and the CSS fallback, which has to pin itself. */
html.has-fsplayer,html.has-fsplayer body{overflow:hidden}
.player.is-fs{
  position:fixed;inset:0;z-index:10001;border-radius:0;
  width:100vw;height:100dvh;max-width:none;
}
.player.is-fs .player__stage{aspect-ratio:auto;height:100%;width:100%}
.player.is-fs .player__canvas{object-fit:contain}
.player.is-fs .player__bar{padding-bottom:clamp(16px,3vh,28px)}
.player.is-fs .player__caption{bottom:110px;font-size:clamp(15px,1.8vw,22px)}
/* :fullscreen so the native path gets the same treatment without a class */
.player:fullscreen{width:100vw;height:100vh;border-radius:0}
.player:fullscreen .player__stage{aspect-ratio:auto;height:100%}

/* Rotate-to-landscape. Used only when the Screen Orientation lock is
   unavailable — iOS, and any browser outside native fullscreen. The player is
   sized to the viewport's OPPOSITE axes and turned a quarter, which is what
   video apps did before the orientation API existed. */
.player.is-fs.is-rotated{
  width:100dvh;height:100vw;
  top:50%;left:50%;inset:auto;
  transform:translate(-50%,-50%) rotate(90deg);
  transform-origin:center center;
}

/* A transformed ancestor becomes the containing block for position:fixed
   descendants, so a player going fullscreen inside the tutorial dialog was
   pinned to the dialog CARD rather than to the viewport — it came out
   clipped and portrait-sized. While a player is fullscreen the card drops its
   transform and its clipping, so the fixed player resolves against the
   viewport as intended. The card is fully covered at that point, so losing
   its centring is invisible. */
/* The card is no longer touched — the player steps out of it while
   fullscreen (see detachForFs in site.js), because overriding the card's
   transform made it animate across the screen on the way in and out.

   It is hidden outright for the duration. Removing the player changes the
   card's content height, so it would otherwise re-centre itself behind the
   fullscreen player; hidden, there is no box left to reflow and nothing that
   can appear at the edges. visibility (not display) keeps its layout box, so
   the dialog does not resize underneath. */
html.has-fsplayer .tdlg{overflow:visible}
html.has-fsplayer .tdlg__card{visibility:hidden}
html.has-fsplayer .tdlg::backdrop{background:#000}



/* Inside a fullscreen player the cursor is a child of the player, so it needs
   to sit above the player's own content — the z-index it carries on body
   (9996) is meaningless in that new stacking context. */
.player.is-fs > .cursor-layer{z-index:20}
.player.is-fs > .cursor-arrow,
.player.is-fs > .cursor-tag{z-index:21}


/* ==========================================================================
   Video cards — the gradient, the way the feature cards do it

   The thumbnails were flat pastel fills. They now carry a brand gradient per
   track, and the card answers a pointer the same way an .hcell does: a blue
   fill wipes up from the bottom edge under a pointer-tracked spotlight.
   ========================================================================== */
.vid{position:relative;isolation:isolate;overflow:hidden;border-radius:16px}
.vid::before{
  content:"";position:absolute;inset:0;z-index:-2;background:var(--blue);
  transform:translateY(101%);
  transition:transform .52s var(--ease-out-expo);
}

@media (hover: hover) and (pointer: fine){.vid:hover::before,.vid:focus-visible::before{transform:translateY(0)}}
.vid::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;opacity:0;
  transition:opacity .35s var(--ease);
  background:radial-gradient(260px circle at var(--mx,50%) var(--my,50%),
             rgba(255,255,255,.16),transparent 70%);
}

@media (hover: hover) and (pointer: fine){.vid:hover::after{opacity:1}}

@media (hover: hover) and (pointer: fine){.vid:hover,.vid:focus-visible{color:#fff}}
.vid:hover .vid__body p,.vid:hover .vid__meta span,

@media (hover: hover) and (pointer: fine){.vid:hover .vid__chaps span{color:rgba(255,255,255,.84)}}

@media (hover: hover) and (pointer: fine){.vid:hover .vid__meta b{color:var(--yellow)}}

@media (hover: hover) and (pointer: fine){.vid:hover .vid__chaps span{background:rgba(255,255,255,.16);border-color:transparent}}
/* Keep the dashed edge on hover: it is the whole signal, and the hover state
   was flattening it into an ordinary chapter. */

@media (hover: hover) and (pointer: fine){.vid:hover .vid__chaps span.is-soon{background:transparent;border-color:rgba(255,255,255,.45)}}

/* the thumbnail itself: a gradient per track rather than a flat tint */
.vid__thumb{
  background-image:linear-gradient(152deg,var(--t1),var(--t2));
  transition:transform .6s var(--ease-out-expo);
}

@media (hover: hover) and (pointer: fine){.vid:hover .vid__thumb{transform:scale(1.03)}}
.vid[data-track="Setup"]    {--t1:#BFD4FB;--t2:#5E8DF0}
.vid[data-track="Workforce"]{--t1:#CFC7F3;--t2:#7A6BE0}
.vid[data-track="Time"]     {--t1:#BFE3D2;--t2:#4FA987}
.vid[data-track="Payroll"]  {--t1:#F7E6B8;--t2:#D8A63C}
.vid[data-track="Billing"]  {--t1:#F6C9C9;--t2:#DC6A6A}
@media(hover:none){
  .vid::before,.vid::after{display:none}
  .vid:hover{color:inherit}
  .vid:hover .vid__body p,.vid:hover .vid__meta span{color:var(--ink-65)}
}

/* ==========================================================================
   Ad slot — the featured video, framed and centred
   The chapter rail is gone: this is an advert, not a lesson, so the only
   thing beside the picture is the reason to click.
   ========================================================================== */
.adslot{
  max-width:940px;margin:0 auto;text-align:center;
  display:flex;flex-direction:column;align-items:center;
  padding:clamp(18px,2.4vw,30px);
  border-radius:26px;
  background:
    radial-gradient(ellipse 62% 46% at 50% -6%,rgba(255,255,255,.34),transparent 62%),
    radial-gradient(ellipse 80% 60% at 50% 118%,rgba(12,52,140,.3),transparent 70%),
    linear-gradient(180deg,#175FD2 0%,#1E68D8 50%,#2472DE 100%);
  box-shadow:0 50px 110px -60px rgba(8,22,60,.6);
}
.adslot__label{
  display:inline-flex;align-items:center;gap:9px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.15em;text-transform:uppercase;
  color:#fff;background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.34);
  padding:6px 13px;border-radius:999px;margin-bottom:clamp(14px,1.8vw,20px);
}
.adslot__label i{width:6px;height:6px;border-radius:50%;background:var(--yellow);display:block}
.adslot .player{width:100%;box-shadow:0 30px 70px -34px rgba(4,12,34,.75)}
.adslot__cap{
  margin:clamp(18px,2.4vw,26px) auto 0;max-width:56ch;
  font-size:clamp(15px,1.7vw,17.5px);line-height:1.55;color:#fff;
}
.adslot .btn{margin-top:20px}
.adslot__fine{
  margin-top:12px;font-family:var(--mono);font-size:10px;
  letter-spacing:.1em;text-transform:uppercase;color:#fff;opacity:.9;
}
/* the ad sits under the fixed header */
.adslot{margin-top:clamp(6px,1.4vw,16px)}
@media(max-width:700px){
  .adslot{padding:14px;border-radius:20px}
  .adslot__cap{font-size:14.5px}
}

/* The filename label was ink-62 on a flat pastel. Against the saturated
   gradients it measured 2.44-3.40:1 — under AA on every track. It gets the
   same treatment the duration badge already had: white on a dark scrim, which
   is independent of whatever the thumbnail is doing behind it. */
.vid__slot{
  color:#fff;background:rgba(8,18,44,.58);
  padding:3px 8px;border-radius:5px;
  backdrop-filter:blur(2px);
}

@media (hover: hover) and (pointer: fine){.vid:hover .vid__slot{background:rgba(8,18,44,.72)}}

/* ==========================================================================
   Tutorial dialog — on the gradient
   The opened video box now carries the same ramp as the ad slot, so the two
   ways of watching a tutorial look like one thing. Everything inside inverts
   to white; the chapter buttons and the close control become glass.
   ========================================================================== */
.tdlg__card{
  background:
    radial-gradient(ellipse 62% 46% at 50% -6%,rgba(255,255,255,.32),transparent 62%),
    radial-gradient(ellipse 52% 40% at 88% 18%,rgba(154,204,255,.28),transparent 68%),
    radial-gradient(ellipse 80% 60% at 50% 118%,rgba(12,52,140,.32),transparent 70%),
    linear-gradient(180deg,#175FD2 0%,#1E68D8 50%,#2472DE 100%);
  color:#fff;
}
.tdlg__head h2{color:#fff}
/* Dark glass, not light. A white overlay LIGHTENS the ramp underneath, which
   pushed white text on these chips down to 2.4-4.1:1; tinting them darker
   moves it the other way. */
.tdlg__tag{
  color:#fff;background:rgba(8,18,44,.34);border-color:rgba(255,255,255,.34);
}
.tdlg__x{
  background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.4);color:#fff;
}

@media (hover: hover) and (pointer: fine){.tdlg__x:hover{background:#fff;border-color:#fff;color:var(--ink)}}
.tdlg__foot p{color:#fff;opacity:1}

/* chapter buttons become glass on the gradient */
.tdlg__chaps .chap{background:rgba(8,18,44,.34);border:1px solid rgba(255,255,255,.16)}

@media (hover: hover) and (pointer: fine){.tdlg__chaps .chap:hover{background:rgba(8,18,44,.46);border-color:rgba(255,255,255,.38)}}
.tdlg__chaps .chap.is-on{background:rgba(8,18,44,.55);border-color:rgba(255,255,255,.5)}
.tdlg__chaps .chap__time{color:rgba(255,255,255,.88)}
.tdlg__chaps .chap__t{color:#fff}
.tdlg__chaps .chap.is-on .chap__t{color:var(--yellow);font-weight:600}

/* the player sits ON the gradient, so it needs an edge of its own to read as
   a screen rather than a hole cut in the panel */
.tdlg .player{
  box-shadow:0 24px 60px -28px rgba(4,12,34,.8),0 0 0 1px rgba(255,255,255,.18);
}

/* ==========================================================================
   Legal documents — privacy, terms, cookies
   A reading layout, not a marketing layout: one column at a comfortable
   measure, a sticky table of contents beside it on wide screens, and numbered
   clauses that can be cited in an email ("see 4.2") without ambiguity.
   ========================================================================== */
.doc{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(28px,4vw,56px)}
@media(min-width:1000px){
  .doc{grid-template-columns:210px minmax(0,1fr)}
}
.doc__nav{display:none}
@media(min-width:1000px){
  .doc__nav{display:block;position:sticky;top:calc(var(--headerH) + 16px);align-self:start}
}
.doc__nav b{
  display:block;font-family:var(--mono);font-size:10.5px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-55);padding-bottom:10px;margin-bottom:10px;
  border-bottom:1px solid var(--ink-12);
}
.doc__nav a{
  display:block;font-size:13.5px;line-height:1.45;color:var(--ink-65);
  text-decoration:none;padding:6px 0;transition:color .2s var(--ease);
}

@media (hover: hover) and (pointer: fine){.doc__nav a:hover{color:var(--blue)}}

.doc__body{max-width:72ch}
.doc__meta{
  display:flex;flex-wrap:wrap;gap:8px 22px;font-family:var(--mono);font-size:11px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink-55);
  padding-bottom:18px;margin-bottom:30px;border-bottom:1px solid var(--ink-12);
}
.doc__intro{font-size:17px;line-height:1.62;color:var(--ink);margin:0 0 8px}
.doc h2{
  font-size:clamp(19px,2.2vw,25px);letter-spacing:-.025em;font-weight:600;
  margin:44px 0 14px;scroll-margin-top:calc(var(--headerH) + 20px);
}
.doc h2 i{
  font-style:normal;font-family:var(--mono);font-size:.62em;font-weight:500;
  color:var(--blue);margin-right:12px;letter-spacing:0;
}
.doc h3{font-size:16px;font-weight:600;letter-spacing:-.015em;margin:26px 0 8px}
.doc p{font-size:15px;line-height:1.68;color:var(--ink-72);margin:0 0 14px}
.doc ul,.doc ol{margin:0 0 16px;padding-left:22px}
.doc li{font-size:15px;line-height:1.66;color:var(--ink-72);margin-bottom:8px}
.doc li strong,.doc p strong{color:var(--ink);font-weight:600}
.doc a{color:var(--blue);text-decoration:underline;text-underline-offset:2px}
.doc code{font-family:var(--mono);font-size:13px;background:var(--surface);padding:2px 6px;border-radius:5px}

/* the one thing a reader must not miss: a fact the operator still has to supply */
.doc mark{
  background:rgba(235,38,38,.1);color:var(--red);border:1px solid rgba(235,38,38,.22);
  border-radius:5px;padding:1px 7px;font-family:var(--mono);font-size:12.5px;font-weight:500;
}
/* A tinted panel rather than a coloured tab down one edge. The 3px blue
   border-left is the generic "callout" costume; the note earns attention
   from its own surface instead, and the shape is no longer half a card. */
.doc__note{
  border:1px solid rgba(38,99,235,.22);
  border-radius:10px;padding:18px 20px;margin:0 0 34px;background:rgba(38,99,235,.05);
}
.doc__note p{margin:0;font-size:14.5px;color:var(--ink-72)}
.doc__note b{color:var(--ink)}

.doc__tbl{overflow-x:auto;margin:0 0 20px;border:1px solid var(--ink-12);border-radius:10px;background:#fff}
.doc__tbl table{border-collapse:collapse;width:100%;font-size:14px;min-width:460px}
.doc__tbl th{
  /* 12px, not 10.5px: these head the retention and rights tables in the
     privacy policy and the terms — the two tables a customer is most likely
     to actually read, at the moment they are deciding whether to trust us.
     Uppercase mono at 10.5px is a label size, not a reading size. */
  text-align:left;font-family:var(--mono);font-size:12px;font-weight:600;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-55);padding:11px 16px;border-bottom:1px solid var(--ink-12);
}
.doc__tbl td{padding:11px 16px;border-bottom:1px solid var(--ink-10);color:var(--ink-72);line-height:1.55}
.doc__tbl tr:last-child td{border-bottom:0}

/* A store button with no store behind it. It keeps the shape of the real ones
   so the row still reads as a set, but it is not a link, does not take focus,
   and says plainly that there is nothing to download yet. */
.store--soon{cursor:default;opacity:.62;position:relative}

@media (hover: hover) and (pointer: fine){.store--soon:hover{transform:none;box-shadow:none}}
.store__soon{
  font-family:var(--mono);font-style:normal;font-size:9px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;
  border:1px solid currentColor;border-radius:999px;padding:2px 6px;
  margin-left:10px;opacity:.8;align-self:center;
}

/* ==========================================================================
   Custom select
   The native popup is drawn by the OS and cannot be styled, so the real
   <select> is kept for submission and hidden, and this listbox is drawn over
   it. See customSelects() in site.js for the keyboard contract.
   ========================================================================== */
.sel{position:relative}
.sel__native{position:absolute;opacity:0;pointer-events:none;width:1px;height:1px;overflow:hidden}
.sel__btn{
  display:flex;align-items:center;gap:12px;width:100%;min-height:52px;
  padding:13px 15px;text-align:left;cursor:pointer;
  font-family:var(--sans);font-size:15px;color:var(--ink);
  background:var(--sky-1);border:1px solid var(--ink-14);border-radius:12px;
  transition:border-color .18s var(--ease),box-shadow .18s var(--ease),background .18s var(--ease);
}

@media (hover: hover) and (pointer: fine){.sel__btn:hover{border-color:var(--ink-18);background:#fff}}
.sel.is-open .sel__btn,.sel__btn:focus-visible{
  outline:none;background:#fff;border-color:var(--blue);box-shadow:0 0 0 3px rgba(38,99,235,.15);
}
.sel__val{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sel.is-empty .sel__val{color:var(--ink-50)}
.sel__caret{
  flex:none;width:9px;height:9px;border-right:1.8px solid var(--ink-55);border-bottom:1.8px solid var(--ink-55);
  transform:rotate(45deg) translate(-2px,-2px);transition:transform .24s var(--ease-out-expo);
}
.sel.is-open .sel__caret{transform:rotate(-135deg) translate(-3px,-3px)}

.sel__list{
  position:absolute;z-index:40;top:calc(100% + 7px);left:0;right:0;
  max-height:302px;overflow-y:auto;overscroll-behavior:contain;
  background:#fff;border:1px solid var(--ink-12);border-radius:14px;
  box-shadow:0 30px 64px -28px rgba(12,30,80,.5),0 2px 6px rgba(12,30,80,.06);
  padding:6px;
  opacity:0;visibility:hidden;transform:translateY(-6px) scale(.985);transform-origin:50% 0;
  transition:opacity .17s var(--ease),transform .26s var(--ease-out-expo),visibility .17s;
}
.sel.is-open .sel__list{opacity:1;visibility:visible;transform:none}
.sel__opt{
  display:flex;align-items:flex-start;gap:11px;padding:10px 11px;border-radius:9px;
  cursor:pointer;position:relative;
}
.sel__opt.is-on{background:var(--sky-2)}
.sel__opt.is-sel{background:rgba(38,99,235,.07)}
.sel__dot{
  flex:none;width:7px;height:7px;border-radius:50%;background:var(--blue);margin-top:6px;
  transition:transform .2s var(--ease);
}
.sel__opt--warn .sel__dot{background:var(--yellow)}
.sel__opt--alert .sel__dot{background:var(--red)}
.sel__opt.is-on .sel__dot{transform:scale(1.35)}
.sel__text{flex:1;min-width:0}
.sel__text b{display:block;font-size:14.5px;font-weight:600;letter-spacing:-.012em;line-height:1.35}
.sel__text small{display:block;font-size:12.5px;line-height:1.45;color:var(--ink-55);margin-top:2px}
.sel__tick{flex:none;width:16px;height:16px;color:var(--blue);opacity:0;transform:scale(.6);margin-top:3px;
  transition:opacity .18s var(--ease),transform .3s var(--ease-out-expo)}
.sel__tick svg{width:100%;height:100%;display:block}
.sel__opt.is-sel .sel__tick{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .sel__list,.sel__caret,.sel__dot,.sel__tick{transition:none}
}

/* ==========================================================================
   Contact — "watch it route"
   The page is one object: a form on the left, and a panel on the right that
   answers, live, the question every contact form leaves unanswered — where is
   this going and when will somebody read it. Choosing a topic is therefore
   functional, not decorative, which is the whole reason the select got built.
   ========================================================================== */
.cx{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(26px,3.4vw,44px);align-items:start}
@media(min-width:980px){.cx{grid-template-columns:minmax(0,1.5fr) minmax(0,1fr)}}

.cx__form{
  background:#fff;border:1px solid var(--ink-12);border-radius:22px;
  padding:clamp(22px,3vw,38px);
  box-shadow:0 34px 70px -52px rgba(12,30,80,.55);
}
.fgrid{display:grid;grid-template-columns:minmax(0,1fr);gap:18px}
@media(min-width:600px){.fgrid--2{grid-template-columns:1fr 1fr}}
/* A <legend> is not a grid item — browsers lift it out of the box's flow — so
   the fieldset lays out as a block and its children space themselves. Using a
   div instead would have lost the group name for screen readers. */
.fset{border:0;padding:0;margin:0 0 26px;display:block}
.fset:last-of-type{margin-bottom:0}
.fset > * + *{margin-top:18px}
.fset__h{
  font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-50);
  display:flex;align-items:center;gap:12px;width:100%;padding:0;margin:0 0 16px;
}
.fset__h::after{content:"";flex:1;height:1px;background:var(--ink-10)}

.fld{display:flex;flex-direction:column;gap:7px;min-width:0}
.fld > label{
  font-family:var(--mono);font-size:10.5px;font-weight:600;letter-spacing:.13em;
  text-transform:uppercase;color:var(--ink-55);
}
.fld .req{color:var(--red);margin-left:3px}
.fld input,.fld textarea{
  font-family:var(--sans);
  /* 16px minimum on touch: iOS Safari zooms the page when a focused field is
     smaller, which throws the layout off-screen on every tap. Not a type
     decision — a platform one. */
  font-size:15px;color:var(--ink);width:100%;
  background:var(--sky-1);border:1px solid var(--ink-14);border-radius:12px;
  padding:13px 15px;min-height:52px;
  transition:border-color .18s var(--ease),box-shadow .18s var(--ease),background .18s var(--ease);
}
.fld textarea{min-height:146px;resize:vertical;line-height:1.62}

@media (hover: hover) and (pointer: fine){.fld input:hover,.fld textarea:hover{border-color:var(--ink-18);background:#fff}}
.fld input:focus,.fld textarea:focus{
  outline:none;background:#fff;border-color:var(--blue);box-shadow:0 0 0 3px rgba(38,99,235,.15);
}
.fld__hint{font-size:12.5px;color:var(--ink-55);line-height:1.5}
.fld__err{font-size:12.5px;color:var(--red);font-weight:500;display:none}
.fld.is-bad input,.fld.is-bad textarea{border-color:var(--red);box-shadow:0 0 0 3px rgba(235,38,38,.12)}
.fld.is-bad .sel__btn{border-color:var(--red);box-shadow:0 0 0 3px rgba(235,38,38,.12)}
.fld.is-bad .fld__err{display:block}
.fld__count{font-family:var(--mono);font-size:11px;color:var(--ink-50);text-align:right;
  font-variant-numeric:tabular-nums}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

.cx__foot{display:flex;flex-wrap:wrap;align-items:center;gap:16px;margin-top:24px;
  padding-top:22px;border-top:1px solid var(--ink-10)}
.cx__legal{font-size:12.5px;color:var(--ink-55);line-height:1.55;flex:1 1 230px;min-width:0}
.cx__legal a{color:var(--blue)}

.cx__msg{display:none;border-radius:14px;padding:17px 19px;margin-bottom:22px;font-size:14.5px;line-height:1.6}
.cx__msg.is-on{display:block}
.cx__msg--ok{background:rgba(6,118,71,.08);border:1px solid rgba(6,118,71,.26);color:#05603A}
.cx__msg--bad{background:rgba(235,38,38,.07);border:1px solid rgba(235,38,38,.24);color:#9B1C1C}
.cx__msg b{font-weight:600}
.cx__msg a{color:inherit;text-decoration:underline}

/* ---- the routing panel ---- */
.rt{position:relative}
@media(min-width:980px){.rt{position:sticky;top:calc(var(--headerH) + 16px)}}
.rt__card{
  border-radius:20px;padding:clamp(20px,2.4vw,28px);color:#fff;overflow:hidden;position:relative;
  background:
    radial-gradient(ellipse 62% 46% at 50% -6%,rgba(255,255,255,.34),transparent 62%),
    radial-gradient(ellipse 70% 52% at 14% 96%,rgba(12,52,140,.34),transparent 68%),
    linear-gradient(180deg,#175FD2 0%,#1E68D8 52%,#2472DE 100%);
  box-shadow:0 34px 70px -48px rgba(12,30,80,.8);
}
.rt__k{
  font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:rgba(255,255,255,.62);margin:0 0 14px;
  display:flex;align-items:center;gap:9px;
}
.rt__k i{width:6px;height:6px;border-radius:50%;background:var(--tick);display:block;flex:none}
.rt__desk{font-size:clamp(19px,2.2vw,24px);font-weight:600;letter-spacing:-.03em;line-height:1.12;margin:0 0 9px}
.rt__desc{font-size:14px;line-height:1.6;color:rgba(255,255,255,.82);margin:0}
.rt__meta{display:grid;grid-template-columns:1fr 1fr;gap:1px;margin-top:20px;
  background:rgba(255,255,255,.18);border:1px solid rgba(255,255,255,.18);border-radius:12px;overflow:hidden}
.rt__cell{background:rgba(10,44,120,.28);padding:12px 14px}
.rt__cell b{display:block;font-family:var(--mono);font-size:9.5px;font-weight:600;letter-spacing:.13em;
  text-transform:uppercase;color:rgba(255,255,255,.6);margin-bottom:5px}
.rt__cell span{display:block;font-size:14px;font-weight:500;letter-spacing:-.01em}
.rt__tips{margin:18px 0 0;padding:0;list-style:none;display:grid;gap:8px}
.rt__tips li{display:flex;gap:9px;font-size:13.5px;line-height:1.55;color:rgba(255,255,255,.86)}
.rt__tips li::before{content:"";flex:none;width:5px;height:5px;border-radius:50%;
  background:rgba(255,255,255,.55);margin-top:7px}
.rt__swap{transition:opacity .24s var(--ease),transform .34s var(--ease-out-expo)}
.rt.is-swapping .rt__swap{opacity:0;transform:translateY(6px)}

.rt__other{margin-top:20px;border-top:1px solid var(--ink-12);padding-top:18px}
.rt__other h3{font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-50);margin:0 0 12px}
.rt__line{display:flex;gap:10px;align-items:baseline;font-size:13.5px;line-height:1.55;
  color:var(--ink-65);padding:7px 0}
.rt__line b{color:var(--ink);font-weight:600;flex:none;min-width:8.5ch}
.rt__line a{color:var(--blue)}
@media (prefers-reduced-motion:reduce){.rt__swap{transition:none}}

/* ==========================================================================
   Scrollbars
   The page scrollbar is hidden: the site drives its own eased scroll and
   already shows position in the progress rule at the top of the viewport, so
   the native bar was a second, competing indicator.

   Inner scrollers KEEP a bar, slimmed and themed. Hiding those too would have
   removed the only clue that a dropdown list or a dialog has more content
   below the fold — the page bar is redundant, an overflow bar is information.
   ========================================================================== */
html{
  scrollbar-width:none;              /* Firefox */
  -ms-overflow-style:none;           /* legacy Edge */
}
html::-webkit-scrollbar,
body::-webkit-scrollbar{width:0;height:0;display:none}

/* Anything that scrolls inside the page gets the slim treatment instead. */
.sel__list,.mdl__card,.tdlg__card,.chaps,.tw,.doc__tbl,
.player__chapters,.navdrop__inner,.mobilepanel{
  scrollbar-width:thin;
  scrollbar-color:rgba(30,30,30,.26) transparent;
}
.sel__list::-webkit-scrollbar,.mdl__card::-webkit-scrollbar,
.tdlg__card::-webkit-scrollbar,.chaps::-webkit-scrollbar,
.tw::-webkit-scrollbar,.doc__tbl::-webkit-scrollbar,
.player__chapters::-webkit-scrollbar,.navdrop__inner::-webkit-scrollbar,
.mobilepanel::-webkit-scrollbar{width:9px;height:9px;display:block}
.sel__list::-webkit-scrollbar-track,.mdl__card::-webkit-scrollbar-track,
.tdlg__card::-webkit-scrollbar-track,.chaps::-webkit-scrollbar-track,
.tw::-webkit-scrollbar-track,.doc__tbl::-webkit-scrollbar-track,
.player__chapters::-webkit-scrollbar-track,.navdrop__inner::-webkit-scrollbar-track,
.mobilepanel::-webkit-scrollbar-track{background:transparent}
.sel__list::-webkit-scrollbar-thumb,.mdl__card::-webkit-scrollbar-thumb,
.tdlg__card::-webkit-scrollbar-thumb,.chaps::-webkit-scrollbar-thumb,
.tw::-webkit-scrollbar-thumb,.doc__tbl::-webkit-scrollbar-thumb,
.player__chapters::-webkit-scrollbar-thumb,.navdrop__inner::-webkit-scrollbar-thumb,
.mobilepanel::-webkit-scrollbar-thumb{
  background:rgba(30,30,30,.24);border-radius:99px;
  border:2px solid transparent;background-clip:content-box;
}
.sel__list::-webkit-scrollbar-thumb:hover,.mdl__card::-webkit-scrollbar-thumb:hover,
.tdlg__card::-webkit-scrollbar-thumb:hover,.tw::-webkit-scrollbar-thumb:hover,

@media (hover: hover) and (pointer: fine){.doc__tbl::-webkit-scrollbar-thumb:hover{background:rgba(38,99,235,.5);background-clip:content-box}}

/* On the dark surfaces the same thumb would disappear. */
.mdl__card,.tdlg__card,.mobilepanel{scrollbar-color:rgba(255,255,255,.34) transparent}
.mdl__card::-webkit-scrollbar-thumb,.tdlg__card::-webkit-scrollbar-thumb,
.mobilepanel::-webkit-scrollbar-thumb{background:rgba(255,255,255,.32);background-clip:content-box}

/* ==========================================================================
   Stat band → the section below: the hand-off
   The card no longer stops dead against the page because it is white on white,
   so this is a soft ground shadow rather than a tonal band: it carries the
   sky's tint a little further down and dissolves.

   Two masks, not one rectangle — the vertical gradient ends fully transparent
   and the horizontal mask pulls it to nothing at the left and right edges, so
   the strip has no sides to give itself away. That is the lesson from the weld
   strips removed earlier: a transition that ends on a visible edge is worse
   than no transition at all.
   ========================================================================== */
.metricband{position:relative}
.metricband .wrap{position:relative}
.metricband .wrap::after{
  content:"";position:absolute;z-index:-1;
  left:0;right:0;top:calc(100% - 22px);
  height:clamp(84px,10vw,140px);
  pointer-events:none;
  background:linear-gradient(180deg,
    rgba(var(--lav),.20) 0%,
    rgba(var(--lav),.11) 36%,
    rgba(var(--lav),.04) 66%,
    transparent 100%);
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 12%,#000 88%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 12%,#000 88%,transparent 100%);
  filter:blur(7px);
}
@media(max-width:900px){
  .metricband .wrap::after{top:calc(100% - 16px);height:clamp(64px,14vw,104px)}
}


/* ---- Phone: form fields at 16px, after the .fld rule above so it wins on
   order rather than on !important. iOS Safari zooms a focused field under
   16px and takes the whole page with it. ---- */
@media(max-width:760px){
  .fld input,.fld textarea,.fld select,.sel__btn{font-size:16px}
}

/* ══════════════════════════════════════════════════════════════════════════
 * The hero's two small lines, on a phone
 *
 * THE TRUST LINE broke in the wrong place. "7 days free · Cancel anytime ·
 * India · Canada · USA" is one run of text centred in 331px, so the browser
 * broke it wherever it ran out of room — which put a separator at the START
 * of the second line: "India / · Canada · USA". A line that opens with a
 * middot reads as a bullet somebody forgot to finish.
 *
 * It is a wrapping flex row now, one item per claim. Each item is
 * unbreakable and carries its own separator behind it, so a break can only
 * ever happen BETWEEN claims and a line can never begin with a dot. The
 * separator is a pseudo-element rather than text, which also takes it out of
 * the accessibility tree — a screen reader reads five claims instead of
 * spelling out four middots.
 * ══════════════════════════════════════════════════════════════════════════ */
.hero__trust{
  display:flex;flex-wrap:wrap;justify-content:center;align-items:baseline;
  column-gap:8px;row-gap:2px;
}
/*
 * Two groups: what the trial costs, then where it runs. On a wide screen
 * they read as one line and nothing about them looks grouped; on a phone the
 * line has to break somewhere, and the only sensible place is between the
 * offer and the countries rather than in the middle of either.
 */
.hero__trust .grp{
  display:inline-flex;flex-wrap:wrap;justify-content:center;align-items:baseline;
  column-gap:8px;
}
.hero__trust span{white-space:nowrap}
/* A separator belongs to the item in front of it, so a break can never put
   one at the start of a line. Scoped within the group, so neither group ends
   on a dangling dot when they are stacked. */
.hero__trust .grp > span:not(:last-child)::after{content:'·';margin-left:8px;opacity:.55}
/* The join between the two groups, which only exists while they share a line. */
.hero__trust .grp + .grp::before{content:'·';margin-right:8px;opacity:.55}

@media (max-width: 760px){
  /*
   * `align-items`, not `justify-content`. Turning this into a column swaps
   * which axis each one governs — `justify-content:center` from the base
   * rule now centres the two rows vertically inside a box exactly tall
   * enough to hold them, which does nothing, and the rows sat hard against
   * the left edge under a centred hero.
   */
  .hero__trust{flex-direction:column;row-gap:4px;align-items:center}
  .hero__trust .grp + .grp::before{content:none}
}

/*
 * THE HERO PILL'S SPACING, which was the thing that looked wrong about it.
 *
 * `.pill` is a flex row with a gap, and the live clock is a `<span>` in the
 * middle of the sentence — so the sentence was not one flex item, it was
 * three: the words before the clock, the clock, and the words after it. The
 * gap then applied between each, punching an 8px hole either side of the
 * time on top of the word spaces already there. "It's  3:57pm  — payroll…"
 * with the time floating in the middle of two double-wide gaps.
 *
 * The sentence is one element now, so the gap only separates the three
 * things it is meant to: the dot, the sentence and the badge.
 */
.pill__text{min-width:0}

/* ══════════════════════════════════════════════════════════════════════════
 * THE HERO PILL already wrapped on a phone — that is deliberate, and set
 * above at 720px. What it did not do was wrap *well*.
 *
 * The version badge is a flex item and the sentence beside it is one
 * anonymous item, so with `align-items:center` the badge floated at the
 * vertical middle of a two-line block, level with neither line and attached
 * to nothing. And the sentence broke wherever it ran out of room, which put
 * "already approved" alone on the second line under a nearly full first one.
 *
 * `balance` evens the two lines, and aligning to the first line puts the
 * badge where the eye expects it — beside the start of the sentence, the
 * way it sits on one line at desktop width.
 * ══════════════════════════════════════════════════════════════════════════ */
@media(max-width:720px){
  /*
   * The sentence is centred and the two markers sit either side of it,
   * each vertically centred against the whole block rather than against its
   * first line. Left-aligned over two uneven lines, the pill read as a
   * paragraph that had been cut off; centred, the two lines balance against
   * each other and the dot and the badge become a matched pair holding them.
   */
  .pill{align-items:center;text-wrap:balance}
  .pill__text{flex:1 1 auto;text-align:center}
  .pill .dot{align-self:center}
  .pill .tag{align-self:center}
}

/* ══════════════════════════════════════════════════════════════════════════
 * The sticky trial bar, on a phone
 *
 * It read as three ragged lines — "Still / reconciling / by hand?" — in a
 * 72px column beside the button, on a bar that was only 277px wide with 375
 * to use.
 *
 * `max-width: calc(100vw - 24px)` was already there and was not the problem.
 * A `position: fixed` box is shrink-to-fit: it sizes to its content, and its
 * content is a flex row, so the paragraph was free to shrink to its
 * min-content width — the longest single word, "reconciling", at 72px — and
 * the bar then sized itself to that shrunken result. A max-width cannot stop
 * a box being narrower than it needs to be.
 *
 * A definite width does. The bar now takes the room it already had, the
 * copy gets roughly twice the column, and it sets in two lines instead of
 * three. The centring transform is untouched, which matters — the slide-up
 * animation on `.is-up` is written against it.
 *
 * And it lifts clear of the home indicator. `bottom: 18px` put it right on
 * top of the bar every modern iPhone draws across the bottom of the screen,
 * over a control whose whole job is to be tapped.
 * ══════════════════════════════════════════════════════════════════════════ */
@media(max-width:620px){
  .stickycta{
    width:calc(100vw - 24px);
    bottom:calc(18px + env(safe-area-inset-bottom, 0px));
  }
  /* Takes the slack, so the button and the close keep their exact sizes and
     only the sentence gets the extra room. */
  .stickycta p{flex:1 1 auto;min-width:0}
  .stickycta .btn{flex:none}
}

/* ══════════════════════════════════════════════════════════════════════════
 * The phone platform layer
 *
 * The site was responsive — nothing overflowed 375px and the type scaled —
 * but it had none of the handful of declarations that separate a page being
 * viewed on a phone from something that feels like it belongs there. Each
 * one below is one line with one reason.
 * ══════════════════════════════════════════════════════════════════════════ */

html{
  /* iOS and Android paint a translucent grey box over anything tapped that
     has a handler. It is the loudest "this is a web page" signal there is,
     and it fires on every button, link and card on this site. Removed here,
     and the :active states below put something back in its place — taking it
     away and leaving nothing is worse than leaving it alone. */
  -webkit-tap-highlight-color:transparent;
}

/*
 * A control should answer the finger, not the release.
 *
 * With the highlight gone and all 85 hover rules now correctly behind
 * `(hover: hover)`, a touch device had no feedback at all: nothing changed
 * until the navigation actually happened. `:active` fires on touch-down on
 * every input type, which is what makes a press feel immediate even when the
 * work behind it is not.
 */
@media (hover: none){
  .btn:active,.navpill a:active,.menubtn:active,.stickycta__x:active,
  .pricebox__term:active,.card:active,a.card:active{
    transform:scale(.98);
    transition:transform .1s cubic-bezier(.22,.61,.36,1);
  }
}
@media (prefers-reduced-motion: reduce){
  .btn:active,.navpill a:active,.menubtn:active,.stickycta__x:active,
  .pricebox__term:active,.card:active,a.card:active{transform:none;opacity:.85}
}

/*
 * The safe areas, which `viewport-fit=cover` in the page head switches on.
 *
 * Without that meta the browser letterboxes the page inside the notch and
 * fills the margins with the body colour — which on this site means white
 * bars across the top and bottom of a blue hero. With it, the page paints
 * edge to edge and has to pad its own content back out of the way.
 *
 * Only the two elements that sit against an edge need it. Ordinary sections
 * get their clearance from the header above them.
 */
.header{padding-top:calc(clamp(12px,2.4vw,18px) + env(safe-area-inset-top, 0px))}

/* Landscape is where the side notch actually bites: in portrait these
   resolve to zero and nothing moves. `max()` rather than addition, so the
   existing padding is a floor and the inset only matters when it exceeds
   it — otherwise a notched phone would get double the gutter. */
/*
 * NOT `.wrap`. It has `max-width` and `margin:0 auto` and deliberately no
 * padding of its own — the section around it supplies the gutter. Adding it
 * here applied the gutter twice to everything inside one, which took every
 * card on the site from 331px to 287px on a 375px screen. That was a
 * regression introduced by this very rule and is the reason the cards looked
 * pinched.
 */
.header,.footer,.section,.section--tight{
  padding-left:max(var(--pad), env(safe-area-inset-left, 0px));
  padding-right:max(var(--pad), env(safe-area-inset-right, 0px));
}

/*
 * The billing toggle was a 30px target.
 *
 * Annual against Monthly is the one control on the pricing section, and it
 * sat well under the 44px a fingertip reliably lands on. The type and the
 * pill shape are unchanged — only the box around the label grows.
 */
.pricebox__term{min-height:44px;padding:8px 18px}


/* ══════════════════════════════════════════════════════════════════════════
 * ONE GUTTER ON A PHONE
 *
 * The site had three. At 375px a `.wrap` gave 331px, a card inside one gave
 * 287px, and the closing CTA gave 355px — because that section carries its
 * own `#cta` override at 10px and sits outside any wrap. Three widths down
 * one scroll is what read as "the cards are the wrong size": no single one
 * of them was wrong, they just never agreed.
 *
 * So the page gutter becomes one value, and it is the CTA's own — every
 * boxed surface on the site now lines up with the card above the footer,
 * which is the widest and the one worth matching.
 *
 * Bare text is the exception and has to be. Section headings sit directly in
 * a wrap with nothing around them, and at a 10px gutter a heading starts
 * 10px from the bezel. A card does not have that problem because its own
 * padding holds the text well inside it. So the text blocks keep a reading
 * inset while the boxes go wide — which is the arrangement that makes the
 * boxes look aligned rather than the text look neglected.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 760px){
  :root{ --pad: clamp(10px, 2.4vw, 18px); }

  /* Already this value; stated so the two cannot drift apart. */
  #cta{ padding-left: var(--pad); padding-right: var(--pad); }

  /*
   * ══════════════════════════════════════════════════════════════════════
   * ONE LEFT EDGE FOR EVERY WORD ON THE PAGE
   *
   * The page gutter above put every box on the same outer edge. It did not
   * put the TEXT on the same edge, and that is what actually reads as
   * misaligned, because a card holds its copy in from its own border while
   * a bare paragraph does not.
   *
   * Measured at 375px before this rule: card borders all at 10px, but the
   * copy inside them started at 28, 30, 36 or 40 depending on which card it
   * was, and a bare section heading started at 22. Nine content surfaces
   * with nine different inner paddings — 18px on one, 40px on another — so
   * no two columns of text on the page shared a margin.
   *
   * One value now, used twice: as the inner padding of every content
   * surface, and as the inset on text that has no surface around it. Every
   * word on every page therefore begins at 10 + 24 = 34px, whether it sits
   * in a card or on the page itself.
   *
   * 24px rather than the 28-30 the bigger cards used: on a 355px-wide card
   * that leaves 307px for the line, and the wider paddings were inherited
   * from a desktop where the same clamp had a lot more room to spend.
   * ══════════════════════════════════════════════════════════════════════
   */
  :root{ --pad-inner: 24px; }

  /* The surfaces. Small pills and chips are deliberately not in this list —
     they are labels, not places to read. */
  .card, .closer, .cx__form, .mdl__card, .numcard,
  .panel, .pricebox, .rt__card, .tdlg__card{
    padding-left: var(--pad-inner);
    padding-right: var(--pad-inner);
  }

  /*
   * Text with no surface around it takes the same inset, so it lines up with
   * the copy inside the cards above and below it. Matched on the element
   * rather than on a class list, because the blocks that sit bare in a wrap
   * differ on every page — headings, eyebrows and ledes on one, FAQ rows and
   * legends on another — and a class list would go stale the first time a
   * section was added.
   */
  /*
   * `:not(...)` on the surfaces, and it is load-bearing.
   *
   * A few elements are BOTH — `.wrap.panel` is a wrap that is also a padded
   * card. Without this, it takes the card padding from the rule above and
   * its children take the text inset as well, so its copy started at
   * 10 + 24 + 24 = 58px while everything else on the page started at 34.
   * That is the same double-gutter fault the page-level rule was written to
   * fix, one level further in.
   */
  .wrap:not(.panel):not(.card):not(.closer):not(.pricebox):not(.numcard)
    > :where(h1, h2, h3, h4, p, ul, ol, .eyebrow, .lede, .sec, .h-md, .h-lg){
    padding-left: var(--pad-inner);
    padding-right: var(--pad-inner);
  }
}

/* ══════════════════════════════════════════════════════════════════════════
 * ONE SLIDER, NOT TWO
 *
 * The site has two range inputs — the pricing box and the calculator in the
 * maths section — and only one of them was ever styled. The pricing slider
 * sets `-webkit-appearance:none` and draws a 26px yellow thumb; the
 * calculator never sets it, and WebKit ignores every `::-webkit-slider-*`
 * rule on a control that has not been un-styled first. So the maths section
 * rendered the operating system's own grey slider next to a yellow readout,
 * on a page where the identical control two sections down is a yellow disc.
 * Measured: `appearance: auto` on the calculator, `none` on the pricing box.
 *
 * Its track colour was wrong too, and for the same reason it never showed —
 * `--ink-12` is a dark tint meant for a light ground, and this slider sits
 * on #1E1E1E. It would have been invisible the moment the thumb rule started
 * working, which is the kind of thing that only surfaces once something else
 * is fixed.
 *
 * Both are declared together here so they cannot drift apart again.
 * ══════════════════════════════════════════════════════════════════════════ */
.pricebox input[type=range],
.calc input[type=range]{
  -webkit-appearance:none;appearance:none;
  width:100%;height:44px;background:transparent;outline:none;cursor:pointer;
}

.pricebox input[type=range]::-webkit-slider-runnable-track,
.calc input[type=range]::-webkit-slider-runnable-track{
  height:4px;border-radius:4px;background:rgba(255,255,255,.2);
}
.pricebox input[type=range]::-moz-range-track,
.calc input[type=range]::-moz-range-track{
  height:4px;border-radius:4px;background:rgba(255,255,255,.2);
}

.pricebox input[type=range]::-webkit-slider-thumb,
.calc input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:26px;height:26px;border-radius:50%;
  background:var(--yellow);border:3px solid var(--ink);
  box-shadow:0 4px 14px -4px rgba(0,0,0,.6);
  cursor:grab;
  /* Chrome centres the thumb on the track only if you offset it yourself
     once the track no longer fills the input box: (44 - 4)/2 - 26/2 = 7. */
  margin-top:-11px;
}
.pricebox input[type=range]::-moz-range-thumb,
.calc input[type=range]::-moz-range-thumb{
  width:26px;height:26px;border-radius:50%;
  background:var(--yellow);border:3px solid var(--ink);
  box-shadow:0 4px 14px -4px rgba(0,0,0,.6);
  cursor:grab;
}
.pricebox input[type=range]:focus-visible,
.calc input[type=range]:focus-visible{outline:3px solid var(--yellow);outline-offset:4px}

/* The calculator's row put the track in whatever space was left after the
   label and the readout — 165px of a 355px card. The track takes the slack
   now and the two fixed items keep their size. */
.calc__slider input[type=range]{flex:1 1 auto;min-width:0}

@media (max-width: 760px){
  /*
   * The visible "Team size" label goes, and the row fits on one line again.
   *
   * Label plus track plus readout needs 311px in a 263px row, so the readout
   * wrapped underneath and the yellow number sat alone on a line of its own.
   * The label is the part worth losing: the heading directly above it reads
   * "ANNUAL COST · TEAM OF 25" and the readout repeats the figure, so it is
   * the third thing on screen saying the same word.
   *
   * Safe to hide rather than shrink because the input carries its own
   * `aria-label="Team size"` — the control keeps its name for a screen
   * reader, which is the only thing the <label> was still doing.
   */
  .calc__slider > label{display:none}
}

/* ══════════════════════════════════════════════════════════════════════════
 * The tutorial player's controls, on a phone — again
 *
 * There is already a rule for this, at `@media(max-width:600px)`, with a
 * comment recording that the buttons measured 38x38 and were raised to 44.
 * It does not apply. A later base rule sets `width:34px;height:34px` on
 * `.player__btn`, and an explicit width beats a `min-width` that came
 * earlier in the file at the same specificity — so the fix was undone by a
 * rule written after it, and the controls measured 34px again.
 *
 * Restated here, at the end, in the same properties the base rule uses so
 * the argument cannot be lost a second time. Back 10, play, forward 10,
 * mute, captions, speed and fullscreen are the whole of the player on a
 * phone, and they were all a third under the size a fingertip reliably
 * lands on.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px){
  .player__btn{
    width:44px;height:44px;min-width:44px;min-height:44px;padding:4px;
  }
}


/* ══════════════════════════════════════════════════════════════════════════
 * The hero pill now sits under the buttons
 *
 * It opened the hero, above the headline, where it competed with the first
 * line for the eye. Below the two calls to action it reads as what it
 * actually is — a live proof point for the claim you have just been asked to
 * act on — and the hero opens on the headline instead.
 *
 * It was `margin-bottom:30px` for its old position at the top; the spacing
 * moves with it.
 * ══════════════════════════════════════════════════════════════════════════ */
/*
 * The pill opens the hero again, and it is sized to its text rather than to
 * the column.
 *
 * At full width it was a 355px bar — the same width as every card below it —
 * and a bar is not what it is: it is a small live badge, and spanning the
 * column made it read as the first section of the page rather than as a
 * note above the headline. `fit-content` lets it hug its own two centred
 * lines, with the dot and the version badge closing either end.
 */
.hero__inner .pill{
  width:fit-content;
  max-width:100%;
  margin-left:auto;margin-right:auto;
}

/*
 * SCOPED TO THE PHONE, which it was not at first — and on a 1280px desktop
 * the cap squeezed a sentence that fits comfortably on one line into a
 * 318px box and broke it over two. The pill is only constrained where the
 * constraint is needed.
 */
@media (max-width: 720px){
  .hero__inner .pill{
    max-width:100%;
    margin-top:0;margin-bottom:26px;
  }
}
.hero__trust{margin-top:14px}


/* ══════════════════════════════════════════════════════════════════════════
 * The pill is one line on a phone
 *
 * Measured at 12px: the full sentence needs 409px. Beside the version badge
 * there are 260px of room, and 316px without it — so no amount of balancing
 * was going to get it onto one line. Two things give way, and they are the
 * two least load-bearing:
 *
 *   · the `v2.0` badge, which is version chrome rather than the hook, and
 *     costs 56px of the line it is sitting on;
 *   · "for 128 people is", which leaves "It's 4:04pm — payroll already
 *     approved" at 285px — comfortably inside 316 even when the clock rolls
 *     to a two-digit hour and takes another 8px.
 *
 * The desktop keeps the whole sentence and the badge. The copy is not
 * duplicated anywhere: the phrase is wrapped in a span that is simply not
 * shown below 720px, so the two versions cannot drift apart.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 720px){
  /*
   * One line, and now it fits with room rather than by a hair.
   *
   * The old sentence needed 409px and had 260 beside the badge, so getting
   * it onto one line meant dropping the badge AND trimming the copy. The
   * new line is 36 characters and about 211px, which clears the 261px
   * available even on a 320px phone — so the version badge stays.
   */
  .pill__text{text-wrap:nowrap}
  .hero__inner .pill{max-width:100%}
}


/* The clock is gone from the pill, so the styles that drove it are dead
   weight. Left in place would be a rule nobody can trace to anything on the
   page — the next person to read it would go looking for the element. */

/* ══════════════════════════════════════════════════════════════════════════
 * A smaller pill on a phone
 *
 * At 12px in a 41px-tall box it carried the same weight as the buttons under
 * the headline, which is more than a note above the headline should have. It
 * is a footnote with a pulse on it, not a control.
 *
 * Every value comes down together — the type, the padding, the gap, the dot
 * and the version badge — because shrinking only the text would have left
 * the same box with more air in it and looked like a mistake rather than a
 * smaller object.
 *
 * It stays on one line, with room. The line measures about 193px at 11px,
 * and the dot, gaps, padding and badge add roughly 79 — about 272px in a
 * 355px column, and still inside the 300px a 320px phone gives.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 720px){
  .pill{
    padding:5px 6px 5px 11px;
    gap:7px;
    font-size:11px;
    border-radius:13px;
  }
  .pill .dot{width:6px;height:6px}
  .pill .tag{
    font-size:9.5px;
    padding:3px 8px;
    letter-spacing:.03em;
  }
}
