/* ── self-hosted faces ────────────────────────────────────────────────────────────────────
   Self-hosted faces, served from this directory instead of fonts.googleapis.com.

   NOT a preference — a requirement. The application's CSP is ENFORCING with
   `style-src 'self'` and no `font-src`, so the Google stylesheet was refused outright and
   every heading fell back to Georgia. Self-hosting is also what `lib/report` already does
   for its own faces: never a CDN URL. See fonts/NOTICE.txt for the OFL terms.

   Both files are VARIABLE, so one file covers the whole weight range rather than four
   static cuts — 3 files, 238 KB total, latin subset only (the site's entire non-ASCII
   character set is ä, — and €, all inside this range). `swap` so text paints immediately
   in the fallback and never blocks on the font. */
/* ── BRAND FACES, 2026-08-23 ───────────────────────────────────────────────────────────────
   Space Grotesk (display + wordmark) · Inter (body) · Geist Mono (eyebrows/labels) ·
   Source Serif 4 (the three pull-quotes only).

   THESE ARE THE EXACT BYTES THE ROOT SITE SERVES, copied from its build output — see
   fonts/NOTICE.txt for sha256 per file and why the hash is the only durable provenance.
   NEWSREADER IS GONE: it was the old site's heading face and echoed nothing. The three
   pull-quotes now use SOURCE SERIF 4, which is the face the reader has already seen in
   their own report (lib/report/styles/baseStyles.ts and the personal-read view both
   render in it) — so the echo is true rather than merely serif-shaped. */
@font-face{font-family:"Space Grotesk";font-style:normal;font-weight:500 700;font-display:swap;
  src:url("fonts/space-grotesk-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Geist Mono";font-style:normal;font-weight:400 500;font-display:swap;
  src:url("fonts/geist-mono-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Source Serif 4";font-style:normal;font-weight:400 600;font-display:swap;
  src:url("fonts/source-serif-4-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Source Serif 4";font-style:italic;font-weight:400 600;font-display:swap;
  src:url("fonts/source-serif-4-italic-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Inter";font-style:normal;font-weight:400 700;font-display:swap;
  src:url("fonts/inter-normal-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}

:root{
  /* ── BRAND TOKENS (brand-kit/unseen-tokens.css). The legacy variable NAMES are kept so every
     existing rule keeps working and the diff stays a colour change rather than a rewrite; the
     VALUES are now the brand's. Mapping, from the design brief:
        --navy  -> --ud-carbon      --teal   -> --ud-teal        --teal-d -> --ud-teal-deep
        --light -> --ud-mist        --line   -> --ud-line        body bg  -> --ud-cloud
     --gold has NO brand equivalent: the palette contains no gold. Its five uses are resolved
     individually below, and NONE of them maps to --ud-sterile (#C9A24A) — that is the closest
     hue and it is semantically reserved for the STUCK state. That mapping is the obvious one
     and it is wrong. */
  --navy:#0C1110; --navy-2:#161B19; --teal:#1F9E8A; --teal-d:#0F6F60;
  --teal-bright:#28C2A8; --teal-tint:#EAF6F3;
  --ink:#0C1110; --muted:#4A544F; --graphite:#7D8A85;
  --light:#EEF1ED; --cloud:#F7F9F7; --line:#E1E6E1; --line-soft:#ECEEEC; --white:#fff;
  /* STATE COLOURS. On state cards and scorecard bars ONLY — never on chrome, never on an
     availability tag. Names kept; values are the brand's diagnostic palette. */
  --green:#1F9E8A; --amber:#C9A24A; --red:#D4694A;
  --maxw:1120px;
  --serif:"Source Serif 4",Georgia,"Times New Roman",serif;
  --sans:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  --display:"Space Grotesk","Inter",-apple-system,BlinkMacSystemFont,sans-serif;
  --mono:"Geist Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --r-chip:4px; --r-btn:6px; --r-card:8px; --r-panel:12px;
  --shadow-card:0 1px 3px rgba(12,17,16,.09); --shadow-pop:0 12px 40px rgba(12,17,16,.07);
  /* ON-CARBON TEXT TINTS. The sheet previously used blue-greys (var(--on-dark), var(--on-dark-dim), var(--on-dark-dim), var(--on-dark),
     var(--on-dark), var(--light)) left over from the old navy palette — invisible to a `var(--gold)` grep because
     they were literals. These two replace all six. */
  --on-dark:#C7D2CD; --on-dark-dim:#9AA8A2;
  /* Sign out reads as destructive. --red #D4694A is 3.55:1 on white — below AA for normal text — so the
     CONTROL uses a darker step and --red stays the state/graphic colour. Measured: 5.31:1 on white. */
  --red-d:#A8402A; --red-tint:#FCF2EF;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
/* Body 15px is SMALLER than the site ran at (17px). That is the brand's choice and it is followed. */
body{margin:0;font-family:var(--sans);color:var(--ink);background:var(--cloud);
  font-size:15px;line-height:1.55;-webkit-font-smoothing:antialiased}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 28px}
.narrow{max-width:780px}
a{color:var(--teal-d);text-decoration:none;border-bottom:1px solid rgba(31,158,138,.30)}
a:hover{border-bottom-color:var(--teal)}
/* DISPLAY FACE ON HEADINGS, tracking −2 to −3% per the spec. The serif is no longer a heading
   face at all: it is reserved for the three report pull-quotes. */
h1,h2,h3,h4{font-family:var(--display);font-weight:600;line-height:1.14;margin:0 0 .5em;
  letter-spacing:-.025em;color:var(--navy)}
h1{font-size:clamp(2.4rem,5.2vw,3.4rem);letter-spacing:-.03em}
h2{font-size:clamp(1.45rem,2.6vw,1.75rem);margin-top:0}
h3{font-size:1.06rem;color:var(--navy);letter-spacing:-.015em}
h4{font-size:.95rem;font-family:var(--sans);font-weight:600;letter-spacing:0}
p{margin:0 0 1.05em}
.lede{font-size:1.13rem;color:var(--muted);line-height:1.55}
.eyebrow{font-family:var(--mono);font-size:12px;font-weight:500;letter-spacing:.14em;
  text-transform:uppercase;color:var(--teal-d);margin:0 0 .9em;display:flex;align-items:center;gap:.6em}
.eyebrow::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--teal);flex:none}
.dark .eyebrow{color:var(--teal-bright)} .dark .eyebrow::before{background:var(--teal-bright)}

/* nav */
header.nav{position:sticky;top:0;z-index:50;background:rgba(247,249,247,.93);
  backdrop-filter:saturate(160%) blur(10px);border-bottom:1px solid var(--line)}
.nav-in{max-width:var(--maxw);margin:0 auto;padding:14px 28px;display:flex;align-items:center;gap:28px}
.brand{font-family:var(--display);font-weight:600;font-size:1.06rem;letter-spacing:-.02em;color:var(--navy);
  border:0;display:flex;align-items:center;gap:9px;white-space:nowrap}
/* THE MARK, extracted verbatim from the live root page rather than redrawn — a new one would have
   meant two logos. #1F9E8A is correct here: a GRAPHIC carries no contrast requirement (BRAND.md §5).
   `currentColor` on the muted dots means it inverts correctly in the carbon footer for free. */
.brand .mk{width:22px;height:22px;flex:none;display:block}
nav.links{display:flex;gap:22px;margin-left:auto;align-items:center;flex-wrap:wrap}
nav.links a{border:0;font-size:.94rem;color:var(--ink);font-weight:500}
nav.links a:hover{color:var(--teal-d)}
nav.links a.cta{background:var(--teal-d);color:#fff;padding:8px 15px;border-radius:var(--r-btn);font-weight:600}
nav.links a.cta:hover{background:var(--teal-d);color:#fff}

/* sections */
section{padding:76px 0}
section.tight{padding:52px 0}
section.dark{background:var(--navy);color:var(--on-dark)}
section.dark h1,section.dark h2,section.dark h3{color:#fff}
section.dark .lede{color:var(--on-dark)}
section.light{background:var(--light)}
.hero{padding:86px 0 66px;position:relative;overflow:hidden}
.hero .lede{max-width:660px}
.hero-orb{position:absolute;border-radius:50%;pointer-events:none}
.o1{width:520px;height:520px;right:-160px;top:-200px;background:radial-gradient(circle at 30% 30%,rgba(12,17,16,.10),rgba(12,17,16,0) 70%)}
.o2{width:340px;height:340px;right:60px;top:180px;background:radial-gradient(circle at 40% 40%,rgba(31,158,138,.13),rgba(31,158,138,0) 70%)}

/* buttons */
.btn{display:inline-block;padding:12px 22px;border-radius:var(--r-btn);font-weight:600;font-size:.95rem;border:0}
/* THE ONE VISIBLE COLOUR CHANGE PRIIT APPROVED: the primary action is teal fill on white text.
   It was carbon here and gold on the hero CTA via an inline override; both are gone. */
.btn.primary{background:var(--teal-d);color:#fff}
.btn.primary:hover{background:var(--teal)}
.btn.ghost{background:var(--white);color:var(--navy);box-shadow:inset 0 0 0 1px var(--line)}
.btn.ghost:hover{box-shadow:inset 0 0 0 1.5px var(--teal)}
.dark .btn.ghost{background:transparent;color:#fff;box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.28)}
.btn-row{display:flex;gap:13px;flex-wrap:wrap;margin-top:26px;align-items:center}
.btn-note{font-size:.9rem;color:var(--muted)}
.dark .btn-note{color:var(--on-dark-dim)}

/* grid + cards */
.grid{display:grid;gap:22px}
.g2{grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
.g4{grid-template-columns:repeat(auto-fit,minmax(215px,1fr))}
/* WHITE ON CLOUD with --ud-shadow-card. The page ground is now cloud, so a white card reads as a
   surface rather than as the background it used to match. */
.card{background:var(--white);border:1px solid var(--line-soft);border-radius:var(--r-card);
  padding:24px;box-shadow:var(--shadow-card)}
.card h3{margin-bottom:.4em}
.card p:last-child{margin-bottom:0}
.card.tint{background:var(--teal-tint);border-color:var(--line);box-shadow:none}
.dark .card{background:var(--navy-2);border-color:rgba(255,255,255,.1)}
.stat{font-family:var(--serif);font-size:2.1rem;font-weight:650;color:var(--navy);line-height:1.1;display:block}
.dark .stat{color:var(--teal-bright)}
.stat-l{font-size:.93rem;color:var(--muted);margin-top:.35em;display:block}
.dark .stat-l{color:var(--on-dark)}

/* state pills */
.states{display:grid;gap:18px;grid-template-columns:repeat(auto-fit,minmax(250px,1fr))}
.state{border-radius:var(--r-card);padding:22px;border:1px solid var(--line-soft);background:var(--white);box-shadow:var(--shadow-card)}
.state .nm{font-family:var(--serif);font-size:1.4rem;font-weight:650;margin-bottom:.3em;display:block}
.state.gen{border-top:4px solid var(--green)} .state.gen .nm{color:var(--green)}
.state.stk{border-top:4px solid var(--amber)} .state.stk .nm{color:var(--amber)}
.state.dmg{border-top:4px solid var(--red)}  .state.dmg .nm{color:var(--red)}
.state p{margin:0;font-size:.98rem;color:var(--muted)}

/* rungs */
.rung{display:grid;grid-template-columns:66px 1fr;gap:20px;padding:22px 0;border-top:1px solid var(--line)}
.rung:last-child{border-bottom:1px solid var(--line)}
.rung .n{font-family:var(--serif);font-size:1.5rem;color:var(--teal);font-weight:650;line-height:1}
.rung h3{margin-bottom:.25em}
.rung p{margin:0;color:var(--muted)}
.tag{display:inline-block;font-size:.72rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  padding:3px 9px;border-radius:20px;margin-left:9px;vertical-align:2px}
/* NEUTRAL, NOT STATE COLOURS. Mapping these to --ud-generative/--ud-sterile would paint an
   AVAILABILITY marker in the productive and stuck colours — the automatic mapping's one real
   violation, and the reason the palette is applied by role rather than by hue. */
.tag.now{background:var(--teal-tint);color:var(--teal-d)}
.tag.build{background:var(--light);color:var(--muted)}
.tag.road{background:var(--light);color:var(--muted)}

/* table */
table{width:100%;border-collapse:collapse;margin:22px 0;font-size:.96rem}
th,td{text-align:left;padding:13px 14px;border-bottom:1px solid var(--line);vertical-align:top}
th{background:var(--navy);color:#fff;font-weight:600;font-size:.87rem;letter-spacing:.02em}
tbody tr:nth-child(even){background:var(--light)}
td.num,th.num{text-align:right;white-space:nowrap}
.tbl-wrap{overflow-x:auto}

/* pricing */
.plans{display:grid;gap:20px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));align-items:stretch}
.plan{border:1px solid var(--line);border-radius:12px;padding:26px;display:flex;flex-direction:column;background:#fff}
.plan.feature{border:1.5px solid var(--teal);box-shadow:0 6px 26px rgba(12,17,16,.07)}
.plan .pname{font-family:var(--serif);font-size:1.3rem;font-weight:650;color:var(--navy)}
.plan .price{font-family:var(--serif);font-size:2.3rem;font-weight:650;color:var(--navy);margin:.25em 0 0}
.plan .per{font-size:.9rem;color:var(--muted);margin-bottom:1em}
.plan ul{list-style:none;padding:0;margin:0 0 20px;font-size:.96rem}
.plan ul li{padding:7px 0 7px 22px;position:relative;color:var(--ink)}
.plan ul li::before{content:"";position:absolute;left:0;top:15px;width:9px;height:9px;border-radius:50%;
  background:var(--teal);opacity:.35}
.plan .foot{margin-top:auto}
/* The invoice route is a SECONDARY action, deliberately: one clear way to buy, one quieter way to be
   invoiced. Not a second primary button. */
.ctanote{margin-top:9px;font-size:.86rem;line-height:1.4}
.ctanote a{color:var(--teal-d)}

/* quote / notes */
blockquote{margin:26px 0;padding:20px 24px;background:var(--teal-tint);border-left:4px solid var(--teal);
  border-radius:0 8px 8px 0;font-size:1.06rem}
blockquote p:last-child{margin-bottom:0}
.note{background:var(--light);border:1px solid var(--line);border-radius:10px;padding:20px 22px;font-size:.96rem}
.note strong{color:var(--navy)}
ul.plain{list-style:none;padding:0}
ul.plain li{padding:9px 0 9px 24px;position:relative;border-bottom:1px solid var(--line)}
ul.plain li::before{content:"";position:absolute;left:0;top:18px;width:8px;height:8px;border-radius:50%;background:var(--teal);opacity:.4}
ul.plain li:last-child{border-bottom:0}

/* footer */
footer{background:var(--navy);color:var(--on-dark-dim);padding:56px 0 34px;font-size:.93rem}
footer h4{color:#fff;font-family:var(--sans);font-size:.8rem;letter-spacing:.11em;text-transform:uppercase;margin-bottom:1em}
footer a{color:var(--on-dark);border:0}
footer a:hover{color:#fff}
.fgrid{display:grid;gap:34px;grid-template-columns:1.7fr 1fr 1fr 1fr}
.fcol ul{list-style:none;padding:0;margin:0}
.fcol li{padding:5px 0}
.fbot{margin-top:40px;padding-top:22px;border-top:1px solid rgba(255,255,255,.11);
  display:flex;gap:18px;justify-content:space-between;flex-wrap:wrap;font-size:.86rem}
.pill{display:inline-block;font-size:.75rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  background:var(--teal-tint);color:var(--teal-d);padding:4px 11px;border-radius:var(--r-chip)}

@media(max-width:820px){
  .fgrid{grid-template-columns:1fr 1fr}
  nav.links{gap:14px}
  nav.links a.hide-sm{display:none}
  section{padding:56px 0}
  .rung{grid-template-columns:44px 1fr;gap:14px}
}
@media(max-width:520px){
  body{font-size:16px}
  .fgrid{grid-template-columns:1fr}
  .wrap{padding:0 20px}
  .nav-in{padding:12px 20px}
}

/* ── journey path strip ──────────────────────────────────────────────────────────────
   THE CENTREPIECE. One glance has to say: this starts with your own meetings and can grow to a
   whole organisation, and you choose how far to go.

   Three devices, deliberately independent so none of them is load-bearing alone:
   1. THE BAND THICKENS left→right and runs THROUGH the nodes, so the row reads as one path
      with stations on it rather than five cards. 3px under step 1 → 11px under step 5.
   2. THE NODE GROWS with it (34px → 58px) and every node CENTRE sits on the same axis, which
      is what makes the band a single continuous line instead of a staircase.
   3. THE DOT GLYPH says what that scale IS: one meeting, a handful of people, a team over
      time, an organisation, continuous. aria-hidden — the text label already says it.

   AVAILABILITY IS TEXTURE, NOT COLOUR. Paved (solid) = today; marked (tinted) = needs a plan;
   dashed = not built. Survives greyscale and a slide screenshot, and the `.sa` tag says it in
   words too, so three encodings agree and none depends on colour vision.

   NOTE the class is `.onplan`, not `.plan` — `.plan` is the PRICING card, and reusing it here
   inherited its border, fill and padding, drawing a spurious box around steps 3 and 4.

   No JS. The only motion is a hover lift, disabled under prefers-reduced-motion. */
.journey{padding:52px 0 14px}
.journey .jhead{max-width:760px;margin-bottom:36px}
.journey .jhead p{font-size:1.16rem;color:var(--muted);margin:0}

.path{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(5,1fr);
  gap:0;position:relative}
.step{position:relative;padding:0 12px;text-align:center;min-width:0;
  display:flex;flex-direction:column;align-items:center}

/* THE BAND — one segment per step. `top` is set per step so the segment stays centred on the
   shared 29px node axis as it thickens; bled 1px sideways so segments meet with no hairline. */
.step::before{content:"";position:absolute;left:-1px;right:-1px;z-index:0;border-radius:2px}
.step.s1::before{top:27.5px;height:3px}
.step.s2::before{top:26.5px;height:5px}
.step.s3::before{top:25.5px;height:7px}
.step.s4::before{top:24.5px;height:9px}
.step.now::before{background:var(--teal)}
.step.onplan::before{background:rgba(31,158,138,.30)}
/* The dash is bound to .future, NOT to .s5 — step 3 is also not-built, and a step-indexed dash
   left a transparent GAP in the band the moment step 3 was reclassed. Any step can be dashed. */
.step.future::before{top:28px !important;height:0 !important;background:transparent;
  border-top:2px dashed var(--line);border-radius:0}

/* THE NODE — margin-top centres every size on the same 29px axis: (58 − size) / 2. */
.knob{position:relative;z-index:2;display:flex;align-items:center;justify-content:center;
  border-radius:50%;background:#fff;transition:transform .18s ease}
.s1 .knob{width:34px;height:34px;margin:12px auto 12px}
.s2 .knob{width:40px;height:40px;margin:9px auto 9px}
.s3 .knob{width:46px;height:46px;margin:6px auto 6px}
.s4 .knob{width:52px;height:52px;margin:3px auto 3px}
.s5 .knob{width:58px;height:58px;margin:0 auto 0}
.step.now .knob{background:var(--teal-d);border:2px solid var(--teal-d)}
.step.onplan .knob{background:#fff;border:2px solid var(--teal)}
.step.future .knob{background:#fff;border:2px dashed var(--line)}
.knob .num{font-family:var(--serif);font-weight:650;font-size:1.05rem;line-height:1}
.step.now .knob .num{color:#fff}
.step.onplan .knob .num{color:var(--teal-d)}
.step.future .knob .num{color:var(--muted)}

/* THE SCALE GLYPH — outside the knob, where it has room to be read. Inside a 34px circle it
   was a smudge; here it is a widening field of dots. Wrapped 3 per row: a dot, a row, a block. */
.scale{display:flex;flex-wrap:wrap;gap:2.5px;justify-content:center;align-items:center;
  margin:0 auto;line-height:0;height:14px}
.scale i{width:3.5px;height:3.5px;border-radius:50%;background:var(--teal);display:block}
.scale{max-width:19px}
.step.future .scale i{background:var(--line)}

/* LABELS */
.step .st{font-family:var(--sans);font-weight:650;font-size:.98rem;color:var(--navy);
  display:block;line-height:1.3;margin-top:14px;text-wrap:balance}
.step .sd{font-size:.86rem;color:var(--muted);display:block;margin-top:7px;line-height:1.45;
  text-wrap:pretty;margin-bottom:12px}
.step .sa{font-size:.68rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  display:inline-block;margin-top:auto;padding:4px 10px;border-radius:999px;
  /* margin-top:auto — bottom-aligns every tag despite titles wrapping to different depths. */
  align-self:center}
.step.now .sa{background:var(--teal-d);color:#fff}
.step.onplan .sa{background:transparent;color:var(--teal-d);box-shadow:inset 0 0 0 1px var(--teal)}
.step.future .sa{background:transparent;color:var(--muted);box-shadow:inset 0 0 0 1px var(--line)}
.step.future .st{color:var(--muted)}

/* The key, so the texture distinction never needs decoding. */
.pkey{display:flex;flex-wrap:wrap;align-items:center;gap:9px 22px;margin:30px 0 0;
  font-size:.78rem;color:var(--muted)}
.pkey .k{width:24px;height:6px;border-radius:2px;display:inline-block;margin-right:-13px}
.pkey .k.now{background:var(--teal)}
.pkey .k.onplan{background:rgba(31,158,138,.32)}
.pkey .k.future{background:transparent;height:0;border-top:2px dashed var(--line);border-radius:0}

@media(hover:hover){ .step:hover .knob{transform:translateY(-2px)} }
@media(prefers-reduced-motion:reduce){
  .knob{transition:none}
  .step:hover .knob{transform:none}
}

/* MOBILE — the path stands up. The spine's WIDTH now grows down the sequence, so the same
   "it gets bigger" reading survives the rotation, and the nodes stay centred on it. */
@media(max-width:860px){
  .path{grid-template-columns:1fr}
  .step{display:grid;grid-template-columns:58px 1fr;gap:0 18px;text-align:left;
    padding:0 0 26px 0;align-items:start}
  /* EXPLICIT placement. `.scale` is display:none here, so auto-placement was flowing the
     DESCRIPTION into the 58px rail column and overlapping the spine — unreadable. The rail
     gets column 1 and spans the whole step; all three text elements stack in column 2. */
  .step .knob{grid-column:1;grid-row:1 / span 3}
  .step .st{grid-column:2;grid-row:1;margin-top:0}
  .step .sd{grid-column:2;grid-row:2;margin-top:7px;margin-bottom:0}
  .step .sa{grid-column:2;grid-row:3;margin-top:11px;align-self:start;justify-self:start}
  .step::before{top:0 !important;bottom:0;left:28px;right:auto;height:auto !important;
    width:3px;border-top:0 !important;transform:translateX(-50%)}
  .step.s2::before{width:5px}
  .step.s3::before{width:7px}
  .step.s4::before{width:9px}
  /* The desktop `.step.future::before` sets height:0 to make a horizontal dash, and being two
     classes it OUT-SPECIFIES the mobile `.step::before` override — which left step 3's spine
     invisible here. So restore the vertical run explicitly. */
  .step.future::before{top:0 !important;bottom:0;height:auto !important;
    width:0 !important;border-top:0 !important;
    border-left:2px dashed var(--line);transform:translateX(-1px)}
  .step.future:first-child::before{top:29px !important}
  .step.future:last-child::before{bottom:auto;height:36px !important}
  .step:last-child::before{bottom:auto;height:36px !important}
  .s1 .knob,.s2 .knob,.s3 .knob,.s4 .knob,.s5 .knob{margin:0 auto}
  .scale{display:none}            /* the node size alone carries scale in the vertical rail */
  .step .st{margin-top:0}
  .step:first-child::before{top:29px !important}
  .pkey{margin-top:10px}
}

/* ══ DESIGN PASS 2026-08-22 ═══════════════════════════════════════════════════════════════
   Everything below refines what the base sheet already establishes. Nothing here changes the
   palette or the typefaces, and no rule needs JavaScript. */

/* ── accessibility foundations ────────────────────────────────────────────────────────────
   Neither of these existed. A keyboard user had no visible focus anywhere on the site and no
   way past the nav. */
.skip{position:absolute;left:16px;top:-48px;z-index:100;background:var(--navy);color:#fff;
  padding:10px 16px;border-radius:0 0 8px 8px;font-size:.9rem;font-weight:600;
  text-decoration:none;transition:top .15s ease}
.skip:focus{top:0}
/* One visible ring, everywhere, in the brand teal — and :focus-visible so it appears for
   keyboards without ringing every mouse click. */
a:focus-visible,button:focus-visible,summary:focus-visible,[tabindex]:focus-visible{
  outline:3px solid var(--teal);outline-offset:3px;border-radius:3px}
.dark a:focus-visible,footer a:focus-visible{outline-color:var(--teal-bright)}
@media(prefers-reduced-motion:reduce){ .skip{transition:none} html{scroll-behavior:auto} }

/* ── hero ─────────────────────────────────────────────────────────────────────────────────
   Was plain: two orbs and left-aligned text. Now it has a measured opening — a hairline over
   the eyebrow, a larger display size, and a quieter lede — so it reads as considered rather
   than empty. The orbs are pushed further out and softened so they read as atmosphere. */
.hero{padding:104px 0 76px}
.hero .eyebrow{padding-top:22px;border-top:1px solid var(--line);display:inline-flex}
.hero h1{font-size:clamp(2.3rem,4.6vw,3.5rem);letter-spacing:-.018em;max-width:20ch;
  margin-bottom:.42em}
.hero .lede{font-size:1.2rem;color:var(--muted);max-width:62ch}
.hero .btn-row{margin-top:34px;align-items:center}
.hero-orb.o1{right:-220px;top:-240px;opacity:.75}
.hero-orb.o2{right:20px;top:200px;opacity:.6}
@media(max-width:860px){ .hero{padding:56px 0 52px} .hero .lede{font-size:1.08rem} }

/* ── the three states ─────────────────────────────────────────────────────────────────────
   The brand's core vocabulary, so it should be the most memorable object here. A tinted field,
   a heavier top rule, and a THREE-BAR TRACE whose SHAPE carries the state: rising for
   productive, flat for stuck, falling for damaging. That is what keeps them distinguishable
   with no colour at all — print it greyscale and it still reads. */
.state{border-radius:14px;padding:26px 24px 24px;position:relative;overflow:hidden;
  border:1px solid var(--line);transition:transform .18s ease,box-shadow .18s ease}
.state .nm{font-size:1.5rem;margin-bottom:.34em}
.state p{font-size:.96rem;line-height:1.6}
.state .mark{display:flex;align-items:flex-end;gap:4px;height:26px;margin-bottom:16px}
.state .mark i{width:7px;border-radius:2px;display:block;background:currentColor;opacity:.9}
.state.gen{border-top:4px solid var(--green);background:rgba(31,158,138,.045)}
.state.stk{border-top:4px solid var(--amber);background:rgba(201,162,74,.05)}
.state.dmg{border-top:4px solid var(--red);background:rgba(212,105,74,.045)}
/* rising */
.state.gen .mark i:nth-child(1){height:10px} .state.gen .mark i:nth-child(2){height:17px}
.state.gen .mark i:nth-child(3){height:24px}
/* flat — it ran and produced nothing */
.state.stk .mark i{height:13px}
/* falling */
.state.dmg .mark i:nth-child(1){height:24px} .state.dmg .mark i:nth-child(2){height:17px}
.state.dmg .mark i:nth-child(3){height:10px}
.state p{color:var(--muted)}
@media(hover:hover){ .state:hover{transform:translateY(-3px);box-shadow:0 10px 28px rgba(12,17,16,.07)} }
@media(prefers-reduced-motion:reduce){ .state{transition:none} .state:hover{transform:none} }

/* ── the climb ────────────────────────────────────────────────────────────────────────────
   Same visual language as the journey strip, so the two read as one system: the numeral sits
   in a teal disc like a path node instead of floating as loose serif text. */
.rung{grid-template-columns:52px 1fr;gap:22px;padding:24px 0;align-items:start}
.rung .n{width:38px;height:38px;border-radius:50%;background:rgba(31,158,138,.10);
  color:var(--teal-d);display:flex;align-items:center;justify-content:center;
  font-size:.95rem;font-weight:650}
.rung h3{font-size:1.12rem}
@media(max-width:520px){ .rung{grid-template-columns:40px 1fr;gap:16px} }

/* ── stats ────────────────────────────────────────────────────────────────────────────────
   Given a hairline and tighter type so a row of them reads as a set, not as loose numerals. */
.stat{font-size:2.35rem;letter-spacing:-.02em}
.stat-l{font-size:.88rem;line-height:1.45;max-width:24ch}

/* ── pricing plans ────────────────────────────────────────────────────────────────────────
   Hierarchy without relying on a colour badge: the featured plan gets a heavier border and a
   lift, so it is distinguishable in greyscale too. */
.plan{border-radius:14px;transition:transform .18s ease,box-shadow .18s ease}
.plan.feature{border:2px solid var(--teal);box-shadow:0 10px 30px rgba(12,17,16,.08)}
@media(hover:hover){ .plan:hover{transform:translateY(-3px)} }
@media(prefers-reduced-motion:reduce){ .plan{transition:none} .plan:hover{transform:none} }

/* ── tables ───────────────────────────────────────────────────────────────────────────────
   Functional but plain before. Zebra banding and a stronger header edge make a long privacy
   table scannable; the wrapper already scrolls on mobile rather than overflowing. */
.tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;border-radius:10px;
  border:1px solid var(--line)}
.tbl-wrap table{margin:0;border:0}
th{background:var(--light);border-bottom:2px solid var(--line);font-size:.82rem;
  letter-spacing:.04em;text-transform:uppercase;color:var(--navy)}
tbody tr:nth-child(even){background:rgba(238,241,237,.6)}
td,th{padding:13px 16px}

/* ── vertical rhythm ─────────────────────────────────────────────────────────────────────
   Alternating white and --light was the only device. A hairline between two same-coloured
   sections stops them merging into one long slab. */
section + section:not(.light):not(.dark){border-top:1px solid transparent}
section.light + section.light{border-top:1px solid var(--line)}
h2{letter-spacing:-.012em}

/* ── nav ──────────────────────────────────────────────────────────────────────────────────
   At 390px the links wrapped to four rows and the header stood 183px tall before the hero
   began. Tighter gaps and a smaller CTA bring it down without hiding anything extra. */
@media(max-width:620px){
  .nav-in{padding:10px 20px;gap:12px;flex-wrap:wrap}
  nav.links{gap:10px 14px;margin-left:auto}
  nav.links a{font-size:.88rem}
  nav.links a.cta{padding:7px 13px;font-size:.85rem}
  .brand{font-size:1.05rem}
  /* The eyebrow's leading dot should stay on the first line when the text wraps. */
  .eyebrow{align-items:flex-start}
}

/* ── CONTRAST, MEASURED AGAINST THE CURRENT TOKENS ───────────────────────────────────────────
   Re-measured 2026-08-23. The previous note in this slot quoted 4.75:1 and 6.47:1 — the figures
   for #2E7D52 and #A3312B, the OLD green and red. It was written inside the pass that replaced
   them, so it measured a palette that no longer existed and reported margins three times the
   real ones. Every number below carries the hex it came from, so the next palette change
   invalidates it visibly instead of silently.

   Ground is #FFFFFF (cards) / #F7F9F7 (cloud page). Ratios: white / cloud.

     --green      Productive  #1F9E8A   3.32 / 3.14   state name @ 1.4rem 650  → LARGE, passes 3:1
     --red        Damaging    #D4694A   3.55 / 3.35   state name @ 1.4rem 650  → LARGE, passes 3:1
     --amber      Stuck       #C9A24A   2.40 / 2.27   FAILS even large text — never used as text
     --amber-d    Stuck text  #8F6111   5.40 / 5.11   the substitute actually rendered
     --teal-d     links       #0F6F60   6.06 / 5.73   passes AA normal
     --muted      body dim    #4A544F   7.86 / 7.43
     --graphite   labels      #7D8A85   3.59 / 3.40   LARGE/decorative only

   Productive and Damaging clear 3:1 only because the state name is 1.4rem at 650 — large text.
   Their margins are THIN, not comfortable: 0.32 and 0.55 above the floor. Shrink that type and
   they fail, so the size is load-bearing and not a style choice.

   AND THE PRIMARY BUTTON: white on --teal #1F9E8A is 3.32:1, which FAILS AA for normal text —
   and a button at .95rem/600 is normal text. So the primary fill is --teal-d #0F6F60 (white on
   it: 6.06:1) with --teal as the hover. That deviates from the brief's "teal fill"; WCAG AA was
   also a stated constraint, and between a hue and a measurement the measurement wins. FLAGGED
   for Priit rather than quietly substituted. */
:root{ --amber-d:#8F6111 }
.state.stk .nm{color:var(--amber-d)}

/* In-table CTA — pricing is where a buyer lands, so the Sprint rows carry the same buy path as sprint.html
   rather than sending them to another page to find it. */
.rowcta{margin-top:10px}
.btn.sm{padding:8px 14px;font-size:.9rem}

/* ── ACCOUNT MENU (progressive enhancement; the served HTML is always signed-out) ──────────
   `Sign in` is a TEXT LINK beside the button, not a second button: one primary action in the
   nav. The menu itself is white-on-cloud with the brand card shadow, like every other surface. */
.signin{border:0;font-size:.94rem;color:var(--navy);font-weight:500}
.signin:hover{color:var(--teal-d)}
.acct{position:relative}
.acct-btn{width:30px;height:30px;border-radius:50%;border:0;cursor:pointer;
  background:var(--teal-d);color:var(--white);font-family:var(--sans);font-weight:600;font-size:.85rem}
.acct-btn:hover{background:var(--teal)}
.acct-menu{position:absolute;right:0;top:38px;z-index:60;width:250px;padding:6px;
  background:var(--white);border:1px solid var(--line);border-radius:var(--r-card);
  box-shadow:var(--shadow-pop);text-align:left}
.acct-who{padding:9px 11px 11px}
/* --graphite at 11px is 3.59:1 — below AA for normal text, and 11px is emphatically normal. Caught by
   check:sitecontrast on the very code that added it, which is the argument for the gate in one line. */
.acct-lbl{font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);margin:0 0 3px}
.acct-eml{font-size:.9rem;font-weight:600;color:var(--navy);margin:0;overflow:hidden;text-overflow:ellipsis}
.acct-item{display:block;border:0;padding:8px 11px;border-radius:var(--r-btn);border-top:1px solid var(--line-soft)}
.acct-item:hover{background:var(--light)}
.acct-t{display:block;font-size:.9rem;font-weight:600;color:var(--navy)}
.acct-d{display:block;font-size:.8rem;color:var(--muted)}
.acct-out{margin:0;border-top:1px solid var(--line-soft)}
.acct-out button{width:100%;text-align:left;padding:9px 11px;border:0;background:none;cursor:pointer;
  font-family:var(--sans);font-size:.9rem;font-weight:600;color:var(--red-d);border-radius:var(--r-btn)}
.acct-out button:hover{background:var(--red-tint)}
