/* Marketing page layout — talous.dev. Component-level styling lives in the
   design system's patterns/components.css; this file is only the scaffolding.

   SURFACE RHYTHM. White paper, one pine theatre. The story section is the
   product demo and the identity moment at once: a full pine band where the
   real Command view stays pinned while four moments of one morning scroll
   past. Ember stays the only action colour; sage stays on healthy figures;
   deep-green eyebrows thread the identity through the white sections. */
:root{--green-text:#3D684B}
.tls-band{--surface-band:var(--green-900);--surface-raised-on-dark:var(--green-700);--text-on-dark:#F2F5F1;--text-muted-on-dark:#A8C4AF;--band-muted:#A8C4AF;--on-black:#F2F5F1;--on-black-muted:#A8C4AF;--border-on-dark:color-mix(in oklab, #A8C4AF 26%, transparent);background:var(--green-900)}
.ep-eyebrow{color:var(--green-text)}
body{background:var(--surface-page);overflow-x:clip}
.skip{position:absolute;left:16px;top:16px;z-index:100;transform:translateY(-200%);background:var(--surface-card);color:var(--text-primary);border:1px solid var(--border-strong);border-radius:var(--radius-md);padding:10px 16px;font-size:var(--size-small);font-weight:500;text-decoration:none;transition:transform var(--dur-fast) var(--ease-standard)}
.skip:focus{transform:none}

/* Scroll-driven reveals. Tagged blocks rise once; the observer lives in Home. */
[data-rv]{opacity:0;transform:translateY(18px);transition:opacity .65s var(--ease-standard),transform .65s var(--ease-standard)}
[data-rv][data-in]{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){[data-rv]{opacity:1;transform:none;transition:none}}

/* Header */
.site-head{position:sticky;top:0;z-index:40;background:color-mix(in oklab, var(--paper) 88%, transparent);backdrop-filter:var(--blur-header);-webkit-backdrop-filter:var(--blur-header);border-bottom:1px solid transparent;transition:border-color var(--dur-base) var(--ease-standard)}
.site-head.stuck{border-bottom-color:var(--border-default)}
.head-in{display:flex;align-items:center;gap:var(--space-9);min-height:var(--head-h)}
.head-nav{display:flex;align-items:center;gap:var(--space-8);margin-left:auto}
.head-nav a:not(.tls-btn){position:relative;display:inline-flex;align-items:center;min-height:40px;line-height:1.2;font-size:var(--size-small);color:var(--text-secondary);text-decoration:none;transition:var(--transition-color)}
.head-nav a:not(.tls-btn)::after{content:"";position:absolute;left:0;right:0;top:calc(50% + .6em + 4px);height:1px;background:var(--ink);clip-path:inset(0 100% 0 0);transition:clip-path var(--dur-base) var(--ease-standard)}
.head-nav a:not(.tls-btn):hover{color:var(--text-primary)}
.head-nav a:not(.tls-btn):hover::after,.head-nav a.is-here::after{clip-path:inset(0)}
.head-nav a.is-here{color:var(--text-primary)}

/* ═══ HERO — unchanged ═══════════════════════════════════════════════════════ */
.hero{position:relative;padding:var(--space-13) 0 var(--space-14)}
.hero-c{text-align:center;max-width:var(--measure-hero);margin:0 auto}
/* Base gives every p a reading measure, which pulls a centred eyebrow or
   caption off the page's axis. Centred blocks here take the full column. */
.hero-c .ep-eyebrow,.hero-c .hero-meta,.app-cap{max-width:none;margin-inline:auto}
.hero-c .t-hero{margin:0 auto;max-width:17ch}
.hero-lede{margin:var(--space-8) auto 0;max-width:44ch;text-align:center;text-wrap:balance}
.hero-c .tls-btn-row,.tls-head-c .tls-btn-row{margin-top:var(--space-9);justify-content:center}
.hero-meta{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--space-4) var(--space-8);margin-top:var(--space-9);font-family:var(--font-mono);font-size:var(--size-caption);letter-spacing:.02em;color:var(--text-secondary)}
.app-slot{margin-top:var(--space-13)}
.app-cap{display:block;margin-top:var(--space-6);text-align:center;max-width:none}
.hero-app{display:grid;grid-template-columns:212px 1fr;border-radius:var(--radius-frame);border:1px solid var(--border-default);background:var(--surface-card);box-shadow:var(--shadow-lg);overflow:hidden;color:var(--text-primary);text-align:left}
.ha-side{background:var(--green-900);color:#F2F5F1;padding:var(--space-6) 0;display:flex;flex-direction:column}
.ha-brand{padding:var(--space-2) var(--space-6) var(--space-8)}
.ha-nav{display:flex;flex-direction:column;gap:1px;padding:0 var(--space-4)}
.ha-nav span{display:flex;align-items:center;gap:10px;height:32px;padding:0 var(--space-5);border-radius:var(--radius-md);font-size:var(--size-app-small);color:#A8C4AF}
.ha-nav span.on{background:var(--green-700);color:#F2F5F1}
.ha-nav svg{width:15px;height:15px;flex:none;stroke-width:1.5}
.ha-nav b{margin-left:auto;font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:var(--size-micro);font-weight:400}
.ha-user{margin-top:auto;padding-top:var(--space-6);margin:auto var(--space-6) 0;border-top:1px solid color-mix(in oklab, #A8C4AF 26%, transparent);display:flex;align-items:center;gap:10px;font-size:var(--size-app-small);line-height:1.3}
.ha-user em{display:block;font-style:normal;font-size:var(--size-micro);color:#A8C4AF}
.ha-av{width:26px;height:26px;flex:none;border-radius:var(--radius-pill);background:var(--green-700);color:#F2F5F1;display:grid;place-items:center;font-family:var(--font-mono);font-size:var(--size-micro)}
.ha-main{display:flex;flex-direction:column;min-width:0}
.ha-top{display:flex;align-items:center;gap:var(--space-5);height:52px;padding:0 var(--space-7);border-bottom:1px solid var(--border-hairline)}
.ha-brandsel{display:inline-flex;align-items:center;gap:7px;height:28px;padding:0 var(--space-5);border:1px solid var(--border-default);border-radius:var(--radius-pill);font-size:var(--size-app-small)}
.ha-brandsel svg{width:13px;height:13px;stroke-width:1.5;color:var(--text-secondary)}
.ha-when{margin-left:auto;font-family:var(--font-mono);font-size:var(--size-micro);color:var(--text-secondary)}
.ha-body{padding:var(--space-7);background:var(--surface-sunken);display:flex;flex-direction:column;gap:var(--space-6);flex:1}
.ha-greet{display:flex;align-items:baseline;gap:var(--space-6);flex-wrap:wrap}
/* A <p>, not an <h3>. These are the demo's own titles — "Meta Ads", "CRM",
   "Good morning, Wei Jian" — and as headings they went into the page's outline
   and into what a crawler reads as its structure, seven levels below an <h1>
   with no <h2> between. Each panel already has an accessible name from the tab
   that labels it. */
.ha-greet .ha-gt{font-family:var(--font-serif);font-size:var(--size-app-h1);font-weight:400;letter-spacing:0}
.ha-greet span{font-size:var(--size-app-small);color:var(--text-secondary)}
.ha-deck{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-5)}
.ha-tile{background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:var(--radius-lg);padding:var(--space-6)}
.ha-tile .l{display:flex;align-items:center;gap:7px;font-size:var(--size-app-small);font-weight:500}
.ha-tile .l svg{width:14px;height:14px;flex:none;stroke-width:1.5;color:var(--text-secondary)}
.ha-tile .l b{margin-left:auto;width:6px;height:6px;border-radius:50%;flex:none}
.ha-tile .v{display:block;margin-top:var(--space-4);font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:var(--size-metric-md);font-weight:500;letter-spacing:-.01em;line-height:1.1}
.ha-tile .s{display:block;margin-top:2px;font-family:var(--font-mono);font-size:var(--size-micro);color:var(--text-secondary)}
@media (max-width:900px){.hero-app{grid-template-columns:1fr}.ha-side{display:none}.ha-deck{grid-template-columns:repeat(2,1fr)}}

/* ═══ THE ROOM — one morning, scroll-driven ══════════════════════════════════
   Pine theatre. Left rail: four numbered moments that light up as they cross
   centre. Right: the Command view pinned, crossfading between the state each
   moment describes. The frame chrome reuses the hero dashboard's classes so
   the product looks like itself twice. */
.room{position:relative;overflow:clip}
/* Scoped to the head, not the section. The story frame is a WHITE card
   inside the pine band, and its queue label — the one eyebrow left on the
   page that is doing a job — was taking the band's muted green onto paper
   at 1.9:1. */
.room-head .ep-eyebrow{color:var(--band-muted)}
/* And the same again from the other direction: components.css paints every
   .tls-band eyebrow band-muted, which is right for the band and wrong for a
   white product card sitting on it. */
.rf .ep-eyebrow,.hero-app .ep-eyebrow{color:var(--green-text)}
.room-head{padding:var(--space-14) 0 var(--space-6)}
.room-head h2{margin-top:var(--space-5);color:var(--text-on-dark);max-width:18ch}
.room-head p{margin-top:var(--space-6);max-width:52ch;color:var(--band-muted)}
.spot{display:grid;grid-template-columns:340px 1fr;gap:var(--space-12);align-items:start;padding-bottom:var(--space-14)}
.stepcol{padding-top:var(--space-6)}
/* Each moment owns real scroll distance, and the active one is whichever sits
   nearest the focal line — so the section opens on 01 and moves one at a time. */
.step{min-height:66vh;display:flex;flex-direction:column;justify-content:center;padding:var(--space-8) 0;border-top:1px solid var(--border-on-dark);opacity:.3;cursor:pointer;transition:opacity .45s var(--ease-standard)}
.step.on{opacity:1}
.step.past{opacity:.5}
.step.past .step-k{color:var(--sage)}
.step-k{font-family:var(--font-mono);font-size:var(--size-caption);letter-spacing:var(--tracking-eyebrow);color:var(--band-muted)}
.step h3{margin-top:var(--space-4);font-size:var(--size-h3);color:var(--text-on-dark)}
.step p{margin-top:var(--space-4);font-size:var(--size-small);line-height:1.55;color:var(--band-muted)}
.stepcol .t-illus{color:color-mix(in oklab, #A8C4AF 70%, transparent)}
.frame-hold{position:sticky;top:96px;padding-top:var(--space-6)}
.spot-dots{display:flex;align-items:center;gap:var(--space-4);margin-top:var(--space-6)}
.spot-dot{appearance:none;background:none;border:0;padding:6px 0;cursor:pointer;flex:none}
.spot-dot i{display:block;width:26px;height:2px;border-radius:2px;background:var(--border-on-dark);transition:background var(--dur-base) var(--ease-standard)}
.spot-dot:hover i{background:var(--band-muted)}
.spot-dot.on i{background:var(--action)}
.spot-count{margin-left:var(--space-4);font-family:var(--font-mono);font-size:var(--size-micro);text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);color:var(--band-muted)}
.rf{display:grid;grid-template-columns:190px 1fr;border-radius:var(--radius-frame);border:1px solid var(--border-on-dark);background:var(--surface-card);box-shadow:0 32px 80px -24px rgba(4,12,8,.55);overflow:hidden;color:var(--text-primary);text-align:left}
.rf-side{min-height:470px;padding:var(--space-5) 0}
.rf .ha-nav span{height:32px;font-size:var(--size-app-small)}
.rf-top{height:48px;padding:0 var(--space-6)}
.rf-body{position:relative;flex:1}
.fv{position:absolute;inset:0;padding:var(--space-6);display:flex;flex-direction:column;gap:var(--space-5);opacity:0;transform:translateY(12px);transition:opacity .5s var(--ease-standard),transform .5s var(--ease-standard)}
.spot[data-s="0"] .fv0,.spot[data-s="1"] .fv1,.spot[data-s="2"] .fv2,.spot[data-s="3"] .fv3{opacity:1;transform:none}
.rf-kpis{grid-template-columns:repeat(2,1fr)}
.rf .tls-kpi{background:var(--surface-sunken)}
.fv-head{display:flex;align-items:center;gap:var(--space-5)}
.fv-head h4{font-size:var(--size-body);font-weight:600}
.fv-say{font-size:var(--size-small);line-height:1.55;color:var(--text-secondary);max-width:52ch}
.fv-rec{border:1px solid var(--border-default);border-radius:var(--radius-lg);padding:var(--space-7);display:flex;flex-direction:column;gap:var(--space-5);background:var(--surface-sunken)}
.fv-rec b{font-size:var(--size-body);font-weight:600}
.fv-rec p{font-size:var(--size-small);color:var(--text-secondary);line-height:1.5}
.fv-act{display:flex;gap:var(--space-4)}
.fv-label{font-family:var(--font-mono);font-size:var(--size-micro);text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);color:var(--text-secondary)}
.rf-rec{border:1px solid var(--border-hairline);border-radius:var(--radius-lg);overflow:hidden}
.rf-rec .tls-rrow{padding:var(--space-5) var(--space-6)}
.fv-sum{font-family:var(--font-mono);font-size:var(--size-micro);color:var(--text-secondary)}
/* Integrations — the room's back wall */
/* padding-block, not the four-value shorthand: this element is also the
   .tls-wrap, and `padding: X 0 Y` zeroes the gutter the wrap set. */
.intg{border-top:1px solid var(--border-on-dark);padding-block:var(--space-11) var(--space-13)}
.intg-t{margin-top:var(--space-5);color:var(--text-on-dark);max-width:30ch}
.intg-g{display:grid;grid-template-columns:repeat(6,1fr);gap:1px;background:var(--border-on-dark);border:1px solid var(--border-on-dark);border-radius:var(--radius-lg);overflow:hidden;margin-top:var(--space-9)}
.intg-c{background:var(--green-900);padding:var(--space-6) var(--space-6) var(--space-7)}
.intg-c b{display:block;font-size:var(--size-small);font-weight:600;color:var(--text-on-dark)}
.intg-c span{display:block;margin-top:var(--space-3);font-family:var(--font-mono);font-size:var(--size-micro);text-transform:uppercase;letter-spacing:.12em;color:var(--band-muted)}
.intg-c.now{background:var(--green-700)}
.intg-c.now span{color:var(--text-on-dark)}

/* ═══ THE DECISION — both ways it can go ═════════════════════════════════════ */
.ledger{max-width:840px;margin:0 auto}
.led-k{font-family:var(--font-mono);font-size:var(--size-micro);text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);color:var(--text-secondary)}
.led-q{border:1px solid var(--border-default);border-radius:var(--radius-xl);background:var(--surface-card);padding:var(--space-8);display:grid;grid-template-columns:1fr auto;gap:var(--space-7);align-items:center;box-shadow:var(--shadow-md)}
.led-q p{margin-top:var(--space-4);font-size:var(--size-small);color:var(--text-secondary);max-width:44ch}
.led-act{display:flex;gap:var(--space-4);flex:none}
.led-paths{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-6);margin-top:var(--space-6)}
.led-p{border:1px dashed var(--border-strong);border-radius:var(--radius-lg);padding:var(--space-7)}
.led-p ul{list-style:none;margin:var(--space-5) 0 0;padding:0;display:flex;flex-direction:column}
.led-p li{display:flex;gap:var(--space-5);align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border-hairline);font-size:var(--size-small);color:var(--text-primary)}
.led-p li:last-child{border-bottom:0}
.led-p li::before{content:"";width:14px;height:1px;background:var(--ink);flex:none;transform:translateY(-4px)}
.led-p b{font-family:var(--font-mono);font-weight:500}
.led-write{margin-top:var(--space-6);border-radius:var(--radius-lg);background:var(--green-900);color:#F2F5F1;padding:var(--space-6) var(--space-7);display:flex;align-items:baseline;gap:var(--space-6);flex-wrap:wrap;transition:background var(--dur-base) var(--ease-standard)}
.led-write .led-k{color:#A8C4AF;flex:none}
.led-write em{font-style:normal;font-size:var(--size-small);max-width:60ch}
.led-write.on{background:var(--green-700)}
/* Answering the question: the path you took lights, the other recedes, and the
   record strip rewrites itself. Approve reads sage; pushing back reads ink —
   neither is scolded, and ember stays reserved for the buttons. */
.led-p{transition:border-color var(--dur-base) var(--ease-standard),background var(--dur-base) var(--ease-standard),opacity var(--dur-base) var(--ease-standard)}
.led-ph{display:flex;align-items:center;gap:var(--space-5);min-height:24px}
.led-ph .tls-chip{margin-left:auto}
/* The chosen path is marked by its solid border and wash. The other card keeps
   full contrast — its three lines are the point of the section, and dimming
   text to signal "not chosen" cannot clear AA at any opacity worth reading. */
.led-paths>.led-p.lit:first-child{border-style:solid;border-color:color-mix(in oklab, var(--sage) 62%, transparent);background:color-mix(in oklab, var(--sage) 9%, #FFFFFF)}
.led-paths>.led-p.lit:last-child{border-style:solid;border-color:color-mix(in oklab, var(--green-900) 38%, transparent);background:color-mix(in oklab, var(--green-900) 5%, #FFFFFF)}
/* The chosen button carries the emphasis; the other stays at full strength, so
   the way back to the alternative never reads as disabled. */
.led-act .tls-btn{transition:box-shadow var(--dur-base) var(--ease-standard)}
.led-act .tls-btn[aria-pressed="true"]{box-shadow:0 0 0 3px color-mix(in oklab, var(--action) 26%, transparent)}
.led-reset{display:block;margin:var(--space-6) auto 0;appearance:none;background:none;border:0;padding:6px 2px;font-family:var(--font-mono);font-size:var(--size-micro);text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);color:var(--text-secondary);cursor:pointer;border-bottom:1px solid var(--border-strong)}
.led-reset:hover{color:var(--text-primary)}

/* ═══ THE MARK — where the logo comes from ══════════════════════════════════
   The one section that is about the company rather than the product, so it sits
   on the palest sage wash and gives the mark room to be looked at. */
.mark{background:color-mix(in oklab, var(--sage) 6%, #FFFFFF)}
.markwrap{display:grid;grid-template-columns:minmax(280px,.85fr) minmax(0,1.15fr);gap:var(--space-12);align-items:center}
.mark-art{display:flex;flex-direction:column;align-items:center;gap:var(--space-8)}
.mark-glyph{width:min(300px,68%);aspect-ratio:1;background:var(--ink);-webkit-mask:url(../assets/talous-mark.png) center/contain no-repeat;mask:url(../assets/talous-mark.png) center/contain no-repeat;animation:mark-turn 64s linear infinite}
@keyframes mark-turn{to{transform:rotate(360deg)}}
.mark-copy h2{margin-top:var(--space-5);max-width:20ch}
.mark-lede{margin-top:var(--space-6);color:var(--text-secondary)}
.legend{list-style:none;margin:var(--space-9) 0 0;padding:0;display:flex;flex-direction:column}
.legend li{display:grid;grid-template-columns:96px 1fr;gap:var(--space-7);align-items:center;padding:var(--space-6) 0;border-top:1px solid color-mix(in oklab, var(--sage) 26%, transparent)}
.legend li:last-child{border-bottom:1px solid color-mix(in oklab, var(--sage) 26%, transparent)}
.legend b{display:block;font-size:var(--size-small);font-weight:600}
.legend p{margin-top:var(--space-2);font-size:var(--size-small);color:var(--text-secondary);line-height:1.5}
.lg{display:flex;align-items:center;gap:4px;height:22px}
.lg i{display:block;background:var(--ink);border-radius:50%;flex:none}
.lg-dot i:first-child{width:14px;height:14px}
.lg-dot i:not(:first-child){display:none}
.lg-pair i:nth-child(-n+2){width:13px;height:13px;margin-right:-3px}
.lg-pair i:last-child{display:none}
.lg-chain i:first-child{width:15px;height:15px}
.lg-chain i:nth-child(2){width:11px;height:11px;margin-left:-2px}
.lg-chain i:last-child{width:7px;height:7px;margin-left:-1px}
.lg-ring{width:22px}
.lg-ring i{display:none}
.lg-ring::before{content:"";width:22px;height:22px;background:var(--ink);-webkit-mask:url(../assets/talous-mark.png) center/contain no-repeat;mask:url(../assets/talous-mark.png) center/contain no-repeat}
.mark-close{margin-top:var(--space-8);font-size:var(--size-body);font-weight:500;max-width:44ch}

/* ═══ ANSWERS ════════════════════════════════════════════════════════════════ */
.qa{max-width:760px;margin:0 auto}

/* ═══ CLOSE — ten seats ══════════════════════════════════════════════════════ */
#close{padding:var(--space-14) 0}
#close .ep-eyebrow{color:var(--band-muted)}
.close-t{margin-top:var(--space-5);color:var(--text-on-dark);max-width:20ch}
.steps3{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--space-8);margin:var(--space-11) 0}
.steps3 > div{border-left:1px solid var(--border-on-dark);padding-left:var(--space-6)}
.steps3 .led-k{color:var(--band-muted)}
.steps3 b{display:block;margin-top:var(--space-4);font-size:var(--size-body);font-weight:600;color:var(--text-on-dark)}
.steps3 p{margin-top:var(--space-3);font-size:var(--size-small);line-height:1.5;color:var(--band-muted);max-width:30ch}

/* ═══ FOOTER ═════════════════════════════════════════════════════════════════ */
.site-foot{background:var(--surface-page);padding:var(--space-13) 0 var(--space-9)}
.foot-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr;gap:var(--grid-gap)}
.foot-note{color:var(--text-secondary);max-width:34ch;margin-top:var(--space-6)}
.foot-links{display:flex;flex-direction:column;gap:var(--space-4)}
.foot-links .ep-eyebrow{margin-bottom:var(--space-2)}
.foot-links a{position:relative;font-size:var(--size-small);color:var(--text-secondary);text-decoration:none;transition:var(--transition-color)}
.foot-links a:hover{color:var(--text-primary)}
.foot-links a::after{content:"";position:absolute;left:0;right:0;bottom:-2px;height:1px;background:currentColor;clip-path:inset(0 100% 0 0);transition:clip-path var(--dur-base) var(--ease-standard)}
.foot-links a:hover::after{clip-path:inset(0)}
.foot-bottom{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-6);margin-top:var(--space-13);padding-top:var(--space-6);border-top:1px solid var(--border-hairline);font-size:var(--size-caption);color:var(--text-secondary)}

@media (prefers-reduced-motion:reduce){.mark-glyph{animation:none}}
@media (max-width:940px){.spot{grid-template-columns:1fr}.frame-hold{position:static;order:-1;padding-top:0}.step,.step.past{opacity:1}.step{min-height:0;padding:var(--space-7) 0;cursor:default}.spot-dots{display:none}.intg-g{grid-template-columns:repeat(3,1fr)}.led-q{grid-template-columns:1fr}.led-paths,.steps3{grid-template-columns:1fr}.markwrap{grid-template-columns:1fr;gap:var(--space-9)}.foot-grid{grid-template-columns:1fr}}
@media (max-width:560px){.intg-g{grid-template-columns:1fr 1fr}.rf{grid-template-columns:1fr}.rf-side{display:none}}

/* ═══ STATIC-BUILD ADDITIONS ═════════════════════════════════════════════════
   Two rules the React prototype expressed as inline styles rather than CSS.
   Neither changes a rendered pixel. */

/* Lockup. The component derived its gap and wordmark box from the mark height
   (its `size` prop); same arithmetic, held in one custom property. The mark's
   own min-width in pattern.css still clamps it at 24px, exactly as it did when
   the prop was set to 18 or 16 inside the product frames. */
.tls-lock{display:inline-flex;align-items:center;gap:calc(var(--lk) * .42);text-decoration:none}
.tls-lock .tls-mark{width:var(--lk);height:var(--lk)}
.tls-lock .tls-wordmark{width:calc(var(--lk) * 4);height:calc(var(--lk) * .96)}

/* The brand name in text, for crawlers and for copy-paste, beside a mark that
   is a CSS mask. Out of flow, so it is not a flex item and cannot open a gap. */
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}

/* ═══ INSTEAD — the five things already paid for ═════════════════════════════
   §4.4 as a ledger rather than prose. What each one gave you is muted; what it
   took with it carries full ink, because the enemy is the leaving, not the
   buying. */
.inst{max-width:940px;margin:0 auto}
.inst-h,.inst-r{display:grid;grid-template-columns:minmax(110px,.62fr) minmax(0,1fr) minmax(0,1fr);gap:var(--space-5) var(--space-9);align-items:baseline}
.inst-h{padding-bottom:var(--space-5);border-bottom:1px solid var(--ink)}
.inst-h span{font-family:var(--font-mono);font-size:var(--size-micro);text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);color:var(--text-secondary)}
.inst-r{padding:var(--space-8) 0;border-bottom:1px solid var(--border-default)}
.inst-r b{font-size:var(--size-h3);font-weight:var(--weight-semibold);letter-spacing:var(--tracking-heading)}
.inst-r p{font-size:var(--size-small);line-height:1.55;color:var(--text-secondary);max-width:34ch}
.inst-r .gone{color:var(--text-primary)}
.inst-close{margin-top:var(--space-12);text-align:center}
.inst-close p{margin:0 auto;max-width:58ch;font-size:var(--size-body);line-height:1.6;color:var(--text-secondary)}
.inst-close b{display:block;margin-top:var(--space-10);font-family:var(--font-heading);font-size:var(--size-mega);font-weight:var(--weight-semibold);line-height:1.08;letter-spacing:-.026em;color:var(--text-primary)}

/* Integrations: six live, three dated — §3.4's horizons with TikTok at the
   front. Nine cells, so three columns is the only split without an orphan;
   held at three all the way down rather than leaving a half-row on a phone. */
.intg-g{grid-template-columns:repeat(3,1fr)}
.intg-c b{overflow-wrap:break-word}

/* The header nav ran off the side of a phone: at 390px the CTA sat 141px past
   the right edge and the page scrolled sideways. Below the width where all
   four links plus the button fit, the links drop and the button stays — the
   footer carries the same nav in full. */
@media (max-width:820px){.head-nav a:not(.tls-btn){display:none}}

@media (max-width:940px){
  .inst-h{display:none}
  .inst-r{grid-template-columns:1fr;gap:var(--space-4);padding:var(--space-7) 0}
  .inst-r p{max-width:52ch}
  /* Without the header row the two columns need their own labels. */
  .inst-r p::before{font-family:var(--font-mono);font-size:var(--size-micro);text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);color:var(--text-secondary);display:block;margin-bottom:var(--space-2)}
  .inst-r .got::before{content:"What you got"}
  .inst-r .gone::before{content:"What walked out"}
}

/* The legend is glyph and label only, as the concept sheet sets it out, so the
   rows tighten to the height of a single line. */
.legend li{padding:var(--space-5) 0}
.legend b{font-size:var(--size-body)}

/* ═══ NO INLINE STYLES ═══════════════════════════════════════════════════════
   The live origin sends style-src 'self' with no 'unsafe-inline', so every
   style="" attribute is dropped before it applies. That is how the icon sprite
   ended up laying out at its default 300×150 above the header, and how the
   wordmark — sized from calc(var(--lk) * 4) — collapsed to nothing when --lk
   never arrived. Everything the markup used to carry inline lives here. */
.lu-sprite{position:absolute;width:0;height:0;overflow:hidden}
.tls-lock{--lk:24px}
.tls-lock-sm{--lk:18px}
.tls-lock-xs{--lk:16px}
.mark-bleed-left{width:920px;height:920px;left:-419.52px;bottom:-379.96px}
.ha-tile .l b.d-action{background:var(--action)}
.ha-tile .l b.d-watch{background:var(--watch)}
.ha-tile .l b.d-sage{background:var(--sage)}
/* The frame's buttons are a picture of the product, not controls. */
.fv-act{pointer-events:none}

/* ═══ RUNNING TODAY ══════════════════════════════════════════════════════════
   What the product does now, and nothing else. The previous version of this
   block put "Next" and "Later" cells beside the live ones, which reads as a
   roadmap and invites a visitor to discount everything on the row. Six things
   that work, stated once. */
.live-g{list-style:none;margin:var(--space-10) 0 0;padding:0;display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--border-on-dark);border:1px solid var(--border-on-dark);border-radius:var(--radius-xl);overflow:hidden}
.live-g li{background:var(--green-900);padding:var(--space-8) var(--space-7) var(--space-9);display:flex;flex-direction:column;gap:var(--space-4)}
.live-d{width:7px;height:7px;border-radius:50%;background:var(--sage);flex:none;box-shadow:0 0 0 4px color-mix(in oklab, var(--sage) 22%, transparent)}
.live-g b{font-size:var(--size-h3);font-weight:var(--weight-semibold);letter-spacing:var(--tracking-heading);color:var(--text-on-dark)}
.live-g em{font-style:normal;font-size:var(--size-small);line-height:1.5;color:var(--band-muted);max-width:26ch}
.live-note{margin-top:var(--space-8);font-family:var(--font-mono);font-size:var(--size-micro);text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);color:var(--band-muted);max-width:none}

/* ═══ THE STORY HEAD ═════════════════════════════════════════════════════════
   Centred, at masthead scale, and the pinned frame centred under it rather than
   flush to the right edge of its column. */
.room-head{text-align:center;padding-bottom:var(--space-9)}
.room-head .ep-eyebrow{display:block;max-width:none;margin:0 auto}
.room-head h2{margin:var(--space-6) auto 0;max-width:15ch;color:var(--text-on-dark)}
.room-head p{margin:var(--space-7) auto 0;max-width:46ch}
.frame-hold{display:flex;flex-direction:column;align-items:center}
.frame-hold .rf{width:100%;max-width:660px}
.spot{grid-template-columns:320px minmax(0,1fr)}
.spot-dots{align-self:center}

/* ═══ THE DECISION — the chosen path inverts ═════════════════════════════════
   A wash and a border change was too quiet to read as an answer. The path you
   take flips to the dark surface with light type; the one you did not keeps
   full ink on paper. Nothing is dimmed, so both stay legible — the contrast is
   between the two surfaces, not between readable and unreadable. */
.led-paths>.led-p.lit,
.led-paths>.led-p.lit:first-child,
.led-paths>.led-p.lit:last-child{border-style:solid;border-color:var(--green-900);background:var(--green-900);color:var(--text-on-dark);box-shadow:var(--shadow-lg)}
.led-p.lit .led-k{color:var(--green-300)}
.led-p.lit li{color:var(--text-on-dark);border-bottom-color:color-mix(in oklab, #A8C4AF 24%, transparent)}
.led-p.lit li::before{background:var(--green-300)}
.led-p.lit .tls-chip{background:var(--green-700);color:var(--text-on-dark)}
.led-paths>.led-p.lit:first-child{border-color:var(--sage);background:color-mix(in oklab, var(--sage) 82%, var(--green-900))}
.led-paths>.led-p.lit:first-child .led-k,
.led-paths>.led-p.lit:first-child li::before{color:#EAF2EC;background:none}
.led-paths>.led-p.lit:first-child li::before{background:#EAF2EC}
.led-p.dim{background:var(--surface-card)}

@media (max-width:940px){
  .live-g{grid-template-columns:1fr}
  .frame-hold .rf{max-width:none}
}

/* The pinned frame centres in the viewport rather than hugging the header, so
   it sits level with whichever moment is currently lit — the focal line for the
   steps is 46% of the viewport, and the screen should meet it there. Falls back
   to the old offset on short viewports where centring would push it under the
   sticky header. */
.frame-hold{top:max(96px, calc((100vh - 560px) / 2))}
.spot{grid-template-columns:300px minmax(0,1fr)}
.frame-hold .rf{max-width:640px}

/* ═══ THE STAGE — the product, centred ═══════════════════════════════════════
   The moments used to sit in a rail beside the screen, which pushed the screen
   off to the right and made the text the thing you read first. Now the screen
   pins in the middle of the viewport and the moments crossfade beneath it: one
   at a time, in the same place, under the thing they describe. The track below
   the stage carries the scroll distance. */
.spot{display:block;position:relative;padding-bottom:0}
.stage{position:sticky;top:0;min-height:100svh;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-8);padding:var(--space-9) 0}
.stage .rf{width:100%;max-width:720px;margin:0}
/* Four captions stacked in one place. The box reserves the tallest so nothing
   below it moves as they swap. */
.stepcol{position:relative;width:100%;max-width:560px;min-height:137px;text-align:center;padding:0}
.step{position:absolute;inset:0;display:block;min-height:0;padding:0;border:0;opacity:0;transform:translateY(10px);transition:opacity .45s var(--ease-standard),transform .45s var(--ease-standard);cursor:default}
.step.on{opacity:1;transform:none}
.step.past{opacity:0}
.step .step-k{color:var(--action)}
.step h3{margin-top:var(--space-4);font-size:var(--size-h2);color:var(--text-on-dark)}
.step p{margin:var(--space-5) auto 0;max-width:46ch;font-size:var(--size-body);line-height:1.55;color:var(--band-muted)}
.spot-dots{margin:0;justify-content:center}
.spot-dot{cursor:pointer}
.stage .t-illus{color:color-mix(in oklab, #A8C4AF 70%, transparent)}
/* 4 moments × 85vh of reading room each. */
.spot-track{height:340svh;pointer-events:none}

/* ═══ SIX IN, ONE OUT ════════════════════════════════════════════════════════
   The section's claim, drawn. Six live sources run into one rail and one
   figure comes out — which is the product in a picture, and it can only show
   things that exist. */
.conv{display:grid;grid-template-columns:minmax(0,1fr) 64px minmax(0,.95fr);align-items:center;margin-top:var(--space-11)}
.conv-in{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:1px}
.conv-in li{position:relative;padding:var(--space-6) var(--space-8) var(--space-6) var(--space-7);background:color-mix(in oklab, #FFFFFF 4%, transparent);border-radius:var(--radius-md) 0 0 var(--radius-md);display:flex;flex-direction:column;gap:3px}
/* Each row runs a hairline out to the rail. */
.conv-in li::after{content:"";position:absolute;left:100%;top:50%;width:64px;height:1px;background:var(--border-on-dark)}
.conv-d{position:absolute;left:var(--space-5);top:calc(50% - 3px);width:6px;height:6px;border-radius:50%;background:var(--sage)}
.conv-in b{font-size:var(--size-body);font-weight:var(--weight-semibold);color:var(--text-on-dark)}
.conv-in em{font-style:normal;font-size:var(--size-caption);color:var(--band-muted)}
.conv-rail{position:relative;height:100%;justify-self:center;width:1px;background:var(--border-on-dark)}
.conv-rail::after{content:"";position:absolute;left:0;top:50%;width:32px;height:1px;background:var(--sage)}
.conv-out{padding:var(--space-9) var(--space-9) var(--space-9) var(--space-10);border:1px solid color-mix(in oklab, var(--sage) 46%, transparent);background:color-mix(in oklab, var(--sage) 12%, transparent);border-radius:var(--radius-xl)}
.conv-k{font-family:var(--font-mono);font-size:var(--size-micro);text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);color:var(--band-muted)}
.conv-v{margin-top:var(--space-4);font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:clamp(30px,3.4vw,46px);font-weight:var(--weight-medium);letter-spacing:-.02em;line-height:1;color:var(--green-300)}
.conv-s{margin-top:var(--space-6);font-size:var(--size-small);line-height:1.55;color:var(--band-muted);max-width:34ch}
.conv-out .t-illus{display:block;margin-top:var(--space-7)}

/* ═══ THE DECISION — the answer you gave, unmistakably ═══════════════════════
   A wash and a border swap read as nothing. The path you take goes to the dark
   surface with light type and lifts off the page; the one you did not sinks
   into the paper and keeps every word at full contrast. */
.led-paths>.led-p{transition:background var(--dur-slow) var(--ease-standard),border-color var(--dur-slow) var(--ease-standard),transform var(--dur-slow) var(--ease-standard),box-shadow var(--dur-slow) var(--ease-standard)}
.led-paths>.led-p.lit,
.led-paths>.led-p.lit:first-child,
.led-paths>.led-p.lit:last-child{border-style:solid;border-color:var(--green-900);background:var(--green-900);color:var(--text-on-dark);transform:translateY(-6px);box-shadow:0 18px 44px -12px rgba(15,32,25,.45)}
.led-p.lit .led-k{color:var(--green-300)}
.led-p.lit li{color:var(--text-on-dark);border-bottom-color:color-mix(in oklab, #A8C4AF 22%, transparent)}
.led-p.lit li::before{background:var(--green-300)}
.led-p.lit b{color:#FFFFFF}
.led-p.lit .tls-chip{background:var(--green-700);color:var(--text-on-dark)}
.led-paths>.led-p.dim{background:var(--surface-sunken);border-style:dashed;border-color:var(--border-default);transform:none;box-shadow:none}

/* ═══ THE ASK ════════════════════════════════════════════════════════════════ */
.cta{text-align:center;max-width:760px;margin:0 auto}
.cta .ep-eyebrow{display:block;max-width:none;margin:0 auto}
.cta-t{margin:var(--space-6) auto 0;max-width:14ch;color:var(--text-on-dark)}
.cta-l{margin:var(--space-8) auto 0;max-width:52ch}
.cta-go{margin-top:var(--space-10);height:60px;padding:0 var(--space-10);font-size:var(--size-body)}
.cta-sub{margin:var(--space-6) auto 0;max-width:none;font-family:var(--font-mono);font-size:var(--size-caption);letter-spacing:.02em;color:var(--band-muted)}
.cta-steps{list-style:none;margin:var(--space-13) 0 0;padding:0;display:grid;grid-template-columns:repeat(3,1fr);gap:var(--space-8);text-align:left}
.cta-steps li{border-top:1px solid var(--border-on-dark);padding-top:var(--space-6)}
.cta-steps span{font-family:var(--font-mono);font-size:var(--size-micro);letter-spacing:var(--tracking-eyebrow);color:var(--action)}
.cta-steps b{display:block;margin-top:var(--space-4);font-size:var(--size-small);font-weight:var(--weight-semibold);color:var(--text-on-dark)}
.cta-steps em{display:block;margin-top:var(--space-3);font-style:normal;font-size:var(--size-small);line-height:1.5;color:var(--band-muted)}
.cta-alt{margin:var(--space-11) auto 0;max-width:none;font-size:var(--size-small);color:var(--band-muted)}

@media (max-width:940px){
  .stage{min-height:0;position:static;padding:0}
  .stage .rf{max-width:none}
  .stepcol{position:static;min-height:0;max-width:none;text-align:left;margin-top:var(--space-9)}
  .step{position:static;opacity:1;transform:none;margin-bottom:var(--space-9)}
  .step.past{opacity:1}
  .step p{margin-inline:0}
  .spot-track{display:none}
  .spot-dots{display:none}
  .conv{grid-template-columns:1fr;gap:var(--space-8)}
  .conv-in li{border-radius:var(--radius-md)}
  .conv-in li::after,.conv-rail{display:none}
  .cta-steps{grid-template-columns:1fr;gap:var(--space-7)}
}

/* Stage order: the screen first, then the moment it is showing, then the pager.
   Caption, pager and hint live in one wrapper (.stage-under) so the grid that
   centres the frame can treat them as a single row — see THE STAGE, CENTRED at
   the end of this file. The wrapper takes the stage's own gap, so the rhythm
   between caption, pager and hint does not change. */
.frame-hold{position:static;top:auto;padding:0;width:100%;display:flex;justify-content:center}
.stage .rf{max-width:880px}
.stage-under{display:flex;flex-direction:column;align-items:center;gap:inherit;width:100%}
.stage .t-illus{margin:0}

/* At stage width the workspace is wide enough for the KPI strip to run in one
   row, which is how the product actually lays it out — and it stops the frame
   growing tall and half-empty on the shorter moments. */
.stage .rf-kpis{grid-template-columns:repeat(4,1fr)}
.stage .rf-side{min-height:0}
.stage .rf-body{min-height:380px}
.stage .fv{padding:var(--space-7)}

/* ═══ SIX IN, ONE OUT — drawn ════════════════════════════════════════════════
   The card version was a stack of grey boxes with a rule beside it: it listed
   the claim rather than making it. This one draws it. Six labels, right-aligned
   so they read as the start of something, six hairlines curving into a single
   point, and the figure they produce set as type rather than boxed. */
.flow{display:grid;grid-template-columns:minmax(0,1fr) clamp(96px,13vw,210px) minmax(0,1.05fr);align-items:stretch;min-height:420px;margin-top:var(--space-12)}
.flow-in{list-style:none;margin:0;padding:0;display:grid;grid-template-rows:repeat(6,1fr);text-align:right}
.flow-in li{display:flex;flex-direction:column;justify-content:center;padding-right:var(--space-8)}
.flow-in b{font-size:var(--size-h3);font-weight:var(--weight-semibold);letter-spacing:var(--tracking-heading);color:var(--text-on-dark)}
.flow-in em{margin-top:5px;font-style:normal;font-family:var(--font-mono);font-size:var(--size-caption);text-transform:none;letter-spacing:0;color:var(--band-muted)}
.flow-art{width:100%;height:100%;fill:none;stroke:color-mix(in oklab, #A8C4AF 32%, transparent);stroke-width:1}
/* The point everything arrives at. */
.flow-out{position:relative;display:flex;flex-direction:column;justify-content:center;padding-left:var(--space-10)}
.flow-out::before{content:"";position:absolute;left:-4px;top:calc(50% - 4px);width:8px;height:8px;border-radius:50%;background:var(--sage);box-shadow:0 0 0 5px color-mix(in oklab, var(--sage) 20%, transparent)}
.flow-k{font-family:var(--font-mono);font-size:var(--size-caption);text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);color:var(--band-muted)}
.flow-v{margin-top:var(--space-5);font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:clamp(34px,4.2vw,62px);font-weight:var(--weight-medium);letter-spacing:-.03em;line-height:1;color:var(--green-300)}
.flow-s{margin-top:var(--space-7);font-size:var(--size-body);line-height:1.6;color:var(--band-muted);max-width:32ch}
.flow-note{margin-top:var(--space-9);max-width:none}

@media (max-width:940px){
  .flow{grid-template-columns:1fr;min-height:0;gap:var(--space-9)}
  .flow-in{grid-template-rows:none;gap:var(--space-6);text-align:left}
  .flow-in li{padding-right:0}
  .flow-art{display:none}
  .flow-out{padding-left:var(--space-7);border-left:2px solid var(--sage)}
  .flow-out::before{display:none}
}

/* The strands were near-invisible on an 8-bit panel; the caption belongs under
   the number it qualifies, not stranded at the far left of the section. */
.flow-art{stroke:color-mix(in oklab, #A8C4AF 46%, transparent)}
.flow-note{margin-top:var(--space-8)}

/* ═══ SIX IN, ONE OUT — give it a focal point ════════════════════════════════
   The first version was six grey hairlines and a green figure on a green
   ground: no contrast, no direction, nothing to land on. Three changes.
   The strands brighten as they travel, so the eye follows the money rather
   than scanning six identical lines. They draw themselves in when the block
   arrives, one after another, so you watch six things become one. And the
   figure at the end is the brightest thing in the section — it is the only
   thing here anyone actually wants. */
.flow{min-height:460px}
.flow-art{stroke-width:1.25}
/* The draw-in is a wipe, not a dash.
   It was stroke-dasharray:1 over pathLength="1", which is the usual way to draw
   an SVG path on. It cannot work here. These paths carry
   vector-effect="non-scaling-stroke" inside a viewBox with
   preserveAspectRatio="none", so the stroke is generated in screen space while
   pathLength normalises user space — the dash pattern stops matching the path
   it is dashing, and the browser draws each strand for a while and then simply
   stops. Every strand was rendering with a hole punched through its middle:
   six stubs by the labels, a bright fan by the figure, and nothing joining
   them. The section's whole claim is that these six run into one, and the
   picture was saying the opposite.
   Clipping the group left-to-right animates the same idea, sweeps the way the
   money goes, and depends on no path geometry at all. */
.flow-reveal{clip-path:inset(0 100% 0 0)}
[data-in].flow .flow-reveal{clip-path:inset(0);transition:clip-path 1.6s var(--ease-out)}
@media (prefers-reduced-motion:reduce){
  .flow-reveal{clip-path:none}
  [data-in].flow .flow-reveal{transition:none}
}
/* The arrival: a lamp behind the figure, not a border around it. */
.flow-out::after{content:"";position:absolute;left:-140px;top:50%;width:420px;height:420px;transform:translateY(-50%);border-radius:50%;background:radial-gradient(circle, color-mix(in oklab, var(--sage) 30%, transparent) 0%, transparent 68%);pointer-events:none;z-index:-1}
.flow-out{z-index:0}
.flow-out::before{width:10px;height:10px;left:-5px;top:calc(50% - 5px);background:#C7E4D0;box-shadow:0 0 0 6px color-mix(in oklab, var(--sage) 28%, transparent),0 0 26px 6px color-mix(in oklab, var(--sage) 40%, transparent)}
.flow-v{font-size:clamp(38px,5.2vw,80px);color:color-mix(in oklab, var(--green-300) 62%, #FFFFFF);letter-spacing:-.035em}
.flow-k{color:#C7E4D0}
.flow-s{color:var(--text-muted-on-dark);max-width:34ch}
/* The labels were the same muted green as everything else on the band. */
.flow-in b{font-size:var(--size-h2)}
.flow-in em{color:color-mix(in oklab, #A8C4AF 78%, transparent)}
/* One line, always — a wrapped "RM / 118,420" reads as two numbers. */
.flow-v{font-size:clamp(34px,4.4vw,64px);white-space:nowrap}
/* The new headline is two spoken sentences, so it needs a hair more room. */
.hero-c .t-hero{max-width:19ch}
/* NB for anyone auditing this: .rf-body reports a 12px scroll overflow and it is
   not a bug. The three inactive panels sit at translateY(12px) waiting to fade
   in, so they hang 12px past the bottom while invisible. .rf clipping them is
   the correct behaviour — every panel's content fits the box with ~50px spare. */

/* ═══ COMPACTION ═════════════════════════════════════════════════════════════
   Every section was breathing at 128px top and bottom, which on a 910px-tall
   laptop meant a quarter of some screens was empty before the content started.
   Pulled in across the board. The hero keeps its original spacing — it is the
   one place the air is doing work. */
.tls-sec{padding:var(--space-14) 0}
.tls-sec-tight{padding:var(--space-12) 0}
.tls-head-c{margin-bottom:var(--space-11)}
.ledger .led-q{padding:var(--space-7)}
.inst{margin-top:0}
.inst-r{padding:var(--space-7) 0}
.inst-close{margin-top:var(--space-10)}
.inst-close b{margin-top:var(--space-8)}
.legend{margin-top:var(--space-8)}
.legend li{padding:var(--space-4) 0}
.markwrap{gap:var(--space-11)}
.mark-close{margin-top:var(--space-7)}
.qa{margin-top:0}
#close{padding:var(--space-13) 0}
.cta-steps{margin-top:var(--space-11)}
.cta-alt{margin-top:var(--space-9)}
.room-head{padding:var(--space-12) 0 var(--space-6)}
/* Four moments at ~62vh of scroll each rather than 85. Still one at a time and
   still unhurried; it was simply a long way to the bottom. */
.spot-track{height:250svh}
.stage{min-height:100svh;padding:var(--space-7) 0}
.flow{min-height:400px;margin-top:var(--space-10)}

/* ═══ SIX IN, ONE OUT — its own surface, and a centred head ══════════════════
   Green 700 against the story's green 900: a step lighter, so the block reads
   as a different place rather than more of the band above it. The head centres
   like every other section head on the page; the diagram inside stays
   left-to-right, because that is the direction it means. */
/* Black, not another green. Green 700 beside green 900 was a shade, not a
   change — it still read as more of the same band. The brand's third surface is
   the neutral one, and on it the sage strands and the figure carry further than
   they ever did on green. Hairlines top and bottom so the edge is a decision
   rather than a fade. */
/* Flush to both edges of the story section. It used to sit 64px below the
   stage and 96px above the section's own bottom padding, so a strip of pine
   showed above the black and another below it — which does not read as two
   surfaces meeting, it reads as a block that failed to fill its box. The
   colour change IS the boundary, so nothing may show through on either side:
   the band's own padding gives it room, in black. One hairline on the pine
   seam above; below, black meets cream and needs no help. */
.intg-band{background:var(--black-900);padding:var(--space-13) 0;margin-top:0;border-top:1px solid color-mix(in oklab, #A8C4AF 20%, transparent);border-bottom:0}
.room{padding-bottom:0}
/* padding-block, not padding. This element is also the .tls-wrap, and a flat
   `padding:0` took its horizontal gutter with it — so on anything narrower than
   the page max the six labels and the figure ran hard into both screen edges.
   The band supplies the vertical rhythm now; the gutter still belongs to the
   wrap. */
.intg{padding-block:0;border-top:0;text-align:center}
.intg .ep-eyebrow{display:block;max-width:none;margin:0 auto}
.intg-t{margin:var(--space-6) auto 0;max-width:22ch;color:var(--text-on-dark)}
.flow{text-align:left}
/* On the lighter ground the strands and the lamp need to work a little harder. */
.intg-band .flow-art{stroke:color-mix(in oklab, #C7E4D0 50%, transparent)}
.intg-band .flow-out::after{background:radial-gradient(circle, color-mix(in oklab, var(--sage) 34%, transparent) 0%, transparent 70%)}
.intg-band .flow-in em{color:color-mix(in oklab, #A8C4AF 82%, transparent)}
.intg-band .flow-s{color:var(--on-black-muted)}

/* ═══ THE STRANDS, LEGIBLE ═══════════════════════════════════════════════════
   The middle column was capped at 210px. With preserveAspectRatio="none" the
   curve's shape is the column's aspect ratio, so 210 wide against 400 tall
   squashed all six into a near-vertical smear that met at the dot looking like
   a stray arrowhead — three of the six could not be told apart. Give them room
   to travel and the fan reads as a fan.
   Guarded by min-width, because the stack rule that collapses .flow to one
   column lives further up the file — an unguarded .flow here wins at every
   width and puts the six labels and the figure back into two columns on a
   phone, at 390px, where they have no room to be. */
@media (min-width:941px){
  .flow{grid-template-columns:minmax(0,1fr) clamp(120px,22vw,360px) minmax(0,.95fr)}
}

/* Each source gets a node where its strand begins. Without one the curve
   starts in empty space a couple of dozen pixels off the end of the label and
   reads as unconnected — the whole point of the drawing is that these six
   things run into one. */
.flow-in li{position:relative;padding-right:var(--space-7)}
.flow-in li::after{content:"";position:absolute;right:-2px;top:50%;width:5px;height:5px;margin-top:-2.5px;border-radius:50%;background:color-mix(in oklab, #A8C4AF 55%, transparent)}
/* A hairline is 1.25px of half-transparent sage on near-black. Six of them
   overlap into a bright wedge at the junction and read as almost nothing in the
   middle of the run, which is where the eye actually travels. */
.intg-band .flow-art{stroke-width:1.4}

@media (max-width:940px){
  /* Stacked, so there is no strand to begin and no node to mark. */
  .flow-in li::after{display:none}
  .flow-in li{padding-right:0}
}

/* ═══ THE HERO DEMO, MADE PRESSABLE ══════════════════════════════════════════
   The dashboard was drawn from tokens so it would be sharp, readable and legible
   to a screen reader. Now it also answers. Seven real panels behind a real
   tablist, and under each approval the two buttons the whole page is about.
   Everything here lives in CSS: style-src is 'self' with no 'unsafe-inline',
   so a style="" attribute is dropped before it applies. */

/* The rail's items are buttons now. The story frame further down the page keeps
   its <span> version — that one is an illustration and must not invite a click —
   so every rule states both. */
.ha-nav button{display:flex;align-items:center;gap:10px;width:100%;height:32px;padding:0 var(--space-5);border:0;border-radius:var(--radius-md);background:transparent;font:inherit;font-size:var(--size-app-small);color:#A8C4AF;text-align:left;cursor:pointer;transition:background var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard)}
.ha-nav button:hover{background:color-mix(in oklab, #A8C4AF 14%, transparent);color:#F2F5F1}
.ha-nav button[aria-selected="true"]{background:var(--green-700);color:#F2F5F1}
.ha-nav button:focus-visible{outline:2px solid #C7E4D0;outline-offset:-2px}
.ha-nav button svg{width:15px;height:15px;flex:none;stroke-width:1.5}
.ha-nav button b{margin-left:auto;font-family:var(--font-mono);font-variant-numeric:tabular-nums;font-size:var(--size-micro);font-weight:400}
/* A badge at zero is noise. It goes, and the row closes up. */
.ha-nav button b:empty{display:none}

.ha-panel{display:flex;flex-direction:column;gap:var(--space-6)}
.ha-panel[hidden]{display:none}
.ha-panel:focus-visible{outline:2px solid var(--green-700);outline-offset:4px;border-radius:var(--radius-md)}

/* Deck tiles and queue rows open the tab they describe. They keep the exact
   look they had as static blocks — the only new thing is that the cursor and
   the hover say so. */
button.ha-tile,button.tls-qrow{width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:var(--surface-card);transition:border-color var(--dur-fast) var(--ease-standard),box-shadow var(--dur-fast) var(--ease-standard),background var(--dur-fast) var(--ease-standard)}
button.ha-tile:hover{border-color:var(--green-700);box-shadow:var(--shadow-sm)}
button.tls-qrow{border-left:0;border-right:0;border-top:0}
button.tls-qrow:hover{background:var(--surface-sunken)}
button.ha-tile:focus-visible,button.tls-qrow:focus-visible{outline:2px solid var(--green-700);outline-offset:-2px}

/* Approvals. Every card carries the number it is asking about, because a yes
   or a no with the figure out of sight is not a decision. */
.ha-apr{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--space-5)}
.ha-apr li{background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:var(--radius-lg);padding:var(--space-6) var(--space-7)}
.ha-apr-t{font-size:var(--size-small);font-weight:var(--weight-medium);line-height:1.4}
.ha-apr-w{margin-top:4px;font-size:var(--size-app-small);color:var(--text-secondary);line-height:1.5}
.ha-apr-f{display:flex;align-items:center;gap:var(--space-5);margin-top:var(--space-5)}
.ha-apr-f .tls-q-a{font-size:var(--size-caption)}
.ha-apr-b{display:flex;gap:var(--space-4);margin-top:var(--space-6)}
/* Approve is pine here, not ember. The brand spends ember on one call to action
   per screen and the page has already spent it, on the hero button — three more
   ember buttons inside the demo take that rule apart. It is also the only
   colour choice available: ember on white is 3.18:1, under AA at this size,
   while pine is 15.4:1. */
.ha-apr .tls-btn-primary{background:var(--green-900);border-color:var(--green-900);color:var(--text-on-dark)}
.ha-apr .tls-btn-primary:hover{background:var(--green-700);border-color:var(--green-700)}
.ha-apr-d{display:none}
/* Decided: the buttons go, the outcome stays. Nothing is hidden about what the
   answer did — that is the difference between a record and a toast. */
.ha-apr li.said .ha-apr-b{display:none}
.ha-apr li.said .ha-apr-d{display:block;margin-top:var(--space-6);padding-top:var(--space-5);border-top:1px solid var(--border-hairline);font-size:var(--size-caption);line-height:1.5;color:var(--text-secondary)}
.ha-apr li.said{border-color:color-mix(in oklab, var(--green-700) 30%, var(--border-hairline))}
.ha-apr li.said .ha-apr-t{color:var(--text-secondary)}
.ha-apr-d b{display:block;font-weight:var(--weight-medium);color:var(--text-primary)}

.ha-empty{font-size:var(--size-small);color:var(--text-secondary);padding:var(--space-6) var(--space-7)}
.ha-again{border:0;background:none;padding:0;font:inherit;color:var(--text-primary);text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.ha-again:focus-visible{outline:2px solid var(--green-700);outline-offset:2px;border-radius:2px}

/* Decision record. Newest first, and the newest one arrives lit so you can see
   where your answer went. */
.ha-rec{list-style:none;margin:0;padding:0;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:var(--radius-lg);overflow:hidden}
.ha-rec li{padding:var(--space-5) var(--space-7);border-bottom:1px solid var(--border-hairline);font-size:var(--size-app-small);line-height:1.5;color:var(--text-secondary)}
.ha-rec li:last-child{border-bottom:0}
.ha-rec li b{display:block;font-family:var(--font-mono);font-size:var(--size-micro);text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);font-weight:400;color:var(--text-primary);margin-bottom:3px}
.ha-rec li.fresh{background:color-mix(in oklab, var(--sage) 12%, var(--surface-card))}

/* Channel panels all share one table. Four data sets, one design. */
.ha-tbl{width:100%;border-collapse:collapse;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:var(--radius-lg);overflow:hidden;font-size:var(--size-app-small)}
.ha-tbl th{text-align:left;font-family:var(--font-mono);font-size:var(--size-micro);font-weight:400;text-transform:uppercase;letter-spacing:var(--tracking-eyebrow);color:var(--text-secondary);padding:var(--space-5) var(--space-6);border-bottom:1px solid var(--border-hairline);white-space:nowrap}
.ha-tbl td{padding:var(--space-5) var(--space-6);border-bottom:1px solid var(--border-hairline);line-height:1.4}
.ha-tbl tr:last-child td{border-bottom:0}
.ha-tbl td:nth-child(2),.ha-tbl td:nth-child(3){font-family:var(--font-mono);font-variant-numeric:tabular-nums;white-space:nowrap}

/* Panels differ in height — Command needs 584px, Clients 268. Without a floor,
   every tab press resizes the card and shoves the rest of the page up or down.
   The floor is the tallest panel (Approvals, 624), so on a desktop the card
   never changes size at all. The thin panels spend the difference on white
   below the table, which is what a real dashboard with a short list looks
   like. */
@media (min-width:901px){.ha-body{min-height:624px}}

@media (max-width:900px){
  /* .ha-side is display:none here, which would take the only way into six of
     the seven panels with it. Bring it back as a strip across the top of the
     card: the rail's chrome is what goes, not the navigation. This is scoped to
     the hero, because the story frame's copy of .ha-side is an illustration. */
  /* minmax(0,1fr), and min-width:0 on the rail. A bare `1fr` is
     minmax(auto,1fr), so the column refuses to shrink below its content's
     min-content width — and this rail's content is seven nowrap buttons in a
     row, 865px of them. The card kept its 342px box and quietly clipped a third
     of the dashboard, because .hero-app is overflow:hidden. Let the column
     shrink and the rail's own overflow-x does the scrolling, as intended. */
  .hero-app{grid-template-columns:minmax(0,1fr)}
  .hero-app .ha-side{display:block;min-width:0;padding:var(--space-4) 0}
  .hero-app .ha-brand,.hero-app .ha-user{display:none}
  .hero-app .ha-nav{flex-direction:row;gap:var(--space-2);padding:0 var(--space-5);overflow-x:auto;scrollbar-width:none}
  .hero-app .ha-nav::-webkit-scrollbar{display:none}
  .hero-app .ha-nav button{width:auto;flex:none;white-space:nowrap}
  /* The top bar has three things and room for two. The sync time is the one a
     phone can lose — it was wrapping and pushing the brand selector onto two
     lines, which looked like a broken card rather than a tight one. */
  .hero-app .ha-brandsel{white-space:nowrap}
  .hero-app .ha-when{display:none}
  .ha-tbl{display:block;overflow-x:auto}
}

/* ═══════════════════════════════════════════════════════════════════════════
   MOBILE
   Most of the page was already responsive — nothing scrolled sideways and
   every section stacked. What follows is the difference between a page that
   fits on a phone and a page that was made for one: targets a thumb can hit,
   a press state where there is no hover, a story frame that is not sawn off at
   the edge, and the platform details (safe areas, tap highlight, rubber band)
   that read as sloppy the moment they are missing.
   ═══════════════════════════════════════════════════════════════════════════ */

/* [hidden] has to win. The UA sheet declares it at element-selector strength,
   so any class that sets `display` beats it — .tls-btn is display:inline-flex,
   which is why the Back button on /application rendered on question one, with
   nothing behind it to go back to. */
[hidden]{display:none !important}

/* Anchors land under the sticky masthead without this. 68px of header plus a
   little air, so a heading arrives with room above it rather than pinned to
   the underside of the bar. */
:root{scroll-padding-top:88px}
section[id]{scroll-margin-top:88px}

html{overscroll-behavior-y:none}

/* The gutter has to clear the notch in landscape, and the footer has to clear
   the home indicator. max() so the normal case is untouched. */
.tls-wrap,.tls-wrap-narrow{
  padding-left:max(var(--page-gutter), env(safe-area-inset-left));
  padding-right:max(var(--page-gutter), env(safe-area-inset-right));
}
.site-foot{padding-bottom:max(var(--space-9), env(safe-area-inset-bottom))}

/* ── Touch ─────────────────────────────────────────────────────────────────
   pointer:coarse rather than a width query. A touchscreen laptop is a finger
   at 1400px, and a narrow window on a desktop is still a mouse — sizing off
   the pointer gets both right where sizing off the viewport gets both wrong. */
@media (pointer:coarse){
  /* The default tap flash is a translucent blue rectangle that belongs to no
     brand. It is the single loudest tell that nobody looked at the page on a
     phone. Removed — and replaced below, because taking it away without giving
     a press state back leaves taps feeling dead. */
  html{-webkit-tap-highlight-color:transparent}

  /* 44px is the floor Apple and Google both publish. The page had 24 targets
     under it: the masthead lock at 24px tall, every footer link at 25, the
     demo tabs at 32, every small button at 38. */
  .tls-btn-sm{height:44px}
  .site-head .tls-lock,.site-foot .tls-lock{display:inline-flex;align-items:center;min-height:44px}
  .ha-nav button{height:44px}
  .foot-links a{display:inline-flex;align-items:center;min-height:44px}
  .foot-links{gap:0}
  .tls-q summary{min-height:56px}
  .opt{min-height:52px}
  .spot-dot{min-width:44px;min-height:44px}
  /* An inline link inside a sentence is exempt from the target-size rule, but
     this one is the page's second call to action and deserves better than
     19px of hit area. Its own line, its own box. */
  .cta-alt a{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding-inline:var(--space-5)}

  /* Hover does not exist here, so the press is the only feedback there is.
     Every interactive surface answers within one frame. */
  .tls-btn:active{transform:scale(.97)}
  .ha-nav button:active,button.ha-tile:active,button.tls-qrow:active,.opt:active{background:color-mix(in oklab, currentColor 10%, transparent)}
  .ha-nav button:active{background:color-mix(in oklab, #A8C4AF 22%, transparent)}
  .tls-q summary:active{background:var(--surface-sunken)}

  /* Hover styling that sticks after a tap looks like a stuck selection. Kill
     the ones that paint a background or move something. */
  .foot-links a:hover::after{clip-path:inset(0 100% 0 0)}
  button.ha-tile:hover{border-color:var(--border-hairline);box-shadow:none}
  button.tls-qrow:hover{background:var(--surface-card)}
  .ha-nav button:hover{background:transparent;color:#A8C4AF}
  .ha-nav button[aria-selected="true"]:hover{background:var(--green-700);color:#F2F5F1}
}

/* ── Below 900: the phone layout proper ───────────────────────────────────── */
@media (max-width:900px){
  /* THE STORY FRAME. `.stage .rf-kpis{repeat(4,1fr)}` sits later in this file
     than the 760px rule that takes .tls-kpis to two columns, so it won every
     time: four KPI cards needing 408px inside a 300px frame. Two of them were
     off the right edge of the phone and the labels of all four were sheared
     off. This is the section the page calls "the real product, not a picture
     of one" — it was the one thing on the page a phone could not see. */
  .stage .rf-kpis,.rf-kpis{grid-template-columns:repeat(2,1fr)}
  .rf-body{min-height:0}

  /* 920px of decorative watermark on a 390px screen is 530px of it off the
     side, which turns a balanced bleed into a lopsided smear. Half size, and
     anchored so the arc still reads. */
  .tls-mark-bleed.mark-bleed-left{width:460px;height:460px;left:-190px;bottom:-160px}

  /* The mono captions are the smallest type on the page and a phone is held
     further from the eye than a monitor is. Nothing under 11px. */
  .ha-tile .s,.fv-label,.intg-c span{font-size:var(--size-micro)}
  .flow-in em{font-size:var(--size-caption)}

  /* Ragged headline breaks are the most visible difference between a page laid
     out for a phone and a page that merely reflowed onto one. */
  h1,h2,h3,.t-hero,.t-mega{text-wrap:balance}

  /* Two buttons of different widths stacked centre read as an accident. Every
     button row on a phone: one column, one width, full bleed of its container.
     This is the hero, and it is also the pair at the end of the application. */
  .tls-btn-row{flex-direction:column;align-items:stretch}
  .tls-btn-row .tls-btn{width:100%}
}

/* ── Small phones (≤360) ──────────────────────────────────────────────────── */
@media (max-width:360px){
  /* .tls-btn is white-space:nowrap, so a long label simply runs off the side
     of a 320px screen rather than wrapping. Let the two long ones wrap, and
     give them the height to do it in. */
  .tls-btn{white-space:normal;height:auto;min-height:44px;padding-block:12px;text-align:center;line-height:1.3}
  .tls-qrow{grid-template-columns:1fr}
  .tls-qrow .tls-q-a{justify-self:start}
  /* Two KPI cards need 241px of a 230px row at this width, so the right-hand
     one was being clipped inside the card. Buy the 11px back from the padding
     rather than stacking four cards and making the hero twice as tall. */
  .hero-app .tls-kpi,.hero-app .ha-tile{padding:var(--space-5)}
  /* The figure is clamped at 38px, which is 10 mono characters wider than a
     320px screen has left after the rail. */
  .flow-out{padding-left:var(--space-6)}
  .flow-v{font-size:30px}
}

/* iOS Safari zooms the page in when a control under 16px takes focus, and
   never zooms back out. Every field on the form, including the ones that only
   take a tap. */
@media (max-width:900px){
  input,select,textarea,button{font-size:max(16px,1em)}
  .ap-f input{font-size:16px}
}

.spot-hint{display:none;order:4;margin:var(--space-6) 0 0;text-align:center;font-family:var(--font-mono);
  font-size:var(--size-caption);letter-spacing:.02em;
  color:color-mix(in oklab, #A8C4AF 78%, transparent)}

/* ── THE STORY, ON A PHONE ──────────────────────────────────────────────────
   The desktop story pins one screen and crossfades four moments beneath it.
   Below 940px the pin is off — a sticky stage inside a 340svh track is a
   scroll hijack on a device that is already all scroll — so the section fell
   back to all four moments stacked as text with the frame frozen on the first.
   Four paragraphs and a screenshot of one of them, under a heading that says
   "that screen is the real product". The picture stopped agreeing with the
   words.
   So: keep the crossfade, and hand the control to the thumb. One moment at a
   time, the screen and the words changing together, moved by a swipe or by the
   pager — the same idea as the desktop, driven the way a phone is driven. It
   also takes roughly 900px out of the page. */
@media (max-width:940px){
  /* The moments are stacked in one place, so the box has to reserve the
     tallest of the four or the one below it moves when you swipe. Measured:
     171px at 390 and up, 198 at 360 and 320 where the headings take a third
     line. */
  .stepcol{position:relative;min-height:180px;margin-top:var(--space-8)}
  .step{position:absolute;inset:0;opacity:0;transform:translateY(10px);margin-bottom:0;
        transition:opacity .4s var(--ease-standard),transform .4s var(--ease-standard)}
  .step.on{opacity:1;transform:none}
  .step.past{opacity:0}

  /* The pager is the only visible handle, so it has to look like one: a row of
     bars wide enough to hit, with the live one in the action colour. */
  .spot-dots{display:flex;justify-content:center;gap:var(--space-2);margin-top:var(--space-7)}
  .spot-dot{padding:14px 4px}
  .spot-dot i{width:32px;height:3px}

  /* A swipe should move the moment, not select the caption underneath it. */
  .stage{touch-action:pan-y}
  .stepcol,.frame-hold{-webkit-user-select:none;user-select:none}

  /* Desktop drives the moments from the scroll and needs no instructions, so
     the hint's default is display:none — declared above this block, because a
     default that comes after the rule revealing it wins at every width and the
     hint never appears. order:4 puts it under the pager: without one it
     defaults to 0 and jumps ahead of the frame. */
  .spot-hint{display:block;order:4}
}


/* ── The story frame, sized to its contents ─────────────────────────────────
   .fv panels were position:absolute;inset:0 in a box floored at 380px, which
   is the only height they could ever have. At 1440 the tallest needs 352 and
   nobody noticed. At 900 it needs 807. Every viewport under about 1000px —
   tablets, split-screen laptops and every phone — was showing the product
   screen with its bottom third cut off, including the approvals queue, which is
   the thing the moment is about.
   Grid stacking instead: one cell, four panels in it, the row sized to the
   tallest. No magic number to be wrong, the crossfade unchanged, and the frame
   cannot be shorter than what is inside it at any width. */
.rf-body{display:grid}
.stage .fv,.fv{position:relative;inset:auto;grid-area:1/1}
/* Out of the accessibility tree and out of hit-testing when faded out, on a
   delay so the fade still runs. opacity:0 alone leaves all four readable to a
   screen reader and tappable by a finger. */
.fv{visibility:hidden;transition:opacity .5s var(--ease-standard),transform .5s var(--ease-standard),visibility 0s linear .5s}
.spot[data-s="0"] .fv0,.spot[data-s="1"] .fv1,.spot[data-s="2"] .fv2,.spot[data-s="3"] .fv3{
  visibility:visible;transition:opacity .5s var(--ease-standard),transform .5s var(--ease-standard),visibility 0s}
@media (prefers-reduced-motion:reduce){.fv{transition:none}}

@media (max-width:380px){.stepcol{min-height:205px}}

/* ═══ SIX IN, ONE OUT — the part you can press ════════════════════════════════
   The drawing said "six systems run into one number" and then sat there. Two
   things were missing: nothing moved along the strands, so the fan read as a
   diagram rather than a flow; and nothing answered the obvious question, which
   is what any one of those six actually puts into the number. */

/* margin-inline:auto, like .intg-t — a paragraph in this band inherits a
   max-width, so text-align:center only centres it inside a box still parked
   at the left gutter. */
.flow-cue{margin:var(--space-6) auto 0;max-width:none;font-family:var(--font-mono);font-size:var(--size-caption);
  letter-spacing:.02em;color:color-mix(in oklab, #A8C4AF 82%, transparent)}

/* Each source row is a button that fills its grid track, so the target is the
   whole 70-odd pixels of the row rather than the two lines of text in it. */
.fin{display:flex;flex-direction:column;align-items:flex-end;justify-content:center;
  width:100%;height:100%;margin:0;padding:var(--space-4) var(--space-5);border:0;
  border-radius:var(--radius-md);background:transparent;font:inherit;color:inherit;
  text-align:right;cursor:pointer;-webkit-appearance:none;appearance:none;
  transition:background .25s var(--ease-standard)}
.fin:hover{background:color-mix(in oklab, #A8C4AF 9%, transparent)}
.fin[aria-pressed="true"]{background:color-mix(in oklab, #A8C4AF 15%, transparent)}
.fin:focus-visible{outline:2px solid #C7E4D0;outline-offset:2px}
/* The dot where the row meets its strand: the live one, brighter and larger. */
.flow-in li.on::after{background:#E4F6EA;box-shadow:0 0 0 4px color-mix(in oklab, var(--sage) 26%, transparent)}

/* Picking a source drops the other five back rather than hiding them — the
   claim is still six, and you can see the one you chose against the rest. */
.fs{transition:opacity .45s var(--ease-standard)}
.flow[data-src] .fs{opacity:.14}
.flow[data-src] .fs.on{opacity:1}

/* The glint. A copy of the strands seen through a band that slides across
   them, so light travels the way the money does. It holds off the mark until
   the wipe-in has finished, then runs, then waits — a pulse, not a treadmill. */
.flow-hot{opacity:0;transition:opacity .6s var(--ease-standard)}
[data-in].flow .flow-hot{opacity:.9}
[data-in].flow .fsw{animation:flow-glint 5s cubic-bezier(.42,0,.58,1) 1.9s infinite}
@keyframes flow-glint{
  0%{transform:translateX(0)}
  56%{transform:translateX(132px)}
  100%{transform:translateX(132px)}
}
@media (prefers-reduced-motion:reduce){
  .flow-hot{display:none}
  [data-in].flow .fsw{animation:none}
}

/* The readout under the number. It holds its height across the swap so the
   block does not jump when you move between sources. */
.flow-read{min-height:112px}
.flow-f{margin-top:var(--space-6);font-family:var(--font-mono);font-variant-numeric:tabular-nums;
  font-size:var(--size-small);letter-spacing:.02em;color:#C7E4D0}
/* :not([hidden]) matters — adjacency is structural, so a plain .flow-f+.flow-s
   would tighten the default sentence too, when there is no figure above it. */
.flow-f:not([hidden])+.flow-s{margin-top:var(--space-4)}

@media (max-width:940px){
  .flow-cue{margin:var(--space-5) auto 0}
  /* Flush left, and the padding does not change with state — a button that
     grows when you press it drags the five rows under it down the screen. */
  .fin{align-items:flex-start;text-align:left;padding:var(--space-5) var(--space-5) var(--space-5) 0}
  .flow-read{min-height:0}
}
@media (pointer:coarse){
  .fin:hover{background:transparent}
  .fin[aria-pressed="true"]{background:color-mix(in oklab, #A8C4AF 15%, transparent)}
  .fin:active{background:color-mix(in oklab, #A8C4AF 22%, transparent)}
}

/* ═══ THE BRAND, ON THE WHITE ════════════════════════════════════════════════
   The page is white paper and stays white paper. What it lacked was any sign
   of whose paper it is: eight sections of black type on white, with the two
   brand colours locked away inside the pine band and the one CTA.

   THE HIERARCHY. Pine is the brand's main colour; ember is the accent. So on
   white, everything structural — the rule that opens a section, the mark in
   the chrome, the identity section, the column the ledger argues for — is
   pine, and ember appears only where something acts or is leaned on: buttons,
   links, the masthead's one italic word, the marker you press to open an
   answer. A tint, a rule and a glyph per section is the whole budget. */

/* Every section head opened with a mono eyebrow, and eight of them in a row is
   a tic rather than a system. The rule that replaces them says the same thing
   — "a new section starts here" — in the brand's own colours and in no words:
   a pine bar with an ember tick, main colour first, accent after. */
.tls-head-c::before,
.room-head::before,
.intg::before,
.cta::before{
  content:"";display:block;width:38px;height:3px;border-radius:2px;
  background:linear-gradient(90deg, var(--pine-500) 0 26px, transparent 26px 30px, var(--action) 30px 38px);
  margin:0 auto var(--space-7)}
/* On the dark bands the pine segment vanishes into the ground; the same rule
   reads there as sage + ember. */
.room-head::before,
.intg::before,
.cta::before{background:linear-gradient(90deg, var(--green-300) 0 26px, transparent 26px 30px, var(--action) 30px 38px)}

/* The masthead's italic word stays ember — "You" is the one word the whole
   brand leans on, which is exactly what an accent is for. The mark in both
   lockups is pine, the brand's own dark green against the ink wordmark. */
.hero .t-accent{color:var(--ember-700)}
.site-head .tls-mark,.site-foot .tls-mark{background:var(--green-700)}

/* The one section that is about the company rather than the product: the
   identity moment, so it is the most pine thing on the white run. Sage wash,
   pine mark, and the legend glyphs are miniatures of that mark. */
.mark{background:color-mix(in oklab, var(--sage) 6%, #FFFFFF)}
.mark-glyph{background:var(--green-700)}
.legend li{border-top-color:color-mix(in oklab, var(--sage) 30%, transparent)}
.legend li:last-child{border-bottom-color:color-mix(in oklab, var(--sage) 30%, transparent)}
.lg i{background:var(--green-700)}
.lg-ring::before{background:var(--green-700)}

/* Answers. The card you opened is marked in pine — structure — while the
   marker itself, the thing you press, keeps the accent. */
.tls-q summary::after{color:var(--action)}
.tls-q[open]{border-color:color-mix(in oklab, var(--sage) 44%, var(--border-default))}
.tls-q[open] summary{background:color-mix(in oklab, var(--sage) 7%, transparent)}
.tls-q[open] summary:hover{background:color-mix(in oklab, var(--sage) 10%, transparent)}

/* The comparison ledger. "With us" is the column the page is arguing for, and
   the argument is the brand — pine edge, pine label. --green-text, not sage:
   the label is 12px mono and sage on white sits under AA at that size. */
.inst-h span:last-child{color:var(--green-text)}
.inst-r .gone::before{color:var(--green-text)}
@media (min-width:941px){
  .inst-r .gone{border-left:2px solid color-mix(in oklab, var(--sage) 46%, transparent);
                padding-left:var(--space-7);margin-left:calc(var(--space-7) * -1)}
}
/* The question card that opens the decision section keeps the ember edge —
   it is the one card on the page holding live Approve / Push back buttons,
   and marking action is the accent's whole job. */
.led-q{border-left:3px solid var(--action)}

/* ═══ THE SIX SOURCES, IN THEIR OWN MARKS ════════════════════════════════════
   Six lines of text set in the same face said "we read six things"; six logos
   say "we read yours". The platform marks are reproduced at label size purely
   to identify the integration. CRM and SEO have no logo to borrow, so they are
   drawn in the product's icon language and take ember — which also says, at a
   glance, which two of the six are ours. */
.fin-h{display:flex;align-items:center;gap:var(--space-5)}
.fin-i{flex:none;width:36px;height:36px;border-radius:11px;display:grid;place-items:center;
  background:color-mix(in oklab, #FFFFFF 8%, transparent);
  transition:background .25s var(--ease-standard)}
.fin-i .src{display:block;width:21px;height:21px}
.fin:hover .fin-i{background:color-mix(in oklab, #FFFFFF 13%, transparent)}
.fin[aria-pressed="true"] .fin-i{background:color-mix(in oklab, #FFFFFF 18%, transparent)}
/* The name comes down a step now that a 36px tile sits beside it, and the line
   under it stops being mono, uppercase and 10.5px — it is a sentence about what
   that system contributes, so it is set as one, in the page's reading face. */
.flow-in b{font-size:var(--size-h3)}
.flow-in em{font-family:var(--font-sans);font-size:var(--size-small);text-transform:none;
  letter-spacing:0;line-height:1.45;max-width:none}
.flow{min-height:470px}
@media (max-width:940px){
  .flow-in li{padding-block:var(--space-2)}
  .flow-in em{max-width:38ch}
}

/* ═══ THE STAGE, CENTRED — exactly ═══════════════════════════════════════════
   Take 1 centred the stage's flex column, which centres the GROUP — frame plus
   caption plus pager — so the frame itself still sat above the middle by half
   the height of everything under it. The thing the eye reads as "the screen"
   is the frame, so the frame is what gets centred now.

   Grid, three rows. The frame is the middle row; the outer rows are 1fr each
   and split the leftover equally, which puts the frame's centre on the centre
   of the area under the sticky masthead at any viewport height. The caption
   block lives INSIDE the bottom spacer (minmax(auto,1fr)), so it costs the
   centring nothing until the spacer genuinely cannot hold it — at which point
   the frame gives ground rather than the captions clipping.

   Two things keep that spacer tall enough on real laptop heights:
   the height buckets below shrink the frame and the caption reserve a step
   ahead of the room they lose, and the one line that never influences a
   decision — "Illustrative. Not a live account." — is pinned to the stage's
   bottom edge, out of the equation entirely. */
@media (min-width:941px){
  .stage{top:var(--head-h);height:calc(100svh - var(--head-h));min-height:0;
    padding:var(--space-6) 0;display:grid;
    grid-template-rows:1fr auto minmax(auto,1fr);justify-items:center;align-items:start}
  .frame-hold{grid-row:2}
  .stage-under{grid-row:3}
  /* max-width:none, because base gives every p a reading measure and a 65ch
     box anchored left-0 right-0 parks at the left edge, not the middle. */
  .stage .t-illus{position:absolute;left:0;right:0;bottom:var(--space-3);text-align:center;max-width:none}
}
@media (min-width:941px) and (max-height:900px){
  .stage{gap:var(--space-5)}
  .stage .rf-body{min-height:320px}
}
@media (min-width:941px) and (max-height:820px){
  .stage{gap:var(--space-4)}
  .stage .rf-body{min-height:264px}
  .stage .fv{padding:var(--space-6)}
  .stage .tls-qrow{padding:var(--space-5) var(--space-6)}
  .step h3{font-size:var(--size-h3)}
  .step p{margin-top:var(--space-4);font-size:var(--size-small)}
  .stepcol{min-height:118px}
  /* The bottom spacer runs within ~2px of its minimum here, so the pinned
     footnote would sit on the pager. The same disclaimer is on the hero demo
     and the six-systems figure; this height can lose this copy of it. */
  .stage .t-illus{display:none}
}
@media (min-width:941px) and (max-height:720px){
  .stage{padding:var(--space-4) 0}
  .stage .rf-body{min-height:220px}
  .stage .rf-kpis{gap:var(--space-4)}
  .stage .tls-kpi{padding:var(--space-5)}
  /* At this height the caption comes down to reading size — the frame beside
     it has already given up a third of its body. */
  .step h3{font-size:var(--size-body)}
  .step p{margin-top:var(--space-3);font-size:var(--size-caption)}
  .stepcol{min-height:104px}
  /* The floor above is now below what the panels actually need, so the body's
     height is content-driven — the only real room left is in the rows. */
  .stage .tls-queue-h{padding:var(--space-4) var(--space-6)}
  .stage .tls-qrow{padding:var(--space-4) var(--space-6)}
  .stage .tls-kpi{padding:var(--space-4)}
  .stage .fv{padding:var(--space-5)}
  .spot-dot{padding:4px 0}
  /* The row is as tall as the taller column, and at this height that is the
     SIDEBAR — five rail items and the user block outlive every panel the
     compression above shrank. The user chip is set dressing, not chrome the
     moments refer to; it goes first. */
  .stage .rf .ha-user{display:none}
  .stage .rf .ha-nav span{height:28px}
  /* ...and once the sidebar is short, the tallest PANEL is the driver — the
     decision record's 3 rows. */
  .stage .rf-rec .tls-rrow{padding:var(--space-3) var(--space-6)}
  .stage .rf-rec .tls-r-a{margin-top:var(--space-2)}
}
