/* supreeth.in: the one stylesheet for every page except the prototypes. The rules it follows (type
   scale, colours, space, corners, boxes and hover, focus and tap areas) are in README.md, "Rules". */

/* Fonts, self-hosted (site audit, 6 Nov 2026, D8 a): the latin files Google Fonts served, under the same
   names. Geist is variable in weight (the file runs 100–900); the site uses 400 only ("Copy" and "Copied"
   moved from 500 to 400, 7 Nov 2026). Hedvig has one weight and a variable optical size (opsz 12–24). No descriptor is needed for
   that: font-optical-sizing: auto, the default, sets opsz from the font size. Geist's latin-ext file
   carries "₹" and loads only where it is used. Neither Geist file has "→" (U+2192), so Geist text borrows
   Hedvig's arrow from its symbols file (same Google CSS, same OFL), which loads only on a page that has
   one (the customer journey map essay; 7 Nov 2026). Licences: fonts/OFL-*.txt. */
@font-face { font-family: "Geist"; font-style: normal; font-weight: 100 900; font-display: swap; src: url("/fonts/geist-latin.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Geist"; font-style: normal; font-weight: 100 900; font-display: swap; src: url("/fonts/geist-latin-ext.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Geist"; font-style: normal; font-weight: 100 900; font-display: swap; src: url("/fonts/hedvig-letters-serif-symbols.woff2") format("woff2"); unicode-range: U+2192; }
@font-face { font-family: "Hedvig Letters Serif"; font-style: normal; font-weight: 400; font-display: swap; src: url("/fonts/hedvig-letters-serif-latin.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

:root {
  --bg: #ecedea; --ground: #e1e2dd; --ink: #1c1d1a; --muted: #61635d; --faint: #b9bbb4; --rim: rgba(28, 29, 26, .1); --mark: #0d7254;
  --serif: "Hedvig Letters Serif", Georgia, "Times New Roman", serif;
  --sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --gut: clamp(1.25rem, 6vw, 7rem);
  --rail: 8.5rem; --rail-gap: clamp(2rem, 3.2vw, 3.25rem);
  --measure: 64rem; --text: 38rem;
  --col-gap: clamp(2rem, 4vw, 4rem);
  --space-sec: clamp(6rem, 16vh, 11rem);
  --space-entry: clamp(5rem, 12vh, 8rem);
  --r-s: 3px; --r-m: 6px; --r-phone: 18px; /* squared off 27 Oct: boxes, pills and rows 6px; screens 3px; phones keep their own corner */
  --ease: cubic-bezier(.23, 1, .32, 1);
  --shade: 0 1px 0 rgba(0, 0, 0, .02), 0 18px 36px -26px rgba(0, 0, 0, .35);
  /* the two hover greys, named by what they're for (28 Oct): large surfaces (cards, the 5-minute
     screens) take the lighter step; small pills (menu, tabs, case-study pills) and every tap take
     the stronger one. Nothing else may mix a new grey. */
  --hover-lg: color-mix(in srgb, var(--ground) 93%, var(--ink));
  --hover-sm: color-mix(in srgb, var(--ground) 88%, var(--ink));
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --bg: #171816; --ground: #20211e; --ink: #e8e9e4; --muted: #93958e; --faint: #454741; --rim: rgba(255, 255, 255, .1); --mark: #62c79c; --shade: 0 18px 36px -24px rgba(0, 0, 0, .8); color-scheme: dark; }
}
[data-theme="dark"] { --bg: #171816; --ground: #20211e; --ink: #e8e9e4; --muted: #93958e; --faint: #454741; --rim: rgba(255, 255, 255, .1); --mark: #62c79c; --shade: 0 18px 36px -24px rgba(0, 0, 0, .8); color-scheme: dark; }

/* ---------------------------------------------------------------- Base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-padding-top: 5.5rem; }
@media (prefers-reduced-motion: no-preference) { html:has(body.home) { scroll-behavior: smooth; } } /* home only: the lengths and tabs glide there; elsewhere a Tab press or a contents link jumps (7 Nov 2026) */
body { margin: 0; background: var(--bg); color: var(--ink); font: 400 1.0625rem/1.6 var(--sans); font-synthesis: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
h1, h2, h3, p, ol, ul, figure { margin: 0; padding: 0; }
h1, h2, h3 { font-weight: 400; }
ol, ul { list-style: none; }
img { display: block; max-width: 100%; height: auto; }
b, strong { font-weight: 400; }
a { color: inherit; text-decoration-line: underline; text-decoration-thickness: 1px; text-underline-offset: .22em; text-decoration-color: var(--faint); transition: text-decoration-color .2s ease, color .2s ease; }
@media (hover: hover) and (pointer: fine) { a:hover { text-decoration-color: var(--mark); } }
:focus-visible { outline: 2px solid var(--mark); outline-offset: 4px; border-radius: 2px; }
::selection { background: color-mix(in srgb, var(--mark) 20%, transparent); }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
.skip { position: fixed; z-index: 50; left: var(--gut); top: .75rem; padding: .55rem .85rem; border-radius: var(--r-s); background: var(--ink); color: var(--bg); text-decoration: none; transform: translateY(-160%); transition: transform .2s var(--ease); }
.skip:focus { transform: none; }
html.theme-switching * { transition: background-color .3s ease, color .3s ease !important; }

/* ---------------------------------------------------------------- Header (as on supreeth.in) */
.head { position: sticky; top: 0; z-index: 20; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .4rem 1.5rem; padding: 1rem var(--gut) .85rem; background: var(--bg); }
.head a { text-decoration-line: none; }

/* ---------------------------------------------------------------- Blocks: rail + body */
.block { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); column-gap: var(--rail-gap); align-items: start; padding: var(--space-sec) var(--gut) 0; }
.block--top { padding-top: clamp(3.5rem, 12vh, 8rem); }
.rail { position: sticky; top: 5.5rem; font-size: 1rem; line-height: 1.4; padding-top: .35rem; }
.rail h2 { font: 400 1rem/1.4 var(--sans); }
.rail p { color: var(--muted); margin-top: .1rem; }
.body { min-width: 0; max-width: var(--measure); }

/* ---------------------------------------------------------------- The question */
.statement { font: 400 clamp(2.6rem, 1rem + 5vw, 5.25rem)/1.04 var(--serif); letter-spacing: -.022em; }

/* ---------------------------------------------------------------- 30 seconds */
.say { max-width: var(--text); font: 400 clamp(1.35rem, 1.05rem + .9vw, 1.85rem)/1.42 var(--serif); letter-spacing: -.008em; color: var(--muted); text-wrap: pretty; }
.say p + p { margin-top: 1em; }
.say b { color: var(--ink); }


/* ---------------------------------------------------------------- 5 minutes */
.prod { display: grid; gap: 1.5rem; }
.prod + .prod { margin-top: var(--space-entry); }
.prod h3 { font: 400 clamp(1.9rem, 1.3rem + 1.6vw, 2.6rem)/1.08 var(--serif); letter-spacing: -.018em; }
.prod .meta { margin-top: .4rem; font-size: .9375rem; color: var(--muted); }
.prod .what { margin-top: .6rem; max-width: 30rem; text-wrap: pretty; }
.prod .claim { margin-top: .9rem; max-width: 30rem; font-size: .9375rem; color: var(--muted); text-wrap: pretty; }
.act { display: flex; flex-wrap: wrap; align-items: baseline; gap: .4rem 1.4rem; margin-top: 1.1rem; font-size: .9375rem; }
.act a { display: inline-flex; align-items: center; min-height: 44px; }
.act span { color: var(--muted); }

.ground { position: relative; border-radius: var(--r-m); background: var(--ground); padding: clamp(.9rem, 2.4vw, 1.6rem); }
.hero figcaption, .tiles figcaption { margin-top: .65rem; font-size: .875rem; color: var(--muted); text-wrap: pretty; }
.hero img.desk { width: 100%; border-radius: var(--r-s); outline: 1px solid var(--rim); outline-offset: -1px; box-shadow: var(--shade); }
.stage { padding-right: calc(clamp(.9rem, 2.4vw, 1.6rem) + 12%); }
.stage img.phone { position: absolute; right: clamp(.9rem, 2.4vw, 1.6rem); bottom: clamp(.9rem, 2.4vw, 1.6rem); width: 23%; height: 82%; object-fit: cover; object-position: top; border-radius: var(--r-phone); outline: 1px solid var(--rim); outline-offset: -1px; box-shadow: var(--shade); }
.ground.phones { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(.6rem, 2vw, 1.25rem); padding-bottom: 0; overflow: hidden; }
.ground.phones img { width: 100%; aspect-ratio: 1170 / 1650; object-fit: cover; object-position: top; border-radius: var(--r-phone) var(--r-phone) 0 0; outline: 1px solid var(--rim); outline-offset: -1px; }

.strip { display: grid; gap: .75rem; }
.strip-label { font-size: .9375rem; color: var(--muted); }
.tiles { display: grid; grid-auto-flow: column; grid-auto-columns: 78%; gap: .9rem; overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: .4rem; scrollbar-width: thin; }
.tiles figure { scroll-snap-align: start; min-width: 0; }
/* every tile is the same ground at the same ratio; what sits on it is a desktop crop or a phone */
.tile { position: relative; display: flex; justify-content: center; aspect-ratio: 4 / 3; border-radius: var(--r-m); background: var(--ground); overflow: hidden; }
.tile img { outline: 1px solid var(--rim); outline-offset: -1px; }

/* ---------------------------------------------------------------- No rush
   One row everywhere: a serif title, then a muted line led by its length.
   Each group's name sits in a narrow column of its own, the way the rail
   sits beside the page. Groups are separated by space alone. */
.shelf { display: grid; gap: clamp(3rem, 7vh, 4.5rem); }
.group { display: grid; grid-template-columns: 10rem minmax(0, var(--text)); column-gap: var(--col-gap); align-items: start; }
.group h3, .group h2 { font: 400 .9375rem/1.9 var(--sans); color: var(--muted); padding-top: .1rem; }
.group ol { display: grid; gap: 1.35rem; }
.group li > a { display: grid; gap: .2rem; text-decoration: none; }
.group .t { justify-self: start; font: 400 1.25rem/1.3 var(--serif); letter-spacing: -.004em; text-wrap: balance; }
.group .d { font-size: .9375rem; color: var(--muted); text-wrap: pretty; }
.group .m { color: var(--ink); margin-right: .55em; font-variant-numeric: tabular-nums; }
.group .m::after { content: "·"; color: var(--faint); margin-left: .55em; }

/* ---------------------------------------------------------------- Contact and footer */
.thanks { color: var(--muted); }
.foot { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); column-gap: var(--rail-gap); padding: var(--space-entry) var(--gut) max(1.75rem, env(safe-area-inset-bottom)); font-size: .9375rem; color: var(--muted); }
.foot .rail { position: static; }
.foot a, .foot button { color: var(--muted); }
.foot button { text-decoration: underline; text-decoration-color: var(--faint); text-underline-offset: .22em; }

/* ---------------------------------------------------------------- Wider screens */
@media (min-width: 760px) {
  .tiles { grid-auto-columns: 46%; }
}
@media (min-width: 1100px) {
  .prod { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); column-gap: var(--col-gap); align-items: start; }
  .prod .strip { grid-column: 1 / -1; margin-top: .75rem; }
  .tiles { grid-auto-flow: row; grid-template-columns: repeat(3, minmax(0, 1fr)); overflow: visible; gap: 1.25rem; padding-bottom: 0; }
}

/* ---------------------------------------------------------------- Narrower: the rail folds above its content (as on supreeth.in) */
@media (max-width: 899px) {
  .block, .foot { grid-template-columns: minmax(0, 1fr); }
  .rail { position: static; padding-top: 0; margin-bottom: 1.5rem; }
  .block--top .rail, .foot .rail { display: none; }
  .tiles { margin-right: calc(-1 * var(--gut)); padding-right: var(--gut); }
}
@media (max-width: 639px) {
  .group { grid-template-columns: minmax(0, 1fr); row-gap: .9rem; }
  .group h3, .group h2 { line-height: 1.4; }
}

/* ---------------------------------------------------------------- Reduced motion */
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition: none !important; } }

/* dark: light screenshots step down a little so they don't glare (as on supreeth.in) */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) :is(.ground, .tile) img:not(.dk-only) { filter: brightness(.88); } }
[data-theme="dark"] :is(.ground, .tile) img:not(.dk-only) { filter: brightness(.88); }

/* =================================================================== Inner pages (About first)
   Same rail and voices as the home page. A page opens with a serif title and a
   muted serif standfirst, as on supreeth.in's case studies. */
.title { font: 400 clamp(2.3rem, 1.1rem + 3.4vw, 4.4rem)/1.06 var(--serif); letter-spacing: -.018em; max-width: 15em; text-wrap: balance; }
.standfirst { margin-top: clamp(1.25rem, 3vh, 1.75rem); max-width: 34rem; font: 400 clamp(1.25rem, 1.1rem + .45vw, 1.5rem)/1.4 var(--serif); color: var(--muted); text-wrap: pretty; }
.prose { max-width: var(--text); }
.prose p { text-wrap: pretty; }
.prose p + p { margin-top: 1em; }

/* rows with a short left column: years on Product design, statuses on Side projects */
.refs { display: flex; flex-wrap: wrap; gap: 0 1.5rem; margin-top: .35rem; font-size: .9375rem; }
.refs a { display: inline-flex; flex-wrap: wrap; align-items: baseline; align-content: center; column-gap: .45rem; min-height: 44px; text-decoration: none; } /* a name and its kind wrap as one unit */
.refs .n { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .22em; text-decoration-color: var(--faint); transition: text-decoration-color .2s ease; }
.refs .k { color: var(--muted); white-space: nowrap; }
@media (hover: hover) and (pointer: fine) { .refs a:hover .n { text-decoration-color: var(--mark); } }

/* copy that still needs his words: drafts carry a light green highlight, placeholders stay grey and italic */
.draft { background: color-mix(in srgb, var(--mark) 11%, transparent); border-radius: 3px; box-decoration-break: clone; -webkit-box-decoration-break: clone; padding: 0 .12em; }
.tbd { font-style: italic; color: var(--muted); }


/* =================================================================== Boxes and hovers (27 Oct 2026)
   When something gets a box (revised 27 Oct, rev. 3):
   - A resting box (a ground) marks the choices the page steers you to: the three lengths and
     Selected work in 30 seconds. They carry an arrow on hover, or on tap (see "steering cards").
   - A ground also sits under every screenshot, since a picture needs something to stand on.
   - Text rows that open one page (No rush) get a box only while pointed at: the ghost ground.
   - Rows holding several links (an About role) and plain text (the pitch, the route, side
     projects, the email) never get a box.
   - Anything that can't be opened gets no hover at all (the screen tiles, side projects without
     a link yet), so nothing promises a click it can't keep.
   Hover is one gesture throughout: the link's underline turns green, and a screen, where there is
   one, rises 3–4px. Durations 200ms out, 450ms for screens; touch gets a press state instead. */

/* menu: the current page and the hovered one are underlined in green, drawn from the left */


/* hero figures open their case study: the screens rise, the ground deepens */
a.ground { text-decoration: none; color: inherit; transition: background-color .25s ease; }
a.ground:not(.phones) { display: block; }
.ground img { transition: transform .45s var(--ease); }
@media (hover: hover) and (pointer: fine) {
  a.ground:hover { background: var(--hover-lg); }
  a.ground:hover img.desk { transform: translateY(-3px); }
  a.ground:hover img.phone { transform: translateY(-6px); }
  a.ground.phones:hover img { transform: translateY(-4px); }
  a.ground.phones:hover img:nth-child(2) { transition-delay: 40ms; }
  a.ground.phones:hover img:nth-child(3) { transition-delay: 80ms; }
}

/* text links that act: Case study, Prototype, All work, the emails. The underline turns green and opens a little */
.act a { transition: text-decoration-color .2s ease, text-underline-offset .25s var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .act a:hover { text-underline-offset: .32em; }
}

/* No rush rows: a ghost ground behind the row while pointed at. The padding sits outside the
   text edge (negative margin), so at rest the list keeps one left edge with everything else. */
.group ol { gap: .55rem; }
.group li > a { position: relative; padding: .7rem .9rem .75rem; margin: 0 -.9rem; border-radius: var(--r-m); transition: background-color .2s ease; }
.group li > a:focus-visible { outline-offset: 0; }
.group .d { transition: color .2s ease; }
@media (hover: hover) and (pointer: fine) {
  .group li > a:hover { background: var(--ground); }
  .group li > a:hover .d { color: var(--ink); }
}
.group li > a:active { background: var(--ground); }

/* group names line up with the first title, which now sits inside its ghost padding */
.group h3, .group h2 { padding-top: .8rem; }
@media (max-width: 639px) { .group h3, .group h2 { padding-top: 0; } .group { row-gap: .2rem; } }

/* =================================================================== The steering cards (27 Oct, rev. 3)
   Cards with a resting ground mark the two choices the page wants made: how long you have
   (the lengths) and which product to open (Selected work). Everything else stays plain type,
   so these read as the places to click. At rest: a ground. Pointed at: the ground deepens one
   step and an arrow slides in, green like every pressable thing. On touch, the arrow shows for
   an instant on tap before the page moves (js/next.js). The arrow points where you'll go:
   down for a length (further down this page), right for a product (another page). */

/* clicking a length lands with the section's first line just under the header */
.tier { scroll-margin-top: calc(1.25rem - var(--space-sec)); }

.steer { position: relative; display: grid; align-content: start; gap: .2rem; border-radius: var(--r-m); background: var(--ground); text-decoration: none; transition: background-color .2s ease; -webkit-tap-highlight-color: transparent; }
.steer .arrow { position: absolute; top: 1rem; right: 1.1rem; width: 1.1rem; height: 1.1rem; color: var(--mark); opacity: 0; transition: opacity .2s ease, transform .3s var(--ease); }
.steer .arrow svg { display: block; width: 100%; height: 100%; }
.steer--down .arrow { transform: translateY(-5px); }
.steer--right .arrow { transform: translateX(-5px); }
.steer:focus-visible { outline-offset: 2px; }
.steer:focus-visible .arrow, .steer.is-going .arrow { opacity: 1; transform: none; }
.steer.is-going { background: var(--hover-sm); }
@media (hover: hover) and (pointer: fine) {
  .steer:hover { background: var(--hover-lg); }
  .steer:hover .arrow { opacity: 1; transform: none; }
}

/* the lengths */
.lengths { display: grid; gap: .6rem; margin-top: clamp(2.5rem, 6vh, 4rem); }
.lengths a { padding: 1.1rem 1.25rem 1.25rem; }
.lengths .len { padding-right: 1.75rem; font: 400 clamp(1.5rem, 1.2rem + .8vw, 1.9rem)/1.15 var(--serif); letter-spacing: -.01em; }
.lengths .len-what { color: var(--muted); font-size: .9375rem; max-width: 19rem; text-wrap: pretty; transition: color .2s ease; }
@media (hover: hover) and (pointer: fine) { .lengths a:hover .len-what { color: var(--ink); } }
@media (min-width: 640px) { .lengths { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .9rem; } }

/* 30 seconds: the pitch, ending on the ask and the email; Selected work beside it */
.pitch { display: grid; gap: 2.5rem; }
/* 30 seconds ends with the normal gap before 5 minutes (shrunk 27 Oct); after a click on "30 seconds",
   the top of 5 minutes may show below the email on tall screens. */
.pitch .say { max-width: var(--text); font-size: clamp(1.3rem, .9rem + 1.1vw, 2rem); line-height: 1.38; }
.pitch .say p + p { margin-top: .8em; }
.work-label { font-size: .9375rem; color: var(--muted); margin-bottom: .75rem; }
@media (min-width: 1100px) {
  .pitch { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); column-gap: var(--col-gap); align-items: start; }
}
@media (max-width: 899px) {
  #s30 .rail { margin-bottom: 1rem; }
  .pitch { gap: 2rem; }
  .pitch .say p + p { margin-top: .65em; }
}
/* narrow phones: the menu stays on one line */
/* short phones (iPhone SE and similar): a smaller statement, so the email lands on the first screen */
@media (max-width: 599px) and (max-height: 720px) { .pitch .say { font-size: 1.15rem; line-height: 1.36; } }

/* ---------------------------------------------------------------- 30 seconds, rev. 4
   Selected work: the stake sits above each card as its label; the card holds only the
   product and the role, so the three read as a compact set. */
.sr { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.steer--right.is-going .arrow, .steer--right:focus-visible .arrow { transform: none; }

/* the email: a box like the cards. On a computer it copies (js/next.js) and says so;
   on a phone it opens the mail app, with the same arrow-on-tap as the other cards. */
.mailbox { display: inline-grid; grid-template-columns: auto auto; align-items: center; column-gap: 1.5rem; margin-top: 1.25rem; padding: .7rem 1.15rem .8rem; }
.mailbox .addr { font: 400 clamp(1.4rem, 1.1rem + .9vw, 1.85rem)/1.2 var(--serif); letter-spacing: -.012em; }
.mailbox .mail-act { display: grid; justify-items: end; font-size: .875rem; color: var(--mark); }
.mail-act > span { grid-area: 1 / 1; display: inline-flex; align-items: center; gap: .35rem; white-space: nowrap; opacity: 0; transform: translateX(-4px); transition: opacity .2s ease, transform .3s var(--ease); }
.mail-act svg { width: .95rem; height: .95rem; }
@media (hover: hover) and (pointer: fine) {
  .mailbox:hover .do-copy, .mailbox:focus-visible .do-copy { opacity: 1; transform: none; }
  .mailbox.is-copied .do-copy { opacity: 0; }
  .mailbox.is-copied .done { opacity: 1; transform: none; }
  .mailbox .arrow { display: none; }
}
/* phones: no Copy label; the arrow shows on tap, as on the other cards */
@media (hover: none), (pointer: coarse) {
  .mailbox .mail-act { display: none; }
  .mailbox { grid-template-columns: auto; padding-right: 2.9rem; }
  .mailbox .arrow { top: 50%; margin-top: -.55rem; }
}
@media (max-width: 599px) and (max-height: 720px) { .mailbox .addr { font-size: 1.35rem; } .mailbox { margin-top: .9rem; } }

/* the closing email: the same copy box, at the size of a closing line */
.mailbox--big { margin-top: .9rem; padding: .9rem 1.4rem 1.05rem; column-gap: 2rem; }
.mailbox--big .addr { font-size: clamp(2rem, 1rem + 3.4vw, 3.75rem); letter-spacing: -.02em; line-height: 1.1; }
@media (hover: none), (pointer: coarse) { .mailbox--big { padding-right: 3.2rem; } }
@media (max-width: 420px) { .mailbox--big .addr { font-size: 1.75rem; } }

/* ---------------------------------------------------------------- No rush tabs (27 Oct)
   One small resting card per group, in the steering-card language (ground at rest, a step
   deeper on hover). They stay under the menu while No rush is on screen, and the group being
   read is marked (js/next.js): ink text on the deeper ground. On phones they scroll sideways. */
.tabs { position: sticky; top: 4.375rem; z-index: 10; display: flex; gap: .4rem; margin: 0 calc(-1 * var(--gut)) clamp(2rem, 5vh, 3rem) 0; padding: .6rem var(--gut) .7rem 0; background: var(--bg); overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.tabs::-webkit-scrollbar { display: none; }
.tabs a { flex: none; display: inline-flex; align-items: center; min-height: 38px; padding: 0 .95rem; border-radius: var(--r-m); background: var(--ground); color: var(--muted); font-size: .9375rem; text-decoration: none; white-space: nowrap; transition: background-color .2s ease, color .2s ease; -webkit-tap-highlight-color: transparent; }
.tabs a[aria-current="true"] { background: var(--hover-sm); color: var(--ink); }
.tabs a:focus-visible { outline-offset: 1px; }
@media (hover: hover) and (pointer: fine) { .tabs a:hover { background: var(--hover-lg); color: var(--ink); } }
.tabs a:active { background: var(--hover-sm); }
/* a jump lands the group just under the menu and the tabs */
.group { scroll-margin-top: 3rem; } /* plus the page's own 5.5rem scroll padding */
/* keyboard focus moving back up a list clears the menu and the tabs (home has no scroll padding) */
.home .group li > a { scroll-margin-top: 9rem; }
.role .refs a { scroll-margin-top: 3rem; }
@media (max-width: 899px) { .tabs { margin-left: calc(-1 * var(--gut)); padding-left: var(--gut); } }

/* ---------------------------------------------------------------- Email box hugs the address (27 Oct)
   "Copy"/"Copied" and the phone arrow sit just outside the box, so the box is only as long
   as the address. */
.mailbox, .mailbox--big { grid-template-columns: auto; padding-right: 1.15rem; }
.mailbox--big { padding-right: 1.4rem; }
.mailbox .mail-act { position: absolute; left: 100%; top: 50%; margin: -.6rem 0 0 .8rem; justify-items: start; pointer-events: none; }
.mailbox .arrow { top: 50%; right: auto; left: 100%; margin: -.55rem 0 0 .7rem; }
@media (hover: none), (pointer: coarse) { .mailbox, .mailbox--big { padding-right: 1.15rem; } }


/* ---------------------------------------------------------------- Text links, sorted (27 Oct)
   Three kinds of link, so how a link looks says how much it matters:
   1. The main next step: a resting box, arrow on hover (lengths, Selected work, the emails,
      and "Case study" in 5 minutes).
   2. Items in a list: no box at rest, a ghost box on hover (No rush rows, including All work
      and All writing as each list's last row).
   3. Secondary actions and links in sentences: a faint underline that turns green
      (Prototype, About's references, Now, the footer).
   One box per decision point: each product in 5 minutes has one box (Case study); Prototype
   is the quieter choice beside it. */

/* 5 minutes: Case study is the box, its reading time inside; the arrow appears just outside,
   in the space before Prototype, so the box never carries empty space */
.act { display: flex; flex-direction: column; align-items: flex-start; gap: .2rem; margin-top: 1.4rem; font-size: .9375rem; } /* the box, then the prototype on its own line, so the arrow beside the box points at nothing else */
.act .cta { display: inline-flex; align-items: baseline; gap: .55rem; min-height: 44px; align-items: center; padding: 0 1.05rem; border-radius: var(--r-m); color: var(--ink); font-size: .9375rem; }
.act .cta .m { color: var(--muted); font-size: .9375rem; transition: color .2s ease; }
.act .cta .m::before { content: "·"; margin-right: .55rem; color: var(--faint); }
.act .cta .arrow { top: 50%; right: auto; left: 100%; margin: -.55rem 0 0 .7rem; }
@media (hover: hover) and (pointer: fine) { .act .cta:hover .m { color: var(--ink); } }
.act a.proto { display: inline-flex; align-items: center; min-height: 44px; margin-left: 1.05rem; } /* lines up with the text inside the box */

/* All work, All writing: the list's last row, same as the rows above it */
.group li.all .t { color: var(--ink); }

/* 5 minutes: the text from supreeth.in, a role line then one description (27 Oct) */
.prod .meta + .what { margin-top: 1rem; }

/* 5 minutes, rev. 2: "Case study" box with Prototype beside it. The arrow appears inside the box:
   on hover the words nudge left into the padding and the arrow fades in where they were, so the
   box keeps its size and nothing beside it moves. */
.act { flex-direction: row; align-items: center; gap: .4rem 1.6rem; }
.act a.proto { margin-left: 0; }
.act .cta { position: relative; padding: 0 1.25rem; }
.act .cta .label { display: inline-block; transition: transform .3s var(--ease); }
.act .cta .arrow { left: auto; right: .55rem; margin: -.5rem 0 0; width: 1rem; height: 1rem; }
.act .cta:hover .label, .act .cta:focus-visible .label, .act .cta.is-going .label { transform: translateX(-.6rem); }
@media (hover: none), (pointer: coarse) { .act .cta:hover .label { transform: none; } .act .cta.is-going .label { transform: translateX(-.6rem); } }
.act .cta .label { color: var(--ink); } /* an older ".act span" rule greys spans in this row */

/* ---------------------------------------------------------------- Side projects as rows; the Work page (27 Oct)
   A side project without a live link is a plain row: same type as the rows that open
   something, no hover. Once a project has an address, its row becomes a link like the rest. */
.group li .row { display: grid; gap: .2rem; padding: .7rem 0 .75rem; }

/* Work: the page head, then the same tabs and groups as No rush. A group's label column holds
   the role's years; the role's pieces are text links (kind 3), since a role has several. */
.block--list { padding-top: clamp(2.5rem, 6vh, 4rem); }
.role { padding-top: .7rem; }
.role .t { font: 400 clamp(1.4rem, 1.2rem + .5vw, 1.7rem)/1.2 var(--serif); letter-spacing: -.01em; }
.role .d { margin-top: .4rem; color: var(--muted); }
.role .refs { margin-top: .5rem; }

/* ---------------------------------------------------------------- Writing and Contact (27 Oct)
   Writing: the No rush rows with each essay's one-line summary under its meta. Contact has
   its own section further down. */
.essays .x { margin-top: .3rem; font-size: .9375rem; color: var(--muted); text-wrap: pretty; transition: color .2s ease; }
@media (hover: hover) and (pointer: fine) { .essays a:hover .x { color: var(--ink); } }
.block--top .standfirst + .mailbox { margin-top: 2rem; }
/* About's role rows line up with Work's: the years in the same 10rem label column, names at the same size */
/* narrow windows: "Copy" / "Copied" sit under the box, so nothing reaches past the screen edge */
@media (max-width: 560px) {
  .mailbox .mail-act { left: auto; right: .2rem; top: 100%; margin: .35rem 0 0; justify-items: end; }
  .mail-act > span { transform: translateY(-3px); }
}
/* the footer's theme switch answers like the link beside it */
.foot button { transition: text-decoration-color .2s ease, color .2s ease; }
@media (hover: hover) and (pointer: fine) { .foot button:hover { text-decoration-color: var(--mark); } }
.foot button:focus-visible { text-decoration-color: var(--mark); }

/* =================================================================== Case studies and essays (27 Oct)
   The v4 content, word for word, in the v5 frame. The rail holds what a section is (Case study
   1 of 3, 30 seconds, the contents); the column holds the thing. Rules as everywhere else:
   no text in standing boxes (decisions, personas, what shipped are plain columns); screens stand
   on a ground; the prototype links and the next page are steering cards. */
.cs-prose, .es-prose { max-width: 52rem; }
.cs-prose > *, .es-prose > * { max-width: var(--text); }
.cs-prose > .fig, .es-prose > .fig, .cs-prose > .dec, .cs-prose > .people, .cs-prose > .after,
.cs-prose > .system, .cs-prose > .try, .cs-prose > .route { max-width: none; }

/* the head */
.cs-intro { margin-top: 1.25rem; max-width: var(--text); text-wrap: pretty; }
.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: 1rem 1.5rem; margin-top: 2.25rem; max-width: 52rem; }
.facts dt { font-size: .875rem; color: var(--muted); }
.facts dd { margin: .15rem 0 0; font-size: .9375rem; text-wrap: pretty; }
.es-title { font-size: clamp(2.2rem, 1.1rem + 3vw, 3.9rem); max-width: 18em; }

/* the cover */
.cs-cover { padding-top: clamp(2.5rem, 6vh, 4rem); }
.cover .fig-ground { border-radius: var(--r-m); background: var(--ground); padding: clamp(.9rem, 3vw, 2rem); }
.cover-grid { position: relative; padding-right: 21%; }
.cover-grid .cover-desktop { width: 100%; border-radius: var(--r-s); outline: 1px solid var(--rim); outline-offset: -1px; box-shadow: var(--shade); }
.cover-grid .cover-phone { position: absolute; right: 0; bottom: 0; width: 24%; height: 86%; object-fit: cover; object-position: top; border-radius: var(--r-phone); outline: 1px solid var(--rim); outline-offset: -1px; box-shadow: var(--shade); }

/* 30 seconds: label and line, then the two ways in as pills */
.cs-short ol { display: grid; gap: 1rem; max-width: calc(9rem + 1.5rem + var(--text)); }
.cs-short li { display: grid; grid-template-columns: 9rem minmax(0, 1fr); column-gap: 1.5rem; }
.cs-short li b { font-weight: 400; color: var(--muted); font-size: .9375rem; padding-top: .1rem; }
.cs-short li span { text-wrap: pretty; }
@media (max-width: 639px) { .cs-short li { grid-template-columns: minmax(0, 1fr); row-gap: .15rem; } }

/* the contents, in the rail; the section being read is marked (js/site.js) */
.toc { font-size: .9375rem; line-height: 1.35; }
.toc .toc-title { color: var(--ink); margin-bottom: .6rem; }
.toc ol { display: grid; gap: .15rem; }
.toc a { display: block; padding: .25rem 0; color: var(--muted); text-decoration: none; transition: color .2s ease; }
.toc a[aria-current] { color: var(--ink); }
@media (hover: hover) and (pointer: fine) { .toc a:hover { color: var(--ink); } }
@media (max-width: 899px) { .toc ol { display: flex; flex-wrap: wrap; gap: 0 1.1rem; } .toc a { padding: .6rem 0; } }

/* prose */
.cs-prose p + p, .es-prose p + p { margin-top: 1em; }
.cs-prose > * + *, .es-prose > * + * { margin-top: 1rem; }
.cs-prose p, .es-prose p, .cs-prose li, .es-prose li { text-wrap: pretty; }
.cs-prose .sec { margin-top: clamp(4rem, 10vh, 6rem); font-size: .9375rem; color: var(--muted); }
.cs-prose > .sec:first-child { margin-top: 0; }
.cs-prose h2, .es-prose h2 { margin-top: .35rem; font: 400 clamp(1.9rem, 1.3rem + 1.6vw, 2.6rem)/1.1 var(--serif); letter-spacing: -.018em; text-wrap: balance; max-width: 22ch; scroll-margin-top: 6rem; }
.es-prose h2 { margin-top: 3rem; font-size: clamp(1.5rem, 1.2rem + .9vw, 2rem); max-width: 26ch; }
.cs-prose .intro, .cs-prose .outcome { font-size: 1.125rem; }
.cs-prose .note, .cs-prose .tradeoff, .cs-prose .small-note { color: var(--muted); font-size: .9375rem; }
.cs-prose .small-note { font-size: .875rem; }
.cs-prose .ui-copy, .es-prose .ui-copy { font-style: italic; }
.cs-prose > ul:not([class]), .es-prose > ul:not([class]) { padding-left: 1.2rem; list-style: disc; }
.cs-prose > ol:not([class]), .es-prose > ol:not([class]) { padding-left: 1.2rem; list-style: decimal; }
.cs-prose li + li, .es-prose li + li { margin-top: .4rem; }
.es-prose strong, .cs-prose strong { font-weight: 500; }
.cs-prose blockquote, .es-prose blockquote { margin: 2rem 0; font: 400 clamp(1.35rem, 1.15rem + .6vw, 1.65rem)/1.35 var(--serif); letter-spacing: -.006em; }
.cs-prose blockquote p + p { margin-top: .6rem; }
.cs-prose .closing, .es-prose .closing { margin-top: 2rem; font: 400 clamp(1.25rem, 1.1rem + .5vw, 1.5rem)/1.38 var(--serif); }
.asks { display: grid; gap: .5rem; }
.asks li { font: 400 clamp(1.25rem, 1.1rem + .4vw, 1.45rem)/1.3 var(--serif); }
.asks li + li { margin-top: 0; }
.terms { display: grid; gap: .75rem; margin-top: 1.25rem; }
.terms > div { display: grid; grid-template-columns: 7rem minmax(0, 1fr); column-gap: 1.5rem; }
.terms dt { color: var(--muted); font-size: .9375rem; padding-top: .1rem; }
.terms dd { margin: 0; }

/* the route: in-page links to the decisions, as list rows (a ghost box on hover) */
.route { margin-top: 1.5rem; }
.route ol { display: grid; gap: .1rem; max-width: var(--text); }
.route a { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 1rem; align-items: baseline; padding: .65rem .9rem; margin: 0 -.9rem; border-radius: var(--r-m); text-decoration: none; transition: background-color .2s ease; }
.route b { font: 400 1.2rem/1.3 var(--serif); }
.route span { font-size: .9375rem; color: var(--muted); text-align: right; transition: color .2s ease; }
@media (hover: hover) and (pointer: fine) { .route a:hover { background: var(--ground); } .route a:hover span { color: var(--ink); } }
.route a:active { background: var(--ground); }

/* a decision: where it sits on the path, the headline, then chose / instead of / cost as plain rows */
.dec { margin-top: clamp(3rem, 8vh, 4.5rem); scroll-margin-top: 6rem; }
.dec > * + * { margin-top: 1rem; }
.dec > p { max-width: var(--text); }
.stop { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .7rem; font-size: .9375rem; color: var(--muted); }
.dec h3 { margin-top: .5rem; font: 400 clamp(1.55rem, 1.2rem + 1.1vw, 2.1rem)/1.12 var(--serif); letter-spacing: -.012em; text-wrap: balance; max-width: 24ch; scroll-margin-top: 6rem; }
.ledger-aside { display: grid; gap: .55rem; margin-top: 1.25rem; max-width: var(--text); font-size: .9688rem; }
.ledger-aside > div { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr); column-gap: 1.5rem; }
.ledger-aside dt { color: var(--muted); }
.ledger-aside dd { margin: 0; text-wrap: pretty; }
@media (max-width: 460px) { .ledger-aside > div, .terms > div { grid-template-columns: minmax(0, 1fr); } }

/* people, what shipped, the system: plain columns */
.people, .after, .system { display: grid; gap: 2rem 2.5rem; margin-top: 1.75rem; }
.person > * + * { margin-top: .5rem; }
.person .label { font-size: .875rem; color: var(--muted); }
.person h3 { margin-top: .2rem; font: 400 1.0625rem/1.3 var(--sans); }
.person .q { font: 400 clamp(1.35rem, 1.15rem + .6vw, 1.65rem)/1.2 var(--serif); text-wrap: balance; }
.person p:not(.q):not(.label):not(.imp) { color: var(--muted); }
.person .imp { color: var(--ink); }
.after h3, .system h3 { font: 400 1.3rem/1.25 var(--serif); }
.after p, .system p { margin-top: .45rem; color: var(--muted); text-wrap: pretty; }
@media (min-width: 640px) { .people, .after, .system { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* figures */
.fig { margin-top: 2rem; }
.cs-prose .fig, .dec .fig, .es-prose .fig { margin-top: 2rem; margin-bottom: .5rem; }
.fig-ground { position: relative; border-radius: var(--r-m); background: var(--ground); padding: clamp(.75rem, 2.4vw, 1.5rem); }
.fig-ground img, .fig-ground video { width: 100%; border-radius: var(--r-s); outline: 1px solid var(--rim); outline-offset: -1px; box-shadow: var(--shade); background: var(--bg); }
.figcap { display: flex; flex-wrap: wrap; align-items: baseline; gap: .1rem .6rem; margin-top: .7rem; font-size: .875rem; color: var(--muted); max-width: var(--text); text-wrap: pretty; }
.figcap .n { color: var(--ink); }
.figcap .t { flex: 1 1 18rem; }
.pair, .frames, .duo { display: grid; gap: .9rem; }
.fig--phone, .fig--phones, .fig--portrait { max-width: var(--text); }
.fig--phone .fig-ground > img, .fig--phone .fig-ground > video, .fig-ground > img.phone, .fig-ground > video.phone { width: min(100%, 17rem); margin: 0 auto; border-radius: var(--r-phone); }
.pair .phone, .pair > img, .pair > video { width: min(100%, 15rem); margin: 0 auto; border-radius: var(--r-phone); }
.duo--phones { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(.6rem, 2.5vw, 1.25rem); max-width: 34rem; margin: 0 auto; }
.duo--phones img { border-radius: var(--r-phone); }
.frames .frame { display: grid; gap: .5rem; justify-items: center; }
.frames .phone { width: min(100%, 15rem); border-radius: var(--r-phone); }
.fig--plate .fig-ground img { border-radius: 4px; }
.fig--portrait .fig-ground img { width: min(100%, 22rem); margin: 0 auto; }
.frag .fig-ground { display: grid; gap: clamp(.75rem, 2.4vw, 1.25rem); }
.frag .fig-ground .bank-detail { width: min(100%, 24rem); }
@media (min-width: 640px) { .pair { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; } .frames { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 639px) {
  .frames { grid-auto-flow: column; grid-auto-columns: 72%; overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: .5rem; scrollbar-width: thin; }
  .frames .frame { scroll-snap-align: start; }
  .fig--phone .fig-ground > img, .fig--phone .fig-ground > video, .fig-ground > img.phone, .fig-ground > video.phone { width: min(100%, 15rem); }
}
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) :is(.fig-ground, .cover) img:not(.cover-dark):not(.shot-dark) { filter: brightness(.88); } }
[data-theme="dark"] :is(.fig-ground, .cover) img:not(.cover-dark):not(.shot-dark) { filter: brightness(.88); }

/* try it: the prototypes as steering cards */
.try { display: grid; gap: .9rem; margin-top: 1.75rem; }
.try a { padding: 1.1rem 1.25rem 1.2rem; }
.try b { padding-right: 1.75rem; font: 400 1.45rem/1.2 var(--serif); letter-spacing: -.01em; }
.try span:not(.arrow) { color: var(--muted); font-size: .9375rem; transition: color .2s ease; }
@media (hover: hover) and (pointer: fine) { .try a:hover span:not(.arrow) { color: var(--ink); } }
@media (min-width: 640px) { .try { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* the end of every case study and essay: the next piece, as a steering card */
.next-card { max-width: 34rem; padding: 1.3rem 1.5rem 1.45rem; gap: .3rem; }
.next-card .k { font-size: .9375rem; color: var(--muted); }
.next-card .t { padding-right: 2rem; font: 400 clamp(1.8rem, 1.2rem + 1.8vw, 2.6rem)/1.08 var(--serif); letter-spacing: -.018em; }
.next-card .arrow { top: 1.4rem; right: 1.4rem; }
.also { display: flex; flex-wrap: wrap; gap: 0 1.5rem; margin-top: .75rem; font-size: .9375rem; }
.also a { display: inline-flex; align-items: center; min-height: 44px; }
.cs-main { scroll-margin-top: 0; }
/* phones: a case study's and an essay's label ("Case study 2 of 3", "Essay") stays, above the title */
@media (max-width: 899px) { .cs-top .rail, .es-top .rail { display: block; margin-bottom: 1rem; } }
/* an essay's section break is space, not a line */
.es-prose hr, .cs-prose hr { border: 0; height: 0; margin: 2.5rem 0 0; }

/* ---------------------------------------------------------------- Case studies and essays: audit fixes (27 Oct)
   Type: Geist at 14 / 15 / 17 (plus 16 in the rail); serif at 20 / 23 / 24 / 32 / 42 / title.
   Space: 16 between paragraphs, 28 from a paragraph to the block it introduces, 32 around
   figures, 72 between decisions, 90 between sections. */

/* headings whose lines were written by hand keep those lines on wider screens */
@media (min-width: 640px) { .cs-prose h2:has(br), .dec h3:has(br) { max-width: none; } }
/* on phones the written breaks drop and the browser balances the lines instead */
@media (max-width: 639px) { .cs-prose h2 br, .dec h3 br { display: none; } .cs-prose h2, .dec h3 { text-wrap: balance; } }
.cs-prose blockquote, .es-prose blockquote, .person .q { text-wrap: pretty; }

/* type onto the scale */
.cs-prose .intro, .cs-prose .outcome { font-size: 1.0625rem; }
.ledger-aside { font-size: .9375rem; }
.route b, .after h3, .system h3 { font-size: 1.25rem; line-height: 1.3; }
.person .q, .cs-prose blockquote, .es-prose blockquote { font-size: 1.45rem; line-height: 1.3; }
.dec h3 { font-size: clamp(1.55rem, 1.2rem + 1.1vw, 2rem); }
.cs-prose .closing, .es-prose .closing { font-size: clamp(1.25rem, 1.1rem + .45vw, 1.5rem); }
/* emphasis in body text switches voice, as on supreeth.in: the serif, not a heavier Geist */
.es-prose strong, .cs-prose strong { font-family: var(--serif); font-weight: 400; font-size: 1.06em; color: var(--ink); }

/* space onto the rhythm */
.route, .terms { margin-top: 1.75rem; }
.cs-prose .fig + *, .es-prose .fig + *, .dec .fig + * { margin-top: 2rem; }
.cs-prose > .fig + .sec { margin-top: clamp(4rem, 10vh, 6rem); } /* a section after a figure keeps the section gap */
.cs-prose .fig, .es-prose .fig, .dec .fig { margin-bottom: 0; }

/* the essays' charts sit at the reading width, where their pixels hold up on sharp screens */
.es-prose > .fig--plate { max-width: var(--text); }
/* inline code (permission names, identifiers): one size step down, on the ground */
.cs-prose code, .es-prose code { font: .875em/1 ui-monospace, "SF Mono", Menlo, Consolas, monospace; padding: .12em .35em; border-radius: 4px; background: var(--ground); }

/* ---------------------------------------------------------------- The menu, in the v5 language (27 Oct)
   The page you're on sits in a resting pill, like the marked No rush tab; the others are plain
   words that take the same pill on hover, like the No rush rows. No underline. The name on the
   left goes home and answers with an ink colour change only. */
.head-name { display: inline-flex; align-items: center; min-height: 40px; color: var(--ink); }
.head ul { display: flex; gap: .2rem; margin-right: -.8rem; }
.head ul a { display: inline-flex; align-items: center; min-height: 40px; padding: 0 .8rem; border-radius: var(--r-m); color: var(--muted); text-decoration: none; transition: background-color .2s ease, color .2s ease; -webkit-tap-highlight-color: transparent; }
.head ul a[aria-current="page"] { background: var(--hover-sm); color: var(--ink); }
.head ul a:focus-visible { outline-offset: 1px; }
@media (hover: hover) and (pointer: fine) { .head ul a:not([aria-current]):hover { background: var(--ground); color: var(--ink); } }
.head ul a:active { background: var(--ground); }
/* narrow phones: tighter pills, so the name and all four fit on one line from 320px */
@media (max-width: 420px) { .head { gap: .4rem .5rem; } .head ul { gap: 0; margin-right: -.55rem; } .head ul a { padding: 0 .55rem; font-size: .9375rem; } .head-name { font-size: .9375rem; } }
@media (max-width: 359px) { .head { gap: .25rem; } .head ul a { padding: 0 .38rem; font-size: .875rem; } .head-name { font-size: .875rem; } .head ul { margin-right: -.38rem; } }

/* ---------------------------------------------------------------- Now and 404 (27 Oct) */
.group .now-d { color: var(--ink); font-size: 1.0625rem; max-width: var(--text); }
.lost-try { max-width: 52rem; margin-top: 2.5rem; }
@media (min-width: 900px) { .lost-try { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* Geist has no italic, so italic never rendered. Book titles, quoted interface labels and other
   emphasis inside Geist text switch to the serif instead, as the lead-ins do. */
.cs-prose .ui-copy, .es-prose .ui-copy, :is(.cs-prose, .es-prose, .group .now-d, .say) :is(i, em) { font-family: var(--serif); font-style: normal; font-size: 1.06em; }

/* ---------------------------------------------------------------- Selected and hover, swapped (27 Oct)
   Selected (the menu's page, the tab being read) is the light ground pill; hover is the deeper
   step. Tabs are plain words at rest, like the menu, so the selected one reads. The pills in a
   case study's 30 seconds stay resting cards (ground at rest, the deeper step on hover). */
.head ul a[aria-current="page"] { background: var(--ground); color: var(--ink); }
.tabs:not(.tabs--static) a { background: transparent; }
.tabs:not(.tabs--static) a[aria-current="true"] { background: var(--ground); color: var(--ink); }
@media (hover: hover) and (pointer: fine) {
  .head ul a:not([aria-current]):hover, .tabs:not(.tabs--static) a:not([aria-current]):hover { background: var(--hover-sm); color: var(--ink); }
}
.head ul a:active, .tabs a:active { background: var(--hover-sm); }
/* tabs as plain words: the row lines up with the column's text edge */
.tabs:not(.tabs--static) { margin-left: -.95rem; }
@media (max-width: 899px) { .tabs:not(.tabs--static) { margin-left: calc(-1 * var(--gut)); padding-left: calc(var(--gut) - .95rem); } }

/* ---------------------------------------------------------------- Tabs as ghost buttons (27 Oct)
   No rush and Work: each tab carries a hairline outline at rest, so the row reads as tabs before any
   hover. Selected: the light ground, no outline. Hover: the deeper step, no outline. */
.tabs:not(.tabs--static) { margin-left: -4px; padding-left: 4px; } /* room for the first tab's focus ring inside the scroller (7 Nov 2026) */
@media (max-width: 899px) { .tabs:not(.tabs--static) { margin-left: calc(-1 * var(--gut)); padding-left: var(--gut); } }
.tabs:not(.tabs--static) a { box-shadow: inset 0 0 0 1px var(--faint); }
.tabs:not(.tabs--static) a[aria-current="true"] { box-shadow: none; }
@media (hover: hover) and (pointer: fine) { .tabs:not(.tabs--static) a:not([aria-current]):hover { box-shadow: none; } }
.tabs:not(.tabs--static) a:active { box-shadow: none; }

/* ---------------------------------------------------------------- Narrow screens and page zoom (27 Oct)
   At Safari's 150% or 200% page zoom an iPhone lays the page out at 262px or 196px. Nothing may
   be wider than the screen: the address shrinks with the screen (never larger than its design
   size), the box leaves room for the tap arrow beside it, and long titles may break anywhere. */
.mailbox { max-width: calc(100% - 2.2rem); }
.mailbox .addr { font-size: min(clamp(1.4rem, 1.1rem + .9vw, 1.85rem), calc((100vw - 7rem) / 8.2)); overflow-wrap: anywhere; }
.mailbox--big .addr { font-size: min(clamp(2rem, 1rem + 3.4vw, 3.75rem), calc((100vw - 7.5rem) / 8.2)); }
@media (max-width: 420px) { .mailbox--big .addr { font-size: min(1.75rem, calc((100vw - 7.5rem) / 8.2)); } }
.next-card .t, .title, .statement, .group .t, .lengths .len { overflow-wrap: anywhere; }
.next-card { max-width: min(34rem, 100%); }
.next-card .t { font-size: min(clamp(1.8rem, 1.2rem + 1.8vw, 2.6rem), calc((100vw - 6rem) / 8)); }
/* the menu may wrap under the name rather than push past the edge */
@media (max-width: 300px) { .head { flex-wrap: wrap; } .head ul { flex-wrap: wrap; margin-right: 0; } }
.strip, .try { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 640px) { .try { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 900px) { .lost-try { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.try a, .try b, .lost-try b { min-width: 0; overflow-wrap: anywhere; }
.prod { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1100px) { .prod { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); } }
@media (max-width: 599px) and (max-height: 720px) { .mailbox .addr { font-size: min(1.35rem, calc((100vw - 7rem) / 8.2)); } }
.mailbox .addr { overflow-wrap: normal; white-space: nowrap; }
@media (max-width: 300px) { .head ul { margin-left: -.45rem; } }

/* ---------------------------------------------------------------- Phones: one tap copies and opens the mail app (28 Oct)
   If no mail app opens, "Copied" appears under the box (js/next.js). No extra control. */
@media (hover: none), (pointer: coarse) {
  .mailbox .mail-act { display: grid; position: absolute; left: auto; right: .2rem; top: 100%; margin: .35rem 0 0; justify-items: end; pointer-events: none; }
  .mailbox .do-copy { display: none; }
  .mailbox.is-copied .done { opacity: 1; transform: none; }
}

/* Work: two tabs (Product work, Side projects); the roles sit together under the first */
.tab-group { display: grid; gap: clamp(3rem, 7vh, 4.5rem); scroll-margin-top: 3rem; }

/* ---------------------------------------------------------------- 30 seconds, option B (28 Oct)
   The opening line carries the emphasis by size; the two sentences read in one colour, smaller. */
.pitch .say { font-size: clamp(1.25rem, 1.1rem + .4vw, 1.5rem); line-height: 1.42; color: var(--ink); }
.pitch .say b { color: inherit; }
.pitch .say p + p { margin-top: .75em; }

/* =================================================================== Footer (28 Oct)
   Pages that don't already end on the ask (work, case studies, writing, essays, Now, 404) close with
   it: "Hiring?", the pitch's own line and the email. Home, About and Contact, which end on the ask,
   get only the quiet line: the year and the theme switch. */
html body .foot { display: block; padding: 0; color: var(--muted); font-size: .9375rem; }
.foot .base { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: .5rem 1.5rem; max-width: calc(var(--measure) + var(--rail) + var(--rail-gap) + 2 * var(--gut)); padding: var(--space-entry) var(--gut) max(1.75rem, env(safe-area-inset-bottom)) calc(var(--gut) + var(--rail) + var(--rail-gap)); }
.foot--ask .base { padding-top: 3rem; }
.foot .base button { color: var(--muted); text-decoration: underline; text-decoration-color: var(--faint); text-underline-offset: .22em; min-height: 44px; transition: text-decoration-color .2s ease, color .2s ease; }
@media (hover: hover) and (pointer: fine) { .foot .base button:hover { color: var(--ink); text-decoration-color: var(--mark); } }
.foot .base button:focus-visible { text-decoration-color: var(--mark); }
.foot .ask-band { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); column-gap: var(--rail-gap); padding: var(--space-entry) var(--gut) 0; }
html body .foot .ask-band .rail { display: block; position: static; }
.foot .ask-band .rail h2 { font: 400 .9375rem/1.4 var(--sans); color: var(--ink); }
.foot .ask-text { max-width: 30rem; font: 400 var(--t24, 1.5rem)/1.38 var(--serif); color: var(--ink); text-wrap: pretty; }
.foot .ask-band .mailbox { margin-top: 1.1rem; color: var(--ink); }
@media (max-width: 899px) {
  .foot .ask-band { grid-template-columns: minmax(0, 1fr); }
  html body .foot .ask-band .rail { margin-bottom: .75rem; }
  .foot .base { padding-left: var(--gut); }
}

/* Selected work jumps to its product in 5 minutes: land with the product name just under the menu */
.prod { scroll-margin-top: .5rem; } /* the page already keeps 5.5rem clear for the menu */

/* =================================================================== Type scale (28 Oct)
   Serif steps 20 / 24 / 30 / 40 / 60 / 84 at desktop, each one step down on phones; Geist 14 / 15 / 17.
   Earlier per-element sizes above are overridden here; set new text to one of these steps. */
/* type scale: serif 20 / 24 / 30 / 40 / 60 / 84 at 1440; phones at the step below */
:root {
  --t20: 1.25rem;
  --t24: clamp(1.25rem, calc(1.25rem + 4 * (100vw - 390px) / 1050), 1.5rem);
  --t30: clamp(1.5rem,  calc(1.5rem + 6 * (100vw - 390px) / 1050), 1.875rem);
  --t40: clamp(1.875rem, calc(1.875rem + 10 * (100vw - 390px) / 1050), 2.5rem);
  --t60: clamp(2.5rem, calc(2.5rem + 20 * (100vw - 390px) / 1050), 3.75rem);
  --t84: clamp(2.5rem, calc(2.5rem + 44 * (100vw - 390px) / 1050), 5.25rem);
}
html body .statement { font-size: var(--t84); }
html body .title, html body .es-title { font-size: var(--t60); }
html body .prod h3, html body .cs-prose h2, html body .next-card .t { font-size: var(--t40); }
html body .dec h3, html body .es-prose h2, html body .lengths .len { font-size: var(--t30); }
html body .standfirst, html body .person .q, html body .cs-prose blockquote, html body .es-prose blockquote, html body .closing,
html body .try b, html body .asks li, html body .role .t, html body .pitch .say, html body .mailbox .addr { font-size: var(--t24); }
html body .mailbox--big .addr { font-size: min(var(--t60), calc((100vw - 7.5rem) / 8.2)); }
html body .group .t, html body .route b, html body .after h3, html body .system h3, html body .tiles + * { font-size: var(--t20); }
html body .rail, html body .rail h2, html body .rail p { font-size: .9375rem; }

/* =================================================================== Decisions of 28 Oct
   About's ask reads in one colour, like 30 seconds. Screenshots lose their outline (the ground
   and the shadow are enough). No tightened letter spacing anywhere. Availability sits between
   the ask and the email, in Geist, so it reads as a fact rather than part of the pitch. */
:is(.ground, .tile, .fig-ground, .cover, .stage, .hero) :is(img, video) { outline: 0 !important; }
.fig-ground video:focus-visible { outline: 2px solid var(--mark) !important; outline-offset: 2px; } /* a recording takes focus (click or Space pauses it): it shows the ring */
html body, html body * { letter-spacing: normal !important; }
.pitch .avail + .mailbox, .foot .avail + .mailbox { margin-top: .9rem; }
/* the address keeps its shrink-to-fit on narrow screens under the type scale */
html body .mailbox .addr { font-size: min(var(--t24), calc((100vw - 7rem) / 8.2)); }
html body .mailbox--big .addr { font-size: min(var(--t60), calc((100vw - 7.5rem) / 8.2)); }

/* =================================================================== Home as slides (2 Nov)
   The home page reads like a presentation: each part fills the screen and holds one idea.
   The hero is only the question and the three lengths, with no menu; the menu fades in once the
   hero is behind you. "30 seconds" lands on a slide that is the whole screen. Each product in
   5 minutes is its own slide. Scrolling settles a slide into place when you stop near its edge
   (proximity, so long slides like No rush still scroll freely). */
html:has(body.home) { scroll-padding-top: 0; scroll-snap-type: y proximity; }
@media (prefers-reduced-motion: reduce) { html:has(body.home) { scroll-snap-type: none; } } /* the page moves only when the reader moves it */
.home .slide { min-height: 100svh; scroll-snap-align: start; scroll-margin-top: 0; }
.home .tier { scroll-margin-top: 0; }
/* a slide's content sits in the middle of the screen, clear of the menu above it */
.home .block.slide { padding-top: 5.5rem; padding-bottom: 3rem; align-content: center; }
.home .slide--hero { padding-top: 3rem; }
.home .slide--hero .body { align-self: center; }
/* 5 minutes: the section is a run of slides; its label stays in the rail across them */
.home .block.slides { padding-top: 0; }
.home .prod.slide { padding: 5.5rem 0 3rem; align-content: center; }
.home .prod + .prod { margin-top: 0; }
.home .block.slides .rail { padding-top: 5.85rem; align-self: start; }
/* the last slide: the thank-you and the email, then the quiet footer line */
.home .slide--end { min-height: calc(100svh - 7rem); }
.home .foot .base { padding-top: 2rem; }

/* the menu on the home page: hidden while the hero is on screen */
.home .head { transition: opacity .35s var(--ease), transform .35s var(--ease); }
html.hero-in-view .home .head { opacity: 0; transform: translateY(-.75rem); pointer-events: none; transition: opacity .25s ease, transform .25s ease; }
html.hero-in-view .home .head:focus-within { opacity: 1; transform: none; pointer-events: auto; } /* the keyboard still reaches the menu */
.home .head { margin-bottom: -4.375rem; } /* the menu floats over the slides instead of pushing the hero down */

@media (max-width: 899px) {
  .home .block.slide { padding-top: 5rem; padding-bottom: 2.5rem; }
  .home .prod.slide { padding: 5rem 0 2.5rem; }
  .home .block.slides .rail { padding-top: 5rem; position: static; }
}
/* slides fixes (3 Nov): products start-aligned so the "5 minutes" label lines up; phone 30s fits one screen */
.home .prod.slide { align-content: start; }
.home .block.slides .rail { padding-top: 5.5rem; top: 0; }
@media (max-width: 899px) { .home #s30.slide { padding-bottom: 1.25rem; } }
/* product slides fit one screen on desktop (3 Nov audit) */
@media (min-width: 1100px) {
  .home .prod.slide .tile { aspect-ratio: auto; height: var(--tile-h, 13rem); }
  .home .prod.slide { padding-bottom: 2rem; }
  .home .prod.slide .strip { margin-top: 0; }
  .home .prod.slide .hero .ground { text-align: center; }
}
.home .slide--hero .statement { text-wrap: balance; }
/* hero: the block centred on the page, text left-aligned (3 Nov) */
@media (min-width: 900px) {
  .home .slide--hero { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  .home .slide--hero .rail { display: none; }
  .home .slide--hero .body { width: min(100%, 56rem); }
}

/* 30 seconds, Nov 2026: a short note to recruiters, large, in one column. The email is a link
   (.maillink, below); Selected work is a small row of three after it, like a P.S. */
.pitch.pitch--letter { grid-template-columns: minmax(0, 1fr); }
html body .pitch.pitch--letter .say { max-width: 47.5rem; font-size: var(--t30); line-height: 1.36; }
.pitch--letter .say p + p { margin-top: .65em; }
.pitch--letter .say + .maillink { margin-top: 2.25rem; }
.pitch--letter .work-label { margin: 4rem 0 .5rem; font-size: .875rem; }
.pitch-row { display: flex; flex-wrap: wrap; gap: .4rem 2.25rem; font: 400 .9375rem/1.5 var(--sans); }
.pitch-row a { color: var(--ink); text-decoration: none; }
.pitch-row .pr-name { text-decoration: underline; text-decoration-color: var(--faint); text-decoration-thickness: 1px; text-underline-offset: .2em; transition: text-decoration-color .2s ease; }
.pitch-row .d { color: var(--muted); }
/* on hover a small green down arrow opens beside the name: these links jump down to 5 minutes */
.pr-arr { position: absolute; left: 100%; top: .25em; display: inline-block; width: .8em; height: .8em; margin-left: .3em; color: var(--mark); opacity: 0; vertical-align: -.06em; transform: translateY(-3px); transition: opacity .2s ease, transform .3s var(--ease); } /* out of flow, in the gap: nothing beside it moves (.pitch-row a is position: relative below) */
.pr-arr svg { display: block; width: .8em; height: .8em; }
@media (hover: hover) and (pointer: fine) {
  .pitch-row a:hover .pr-name, .pitch-row a:focus-visible .pr-name { text-decoration-color: var(--mark); }
  .pitch-row a:hover .pr-arr, .pitch-row a:focus-visible .pr-arr { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .pr-arr { transition: none; } }
@media (max-width: 599px) { .pitch--letter .work-label { margin-top: 2.75rem; } .pitch-row { flex-direction: column; gap: .25rem; } }

/* The email as a link (30 seconds and the "Hiring?" footer). Green underline and arrow. On a computer,
   hover lifts the underline and the arrow gives way to "Copy"; a click copies (next.js adds .is-copied)
   and shows "Copied". On a phone a tap copies and opens the mail app, as the email box did. */
.maillink { display: inline-flex; align-items: center; gap: .875rem; font: 400 var(--t30)/1.2 var(--serif); letter-spacing: -.012em; color: var(--ink); text-decoration: none; -webkit-tap-highlight-color: transparent; }
.maillink .addr { text-decoration: underline; text-decoration-color: var(--mark); text-decoration-thickness: 2px; text-underline-offset: .24em; transition: text-underline-offset .3s var(--ease), color .2s ease; }
.maillink:focus-visible { outline: 2px solid var(--mark); outline-offset: 6px; border-radius: 2px; }
.maillink:active .addr { color: var(--mark); }
.ml-slot { position: relative; display: inline-flex; align-items: center; width: 5.25rem; height: 1.75rem; color: var(--mark); }
.ml-arr { display: inline-flex; width: 1.375rem; height: 1.375rem; transition: transform .3s var(--ease), opacity .2s ease; }
.ml-arr svg { display: block; width: 100%; height: 100%; }
.ml-cp, .ml-done { position: absolute; left: 0; top: 50%; display: inline-flex; align-items: center; gap: .375rem; font: 400 .9375rem/1 var(--sans); letter-spacing: .01em; white-space: nowrap; opacity: 0; transform: translate(-6px, -50%); transition: transform .3s var(--ease), opacity .2s ease; }
.ml-done svg { width: 1rem; height: 1rem; }
@media (hover: hover) and (pointer: fine) {
  .maillink:hover .addr, .maillink:focus-visible .addr { text-underline-offset: .12em; }
  .maillink:hover .ml-arr, .maillink:focus-visible .ml-arr { opacity: 0; transform: translateX(12px); }
  .maillink:hover .ml-cp, .maillink:focus-visible .ml-cp { opacity: 1; transform: translate(0, -50%); }
}
.maillink.is-copied .ml-arr, .maillink.is-copied .ml-cp { opacity: 0; }
.maillink.is-copied .ml-done { opacity: 1; transform: translate(0, -50%); }
.maillink--sm { font-size: var(--t24); }
.maillink--lg { font-size: var(--t40); margin-top: 1rem; }
.maillink--lg .addr { text-decoration-thickness: 3px; }
.foot .ask-band .maillink, html body .foot .ask-band .maillink { margin-top: 1.1rem; color: var(--ink); }
/* narrow phones: the address may break, the slot keeps only the arrow's width, nothing pushes the page sideways */
.maillink { max-width: 100%; flex-wrap: wrap; row-gap: .25rem; }
.maillink .addr { min-width: 0; overflow-wrap: anywhere; }
@media (hover: none), (pointer: coarse) { .ml-slot { width: 1.375rem; } .maillink.is-copied .ml-slot { width: 5.25rem; } }
@media (prefers-reduced-motion: reduce) { .maillink .addr, .ml-arr, .ml-cp, .ml-done { transition: none; } }
/* every mail link, on touch: "Copy" never shows and "Copied" only after a tap. Until then both are out
   of layout, so the hidden label can't push the page wider than a small phone (it did at 262px on
   every page with the footer ask). @starting-style keeps the fade-in. (6 Nov 2026) */
@media (hover: none), (pointer: coarse) {
  .maillink .ml-cp, .maillink:not(.is-copied) .ml-done { display: none; }
  @starting-style { .maillink.is-copied .ml-done { opacity: 0; transform: translate(-6px, -50%); } }
}

/* Contact (6 Nov 2026). The rail names the page, as on every page. The ask on the left (title,
   line, email, then Elsewhere), the facts on the right; Elsewhere and the facts both label over value. Three sizes only: the title; one serif size (--t24) for the line and the email, the
   email told apart by ink and its green underline; one small size for everything else (labels
   muted, values and links in ink). Stacks below 1100px; from 640px the first three facts share a line. */
.contact { display: grid; gap: clamp(3.5rem, 9vh, 5rem); }
html body .contact-ask .standfirst + .maillink { margin-top: 1.75rem; }
/* plain wrapping here: the site's 'pretty' wrap pushed "I reply within 48 hrs." onto a line of its own */
.contact-ask .standfirst { text-wrap: wrap; }
.nowrap { white-space: nowrap; } /* "data-dense" stays whole (Contact, About) */
/* About (6 Nov 2026): 72px between its sections, the README's gap between blocks */
.block--chapter { padding-top: 4.5rem; }
.contact-facts, .contact-else { font-size: .9375rem; line-height: 1.6; }
.contact-facts { display: grid; gap: 1.25rem; align-content: start; margin: 0; }
.contact-facts dt, .contact-else .k { color: var(--muted); }
.contact-facts dd { margin: 0; color: var(--ink); text-wrap: pretty; }
.contact-facts .sub { display: block; max-width: 26rem; color: var(--muted); }
.contact-else { margin-top: 2.25rem; color: var(--ink); } /* Elsewhere: label over links, like the facts */
.contact-else dd { margin: 0; }
.contact-else .sep { margin: 0 .9em; color: var(--faint); } /* wide enough that X's and CV's 44px tap areas don't overlap */
@media (min-width: 1100px) {
  .contact { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); column-gap: var(--col-gap); align-items: start; }
  .contact-facts { padding-top: .9rem; }
}
/* mid widths: availability, role and mode on one line; where I am on the next */
@media (min-width: 640px) and (max-width: 1099px) {
  .contact-facts { grid-template-columns: repeat(3, max-content); justify-content: start; column-gap: var(--col-gap); }
  .contact-facts > div:nth-child(4) { grid-column: 1 / -1; }
}
/* small links keep a 44px tap area without moving anything: an invisible box centred on each */
.contact-ask .maillink, .contact-else a { position: relative; }
.contact-ask .maillink::before, .contact-else a::before { content: ""; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: 44px; transform: translate(-50%, -50%); }

/* Consolidate Health cover, Nov 2026: three phones in a row (home, a flagged lab, who can see my
   records), bleeding off the bottom of the ground like the single-phone cover did. Phones scroll
   sideways under 640px. */
.cover--trio .fig-ground { padding-bottom: 0; overflow: hidden; }
.cover-trio { display: grid; grid-template-columns: repeat(3, minmax(0, 15rem)); justify-content: center; gap: clamp(.75rem, 3vw, 2rem); }
.cover-trio img.phone { width: 100%; aspect-ratio: 1170 / 1900; object-fit: cover; object-position: top; border-radius: var(--r-phone) var(--r-phone) 0 0; box-shadow: var(--shade); }
@media (max-width: 639px) { .cover-trio { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 72%; justify-content: start; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; } .cover-trio img.phone { scroll-snap-align: start; } }
.fig--crop .fig-ground img { width: min(100%, 36rem); margin: 0 auto; }

/* 5 minutes, Nov 2026: one way of framing screens, so all three products line up.
   Heroes show whole screens with the same padding on every side (Amazon Pay: desk and phone side by
   side at one height). Tiles are all the same: a close crop of what the caption names, inset by the
   same padding, 3px corners. Overrides the older stage/phones/tile variants above. */
.prod .hero .ground { --hp: clamp(.9rem, 2vw, 1.5rem); padding: var(--hp); }
.prod .hero .ground img.desk { display: block; width: 100%; height: auto; border-radius: var(--r-s); }
.prod .hero .ground.stage { display: flex; align-items: flex-start; gap: var(--hp); padding-right: var(--hp); }
.prod .hero .ground.stage img.desk { flex: 1.6 1 0; min-width: 0; }
.prod .hero .ground.stage img.phone { position: static; flex: .5625 1 0; min-width: 0; width: 100%; height: auto; object-fit: initial; border-radius: var(--r-phone); box-shadow: var(--shade); }
.prod .hero .ground.phones { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--hp); padding: var(--hp); overflow: visible; }
.prod .hero .ground.phones img { width: 100%; height: auto; aspect-ratio: auto; object-fit: initial; border-radius: var(--r-phone); box-shadow: var(--shade); }
.tile.tile--shot { --tp: clamp(.75rem, 1.6vw, 1.15rem); display: block; padding: var(--tp); }
.tile.tile--shot img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top center; border-radius: var(--r-s); box-shadow: var(--shade); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) :is(.ground, .tile) img.shot-dark { filter: none; } }
[data-theme="dark"] :is(.ground, .tile) img.shot-dark { filter: none; }
.tile.tile--shot, .home .prod.slide .tile.tile--shot { height: auto; aspect-ratio: auto; }
.tile.tile--shot img { height: auto; aspect-ratio: 1000 / 625; }
.home .prod.slide .hero .ground { text-align: left; }
/* boxy corners in 5 minutes (Nov 2026): grounds, tiles and desktop crops nearly square; phones keep their own corners */
.prod .hero .ground, .prod .tile { border-radius: 2px; }
.prod .hero .ground img.desk, .tile.tile--shot img { border-radius: 1px; } /* the Amazon Pay phone keeps 18px, like every phone screenshot (7 Nov 2026) */

/* ── Case-study plate ──────────────────────────────────────────────
   Each decision: heading, then the argument with its summary card beside it,
   then the evidence full width. Below 1100px the card sits between the
   heading and the argument, and the note follows the argument. */
.dec { display: flex; flex-direction: column; }
.dec > * + * { margin-top: 0; }
.dec-head { order: 1; }
.dec-side { display: contents; }
.dec-side .ledger-aside { order: 2; margin-top: 1.5rem; }
.dec-text { order: 3; margin-top: 1.5rem; max-width: var(--text); }
.dec-side .note { order: 4; margin-top: 1.25rem; max-width: var(--text); }
.dec > .fig { order: 5; margin-top: 2rem; }

.dec-side .ledger-aside { display: grid; gap: 0; max-width: var(--text); padding: 1rem 1.25rem; border-radius: var(--r-s); background: var(--ground); font-size: 1rem; }
.dec-side .ledger-aside > div { display: block; padding: .8rem 0; border-top: 1px solid var(--rim); }
.dec-side .ledger-aside > div:first-child { border-top: 0; padding-top: .15rem; }
.dec-side .ledger-aside > div:last-child { padding-bottom: .15rem; }
.dec-side .ledger-aside dt { margin-bottom: .2rem; font-size: .875rem; color: var(--muted); }
.dec-side .ledger-aside dd { font: 400 .9375rem/1.45 var(--sans); letter-spacing: 0; color: var(--ink); }
.dec-side .note { padding-left: 1rem; border-left: 2px solid var(--faint); }

@media (min-width: 1100px) {
  .cs-prose { max-width: var(--measure); }
  .dec { display: grid; grid-template-columns: minmax(0, var(--text)) minmax(17rem, 1fr); column-gap: clamp(2rem, 3.5vw, 3.5rem); align-items: start; }
  .dec-head { grid-column: 1 / -1; grid-row: 1; }
  .dec-side { display: block; grid-column: 2; grid-row: 2; margin-top: 1.5rem; }
  .dec-side .ledger-aside { margin-top: 0; }
  .dec-text { grid-column: 1; grid-row: 2; }
  .dec > .fig { grid-column: 1 / -1; grid-row: 3; }
}

/* Section rhythm: a hairline above each section label. */
.cs-prose > .sec { padding-top: 1.25rem; border-top: 1px solid var(--rim); }

/* Terms: a two-column glossary instead of one long list. */
@media (min-width: 760px) {
  .cs-prose > .terms { max-width: 52rem; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.5rem 2.5rem; }
}
.cs-prose > .terms > div { display: block; }
.cs-prose > .terms dt { margin-bottom: .25rem; padding-top: 0; font: 400 var(--t20)/1.3 var(--serif); color: var(--ink); }
.cs-prose > .terms dd { color: var(--muted); }

/* Sections with a rule or an aside: argument left, notes in the margin. */
.sec-plate { margin-top: 1rem; }
.sec-plate .dec-text { margin-top: 0; }
.sec-plate .dec-side { display: block; margin-top: 1.25rem; }
.dec-side > p { max-width: var(--text); padding-left: 1rem; border-left: 2px solid var(--faint); color: var(--muted); font-size: .9375rem; }
.dec-side > p + p { margin-top: 1rem; }
@media (min-width: 1100px) {
  .sec-plate { display: grid; grid-template-columns: minmax(0, var(--text)) minmax(17rem, 1fr); column-gap: clamp(2rem, 3.5vw, 3.5rem); align-items: start; }
  .sec-plate .dec-side { margin-top: .3rem; }
}

/* Short decisions: the summary runs across the top as one strip. */
@media (min-width: 1100px) {
  .dec--short .dec-side { display: contents; }
  .dec--short .dec-side .ledger-aside { grid-column: 1 / -1; grid-row: 2; margin-top: 1.5rem; max-width: none; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 1rem 0; }
  .dec--short .dec-side .ledger-aside > div, .dec--short .dec-side .ledger-aside > div:first-child, .dec--short .dec-side .ledger-aside > div:last-child { padding: .15rem 1.25rem; border-top: 0; }
  .dec--short .dec-side .ledger-aside > div + div { border-left: 1px solid var(--rim); }
  .dec--short .dec-text { grid-column: 1; grid-row: 3; }
  .dec--short .dec-side .note { grid-column: 2; grid-row: 3; margin-top: 1.5rem; }
  .dec--short > .fig { grid-row: 4; }
}

/* The route list: a down arrow on hover says each row jumps down the page. */
.route span::after { content: ""; display: inline-block; width: .8em; height: .8em; margin-left: .4em; vertical-align: -.05em; background: currentColor; opacity: 0; transform: translateY(-2px); transition: opacity .2s ease, transform .2s ease;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2.5v11M3.5 9 8 13.5 12.5 9'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2.5v11M3.5 9 8 13.5 12.5 9'/%3E%3C/svg%3E") center / contain no-repeat; }
@media (hover: hover) and (pointer: fine) { .route a:hover span::after { opacity: 1; transform: none; } }
.route a:focus-visible span::after { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .route span::after { transition: none; } }
.cs-prose > .sec-plate { max-width: none; }
.dec-side > p.small-note, .dec-side > p.tradeoff { font-size: .9375rem; }

/* About photo (6 Nov 2026): beside The route, whose three paragraphs are about its height, from 1100px;
   above The route's text below that: 160px from 640px, the column's full width on phones from a wider 4:3 crop.
   The page head stays exactly as on Work and Writing. */
.about-route .photo { display: block; width: 10rem; margin-bottom: 1.75rem; }
.about-route .photo img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; border-radius: var(--r-s); background: var(--ground); }
@media (max-width: 639px) {
  .about-route .photo { width: 100%; }
  .about-route .photo img { aspect-ratio: 4 / 3; }
}
@media (min-width: 1100px) {
  .about-route { display: grid; grid-template-columns: minmax(0, var(--text)) 12.5rem; column-gap: var(--col-gap); align-content: start; max-width: none; }
  .about-route > p { grid-column: 1; }
  .about-route .photo { grid-column: 2; grid-row: 1 / span 3; width: 100%; margin: .3rem 0 0; }
}

/* ── Buttons review (6 Nov) ───────────────────────────────────────────
   Focus ring: 2px out from boxes and rows, 4px out from text links (the default above). */
.group li > a:focus-visible, .route a:focus-visible, .tabs a:focus-visible, .head ul a:focus-visible,
.prod .hero a.ground:focus-visible { outline-offset: 2px; }
.maillink:focus-visible { outline-offset: 4px; }

/* Tap areas of at least 24px for the short text links (WCAG 2.2, 2.5.8). */
.pitch-row a { position: relative; }
.pitch-row a::before { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 28px; transform: translateY(-50%); }
@media (max-width: 599px) { .pitch-row { gap: .5rem; } }

/* The name in the header reacts like the other links. */
.head-name { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .22em; text-decoration-color: transparent; transition: text-decoration-color .2s ease; }
@media (hover: hover) and (pointer: fine) { .head-name:hover { text-decoration-color: var(--mark); } }

/* Case-study 30 seconds: the main step is a box, the prototype a link, as in 5 minutes. */
.act--cs { margin-top: 1.75rem; }

/* No rush: the last group is a snap point of its own. Without it, its tab ("About me") scrolls the
   page so near the Contact slide that the page's snapping pulls the page onto Contact and hides the group. */
.home #more-about-me { scroll-snap-align: start; scroll-margin-top: 8.5rem; }
.home #no-rush .group { scroll-margin-top: 8.5rem; } /* under the menu and the tabs: home has no scroll padding */
/* From 700px every group is a snap point, so each tab lands its group just under the tabs (without them,
   the snap point above pulls "Essays" short). Phones keep only the last one: snap points on every group
   catch short swipes there. */
@media (min-width: 700px) { .home #no-rush .group { scroll-snap-align: start; scroll-margin-top: 8.5rem; } }

/* Small figures open their full-size image (S-05b, W-28): the link adds nothing visible. */
.fig-full { display: block; }

/* The Amazon Pay phone screens come from an older, square-cornered phone: 3px like the screens. Other phones keep --r-phone. */
img.phone[src*="live-mobile-poster"], img.cover-phone[src*="live-mobile-poster"],
video.phone[poster*="refund-mobile-poster"], img.phone[src*="m-partials"], img.phone[src*="ap-drawer"] { border-radius: var(--r-s) !important; }
