/* Round 27: ONE homepage on warm paper (and dark), built on h26. Also styles h27-case.html (with h27/case.css).
   Kept from h26: tokens, the ring hero, the Linear-style logo row, the footer.
   New here: the sticky header with the F glyph, the real-logo marquee (section 3), the sticky "what we do" story with five
   hairline diagrams (section 4), the case-study carousel (5), the process track (6), the agency-style booking
   block (8) and the questions (7). House rule: nothing pulses or blinks. */

/* ---------- tokens ----------
   CSS variables ("custom properties") are named values the whole page reads. Change one here and every
   section follows. Every font-family lives here (--sans, --mono, --display); nothing below names a font.

   COLOUR  light only (Teegan, 2026-10-16). One paper (--paper) and ONE raised surface (--surface). Every grey is ink at some opacity or a warm tone
           of the same family. Tool logos are the one exception: they show their real brand colour (Teegan's
           decision, 2026-10-16), drawn small, never as a fill behind text.
   ORANGE  only as a filled surface with ink on it (the pill). Never orange text or a thin orange line: on the
           paper it is 2.8:1, too weak to carry meaning.
   MOTION  the token set proposed in website-kit/library/motion-scroll.md section 6. One curve, a few durations.
           Every transition reads these; a raw "ms" value in a component is a bug. The one exception is the
           logo marquee, which runs linear (constant speed) on its own token, --mq-loop. */
:root {
  --paper: #F4F1EB;
  --ink: #1C1713;
  --mute: #6C645B;
  --faint: #A39A8F;
  --hair: rgba(28, 23, 19, .12);
  --hair-strong: rgba(28, 23, 19, .26);
  --surface: #FAF8F4;                 /* the ONE raised tone */
  --orange: #FF560D;
  --logo: brightness(0);              /* client wordmarks: any colour becomes one flat ink shape */
  --dot: rgba(28, 23, 19, .16);       /* the dot grid behind the diagram stage */
  --mono: "JetBrains Mono", ui-monospace, Menlo, monospace;
  --sans: "Bricolage Grotesque", system-ui, sans-serif;
  --display: var(--sans);             /* headings; a separate token so a display face can be swapped in one place */
  --gut: 32px;
  --pad: 48px;                        /* half the gap between two sections (96px of rhythm) */
  --nav-h: 68px;                      /* the sticky header; anchors and the sticky stage sit below it */

  /* motion (motion-scroll.md section 6) */
  --ease: cubic-bezier(.16, 1, .3, 1); /* fast start, long soft landing, no overshoot */
  --t1: 160ms;                        /* feedback: hover, press, a colour */
  --t2: 400ms;                        /* a crossfade, a panel, a disclosure */
  --t3: 700ms;                        /* a reveal on scroll, a line drawing, the hero rising in */
  --t-step: 1000ms;                   /* one step of a figure sequence, seen once */
  --beat: calc(var(--t-step) * .4);   /* the gap between the parts of one diagram (400ms) */
  --stagger: 60ms;                    /* between siblings, at most a handful */
  --rise: 14px;                       /* reveal distance */
  --mq-loop: 55s;                     /* one loop of the logo marquee (Teegan: 50 to 60s) */
  --r-face: var(--surface);           /* the ring hero's display glass (h23/ring.css reads this) */
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
/* scroll-padding-top: in-page links (#what, #cases...) stop below the sticky header instead of under it.
   Smooth scrolling ONLY while focus is inside the page, which is the moment right after a link is clicked.
   A global `scroll-behavior: smooth` also animates the browser's own scroll restoration (reload, back) and any
   adjustment it makes while the page is still laying out; an animation that starts from the top and gets
   interrupted leaves the reader somewhere they did not choose. So: instant everywhere, smooth for link jumps. */
html { scroll-padding-top: calc(var(--nav-h) + 8px); background: var(--paper); }
html:focus-within { scroll-behavior: smooth; }
html, body { margin: 0; color: var(--ink); }
body { position: relative; font: 16px/1.45 var(--sans); -webkit-font-smoothing: antialiased; overflow-x: clip; background: var(--paper); }
a { color: inherit; text-decoration: none; }
/* The panel: 1200px of content (1264 minus 32px gutters each side). */
.wrap { max-width: 1264px; margin: 0 auto; padding: 0 var(--gut); }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
/* Visually hidden, still read by screen readers. */
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* "calm" = ?still=1 or reduced motion: nothing moves, everything shows its finished pose. */
.calm *, .calm *::before, .calm *::after { animation: none !important; transition: none !important; }
.calm, .calm:focus-within { scroll-behavior: auto; }

/* ---------- the sticky header (light only: no theme toggle) ----------
   position: sticky keeps it at the top once the page scrolls past it, with no script. It is painted on the paper
   colour so content slides under it cleanly; .scrolled (shared.js) adds one hairline. No shadow, no blur. */
.nav { position: sticky; top: 0; z-index: 50; height: var(--nav-h); display: flex; align-items: center; background: var(--paper);
  border-bottom: 1px solid transparent; transition: border-color var(--t1) var(--ease); }
.nav.scrolled { border-bottom-color: var(--hair); }
.navin { display: flex; align-items: center; width: 100%; }
.mark { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; font-size: 22px; letter-spacing: -.03em; margin-right: 44px; font-variation-settings: "opsz" 40; }
/* The F glyph (h27/flowsor-logo-glyph.svg, fill = currentColor) before the wordmark. Its box is the glyph plus a
   hair of air, so 20px tall puts the F's top and bottom on the wordmark's cap height and baseline. The gap follows
   the brand lockup (tile mark, one gap, the word); 10px here because the glyph has no tile around it. */
.glyph { width: auto; height: 20px; flex: none; margin-top: -1px; }
.nav nav { display: flex; gap: 30px; font-size: 14.5px; flex: 1; }
.nav nav a { opacity: .82; transition: opacity var(--t1) var(--ease); }
.nav nav a:hover { opacity: 1; }
.navcta { white-space: nowrap; }

/* ---------- 1. hero (h26's) ----------
   The hero fills the first screen on its own; the "worked with" row arrives just after the first scroll
   (Teegan, 2026-10-16: keep the logos a little below the fold). */
.hero { padding-bottom: 20px; }
.herogrid { display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); gap: clamp(24px, 3vw, 48px); align-items: center; min-height: calc(100svh - 68px); }  /* hero fills the first screen on its own; the client logos start just below the fold (Teegan, 2026-10-16) */
.copy { padding-bottom: 36px; }
h1 { margin: 0; font-family: var(--display); font-weight: 450; font-size: clamp(40px, 4.7vw, 68px); line-height: 1.02; letter-spacing: -.035em;
  font-variation-settings: "opsz" 96, "wdth" 92; text-wrap: balance; animation: rise var(--t3) var(--ease) both; }
.sub { margin: 26px 0 0; font-size: clamp(16px, 1.32vw, 19px); line-height: 1.45; color: var(--mute); max-width: 31ch; animation: rise var(--t3) var(--ease) both .15s; }
.ctas { margin-top: 30px; display: flex; gap: 12px; flex-wrap: wrap; animation: rise var(--t3) var(--ease) both .28s; }
/* The one orange: a filled pill with ink on it (5.45:1). The arrow nudges on hover. */
.pill { display: inline-flex; align-items: center; gap: 10px; background: var(--orange); color: #1b0d06; font-weight: 600; font-size: 15.5px;
  padding: 13px 20px 13px 22px; border-radius: 999px; transition: gap var(--t1) var(--ease); }
.pill:hover { gap: 14px; }
/* The small size of the same component, for the header: same colour, shape, arrow and hover, smaller type. */
.pill-sm { gap: 8px; font-size: 14px; padding: 8px 14px 8px 16px; }
.pill-sm svg { width: 15px; height: 15px; }
.pill-sm:hover { gap: 11px; }
.fine { margin: 16px 0 0; font: 400 12px/1.5 var(--mono); color: var(--mute); letter-spacing: .01em; animation: rise var(--t3) var(--ease) both .4s; }
@keyframes rise { from { opacity: 0; transform: translateY(var(--rise)); } }
.herofig { display: flex; justify-content: flex-end; min-width: 0; }
/* The ring keeps its proportion to the text at every width: it fills its column (up to 620px) instead of the old
   fixed 600px box, and the text column is a fraction too (.9fr : 1.1fr), so both shrink together. Its labels scale
   with the figure (cqi = 1% of the figure's width) but never below 9px. Below 960px it moves under the text rather
   than becoming a small island. Overrides h23/ring.css for this page only. */
.herofig .fig { width: 100%; max-width: 620px; }
.herofig .fig .lbl { font-size: clamp(9px, calc(1.9cqi * var(--k, 1)), 11px); }
@media (max-width: 960px) {
  .herogrid { grid-template-columns: minmax(0, 1fr); min-height: 0; padding-top: 24px; }
  .herofig { justify-content: flex-start; margin-top: 16px; }
  .herofig .fig { max-width: 600px; margin-left: 0; }
}
body > .opts { display: none !important; }   /* the ring's own selects are review chrome */

/* ---------- shared section furniture ---------- */
/* Every section is a hairline, then 48px, content, 48px. Two sections therefore sit 96px apart. */
.sec { border-top: 1px solid var(--hair); padding: var(--pad) 0; position: relative; }
.eyebrow { margin: 0 0 18px; font: 500 12px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--mute); }
h2 { margin: 0; font-family: var(--display); font-weight: 450; font-size: clamp(30px, 3.5vw, 46px); line-height: 1.06; letter-spacing: -.03em;
  font-variation-settings: "opsz" 80, "wdth" 94; text-wrap: balance; }
h3 { margin: 0; font-weight: 500; letter-spacing: -.01em; }
.lead { margin: 0; color: var(--mute); font-size: 17px; line-height: 1.5; max-width: 46ch; }
.idx { font: 400 12px/1 var(--mono); color: var(--mute); letter-spacing: .04em; font-variant-numeric: tabular-nums; }
/* Heading left, one line right, baselines level. */
.head { display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 4fr); gap: 48px; align-items: end; margin-bottom: 40px; }
.head h2 { max-width: 24ch; }
.act { font: 500 12px/1 var(--sans); padding: 8px 13px; border-radius: 5px; border: 1px solid var(--hair-strong); }
.act.primary { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* Reveal on scroll (R3): a block rises 14px and fades in once (shared.js adds .in). Hidden only when JS runs. */
.js:not(.calm) .rv { opacity: 0; transform: translateY(var(--rise)); transition: opacity var(--t3) var(--ease), transform var(--t3) var(--ease); }
.js:not(.calm) .rv.in { opacity: 1; transform: none; }

/* ---------- 2. worked with (as h26) ---------- */
.proof { padding: 56px 0 104px; }
.logos { list-style: none; margin: 0; padding: 0; display: flex; justify-content: space-between; align-items: center; gap: 32px; }
.logos li { display: flex; align-items: center; min-width: 0; }
.logos img { display: block; height: var(--h); width: auto; max-width: 100%; filter: var(--logo); opacity: .92; }
.logos img { --h: 36px; }
/* Optical scale (Teegan, 2026-10-17: "not to scale"). Equal heights made the all-text Photo Booth wordmark far
   heavier than the others, so each logo gets a height from its shape instead: wide, dense marks smaller, compact
   marks larger, until they look the same size (website-kit/logo-strip.md: size by area, then adjust by eye). */
.logos li:nth-child(1) img { --h: 20px; }   /* The Photo Booth Company: a bold text wordmark, 12.5 : 1 */
.logos li:nth-child(2) img { --h: 38px; }   /* Ventures ATL: mark plus light serif name, 3.5 : 1 */
.logos li:nth-child(3) img { --h: 34px; }   /* Artisan Land Companies, 5 : 1 */
.logos li:nth-child(4) img { --h: 32px; }   /* Georgia Tech: heavy mark, 5.6 : 1 */
/* The caption sits ABOVE the row (Teegan, round 3), as a small label for it. */
.proof-cap { margin: 0 0 28px; font: 500 11.5px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--mute); }

/* ---------- 3. systems we connect: the marquee (R8) ----------
   Each row holds two identical lists side by side and slides left by exactly one list plus one gap, then starts
   over, so the seam never shows. Row 2 runs the same animation in reverse (rightward). Linear timing: a loop is a
   constant speed, not an arrival (the one written exception to the single easing). The edges fade out through a
   mask (a gradient of transparency, so the fade is exactly the page colour). */
.mq { display: grid; gap: 26px; padding: 6px 0; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.mq-row { display: flex; gap: 48px; width: max-content; animation: mq var(--mq-loop) linear infinite; }
.mq-row[data-dir="right"] { animation-direction: reverse; }
.mq-row ul { display: flex; gap: 48px; margin: 0; padding: 0; list-style: none; }
@keyframes mq { to { transform: translateX(calc(-50% - 24px)); } }
/* Stopped off screen or in a hidden tab (.off, home.js) and under the pointer. */
.mq.off .mq-row { animation-play-state: paused; }
@media (hover: hover) { .mq:hover .mq-row { animation-play-state: paused; } }
/* One tool: its real mark in its brand colour (--c, set by shared.js), then its name in our type. A brand colour
   too close to the paper (Mailchimp's yellow) falls back to ink. */
.tl { display: flex; align-items: center; gap: 10px; white-space: nowrap; font-size: 16px; font-weight: 500; letter-spacing: -.01em; }
.tl svg { width: 22px; height: 22px; flex: none; fill: var(--c); }
/* In the marquee the logo sits to the RIGHT of the name (Teegan, 2026-10-16). order moves it visually only. */
.mq .tl svg { order: 2; }
.lo svg { fill: var(--ink) !important; }
/* Calm: no movement; the rows wrap into a still list. */
.calm .mq { -webkit-mask-image: none; mask-image: none; }
.calm .mq-row { width: auto; }
.calm .mq-row ul { flex-wrap: wrap; gap: 18px 40px; }
.calm .mq-row ul + ul { display: none; }

/* ---------- 4. what we do: the sticky story (R5) ----------
   Two layouts from one markup:
     stack   (default: phones, reduced motion, no JS) each step is its text and then its own diagram
     sticky  (.story.sticky, set by home.js on wide screens) the diagrams sit in one sticky stage on the left,
             the steps scroll on the right, and the step crossing the middle of the window is "on". */
.steps { list-style: none; margin: 0; padding: 0; }
.step-t h3 { display: flex; align-items: baseline; gap: 14px; font-weight: 450; font-size: clamp(24px, 2.3vw, 30px); letter-spacing: -.02em; font-variation-settings: "opsz" 60, "wdth" 94; }
.step-t p { margin: 12px 0 0; color: var(--mute); font-size: 17px; line-height: 1.5; max-width: 40ch; }

/* stack layout */
.step { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: 48px; align-items: center; padding: 40px 0; border-top: 1px solid var(--hair); }
.step:first-child { border-top: 0; padding-top: 8px; }

/* sticky layout. The stage is centred in the part of the window below the sticky header. */
.story.sticky { display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); gap: 72px; }
.story.sticky .stage { position: sticky; top: calc(var(--nav-h) / 2 + 50vh - 230px); height: 460px; display: grid; place-items: center; }
/* the faint dot grid behind the stage, faded toward its edges (as h26's integrations stage) */
.story.sticky .stage::before { content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(circle, var(--dot) 1px, transparent 1.4px); background-size: 22px 22px; background-position: 11px 11px;
  -webkit-mask-image: radial-gradient(ellipse 70% 72% at 50% 50%, #000 30%, transparent 100%); mask-image: radial-gradient(ellipse 70% 72% at 50% 50%, #000 30%, transparent 100%); }
.story.sticky .stage .dg { grid-area: 1 / 1; position: relative; opacity: 0; transition: opacity var(--t2) var(--ease); }
.story.sticky .stage .dg.on { opacity: 1; }
.story.sticky .step { display: flex; align-items: center; min-height: 64vh; padding: 0; border: 0; }
.story.sticky .step-t { opacity: .38; transition: opacity var(--t2) var(--ease); }
.story.sticky .step.on .step-t { opacity: 1; }
.stage:empty { display: none; }

.also { display: flex; gap: 14px; align-items: baseline; margin: 40px 0 0; padding-top: 20px; border-top: 1px solid var(--hair); color: var(--mute); font-size: 15.5px; }
.also span { flex: none; font: 500 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--ink); }

/* ---------- the diagrams ----------
   Each diagram is drawn on a 440 x 340 grid, like an SVG viewBox, but in HTML so its text stays crisp.
   --u is one grid unit: the figure's own width divided by 440 (cqw = 1% of the nearest container's width, and
   the <figure> is that container). Every position and size is a multiple of --u, so the whole diagram scales
   as one piece and nothing drifts out of place at another width. */
.dg { margin: 0; width: 100%; max-width: 500px; justify-self: center; container-type: inline-size; }
.cv { --u: calc(100cqw / 440); position: relative; width: 100%; aspect-ratio: 440 / 340; font-size: calc(13 * var(--u)); line-height: 1.35; }
.cv > * { position: absolute; }
.wires { inset: 0; width: 100%; height: 100%; overflow: visible; }
/* pathLength="1" makes each path's length 1, so a dash of 1 shifted by 1 hides it and a shift of 0 shows it:
   the line draws itself with no measuring in JS. */
.wires path { fill: none; stroke: var(--hair-strong); stroke-width: 1; stroke-dasharray: 1; stroke-dashoffset: 0;
  transition: stroke-dashoffset var(--t3) var(--ease) calc(var(--beat) * (var(--i, 0) + 1)); }
.chip, .card { left: calc(var(--x, 0) * var(--u)); top: calc(var(--y, 0) * var(--u)); background: var(--surface); border: 1px solid var(--hair-strong); border-radius: calc(6 * var(--u)); }
.card { width: calc(var(--w) * var(--u)); }
/* A real tool mark inside any diagram or fragment: <i data-logo="slug"></i>, coloured by --c (shared.js). */
i[data-logo] { display: inline-block; flex: none; width: calc(18 * var(--u, 1px)); height: calc(18 * var(--u, 1px)); vertical-align: middle; }
i[data-logo] svg { display: block; width: 100%; height: 100%; fill: var(--c); }
.card-h { display: flex; justify-content: space-between; align-items: center; height: calc(40 * var(--u)); margin: 0; padding: 0 calc(14 * var(--u)); }
.card-h b { font-weight: 500; }
.card-h span, .row span, .node p span, .kpis span, .hl span, .attn > span, .pipe span { font: 400 calc(10 * var(--u))/1.2 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--mute); }
.with-logo { display: inline-flex; align-items: center; gap: calc(8 * var(--u)); }
.with-logo i[data-logo] { width: calc(16 * var(--u)); height: calc(16 * var(--u)); }

/* 1. connect: chips, wires, one record */
.chip { display: flex; align-items: center; gap: calc(10 * var(--u)); width: calc(150 * var(--u)); height: calc(40 * var(--u)); padding: 0 calc(12 * var(--u)); font-weight: 500;
  transition: opacity var(--t3) var(--ease) calc(var(--stagger) * var(--i)), transform var(--t3) var(--ease) calc(var(--stagger) * var(--i)); }
.row { display: grid; grid-template-columns: calc(78 * var(--u)) minmax(0, 1fr); align-items: center; height: calc(40 * var(--u)); margin: 0; padding: 0 calc(14 * var(--u)); border-top: 1px solid var(--hair); }
.row em { font-style: normal; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: opacity var(--t2) var(--ease) calc(var(--beat) * (var(--i) + 1.8)); }

/* 2. agent: the invoice arrives, the check against the books, the approval bar */
.dg-agent > .cv > .card { transition: opacity var(--t3) var(--ease) calc(var(--beat) * var(--i) * 1.5), transform var(--t3) var(--ease) calc(var(--beat) * var(--i) * 1.5); }
.mail { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; align-items: center; gap: calc(10 * var(--u)); height: calc(56 * var(--u)); margin: 0; padding: 0 calc(14 * var(--u)); }
.mail b { font-weight: 500; white-space: nowrap; }
.mail span { color: var(--mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mail time { font: 400 calc(10 * var(--u))/1 var(--mono); color: var(--mute); }
.ln { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr) minmax(0, 1.1fr) calc(62 * var(--u)); align-items: center; gap: calc(8 * var(--u));
  height: calc(40 * var(--u)); margin: 0; padding: 0 calc(14 * var(--u)); border-top: 1px solid var(--hair); font-size: calc(12 * var(--u)); color: var(--mute); }
.ln span:first-child { color: var(--ink); }
.ln em { font: 400 calc(10 * var(--u))/1 var(--mono); font-style: normal; text-align: center; padding: calc(4 * var(--u)) 0; border-radius: calc(4 * var(--u)); border: 1px solid var(--hair-strong);
  transition: background-color var(--t2) var(--ease) calc(var(--beat) * 3), color var(--t2) var(--ease) calc(var(--beat) * 3); }
.ln.bad span { color: var(--ink); }
.ln.bad em { background: var(--ink); color: var(--paper); border-color: var(--ink); }   /* the one line that needs you */
.bar { display: flex; justify-content: space-between; align-items: center; height: calc(56 * var(--u)); padding: 0 calc(10 * var(--u)) 0 calc(14 * var(--u)); }
.bar p { margin: 0; display: flex; align-items: center; gap: calc(8 * var(--u)); }
.wait { font: 400 calc(11 * var(--u))/1 var(--mono); }
.wait i { width: calc(9 * var(--u)); height: calc(9 * var(--u)); border-radius: 50%; border: 1px solid var(--ink); }
.cv .act { font-size: calc(12 * var(--u)); padding: calc(8 * var(--u)) calc(13 * var(--u)); border-radius: calc(5 * var(--u)); }

/* 3. automations: a rail and four nodes */
.dg-flow .rail { transition-duration: calc(var(--beat) * 4); transition-delay: 0s; }
.node { left: 0; top: calc(var(--y) * var(--u)); width: 100%; height: calc(56 * var(--u));
  transition: opacity var(--t3) var(--ease) calc(var(--beat) * var(--i)), transform var(--t3) var(--ease) calc(var(--beat) * var(--i)); }
.node .dot { position: absolute; left: calc(28 * var(--u)); top: calc(22 * var(--u)); width: calc(12 * var(--u)); height: calc(12 * var(--u)); border-radius: 50%; border: 1px solid var(--ink); background: var(--paper); }
.node .card { position: absolute; left: calc(64 * var(--u)); top: 0; width: calc(376 * var(--u)); height: 100%; display: flex; align-items: center; gap: calc(12 * var(--u)); padding: 0 calc(14 * var(--u)); }
.node .card i[data-logo] { width: calc(20 * var(--u)); height: calc(20 * var(--u)); }
.node p { flex: 1; min-width: 0; margin: 0; display: grid; gap: calc(3 * var(--u)); }
.node p b { font-weight: 500; }
.node em { font: 400 calc(10.5 * var(--u))/1 var(--mono); font-style: normal; color: var(--ink); transition: opacity var(--t2) var(--ease) calc(var(--beat) * (var(--i) + 1)); }

/* 4. dashboard: header, one headline number with an area chart, three sourced tiles, a short attention list.
   Everything sits on the same 14-unit inner padding, so the left edges line up down the panel. */
.panel { height: calc(320 * var(--u)); display: flex; flex-direction: column; }
.panel .card-h { height: calc(36 * var(--u)); border-bottom: 1px solid var(--hair); }
.hl { padding: calc(12 * var(--u)) calc(14 * var(--u)) 0; }
.hl p { margin: 0; display: flex; align-items: center; gap: calc(8 * var(--u)); }
.tag { font: 400 calc(9 * var(--u))/1 var(--mono); font-style: normal; letter-spacing: .06em; text-transform: uppercase; color: var(--mute); padding: calc(3 * var(--u)) calc(5 * var(--u)); border: 1px solid var(--hair); border-radius: calc(3 * var(--u)); }
.hl-v { margin-top: calc(6 * var(--u)) !important; align-items: baseline !important; }
.hl-v b { font-weight: 450; font-size: calc(26 * var(--u)); line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.hl-v span { text-transform: none !important; letter-spacing: 0 !important; color: var(--ink) !important; }
.area { position: relative; height: calc(64 * var(--u)); margin: calc(10 * var(--u)) calc(14 * var(--u)) calc(10 * var(--u)); overflow: hidden; }
.area svg { display: block; width: 100%; height: 100%; }
.area .grid { fill: none; stroke: var(--hair); stroke-width: 1; vector-effect: non-scaling-stroke; }
.area .line { fill: none; stroke: var(--ink); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.area .fill { fill: color-mix(in srgb, var(--ink) 6%, transparent); }
/* The draw: a strip in the panel colour covers the chart and slides off to the right once. */
.area .wipe { position: absolute; inset: 0; background: var(--surface); transform: translateX(100%); transition: transform calc(var(--t-step) * 1.4) var(--ease) var(--beat); }
.kpis { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--hair); border-bottom: 1px solid var(--hair); }
.kpis p { margin: 0; padding: calc(10 * var(--u)) calc(14 * var(--u)); display: grid; gap: calc(6 * var(--u)); border-left: 1px solid var(--hair);
  transition: opacity var(--t3) var(--ease) calc(var(--beat) * 2 + var(--stagger) * var(--i)); }
.kpis p:first-child { border-left: 0; }
.kpis span { display: flex; align-items: center; gap: calc(6 * var(--u)); }
.kpis i[data-logo] { width: calc(12 * var(--u)); height: calc(12 * var(--u)); }
.kpis b { font-weight: 450; font-size: calc(17 * var(--u)); line-height: 1; letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
.attn { padding: calc(10 * var(--u)) calc(14 * var(--u)) 0; }
.attn p { margin: 0; display: flex; align-items: center; gap: calc(8 * var(--u)); height: calc(26 * var(--u)); font-size: calc(12 * var(--u));
  transition: opacity var(--t3) var(--ease) calc(var(--beat) * 3 + var(--stagger) * var(--i)); }
.attn p + p { border-top: 1px solid var(--hair); }
.attn > span { display: block; margin-bottom: calc(4 * var(--u)); }
.attn i { width: calc(6 * var(--u)); height: calc(6 * var(--u)); border-radius: 50%; background: var(--ink); flex: none; }
.attn em { margin-left: auto; font: 400 calc(10.5 * var(--u))/1 var(--mono); font-style: normal; color: var(--mute); }

/* 5. data: three duplicates slide together into one record, which then lands in a pipeline */
.dup { height: calc(116 * var(--u)); padding: 0 calc(10 * var(--u)); font-size: calc(11 * var(--u));
  transition: opacity var(--t3) var(--ease) calc(var(--beat) * 2), transform var(--t3) var(--ease) calc(var(--beat) * 2); }
.dup p { margin: 0; height: calc(26 * var(--u)); display: flex; align-items: center; gap: calc(6 * var(--u)); border-top: 1px solid var(--hair); white-space: nowrap; overflow: hidden; }
.dup .dh { height: calc(36 * var(--u)); border-top: 0; font: 400 calc(9.5 * var(--u))/1 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--mute); }
.dup .dh i[data-logo] { width: calc(13 * var(--u)); height: calc(13 * var(--u)); }
.dup .no, .tr .no { font: 400 calc(9.5 * var(--u))/1 var(--mono); color: var(--faint); }
.merged { border-color: var(--ink); transition: opacity var(--t3) var(--ease) calc(var(--beat) * 3), transform var(--t3) var(--ease) calc(var(--beat) * 3); }
.badge { padding: calc(4 * var(--u)) calc(6 * var(--u)); border: 1px solid var(--hair-strong); border-radius: calc(3 * var(--u)); }
.fld { display: grid; grid-template-columns: calc(50 * var(--u)) minmax(0, 1fr) auto; align-items: center; gap: calc(8 * var(--u)); height: calc(36 * var(--u)); margin: 0;
  padding: 0 calc(14 * var(--u)); border-top: 1px solid var(--hair); font-size: calc(12 * var(--u)); }
.fld > span { font: 400 calc(9.5 * var(--u))/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--mute); }
.fld b { font-weight: 450; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fld small { display: inline-flex; align-items: center; gap: calc(4 * var(--u)); padding: calc(3 * var(--u)) calc(6 * var(--u)) calc(3 * var(--u)) calc(4 * var(--u));
  border: 1px solid var(--hair); border-radius: 999px; font: 400 calc(9 * var(--u))/1 var(--mono); color: var(--mute); }
.fld small i[data-logo] { width: calc(11 * var(--u)); height: calc(11 * var(--u)); }
.pipe { left: 0; top: calc(var(--y) * var(--u)); width: 100%; height: calc(112 * var(--u)); display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: 1px solid var(--hair-strong); border-bottom: 1px solid var(--hair); }
.pipe > div { padding: calc(10 * var(--u)) calc(10 * var(--u)); border-left: 1px solid var(--hair); }
.pipe > div:first-child { border-left: 0; }
.pc { margin: calc(10 * var(--u)) 0 0; padding: calc(8 * var(--u)) calc(10 * var(--u)); border: 1px solid var(--hair-strong); border-radius: calc(5 * var(--u)); background: var(--surface); font-size: calc(12 * var(--u)); display: grid; gap: calc(3 * var(--u)); }
.pc small { font: 400 calc(9.5 * var(--u))/1 var(--mono); color: var(--mute); }
.pc.dim { color: var(--mute); border-color: var(--hair); }
.pc.mine { border-color: var(--ink); transition: opacity var(--t3) var(--ease) calc(var(--beat) * 5), transform var(--t3) var(--ease) calc(var(--beat) * 5); }

/* The start pose. Only when JS runs and motion is allowed; .played (set once, never removed) lets the transitions
   above carry each part to its end pose. Without .played and without JS, every diagram shows its end pose. */
.js:not(.calm) .dg:not(.played) .wires path { stroke-dashoffset: 1; }
.js:not(.calm) .dg:not(.played) .chip,
.js:not(.calm) .dg-agent:not(.played) > .cv > .card,
.js:not(.calm) .dg:not(.played) .node { opacity: 0; transform: translateY(calc(var(--rise) * .6)); }
.js:not(.calm) .dg:not(.played) .row em,
.js:not(.calm) .dg:not(.played) .node em,
.js:not(.calm) .dg:not(.played) .kpis p,
.js:not(.calm) .dg:not(.played) .attn p { opacity: 0; }
.js:not(.calm) .dg:not(.played) .ln.bad em { background: transparent; color: var(--mute); border-color: var(--hair-strong); }
.js:not(.calm) .dg:not(.played) .area .wipe { transform: none; }
.js:not(.calm) .dg:not(.played) .merged { opacity: 0; transform: scale(.97); }
.js:not(.calm) .dg:not(.played) .pc.mine { opacity: 0; transform: translateY(calc(-40 * var(--u))); }
/* The duplicates are the start pose; once played (or under calm, or with no JS) they have merged away. */
.dg-data.played .dup, html:not(.js) .dup, .calm .dup { opacity: 0; transform: translateX(calc(var(--to) * var(--u))) scale(.94); }

/* ---------- 5. case studies: a manual carousel (R9) ----------
   A native horizontal scroller with scroll snap. Each slide is 82% of the panel so the next one peeks in. */
.car-list { display: flex; gap: 24px; margin: 0; padding: 0; list-style: none; overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth; scrollbar-width: none; overscroll-behavior-x: contain; }
.car-list::-webkit-scrollbar { display: none; }
.calm .car-list { scroll-behavior: auto; }
/* position: relative keeps anything absolutely placed inside a slide (the screen-reader rating text) inside the
   scroller, so an off-screen slide can never widen the page. */
.slide { position: relative; flex: 0 0 82%; scroll-snap-align: start; display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: 36px; padding: 24px;
  border: 1px solid var(--hair-strong); border-radius: 8px; background: var(--surface); }
/* The image slot: a framed area waiting for a real photo or a redacted screenshot. No fake picture. */
.shot { position: relative; aspect-ratio: 4 / 3; display: grid; place-content: center; gap: 8px; text-align: center; border: 1px solid var(--hair); border-radius: 6px; background: var(--paper); }
.shot span { font: 500 12px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--mute); }
.shot small { font: 400 11px/1 var(--mono); color: var(--faint); }
/* When the client's image has loaded (shared.js adds .has-img), it fills the frame and the placeholder text goes. */
.shot { overflow: hidden; }
.shot img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.shot.has-img span, .shot.has-img small { visibility: hidden; }
/* Each photo's focus point, so the crop keeps the subject (the booth; the people at their desks). */
.shot[data-img="photobooth"] img { object-position: 30% 60%; }
.shot[data-img="venturesatl"] img { object-position: 50% 60%; }
.facts dd b { font-weight: 500; }
/* One line per project inside "What we built" (the Photo Booth slide holds two projects). */
.facts .bl { display: block; }
.facts .bl + .bl { margin-top: 6px; }
.noquote { margin: 0; }
.slide-t { display: flex; flex-direction: column; min-width: 0; padding: 4px 0; }
/* The rating slot: deliberately an obvious placeholder until a real rating exists. */
.rating { margin: 0 0 14px; display: flex; align-items: center; gap: 8px; }
/* Five filled stars in ink (never orange: orange as a small mark on paper fails contrast), then the score in mono. */
.stars { display: inline-flex; gap: 2px; }
.stars svg { width: 12px; height: 12px; fill: var(--ink); }
.score { font: 500 12px/1 var(--mono); color: var(--ink); letter-spacing: .02em; }
.slide h3 { font-weight: 450; font-size: clamp(24px, 2.3vw, 30px); letter-spacing: -.02em; font-variation-settings: "opsz" 60, "wdth" 94; }
.what { margin: 6px 0 0; color: var(--mute); font-size: 15.5px; }
.status { display: inline-block; margin-left: 8px; padding: 3px 7px; border: 1px solid var(--hair-strong); border-radius: 4px; font: 400 10.5px/1 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--ink); vertical-align: 2px; }
.facts { margin: 18px 0 0; }
.facts div { padding: 12px 0; border-top: 1px solid var(--hair); }
.facts dt { font: 500 10.5px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--mute); margin-bottom: 6px; }
.facts dd { margin: 0; font-size: 15.5px; line-height: 1.45; }
.slide-q { margin: 4px 0 0; padding: 12px 0 0; border-top: 1px solid var(--hair); font-size: 18px; line-height: 1.35; letter-spacing: -.01em; font-weight: 450; }
.slide-q cite { display: block; margin-top: 6px; font: 400 11px/1 var(--mono); font-style: normal; letter-spacing: .1em; text-transform: uppercase; color: var(--mute); }
.readmore { margin-top: auto; padding-top: 18px; display: inline-flex; align-items: center; gap: 8px; align-self: flex-start; font-weight: 500; font-size: 15px; }
.readmore svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; transition: transform var(--t1) var(--ease); }
.readmore { border-bottom: 1px solid var(--hair-strong); padding-bottom: 2px; }
@media (hover: hover) { .readmore:hover svg { transform: translateX(3px); } }
.car-nav { display: flex; justify-content: flex-end; align-items: center; gap: 20px; margin-top: 20px; }
/* Where you are: three short bars, the current one in ink, the others hairline. Each is a button (a 44px tall hit
   area around a 3px bar) that jumps to its slide. The count itself is announced only to screen readers. */
.car-dots { display: flex; gap: 6px; }
.car-dots button { width: 28px; height: 44px; padding: 0; background: transparent; border: 0; cursor: pointer; display: grid; place-items: center; }
.car-dots button::before { content: ""; width: 100%; height: 3px; border-radius: 2px; background: var(--hair-strong); transition: background-color var(--t1) var(--ease); }
.car-dots button[aria-current="true"]::before { background: var(--ink); }
@media (hover: hover) { .car-dots button:hover::before { background: var(--mute); } .car-dots button[aria-current="true"]:hover::before { background: var(--ink); } }
.car-btns { display: flex; gap: 8px; }
.car-btns button { width: 44px; height: 44px; display: grid; place-items: center; padding: 0; background: transparent; color: var(--ink); border: 1px solid var(--hair-strong); border-radius: 6px; cursor: pointer; transition: border-color var(--t1) var(--ease), opacity var(--t1) var(--ease); }
.car-btns button:hover:not(:disabled) { border-color: var(--ink); }
.car-btns button:disabled { opacity: .35; cursor: default; }
.car-btns svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- 6. how we work: the process track ----------
   Five stages on one track (Teegan 2026-10-17: the UI fragments were too cluttered, so they are gone). Two options,
   chosen by ?how=a|b in the address bar (default a); h27/home.js puts "how-a" or "how-b" on .procw, and the rules below
   show only that option's parts. The words (.ps h3 and p) are shared.
   One timing idea for both: --seg is the time the line takes to travel from one stage to the next. Stage i starts at
   i x --seg, so everything arrives in order, in about 3s, then holds. All on the one easing curve. */
.procw { position: relative; --seg: calc(var(--beat) * 1.5); }
.proc { --frag-h: 72px; --node: 11px; --track-y: calc(var(--frag-h) + 28px + var(--node) / 2);
  list-style: none; margin: 16px 0 0; padding: 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 32px; }
.ps { position: relative; display: flex; flex-direction: column; min-width: 0;
  transition: opacity var(--t3) var(--ease) calc(var(--seg) * var(--i)), transform var(--t3) var(--ease) calc(var(--seg) * var(--i)); }
.ps h3 { display: flex; align-items: baseline; gap: 10px; margin-top: 18px; font-size: 17px; font-weight: 500; }
.ps > p { margin: 6px 0 0; color: var(--mute); font-size: 14.5px; line-height: 1.45; max-width: 24ch; }

/* ----- option a: five line glyphs -----
   Every glyph is 72px, drawn with the same 1.25px stroke: ink for the main shape, one warm grey for the quiet one.
   The node (a small ring) sits on the line under each glyph and fills with ink when the line arrives. */
.gl { display: block; width: 72px; height: 72px; color: var(--ink); overflow: visible; }
.gl .d, .gl .g { stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; transition: stroke-dashoffset var(--t-step) var(--ease) calc(var(--seg) * var(--i) + var(--beat) * .5); }
.gl .d { stroke: var(--ink); }
.gl .g { stroke: var(--faint); }
.gl .dot { transition: opacity var(--t2) var(--ease) calc(var(--seg) * var(--i) + var(--beat) * 2); }
.pn { position: relative; display: block; width: var(--node); height: var(--node); margin-top: 28px; border-radius: 50%; border: 1px solid var(--ink); background: var(--ink); z-index: 1;
  transition: background-color var(--t2) var(--ease) calc(var(--seg) * var(--i) + var(--beat) * .5); }
/* the connector to the next stage: from this node's centre to the next node's centre (stage width + gap) */
.ps:not(:last-child)::after { content: ""; position: absolute; left: calc(var(--node) / 2); width: calc(100% + 32px); height: 1px; background: var(--ink); top: var(--track-y);
  transform-origin: 0 50%; transition: transform var(--seg) var(--ease) calc(var(--seg) * var(--i) + var(--beat) * .5); }
/* The last stage (Support) gets a line too, running from its node to the end of its column, so it sits on the track
   like the other four instead of the line stopping dead at its dot (Teegan, 2026-10-17). Desktop only: on phones the
   track runs down the side and the last node is its natural end. */
@media (min-width: 861px) {
  .how-a .ps:last-child::after { content: ""; position: absolute; left: calc(var(--node) / 2); width: calc(100% - var(--node) / 2); height: 1px;
    background: var(--ink); top: var(--track-y); transform-origin: 0 50%; transition: transform var(--seg) var(--ease) calc(var(--seg) * var(--i) + var(--beat) * .5); }
}
/* start pose: stages a little low and clear, glyph strokes undrawn, connectors undrawn, nodes empty rings */
.js:not(.calm) .proc:not(.played) .ps { opacity: 0; transform: translateY(var(--rise)); }
.js:not(.calm) .proc:not(.played) .ps::after { transform: scaleX(0); }
.js:not(.calm) .proc:not(.played) .pn { background: var(--paper); }
.js:not(.calm) .proc:not(.played) .ps:first-child { opacity: .001; }
.js:not(.calm) .proc:not(.played) .gl .d, .js:not(.calm) .proc:not(.played) .gl .g { stroke-dasharray: 1; stroke-dashoffset: 1; }
.js:not(.calm) .proc:not(.played) .gl .dot { opacity: 0; }
.proc.played .gl .d, .proc.played .gl .g { stroke-dasharray: 1; stroke-dashoffset: 0; }

/* ----- option b: numbers on one track, one line that starts loose and ends straight -----
   No glyphs, no nodes, no connectors. The number (from the node's data-n) is big mono text sitting on the hairline,
   with a paper background so the line passes behind it. The drawn line (.trk .draw) goes from a scribble to straight. */
.how-b .gl, .how-b .ps::after, .how-b .idx { display: none; }
.how-a .trk { display: none; }
.how-b .pn { width: auto; height: 40px; margin: 0; border: 0; border-radius: 0; background: var(--paper); align-self: flex-start; padding-right: 14px;
  font: 400 28px/40px var(--mono); letter-spacing: -.02em; color: var(--ink); font-variant-numeric: tabular-nums;
  transition: color var(--t2) var(--ease) calc(var(--seg) * var(--i)); }
.how-b .pn::before { content: attr(data-n); }
.how-b .ps h3 { margin-top: 14px; }
.how-b .trk { position: absolute; left: 0; top: 0; pointer-events: none; overflow: visible; }
.how-b .trk-h { width: 100%; height: 40px; }
.how-b .trk-v { display: none; }
.trk path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.trk .base { stroke: var(--hair-strong); stroke-width: 1; }
.trk .draw { stroke: var(--ink); stroke-width: 1.25; stroke-dasharray: 1; stroke-dashoffset: 0; }
.js:not(.calm) .proc:not(.played) ~ .trk .draw { stroke-dashoffset: 1; }
.proc.played ~ .trk .draw { transition: stroke-dashoffset calc(var(--seg) * 5) linear; }   /* linear: a constant pace, so number i is reached at i x --seg */
.js:not(.calm) .how-b .proc:not(.played) .pn { color: var(--faint); }
/* in b the stage fade is only the words; the numbers stay put */
.js:not(.calm) .how-b .proc:not(.played) .ps { transform: none; }

/* ---------- 7. questions: four open pairs, no accordion ----------
   Heading in the left third, a 2 x 2 grid of questions on the right. No rules between rows: the space between pairs
   does the separating (48px across, 40px down), which is what removes the "stack of folders" look. */
.faqgrid { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: 48px; }
.qa { margin: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px 48px; }
.qa dt { font-size: 18px; font-weight: 500; line-height: 1.3; letter-spacing: -.01em; }
.qa dd { margin: 10px 0 0; color: var(--mute); font-size: 16px; line-height: 1.55; max-width: 44ch; }

/* ---------- 8. book a call: the closing band ----------
   Two columns on the same 12-column split as the hero: the statement takes 7, the action takes 5. align-items: end
   puts the pill on the same baseline as the agenda row, so the eye ends on the button. Extra padding (on top of the
   section's own 48px) gives the last band more air than the sections above it: it is the page's final beat. */
.book { padding-top: calc(var(--pad) + 24px); padding-bottom: calc(var(--pad) + 32px); }
.close { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 72px; align-items: end; }
/* The statement is bigger than the other h2s (closer to the hero's h1), the one place below the hero that is. */
.book h2 { max-width: 14ch; font-size: clamp(38px, 4.6vw, 64px); line-height: 1.02; letter-spacing: -.035em; }
/* The agenda: one row of three, separated by space only. Each point is a mono number above a short phrase. */
.agenda { list-style: none; margin: 40px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 14px 40px; }
.agenda li { display: grid; gap: 8px; font-size: 16px; line-height: 1.3; }
.close-r { display: grid; justify-items: start; gap: 0; }
/* Who you talk to: two overlapping circles (the second slides 12px under the first's edge), then one caption. */
.who { display: flex; align-items: center; gap: 16px; margin-bottom: 32px; }
.faces { list-style: none; margin: 0; padding: 0; display: flex; flex: none; }
.faces li + li { margin-left: -12px; }
/* Monogram slot until real photos exist: initials in mono on the one surface tone. The paper-coloured ring keeps the
   overlap readable (the second circle looks tucked behind the first, not drawn over it). */
.face { width: 52px; height: 52px; display: grid; place-items: center; border-radius: 50%; background: var(--surface);
  box-shadow: 0 0 0 1px var(--hair-strong), 0 0 0 4px var(--paper); font: 500 13px/1 var(--mono); letter-spacing: .04em; color: var(--mute); }
.who p { margin: 0; max-width: 30ch; color: var(--mute); font-size: 15px; line-height: 1.45; }
.who b { display: block; font-weight: 500; color: var(--ink); }
/* The button is the focus of the band: the same orange pill, larger (about 58px tall). */
.pill-lg { gap: 12px; font-size: 18px; padding: 18px 28px 18px 32px; }
.pill-lg:hover { gap: 16px; }
.book-fine { margin: 14px 0 0; font: 400 12px/1.5 var(--mono); color: var(--mute); letter-spacing: .01em; }

/* ---------- 9. footer: minimal ----------
   A hairline, then: the mark and four links on one row; the legal paragraph and the copyright on the next.
   Last, a big faint wordmark cut off by the bottom edge of the page (decoration, 7% ink). */
.foot { border-top: 1px solid var(--hair); padding-top: var(--pad); overflow: hidden; }
.foot-top { display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
/* The same lockup as the header: the F glyph, one gap, the word. */
.foot-mark { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; font-size: 20px; letter-spacing: -.03em; }
.foot-mark .glyph { height: 20px; }
.foot-nav { display: flex; flex-wrap: wrap; gap: 8px 32px; font-size: 14.5px; }
.foot-nav a { color: var(--mute); transition: color var(--t1) var(--ease); }
.foot-nav a:hover { color: var(--ink); }
.foot-meta { margin-top: 40px; display: flex; justify-content: space-between; align-items: baseline; gap: 16px 48px; }
.foot-meta p { margin: 0; font: 400 11.5px/1.6 var(--mono); color: var(--mute); letter-spacing: .01em; }
.foot-legal { max-width: 108ch; }
.foot-copy { flex: none; }
/* The wordmark spans the 1200px panel exactly. Measured: at this weight and width the word is 2.7 times as wide as
   its font size, so font-size = panel width / 2.7. --wm is that size; on narrow screens the panel is the window
   minus the gutters. The box is shorter than the letters (.6 of the size), so the page edge crops the bottom of the
   word: it reads as a signature, not a heading. Decoration only: 7% ink, aria-hidden, not selectable. */
.foot-wm { --wm: min(calc((100vw - 2 * var(--gut)) / 2.7), 444px); max-width: 1264px; margin: 48px auto 0; padding: 0 var(--gut);
  height: calc(var(--wm) * .6); overflow: hidden; }
.foot-wm span { display: block; margin-left: -.035em; font-family: var(--display); font-weight: 450; font-variation-settings: "opsz" 96, "wdth" 92;
  font-size: var(--wm); line-height: .8; letter-spacing: -.045em; white-space: nowrap;
  color: color-mix(in srgb, var(--ink) 7%, var(--paper)); user-select: none; }

/* ---------- case page footer host (h27-case.html still uses h24/footers.css's .ft classes) ---------- */
footer#footer { display: block; }
.ft-wrap { max-width: 1264px; }   /* the same 1200px panel as the page */
.ft-mark { display: inline-flex; align-items: center; gap: 10px; }
.ft-mark .glyph { height: 20px; }
.ft-meta { border-bottom: 0; }
/* The two legal lines, together in one paragraph: the trademark sentence, then the partner sentence. */
.ft-legal { margin: 0; padding: 0 0 22px; max-width: 110ch; font: 400 11.5px/1.5 var(--mono); color: var(--mute); letter-spacing: .01em; }

/* DRAFT outlines, only with ?review=1. A solid thin outline (not dashed, not orange) and a tiny tag. */
.review [data-draft] { position: relative; outline: 1px solid rgba(60, 90, 255, .55); outline-offset: 2px; }
.review [data-draft]::after { content: "DRAFT " attr(data-draft); position: absolute; right: 0; top: -9px; z-index: 5; max-width: 60ch; padding: 2px 5px;
  font: 500 9px/1.2 var(--mono); letter-spacing: .04em; color: #fff; background: rgba(60, 90, 255, .9); border-radius: 2px; pointer-events: none; text-transform: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---------- tablet ---------- */
@media (max-width: 1100px) {
  .story.sticky { gap: 48px; }
  .slide { flex-basis: 88%; }
  .proc { gap: 20px; }
  .ps:not(:last-child)::after { width: calc(100% + 20px); }
}

/* ---------- phone ---------- */
@media (max-width: 860px) {
  :root { --gut: 20px; --pad: 40px; --nav-h: 60px; }
  .nav nav { display: none; }
  .navin { justify-content: space-between; }
  .mark { margin-right: auto; }
  .glyph { height: 18px; }
  .herogrid { gap: 0; }
  .copy { padding-bottom: 8px; }
  h1 { font-size: 38px; }
  .sub { font-size: 16px; max-width: 34ch; margin-top: 16px; }
  .ctas { margin-top: 20px; }
  .herofig { margin-top: 28px; justify-content: stretch; }
  .head { grid-template-columns: minmax(0, 1fr); gap: 20px; margin-bottom: 28px; }
  .head h2 { max-width: none; }

  .proof { padding: 56px 0 64px; }
  .logos { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px 24px; }
  .logos li:nth-child(1) img { --h: 16px; }
  .logos li:nth-child(2) img { --h: 30px; }
  .logos li:nth-child(3) img { --h: 26px; }
  .logos li:nth-child(4) img { --h: 25px; }
  .proof-cap { margin-bottom: 24px; }

  .mq { gap: 20px; }
  .tl { font-size: 15px; }

  /* the story is always the stack on a phone: text, then its diagram */
  .step { grid-template-columns: minmax(0, 1fr); gap: 22px; padding: 32px 0; }
  .also { flex-direction: column; gap: 8px; }

  .slide { flex-basis: 88%; grid-template-columns: minmax(0, 1fr); gap: 18px; padding: 16px; }
  .facts dd { font-size: 15px; }

  /* process: the line runs down the left. Option a: glyph (56px) | node | words. Option b: number on the line | words. */
  .proc { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .ps { display: grid; grid-template-columns: 56px var(--node) minmax(0, 1fr); column-gap: 16px; padding-bottom: 32px; }
  .ps .gl { grid-column: 1; grid-row: 1 / span 3; width: 56px; height: 56px; }
  .ps .pn { grid-column: 2; grid-row: 1; margin-top: 2px; }
  .ps h3, .ps > p { grid-column: 3; }
  .ps h3 { margin-top: 0; grid-row: 1; }
  .ps > p { grid-row: 2; }
  .ps:not(:last-child)::after { left: calc(56px + 16px + var(--node) / 2); top: 13px; width: 1px; height: 100%; transform-origin: 50% 0; }
  .js:not(.calm) .proc:not(.played) .ps::after { transform: scaleY(0); }
  .how-b .ps { grid-template-columns: 44px minmax(0, 1fr); column-gap: 18px; }
  .how-b .pn { grid-column: 1; grid-row: 1 / span 2; align-self: start; width: 44px; padding: 0; font-size: 22px; line-height: 28px; height: 28px; margin-top: 0; text-align: center; }
  .how-b .ps h3, .how-b .ps > p { grid-column: 2; }
  .how-b .ps h3 { margin-top: 2px; }
  .how-b .trk-h { display: none; }
  .how-b .trk-v { display: block; left: 2px; top: 16px; width: 40px; height: calc(100% - 16px); }
  .js:not(.calm) .proc:not(.played) ~ .trk .draw { stroke-dashoffset: 1; }

  /* questions: one column; the bottom: everything stacks, the agenda becomes a short list */
  .qgrid, .faqgrid, .close { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .qa { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .book { padding-top: calc(var(--pad) + 16px); padding-bottom: calc(var(--pad) + 16px); }
  .close { gap: 40px; }
  .agenda { flex-direction: column; margin-top: 28px; gap: 14px; }
  .agenda li { display: flex; align-items: baseline; gap: 0; }
  .agenda .idx { flex: none; width: 34px; }
  .who { margin-bottom: 24px; }
  /* footer: the links go under the mark, the copyright under the legal paragraph */
  .foot-top { flex-direction: column; align-items: flex-start; gap: 20px; }
  .foot-nav { display: grid; grid-template-columns: repeat(2, max-content); gap: 12px 40px; }
  .foot-meta { flex-direction: column; margin-top: 28px; gap: 10px; }
  .foot-wm { margin-top: 28px; }
}

/* Calendly pop-up (h27/booking.js): no page scroll behind it, and its overlay sits above the sticky header. */
html.cal-open, html.cal-open body { overflow: hidden; }
.calendly-overlay { z-index: 1000 !important; }
/* On phones Calendly's pop-up stops at a fixed 700px, leaving a strip of page showing under it.
   Let it run from just under its close button to the bottom of the screen instead. */
@media (max-width: 649px) {
  html body .calendly-overlay .calendly-popup { top: 56px !important; bottom: 0 !important; height: auto !important; max-height: calc(100% - 56px) !important; }
}

/* Partner photos (2026-10-17): the same round 52px faces, now real photos, cropped to fill the circle. */
img.face { display: block; object-fit: cover; object-position: 50% 30%; padding: 0; }
