@font-face { font-family: "Familjen Grotesk"; src: url("assets/fonts/familjen-grotesk-latin.woff2") format("woff2"); font-style: normal; font-weight: 400 700; font-display: swap; }
@font-face { font-family: "Instrument Sans"; src: url("assets/fonts/instrument-sans-latin.woff2") format("woff2"); font-style: normal; font-weight: 400 500; font-display: swap; }
:root {
  color-scheme: light;
  --paper: #f5f6f2;
  --ink: #293b30;
  --muted: #566257;
  --fern: #45603b;
  --wash: #e8ede2;
  --wash-deep: #dce4d3;
  /* Check outcomes. Each text colour holds at least 4.5:1 on its own tint. */
  --pass: #34502c; --pass-tint: #d3e3cb;
  --unsure: #7a5207; --unsure-tint: #f1e2bd;
  --fail: #93402d; --fail-tint: #f3dbd2;
  --none: #566257; --none-tint: #e4e7e0;
  --ease-out: cubic-bezier(.23, 1, .32, 1);
  --ease-in-out: cubic-bezier(.77, 0, .175, 1);
  /* easeInOutSine: a walking camera keeps a steady middle. Same curve as the phone's pan in demo.js. */
  --ease-walk: cubic-bezier(.37, 0, .63, 1);
  --display: "Familjen Grotesk", "Instrument Sans", sans-serif;
  /* One gap between sections, so the page keeps a single rhythm. */
  --section: 112px;
  font-family: "Instrument Sans", sans-serif;
  color: var(--ink);
  background: var(--paper);
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
* { box-sizing: border-box; }
body { margin: 0; overflow-wrap: break-word; }
a { color: inherit; text-decoration: none; }
p, h1, h2, h3, figure, ol, ul { margin: 0; }
img { display: block; max-width: 100%; height: auto; }
svg { display: block; }
button { font: inherit; color: inherit; cursor: pointer; border: 0; background: none; padding: 0; }
button, a { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
::selection { background: #d5dfcb; color: var(--ink); }
:focus-visible { outline: 3px solid var(--fern); outline-offset: 4px; border-radius: 6px; }
.wrap { max-width: 1280px; padding-inline: 56px; margin-inline: auto; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.icon-definitions { position: absolute; width: 0; height: 0; overflow: hidden; }
.skip-link { position: fixed; z-index: 5; bottom: 100%; left: 16px; padding: 14px 20px; border-radius: 0 0 12px 12px; background: var(--ink); color: var(--paper); }
.skip-link:focus { top: 0; bottom: auto; }

h1, h2 { font-family: var(--display); font-weight: 460; text-wrap: balance; }
h1 { font-size: clamp(42px, 4.8vw, 66px); line-height: 1.02; letter-spacing: -.034em; }
h2 { font-size: clamp(30px, 3vw, 42px); line-height: 1.08; letter-spacing: -.026em; }

.site-header { display: flex; align-items: center; justify-content: space-between; min-height: 84px; gap: 24px; }
.wordmark { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; font-family: var(--display); font-size: 19px; font-weight: 500; letter-spacing: -.01em; white-space: nowrap; color: var(--ink); }
nav { display: flex; align-items: center; gap: 28px; font-size: 15px; }
nav a { display: inline-flex; align-items: center; min-height: 44px; }
.nav-pill { padding-inline: 18px; border-radius: 22px; background: var(--wash); transition: background-color 160ms ease; }

/* One capsule for every call to action, matching the phone's own buttons. */
.button, .control { display: inline-flex; align-items: center; justify-content: center; gap: 10px; border-radius: 999px; font-weight: 500; transition: transform 140ms var(--ease-out), background-color 160ms ease; }
.button { min-height: 54px; padding: 0 26px; background: var(--ink); color: var(--paper); font-size: 15px; }
.control { min-height: 44px; padding: 0 18px 0 16px; background: var(--wash); color: var(--ink); font-size: 15px; }
.control svg { fill: currentColor; flex: none; }
.button:active, .control:active, .step:active { transform: scale(.97); }
.text-link { display: inline-flex; align-items: center; min-height: 44px; font-size: 15px; text-decoration-line: underline; text-decoration-thickness: 2px; text-underline-offset: 5px; text-decoration-color: #293b3040; transition: text-decoration-color 160ms ease; }

/* Hero: the proposition and the four steps on the left, the live phone on the right. */
.hero { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "copy phone" "steps phone"; grid-template-rows: auto 1fr; column-gap: clamp(40px, 7vw, 112px); padding-block: 12px 40px; }
.hero-copy { grid-area: copy; max-width: 600px; padding-top: clamp(24px, 7svh, 72px); }
.hero h1 { margin-top: 0; }
/* Each sentence of the headline starts its own line; a sentence only wraps inside itself on narrow screens. */
.hero h1 > span { display: block; }
.lede { max-width: 480px; margin-top: 22px; font-size: 19px; line-height: 1.5; color: var(--muted); text-wrap: pretty; }
.hero-steps { grid-area: steps; align-self: start; max-width: 440px; margin-top: 36px; }

.steps-frame { position: relative; }
/* The highlight is one shape clipped to the current step. demo.js stretches its clip across both
   steps before settling, so it travels as one contour (after Detail's corner morph) instead of jumping. */
.step-indicator { position: absolute; inset: 0; border-radius: 16px; background: var(--wash); clip-path: inset(0 0 calc(100% - 56px) 0 round 16px); pointer-events: none; }
.steps { position: relative; display: grid; list-style: none; padding: 0; }
.step { display: grid; grid-template-columns: 26px minmax(0, 1fr); align-items: center; column-gap: 14px; width: 100%; min-height: 56px; padding: 8px 16px 8px 14px; border-radius: 16px; font-size: 17px; line-height: 1.25; text-align: left; color: var(--muted); transition: color 160ms ease, transform 140ms var(--ease-out); }
.step[aria-current] { color: var(--ink); }
.step:disabled { cursor: default; }
.step-short { display: none; }
.step-n { display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--wash-deep); font-family: var(--display); font-size: 14px; font-weight: 500; font-variant-numeric: tabular-nums; color: var(--ink); transition: background-color 200ms ease, color 200ms ease; }
.step[aria-current] .step-n { background: var(--ink); color: var(--paper); }
.step-progress { grid-column: 2; height: 3px; margin-top: 7px; overflow: hidden; border-radius: 2px; background: #cfd9c6; opacity: 0; transition: opacity 200ms ease; }
.step[aria-current] .step-progress { opacity: 1; }
.step-progress > span { display: block; height: 100%; background: var(--fern); transform: scaleX(0); transform-origin: left; }
.demo-controls { display: flex; align-items: center; gap: 12px; margin-top: 18px; padding-left: 4px; }
.demo-controls [data-demo-play] { min-width: 104px; background: var(--ink); color: var(--paper); }
.demo-controls [hidden] { display: none; }
.pause-symbol, .replay-symbol { display: none; }
[data-control="pause"] .play-symbol, [data-control="replay"] .play-symbol { display: none; }
[data-control="pause"] .pause-symbol, [data-control="replay"] .replay-symbol { display: block; }

/* Device. Magic UI's frame places the screen at these fractions of its 433 × 882 geometry. */
.phone-demo { grid-area: phone; align-self: start; }
.phone-shell { position: relative; height: clamp(440px, calc(100svh - 124px), 700px); aspect-ratio: 433 / 882; }
/* A static shadow shape keeps the animating screen out of a filtered layer. */
.phone-shell::before { content: ""; position: absolute; inset: 3% 5% 1%; border-radius: 14% / 7%; box-shadow: 0 34px 60px -18px #293b3052, 0 10px 24px -12px #293b3033; }
.phone-frame { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.phone-screen { position: absolute; left: 4.9076%; top: 2.1825%; width: 89.9538%; height: 95.6349%; border-radius: 14.3132% / 6.6094%; overflow: hidden; background: #0b1220; container-type: size; isolation: isolate; }

/*
  The drawn app. One point (--pt) is 1/393 of the screen width, the width of an iPhone 15 Pro in points,
  so every size below reads as the SwiftUI value it copies. Text keeps a small pixel floor at the narrowest
  phone sizes; layout still follows the point grid.
*/
.app { --pt: calc(100cqw / 393); --ink-app: #0b1220; --chalk: #f7f5ef; --signal: #1f66f2; --signal-fill: #1a58d6; --signal-text: #1650c8; --caution: #f5b53d; --app-muted: #54575e; position: absolute; inset: 0; overflow: hidden; color: var(--chalk); font-family: ui-rounded, "SF Pro Rounded", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; font-synthesis: weight; line-height: 1.25; overflow-wrap: normal; pointer-events: none; user-select: none; -webkit-user-select: none; }
.scene { position: absolute; inset: 0; width: 100%; height: 100%; }
.bob, .cam, [data-far] { transform-box: view-box; transform-origin: 0 0; }
/* Without JavaScript the camera rests on the meter, as in the first frame of the walkthrough. */
.cam { transform: translate(196.5px, 425.5px) scale(3.2) translate(0px, 140px); }
.pin, .ripples circle, .tape-glyph, .reticle { transform-box: fill-box; transform-origin: center; }
.pin, .end-line, .window-mark, .walk-path, .ripples circle, [data-reticle-mark] { opacity: 0; }

.chrome { position: absolute; inset: 0; }
.counter { position: absolute; top: calc(63 * var(--pt)); right: calc(16 * var(--pt)); display: flex; align-items: center; justify-content: center; gap: calc(6 * var(--pt)); min-width: calc(44 * var(--pt)); height: calc(36 * var(--pt)); padding-inline: calc(12 * var(--pt)); border-radius: 999px; background: var(--ink-app); box-shadow: inset 0 0 0 calc(1 * var(--pt)) #ffffff1a; font-size: max(calc(13 * var(--pt)), 9px); font-weight: 600; font-variant-numeric: tabular-nums; opacity: 0; }
.counter-glyph { width: calc(17 * var(--pt)); height: calc(17 * var(--pt)); color: var(--chalk); }
.swap { display: grid; }
.swap > * { grid-area: 1 / 1; }
.count > span:not(:first-child), [data-upload-copy="check"], [data-upload-icon="check"] { opacity: 0; }

.card { position: absolute; top: calc(109 * var(--pt)); left: calc(16 * var(--pt)); right: calc(16 * var(--pt)); padding: calc(16 * var(--pt)) calc(18 * var(--pt)); border-radius: calc(22 * var(--pt)); background: var(--ink-app); box-shadow: inset 0 0 0 calc(1 * var(--pt)) #ffffff1a; opacity: 0; }
.card[data-card="find"] { opacity: 1; }
.card-title { font-size: max(calc(22 * var(--pt)), 14px); font-weight: 700; line-height: 1.24; text-wrap: pretty; }
.card-detail { margin-top: calc(4 * var(--pt)); font-size: max(calc(17 * var(--pt)), 11px); font-weight: 500; line-height: 1.3; color: #f7f5efeb; text-wrap: pretty; }

/* The bottom stack sits 42 points up: 8 of padding plus the 34-point home indicator area. */
.controls { position: absolute; left: calc(16 * var(--pt)); right: calc(16 * var(--pt)); bottom: calc(130 * var(--pt)); display: flex; gap: calc(10 * var(--pt)); opacity: 0; }
.controls[data-controls="meter"] { bottom: calc(42 * var(--pt)); opacity: 1; }
.controls.stack { flex-direction: column; gap: calc(8 * var(--pt)); }
.btn { display: flex; align-items: center; justify-content: center; gap: calc(7 * var(--pt)); min-height: calc(58 * var(--pt)); padding: calc(6 * var(--pt)) calc(20 * var(--pt)); border-radius: 999px; font-size: max(calc(17 * var(--pt)), 11px); font-weight: 700; line-height: 1.15; text-align: center; }
.btn svg { flex: none; width: calc(19 * var(--pt)); height: calc(19 * var(--pt)); }
.btn.primary { background: var(--signal-fill); color: #fff; }
.btn.secondary { background: var(--ink-app); box-shadow: inset 0 0 0 calc(1 * var(--pt)) #ffffff1a; color: var(--chalk); }
.controls.row .btn.primary { flex: 1 1 0; }
.controls.row .btn.secondary { flex: 0 1 auto; }
.controls[data-controls="meter"] .btn, .controls.stack .btn, .panel-action .btn, .result-body .btn { width: 100%; }

.tape { position: absolute; left: calc(16 * var(--pt)); right: calc(16 * var(--pt)); bottom: calc(42 * var(--pt)); padding: calc(10 * var(--pt)) calc(14 * var(--pt)); border-radius: calc(18 * var(--pt)); background: var(--ink-app); box-shadow: inset 0 0 0 calc(1 * var(--pt)) #ffffff1a; opacity: 0; }
.tape svg { width: 100%; height: calc(58 * var(--pt)); overflow: visible; }
.tape-glyph[data-tape-window], [data-tape-cap], [data-tape-pointer] { opacity: 0; }

.review { position: absolute; inset: 0; background: #00000073; color: var(--ink-app); opacity: 0; }
.panel-sheet { position: absolute; inset: calc(125 * var(--pt)) 0 0; overflow: hidden; border-radius: calc(28 * var(--pt)) calc(28 * var(--pt)) 0 0; background: #fff; }
.panel-content { display: flex; flex-direction: column; gap: calc(20 * var(--pt)); padding: calc(20 * var(--pt)); }
.panel-action { position: absolute; left: 0; right: 0; bottom: 0; padding: calc(8 * var(--pt)) calc(20 * var(--pt)) calc(46 * var(--pt)); background: #fff; }
.soft-card { padding: calc(14 * var(--pt)); border-radius: calc(18 * var(--pt)); background: #f2f1ec; }
.question { font-size: max(calc(20 * var(--pt)), 13px); font-weight: 600; line-height: 1.25; }
.question.small { margin-top: calc(12 * var(--pt)); font-size: max(calc(15 * var(--pt)), 10px); }
.question-detail { margin-top: calc(4 * var(--pt)); font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; font-size: max(calc(15 * var(--pt)), 10px); line-height: 1.33; color: var(--app-muted); }
.answers { display: grid; grid-template-columns: 1fr 1fr; gap: calc(8 * var(--pt)); margin-top: calc(14 * var(--pt)); }
.answers.single { grid-template-columns: 1fr; margin-top: calc(8 * var(--pt)); }
.answer { display: flex; align-items: center; justify-content: center; min-height: calc(46 * var(--pt)); padding: calc(8 * var(--pt)) calc(12 * var(--pt)); border-radius: 999px; background: #1f66f21a; color: var(--signal-text); font-size: max(calc(17 * var(--pt)), 11px); font-weight: 700; }
.answer.wide { grid-column: 1 / -1; }
.review-title { font-size: max(calc(34 * var(--pt)), 20px); font-weight: 700; line-height: 1.2; text-wrap: balance; }
.review-detail { margin-top: calc(6 * var(--pt)); font-size: max(calc(17 * var(--pt)), 11px); font-weight: 500; line-height: 1.3; color: var(--app-muted); }
.feature { display: flex; align-items: center; gap: calc(12 * var(--pt)); }
.feature-icon { display: grid; place-items: center; flex: none; width: calc(44 * var(--pt)); height: calc(44 * var(--pt)); border-radius: 50%; background: #1f66f21a; color: var(--signal); }
.feature-icon svg { width: calc(22 * var(--pt)); height: calc(22 * var(--pt)); }
.feature-text { display: grid; flex: 1; gap: calc(2 * var(--pt)); font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; font-size: max(calc(15 * var(--pt)), 10px); color: var(--app-muted); }
.feature-text b { font-family: ui-rounded, "SF Pro Rounded", system-ui, -apple-system, sans-serif; font-size: max(calc(17 * var(--pt)), 11px); font-weight: 600; color: var(--ink-app); }
.feature-trash { flex: none; width: calc(20 * var(--pt)); height: calc(20 * var(--pt)); margin-inline: calc(12 * var(--pt)); color: #ff5a4e; }

.upload { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(28 * var(--pt)); padding: calc(24 * var(--pt)); background: #f2f1ec; color: var(--ink-app); text-align: center; opacity: 0; }
.emblem { display: grid; place-items: center; width: calc(132 * var(--pt)); height: calc(132 * var(--pt)); border-radius: 50%; background: #1f66f21f; color: var(--signal); }
.emblem svg { grid-area: 1 / 1; width: calc(58 * var(--pt)); height: calc(58 * var(--pt)); }
.upload-title { font-size: max(calc(34 * var(--pt)), 20px); font-weight: 700; line-height: 1.2; text-wrap: balance; }
.upload-detail { margin-top: calc(8 * var(--pt)); font-size: max(calc(17 * var(--pt)), 11px); font-weight: 500; line-height: 1.3; color: var(--app-muted); }

.result { position: absolute; inset: 0; background: #f2f1ec; color: var(--ink-app); opacity: 0; }
.diorama { position: absolute; top: 0; left: 0; width: 100%; height: calc(340 * var(--pt)); clip-path: inset(0 round 0 0 calc(28 * var(--pt)) calc(28 * var(--pt))); }
.model, .model-ground { transform-box: view-box; transform-origin: 0 0; }
.result-body { position: absolute; top: calc(340 * var(--pt)); left: 0; right: 0; display: flex; flex-direction: column; gap: calc(22 * var(--pt)); padding: calc(20 * var(--pt)); }
.headline { display: flex; align-items: flex-start; gap: calc(8 * var(--pt)); font-size: max(calc(34 * var(--pt)), 20px); font-weight: 700; line-height: 1.2; text-wrap: balance; }
.headline svg { flex: none; width: .9em; height: .9em; margin-top: .12em; color: #8f5c00; }
.placement { margin-top: calc(-12 * var(--pt)); font-size: max(calc(20 * var(--pt)), 13px); font-weight: 600; line-height: 1.25; color: var(--signal-text); }
.notice { display: flex; align-items: flex-start; gap: calc(10 * var(--pt)); padding: calc(14 * var(--pt)); border-radius: calc(14 * var(--pt)); background: #f5b53d2e; font-size: max(calc(15 * var(--pt)), 10px); font-weight: 500; line-height: 1.33; }
.notice svg { flex: none; width: calc(17 * var(--pt)); height: calc(17 * var(--pt)); margin-top: .1em; color: #8f5c00; }

/* A fingertip, shown only for the taps a person makes. The app's own automatic photos get none. */
[data-still="true"] .touch { visibility: hidden; }
.touch { position: absolute; left: 0; top: 0; width: calc(40 * var(--pt)); height: calc(40 * var(--pt)); margin: calc(-20 * var(--pt)) 0 0 calc(-20 * var(--pt)); border-radius: 50%; background: radial-gradient(circle at 50% 45%, #ffffffb8, #ffffff5c 62%, #ffffff33); box-shadow: 0 0 0 calc(1.5 * var(--pt)) #ffffffcc, 0 calc(3 * var(--pt)) calc(10 * var(--pt)) #0b122059; opacity: 0; }

/* Status bar and home indicator: one SVG grid of 393 × 851 points over the whole screen. */
.system, .home-indicator { position: absolute; inset: 0; width: 100%; height: 100%; color: var(--chalk); fill: currentColor; }
.clock { font: 600 17px -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, "Segoe UI", Roboto, sans-serif; letter-spacing: -.01em; }

/* The walk, from outside: one continuous wall that separates into three aligned panels (after useLayouts' split cards).
   The default markup is the finished state, so it reads without JavaScript; story.js replays from the start. */
.walk { padding-top: var(--section); }
.section-head { display: flex; align-items: end; justify-content: space-between; gap: 24px; margin-bottom: 28px; }
/* 2 : 1, a ratio a real landing film can be exported at. */
.film-stage { position: relative; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); aspect-ratio: 2 / 1; overflow: hidden; border-radius: 20px; }
/* Every panel holds the same full-width drawing, offset by its column, so the parts line up exactly.
   Splitting clips each panel's inner edges, opening gaps without moving any content. */
.panel { position: relative; clip-path: inset(0 7px 0 0 round 16px); transition: clip-path 700ms var(--ease-out); }
[data-panel="measured"] { clip-path: inset(0 7px 0 7px round 16px); }
[data-panel="placed"] { clip-path: inset(0 0 0 7px round 16px); }
.film:not([data-split]) .panel { clip-path: inset(0 0 0 0 round 0px); }
.panel svg { position: absolute; top: 0; left: 0; width: 300%; height: 100%; }
[data-panel="measured"] svg { left: -100%; }
[data-panel="placed"] svg { left: -200%; }
/* While joined, one uncut copy sits on top so no seam shows; it hides the instant the panels begin to part. */
.film-whole { position: absolute; inset: 0; z-index: 1; visibility: hidden; }
.film-whole svg { width: 100%; height: 100%; }
.film:not([data-split]) .film-whole, .film:not([data-panels]) .film-whole { visibility: visible; }
/* Chapter labels inside each panel. A real film can keep them as its chapter markers. */
.panel-chip { position: absolute; z-index: 1; top: 14px; left: 16px; padding: 5px 11px; border-radius: 13px; background: var(--paper); font-size: 13px; font-weight: 500; line-height: 1.25; color: var(--ink); transition: opacity 300ms ease 350ms; }
[data-panel="measured"] .panel-chip, [data-panel="placed"] .panel-chip { left: 23px; }
.film:not([data-split]) .panel-chip { opacity: 0; transition-delay: 0ms; }
.coverage-strip { fill: none; stroke: #7e9a6c; stroke-width: 9; stroke-dasharray: 26 4; }
.coverage-strip.unseen { stroke: #a4a79c; stroke-dasharray: 3 7; stroke-linecap: round; }
.haze-right, .viewfinder { transform: translateX(450px); transition: transform 2800ms var(--ease-walk), opacity 250ms ease; }
.viewfinder { opacity: 0; }
.film:not([data-walked]) .haze-right, .film:not([data-walked]) .viewfinder { transform: translateX(0); }
.film:not([data-split]) .viewfinder { opacity: 1; }
.reading { transition: opacity 400ms ease, transform 600ms var(--ease-out); }
.reading[data-reading="measured"] { transition-delay: 220ms; }
.reading[data-reading="placed"] { transition-delay: 440ms; }
.film:not([data-read]) .reading { opacity: 0; transform: translateY(10px); }
/* Lines draw by unclipping, left to right or top to bottom. */
.dimension path { fill: none; stroke: #293b30; stroke-width: 2.5; stroke-linecap: round; clip-path: inset(0 0 0 0); transition: clip-path 600ms var(--ease-in-out) 520ms; }
.film:not([data-read]) .dimension path { clip-path: inset(0 100% 0 0); }
.film:not([data-read]) .dimension.side path { clip-path: inset(0 0 100% 0); }
.dimension text, .film-label, .film-tag text { font: 500 9.5px "Instrument Sans", sans-serif; fill: #293b30; }
.dimension text { text-anchor: middle; }
.dimension text[text-anchor="end"] { text-anchor: end; }
.film-tag text { fill: var(--paper); }
.film-battery { transition: transform 600ms var(--ease-out) 700ms; }
.film:not([data-read]) .film-battery { transform: translateY(-16px); }
/* The cable runs from the meter to the battery through all three panels, the same run the phone reports. */
.film-cable { fill: none; stroke: var(--fern); stroke-width: 3.5; stroke-linecap: round; stroke-linejoin: round; clip-path: inset(0 0 0 0); transition: clip-path 900ms var(--ease-in-out) 900ms; }
.film:not([data-read]) .film-cable { clip-path: inset(0 100% 0 0); }
.film[data-instant] *, .film[data-instant] *::before { transition: none !important; }
.readings { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; margin-top: 22px; }
.readings p { padding-right: 24px; font-size: 15px; line-height: 1.45; color: var(--muted); text-wrap: pretty; }
.readings b { display: block; margin-bottom: 4px; font-family: var(--display); font-size: 17px; font-weight: 500; letter-spacing: -.01em; color: var(--ink); }
/* The panels carry their own labels once story.js has built them. */
.film[data-panels] .readings b { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* The system: what leaves the phone, what comes back, and the research lane that may feed it. */
.how { margin-top: var(--section); padding-block: 96px; background: var(--wash); }
.how h2 { max-width: 640px; }
.flow { --gap: 28px; margin-top: 44px; }
.lane-label { font-size: 13px; font-weight: 500; letter-spacing: .02em; color: var(--fern); }
.lane-now { position: relative; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); column-gap: var(--gap); padding: 58px 0 0; list-style: none; }
.loop { position: absolute; top: 12px; left: calc((100% - 4 * var(--gap)) / 10); width: calc(3 * (100% - 4 * var(--gap)) / 5 + 3 * var(--gap)); height: 40px; border: 2px dashed #8fa383; border-bottom: 0; border-radius: 18px 18px 0 0; }
.loop::after { content: ""; position: absolute; left: -8px; bottom: -9px; border: 7px solid transparent; border-top: 9px solid #8fa383; border-bottom: 0; }
.loop span { position: absolute; top: -12px; left: 50%; translate: -50% 0; padding: 2px 12px; background: var(--wash); font-size: 13px; white-space: nowrap; color: var(--muted); }
.node { position: relative; display: flex; flex-direction: column; gap: 14px; }
.art { position: relative; display: block; }
.node-art { width: 100%; height: auto; aspect-ratio: 160 / 100; border-radius: 10px; }
.node-art[viewBox^="-140"] { overflow: hidden; }
[data-node="rules"] .node-art, [data-node="ar"] .node-art { overflow: visible; }
.lane-now .node:not(:last-child) .art::after { content: ""; position: absolute; top: 50%; left: calc(100% + 6px); width: calc(var(--gap) - 12px); height: 2px; border-radius: 1px; background: var(--ink); }
.lane-now .node:not(:last-child) .art::before { content: ""; position: absolute; top: calc(50% - 5px); left: calc(100% + var(--gap) - 12px); border: 6px solid transparent; border-left: 8px solid var(--ink); border-right: 0; }
.node p { display: grid; gap: 4px; font-size: 15px; line-height: 1.45; color: var(--muted); text-wrap: pretty; }
.node b { font-family: var(--display); font-size: 17px; font-weight: 500; line-height: 1.2; letter-spacing: -.01em; color: var(--ink); }
/* Entrance (story.js): the steps arrive left to right, so the direction reads before the text does, then the
   retake loop closes over them. Transitions sit on the shown state only, so hiding at load is instant. */
.flow[data-shown] :is(.node, .loop) { transition: opacity 480ms var(--ease-out), transform 480ms var(--ease-out); }
.flow[data-shown] .node:nth-child(3) { transition-delay: 80ms; }
.flow[data-shown] .node:nth-child(4) { transition-delay: 160ms; }
.flow[data-shown] .node:nth-child(5) { transition-delay: 240ms; }
.flow[data-shown] .node:nth-child(6) { transition-delay: 320ms; }
.flow[data-shown] .loop { transition-delay: 620ms; }
.flow:not([data-shown]) .node { opacity: 0; transform: translateY(12px); }
.flow:not([data-shown]) .loop { opacity: 0; }

/* Node drawings share one small set of materials. */
.a-ink { fill: var(--ink); }
.a-fern { fill: #7e9a6c; }
.a-meter { fill: #8e949c; }
.a-cone { fill: #45603b; fill-opacity: .16; }
.a-path { fill: none; stroke: var(--ink); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 0 9; }
.a-phone, .a-phone-body { fill: var(--ink); }
.a-wall { fill: #efe9dc; stroke: var(--ink); stroke-width: 2.5; }
.a-window { fill: #45603b; fill-opacity: .16; stroke: var(--ink); stroke-width: 2.2; stroke-dasharray: 5 4; }
.a-window-small { fill: #9fb2c4; }
.a-pin { fill: var(--fern); stroke: var(--paper); stroke-width: 3; }
.a-dim, .a-axes { fill: none; stroke: var(--ink); stroke-width: 2.2; stroke-linecap: round; }
.a-axes { stroke: var(--muted); }
.a-track { fill: none; stroke: #c9d2c0; stroke-width: 3; stroke-linecap: round; }
.a-limit { fill: none; stroke: var(--ink); stroke-width: 3; stroke-linecap: round; }
.a-bar { fill: none; stroke-width: 4; stroke-linecap: round; }
.a-bar.pass, .a-chip.pass { stroke: var(--pass); fill: none; }
.a-bar.fail { stroke: var(--fail); }
.a-bar.unsure { stroke: #a87412; }
.a-chip.pass { fill: var(--pass); stroke: none; }
.a-chip.fail { fill: var(--fail); stroke: none; }
.a-chip.unsure { fill: #e2b453; stroke: none; }
.a-glyph { fill: none; stroke: #fff; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.a-glyph.dark { stroke: #3b2a05; stroke-width: 2; }
.a-dot { fill: #3b2a05; }
.a-ground { fill: #b7b2a4; }
.a-q { font: 600 120px "Instrument Sans", sans-serif; fill: var(--ink); text-anchor: middle; }
.a-battery { fill: #f4f5f7; stroke: var(--fern); stroke-width: 2.5; }
.a-battery-top { fill: #fff; stroke: var(--fern); stroke-width: 2; stroke-linejoin: round; }
.a-envelope { fill: none; stroke: var(--ink); stroke-width: 2; stroke-dasharray: 5 4; }
.a-screen { fill: #dfe4dc; }
.a-photo { fill: #f5f6f2; stroke: var(--ink); stroke-width: 2.5; }
.a-photo.mid { fill: #e3e8dc; }
.a-photo.back { fill: #cfd9c6; }
.a-route { fill: none; stroke: var(--ink); stroke-width: 2.5; stroke-linecap: round; }
.a-route.r1 { stroke-dasharray: 7 6; }
.a-route.r2 { stroke-dasharray: 2 6; }
.a-route.r3 { stroke-dasharray: 14 6; }
.a-node { fill: var(--ink); }
.a-mesh { fill: #f5f6f2; stroke: var(--ink); stroke-width: 2.5; stroke-linejoin: round; }
.a-mesh-line { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linejoin: round; }

/* The phone's side: four ARKit layers, the wall in feet, and the file the phone writes.
   Panels share two subgrid rows, so the three captions line up above drawings of different heights. */
.stack, .rebuild { padding-top: var(--section); }
code, .json { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; }
.stack-figure { --gap: 40px; display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr); grid-template-rows: auto auto; column-gap: var(--gap); margin-top: 44px; }
.stack-panel { position: relative; display: grid; grid-row: span 2; grid-template-rows: subgrid; grid-template-columns: minmax(0, 1fr); row-gap: 20px; }
.stack-visual { position: relative; align-self: start; }
.stack-cap { font-size: 15px; line-height: 1.45; color: var(--muted); text-wrap: pretty; }
.stack-cap b { display: block; margin-bottom: 4px; font-family: var(--display); font-size: 17px; font-weight: 500; letter-spacing: -.01em; color: var(--ink); }
/* Connectors between the panels, drawn like the flow diagram's. */
.stack-plan .stack-visual::before, .stack-wire .stack-visual::before { content: ""; position: absolute; top: 132px; left: calc(-1 * var(--gap) + 8px); width: calc(var(--gap) - 22px); height: 2px; border-radius: 1px; background: var(--ink); }
.stack-plan .stack-visual::after, .stack-wire .stack-visual::after { content: ""; position: absolute; top: 127px; left: -14px; border: 6px solid transparent; border-left: 8px solid var(--ink); border-right: 0; }

/* The layers. Each moves by --lift: collapsed before the figure is seen, then spread apart around a selected
   sheet. Sheets that could hide the selected one empty to outlines instead of dimming, because a dimmed sheet
   still paints over a lower one. */
.layers { width: 100%; height: auto; overflow: visible; }
.layer { --lift: 0px; transform: translateY(var(--lift)); transition: transform 300ms var(--ease-out); }
.stack-figure:not([data-exploded]) .layer { --lift: var(--collapse); }
.stack-figure[data-exploding] .layer { transition-duration: 760ms; }
.stack-figure[data-exploding] .layer[data-layer="depth"] { transition-delay: 70ms; }
.stack-figure[data-exploding] .layer[data-layer="camera"] { transition-delay: 140ms; }
[data-focus] .layer[data-pos="above"] { --lift: -18px; }
[data-focus] .layer[data-pos="below"] { --lift: 18px; }
[data-layers-ready] .layer { cursor: pointer; }
.sheet { transition: transform 300ms var(--ease-out); }
.layer[data-pos="focus"] .sheet { transform: translateY(-12px); }
.sheet-body, .sheet-shadow, .layer-n, .layer-note { transition: opacity 180ms ease; }
.sheet-shadow { opacity: .6; }
.layer[data-pos="focus"] .sheet-shadow { opacity: 1; }
.sheet-outline { fill: none; stroke: var(--ink); stroke-width: 1.6; transition: stroke 180ms ease, stroke-width 180ms ease, opacity 180ms ease; }
.layer[data-pos="focus"] .sheet-outline { stroke: var(--fern); stroke-width: 2.6; }
.layer:is([data-pos="above"], [data-pos="below"]) :is(.sheet-body, .sheet-shadow) { opacity: 0; }
.layer:is([data-pos="above"], [data-pos="below"]) .sheet-outline { opacity: .45; stroke-dasharray: 6 5; }
.layer:is([data-pos="above"], [data-pos="below"]) { pointer-events: none; }
.layer:is([data-pos="above"], [data-pos="below"]) :is(.layer-n, .layer-note) { opacity: .35; }
.layer-n circle { fill: var(--ink); transition: fill 180ms ease; }
.layer[data-pos="focus"] .layer-n circle { fill: var(--fern); }
.layer-n text { font: 600 13px "Instrument Sans", sans-serif; fill: var(--paper); text-anchor: middle; }
.layer-axis { font: 500 13px "Instrument Sans", sans-serif; fill: var(--ink); }
.layer-key { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin-top: 16px; padding: 0; list-style: none; }
.layer-btn { display: grid; grid-template-columns: 24px minmax(0, 1fr); grid-template-areas: "n name" "n sub"; column-gap: 10px; align-items: center; width: 100%; min-height: 58px; padding: 8px 12px 8px 9px; border-radius: 14px; text-align: left; transition: background-color 160ms ease, transform 140ms var(--ease-out); }
.layer-btn:active { transform: scale(.97); }
.layer-num { grid-area: n; display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; background: var(--ink); color: var(--paper); font-size: 12px; font-weight: 600; transition: background-color 160ms ease; }
.layer-name { grid-area: name; font-size: 15px; font-weight: 500; line-height: 1.25; color: var(--ink); }
.layer-sub { grid-area: sub; font-size: 13px; line-height: 1.35; color: var(--muted); }
.layer-sub code, .layer-details code { font-size: .92em; color: var(--ink); }
.layer-btn[aria-pressed="true"] { background: var(--wash-deep); }
.layer-btn:is([aria-pressed="true"], [data-preview]) .layer-num { background: var(--fern); }
/* Every detail shares one cell, so the box keeps the height of the longest and nothing below it moves. */
.layer-details { display: grid; margin-top: 10px; padding: 12px 14px; border-radius: 14px; background: var(--wash); font-size: 14px; line-height: 1.5; color: var(--muted); }
.layer-details > p { grid-area: 1 / 1; text-wrap: pretty; }
.layer-details > p[hidden] { display: block; visibility: hidden; }
.layer-details > p[data-layer-detail="all"] { align-self: center; }

.plan { width: 100%; height: auto; border-radius: 16px; background: var(--wash); }
.plan-note, .plan-scale text, .plan-axes text { font: 500 13px "Instrument Sans", sans-serif; fill: var(--muted); }
.plan-scale text { text-anchor: middle; }
.plan-ticks path { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; }
.plan-cams path { fill: #45603b; fill-opacity: .1; stroke: #45603b; stroke-opacity: .55; stroke-width: 1.5; stroke-linejoin: round; }

/* Code. Lines are at most 38 characters, so the examples never wrap: 38 monospace characters fit a 320px screen
   at 11px. Keys, strings, numbers and booleans each have a colour; punctuation keeps the muted base. */
.code { overflow: hidden; border-radius: 16px; background: #1e2a23; box-shadow: inset 0 1px 0 #ffffff14, 0 22px 44px -28px #1f2d2480, 0 3px 8px -4px #1f2d2440; }
.code-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 11px 16px 10px; border-bottom: 1px solid #ffffff14; font-size: 12px; line-height: 1.4; }
.code-file { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-weight: 600; color: #dfe6da; }
.code-note { color: #8ea394; }
.json { margin: 0; padding: 14px 16px 16px; overflow-x: auto; color: #8ea394; font-size: 12.5px; line-height: 1.62; tab-size: 2; }
.json:focus-visible { outline-color: #c9deb5; outline-offset: -4px; border-radius: 0 0 16px 16px; }
.json .k { color: #c9deb5; }
.json .s { color: #efd79c; }
.json .n { color: #a9cde2; }
.json .b { color: #f0b39c; }

/* The server path. Drawings share one light (upper left) and one set of materials with the layers above. */
.rebuild-intro { max-width: 700px; }
.rebuild-intro p { margin-top: 16px; font-size: 17px; line-height: 1.55; color: var(--muted); text-wrap: pretty; }
.rebuild-grid { display: grid; grid-template-columns: minmax(0, 2.2fr) minmax(0, 1fr); column-gap: 48px; align-items: start; margin-top: 44px; }
.rebuild-grid > .code { position: sticky; top: 24px; }
.server-figure { --art-w: 280px; --row-gap: 36px; }
.server-flow { display: grid; row-gap: var(--row-gap); padding: 0; list-style: none; }
.server-node { position: relative; display: grid; grid-template-columns: var(--art-w) minmax(0, 1fr); align-items: center; gap: 28px; }
.server-art { display: block; width: 100%; height: auto; aspect-ratio: 320 / 200; border-radius: 14px; box-shadow: 0 0 0 1px #293b3014; }
/* The art is --art-w wide at 320 : 200, so a connector runs from under one drawing to just above the next. */
.server-node:not(:last-child)::after { content: ""; position: absolute; top: calc(var(--art-w) * .625 + 6px); bottom: calc(10px - var(--row-gap)); left: calc(var(--art-w) / 2 - 1px); width: 2px; background: repeating-linear-gradient(180deg, var(--ink) 0 5px, transparent 5px 9px); }
.server-node:not(:last-child)::before { content: ""; position: absolute; bottom: calc(2px - var(--row-gap)); left: calc(var(--art-w) / 2 - 6px); border: 6px solid transparent; border-top: 8px solid var(--ink); border-bottom: 0; }
.server-node p { display: grid; gap: 4px; max-width: 30em; font-size: 15px; line-height: 1.45; color: var(--muted); text-wrap: pretty; }
.server-node b { font-family: var(--display); font-size: 17px; font-weight: 500; line-height: 1.2; letter-spacing: -.01em; color: var(--ink); }
.server-node code, .server-events code { justify-self: start; padding: 2px 8px; border-radius: 6px; background: var(--wash); font-size: 12px; line-height: 1.5; color: var(--ink); white-space: nowrap; }
.server-node code { margin-top: 6px; }
/* Events point back across the drawings to the phone that uploaded. */
.server-events { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin-top: 30px; padding-left: calc(var(--art-w) + 28px); font-size: 13px; color: var(--muted); }
.server-events::before { content: ""; position: absolute; top: calc(50% - 1px); left: 14px; width: calc(var(--art-w) - 8px); height: 2px; background: repeating-linear-gradient(90deg, #8fa383 0 5px, transparent 5px 9px); }
.server-events::after { content: ""; position: absolute; top: calc(50% - 6px); left: 6px; border: 6px solid transparent; border-right: 8px solid #8fa383; border-left: 0; }
/* Drawing classes. Iso scene: sr- reconstruction, ss- scene. */
.sr-cam-plane { fill: #45603b; fill-opacity: .16; stroke: #293b30; stroke-width: 1.2; stroke-linejoin: round; }
.sr-cam-wire { fill: none; stroke: #293b30; stroke-opacity: .7; stroke-width: 1; }
.sr-cam-eye { fill: #293b30; }
.sr-track { fill: none; stroke: #293b30; stroke-width: 2; stroke-linecap: round; stroke-dasharray: 0 5.5; }
.ss-slab-front { fill: #a9b394; }
.ss-slab-side { fill: #939e80; }
.ss-seen { fill: url(#iso-seen); }
.ss-unseen { fill: url(#iso-haze); }
.ss-grid { fill: none; stroke: #45603b; stroke-opacity: .2; stroke-width: .8; }
.ss-edge-seen { fill: none; stroke: #45603b; stroke-width: 1.2; stroke-dasharray: 3 3; }
.ss-wall-top { fill: #f3efe6; }
.ss-wall-end { fill: #bdb5a3; }
.ss-wall-face { fill: url(#iso-wall); }
.ss-courses { fill: none; stroke: #b8b09d; stroke-width: .8; }
.ss-casing { fill: #f4f1ea; }
.ss-glass { fill: url(#iso-glass); }
.ss-mullion { fill: none; stroke: #f4f1ea; stroke-width: 1.6; }
.ss-meter-face { fill: #9aa0a8; }
.ss-meter-side { fill: #7c828a; }
.ss-meter-top { fill: #b3b9bf; }
.ss-dial { fill: #eef1ee; }
.ss-cable { fill: none; stroke: var(--fern); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.ss-envelope { fill: #45603b; fill-opacity: .1; stroke: #293b30; stroke-width: 1.2; stroke-dasharray: 4 3; stroke-linejoin: round; }
.ss-contact { fill: #293b30; fill-opacity: .18; }
.ss-bat-front { fill: url(#bat-front); stroke: #45603b; stroke-width: 1.2; stroke-linejoin: round; }
.ss-bat-side { fill: #d7dcd3; stroke: #45603b; stroke-width: 1.2; stroke-linejoin: round; }
.ss-bat-top { fill: #fdfdfb; stroke: #45603b; stroke-width: 1.2; stroke-linejoin: round; }
.ss-bat-stripe { fill: none; stroke: var(--fern); stroke-width: 3; stroke-linecap: round; }
/* Played once when the flow scrolls into view (story.js): the stages arrive in upload order, then the events
   line draws back toward the phone. The markup's default is the finished state. The transitions sit on the shown
   state only, so hiding the flow at load is instant instead of a fade-out. */
.server-events::before { clip-path: inset(0 0 0 0); }
.server-figure[data-shown] :is(.server-node, .server-events) { transition: opacity 560ms var(--ease-out), transform 560ms var(--ease-out); }
.server-figure[data-shown] .server-node:nth-child(2) { transition-delay: 90ms; }
.server-figure[data-shown] .server-node:nth-child(3) { transition-delay: 180ms; }
.server-figure[data-shown] .server-node:nth-child(4) { transition-delay: 270ms; }
.server-figure[data-shown] .server-events { transition-delay: 520ms; }
.server-figure[data-shown] .server-events::before { transition: clip-path 640ms var(--ease-out) 620ms; }
/* The arrowhead lands as the line reaches it: this ease-out covers most of the distance in its first half. */
.server-figure[data-shown] .server-events::after { transition: opacity 200ms ease 1000ms; }
.server-figure:not([data-shown]) .server-node { opacity: 0; transform: translateY(10px); }
.server-figure:not([data-shown]) .server-events { opacity: 0; }
.server-figure:not([data-shown]) .server-events::before { clip-path: inset(0 0 0 100%); }
.server-figure:not([data-shown]) .server-events::after { opacity: 0; }
@media (hover: hover) and (pointer: fine) {
  .layer-btn:hover { background: var(--wash); }
  .layer-btn[aria-pressed="true"]:hover { background: var(--wash-deep); }
}

/* Unseen ground: the haze covers what the walk never saw. The range moves its right edge, like a comparison slider. */
.unseen { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); grid-template-areas: "copy ." "scene checks"; column-gap: 56px; padding-top: var(--section); }
.unseen-copy { grid-area: copy; max-width: 640px; margin-bottom: 32px; }
.unseen-copy p { margin-top: 16px; font-size: 17px; line-height: 1.55; color: var(--muted); text-wrap: pretty; }
.unseen-figure { display: contents; }
.unseen-scene { grid-area: scene; position: relative; overflow: hidden; aspect-ratio: 400 / 312; border-radius: 20px; background: #e6ebee; box-shadow: inset 0 0 0 1px #293b3014, 0 28px 56px -36px #1f2d2473; cursor: ew-resize; touch-action: pan-y; }
.unseen-scene > svg { position: absolute; inset: 0; width: 100%; height: 100%; }
/* Unseen: the paper haze the phone uses, with a fine hatch so it reads as missing data rather than fog. */
.unseen-haze { position: absolute; inset: 0; background: repeating-linear-gradient(135deg, transparent 0 8px, #293b3014 8px 9.5px), radial-gradient(120% 100% at 35% 35%, #f7f8f4eb, #eef1e9e0); clip-path: inset(0 0 0 0); }
/* The candidate spot takes its checks' colours (story.js sets data-wall, data-ground, data-room on the scene). */
.us-envelope { fill: var(--none-tint); fill-opacity: .3; stroke: var(--none); stroke-width: 2; stroke-dasharray: 7 5; }
.us-ground { fill: var(--none); fill-opacity: .25; }
.us-bat-front { fill: #fbfbf7; fill-opacity: .4; stroke: var(--ink); stroke-width: 2; stroke-dasharray: 6 4; }
.us-bat-top { fill: #fff; fill-opacity: .6; stroke: var(--ink); stroke-width: 1.5; stroke-linejoin: round; }
.us-bat-side { fill: #d8dbe0; fill-opacity: .55; stroke: var(--ink); stroke-width: 1.5; stroke-linejoin: round; }
.us-bat-stripe { fill: none; stroke: var(--fern); stroke-width: 5; stroke-linecap: round; opacity: .6; }
.us-spot :is(.us-envelope, .us-ground, .us-bat-front) { transition: fill 200ms ease, stroke 200ms ease; }
[data-room="pass"] .us-envelope { fill: var(--pass-tint); stroke: var(--pass); }
[data-room="unsure"] .us-envelope { fill: var(--unsure-tint); stroke: var(--unsure); }
[data-room="fail"] .us-envelope { fill: var(--fail-tint); fill-opacity: .42; stroke: var(--fail); }
[data-ground="pass"] .us-ground { fill: var(--pass); fill-opacity: .45; }
[data-ground="unsure"] .us-ground { fill: var(--unsure); fill-opacity: .45; }
[data-ground="fail"] .us-ground { fill: var(--fail); fill-opacity: .45; }
[data-wall="pass"] .us-bat-front { stroke: var(--pass); }
[data-wall="unsure"] .us-bat-front { stroke: var(--unsure); }
[data-wall="fail"] .us-bat-front { stroke: var(--fail); }
.unseen-request { position: absolute; z-index: 2; top: 18px; left: 18px; display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 10px 16px 10px 13px; border-radius: 16px; background: #0b1220; color: #f7f5ef; font: 600 15px/1.25 ui-rounded, "SF Pro Rounded", system-ui, -apple-system, sans-serif; text-align: left; transition: transform 140ms var(--ease-out); }
.unseen-request:active { transform: scale(.97); }
.unseen-request[hidden] { display: none; }
.unseen-request svg { flex: none; width: 18px; height: 18px; }
.unseen-request:focus-visible { outline-color: #0b1220; }
.unseen-divider { position: absolute; inset: 0; width: 100%; border-left: 3px solid var(--paper); pointer-events: none; transform: translateX(100%); }
.unseen-grip { position: absolute; top: 50%; left: -24px; display: grid; place-items: center; width: 45px; height: 45px; border-radius: 50%; background: var(--paper); box-shadow: 0 4px 16px #293b302e; transform: translateY(-50%); transition: transform 200ms var(--ease-out); }
.unseen-grip::before { content: ""; width: 10px; height: 14px; background: linear-gradient(var(--ink), var(--ink)) left / 2px 100% no-repeat, linear-gradient(var(--ink), var(--ink)) right / 2px 100% no-repeat; }
/* Pointer drags are handled on the scene (iOS drags a range only by its thumb); the range stays for keys and screen readers. */
.unseen-range { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none; }
.unseen-scene:has(.unseen-range:focus-visible) { outline: 3px solid var(--fern); outline-offset: 4px; }
.checks { grid-area: checks; align-self: center; }
.checks-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; font-size: 15px; font-weight: 500; }
.verdict, .chip { display: inline-flex; align-items: center; justify-content: center; min-height: 28px; padding: 0 12px; border-radius: 14px; font-size: 13px; font-weight: 500; white-space: nowrap; }
.check-list { display: grid; gap: 6px; margin-top: 16px; padding: 0; list-style: none; }
.check-list li { display: grid; grid-template-columns: minmax(7.5em, auto) minmax(80px, 1fr) 5.2em; align-items: center; gap: 16px; min-height: 48px; font-size: 15px; }
.chip { justify-self: end; width: 100%; }
[data-state="pass"] { --tone: var(--pass); --tint: var(--pass-tint); }
[data-state="unsure"] { --tone: var(--unsure); --tint: var(--unsure-tint); }
[data-state="fail"] { --tone: var(--fail); --tint: var(--fail-tint); }
[data-state="none"] { --tone: var(--none); --tint: var(--none-tint); }
.verdict, .chip { background: var(--tint); color: var(--tone); transition: background-color 160ms ease, color 160ms ease; }
.bar { position: relative; height: 24px; }
.bar::before { content: ""; position: absolute; left: 0; right: 0; top: calc(50% - 2px); height: 4px; border-radius: 2px; background: #dde2d7; }
[data-state="none"] .bar::before { background: repeating-linear-gradient(90deg, #c3cabd 0 6px, transparent 6px 11px); }
.bar-limit { position: absolute; left: calc(50% - 1.5px); top: 0; bottom: 0; width: 3px; border-radius: 2px; background: var(--ink); }
.bar-estimate { position: absolute; top: calc(50% - 6px); left: calc(var(--lo) * 100%); width: calc((var(--hi) - var(--lo)) * 100%); height: 12px; border-radius: 6px; background: var(--tone); }
[data-state="none"] .bar-estimate { opacity: 0; }
.legend { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; margin-top: 18px; font-size: 13px; color: var(--muted); }
.legend-limit { width: 3px; height: 16px; border-radius: 2px; background: var(--ink); }
.legend-estimate { width: 26px; height: 10px; margin-left: 10px; border-radius: 5px; background: var(--muted); }

.next { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "title actions" "text actions"; align-items: end; column-gap: 40px; padding-top: var(--section); }
.next h2 { grid-area: title; }
.next > p { grid-area: text; max-width: 620px; margin-top: 12px; font-size: 17px; line-height: 1.5; color: var(--muted); text-wrap: pretty; }
.next-actions { grid-area: actions; display: flex; align-items: center; flex-wrap: wrap; gap: 12px 24px; }
.site-footer { display: flex; align-items: center; justify-content: space-between; gap: 16px 32px; padding-block: 40px max(40px, env(safe-area-inset-bottom)); font-size: 13px; line-height: 1.55; color: var(--muted); }
.site-footer p { max-width: 640px; }
.site-footer a { display: inline-flex; align-items: center; min-height: 44px; white-space: nowrap; color: var(--ink); }

/* Touch gets a brief press state on plain links too. */
nav a:active, .site-footer a:active, .text-link:active { opacity: .6; }
@media (hover: hover) and (pointer: fine) {
  nav a:not(.nav-pill):hover, .site-footer a:hover { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 5px; }
  .nav-pill:hover, .control:hover { background: var(--wash-deep); }
  .button:hover, .demo-controls [data-demo-play]:hover { background: var(--fern); }
  .text-link:hover { text-decoration-color: currentColor; }
  .step:not([aria-current]):hover { color: var(--ink); }
  html:not([data-input="keyboard"]) .unseen-scene:hover .unseen-grip { transform: translateY(-50%) scale(1.08); }
}
/* A key press changes these at once; scroll-triggered figures keep their motion. */
html[data-input="keyboard"] :is(.step, .step-n, .step-progress, .control, .button, .nav-pill, .text-link, .unseen-grip, .unseen-request, .verdict, .chip, .layer-btn, .layer-num) { transition: none !important; }
/* A key that selects a layer moves it at once too; the one-time separation on scroll keeps its motion. */
html[data-input="keyboard"] .stack-figure:not([data-exploding]) :is(.layer, .sheet, .sheet-body, .sheet-shadow, .sheet-outline, .layer-n, .layer-n circle, .layer-note) { transition: none !important; }
@media (prefers-reduced-motion: reduce) {
  /* A selection keeps its outlines and colour but does not move the sheets. */
  [data-focus] .layer[data-pos] { --lift: 0px; }
  .layer[data-pos="focus"] .sheet { transform: none; }
  .layer-btn:active { transform: none; }
  *, *::before, *::after { transition-duration: 0ms !important; transition-delay: 0ms !important; }
  .button:active, .control:active, .step:active { transform: none; }
  .film-replay { display: none; }
}

@media (max-width: 980px) {
  .wrap { padding-inline: 36px; }
  .stack-figure { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); row-gap: 40px; }
  .stack-wire { grid-column: 1 / -1; }
  .stack-wire .stack-visual { max-width: 460px; }
  .stack-wire .stack-visual::before, .stack-wire .stack-visual::after { display: none; }
  .rebuild-grid { grid-template-columns: minmax(0, 1fr); row-gap: 48px; }
  .rebuild-grid > .code { position: static; max-width: 460px; }
  .server-figure { --art-w: 220px; }
  .hero { column-gap: 40px; }
  .lane-now { grid-template-columns: minmax(0, 1fr); row-gap: 28px; padding-top: 0; }
  .lane-now { margin-top: 18px; }
  .node { display: grid; grid-template-columns: 148px minmax(0, 1fr); align-items: center; gap: 20px; }
  .lane-now .node:not(:last-child) .art::after { top: calc(100% + 6px); left: calc(50% - 1px); width: 2px; height: 16px; }
  .lane-now .node:not(:last-child) .art::before { top: calc(100% + 17px); left: calc(50% - 6px); border: 6px solid transparent; border-top: 8px solid var(--ink); border-bottom: 0; }
  .loop { position: static; order: 5; height: auto; padding: 0 0 0 168px; border: 0; }
  .loop::after { display: none; }
  .loop span { position: static; display: block; max-width: 17em; translate: none; padding: 0; background: none; white-space: normal; text-wrap: balance; }
  .node[data-node="ar"] { order: 6; }
  .unseen { grid-template-columns: minmax(0, 1fr); grid-template-areas: "copy" "scene" "checks"; column-gap: 0; }
  .checks { margin-top: 32px; }
  .unseen-copy { max-width: 560px; }
}
@media (max-width: 760px) {
  :root { --section: 80px; }
  .wrap { padding-inline: max(20px, env(safe-area-inset-left)) max(20px, env(safe-area-inset-right)); }
  .site-header { min-height: 68px; }
  nav { gap: 18px; font-size: 14px; }
  nav a[href="#how"] { display: none; }
  .hero { grid-template-columns: minmax(0, 1fr); grid-template-areas: "copy" "phone" "steps"; grid-template-rows: none; padding-block: 8px 24px; }
  .hero-copy { padding-top: 16px; }
  /* Scales with the width so each sentence keeps its own line down to 320px (the first spans about 0.84 of the viewport). */
  .hero h1 { margin-top: 0; font-size: clamp(30px, 9.4vw, 44px); }
  .lede { font-size: 17px; margin-top: 16px; }
  .phone-demo { justify-self: stretch; margin-top: 28px; }
  /* Small enough that the step bar and Play sit under the phone in one screen. */
  .phone-shell { width: min(100%, 300px, calc((100svh - 150px) * 433 / 882)); height: auto; margin-inline: auto; }
  .hero-steps { justify-self: stretch; max-width: 420px; width: 100%; margin: 16px auto 0; }
  .steps { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .step { display: flex; flex-direction: column; justify-content: center; gap: 6px; min-height: 52px; padding: 8px 4px; font-size: 15px; text-align: center; }
  .step-n { display: none; }
  .step-name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .step-short { display: block; }
  .step-progress { width: 100%; margin-top: 0; }
  .demo-controls { justify-content: center; margin-top: 12px; padding-left: 0; }
  .section-head { margin-bottom: 20px; }
  .film-stage { margin-inline: -8px; border-radius: 14px; }
  .panel { clip-path: inset(0 4px 0 0 round 10px); }
  [data-panel="measured"] { clip-path: inset(0 4px 0 4px round 10px); }
  [data-panel="placed"] { clip-path: inset(0 0 0 4px round 10px); }
  .panel-chip { top: 6px; left: 6px; padding: 3px 7px; font-size: 11px; }
  [data-panel="measured"] .panel-chip, [data-panel="placed"] .panel-chip { left: 10px; }
  /* Labels scale with the drawing, so they grow in drawing units to stay about 11px on a phone. */
  .dimension text, .film-label { font-size: 21px; }
  .film-label { display: none; }
  .dimension.side text, .film-tag { display: none; }
  .readings { grid-template-columns: minmax(0, 1fr); gap: 14px; margin-top: 20px; }
  .readings p { display: grid; grid-template-columns: 6.2em minmax(0, 1fr); padding-right: 0; }
  .film[data-panels] .readings p { display: block; }
  .readings b { margin: 0; font-size: 17px; }
  .how { padding-block: 64px 72px; }
  .stack-figure { grid-template-columns: minmax(0, 1fr); row-gap: 36px; margin-top: 28px; }
  .stack-plan .stack-visual::before, .stack-plan .stack-visual::after { display: none; }
  .layer-key { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .layer-btn { min-height: 52px; }
  .json { padding: 12px 14px 14px; font-size: 12px; }
  .rebuild-grid { margin-top: 32px; }
  /* Each stage's drawing runs full width above its text, with the connector centred between stages. */
  .server-figure { --row-gap: 44px; }
  .server-node { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .server-node:not(:last-child)::after { top: auto; bottom: calc(10px - var(--row-gap)); left: calc(50% - 1px); height: calc(var(--row-gap) - 20px); }
  .server-node:not(:last-child)::before { left: calc(50% - 6px); }
  .server-events { --art-w: 44px; padding-left: calc(var(--art-w) + 16px); }
  .flow { margin-top: 32px; }
  .node { grid-template-columns: 112px minmax(0, 1fr); gap: 16px; }
  .loop { padding-left: 128px; }
  .unseen-scene { border-radius: 14px; }
  .unseen-request { top: 10px; left: 10px; max-width: calc(100% - 20px); padding: 8px 12px 8px 10px; font-size: 13px; }
  .check-list li { grid-template-columns: minmax(0, 1fr) 5.2em; grid-template-areas: "name chip" "bar bar"; row-gap: 4px; padding-block: 6px; }
  .check-name { grid-area: name; }
  .bar { grid-area: bar; }
  .chip { grid-area: chip; }
  .next { grid-template-columns: minmax(0, 1fr); grid-template-areas: "title" "text" "actions"; }
  .next-actions { margin-top: 24px; }
  .site-footer { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 380px) {
  /* GitHub stays one scroll away, in the closing links; the header keeps the briefing. */
  .nav-pill { display: none; }
  /* At 11px, 38 monospace characters still fit, so the examples keep their lines. */
  .json { padding-inline: 12px; font-size: 11px; }
  .code-head { padding-inline: 12px; }
}
@media (max-width: 360px) {
  .step { padding-inline: 10px; column-gap: 12px; }
}
