/* ═══════════════════════════════════════════════════════════
   Totem — totemcollective.org
   Shared stylesheet.

   Rules of the house:
   · The hotbar is pink, and so is every section kicker. Everything
     else is white with THIN black text.
   · The important bits — in-sentence emphasis — are BOLD BLUE, in the
     same font.
   · Montserrat throughout. One family, three jobs:
       350/400  body copy — the default, deliberately light
       600      headings
       700      the blue emphasis

   Why pink and blue do different jobs: blue is reserved for words
   emphasised INSIDE a sentence — if the accent colour were also the
   hotbar colour, every bolded word would compete with the nav for the
   eye. Pink is the section label above the sentence, not a word
   inside it, so it doesn't compete the same way; it reads closer to
   the hotbar's own job of orienting you, not persuading you.

   HISTORY: this flipped twice. Originally kickers were `--pink-deep`.
   Commit 1c15762 (2026-10-07) moved them to `--blue` on the theory
   that pink should mean ONLY the hotbar, the LIVE dot and error
   states (signalling a state, not emphasising a word) — the brain
   progress-meter lower on this file was the one deliberate exception
   carved out of that rule. Stan reverted it back to pink site-wide on
   2026-10-12: tried it scoped to one kicker first, decided he liked
   it everywhere, not as a one-off. `.head .kicker { color: var(--pink-deep); }`
   below is where that lives now — if kickers ever need to go back to
   blue, that's the one line to change.
   ═══════════════════════════════════════════════════════════ */

/* Montserrat used to load via @import right here. Moved to a <link
   rel="stylesheet"> in every page's <head> (2026-10-05) — an @import inside
   a CSS file is fetched only after the browser has downloaded and started
   parsing style.css itself, so the font request was serialised behind this
   whole file instead of racing it. The <link preconnect>s to
   fonts.googleapis.com/fonts.gstatic.com were already in every head for
   this exact import; now there's a matching <link rel="stylesheet"> next to
   them so the font request fires in parallel with style.css, not after it. */

:root {
  /* the hotbar — the only pink in the building */
  --pink:        #ff2e9f;
  --pink-deep:   #e0007c;

  /* the emphasis — bold blue, same font, nothing decorative uses it.
     #1d4ed8 was already in this file as the hero blob gradient, so
     the page was already half this colour before a single word got
     emphasised. 7.0:1 on white, which clears WCAG AA for body text,
     so a blue-bolded sentence is readable and not just visible. */
  --blue:        #1d4ed8;
  --blue-deep:   #1536a8;
  --blue-tint:   rgba(29, 78, 216, 0.055);

  /* home page */
  --white:       #ffffff;
  --ink:         #0b0b12;
  --ink-2:       #55555f;
  /* was #8b8b96 — measured ~3.4:1 against white, below the 4.5:1 WCAG AA
     floor for normal text. #72727c keeps the same cool-gray hue (B channel
     still a touch higher than R/G) at ~4.76:1. Changed once here rather
     than per usage since every var(--ink-3) reference (~16 of them, incl.
     .fine, .hb-menu .d, sub-label captions, placeholder text) inherits it. */
  /* #6d6d77, not #72727c. Measured 2026-10-18: #72727c on --wash (#f6f6f9) is
     4.41:1 — it misses the 4.5:1 AA minimum by 0.09, which is why it read as
     "nearly fine" everywhere it appears. This colour is used for kickers, fine
     print and footers on every page, so the small miss was site-wide. #6d6d77
     is 4.75:1 on the wash and 5.12:1 on white, and is not distinguishable from
     the old value by eye. */
  --ink-3:       #6d6d77;
  --line:        #e5e5ec;
  --wash:        #f6f6f9;

  --radius: 14px;
  --max: 1180px;
}

*, *::before, *::after { box-sizing: border-box; }

/* ADDED 2026-10-05. Before this, the only focus style anywhere on the site
   was .sub-form input:focus below — every nav link, the Groups dropdown
   trigger, every .btn/.btn-line/.btn.pulse CTA, the burger menu button, and
   the card-links on Find Us/Services had no visible focus state at all, so
   a keyboard-only visitor tabbing through the page couldn't see where they
   were. :focus-visible (not :focus) so this only shows for keyboard/
   switch-device focus, not for a mouse click landing on a button — browsers
   already do that distinction for us.
   .sub-form input keeps its own nicer ring (border + box-shadow) — that rule
   sets outline: none with higher specificity than this one, so the two don't
   stack. */
:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
  border-radius: 2px;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* ADDED 2026-10-04. The hotbar is `position: sticky; top: 0` and 66px tall,
   so until now every in-page anchor jump scrolled the target to y=0 and
   straight underneath it — you clicked "Newsletter" and landed on the body
   copy with the heading and the ask hidden behind the pink bar. That hit
   #newsletter hardest, which is both the declared top of the funnel and the
   anchor linked from four other pages, so the one destination that most
   needed to look deliberate was the one that looked broken.

   86px = the 66px bar plus 20px of air, so the heading clears it instead of
   touching it. Applied to [id] rather than to a list of named anchors on
   purpose: any section that gets an id later is a link target sooner or
   later, and this way nobody has to remember to add it. */
[id] { scroll-margin-top: 86px; }

body {
  margin: 0;
  font-family: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  /* 400, down from 500. Montserrat 300 at 17px is genuinely too light
     to read on a white background at arm's length on a phone, so the
     "thin" is 400 for running copy and 350 reserved for the big ledes
     where the size carries it. Thin that can't be read isn't thin,
     it's broken. */
  font-weight: 400;
  font-size: 17px;
  line-height: 1.6;
  background: var(--white);
  color: var(--ink);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { max-width: 100%; display: block; }
a { color: inherit; }
::selection { background: var(--pink); color: #fff; }

/* ═══ THE EMPHASIS ═════════════════════════════════════════
   Bold blue, same family, same size. This is the one lever for
   "this bit matters" and it works on <strong>, <b>, or .hot in
   the middle of any sentence on any page.

   Deliberately NOT a highlighter, a box, or a different font:
   the weight and the colour change together on the same glyphs,
   so a skim reads the blue words as a sentence of their own. Put
   four of these in one paragraph and that stops being true — so
   the rule is one per paragraph, two if the paragraph is long.
   ═════════════════════════════════════════════════════════ */

strong, b, .hot {
  font-weight: 700;
  color: var(--blue);
  letter-spacing: -0.01em;
}

/* Three places where blue is the wrong colour and bold alone does the
   job: the dark callout panel and the pink bar, where blue doesn't read
   against the background at all; and an error message, where a blue
   phrase in the middle of a pink warning looks like a link and gets
   clicked. In all three, emphasis inherits and stays bold.
   (A fourth selector, .film-cue, was removed 2026-10-06 along with the
   click-to-play cue itself — see the FILM section comment in index.html.) */
.callout strong, .callout b, .callout .hot,
.hotbar strong, .hotbar b, .hotbar .hot,
.sub-msg.bad strong, .sub-msg.bad b, .sub-msg.bad .hot {
  color: inherit;
}

/* Removed 2026-10-04: `.hot-line`, a block-level version of the emphasis
   above. No page ever used it. Same sweep took out `.grid-2` and
   `.price .big` further down — all three were written for layouts that got
   cut, and dead rules in a file this long cost more in reading time than
   they ever would have in bytes. Noted rather than silently deleted so
   nobody re-adds them thinking they were lost by accident.

   `.stats.mid` looked dead on the same pass and isn't — index.html uses it
   as `class="stats pair mid"`, which a grep for `stats mid` misses. Left
   alone. Worth remembering before the next cleanup: search the individual
   class, not the pair. */

/* Visible to screen readers, invisible on screen. Used where a drawing
   carries real words — the #stage scene on index.html is aria-hidden
   because read aloud it's a list of empty divs, but the six lines of
   question-and-answer inside it are genuine copy.

   Clip-rect rather than `display:none` or `visibility:hidden`, both of
   which remove the text from the accessibility tree too and would defeat
   the point. 1px box with everything clipped away is the long-standing
   way to keep it readable by assistive tech and not by eyes. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ═══ HOTBAR PAGES ═════════════════════════════════════════
   Same white/black as home. The hotbar is the only colour.
   ═════════════════════════════════════════════════════════ */

/* ═══ type ═════════════════════════════════════════════════ */

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
  /* HEADING COLOUR — third pass, 2026-10-19, Stan's words: "revert all the
     blue headers back to black."

     The sequence, so nobody re-litigates it from scratch: every heading went
     --pink (2026-10-19 early), then the big statements went --blue as a
     correction, and now they are --ink. Blue is still the site's emphasis
     colour, but only inside body copy — bolded phrases keep it, headings
     don't. What he calls a header is the small caps label above the heading
     (.kicker, .doc-eyebrow) and the card titles (h3), and those stay pink.

     --ink at 44-66px is 19.61:1 on white and 18.18:1 on --wash, the two
     backgrounds these headlines actually sit on — the strongest text on the
     page either way, so hierarchy now comes from size and weight, not colour.
     (Measured, not estimated: WCAG relative-luminance formula, same one
     tools/site-audit.mjs uses for the --ink-3 and hotbar checks.)
     --pink-deep, not --pink, on the labels: #e0007c measures 4.71:1 on white
     and #ff2e9f only 3.42:1, which fails 4.5:1 at 13px.
     Nothing else in this file should set a heading colour. */
  color: var(--ink);
}

h3, h4 { color: var(--pink-deep); }

h1 { font-size: clamp(38px, 5.6vw, 66px); }
h2 { font-size: clamp(28px, 3.6vw, 44px); }
h3 { font-size: 20px; letter-spacing: -0.02em; line-height: 1.3; }

p { margin: 0; font-weight: 400; }

/* 350 rather than 400: a lede is 18.5px and short, so it can take the
   extra lightness that running copy can't, and the drop in weight is
   what separates it from the paragraphs under it without needing a
   second colour. */
.lede {
  font-size: 18.5px;
  line-height: 1.6;
  font-weight: 350;
  color: var(--ink-2);
  max-width: 60ch;
}

.kicker {
  display: inline-block;
  /* Bumped 2026-10-12 per Stan: "make the headers thicker, not bigger (just
     a little bigger)" — weight 600→700 for the actual thickness he asked
     for, size only nudged 12px→13px rather than scaled up, so it reads
     heavier without turning into a bigger label. */
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* The header, as opposed to the subheader under it — pink per Stan
     2026-10-19. #e0007c is 4.71:1 on white, 4.36:1 on --wash. */
  color: var(--pink-deep);
  margin-bottom: 18px;
}

/* ═══ shell ════════════════════════════════════════════════ */

.shell {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 36px;
  position: relative;
  z-index: 2;
}

section { padding: 104px 0; position: relative; z-index: 2; }

.hr { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* ═══ hero ═════════════════════════════════════════════════ */

.hero-wrap {
  position: relative;
  overflow: hidden;
  background: var(--wash);
  border-bottom: 1px solid var(--line);
}

.hero {
  padding: clamp(76px, 11vw, 140px) 36px clamp(72px, 10vw, 128px);
  max-width: 980px;
  margin: 0 auto;
}

.hero h1 { max-width: 17ch; }
.hero .lede { max-width: 60ch; }

/* Centred hero. h1 goes wider than the left-aligned 17ch because a
   centred headline wants to break into balanced lines, not a column. */
.hero.mid { text-align: center; }
.hero.mid h1 {
  max-width: 20ch;
  margin: 0 auto;
  line-height: 1.0;
  letter-spacing: -0.035em;
}

.hero.mid .lede { max-width: 54ch; }

/* RESTORED 2026-10-12 per Stan ("put totem back at the top") — same rules
   that existed 2026-10-06 to 2026-10-07 before the friend-feedback revert
   cut them. h1 is two stacked pieces again: "Totem" is the headline a cold
   visitor needs first, "face the music." is the brand's sign-off underneath
   it, not the opening line. font-size/weight live on these spans rather
   than on h1 itself so each can be sized independently. */
.h1-brand {
  display: block;
  font-size: clamp(44px, 7.4vw, 88px);
  font-weight: 800;
  letter-spacing: -0.035em;
}
.h1-tagline {
  display: block;
  margin-top: 10px;
  font-size: clamp(20px, 3vw, 30px);
  font-weight: 600;
  color: var(--ink);
  opacity: 0.72;
  letter-spacing: -0.01em;
}

/* .film-cap ("Watch first: 90 seconds" label above the hero video) removed
   2026-10-12 per Stan, off a screenshot with it highlighted — no caption
   needed above the video frame. Rule dropped since index.html no longer
   references the class; pull from git history around this commit if it's
   ever wanted back. */

/* ═══ topics marquee ══════════════════════════════════════════════════════
   One line, slow, infinite. .topics clips the overflow; .topics-track holds
   two identical copies of the list side by side and slides left exactly
   -50% of its own width, so the moment the first copy has scrolled fully
   out of view the second is sitting exactly where the first started —
   invisible seam, true loop, no JS needed to reset anything.
   ═══════════════════════════════════════════════════════════════════════ */
.topics {
  overflow: hidden;
  max-width: 720px;
  margin: 26px auto 0;
  /* Fade the two edges so items don't look chopped off mid-word. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}

.topics-track {
  display: flex;
  gap: 10px;
  width: max-content;
  animation: topics-scroll 28s linear infinite;
}

.topics-list {
  display: flex;
  align-items: center;
  gap: 10px;
  list-style: none;
  margin: 0;
  padding: 0;
  white-space: nowrap;
}

.topics-list li {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-3);
  background: var(--wash);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 14px;
}

@keyframes topics-scroll {
  to { transform: translateX(-50%); }
}

/* The "flying mark" (#what) — logo artwork swinging on a trailing pill
   banner — lived here from the 2026-10-07 revision until 2026-10-12, when
   Stan killed it ("the fuck is this floating thing") after seeing it sit
   static and unexplained in a screenshot. Markup removed from index.html's
   #what section in the same change; pull from git history around commit
   1c15762 if it's ever wanted back, rather than rebuilding from scratch. */
.hero.mid .btns { justify-content: center; }

@media (max-width: 800px) {
  .hero { padding-left: 22px; padding-right: 22px; }
}

/* ═══ THE HOTBAR ═══════════════════════════════════════════ */

.hotbar {
  position: sticky;
  top: 0;
  z-index: 200;
  /* --pink-deep, not --pink. Measured 2026-10-18: white nav text on #ff2e9f
     is 3.42:1 — below the 4.5:1 AA minimum for 16px text, and this bar is on
     every page carrying seven links. #e0007c is 4.71:1. It was already in the
     palette (kickers and links have used --pink-deep for a while); the bar
     was the one surface still on the bright pink. --pink stays for decoration
     (selection, the live dot, fills and strokes) where there is no text on it. */
  background: var(--pink-deep);
  color: #fff;
}

.hotbar-in {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 36px;
  height: 66px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.hb-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  margin-right: 26px;
  flex-shrink: 0;
}

.hb-brand img {
  width: 26px;
  height: 26px;
  border-radius: 6px;
  background: #fff;
}

.hb-brand span {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.035em;
  color: #fff;
}

.hb-nav {
  display: flex;
  align-items: center;
  gap: 4px;
}

.hb-nav > a,
.hb-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  font-size: 14.5px;
  font-weight: 500;
  color: #fff;
  background: none;
  border: 0;
  cursor: pointer;
  text-decoration: none;
  padding: 8px 13px;
  border-radius: 8px;
  white-space: nowrap;
  transition: background .16s;
}

.hb-nav > a:hover,
.hb-trigger:hover,
.hb-nav > a.here {
  background: rgba(255,255,255,0.18);
}

.hb-trigger .chev {
  width: 7px;
  height: 7px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
  transition: transform .2s;
}

.hb-group[data-open="true"] .hb-trigger { background: rgba(255,255,255,0.18); }
.hb-group[data-open="true"] .chev { transform: rotate(-135deg) translateY(-2px); }

/* dropdown */
.hb-group { position: relative; }

.hb-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 268px;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 18px 44px rgba(11,11,18,0.22);
  padding: 7px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity .16s, transform .16s, visibility .16s;
}

.hb-group[data-open="true"] .hb-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.hb-menu a {
  display: block;
  padding: 11px 13px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--ink);
  transition: background .14s;
}

.hb-menu a:hover { background: var(--wash); }

.hb-menu .t { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.hb-menu .d { font-size: 12.5px; font-weight: 400; color: var(--ink-3); line-height: 1.4; }

.hb-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }

/* .hb-cta ("Join free") and .hb-cta-line ("Newsletter") removed 2026-10-12
   per Stan: Newsletter moved into .hb-nav as a plain link, Join free
   dropped entirely — .hb-right is now just the burger button's wrapper.
   Pull from git history around this commit if either is ever wanted back. */

/* ADDED 2026-10-12 per Stan, direct ask ahead of filming the Analytics VSL:
   "Sign in" on the far right of the pink hotbar, every page, linking straight
   into the Totem Analytics dashboard on the main networkio app (separate
   domain — see lib/adminGate.ts there for who's actually allowed in once
   they authenticate). White pill against the pink hotbar so it reads as
   its own action, not a nav link. */
.hb-signin {
  display: inline-flex;
  align-items: center;
  /* 44px minimum. At 390px wide this pill measured 37px tall — under the
     WCAG 2.5.5 / Apple 44px target, and it is the one control in the hotbar a
     phone visitor actually has to hit. Measured on 2026-10-19 in a 390x844
     viewport, then padded to the floor rather than resized: the look is
     unchanged, only the hit area. */
  min-height: 44px;
  background: #fff;
  color: var(--pink-deep);
  font-weight: 700;
  font-size: 13px;
  padding: 8px 16px;
  border-radius: 8px;
  text-decoration: none;
  white-space: nowrap;
  transition: opacity 0.15s;
}

.hb-signin:hover { opacity: 0.85; }

.hb-burger {
  display: none;
  background: none;
  border: 0;
  color: #fff;
  cursor: pointer;
  /* Same 44px floor as .hb-signin — this one measured 34x38 on a 390px
     viewport. It is the only way into the nav on a phone. */
  min-width: 44px;
  min-height: 44px;
  padding: 9px;
  border-radius: 8px;
}

.hb-burger span {
  display: block;
  width: 20px;
  height: 2px;
  background: #fff;
  border-radius: 2px;
}

.hb-burger span + span { margin-top: 5px; }

/* ═══ dynamic shapes ═══════════════════════════════════════ */

.shapes {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(62px);
  opacity: 0.5;
  will-change: transform;
}

.blob.a {
  width: 520px; height: 520px;
  top: -190px; right: -130px;
  background: radial-gradient(circle at 30% 30%, rgba(29,78,216,0.32), transparent 70%);
  animation: drift-a 24s ease-in-out infinite;
}

.blob.b {
  width: 430px; height: 430px;
  bottom: -180px; left: -120px;
  background: radial-gradient(circle at 60% 40%, rgba(11,11,18,0.13), transparent 70%);
  animation: drift-b 30s ease-in-out infinite;
}

/* Hero cursor glow (2026-10-27, Stan: "some fancy mouse tracking
   animation"). A soft pink-into-blue light that eases after the pointer
   while it's over the hero, and fades out when it leaves. Sits in .shapes
   with the blobs, so it's behind the copy and never catches a click.
   Position is written by site.js as a transform each frame; it starts at
   opacity 0 and only .glow-on (also site.js, mouse/trackpad only) shows it,
   so touch screens and reduced-motion visitors never see it at all. */
.cursor-glow {
  position: absolute;
  left: 0; top: 0;
  width: 560px; height: 560px;
  margin: -280px 0 0 -280px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,46,159,0.20) 0%, rgba(29,78,216,0.12) 40%, transparent 68%);
  filter: blur(28px);
  opacity: 0;
  transition: opacity 0.6s ease;
  will-change: transform;
}
.hero-wrap.glow-on .cursor-glow { opacity: 1; }

@keyframes drift-a {
  0%,100% { transform: translate(0,0) scale(1); }
  33%     { transform: translate(-70px, 58px) scale(1.12); }
  66%     { transform: translate(46px, -34px) scale(0.94); }
}

@keyframes drift-b {
  0%,100% { transform: translate(0,0) scale(1); }
  50%     { transform: translate(84px, -60px) scale(1.15); }
}

/* rotating outlined ring */
.ring {
  position: absolute;
  border-radius: 50%;
  border: 1.5px dashed var(--line);
  opacity: 0.85;
  animation: spin 46s linear infinite;
}

.ring.r1 { width: 300px; height: 300px; top: 10%;  right: 5%; }
.ring.r2 { width: 170px; height: 170px; bottom: 12%; left: 6%; animation-duration: 33s; animation-direction: reverse; }

@keyframes spin { to { transform: rotate(360deg); } }

/* floating square */
.sq {
  position: absolute;
  width: 74px; height: 74px;
  border: 2px solid var(--line);
  border-radius: 16px;
  animation: bob 11s ease-in-out infinite;
}

.sq.s1 { top: 22%; left: 7%; transform: rotate(14deg); }
.sq.s2 { bottom: 20%; right: 9%; width: 48px; height: 48px; border-radius: 12px; animation-delay: -4s; }

@keyframes bob {
  0%,100% { transform: translateY(0) rotate(14deg); }
  50%     { transform: translateY(-26px) rotate(-8deg); }
}

/* ═══ manifesto (overview page) ════════════════════════════ */

/* .manifesto-row/.manifesto-mark (flex row + small totem mark in the blank
   right column) removed 2026-10-06 per Stan. The 26ch cap on .manifesto
   below is gone with it — that cap only existed to leave room for the mark,
   so the text now runs the full column width instead. */

.manifesto .m-line,
.manifesto .m-ask,
.manifesto .m-punch {
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.08;
  margin: 0 0 34px;
}

.m-line  { font-size: clamp(26px, 3.4vw, 42px); }
.m-ask   { font-size: clamp(32px, 4.4vw, 54px); color: var(--ink); }

.manifesto .m-body {
  max-width: 62ch;
  font-size: clamp(16.5px, 1.5vw, 19px);
  font-weight: 400;
  line-height: 1.68;
  color: var(--ink-2);
  margin: 0 0 26px;
}

.manifesto .m-punch {
  font-size: clamp(30px, 4vw, 50px);
  margin: 46px 0 0;
  padding-top: 40px;
  border-top: 1.5px solid var(--line);
  max-width: 20ch;
}

/* ═══ film ═════════════════════════════════════════════════ */

.film-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--ink);
  border: 1.5px solid var(--line);
  box-shadow: 0 18px 50px rgba(11,11,18,0.14);
}

.film-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* .film-cue (the click-to-play overlay button) and its related rules —
   .film-cue-play, .film-cue-text, the hover/mobile overrides — removed
   2026-10-06. The video now autoplays muted on scroll-in instead of
   waiting for a click (see the FILM section comment in index.html for
   why), so there's nothing left for a cue to sit on top of. */

/* ═══ buttons ══════════════════════════════════════════════ */

.btn {
  display: inline-block;
  background: var(--ink);
  color: #fff;
  text-decoration: none;
  font-size: 15.5px;
  font-weight: 600;
  padding: 14px 28px;
  border-radius: 11px;
  transition: transform .16s, box-shadow .16s;
}

.btn:hover { transform: translateY(-2px); box-shadow: 0 10px 26px rgba(11,11,18,0.2); }

.btn-line {
  display: inline-block;
  text-decoration: none;
  font-size: 15.5px;
  font-weight: 600;
  padding: 14px 26px;
  border: 2px solid var(--line);
  border-radius: 11px;
  transition: border-color .16s, transform .16s;
}

.btn-line:hover { border-color: var(--ink); transform: translateY(-2px); }

.btns { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }

/* ═══ motion — the live pill, the sheen, the pulse ═════════
   Three animations, all deliberately slow. "Flashing" that
   literally flashes is a photosensitivity hazard, so nothing
   in here cycles faster than once every ~2.4s and nothing
   ever fully blanks — it reads as a shimmer, not a strobe.
   The prefers-reduced-motion block at the foot of this file
   already kills every animation on the site, so all three
   switch themselves off for anyone who's asked for that.
   ═══════════════════════════════════════════════════════ */

/* 1 — live pill. Only the halo moves. The dot and the text
   stay put, because anything changing size next to text
   nudges the text and makes the whole pill look unstable. */
.live {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 7px 16px 7px 13px;
  margin-bottom: 20px;
  background: #fff;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.live-dot {
  position: relative;
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--pink);
}

.live-dot::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  background: var(--pink);
  animation: halo 2.4s ease-out infinite;
}

/* Next live call strip in the homepage hero (2026-10-27). */
.next-call-wrap { margin-top: 30px; display: flex; justify-content: center; }
.next-call {
  display: inline-flex; align-items: center; justify-content: center; flex-wrap: wrap;
  gap: 8px 12px; padding: 11px 20px 11px 16px; max-width: 100%;
  background: #fff; border: 1.5px solid var(--line); border-radius: 999px;
  text-decoration: none; color: var(--ink); font-size: 14.5px;
  box-shadow: 0 10px 26px -18px rgba(11, 11, 18, 0.35);
  transition: border-color 0.2s ease, transform 0.2s ease;
}
.next-call[hidden] { display: none; }
.next-call:hover { border-color: var(--pink); transform: translateY(-1px); }
.next-call .nc-label { font-size: 11.5px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--pink-deep); }
.next-call .nc-title { font-weight: 700; }
.next-call .nc-when { color: var(--ink-2); }
.next-call .nc-go { color: var(--blue); font-weight: 700; }
@media (max-width: 640px) {
  .next-call { border-radius: 18px; padding: 12px 16px; font-size: 14px; }
}

@keyframes halo {
  0%        { transform: scale(0.55); opacity: 0.5; }
  70%, 100% { transform: scale(2.2);  opacity: 0; }
}

/* 2 — sheen across a headline word: a moving gradient clipped
   to the glyphs. `color` is set underneath the clip so that a
   browser without background-clip:text falls back to solid
   ink rather than rendering the word invisible. */
.shine {
  color: var(--ink);
  background-image: linear-gradient(
    100deg,
    var(--ink) 0%,   var(--ink) 38%,
    var(--blue) 47%, var(--blue-deep) 53%,
    var(--ink) 62%,  var(--ink) 100%
  );
  background-size: 300% 100%;
  /* repeat, NOT no-repeat. The sweep below runs the 3x-wide gradient from
     165% to -65%, and at both ends a no-repeat image sits entirely off the
     glyphs — background-clip:text then clips nothing, and the brand word is
     literally invisible for roughly the first and last 0.3s of every 4.6s
     loop. Caught on 2026-10-19 in a screenshot of the hero taken at the wrong
     moment. Tiling fixes it with no visible seam because the gradient starts
     and ends on the same --ink. */
  background-repeat: repeat;
  -webkit-background-clip: text;
  background-clip: text;
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .shine {
    -webkit-text-fill-color: transparent;
    animation: sweep 4.6s linear infinite;
  }
}

@keyframes sweep {
  0%   { background-position: 165% 0; }
  100% { background-position: -65% 0; }
}

/* 3 — breathing ring on a primary CTA. Box-shadow only, so it
   can never shift layout or sit over the label. */
.btn.pulse { animation: breathe 2.8s ease-in-out infinite; }

@keyframes breathe {
  0%, 100% { box-shadow: 0 0 0 0   rgba(29, 78, 216, 0); }
  50%      { box-shadow: 0 0 0 9px rgba(29, 78, 216, 0.16); }
}

/* Cursor intent beats ambient motion — kill the pulse on hover
   so the lift reads as a response to the user, not more idle.
   Same on a disabled button: the signup button disables itself
   while the request is in flight, and a thing that still pulses
   invitingly while refusing to be clicked is just a lie. */
.btn.pulse:hover,
.btn.pulse[disabled] { animation: none; }

/* ═══ cards ════════════════════════════════════════════════ */

/* Most cards on this site are themselves links — a whole clickable panel,
   not a panel with a link inside it. Without this they inherit the default
   underline and the entire card renders underlined, heading and body both.
   index.html was patching that with an inline style="text-decoration:none"
   on each of its three cards; find-us.html has six and patched none, so
   that page was shipping six fully underlined panels. Fixing it here means
   the markup doesn't have to remember. */
.card, a.card { text-decoration: none; color: inherit; display: block; }

.card {
  background: #fff;
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  padding: 30px;
  transition: transform .18s, box-shadow .18s, border-color .18s;
}

.card:hover {
  transform: translateY(-4px);
  border-color: var(--ink);
  box-shadow: 0 14px 34px rgba(11,11,18,0.09);
}

.card h3 { margin-bottom: 9px; }
.card p { font-size: 15.5px; color: var(--ink-2); }

/* ADDED 2026-10-07 — a one-line "who this is / start here" steer on each
   group card, see the comment above #groups in index.html. */
.card-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: var(--wash);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 11px;
  margin-bottom: 14px;
}

.card-badge.start { color: var(--blue); border-color: var(--blue); background: var(--blue-tint); }

.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }

/* ═══ stats ════════════════════════════════════════════════ */

.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}

/* Two numbers instead of four. A 2-stat row stretched across the full 1180px
   reads as a page with something missing, so it's capped and left-aligned
   rather than spread. */
.stats.pair { grid-template-columns: repeat(2, 1fr); max-width: 660px; }
.stats.pair.mid { max-width: 420px; margin-left: auto; margin-right: auto; }

.stat {
  border-top: 3px solid var(--ink);
  padding-top: 18px;
}

.stat .n {
  font-size: 42px;
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
  margin-bottom: 7px;
  font-variant-numeric: tabular-nums;
}

.stat .l { font-size: 13.5px; font-weight: 500; color: var(--ink-2); line-height: 1.45; }

/* Centred variant. No top rule and the number carries the accent —
   a rule above every stat fights the centring, and once there are
   only a few numbers the rules read as a table nobody asked for. */
.stats.mid { text-align: center; }
.stats.mid .stat { border-top: 0; padding-top: 0; }
.stats.mid .stat .n { color: var(--blue); font-size: clamp(30px, 3.4vw, 40px); }
.stats.mid .stat .l {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ═══ dynamic hero widget — live Discord presence ═══════════════════════
   ADDED 2026-10-05 per Stan. Reuses the .live pill's shape (pill, border,
   uppercase label) rather than inventing a second visual language for "a
   small live indicator". Starts [hidden] in markup and is only revealed by
   JS once real data is in hand (see the <script> block near the newsletter
   form) — this stylesheet never has to guess what "no data yet" looks like
   because that state is simply not rendered.

   Had a sibling here, .next-call (+ .nc-dot) — a countdown to the next
   guest call, shown to every visitor. REMOVED 2026-10-05 per Stan: that's
   meant to be a newsletter-signup perk, not free on the public page. Markup
   and the fetch that fed it came out of index.html in the same change;
   deleting these rules alongside it rather than leaving unreferenced CSS
   behind. The halo animation .nc-dot used to borrow from .live-dot is
   unaffected — other callers remain. */
.discord-live {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 18px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* Overlapping avatar stack. Negative margin on every avatar but the first
   is what creates the overlap; the white border is what keeps overlapping
   circles from just reading as one blob of mixed pixels. No z-index needed
   — default paint order (later DOM element on top) already gives the usual
   "stack of faces" look every avatar-cluster UI uses. */
.dl-avatars { display: flex; }
.dl-avatars img {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2px solid #fff;
  background: var(--line);
  object-fit: cover;
}
.dl-avatars img:not(:first-child) { margin-left: -9px; }

/* .discord-live sets its own `display`, which has the same specificity as
   the UA `[hidden] { display: none }` rule — so without this, the moment
   that class applied it would win the tie and the element would render
   even while still `hidden`. Same fix the old `.film-cue[hidden]` rule
   used before the click-to-play cue was removed (2026-10-06). */
.discord-live[hidden] { display: none; }

/* ═══ section heading ══════════════════════════════════════ */

.head { max-width: 62ch; margin-bottom: 48px; }
.head h2 { margin-bottom: 16px; }

/* Centred heading. The wrapper's cap is in px on purpose: `ch` here would
   resolve against the WRAPPER's font-size (16px), not the 62px headline
   inside it, so 20ch would be ~160px and shred the headline into one word
   per line. The line-length cap belongs on the h2, where `ch` measures the
   font it's actually setting. */
.head.mid {
  max-width: 820px;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

/* 17ch of the headline's own font — enough to break a big display line into
   two or three stacked lines, which is most of what makes the look, without
   turning a smaller h2 into a column. */
.head.mid h2 { max-width: 17ch; margin-left: auto; margin-right: auto; }

.head.mid .lede { max-width: 54ch; margin-left: auto; margin-right: auto; }
/* Pink kicker on every heading, centred or not — it's the brand accent, and
   restricting it to the centred ones made the left-aligned sections look
   unfinished rather than deliberately quieter.

   RE-FLIPPED TO PINK 2026-10-12 per Stan: tried pulling just the #problem
   kicker left and pink (see index.html / git history around that date for
   the one-off version), he liked the colour but not the position — "move
   it back, keep the text pink, do that with every header." So this reverts
   the blue-ification from commit 1c15762 (2026-10-07) and puts every kicker
   on the page back to --pink-deep, site-wide, not scoped to one section.
   Net effect on the "Rules of the house" note at the top of this file:
   pink is no longer JUST the hotbar/live-dot/error-state/brain-meter — it's
   now also every section kicker. That header comment block is updated to
   match; don't let the two drift. */
.head .kicker { color: var(--pink-deep); }

/* Display headline: bigger and tighter than a normal h2. Reserved for
   the two or three moments on the page that are meant to stop someone
   scrolling — use it everywhere and it stops meaning anything. */
.h-display {
  font-size: clamp(34px, 5.2vw, 62px);
  line-height: 1.0;
  letter-spacing: -0.035em;
  font-weight: 700;
  /* Not an h1-h4 tag, but it is the same thing a subheader is — the open
     statement under a .kicker — so it takes the same --ink as h1/h2. It kept
     --blue from the 2026-10-19-morning pass and had to follow them back to
     black the same day, or six headlines on index.html and analytics.html
     would have been the only blue ones left on the site. See the heading
     comment near the top of the type block for the full sequence. */
  color: var(--ink);
}

/* ═══ chatwall — the two threads, played out ═══════════════
   Replaced a static comparison table (`.ledger`) that said "most
   groups are a feed of dropped links, Totem is people in a room".
   True, and it asked to be believed. This shows it instead: two
   real threads running side by side, eight messages each, one pair
   at a time.

   The structural decision carried over from the old table and it's
   the one that matters: the two sides are paired by ROW, not by
   pane. "gm" sits on the same line as the question that replaces
   it. Build this as two independently scrolling chat columns and
   the comparison — the entire point — is left to the reader to
   guess at.

   Rows are visible by default and hidden only once JS adds
   `.cw-live`. No JS, or reduced motion, and the whole thing renders
   as a plain sixteen-message comparison: less good, still honest,
   never blank.
   ═══════════════════════════════════════════════════════ */

.chatwall {
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  overflow: hidden;
  margin-bottom: 38px;
}

.cw-head {
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: var(--wash);
  border-bottom: 1.5px solid var(--line);
}

.cw-head > * {
  padding: 14px 24px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* The right half is the whole point of the panel, so it carries the
   accent and a faint tint the full height — including the header —
   rather than a border that would read as a second, separate card. */
.cw-head > :last-child,
.cw-row > :last-child {
  border-left: 1.5px solid var(--line);
  background: var(--blue-tint);
}

.cw-head > :last-child { color: var(--blue); }

/* Fixed-height window. The feed is taller than this once it fills,
   and JS scrolls it — which is what makes it read as a live thread
   rather than a list that happens to fade in. */
/* DO NOT put a mask-image on this element to soften the top edge. It
   was tried on 2026-10-04 and rendered the entire panel blank: a
   composited, smooth-scrolled container plus a mask drops the layer.
   A bubble clipped by the top border is how every chat embed behaves
   and reads as scroll, not as breakage. */
.cw-view {
  height: 400px;
  overflow: hidden;
  position: relative;
}

/* Breathing room so the very first message isn't welded to the border
   before any scrolling has happened. */
.cw-feed { padding: 10px 0 14px; }

.cw-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: start;
}

/* ADDED 2026-10-07 per feedback: the bubbles sat edge-to-edge with nothing
   but their own padding between one message and the next, which read as
   cramped next to everything else on the page. A touch of vertical
   breathing room between rows — not inside .msg itself, which would also
   widen the bubble's own padding and change its shape. */
.cw-row + .cw-row > * { padding-top: 16px; }

.cw-row > * {
  padding: 8px 22px;
  min-height: 1px;
}

.cw-live .cw-row {
  opacity: 0;
  transform: translateY(12px);
}

.cw-live .cw-row.on {
  opacity: 1;
  transform: none;
  transition: opacity 0.42s ease, transform 0.42s cubic-bezier(0.2, 0.9, 0.25, 1);
}

/* The reply lands a beat after the message it answers. Without the
   stagger both halves pop together and it reads as a table row. */
.cw-live .cw-row.on > :last-child { transition-delay: 0.22s; }

/* block + fit-content rather than inline-block, so `.me` can push
   itself right with margin-left:auto. The alternative was a :has()
   rule on the parent cell, which is one more thing to break on an
   older Safari for no gain. */
.msg {
  display: block;
  width: fit-content;
  max-width: 94%;
  padding: 9px 14px;
  border-radius: 14px;
  font-size: 14.5px;
  line-height: 1.4;
  font-weight: 400;
}

.msg .who {
  display: block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 3px;
  color: var(--ink-3);
}

.msg.cold {
  background: var(--wash);
  border: 1px solid var(--line);
  border-top-left-radius: 5px;
  color: var(--ink-2);
}

/* Not a message — a thing that happened instead of one. Dashed and
   label-styled so it can't be mistaken for someone talking. */
.msg.cold.dead {
  background: none;
  border: 1px dashed var(--line);
  border-radius: 14px;
  color: var(--ink-3);
  font-style: italic;
  font-size: 13px;
}

.msg.warm {
  background: #fff;
  border: 1.5px solid var(--line);
  border-top-left-radius: 5px;
  color: var(--ink);
  font-weight: 500;
}

/* The visitor's own messages. Blue because that's this site's rule
   for the bit that matters, and pushed right because that is the
   one visual cue that says "chat" without a single decoration. */
.msg.warm.me {
  margin-left: auto;
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
  border-top-left-radius: 14px;
  border-bottom-right-radius: 5px;
}

.msg.warm.me .who { color: rgba(255, 255, 255, 0.72); }

.result {
  text-align: center;
  font-size: clamp(18px, 2.3vw, 25px);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.35;
}

.result b { color: var(--blue); font-weight: 700; }

/* ═══ scene — the stage, the room, and the brain ═══════════
   Everything here is divs and one inline SVG. No image, no canvas,
   no animation library. That's not minimalism for its own sake: an
   illustration of a room full of people is the single easiest thing
   on a site like this to make look like stock art, and stock art of
   a networking event is the exact impression the whole page is
   arguing against.

   Scale is the argument. The whiteboard is the biggest object in the
   frame — bigger than the speaker — because that's what a room looks
   like from row three, and because a page whose point is "you get an
   answer" should not be dominated by a hero figure.

   The brain on the right is a progress meter, not decoration. It
   grows one notch per answered question, so by the time the loop
   restarts the reader has watched the thing they're being sold
   actually accumulate. It's the one pink object in the section;
   pink is otherwise reserved sitewide for the hotbar and the live
   dot, and this is a deliberate exception.

   FAILSAFE: the finished state is the DEFAULT. Questions, replies
   and a full-size brain all render with no JS at all. The sequence
   only hides things once JS sets data-run, and JS refuses to set it
   under prefers-reduced-motion. Break the script and you get a
   static illustration of the same scene, not an empty box.
   ═══════════════════════════════════════════════════════ */

.scene {
  display: grid;
  grid-template-columns: 1fr 190px;
  gap: 22px;
  align-items: stretch;
}

.scene-main {
  position: relative;
  aspect-ratio: 16 / 11;
  background: var(--wash);
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

/* ── the whiteboard: biggest object in the frame ──────── */
.board {
  position: absolute;
  left: 14%;
  top: 6%;
  width: 72%;
  height: 52%;
  background: #fff;
  border: 2.5px solid var(--ink);
  border-radius: 7px;
  box-shadow: 0 14px 30px rgba(11, 11, 18, 0.09);
}

.board-in {
  position: absolute;
  inset: 11% 9%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 11%;
}

/* Marker strokes. Ragged widths on purpose — five bars of equal
   length reads as a loading skeleton, not handwriting. */
.bi {
  display: block;
  height: 5px;
  border-radius: 3px;
  background: var(--ink-3);
  opacity: 0.55;
  transition: width 0.55s cubic-bezier(0.2, 0.9, 0.25, 1);
}

.bi-1 { width: 62%; }
.bi-2 { width: 41%; }
.bi-3 { width: 78%; background: var(--blue); opacity: 0.8; }
.bi-4 { width: 33%; }
.bi-5 { width: 55%; }

/* ── the speaker, standing in front of the board ──────── */
.speaker {
  position: absolute;
  left: 50%;
  bottom: 36%;
  width: 9%;
  transform: translateX(-50%);
  text-align: center;
}

.sp-head {
  display: block;
  width: 56%;
  margin: 0 auto 7%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--ink);
}

.sp-body {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1.25;
  border-radius: 46% 46% 20% 20% / 32% 32% 12% 12%;
  background: var(--ink);
}

/* ── the audience ─────────────────────────────────────── */
/* 9.5% basis + 1.4% gap puts exactly nine per row at every width,
   so rows are deterministically 9 / 9 / 7 and the nth-child rules
   below can address back row and front row by position. Change
   either number and that stops being true. */
.crowd {
  position: absolute;
  left: 4%;
  right: 4%;
  bottom: 3%;
  height: 29%;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-end;
  justify-content: center;
  gap: 2.2% 1.4%;
}

.p {
  position: relative;
  flex: 0 0 9.5%;
  aspect-ratio: 1 / 1.1;
}

.p::before,
.p::after {
  content: "";
  position: absolute;
  background: var(--ink-2);
  left: 50%;
  transform: translateX(-50%);
}

.p::before {
  top: 0;
  width: 48%;
  aspect-ratio: 1;
  border-radius: 50%;
}

.p::after {
  bottom: 0;
  width: 86%;
  height: 52%;
  border-radius: 44% 44% 4px 4px / 60% 60% 4px 4px;
}

/* Depth, cheaply: the back row is smaller and paler, the front row
   is nearer and darker. Three flat rows of identical figures reads
   as a chart. */
.p:nth-child(-n + 9) { opacity: 0.4; transform: scale(0.86); }
.p:nth-child(n + 10):nth-child(-n + 18) { opacity: 0.68; }
.p:nth-child(n + 19) { opacity: 1; transform: scale(1.1); }

/* The three who put a hand up. Blue, and it only lights up on their
   turn — a permanently highlighted asker would just look like a
   legend key. */
.p[data-ask] { transition: opacity 0.3s ease; }
.scene[data-step="1"] .p[data-ask="1"]::before,
.scene[data-step="1"] .p[data-ask="1"]::after,
.scene[data-step="2"] .p[data-ask="2"]::before,
.scene[data-step="2"] .p[data-ask="2"]::after,
.scene[data-step="3"] .p[data-ask="3"]::before,
.scene[data-step="3"] .p[data-ask="3"]::after {
  background: var(--blue);
}

/* ── the questions, fired as arrows ───────────────────── */
.ask {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 3;
}

.ask-text {
  background: var(--blue);
  color: #fff;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.25;
  padding: 7px 11px;
  border-radius: 12px;
  white-space: nowrap;
  box-shadow: 0 6px 16px rgba(29, 78, 216, 0.22);
}

/* The arrow is a 2px rule that grows out of the bubble toward the
   speaker, with a chevron on its tip. Rotation is set per question
   so each one actually points at him rather than off into the wall. */
.ask-arrow {
  position: relative;
  display: block;
  width: 90px;
  height: 2px;
  background: var(--blue);
  transform-origin: left center;
  transition: width 0.5s cubic-bezier(0.2, 0.9, 0.25, 1);
}

.ask-arrow::after {
  content: "";
  position: absolute;
  right: -1px;
  top: 50%;
  width: 8px;
  height: 8px;
  border-top: 2px solid var(--blue);
  border-right: 2px solid var(--blue);
  transform: translateY(-50%) rotate(45deg);
}

/* Each bubble sits over its own asker's row and the arrow is angled to
   land on the SPEAKER, not on whoever happens to be in the way. An
   arrow that stops in the middle of the audience reads as one member
   asking another, which is the exact thing this section exists to say
   doesn't happen here. If you move a bubble, re-aim the rotation. */
.ask[data-step="1"] { left: 2%; bottom: 36%; }
.ask[data-step="1"] .ask-arrow { transform: rotate(-12deg); }

.ask[data-step="2"] { left: 2%; bottom: 24%; }
.ask[data-step="2"] .ask-arrow { transform: rotate(-30deg); }

/* Third asker is stage right, so the whole group mirrors: arrow
   first, bubble second, pointing back in toward the speaker. */
.ask[data-step="3"] { right: 2%; bottom: 36%; flex-direction: row-reverse; }
.ask[data-step="3"] .ask-arrow { transform-origin: right center; transform: rotate(12deg); }
.ask[data-step="3"] .ask-arrow::after {
  right: auto;
  left: -1px;
  border-top: 2px solid var(--blue);
  border-right: 0;
  border-left: 2px solid var(--blue);
  transform: translateY(-50%) rotate(-45deg);
}

/* ── the replies ──────────────────────────────────────── */
.reply {
  position: absolute;
  left: 57%;
  top: 30%;
  max-width: 34%;
  background: #fff;
  border: 1.5px solid var(--ink);
  border-radius: 14px;
  border-bottom-left-radius: 4px;
  padding: 9px 13px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
  box-shadow: 0 8px 20px rgba(11, 11, 18, 0.1);
  z-index: 4;
}

/* Stacked in the same slot when static, so the no-JS render doesn't
   put three bubbles on top of each other. */
.reply[data-step="2"] { top: 47%; }
.reply[data-step="3"] { top: 64%; left: 62%; }

/* ── running state: hide, then reveal step by step ────── */
.scene[data-run] .ask,
.scene[data-run] .reply {
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
}

.scene[data-run] .ask-arrow { width: 0; }
.scene[data-run] .bi { width: 0; }

.scene[data-run] .ask.show,
.scene[data-run] .reply.show {
  opacity: 1;
  transform: none;
  transition: opacity 0.35s ease, transform 0.35s ease;
}

.scene[data-run] .ask.show .ask-arrow { width: 90px; }

/* When the sequence runs, all three replies share one slot — they
   appear one at a time so there's nothing to collide with, and a
   single fixed position stops the reader's eye hunting. */
.scene[data-run] .reply { top: 30%; left: 57%; }

/* The board fills in as the answers land. */
.scene[data-run][data-grown="1"] :is(.bi-1, .bi-2),
.scene[data-run][data-grown="2"] :is(.bi-1, .bi-2, .bi-3, .bi-4),
.scene[data-run][data-grown="3"] :is(.bi-1, .bi-2, .bi-3, .bi-4, .bi-5) {
  width: var(--w);
}

.scene[data-run] .bi-1 { --w: 62%; }
.scene[data-run] .bi-2 { --w: 41%; }
.scene[data-run] .bi-3 { --w: 78%; }
.scene[data-run] .bi-4 { --w: 33%; }
.scene[data-run] .bi-5 { --w: 55%; }

/* ── the brain ────────────────────────────────────────── */
.brainwrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 22px 14px;
  background: #fff;
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
}

.brainsvg {
  width: 100%;
  max-width: 148px;
  overflow: visible;
}

/* Grows from the stem up, which is why the origin is bottom-centre
   of the viewBox and not the middle of it. */
.brain-g {
  transform-origin: 80px 136px;
  transform: scale(1);
  opacity: 1;
  transition: transform 0.75s cubic-bezier(0.2, 0.9, 0.25, 1), opacity 0.75s ease;
}

.lobe {
  fill: var(--pink);
  fill-opacity: 0.13;
  stroke: var(--pink);
  stroke-width: 3.2;
  stroke-linejoin: round;
}

.gyri,
.stem {
  fill: none;
  stroke: var(--pink);
  stroke-width: 2.4;
  stroke-linecap: round;
  opacity: 0.75;
}

.scene[data-run] .brain-g { transform: scale(0.3); opacity: 0.28; }
.scene[data-run][data-grown="1"] .brain-g { transform: scale(0.56); opacity: 0.55; }
.scene[data-run][data-grown="2"] .brain-g { transform: scale(0.78); opacity: 0.8; }
.scene[data-run][data-grown="3"] .brain-g { transform: scale(1); opacity: 1; }

.brain-count {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-3);
  text-align: center;
}

.brain-count b {
  font-size: 22px;
  font-weight: 800;
  color: var(--pink);
  letter-spacing: -0.02em;
}

.brain-label {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-align: center;
}

/* ═══ founder ══════════════════════════════════════════════
   Portrait left, words right. The photo is a phone snap, not a studio
   headshot, and that's the point — it's deliberately not cropped into
   a tidy circular avatar, because a circular avatar is what every
   template does and it would make a real photo look like a stock one.
   ═══════════════════════════════════════════════════════ */

.founder {
  display: grid;
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: 0 44px;
  align-items: center;
  max-width: 880px;
}

.founder-shot {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--wash);
  border: 1.5px solid var(--line);
  /* Fixed ratio so the row height is known before the image loads and
     nothing below it jumps when it does. */
  aspect-ratio: 3 / 4;
}

.founder-shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 28%;
  display: block;
}

.founder-name {
  font-size: clamp(26px, 3vw, 34px);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.1;
  margin-bottom: 4px;
}

.founder-role {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--blue);
  margin-bottom: 18px;
}

.founder p { font-size: 16.5px; line-height: 1.6; color: var(--ink-2); font-weight: 400; }

/* Set by the <img>'s onerror. A missing photo leaves an empty bordered box
   holding a broken-image icon, which reads as a bug; collapsing to one column
   just reads as a section without a photo. */
.founder.no-shot { grid-template-columns: 1fr; }
.founder.no-shot .founder-shot { display: none; }

/* ═══ numbered rows ════════════════════════════════════════ */

.rows { border-top: 1.5px solid var(--line); }

.row-i {
  display: grid;
  grid-template-columns: 56px 220px 1fr;
  gap: 0 28px;
  padding: 26px 0;
  border-bottom: 1.5px solid var(--line);
  align-items: start;
}

/* Some of these lists use sentence-shaped titles ("You turn up when
   someone's on", "You're stuck on something specific") rather than the
   one-word headings the default column was sized for, so this variant
   buys the title column the width it needs instead of wrapping every
   heading onto two lines. Used by the steps list and by the "who it's
   for" list on index.html, which stopped being one-worders when Sales /
   AI / SMMA came off the site. */
.rows.steps .row-i { grid-template-columns: 56px 270px 1fr; }

.row-i .n { font-size: 22px; font-weight: 700; letter-spacing: -0.03em; opacity: 0.32; }
.row-i p { font-size: 15.5px; color: var(--ink-2); }

/* ═══ guest-call block (.pack) ═════════════════════════════ */

.pack {
  background: var(--wash);
  border: 1.5px solid var(--line);
  border-radius: 20px;
  padding: 44px;
}

/* `.price`/`.price .sm` styled the price line services.html used to show
   above the deliverables list. Gone with the figure itself (same sweep as
   the `.tier-price`/`.tier-sub` note that lived on the deleted offer page) —
   no page has rendered `class="price"` since. Noted, not silently deleted:
       .price { display: flex; align-items: baseline; flex-wrap: wrap;
                gap: 14px; padding-bottom: 24px;
                border-bottom: 1.5px solid var(--line); margin-bottom: 8px; }
       .price .sm { font-size: 14.5px; font-weight: 500; color: var(--ink-2); } */

/* FIXED 2026-10-04. Every rule in this block used to be written against
   `.deliv li`, and services.html — the only page that has ever used .deliv —
   builds the list out of `<div>`s with an explicit `<span class="n">`. So
   none of it applied: no number column, no row separators, no padding. The
   deliverables rendered as a stack of nine undifferentiated text blocks,
   which is exactly why a reader couldn't tell which of them mattered.

   Selectors now match the markup that exists. The `.n` span is styled
   directly instead of being generated by a CSS counter, because the numbers
   in the HTML are hand-written and a counter would fight them the moment
   the list is split into two groups that don't restart at 01. */
.deliv > div,
.deliv li {
  list-style: none;
  display: grid;
  grid-template-columns: 46px 1fr;
  gap: 0 16px;
  padding: 20px 0;
  border-bottom: 1.5px solid var(--line);
}

.deliv > div:last-child,
.deliv li:last-child { border-bottom: 0; }

.deliv .n {
  grid-column: 1;
  grid-row: 1;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  opacity: 0.34;
  padding-top: 3px;
}

/* Both of these are pinned to column 2 explicitly. Each row has three
   children and two columns, so auto-placement sends the number to 1/1, the
   heading to 2/1, and then wraps the paragraph back round to 1/2 — the
   46px number column — where it renders one word per line. The old
   `li::before` version had the same three-items-two-columns shape and the
   same bug; it just never ran, because the selector didn't match anything
   in the markup. */
/* h3, not h4. These headings sit directly under the section's <h2> with no
   <h3> between them, which skipped a level in the document outline on
   services.html — the only place on the site that did (checked across all
   nine pages on 2026-10-18). The sibling section on the same page (brands)
   already uses h3 for exactly this role, so the tag now matches the structure
   and the outline heals. Sizes are unchanged; see .deliv.lead h3 below, which
   carries the 19.5px that h4 had.

   (The other sibling named here used to be Totem+, whose section came off
   services.html on 2026-10-19. Comment only — the rule never depended on it.) */
.deliv h3 { grid-column: 2; font-size: 17px; font-weight: 600; margin-bottom: 4px; }
.deliv p { grid-column: 2; font-size: 15px; color: var(--ink-2); }

/* The split. Nine things presented as one flat list asks the reader to rank
   them, and they won't — they'll skim and take nothing. The first three are
   the ones a guest actually turns up for, so they get their own group, more
   room and a heavier line. The other seven are real and stay on the page;
   they just stop competing with the three for the first read. */
.deliv-head {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* A small caps header, same job as .kicker, so it takes the same colour —
     this was the last label still on --blue after the 2026-10-19 split, which
     made one card's header read as a different kind of thing from every other
     header on the site. These sit inside .pack panels (--wash), where
     --pink-deep is 4.36:1 — the same ratio every pink label on a wash panel
     already carries, and the label is 13px/700. */
  color: var(--pink-deep);
  margin: 0 0 4px;
}

/* `.deliv-head.rest`/`.deliv.rest` styled the second, de-emphasised group
   from the split described above — the other seven deliverables, under the
   first three. services.html's markup now only renders the `.deliv.lead`
   group (see the comment at the top of this file's `.deliv` rule for the
   current nine-vs-three state); nothing ever gets a "rest" class, so this
   is dead. Noted rather than deleted since the look is specific and would
   have to be re-derived if the second group ever comes back:
       .deliv-head.rest { color: var(--ink-3); margin-top: 34px;
                           padding-top: 26px; border-top: 1.5px solid var(--line); }
       .deliv.rest h3 { font-size: 16px; }
       .deliv.rest p { font-size: 14.5px; } */

.deliv.lead > div { padding: 24px 0; }
.deliv.lead h3 { font-size: 19.5px; }
.deliv.lead p { font-size: 15.5px; color: var(--ink-2); }
.deliv.lead .n { opacity: 1; color: var(--blue); }

.callout {
  margin-top: 28px;
  padding: 22px 26px;
  background: var(--ink);
  color: #fff;
  border-radius: 14px;
}

.callout .t {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  opacity: 0.6;
  margin-bottom: 7px;
}

.callout p { font-size: 15.5px; color: rgba(255,255,255,0.88); }

.fine { margin-top: 18px; font-size: 12.5px; font-weight: 400; color: var(--ink-3); max-width: 64ch; }
.fine a { text-decoration: underline; }

/* ═══ newsletter signup ════════════════════════════════════ */

.sub-row {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 18px;
  margin-bottom: 22px;
}

.sub-field { display: block; }

.sub-lab {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin-bottom: 8px;
}

/* The "optional" marker has to be visibly quieter than the label itself —
   if it reads at the same weight, people treat the field as required and a
   chunk of them abandon rather than hand over a Discord name. */
.sub-lab em { font-style: normal; text-transform: none; letter-spacing: 0; font-weight: 400; color: var(--ink-3); }

.sub-form input {
  width: 100%;
  font: inherit;
  font-size: 16px;
  font-weight: 400;
  color: var(--ink);
  background: var(--white);
  border: 1.5px solid var(--line);
  border-radius: 10px;
  padding: 13px 15px;
  transition: border-color .15s, box-shadow .15s;
  -webkit-appearance: none;
  appearance: none;
}

.sub-form input::placeholder { color: var(--ink-3); }

.sub-form input:focus {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(11,11,18,0.08);
}

.sub-form button[type="submit"] { border: 0; cursor: pointer; font: inherit; }
.sub-form button[disabled] { opacity: 0.55; cursor: progress; }

/* ── consent ────────────────────────────────────────────────
   The rule above sets width:100% and appearance:none on every input in
   the form, which would stretch the checkbox across the panel and strip
   the tick off it. This claws the native control back — a checkbox that
   doesn't visibly look checked is not evidence of consent.            */
.consent {
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: 0 11px;
  align-items: start;
  margin: 18px 0 20px;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
  color: var(--ink-2);
  cursor: pointer;
}

.consent input[type="checkbox"] {
  width: 18px;
  height: 18px;
  margin: 2px 0 0;
  padding: 0;
  border-radius: 5px;
  -webkit-appearance: auto;
  appearance: auto;
  accent-color: var(--blue);
  cursor: pointer;
  flex: none;
}

.consent a { text-decoration: underline; }

.sub-msg {
  margin-top: 18px;
  padding: 14px 16px;
  border-radius: 10px;
  font-size: 15px;
  font-weight: 500;
  line-height: 1.5;
  border: 1.5px solid var(--line);
  background: var(--white);
}

.sub-msg a { text-decoration: underline; font-weight: 600; }
.sub-msg.good { border-color: var(--ink); }
.sub-msg.bad  { border-color: var(--pink); color: var(--pink-deep); }

/* ═══ faq ══════════════════════════════════════════════════ */

details { border-bottom: 1.5px solid var(--line); }

summary {
  cursor: pointer;
  list-style: none;
  padding: 19px 40px 19px 0;
  font-size: 16.5px;
  font-weight: 600;
  letter-spacing: -0.015em;
  position: relative;
}

summary::-webkit-details-marker { display: none; }

summary::after {
  content: "";
  position: absolute;
  right: 8px;
  top: 28px;
  width: 9px; height: 9px;
  border-right: 2.5px solid currentColor;
  border-bottom: 2.5px solid currentColor;
  opacity: 0.4;
  transform: rotate(45deg);
  transition: transform .2s;
}

details[open] summary::after { transform: rotate(-135deg); top: 32px; }

details .a {
  padding: 0 40px 22px 0;
  font-size: 15.5px;
  font-weight: 400;
  color: var(--ink-2);
  max-width: 70ch;
}

/* ═══ reveal on scroll ═════════════════════════════════════ */

/* Scoped to `.js .rv`, not bare `.rv`, and that prefix is the whole point.
   `.in` is only ever added by site.js, so for as long as the hidden state was
   the CSS default, every page on this site was staking its entire visible
   content on one 4KB file arriving and not throwing. When it didn't, you got a
   blank white page under a pink bar — 57 hidden elements on index.html alone.

   The `js` class is added by a tiny inline script in every <head>, which also
   starts a watchdog that strips the class again if site.js hasn't reported in.
   So the three failure modes all now render a complete page: JS disabled (class
   never added), script blocked or 404 (watchdog fires), script throws before
   the reveal (watchdog fires).

   This also puts the reveal back in line with the house rule the two
   animations already follow: the finished state is the CSS default and JS adds
   the class that hides things, never the other way round. */
.js .rv {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .6s cubic-bezier(.2,.7,.3,1), transform .6s cubic-bezier(.2,.7,.3,1);
}

.js .rv.in { opacity: 1; transform: none; }

/* Dramatic zoom-out on the film video as it scrolls into view. ADDED
   2026-10-06 per Stan ("dramatic zoom out at the start... to engage and
   keep attention"). Follows the exact same house rule as the block above:
   the finished state (scale(1), full frame, nothing cropped) is the CSS
   default, and the zoomed starting state only exists under .js — the class
   the inline <head> guard adds and strips again if site.js never reports
   in. Without that scoping, a visitor whose JS fails would get the iframe
   stuck cropped at 1.35x forever, with nothing left to ever un-scale it —
   the same failure mode the reveal-on-scroll system exists to avoid, just
   on a transform instead of an opacity.

   Targets the iframe, not .film-frame itself: .film-frame already has its
   own .rv slide-up (the block above), and scaling the outer box would also
   scale its border and rounded corners, which looks like the whole card
   growing past its frame rather than the video diving toward the viewer.
   Scaling only the iframe keeps the frame's edge fixed and reads as the
   player itself zooming in on load.

   Piggybacks on .film-frame's own .rv/.in state — same element, same
   IntersectionObserver trigger in site.js — rather than wiring up a second
   observer for one more element. */
.js .film-frame iframe {
  transform: scale(1.35);
  transition: transform 1.7s cubic-bezier(.16,.84,.26,1);
}
.js .film-frame.in iframe { transform: scale(1); }

/* ═══ footer ═══════════════════════════════════════════════ */

.foot {
  border-top: 1.5px solid var(--line);
  padding: 30px 0 46px;
  font-size: 13px;
  font-weight: 400;
  color: var(--ink-3);
  position: relative;
  z-index: 2;
}

.foot-in {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  justify-content: space-between;
}

.foot a:hover { color: var(--ink); }

/* ═══ DOC PAGES — privacy, terms ═══════════════════════════
   These two used to carry their own inline dark theme: #0d0c10
   background, white text, dashed borders. Two consequences, both
   bad. One, a visitor reading the privacy notice got dropped onto
   a page that looks like a different company's, which is exactly
   the wrong moment to look untrustworthy. Two, the palette lived
   in two <style> blocks nobody was going to remember to update,
   so the site had three versions of pink.

   Now they link this file like every other page and only bring
   their own structure. The doc classes below are the structure.
   ═════════════════════════════════════════════════════════ */

.wrapper { max-width: 760px; margin: 0 auto; padding: 0 24px; }

.doc-head {
  padding: 64px 0 34px;
  border-bottom: 1.5px solid var(--line);
  margin-bottom: 44px;
}

.doc-eyebrow {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* The doc pages' equivalent of .kicker — the small caps header above the
     h1. Pink (2026-10-19); the h1 under it sets no color of its own, so it
     inherits the global h1 rule and renders --ink (black), matching every
     other heading on the site after the blue-headings revert. */
  color: var(--pink-deep);
  margin-bottom: 14px;
}

.doc-head h1 {
  font-size: clamp(32px, 5vw, 48px);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.05;
  margin-bottom: 14px;
}

/* The version line is a date, and a date on a legal notice is the
   single most load-bearing fact on the page — it's how a reader
   knows whether what they agreed to is what's written here. So it
   gets the emphasis treatment rather than being grey small print. */
.doc-version { font-size: 14.5px; font-weight: 400; color: var(--ink-2); }
.doc-version b, .doc-version strong { font-weight: 700; color: var(--blue); }

.doc-body { padding-bottom: 96px; }

/* The global `section { padding: 104px 0 }` is right for a landing page where
   each section is a screenful, and completely wrong here, where a "section" is
   clause 4 of a contract. Without this reset every numbered clause sits in 208px
   of whitespace and a ten-clause document becomes a scroll marathon. */
.doc-body section { padding: 0; margin-bottom: 40px; }
/* Privacy notice "In short" box (2026-10-27). */
.doc-summary { border: 1.5px solid var(--line); border-left: 4px solid var(--blue); border-radius: 12px; padding: 20px 24px; margin: 0 0 44px; background: var(--blue-tint); }
.doc-summary h2 { margin: 0 0 10px; font-size: 18px; }
.doc-summary ul { margin: 0; padding-left: 18px; }
.doc-summary li { margin: 6px 0; font-size: 15px; line-height: 1.55; color: var(--ink); }

.doc-body h2 {
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.25;
  margin-bottom: 12px;
  display: flex;
  align-items: baseline;
  gap: 10px;
}

/* The section number is navigation, not content — sections get
   cross-referenced by number all through both documents ("see
   section 7"), so it has to be findable at a glance without
   shouting over the heading it belongs to. Blue does that. */
.doc-body h2 .num {
  font-weight: 700;
  color: var(--blue);
  font-size: 15px;
  flex: none;
}

.doc-body p {
  color: var(--ink-2);
  line-height: 1.72;
  font-size: 16px;
  font-weight: 400;
  margin-bottom: 11px;
  max-width: 68ch;
}

.doc-body ul { list-style: none; margin: 15px 0; padding: 0; }

.doc-body ul li {
  position: relative;
  padding-left: 22px;
  color: var(--ink-2);
  line-height: 1.72;
  font-size: 16px;
  font-weight: 400;
  margin-bottom: 9px;
  max-width: 68ch;
}

.doc-body ul li::before {
  content: "—";
  position: absolute;
  left: 0;
  color: var(--blue);
  font-weight: 700;
}

.doc-body a { color: var(--blue); font-weight: 600; text-decoration: underline; }

.contact-box {
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 24px;
  background: var(--wash);
  margin-top: 10px;
}

.contact-box p { margin-bottom: 0; color: var(--ink); font-weight: 500; }
.contact-box p + p { margin-top: 8px; }

.serial { font-variant-numeric: tabular-nums; letter-spacing: 0.04em; }

/* ═══ QUALIFIER STEPS — the funnel page ════════════════════
   Numbered questions with the answer-shape underneath. This is
   the only place on the site that asks for anything, and it
   deliberately looks like a list of questions rather than a
   form: the actual form lives off-site, and a page that mimics
   one would make people think they'd already applied.
   ═════════════════════════════════════════════════════════ */

.qs { counter-reset: q; border-top: 1.5px solid var(--line); margin-top: 8px; }

.q {
  counter-increment: q;
  display: grid;
  grid-template-columns: 52px 1fr;
  gap: 0 24px;
  padding: 26px 0;
  border-bottom: 1.5px solid var(--line);
  align-items: start;
}

.q::before {
  content: counter(q, decimal-leading-zero);
  font-size: 15px;
  font-weight: 700;
  color: var(--blue);
  padding-top: 4px;
  font-variant-numeric: tabular-nums;
}

.q h3 { margin-bottom: 7px; }
.q p { font-size: 15.5px; color: var(--ink-2); }

/* What a good answer looks like. Shown because the commonest reason
   an application is useless isn't a bad fit, it's a one-word answer
   to a question the reader didn't understand the point of. */
.q .eg {
  margin-top: 10px;
  font-size: 14.5px;
  font-weight: 400;
  color: var(--ink-3);
  padding-left: 14px;
  border-left: 2px solid var(--blue);
}

/* The "no money changes hands here" strip. It is load-bearing: the
   price is on this site, so without it the page reads as a thing
   you buy, and the entire point is that you can't. */
.no-pay {
  margin-top: 34px;
  padding: 20px 24px;
  background: var(--blue-tint);
  border: 1.5px solid rgba(29, 78, 216, 0.18);
  border-radius: var(--radius);
}

.no-pay .t {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--blue);
  margin-bottom: 7px;
}

.no-pay p { font-size: 15.5px; color: var(--ink-2); max-width: 64ch; }

@media (max-width: 800px) {
  .wrapper { padding: 0 20px; }
  .doc-head { padding-top: 46px; }
  .q { grid-template-columns: 1fr; gap: 0; }
  .q::before { display: block; margin-bottom: 8px; }
  .no-pay { padding: 18px 20px; }
}

/* ═══ responsive ═══════════════════════════════════════════ */

@media (max-width: 980px) {
  .grid-3 { grid-template-columns: 1fr 1fr; }
  .stats { grid-template-columns: 1fr 1fr; gap: 26px 20px; }
  .row-i { grid-template-columns: 44px 1fr; }
  /* `.rows.steps .row-i` (0,2,1) out-specifies the `.row-i` rule above
     regardless of source order, so without restating it here the steps keep
     their desktop 56px/270px title column, the `1fr` description column
     resolves to 0px, and all five step descriptions vanish on a phone. */
  .rows.steps .row-i { grid-template-columns: 44px 1fr; }
  .row-i p { grid-column: 2; margin-top: 8px; }
}

@media (max-width: 800px) {
  .shell, .hotbar-in { padding: 0 20px; }
  section { padding: 64px 0; }

  /* 17ch is a sensible cap on a 62px headline and a straitjacket on the
     34px one the clamp lands at down here, so the centred head gives all
     the width back on mobile and lets the viewport do the wrapping. */
  .head.mid,
  .head.mid h2 { max-width: none; }

  /* Two columns of ~160px turns every message into a five-line
     paragraph, so the threads stack. The column headers go with them
     and each bubble grows its own label instead — without that, a
     stacked pair is just sixteen unattributed lines and the whole
     comparison stops meaning anything.

     The handle goes when the column label arrives. Both is three
     lines of metadata on a two-line message, and of the two it's the
     column name that carries the argument. */
  .cw-head { display: none; }
  .cw-view { height: 440px; }
  .cw-row { grid-template-columns: 1fr; }
  .cw-row > * { padding: 10px 20px; }
  .cw-row > :last-child { border-left: 0; }

  .msg { max-width: 100%; }
  .msg .who { display: none; }

  .msg::before {
    content: attr(data-lab);
    display: block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-3);
    margin-bottom: 4px;
  }

  .msg.warm::before { color: var(--blue); }
  .msg.warm.me::before { color: rgba(255, 255, 255, 0.72); }

  /* Stage: the brain moves under the room rather than beside it, and
     goes horizontal so it doesn't eat half a phone screen. */
  .scene { grid-template-columns: 1fr; gap: 14px; }
  .scene-main { aspect-ratio: 4 / 3.4; }
  .brainwrap { flex-direction: row; gap: 18px; padding: 16px 18px; }
  .brainsvg { max-width: 72px; flex: 0 0 72px; }
  .brain-count,
  .brain-label { text-align: left; }

  /* Nowrap question bubbles are what makes the arrow read as aimed;
     at 360px they'd run off both edges instead. */
  .ask-text { white-space: normal; max-width: 40vw; font-size: 11px; }
  .ask-arrow { width: 46px; }
  .scene[data-run] .ask.show .ask-arrow { width: 46px; }
  .reply { font-size: 11px; max-width: 40%; }

  /* Photo over words, and capped — a 3:4 portrait at full phone width
     is most of a screen of face before a single sentence is reached. */
  .founder { grid-template-columns: 1fr; gap: 24px 0; }
  .founder-shot { max-width: 230px; }

  .stats.mid { grid-template-columns: 1fr 1fr; gap: 28px 20px; }

  .hb-nav {
    position: fixed;
    top: 66px; left: 0; right: 0;
    /* Matches .hotbar above — the mobile menu is the same pink slab with the
       same white links, so it fails contrast the same way at the same sizes. */
    background: var(--pink-deep);
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: 12px 16px 20px;
    border-top: 1px solid rgba(255,255,255,0.22);
    display: none;
  }

  .hotbar[data-menu="true"] .hb-nav { display: flex; }

  .hb-nav > a, .hb-trigger { width: 100%; justify-content: space-between; padding: 12px 14px; font-size: 16px; }

  .hb-menu {
    position: static;
    opacity: 1; visibility: visible; transform: none;
    box-shadow: none;
    background: rgba(255,255,255,0.14);
    margin: 4px 0 8px;
    display: none;
  }
  .hb-group[data-open="true"] .hb-menu { display: block; }
  .hb-menu a { color: #fff; }
  .hb-menu a:hover { background: rgba(255,255,255,0.16); }
  .hb-menu .d { color: rgba(255,255,255,0.7); }

  .hb-burger { display: block; }
  .hb-right { gap: 6px; }

  .grid-3 { grid-template-columns: 1fr; }
  .stats.pair { grid-template-columns: 1fr 1fr; }
  .sub-row { grid-template-columns: 1fr; gap: 16px; }
  .sub-form button[type="submit"] { width: 100%; text-align: center; }
  .pack { padding: 26px 22px; border-radius: 16px; }
  .deliv > div, .deliv li { grid-template-columns: 36px 1fr; gap: 0 10px; }
  .deliv.lead h3 { font-size: 18px; }
}

/* The narrowest-phones .hb-cta-line crowding fix that used to live here
   (2026-10-07) is moot 2026-10-12 — Newsletter is a plain .hb-nav link now,
   Join free is gone, so there's nothing left fighting the burger for room
   at ~320px. */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }
  html { scroll-behavior: auto; }
  /* Matches the `.js .rv` specificity above so it still wins by order. A bare
     `.rv` here would lose to it and reduced-motion users would get the hidden
     state with no transition to bring it back — i.e. a blank page. */
  .js .rv { opacity: 1; transform: none; }

  /* The chat and the stage both have a hidden-until-revealed running
     state. JS already refuses to enter it under reduced motion, but
     killing transitions without also forcing the finished state is
     how you ship a permanently blank panel if that check ever
     regresses. Both of these are the no-JS render, pinned. */
  .cw-live .cw-row { opacity: 1 !important; transform: none !important; }
  .cw-view { height: auto !important; }

  .scene[data-run] .ask,
  .scene[data-run] .reply { opacity: 1 !important; transform: none !important; }
  .scene[data-run] .ask-arrow { width: 90px !important; }
  .scene[data-run] .brain-g { transform: scale(1) !important; opacity: 1 !important; }
  .scene[data-run] .reply[data-step="2"] { top: 47%; left: 57%; }
  .scene[data-run] .reply[data-step="3"] { top: 64%; left: 62%; }
  .scene[data-run] .bi-1 { width: 62% !important; }
  .scene[data-run] .bi-2 { width: 41% !important; }
  .scene[data-run] .bi-3 { width: 78% !important; }
  .scene[data-run] .bi-4 { width: 33% !important; }
  .scene[data-run] .bi-5 { width: 55% !important; }
}

/* ═══ guest application form — REMOVED 2026-10-19 ═══════════════════
   The .apply-form/.af-* rules that lived here (added 2026-10-18 alongside
   /api/apply) styled a local application form. That form and apply.html
   were both deleted at 7325d0a ("Take the guest application off the site
   and link out to the form instead") — every guest-apply CTA is now an
   external link, nothing posts to this domain. Confirmed zero HTML
   references to .apply-form/.af-grid/.af-field/.af-hp/.af-status/
   .af-fallback anywhere in the repo before deleting ~127 lines of dead
   CSS. If a local form ever comes back, pull the old rules from git
   history (commit 824ba96) rather than re-authoring them. */

/* ═══ SKIP LINK ═══════════════════════════════════════════
   2026-10-27. First thing a keyboard or screen-reader user reaches on
   every page: jumps past the hotbar to #content, an empty marker placed
   straight after </header>. Off-screen until focused. */
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 1000;
  padding: 10px 16px; border-radius: 10px;
  background: var(--ink, #0b0b12); color: #fff; font-weight: 600; text-decoration: none;
  transition: top .15s ease;
}
.skip-link:focus { top: 12px; }
#content:focus { outline: none; }

/* ═══ SERVICES DROPDOWNS (2026-10-29) ═════════════════════
   services.html: the three ways in (guest speaker, Totem Plus, become a
   client) as <details>. Summary = number, title, one-line description and
   a chevron; the body is the old section's content. */
.svc-wrap { padding-top: 24px; }
.svc {
  border: 1px solid var(--line, rgba(11,11,18,.1));
  border-radius: 18px;
  background: #fff;
  margin-bottom: 16px;
  box-shadow: 0 1px 2px rgba(11,11,18,.04);
  transition: box-shadow .2s ease, border-color .2s ease;
}
.svc, .svc[open] { border-bottom-width: 1px; }
.svc[open] { border-color: rgba(29,78,216,.35); box-shadow: 0 10px 30px rgba(29,78,216,.08); }
.svc > summary {
  list-style: none;
  display: grid; grid-template-columns: auto 1fr auto; gap: 18px; align-items: center;
  padding: 24px 28px; cursor: pointer; border-radius: 18px;
}
.svc > summary::-webkit-details-marker { display: none; }
/* The FAQ chevron (summary::after, above) is global; .svc draws its own. */
.svc > summary::after { content: none; }
.svc > summary:hover { background: rgba(29,78,216,.03); }
.svc > summary:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
.svc-k { font-size: 13px; font-weight: 700; color: var(--blue); font-variant-numeric: tabular-nums; }
.svc-t { font-size: 22px; font-weight: 700; color: var(--ink); line-height: 1.25; }
.svc-s { display: block; margin-top: 4px; font-size: 15px; font-weight: 400; color: var(--ink-2); }
.svc-chev {
  width: 12px; height: 12px; margin-right: 4px;
  border-right: 2px solid var(--ink-2); border-bottom: 2px solid var(--ink-2);
  transform: rotate(45deg); transition: transform .2s ease;
}
.svc[open] .svc-chev { transform: rotate(-135deg); }
.svc-body { padding: 4px 28px 30px; }
.svc-body .head { margin-bottom: 24px; }
.svc-body .lede a, .svc-f p a { color: var(--blue); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }

.svc-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; margin-top: 28px; }
.svc-f { border: 1px solid var(--line, rgba(11,11,18,.1)); border-radius: 14px; padding: 20px; background: #fafafc; }
.svc-f .n { font-size: 12px; font-weight: 700; color: var(--blue); }
.svc-f h3 { font-size: 17px; margin: 8px 0 6px; }
.svc-f p { font-size: 14.5px; color: var(--ink-2); line-height: 1.55; margin: 0; }

.svc-steps { margin-top: 28px; padding: 20px 24px; border-radius: 14px; background: rgba(29,78,216,.055); border-left: 4px solid var(--blue); }
.svc-steps .t { font-weight: 700; margin-bottom: 8px; }
.svc-steps ol { margin: 0; padding-left: 20px; }
.svc-steps li { margin: 6px 0; color: var(--ink-2); }
.svc-steps li b { color: var(--ink); }

.btn.btn-blue { background: var(--blue); }
.btn.btn-blue:hover { background: #1e40af; }

@media (max-width: 900px) { .svc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) {
  .svc > summary { padding: 20px; gap: 12px; }
  .svc-t { font-size: 19px; }
  .svc-body { padding: 0 20px 24px; }
  .svc-grid { grid-template-columns: 1fr; }
}
/* Stan, 2026-10-29: no 01/02/03 numbering inside the services dropdowns. The
   guest block's .deliv grid reserves a column for the number, so collapse it. */
.svc .deliv .n { display: none; }
.svc .deliv > div { grid-template-columns: 1fr; }
.svc .deliv h3, .svc .deliv p { grid-column: 1; }
/* The guest row's old section heading repeats the row's own title once it's open. */
.svc-body .head h2 { display: none; }
.svc-body .head .lede { margin-top: 0; }

/* ═══ FOUNDERS PAGE (2026-10-29) ══════════════════════════
   founders.html. Prefixed .fnd-, not .founder-: index.html's founder
   section already owns .founder with a grid layout. */
/* 2026-10-29, Stan: "very in your face" as three big cards. Now one row per
   founder, smaller photo on the left, words on the right, stacked in order. */
.fnd-grid { display: flex; flex-direction: column; gap: 20px; max-width: 860px; margin: 8px 0 80px; }
.fnd {
  display: grid; grid-template-columns: 180px 1fr; gap: 28px; align-items: center;
  background: #fff; border: 1px solid var(--line); border-radius: 18px; padding: 18px;
}
.fnd-photo {
  position: relative; aspect-ratio: 1 / 1; border-radius: 14px; overflow: hidden;
  background: linear-gradient(135deg, #e8eefc, #f6e8f3);
  display: grid; place-items: center;
}
.fnd-photo::before { content: attr(data-initials); font-size: 36px; font-weight: 700; color: var(--blue); opacity: .55; }
.fnd-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.fnd h2 { font-size: 22px; margin: 0 0 8px; }
.fnd-bio { color: var(--ink-2); font-size: 15.5px; line-height: 1.6; margin: 0; }
@media (max-width: 600px) {
  .fnd { grid-template-columns: 96px 1fr; gap: 16px; align-items: start; padding: 14px; }
  .fnd h2 { font-size: 19px; }
  .fnd-bio { font-size: 14.5px; }
}
.fnd-cta { max-width: 860px; margin: -40px 0 90px; padding: 28px; border-radius: 18px; background: rgba(29,78,216,.055); border-left: 4px solid var(--blue); }
.fnd-cta h2 { font-size: 24px; margin: 0 0 6px; }
.fnd-cta p { color: var(--ink-2); margin: 0; }
.svc-for { margin: 18px 0 0; color: var(--ink-2); font-size: 15.5px; max-width: 760px; }
.svc-for b { color: var(--ink); }
.svc-promise { margin-top: 20px; padding: 16px 20px; border: 1px dashed rgba(29,78,216,.4); border-radius: 14px; color: var(--ink-2); font-size: 15px; line-height: 1.6; }
.svc-promise b { color: var(--ink); }
.svc-stats { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 12px; margin-top: 22px; }
.svc-stats > div { border: 1px solid var(--line); border-radius: 14px; padding: 16px 18px; background: #fafafc; }
.svc-stats b { display: block; font-size: 22px; color: var(--blue); letter-spacing: -0.02em; }
.svc-stats span { display: block; margin-top: 2px; font-size: 13.5px; color: var(--ink-2); }
@media (max-width: 600px) { .svc-stats { grid-template-columns: 1fr; } }

/* ═══ POLISH PASS (2026-10-29) ═══════════════════════════════
   Stan: "make it look like it was built by Opus 5.5". One layer, appended
   last so every rule above still reads as the source of truth and this
   block can be lifted out whole if any of it is unwanted.

   1. The outline rings and squares that float in the heroes go. They read
      as template decoration, and Stan already had the Overview ones removed.
      The soft colour blobs stay: they give depth without drawing lines.
   2. Headlines balance their line breaks instead of leaving one word on the
      last line; paragraphs avoid orphans.
   3. Ledes at 400, not 350. On a light grey they read as faint, not refined.
   4. Surfaces (cards, panels, dropdowns, the film) share one soft shadow and
      a hairline border, so the site has one depth system instead of several.
   5. Primary buttons get a tinted shadow and a pressed state. */
.ring, .sq { display: none !important; }

h1, h2, .h-display { text-wrap: balance; }
p, .lede, li { text-wrap: pretty; }

.lede { font-weight: 400; }

.film-frame,
.pack,
.svc,
.fnd,
.svc-f,
.doc-summary,
.contact-box {
  box-shadow: 0 1px 2px rgba(11,11,18,.04), 0 8px 24px -12px rgba(11,11,18,.10);
}
.film-frame { box-shadow: 0 2px 4px rgba(11,11,18,.06), 0 24px 60px -20px rgba(11,11,18,.35); }
.svc-f { transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease; }
.svc-f:hover { transform: translateY(-2px); border-color: rgba(29,78,216,.25); box-shadow: 0 2px 4px rgba(11,11,18,.05), 0 14px 30px -14px rgba(29,78,216,.25); }
.fnd { transition: box-shadow .2s ease; }
.fnd:hover { box-shadow: 0 2px 4px rgba(11,11,18,.05), 0 16px 36px -16px rgba(11,11,18,.18); }

.btn { box-shadow: 0 1px 1px rgba(11,11,18,.12), 0 6px 16px -6px rgba(11,11,18,.35); }
.btn.btn-blue { box-shadow: 0 1px 1px rgba(29,78,216,.25), 0 8px 20px -6px rgba(29,78,216,.55); }
.btn:active, .btn-line:active { transform: translateY(0); box-shadow: none; }

.hotbar { box-shadow: 0 1px 0 rgba(0,0,0,.06), 0 6px 20px -12px rgba(140,0,80,.45); }

@media (prefers-reduced-motion: reduce) {
  .svc-f, .fnd { transition: none; }
  .svc-f:hover { transform: none; }
}

/* Become a client: "Why Totem" list + mission line (2026-10-29) */
.svc-why { margin-top: 24px; padding: 22px 24px; border-radius: 14px; background: #fff; border: 1px solid var(--line); box-shadow: 0 1px 2px rgba(11,11,18,.04), 0 8px 24px -12px rgba(11,11,18,.10); }
.svc-why h3 { margin: 0 0 12px; }
.svc-why ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.svc-why li { position: relative; padding-left: 20px; color: var(--ink-2); font-size: 15px; line-height: 1.6; }
.svc-why li::before { content: ""; position: absolute; left: 2px; top: 10px; width: 7px; height: 7px; border-radius: 2px; background: var(--blue); }
.svc-why li b { color: var(--ink); }
.svc-mission { margin-top: 18px; font-size: 15px; color: var(--ink-2); }
.svc-mission b { color: var(--ink); }
.fnd h2 .fnd-link { text-decoration: none; color: inherit; }
.fnd h2 .fnd-link:hover { color: var(--blue); }
.svc-scarce { margin-top: 24px; display: inline-flex; align-items: center; gap: 10px; padding: 8px 14px; border-radius: 999px; background: rgba(224,0,124,.07); color: var(--ink-2); font-size: 14.5px; }
.svc-scarce b { color: var(--ink); }
.svc-scarce .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--pink-deep); }
