/* hycudesign.com — one stylesheet, no build step.
   Direction: "Limestone & Cypress" (DECISIONS.md, 2026-09-12), which retires the near-white ground
   of "Restraint" and keeps its one surviving clause — the site must not read as default-AI design,
   and in 2026 that look is the warm off-white five AI companies share. Tufa-stone ground, green-
   black ink, a cypress accent, and four washes of the capability colours gathered behind the first
   screen. Two faces: EB Garamond italic for the big headers, Hanken Grotesk at a few sizes for
   everything below them. Generous margins, no cards, no borders except hairlines. The graph is the
   only thing on the site that moves. */

:root {
  --bg: #e9e5d8;
  --bg-hi: #f2efe5;   /* the lightest stone: the wash behind the headline, and the axis-label chips */
  --ink: #1a1e18;
  --ink-2: #55584e;
  --ink-3: #837f71;
  --rule: #d4cdb9;
  --rule-mid: #bcb49f;
  --accent: #3e5d3a; /* hover and focus: cypress (Wyatt, 2026-09-12). 5.88:1 on the ground, so it holds at body size */
  --accent-ink: #f2efe5;

  /* The four capabilities, the only colour on the site. Same values as js/scene.js.
     Re-tuned for a stone ground: ochre, slate, olive, wine. Ochre is the lightest at 2.62:1 — it
     is a dot, a bar and a cube face, never text. */
  --c-research: #b3862f;
  --c-strategy: #33607f;
  --c-product: #4f7245;
  --c-systems: #7a4258;

  --sans: "Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "DM Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* Display only — the two largest header roles, and the project names. Everything else is the
     grotesk. Only the ITALIC is served, so every rule that uses this face also sets
     font-style: italic; asking for the roman would make the browser fake one. A real serif
     fallback this time: the face it stands in for is a serif, so Georgia flashes less than the
     grotesk would. */
  --display-face: "EB Garamond", Georgia, "Times New Roman", serif;

  --nav-h: 64px;
  --gutter: clamp(24px, 8vw, 144px);
  --max: 1240px;
  --measure: 640px;
  /* The inset that puts fixed/absolute elements on the same left edge as a centred .wrap */
  --edge: max(var(--gutter), calc((100vw - var(--max)) / 2 + var(--gutter)));

  --t-fast: 160ms cubic-bezier(.4, 0, .2, 1);
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
/* The gradient lives on the root element, whose box grows with the document, so it spans every
   page top to bottom. Sizing it to the body or to 100% height sizes it to one window and leaves a
   seam at the fold (CEO Review 12). */
html {
  -webkit-text-size-adjust: 100%; scroll-behavior: smooth;
  min-height: 100%;
  /* TWO layers, and the order matters — the first paints on top of the second.

     1. A radial bloom of white, behind the hero headline. Wyatt, 2026-09-09: "i don't want the top
        of the page to be the lightest area, because that reads as white. i want the lightness to
        come from behind the words to draw your eye." Its centre is given in vh, not %, on purpose:
        this element is as tall as the whole DOCUMENT, so a percentage would drop the bloom in a
        different place on a long study page than on a short one. 62vh is inside the first screen
        on every page, because #hero is exactly 100vh.
     2. The silver base. Its top stop is the DARKEST of the run rather than pure white — that
          is the half of the change that stops the page reading white before you have scrolled.
          Halved toward white on 2026-09-09. Wyatt: "the background is now TOO grey ... I want the
          background silver 50% closer to white than it currently is." Every stop is exactly
          halfway from where it was to #ffffff, so the SHAPE of the gradient is untouched and only
          its depth moved — the darkest stop went from 39 points off white to 19, the lightest
          from 9 to 5. The bloom above is unchanged and still reaches pure white at its centre.

     Sized to the document, not the window, so there is no seam at the fold (CEO Review 12). */
  background-color: var(--bg);
  /* The Aura: four washes of the capability colours, plus the stone highlight behind the headline.
     Each wash is a CIRCLE whose radius is a share of the WIDTH, placed at a fixed pixel depth from
     the top of the document. That is the whole trick, and Wyatt found the alternative on a phone:
     this element is as tall as the DOCUMENT, so a radius given as a percentage of height became a
     900px vertical smear on a narrow screen. Width-relative radii hold their shape at every size.
     They fade out by about 1100px, so everything below the first screen is flat stone — which is
     also his 2026-09-09 ruling: the light comes from behind the words, not from everywhere. */
  background-image:
    radial-gradient(circle min(62vw, 720px) at 88% 30px, color-mix(in srgb, var(--c-systems) 30%, transparent), transparent 70%),
    radial-gradient(circle min(54vw, 640px) at 4% 240px, color-mix(in srgb, var(--c-research) 26%, transparent), transparent 70%),
    radial-gradient(circle min(58vw, 680px) at 76% 470px, color-mix(in srgb, var(--c-product) 22%, transparent), transparent 70%),
    radial-gradient(circle min(66vw, 760px) at 18% 760px, color-mix(in srgb, var(--c-strategy) 22%, transparent), transparent 70%),
    radial-gradient(100vh 70vh at 30% 62vh, var(--bg-hi) 0%, color-mix(in srgb, var(--bg-hi) 55%, transparent) 38%, transparent 72%);
  background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: transparent; /* the root paints the ground; see html above */
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: inherit; text-decoration: none; }
a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}
p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }
strong { font-weight: 600; }

.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0; padding: 0; margin: -1px;
}

/* ── Type roles ─────────────────────────────────────────────────────────── */
.eyebrow {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.eyebrow.dark { color: var(--ink-2); }
h1, h2, h3 { font-weight: 600; letter-spacing: -.02em; line-height: 1.12; margin: 0; text-wrap: balance; }
.display {
  font-size: clamp(38px, 5vw, 66px);
  letter-spacing: -.03em;
  line-height: 1.02;
}
.h-lg { font-size: clamp(30px, 3.6vw, 44px); }
.h-md { font-size: clamp(22px, 2.2vw, 27px); letter-spacing: -.015em; line-height: 1.22; }
.h-sm { font-size: 19px; letter-spacing: -.01em; }
/* The short project title (Wyatt, 2026-09-08). Two or three words in the display face, above the
   sentence-long headline — the same words on the Work card and on the study page, and untied to
   anything else. They are NOT the graph tile names: five of the eight differ from `name` in
   data/projects.json, and Polycam differs from its own <title> as well (CEO Review 30). Whether
   the three should agree is Wyatt's call, logged as HY-36. It names the project; the headline
   below it still does the explaining. The two sizes live with their own layouts, below. */
.proj { font-family: var(--display-face); font-style: italic; font-weight: 500; letter-spacing: -.02em; line-height: 1.08; margin: 0; }
/* EB Garamond italic carries the two big header roles (Wyatt, 2026-09-12). Only the italic is
   served, so font-style is set explicitly here — ask for the roman and the browser fakes a slant.
   An old-style serif sets smaller on the same point size than the grotesk does, so these two roles
   step UP about 18% rather than down, and the tracking comes in slightly. Long headlines are
   exempt — see .study-head .h-lg below. */
.display, .h-lg {
  font-family: var(--display-face);
  font-style: italic;
  font-weight: 500;
  letter-spacing: -.02em;
}
.display { font-size: clamp(38px, 5.1vw, 66px); line-height: 1.06; }
.h-lg { font-size: clamp(31px, 3.7vw, 46px); line-height: 1.12; }
.lede { font-size: clamp(18px, 1.6vw, 21px); line-height: 1.45; color: var(--ink-2); max-width: 32em; }
.muted { color: var(--ink-2); }
.dim { color: var(--ink-3); }
.mono { font-family: var(--mono); }
.num { font-variant-numeric: tabular-nums; }

/* ── Layout ─────────────────────────────────────────────────────────────── */
.wrap { max-width: var(--max); margin: 0 auto; padding-left: var(--gutter); padding-right: var(--gutter); }
.prose { max-width: var(--measure); }
.prose p { margin-bottom: 1.15em; }
.prose h2 { margin: 2.2em 0 .6em; }
.prose h3 { margin: 1.8em 0 .5em; }
.prose ul { padding-left: 1.2em; margin: 0 0 1.15em; }
.prose li { margin-bottom: .35em; }
section.band { padding: clamp(48px, 6vw, 100px) 0; border-top: 1px solid var(--rule); }
section.band.flush { border-top: 0; }
#hero + .band { padding-top: clamp(20px, 2.5vw, 36px); } /* no tall pause between the graph and What we do */
.band-head { display: flex; justify-content: space-between; align-items: baseline; gap: 24px; margin-bottom: clamp(20px, 2.5vw, 36px); }
.band-head .eyebrow { margin: 0; }
.link { border-bottom: 1px solid var(--rule-mid); transition: border-color var(--t-fast), color var(--t-fast); }
.link:hover { color: var(--accent); border-color: var(--accent); }
.arrow::after { content: " \2192"; }

/* ── Buttons ────────────────────────────────────────────────────────────── */
/* Square, with a keyline of the ground set a few pixels inside the rectangle — a printed label
   rather than a pill (Wyatt's type proof, 2026-09-08; chosen 2026-09-12). Two stacked inset shadows
   draw it: the first paints the whole face, the second sits on top and shows only in the gap
   between the two spreads. --face carries the fill so the keyline follows the button into hover. */
.btn {
  --face: var(--ink);
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font: 600 15px/1 var(--sans);
  padding: 14px 22px;
  border-radius: 0;
  border: 0;
  background: var(--face); color: var(--bg) !important;
  box-shadow: inset 0 0 0 4px var(--face), inset 0 0 0 5.5px var(--bg);
  cursor: pointer; white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast), box-shadow var(--t-fast);
}
.btn:hover { --face: var(--accent); color: var(--accent-ink) !important; }
.btn.quiet { background: transparent; color: var(--ink) !important; box-shadow: inset 0 0 0 1px var(--rule-mid); }
.btn.quiet:hover { background: transparent; color: var(--accent) !important; box-shadow: inset 0 0 0 1px var(--accent); }
.btn.sm { font-size: 14px; padding: 10px 16px; }

/* ── Nav ────────────────────────────────────────────────────────────────── */
#nav {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  height: var(--nav-h);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--edge);
  background: rgba(233, 229, 216, .72); /* the ground, not white — a white here is a visible seam */
  -webkit-backdrop-filter: saturate(180%) blur(14px); backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-fast);
}
#nav.is-scrolled { border-bottom-color: var(--rule); }
/* The wordmark went back to the grotesk on 2026-09-08 — Wyatt saw it in Shrikhand and preferred
   what it was. Byte-for-byte the rule from before, including no font-family of its own: it inherits
   Geist from body. The mark's -1px nudge goes with it, having only existed to answer Shrikhand's
   low baseline. Every page still requests the display face and still draws with it — .display on
   the five top-level pages, .proj on the eight studies — so nothing here strands a font request. */
/* The wordmark is a drawing, not text, so .brand carries no type rules at all. Height is set and
   width left to follow, or the outlines distort. */
.brand { display: inline-flex; align-items: center; gap: 10px; }
.brand .mark { display: block; width: 20px; height: 20px; }
.brand .wordmark { display: block; height: 19px; width: auto; }
.nav-links { display: flex; align-items: center; gap: clamp(18px, 2.4vw, 32px); font-size: 15px; font-weight: 500; }
.nav-links a:not(.btn) { color: var(--ink-2); transition: color var(--t-fast); }
.nav-links a:not(.btn):hover, .nav-links a[aria-current="page"] { color: var(--ink); }
.nav-links .btn { margin-left: 8px; }
.nav-toggle { display: none; background: none; border: 0; font: inherit; color: var(--ink); padding: 8px; cursor: pointer; }
@media (max-width: 720px) {
  .nav-links { display: none; }
  .nav-links.is-open {
    display: flex; flex-direction: column; align-items: flex-start; gap: 20px;
    position: absolute; top: var(--nav-h); left: 0; right: 0;
    padding: 20px var(--gutter) 28px;
    background: var(--bg); border-bottom: 1px solid var(--rule);
    font-size: 20px;
  }
  .nav-links.is-open .btn { margin: 6px 0 0; }
  .nav-toggle { display: block; }
}

main { padding-top: var(--nav-h); }
main.has-hero { padding-top: 0; }

/* ── Hero: the graph ────────────────────────────────────────────────────── */
#hero { position: relative; height: 100vh; height: 100svh; min-height: 560px; overflow: hidden; }
.graph-stage { position: absolute; inset: 0; }
#graph-canvas, #graph-2d { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
#graph-canvas { touch-action: pan-y; }
#graph-2d svg { width: 100%; height: 100%; }

#axis-labels { position: absolute; inset: 0; pointer-events: none; z-index: 3; }
.axis-label {
  position: absolute; top: 0; left: 0;
  font-family: var(--mono); font-size: 12px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink);
  background: rgba(242, 239, 229, .85); /* --bg-hi, so the chip reads as stone and not as a hole */
  padding: 4px 9px; border-radius: 3px;
  white-space: nowrap; user-select: none;
  opacity: 0; will-change: transform;
}
.axis-label.helper { font-size: 11px; font-weight: 400; color: var(--ink-3); background: none; padding: 0 4px; letter-spacing: .2em; }

#graph-hover {
  position: absolute; z-index: 12; max-width: 300px;
  background: var(--ink); color: var(--bg);
  padding: 9px 12px; border-radius: 6px;
  font-size: 13px; line-height: 1.4;
  pointer-events: none; transform: translate(-50%, -130%);
}
#graph-hover .hl-eyebrow { display: block; font-family: var(--mono); font-size: 10px; letter-spacing: .12em; text-transform: uppercase; opacity: .7; margin-bottom: 3px; }

.hero-copy {
  position: absolute; z-index: 4;
  left: var(--edge); right: var(--edge); bottom: clamp(40px, 8vh, 96px);
  display: flex; justify-content: space-between; align-items: flex-end; gap: 32px;
  pointer-events: none; /* desktop: copy overlays the graph; clicks fall through to tiles */
}
.hero-copy a, .hero-controls { pointer-events: auto; }
/* The headline is sized from ITS OWN COLUMN, not the viewport (Wyatt, 2026-09-08: "audit all of the
   different screen sizes and re-logic the header so that these awkward line breaks never happen").
   It used to be clamp(34px, 3.9vw, 54px) against a column capped at 720px, so the type kept growing
   with the window while the column stopped — and the longest line, "We see where you are,", came out
   the same width as the box it had to fit in. At 1050px they were both 475px, and rounding decided
   whether you got three lines or an orphaned "are,".
   `cqw` is a percentage of this container's width, so 8.4cqw keeps that line at ~97% of the column
   at every size, with the clamp holding a floor and a ceiling. Measured across sixteen widths. */
.hero-text { flex: 1 1 0; min-width: 0; max-width: 720px; container-type: inline-size; }
.hero-text .display {
  margin-bottom: 18px;
  text-wrap: balance;
  /* The vw line is the fallback: a browser without container queries drops the cqw declaration at
     parse time and keeps this one, which is the sizing this hero had before. Without it the headline
     would fall through to .display's generic clamp — larger than this hero has ever been. Such a
     browser also drops the @container rule below, so it gets the old SIZE with the forced break
     permanently off; the line still wraps rather than overflowing (CEO Review 37). */
  font-size: clamp(34px, 3.9vw, 54px);
  font-size: clamp(30px, 8.4cqw, 53px);
}
/* The forced break is Wyatt's ruling from 2026-09-02 — "are" ends the first line — and it only
   helps when the line actually fits. It used to switch on at a 721px VIEWPORT, where the graph has
   already taken its share and the column is 311px against a 394px line: six rendered lines. It now
   switches on when the COLUMN is wide enough to hold the line. Below that there is no forced break
   and `text-wrap: balance` divides the words evenly instead of orphaning two of them. */
.br-desk { display: none; }
/* 470px is "We see where you are," at the LARGEST size any rule here can give it — the 40px cap of
   the phone clamp, where that line measures 464px. Below the phone breakpoint the type is sized by
   viewport and can outgrow the column, so the threshold has to clear the worst case, not the typical
   one: at 470 it was orphaning "way" onto its own line at 480px wide. Above the threshold the break
   is Wyatt's 2026-09-02 ruling; below it, `text-wrap: balance` reaches the same three lines on its
   own wherever they fit. Calibrated to THAT STRING at THAT SIZE — change the headline copy or either
   clamp and re-measure. */
@container (min-width: 470px) { .br-desk { display: inline; } }
/* The two emphasised words are blue (Wyatt, 2026-09-12). Deliberately NOT the strategy slate
   #33607f: the four capability colours are data on this site — a dot, a bar, a cube — and borrowing
   one for emphasis makes the headline look like it is naming a capability. This blue is deeper and
   more saturated than the slate, and reads at 6.60:1 on the stone. */
.hero-text .hl { color: #1f4e8c; }
.hero-text .lede { margin-bottom: 22px; }
.hero-controls { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.hero-controls button {
  font: 500 12px/1 var(--mono); letter-spacing: .06em;
  color: var(--ink-2); background: rgba(242, 239, 229, .85);
  border: 1px solid var(--rule); border-radius: 999px;
  height: 34px; min-width: 34px; padding: 0 12px; cursor: pointer;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.hero-controls button:hover { color: var(--ink); border-color: var(--ink); }
.hero-hint { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); margin: 0 8px 0 0; }
@media (max-width: 720px) {
  /* Below 720px the volume hangs from the nav and the headline follows the PRODUCT label. */
  #hero { height: auto; min-height: 0; padding-top: var(--nav-h); }
  /* The canvas keeps its tall frame; the stage is the window we crop it to, so the copy can
     follow the volume instead of the empty half of the canvas below it. */
  .graph-stage { position: relative; height: calc(75vw + 5px); min-height: 0; overflow: hidden; }
  .graph-stage #graph-canvas, .graph-stage #graph-2d, .graph-stage #axis-labels { height: 200vw; }
  .axis-label.helper { display: none; }
  .hero-copy { position: static; flex-direction: column; align-items: flex-start; padding: 6px var(--gutter) 20px; pointer-events: auto; }
  /* align-items: flex-start sizes a flex item by its content, and the headline's container query
     needs its width from the outside — without this the container measures 0 and the type falls to
     its floor. Stretch gives it the column's real width. */
  .hero-text { align-self: stretch; }
  /* Restored after CEO Review 36 caught it being deleted as "redundant". It is not: below 720px the
     column is the viewport minus the gutter, so 8.6vw and 8.4cqw are not the same number, and this
     line is worth 33.5px at 390 and 37px at 430 where the container rule gives the 30px floor. */
  .hero-text .display { font-size: clamp(30px, 8.6vw, 40px); }
  /* Pinch and drag do this on a touchscreen, and the buttons read as stray controls under the
     headline once the copy sits below the graph. */
  .hero-controls { display: none; }
  .hero-hint { display: none; }
}

/* ── Selected work ──────────────────────────────────────────────────────── */
.work-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(40px, 7vw, 120px); row-gap: 0; }
@media (max-width: 800px) { .work-list { grid-template-columns: 1fr; } }
.work-item { display: block; padding: 18px 0 28px; border-top: 1px solid var(--rule); }
.work-item .eyebrow { display: flex; justify-content: space-between; gap: 16px; margin-bottom: 18px; }
.work-item .eyebrow .year { font-family: var(--sans); font-size: 13px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--ink-2); white-space: nowrap; }
.work-item .proj { font-size: clamp(25px, 2.5vw, 31px); margin-bottom: 10px; transition: color var(--t-fast); }
.work-item h3 { transition: color var(--t-fast); }
.work-item:hover h3, .work-item:hover .proj { color: var(--accent); }
.work-item .sub { margin: 12px 0 18px; color: var(--ink-2); max-width: 34em; }
.tags { display: flex; flex-wrap: wrap; gap: 6px 16px; font-family: var(--mono); font-size: 12px; letter-spacing: .04em; color: var(--ink-3); }
[data-cap]::before { content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 7px; vertical-align: 1px; background: var(--c, var(--ink-3)); }
[data-cap="research"] { --c: var(--c-research); }
[data-cap="strategy"] { --c: var(--c-strategy); }
[data-cap="product"] { --c: var(--c-product); }
[data-cap="systems"] { --c: var(--c-systems); }
.cap h3[data-cap]::before { width: 9px; height: 9px; margin-right: 10px; vertical-align: 2px; }

/* ── Capabilities ───────────────────────────────────────────────────────── */
.caps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 40px clamp(32px, 4vw, 64px); }
@media (max-width: 900px) { .caps { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .caps { grid-template-columns: 1fr; } }
.cap { padding-top: 18px; border-top: 1px solid var(--rule); }
.cap h3 { margin-bottom: 10px; }
.cap p { color: var(--ink-2); font-size: 16px; }
.cap .where { margin-top: 12px; font-family: var(--mono); font-size: 12px; color: var(--ink-3); letter-spacing: .04em; }

/* The fifth capability is not a fifth column, it is the floor the other four stand on. The bar
   below the columns carries one segment per capability, in that capability's own colour and
   exactly its width, so the four visibly gather into the one line the AI text hangs from. No
   separating rule: a grey hairline above it read as "another item", which is the opposite. */
.cap-bar {
  margin-top: 26px;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: clamp(32px, 4vw, 64px);
}
.cap-bar i { display: block; height: 3px; border-radius: 2px; }
.cap-bar i:nth-child(1) { background: var(--c-research); }
.cap-bar i:nth-child(2) { background: var(--c-strategy); }
.cap-bar i:nth-child(3) { background: var(--c-product); }
.cap-bar i:nth-child(4) { background: var(--c-systems); }
@media (max-width: 900px) { .cap-bar { column-gap: 6px; } }

.cap-ground {
  margin-top: 22px;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2.2fr);
  gap: 14px clamp(32px, 4vw, 64px); align-items: start;
}
@media (max-width: 720px) { .cap-ground { grid-template-columns: 1fr; } }
.cap-ground h3 { display: flex; align-items: center; gap: 11px; }
.cap-ground p { color: var(--ink-2); font-size: 16px; max-width: 46em; margin: 0; }
/* The label carries all four dots as well as the bar: the bar says which columns, the dots say
   which capabilities, in the same vocabulary the four headings already use. */
.cap-dots { display: inline-flex; gap: 4px; flex: none; }
.cap-dots i { display: block; width: 7px; height: 7px; border-radius: 50%; }
.cap-dots i:nth-child(1) { background: var(--c-research); }
.cap-dots i:nth-child(2) { background: var(--c-strategy); }
.cap-dots i:nth-child(3) { background: var(--c-product); }
.cap-dots i:nth-child(4) { background: var(--c-systems); }
/* Studio lists its four in rows, not columns, so the bar spans the list as one line, and both it
   and the text below it belong in the list's column, not beside it. */
.not-list + .cap-bar { column-gap: 4px; }
.two-col > .cap-bar, .two-col > .cap-ground { grid-column: 2; }
@media (max-width: 860px) { .two-col > .cap-bar, .two-col > .cap-ground { grid-column: 1; } }

/* ── Statement / thesis band ────────────────────────────────────────────── */
.statement { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 48px clamp(48px, 8vw, 140px); align-items: start; }
@media (max-width: 860px) { .statement { grid-template-columns: 1fr; } }
.statement .h-lg { max-width: 14em; }
.statement .prose p { font-size: 18px; }
/* Not italic any more: it sits directly under an italic headline, and italic-under-italic reads as
   one run of the same voice instead of an aside. The mono face and the tracking do that job now. */
.pronounce { font-family: var(--mono); font-size: 13px; letter-spacing: .04em; color: var(--ink-2); margin: 12px 0 0; }
.studio-hero .pronounce { margin-top: 14px; }

/* ── Contact strip ──────────────────────────────────────────────────────── */
.contact-strip { display: flex; justify-content: space-between; align-items: flex-end; gap: 32px; flex-wrap: wrap; }
.contact-strip .actions { display: flex; gap: 12px; flex-wrap: wrap; }

/* ── Footer ─────────────────────────────────────────────────────────────── */
footer {
  border-top: 1px solid var(--rule);
  padding: 24px 0 32px;
  font-family: var(--mono); font-size: 12px; letter-spacing: .04em; color: var(--ink-3);
}
footer .wrap { display: flex; justify-content: space-between; gap: 16px 32px; flex-wrap: wrap; }
footer a:hover { color: var(--ink); }

/* ── Study pages ────────────────────────────────────────────────────────── */
.study-head { padding-top: clamp(40px, 5.5vw, 88px); padding-bottom: clamp(28px, 3.5vw, 48px); }
.study-head .eyebrow { margin-bottom: 28px; }
/* A study head is h1 → h2 → body (Wyatt, 2026-09-08). The project name IS the page's heading and
   sets largest; the sentence under it is the byline, an h2 in the grotesk; the paragraph under that
   is body text with no type role of its own — it was a .lede, which made it a third display size
   and greyed it. Before this the biggest thing on the page was a <p> and the h1 was the sentence,
   so what a reader saw and what a screen reader announced were different pages (CEO Review 32). */
.study-head .proj { font-size: clamp(34px, 4vw, 50px); margin-bottom: 14px; }
.study-head .study-intro { margin-top: 24px; max-width: var(--measure); }
/* The study headlines are full sentences of 20 to 30 words. At that length a display italic stops
   being a headline and becomes a wall. These stay in the grotesk — and reset font-style with it,
   or they inherit the italic from .h-lg above. The hero, the section heads and the page titles
   carry the display face instead. */
.study-head .h-lg {
  font-family: var(--sans);
  font-style: normal;
  font-weight: 600;
  font-size: clamp(30px, 3.6vw, 44px);
  letter-spacing: -.02em;
  line-height: 1.12;
}
.study-body { display: grid; grid-template-columns: minmax(0, 7fr) minmax(220px, 3fr); gap: 56px clamp(56px, 9vw, 160px); align-items: start; padding-bottom: clamp(48px, 6vw, 100px); }
@media (max-width: 860px) { .study-body { grid-template-columns: 1fr; } .study-rail { order: -1; } }
/* The rail sticks only in the two-column layout, where it has a column of its own to stick in: its
   grid area is as tall as the article beside it, so it slides 1703px on Pour at 1440px wide and
   holds the project details in view while you read. That is the whole point of it.
   At 860px and below the body drops to ONE column and the rail becomes a full-width block sitting
   above the article (`order: -1`). Sticky there does not go quiet — its containing block is still
   the whole study body, so it pins under the nav and rides 3516px down the page on Pour at 390px,
   with the article scrolling straight through it. Measured at y=1600: four paragraphs and headings
   overlapping the rail, the worst 328x223px, text printed over text. That is what Wyatt reported on
   2026-09-11 — "scrolling is Totally broken on mobile ... the index page works fine, but all of the
   individual studio projects are broken" — and it is only the eight study pages because the rail is
   the only sticky element on the site, and home, Work, Studio, Contact and 404 do not have one.
   Declaring sticky above the breakpoint rather than unsetting it below keeps the rule where it
   earns its keep and leaves nothing to leak downward.

   The .02 pairs with the `max-width: 860px` above it and is not a typo. `min-width: 861px` would
   leave every width BETWEEN them matching neither rule — at 860.5, which browser zoom really does
   produce, you got the two-column layout with a rail that had quietly stopped sticking. Verified:
   860.01, 860.02 and 860.5 all fell through the pair. .02 shrinks that hole to widths between
   860 and 860.02, which no browser reports (CEO Review 38).

   One honest footnote on "its containing block is still the whole study body": that is what the
   browsers DO -- the rail's own grid row measures 510.5px while the rail travels 3516px -- but the
   Grid spec says a grid item's containing block is its grid area, which would have meant almost no
   travel at all. Reasoning from the spec is what hid this bug; the 3516px came from measuring, and
   an early draft of this comment claimed 0px travel on exactly that bad reasoning (CEO Review 38). */
@media (min-width: 860.02px) { .study-rail { position: sticky; top: calc(var(--nav-h) + 24px); } }
.rail { list-style: none; margin: 0; padding: 0; font-size: 15px; }
.rail li { padding: 14px 0; border-top: 1px solid var(--rule); display: grid; gap: 4px; }
.rail li:last-child { border-bottom: 1px solid var(--rule); }
.rail .k { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.beat { margin-top: clamp(28px, 3.5vw, 48px); }
.beat:first-child { margin-top: 0; }
.beat .eyebrow { margin-bottom: 14px; }
.beat h2 { margin: 0 0 18px; }
.beat p { font-size: 18px; }
.figures { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; margin: 32px 0 8px; }
@media (max-width: 560px) { .figures { grid-template-columns: 1fr; } }
.figure { padding-top: 14px; border-top: 1px solid var(--rule); }
.figure .n { font-size: clamp(30px, 3vw, 40px); font-weight: 500; letter-spacing: -.03em; line-height: 1; font-variant-numeric: tabular-nums; }
.figure .l { display: block; margin-top: 8px; font-size: 14px; color: var(--ink-2); }

/* A takeaway: the one sentence a beat is actually for, pulled out and given air. .figures is for
   numbers you scan and body text is for the argument; this is the finding itself, stated first the
   way the AEO rules on this page say to state one. No card and no fill -- a hairline above and
   space around it, which is how .figure, .rail and .study-next already set themselves off
   (Restraint, DECISIONS.md 2026-09-02). It sits BELOW `.beat p` so the 18px body rule loses the
   specificity tie on source order; `.takeaway .l` carries two classes and wins outright. */
.takeaway { margin: clamp(40px, 4vw, 56px) 0 8px; padding-top: 18px; border-top: 1px solid var(--rule); }
.takeaway p { font-size: clamp(20px, 2vw, 25px); line-height: 1.3; letter-spacing: -.015em; max-width: 24em; margin: 0; }
.takeaway .l { margin-top: 10px; font-size: 14px; line-height: 1.5; letter-spacing: 0; color: var(--ink-2); max-width: 34em; }
.study-next { border-top: 1px solid var(--rule); padding-top: 28px; padding-bottom: clamp(48px, 6vw, 88px); }
.study-next a { display: inline-block; margin-top: 10px; }

/* ── Studio page ────────────────────────────────────────────────────────── */
.studio-hero { padding-top: clamp(40px, 5.5vw, 88px); padding-bottom: clamp(32px, 4vw, 60px); display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 48px; align-items: center; }
@media (max-width: 860px) { .studio-hero { grid-template-columns: 1fr; } }
.tesseract { width: min(100%, 360px); aspect-ratio: 1; display: block; margin: 0 auto; color: var(--ink); }
.statement .tesseract { width: min(100%, 260px); margin: 8px 0 0; }
.two-col { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 40px clamp(48px, 8vw, 140px); }
@media (max-width: 860px) { .two-col { grid-template-columns: 1fr; } }
.not-list { list-style: none; margin: 0; padding: 0; }
.not-list li { padding: 16px 0; border-top: 1px solid var(--rule); display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 8px 32px; }
.not-list li:last-child { border-bottom: 1px solid var(--rule); }
.not-list .n { font-weight: 500; }
.not-list .w { color: var(--ink-2); font-size: 16px; }
@media (max-width: 560px) { .not-list li { grid-template-columns: 1fr; } }

/* ── Contact page ───────────────────────────────────────────────────────── */
.contact-single { padding-bottom: clamp(48px, 6vw, 100px); }
.contact-single #write { max-width: var(--measure); }
.field { display: grid; gap: 8px; margin-bottom: 22px; }
.field label { font-size: 14px; font-weight: 500; color: var(--ink-2); }
.field input, .field textarea {
  font: inherit; font-size: 16px; color: var(--ink);
  background: transparent; border: 0; border-bottom: 1px solid var(--rule-mid); border-radius: 0;
  padding: 10px 0; width: 100%;
  transition: border-color var(--t-fast);
}
.field textarea { min-height: 140px; resize: vertical; }
.field input:focus, .field textarea:focus { outline: none; border-bottom-color: var(--ink); }
.field .hint { font-size: 13px; color: var(--ink-3); }
.form-status { margin-top: 14px; font-size: 14px; color: var(--ink-2); min-height: 1.4em; }

/* ── 404 ────────────────────────────────────────────────────────────────── */
.four-oh-four { min-height: 60vh; display: grid; align-content: center; padding-top: 64px; padding-bottom: 64px; }
