/* fonts.css */
/*
 * Fonts (all SIL OFL 1.1), self-hosted from public/assets/fonts/ (licences and sources in
 * NOTICE.txt there): Instrument Sans (variable, 400-700) for headings and body, Instrument Serif
 * Italic for the accent words, Big Shoulders Display 800 for display caps. Latin subsets as Google
 * Fonts serves them; the site's text is all inside that range.
 *
 * Instrument Sans is preloaded on the home page (hero label, role, sentence and buttons; see
 * heroPreload in src/templates/components/hero.ts). The other two swap in over the metric-matched
 * fallbacks below.
 */
@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/instrument-sans-variable-latin.woff2") format("woff2");
}

@font-face {
  font-family: "Instrument Serif";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/instrument-serif-italic-latin.woff2") format("woff2");
}

@font-face {
  font-family: "Big Shoulders Display";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("/assets/fonts/big-shoulders-display-800-latin.woff2") format("woff2");
}

/*
 * Metric-matched fallbacks, used only until the web fonts arrive, so the swap does not move text
 * (no layout shift). Ratios measured in Chrome against the real faces at 100px:
 * width (size-adjust), and ascent/descent divided by size-adjust (the overrides scale with it).
 */
@font-face {
  font-family: "Instrument Sans Fallback";
  font-weight: 400;
  src: local("Arial"), local("ArialMT");
  size-adjust: 101.8%;
  ascent-override: 95.3%;
  descent-override: 24.6%;
  line-gap-override: 0%;
}

@font-face {
  font-family: "Instrument Sans Fallback";
  font-weight: 700;
  src: local("Arial Bold"), local("Arial-BoldMT");
  size-adjust: 98.1%;
  ascent-override: 98.9%;
  descent-override: 25.5%;
  line-gap-override: 0%;
}

@font-face {
  font-family: "Big Shoulders Display Fallback";
  font-weight: 800;
  src: local("Impact");
  size-adjust: 89.8%;
  ascent-override: 109.1%;
  descent-override: 23.4%;
  line-gap-override: 0%;
}

@font-face {
  font-family: "Instrument Serif Fallback";
  font-style: italic;
  src: local("Times New Roman Italic"), local("TimesNewRomanPS-ItalicMT");
  size-adjust: 87.5%;
  ascent-override: 113.1%;
  descent-override: 35.4%;
  line-gap-override: 0%;
}

:root {
  --font-sans:
    "Instrument Sans", "Instrument Sans Fallback", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    sans-serif;
  --font-serif: "Instrument Serif", "Instrument Serif Fallback", "Iowan Old Style", Georgia, serif;
  --font-cond:
    "Big Shoulders Display", "Big Shoulders Display Fallback", "Avenir Next Condensed", "Arial Narrow", sans-serif;
}

/* tokens.css */
/*
 * Design tokens (plan section 4). Light editorial paper for the site (reel 1); one dark,
 * amber-bordered material for the work sequence (reel 2). One accent across both.
 * scripts/check-dist.ts reads the hex values below and verifies the declared contrast pairs.
 *
 * Amber rule: on light surfaces --amber (#B88A46, 2.75:1 on paper) is never text, an icon or the
 * only boundary of a control. Amber text on light uses --amber-ink. Never white text on amber.
 */
:root {
  /* light surface */
  --paper: #f4f1eb;
  --paper-raised: #faf8f4;
  --paper-sunk: #ebe7de;
  --ink: #171714;
  --ink-hover: #2e2c27;
  --ink-2: #45423b;
  --ink-3: #625e55;
  --ghost: #e7e2d8;
  --rule: #d8d2c6;
  --rule-strong: #8a8477;
  --amber: #b88a46;
  --amber-ink: #7d5a1e;
  /* form errors: text and the 2px border of an invalid field */
  --error: #a3271b;

  /* dark panels */
  --night: #171714;
  --panel: #1e1b16;
  --panel-hi: #2b251b;
  --on-dark: #f7f4ee;
  --on-dark-2: #d6d0c4;
  --on-dark-3: #a8a193;
  --amber-bright: #d2a562;
  --amber-line: rgb(184 138 70 / 0.42);

  /* type scale */
  --fs-ghost: min(20vw, 28rem);
  --fs-display: clamp(3rem, 5.2vw, 5rem);
  --fs-role: clamp(1.75rem, min(3.5vw, 7svh), 3.5rem);
  --fs-h2: clamp(2.25rem, 4.6vw, 4rem);
  --fs-h3: clamp(1.625rem, 2.4vw, 2.125rem);
  --fs-lead: clamp(1.125rem, 1.5vw, 1.375rem);
  --fs-body: clamp(1.0625rem, 1.2vw, 1.1875rem);
  --fs-small: 0.875rem;
  --fs-label: 0.8125rem;

  /* space */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 4rem;
  --s-9: 6rem;
  --s-10: 8rem;
  --gutter: clamp(1rem, 4vw, 3.5rem);
  --container: 82rem;
  /* Inline padding that puts a full-width element's content on the .container edge: the gutter,
     or half the space either side of an 82rem container once the viewport is wider than that.
     (100% is the element's containing block, the viewport width for the header and hero.) */
  --edge: max(var(--gutter), calc((100% - var(--container)) / 2));
  --section-pad: clamp(4rem, 9vw, 7.5rem);
  --header-h: 4.5rem;

  /* shape and depth */
  --r-pill: 999px;
  --r-panel: 1.25rem;
  --r-card: 1rem;
  --r-img: 0.75rem;
  --r-tile: 0.625rem;
  --shadow-float: 0 8px 24px -12px rgb(23 23 20 / 0.25);
  --shadow-leaf: -20px 0 36px -22px rgb(0 0 0 / 0.7);

  /* motion */
  --dur-1: 160ms;
  --dur-2: 220ms;
  --dur-3: 420ms;
  --dur-4: 520ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
}

@media (max-width: 59.99rem) {
  :root {
    --header-h: 4rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-1: 0.01ms;
    --dur-2: 0.01ms;
    --dur-3: 0.01ms;
    --dur-4: 0.01ms;
  }
}

/* base.css */
/* Base: reset, type, links, buttons, focus, containers, sections, the contact address and the 404. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Anything scrolled into view (anchor targets, and focused controls: WCAG 2.4.11) clears the fixed
   header. The dark Work section takes this back with a negative scroll-margin to land flush. */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}

/* A column, so a short page (the 404) keeps its footer at the bottom of the viewport. */
body {
  display: flex;
  flex-direction: column;
  margin: 0;
  min-height: 100vh;
  background: var(--paper);
  color: var(--ink);
  font: 400 var(--fs-body) / 1.55 var(--font-sans);
  font-kerning: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* The hidden attribute beats a component's own display rule (forms, status blocks, the buttons the
   scripts reveal): (0,2,0) outranks any single-class rule, wherever it sits in the cascade. */
:root [hidden] {
  display: none;
}

img,
svg,
picture {
  display: block;
  max-width: 100%;
}

img {
  height: auto;
}

p,
h1,
h2,
h3,
figure,
dl,
dd {
  margin: 0;
}

h1,
h2,
h3 {
  text-wrap: balance;
}

p,
figcaption {
  text-wrap: pretty;
}

a {
  color: inherit;
}

em {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
}

::selection {
  background: var(--amber);
  color: var(--ink);
}

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

main {
  flex: 1 0 auto;
}

main:focus {
  outline: none;
}

.skip {
  position: fixed;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 100;
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 1.125rem;
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--paper);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-160%);
}

/* Ink ring on a paper halo, as on the header mark: 17:1 on paper (amber was 2.75:1), and the
   halo keeps it visible if the link is ever focused over the dark Work sheet. */
.skip:focus {
  transform: none;
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--paper-raised);
}

.top-sentinel {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1.5rem;
  pointer-events: none;
}

.container {
  width: 100%;
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Heading voice (reel 1): bold sans, then lighter italic serif, ending in punctuation. */
.h2 {
  font: 700 var(--fs-h2) / 1.02 var(--font-sans);
  letter-spacing: -0.03em;
  color: var(--ink);
}

.h2 em {
  font-size: 1.08em;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--ink-3);
}

.lead {
  font-size: var(--fs-lead);
  line-height: 1.45;
  color: var(--ink-2);
}

.link {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--amber);
  text-underline-offset: 0.22em;
  transition: text-decoration-color var(--dur-1) var(--ease-out);
}

.link:hover {
  text-decoration-color: currentColor;
}

/* Buttons: reel 1's dark pill plus ghost pill. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.625rem;
  min-height: 3rem;
  padding: 0 1.375rem;
  border: 1.5px solid var(--ink);
  border-radius: var(--r-pill);
  font: 600 1rem / 1 var(--font-sans);
  letter-spacing: -0.005em;
  text-decoration: none;
  white-space: nowrap;
  transition:
    background-color var(--dur-1) var(--ease-out),
    border-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out);
}

.btn .icon {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
  transition: transform var(--dur-2) var(--ease-out);
}

.btn:hover .icon--arrow {
  transform: translateX(3px);
}

.btn--primary {
  background: var(--ink);
  color: var(--paper);
}

.btn--primary:hover {
  background: var(--ink-hover);
  border-color: var(--ink-hover);
}

.btn--ghost {
  background: transparent;
  color: var(--ink);
}

.btn--ghost:hover {
  background: var(--paper-raised);
}

.btn__kicker {
  color: var(--ink-3);
  font-weight: 500;
}

/* Light sections on paper. */
.section {
  padding-block: var(--section-pad);
}

.section--rule {
  border-top: 1px solid var(--rule);
}

.line {
  display: block;
}

/* Visually hidden, still read by assistive tech. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.contact-email__link {
  display: inline-block;
  min-height: 2.75rem;
  padding-block: 0.375rem;
  font: 600 clamp(1.375rem, 2.6vw, 2rem) / 1.2 var(--font-sans);
  letter-spacing: -0.02em;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--amber);
  text-underline-offset: 0.22em;
  overflow-wrap: anywhere;
}

.contact-email__link:hover {
  text-decoration-color: currentColor;
}

.contact-based {
  color: var(--ink-2);
}

/* 404 */
.missing {
  padding-top: calc(var(--header-h) + var(--section-pad) * 0.6);
}

.missing .lead {
  margin-top: 1.25rem;
  max-width: 34rem;
}

.missing__list {
  margin: 2rem 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--rule);
  max-width: 40rem;
}

.missing__list li {
  border-bottom: 1px solid var(--rule);
}

.missing__link {
  display: flex;
  align-items: center;
  min-height: 3.25rem;
  font-weight: 500;
  text-decoration: none;
}

.missing__link:hover {
  text-decoration: underline;
  text-decoration-color: var(--amber);
  text-underline-offset: 0.22em;
}

/* header.css */
/*
 * Header (reel 1): a circular monogram at the top left and three links at the top right, on a
 * compact solid paper band. The band is part of the page's top edge, not a float: nothing readable
 * ever shows through or under it, and the root scroll-padding-top (base.css) keeps anchor targets
 * and focused controls below it (WCAG 2.4.11). Once the page scrolls the band gets a hairline, the
 * links sit in a light pill with the current section as a dark pill, and the monogram fills.
 * Without JS the header is always in that scrolled state. With JS the plain top state is the first
 * paint, so a page opened at the top does not flash the pill; src/client/site.ts adds .is-scrolled
 * once the top sentinel leaves the viewport, and .is-settled after its first reading, so only real
 * scrolling animates (a mid-page load snaps).
 * Phones (< 48rem) with JS (.has-menu): the bar is the monogram and a "Menu" button; the links
 * become a disclosure panel under the bar, over a backdrop. Without JS they stay inline.
 */
.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  /* Aligned with the content container, not the viewport edge. */
  padding-inline: var(--edge);
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
}

.mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 1.5px solid var(--ink);
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  font: 700 0.8125rem / 1 var(--font-sans);
  letter-spacing: 0.06em;
  text-decoration: none;
  box-shadow:
    0 0 0 1.5px var(--paper-raised),
    var(--shadow-float);
}

.nav__list {
  display: flex;
  gap: 0.125rem;
  margin: 0;
  padding: 0.25rem;
  list-style: none;
  border: 1px solid var(--rule);
  border-radius: var(--r-pill);
  background: var(--paper-raised);
  box-shadow: var(--shadow-float);
}

/* Top state: the first paint whenever scripts run (see the note at the top). */
@media (scripting: enabled) {
  .site-header:not(.is-scrolled, .is-open) {
    border-bottom-color: transparent;
  }

  .site-header:not(.is-scrolled) .mark {
    background: transparent;
    color: var(--ink);
    box-shadow: none;
  }

  .site-header:not(.is-scrolled) .nav__list {
    border-color: transparent;
    background: transparent;
    box-shadow: none;
  }
}

.is-settled.site-header {
  transition: border-color var(--dur-2) var(--ease-out);
}

.is-settled .mark {
  transition:
    background-color var(--dur-2) var(--ease-out),
    color var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out);
}

.is-settled .nav__list {
  transition:
    background-color var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out);
}

/* Two-tone ring: ink on a paper halo, so it reads on the band and anywhere else. After the
   top-state rules, which it must override. */
.site-header .mark:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--paper-raised);
}

.nav__link {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 1.125rem;
  border-radius: var(--r-pill);
  color: var(--ink);
  font: 500 0.9375rem / 1 var(--font-sans);
  text-decoration: none;
  transition:
    background-color var(--dur-2) var(--ease-out),
    color var(--dur-2) var(--ease-out);
}

.nav__link:hover {
  background: var(--paper-sunk);
}

.nav__link[aria-current] {
  background: var(--ink);
  color: var(--paper);
}

/* Without JS on small phones the three links stay inline, a little tighter. */
@media (max-width: 29.99rem) {
  .nav__link {
    padding: 0 0.875rem;
    font-size: 0.875rem;
  }
}

@media (max-width: 22.49rem) {
  .nav__list {
    gap: 0;
  }

  .nav__link {
    padding: 0 0.75rem;
  }
}

/* ---------- Phone menu (JS only; the button ships with the hidden attribute) ---------- */

.menu-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  min-width: 2.75rem;
  min-height: 2.75rem;
  padding: 0 1.125rem;
  border: 1px solid var(--rule);
  border-radius: var(--r-pill);
  background: var(--paper-raised);
  color: var(--ink);
  font: 500 0.9375rem / 1 var(--font-sans);
  cursor: pointer;
}

.menu-toggle[aria-expanded="true"] {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--paper);
}

/* Two lines that cross when the panel is open. */
.menu-toggle__icon {
  position: relative;
  width: 1rem;
  height: 0.625rem;
}

.menu-toggle__icon::before,
.menu-toggle__icon::after {
  content: "";
  position: absolute;
  left: 0;
  width: 100%;
  height: 1.5px;
  border-radius: 1px;
  background: currentColor;
}

.menu-toggle__icon::before {
  top: 0;
}

.menu-toggle__icon::after {
  bottom: 0;
}

.menu-toggle[aria-expanded="true"] .menu-toggle__icon::before {
  top: calc(50% - 0.75px);
  rotate: 45deg;
}

.menu-toggle[aria-expanded="true"] .menu-toggle__icon::after {
  bottom: calc(50% - 0.75px);
  rotate: -45deg;
}

.menu-backdrop {
  position: fixed;
  inset: var(--header-h) 0 0;
  background: rgb(23 23 20 / 0.45);
  /* A drag on the backdrop does not scroll the page behind it. */
  touch-action: none;
}

@media (min-width: 48rem) {
  .menu-toggle,
  .menu-backdrop {
    display: none;
  }
}

@media (max-width: 47.99rem) {
  .has-menu .nav {
    display: none;
  }

  .has-menu.is-open .nav {
    display: block;
    position: fixed;
    z-index: 1;
    inset: var(--header-h) 0 auto;
    max-height: calc(100dvh - var(--header-h));
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0.75rem var(--edge) 1.25rem;
    border-bottom: 1px solid var(--rule);
    background: var(--paper);
  }

  .has-menu .nav__list,
  .has-menu:not(.is-scrolled) .nav__list {
    flex-direction: column;
    gap: 0.25rem;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
  }

  .has-menu .nav__link {
    display: flex;
    min-height: 3rem;
    padding: 0 1.125rem;
    font-size: 1.125rem;
  }
}

@media (max-width: 47.99rem) and (prefers-reduced-motion: no-preference) {
  .has-menu.is-open .nav {
    animation: menu-in var(--dur-2) var(--ease-out);
  }

  .menu-backdrop:not([hidden]) {
    animation: menu-fade var(--dur-2) var(--ease-out);
  }
}

@keyframes menu-in {
  from {
    opacity: 0;
    translate: 0 -0.5rem;
  }
}

@keyframes menu-fade {
  from {
    opacity: 0;
  }
}

/* hero.css */
/*
 * Hero (plan section 5; reel 1's composition). Layers inside one isolated stacking context:
 * the faint ghost name (z -2), the cut-out portrait (z -1), then the readable copy.
 * >= 60rem: full-bleed; the figure sits flush with the right and bottom edges, so the photo's own
 * crops (forearm, torso) read as the edge of the picture. Copy bottom-left, never over the figure.
 * <  60rem: a fixed-height stage (one ghost line, bust centred under it) closed by an ink rule,
 *          then the copy.
 */
.hero {
  --ghost-fs: var(--fs-ghost);
  position: relative;
  isolation: isolate;
  overflow: clip;
  min-height: clamp(35rem, 100svh, 60rem);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background: var(--paper);
}

.hero__stage {
  display: contents;
}

/* Decorative: hidden from assistive tech, never selectable. Positioned from the font's measured
   width (RYAN NUGARA = 4.696em in Big Shoulders Display 800), so a font swap cannot move its start. */
.hero__ghost {
  position: absolute;
  z-index: -2;
  top: calc(var(--header-h) + 1.25svh);
  left: calc(50% - 2.348 * var(--ghost-fs));
  margin: 0;
  color: var(--ghost);
  font: 800 var(--ghost-fs) / 0.84 var(--font-cond);
  letter-spacing: 0;
  text-transform: uppercase;
  white-space: nowrap;
  user-select: none;
  pointer-events: none;
}

.hero__figure {
  position: absolute;
  z-index: -1;
  right: 0;
  bottom: 0;
  height: min(80svh, 45rem);
  aspect-ratio: 4 / 5;
  /* The forearm leaves the photo 17 rows above its bottom edge: sink the figure that far. */
  translate: 0 1.6%;
}

.hero__figure picture,
.hero__figure img {
  width: 100%;
  height: 100%;
}

/* The ghost and the figure are full-bleed; the copy keeps the page's container edge, so on wide
   screens it starts where "Selected systems." and the deck start (same rule as .site-header). */
.hero__copy {
  position: relative;
  padding: 0 var(--edge) clamp(2rem, 6svh, 4.5rem);
}

.hero__name {
  margin-bottom: 1.125rem;
  color: var(--ink-2);
  font: 600 var(--fs-label) / 1.3 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.hero__place {
  color: var(--ink-3);
  font-weight: 500;
}

.hero__dot {
  margin-inline: 0.2em;
}

/* Reel 1's stacked bold role; its lighter final period becomes --amber-ink (5.56:1). */
.hero__role {
  color: var(--ink);
  font: 700 var(--fs-role) / 1.06 var(--font-sans);
  letter-spacing: -0.025em;
}

.hero__role span {
  display: block;
}

.hero__role i {
  font-style: normal;
  color: var(--amber-ink);
}

.hero__lede {
  max-width: 32rem;
  margin-top: 1.25rem;
  color: var(--ink-2);
  font-size: clamp(1.0625rem, 1.25vw, 1.1875rem);
  line-height: 1.5;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.75rem;
}

/* Typographic fallback (site.hero.portrait = "none"): no figure, larger role. */
.hero--type-only .hero__role {
  font-size: clamp(2rem, 5.4vw, 5rem);
}

/* Short laptops (e.g. 1366x650): a slightly tighter copy block, so the ghost can still span
   90%+ of the width and stay clear of the copy. */
@media (min-width: 60rem) and (max-height: 43.75rem) {
  .hero {
    --ghost-fs: min(20vw, 41svh);
  }

  .hero__name {
    margin-bottom: 0.875rem;
  }

  .hero__role {
    font-size: clamp(1.75rem, min(3.5vw, 6.4svh), 3.5rem);
  }

  .hero__lede {
    margin-top: 1rem;
  }

  .hero__actions {
    margin-top: 1.375rem;
  }
}

/* 60-64rem: copy and figure side by side with a smaller figure. */
@media (min-width: 60rem) and (max-width: 63.99rem) {
  .hero__figure {
    height: min(72svh, 40rem);
  }
}

/* The dark Work section rises over the pinned hero (reel 2's panels rising over one another).
   CSS only, ordinary scrolling; off for small or short screens and for reduced motion. */
@media (min-width: 60rem) and (min-height: 37.5rem) and (prefers-reduced-motion: no-preference) {
  .rise > .hero {
    position: sticky;
    top: 0;
  }

  .rise > .work {
    min-height: 100svh;
  }
}

/* Below 60rem: stacked. No text ever sits over the figure. */
@media (max-width: 59.99rem) {
  .hero {
    display: block;
    min-height: 0;
    padding-top: var(--header-h);
  }

  /* 40% of the viewport height, or enough that the bust under the 20vw ghost line stays ~40vw
     tall on wide tablets (0.25rem + 13vw is where the hair meets the letters), never above half
     the viewport height. */
  .hero__stage {
    display: block;
    position: relative;
    height: clamp(15rem, min(max(40svh, 0.25rem + 53vw), 50svh), 32rem);
    overflow: clip;
    border-bottom: 1px solid var(--ink);
  }

  .hero__ghost {
    top: 0.25rem;
  }

  /* One ghost line across the top, the bust centred under it (a poster, so a tablet has no empty
     half). As on desktop, only the hair meets the letters: the hair top (7.5% down the photo)
     sits at --hair, the bottom fifth of the caps (glyph bottom = 0.814em at this line height),
     so the face never hides part of the name. The height is solved so the stage's bottom edge
     cuts the photo at 74%, above the hands (the frame-cropped forearm never shows):
     H = (stage - hair) / (0.74 - 0.075). Never shorter than the stage (landscape phones). */
  .hero__figure {
    --hair: calc(0.25rem + 0.652 * var(--ghost-fs));
    --fig-h: max(100%, (100% - var(--hair)) / 0.665);
    top: calc(var(--hair) - 0.075 * var(--fig-h));
    right: auto;
    bottom: auto;
    left: 50%;
    height: var(--fig-h);
    translate: -50% 0;
  }

  .hero__copy {
    padding: 1.5rem var(--gutter) 2.75rem;
  }

  .hero__role {
    font-size: clamp(1.25rem, 6.3vw, 2.75rem);
  }
}

/* Phones: the same poster stage as tablets (one ghost line, centred bust). */
@media (max-width: 29.99rem) {
  /* The ghost line is only ~20vw tall here, so the tablet overlap (hair over the bottom fifth of
     the caps) hid most of the middle letters. Drop the hair to the last ~5% of the caps (glyph
     bottom = 0.814em) so the whole name reads; --fig-h re-solves, keeping the 74% cut. */
  .hero__figure {
    --hair: calc(0.25rem + 0.77 * var(--ghost-fs));
  }

  /* 6.3vw gave a 20px role under a 17px sentence at 320; 24-26px keeps it the headline. */
  .hero__role {
    font-size: clamp(1.5rem, 1rem + 2.5vw, 1.625rem);
  }

  /* The pair needs ~358px and a 390 phone gives it 358, so side by side would hang on sub-pixel
     text and border rounding. On phones the actions always stack at full width instead. */
  .hero__actions {
    flex-direction: column;
    gap: 0.625rem;
  }
}

@media (max-width: 22.49rem) {
  .hero__place {
    display: block;
    margin-top: 0.25rem;
  }

  .hero__dot {
    display: none;
  }
}

/* deck.css */
/*
 * Work section (plan section 7). Material from reel 2: warm dark gradient, 1px amber border,
 * white condensed caps, outlined amber numerals. Mechanics from reel 1: one wide open panel with
 * slim vertical tabs (number, rotated title, round "+").
 *
 * Default = vertical list (no JS, < 75rem, reduced motion): everything visible, nothing pinned.
 * .is-deck (added by src/client/deck.ts at >= 75rem): leaves stacked like index cards.
 */
.work {
  position: relative;
  z-index: 1;
  padding-block: calc(var(--section-pad) + 1.25rem) var(--section-pad);
  background: var(--night);
  color: var(--on-dark-2);
  /* Land flush (cancel the root scroll-padding): the header band covers only the section's own top padding. */
  scroll-margin-top: calc(-1 * (var(--header-h) + 1rem));
}

/* On large screens the section is a sheet with a rounded leading edge that rises over the hero. */
@media (min-width: 60rem) {
  .work {
    border-radius: 1.75rem 1.75rem 0 0;
    /* Landing on #work tucks the rounded edge just above the viewport; the extra top padding
       keeps the heading clear of the fixed header. */
    scroll-margin-top: calc(-1 * (var(--header-h) + 1rem) - 1.75rem);
    padding-top: calc(var(--section-pad) + 1.75rem);
  }
}

.work :focus-visible {
  outline-color: var(--paper);
}

.work__inner {
  width: 100%;
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.work__head {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: 1rem 3rem;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.work .h2 {
  color: var(--on-dark);
}

.work .h2 em {
  color: var(--on-dark-3);
}

.work__note {
  max-width: 22rem;
  color: var(--on-dark-3);
  font-size: var(--fs-body);
  line-height: 1.5;
}

/* ---- Panels: the vertical list ---- */
.deck {
  display: grid;
  gap: 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.sys {
  position: relative;
  overflow: clip;
  border: 1px solid var(--amber);
  border-radius: var(--r-panel);
  background: linear-gradient(100deg, var(--panel) 0%, var(--panel-hi) 100%);
}

.sys__spine {
  padding: clamp(1.25rem, 3vw, 2.25rem) clamp(1.25rem, 3vw, 2.5rem) 0;
}

.sys__title {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.sys__name {
  color: var(--on-dark);
  font: 800 clamp(2.5rem, 7vw, 4.5rem) / 0.9 var(--font-cond);
  letter-spacing: 0.005em;
  text-transform: uppercase;
}

/* Outlined numeral, top right as on reel 2's panels. Decorative (aria-hidden). */
.sys__num {
  order: 2;
  color: transparent;
  font: 800 clamp(2.25rem, 5vw, 3.5rem) / 0.9 var(--font-cond);
  -webkit-text-stroke: 1.25px var(--amber);
}

.sys__plus,
.sys__heading {
  display: none;
}

.sys__body {
  display: grid;
  gap: 1.75rem;
  padding: clamp(1.25rem, 2.5vw, 2rem) clamp(1.25rem, 3vw, 2.5rem) clamp(1.5rem, 3vw, 2.5rem);
}

.sys__sector {
  color: var(--amber-bright);
  font: 600 var(--fs-label) / 1.3 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.sys__problem-title {
  margin-top: 0.75rem;
  color: var(--on-dark);
  font: italic 400 var(--fs-h3) / 1.1 var(--font-serif);
}

.sys__challenge,
.sys__summary {
  max-width: 34rem;
}

.sys__challenge {
  margin-top: 0.875rem;
  color: var(--on-dark-2);
}

.sys__summary {
  margin-top: 0.875rem;
  color: var(--on-dark);
}

/* No screenshot exists for this system: its problem statement is set as a typographic panel in the
   figure's place (never a stand-in interface). */
.sys__statement {
  max-width: 36rem;
  margin-top: 1rem;
  padding: clamp(1.125rem, 2.5vw, 1.75rem);
  border: 1px solid var(--amber-line);
  border-radius: var(--r-img);
  background: rgb(247 244 238 / 0.03);
}

.sys__statement .sys__challenge {
  margin-top: 0;
  color: var(--on-dark);
  font: italic 400 clamp(1.375rem, 2.4vw, 1.875rem) / 1.2 var(--font-serif);
}

.sys__link {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  min-height: 2.75rem;
  margin-top: 1.5rem;
  padding: 0 1.25rem;
  border: 1px solid var(--amber);
  border-radius: var(--r-pill);
  color: var(--on-dark);
  font: 600 0.9375rem / 1.2 var(--font-sans);
  text-decoration: none;
  transition:
    background-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out);
}

.sys__link .icon {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
  transition: transform var(--dur-2) var(--ease-out);
}

/* Ink on amber is 5.78:1; never white on amber. */
.sys__link:hover {
  background: var(--amber);
  color: var(--ink);
}

.sys__link:hover .icon {
  transform: translateX(3px);
}

.sys__figure img {
  width: 100%;
  border-radius: var(--r-img);
  outline: 1px solid rgb(247 244 238 / 0.14);
  outline-offset: -1px;
}

.sys__figure figcaption {
  max-width: 40rem;
  margin-top: 0.75rem;
  color: var(--on-dark-3);
  font-size: 0.8125rem;
  line-height: 1.45;
}

@media (min-width: 48rem) {
  .sys__body {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    gap: 2.5rem;
    align-items: start;
  }

  .sys--text .sys__body {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---- Deck: desktop enhancement ---- */
@media (min-width: 75rem) {
  .deck.is-deck {
    --spine: 5.25rem;
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(clamp(32rem, 64svh, 38rem), auto);
    gap: 0;
    overflow: clip;
    border: 1px solid var(--amber);
    border-radius: var(--r-panel);
    background: var(--panel);
  }

  /* All leaves share one grid cell, offset by one spine each; the tallest sets the height,
     so no text is ever clipped. Later leaves stack above earlier ones. --leaves (on the deck) and
     --i (0-based, per leaf) are generated from src/content/systems.ts by the build (deckCss() in
     src/templates/components/deck.ts), so the deck takes any number of systems. */
  .is-deck > .sys {
    z-index: calc(var(--i, 0) + 1);
    grid-area: 1 / 1;
    width: calc(100% - (var(--leaves, 1) - 1) * var(--spine));
    margin-left: calc(var(--i, 0) * var(--spine));
    border-width: 0 0 0 1px;
    border-radius: var(--r-panel) 0 0 var(--r-panel);
    box-shadow: var(--shadow-leaf);
  }

  .is-deck > .sys:first-child {
    border-left-width: 0;
    box-shadow: none;
  }

  /* Leaves after the open one slide right until only their spine shows. */
  .is-deck > .sys.is-after {
    transform: translateX(calc(100% - var(--spine)));
  }

  .is-deck.is-ready > .sys {
    transition: transform var(--dur-4) var(--ease-out);
  }

  .is-deck .sys__card {
    display: grid;
    grid-template-columns: var(--spine) minmax(0, 1fr);
    height: 100%;
  }

  .is-deck .sys__spine {
    padding: 0;
    border-right: 1px solid var(--amber-line);
  }

  .is-deck .sys__title {
    display: block;
    height: 100%;
  }

  .sys__toggle {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 1.375rem 0 1.25rem;
    border: 0;
    border-radius: var(--r-panel) 0 0 var(--r-panel);
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: center;
    cursor: pointer;
    transition: background-color var(--dur-1) var(--ease-out);
  }

  .sys__toggle:hover {
    background: rgb(247 244 238 / 0.035);
  }

  .sys__toggle[aria-disabled="true"] {
    cursor: default;
  }

  .sys__toggle[aria-disabled="true"]:hover {
    background: transparent;
  }

  .sys__toggle:focus-visible {
    outline: 2px solid var(--paper);
    outline-offset: -4px;
  }

  .is-deck .sys__num {
    order: 0;
    font-size: 2.25rem;
  }

  .is-deck .sys__name {
    writing-mode: vertical-rl;
    rotate: 180deg;
    font-size: 1.75rem;
    letter-spacing: 0.04em;
    white-space: nowrap;
    transition: opacity var(--dur-3) var(--ease-out);
  }

  /* The open leaf's name is carried by the large heading in its body. */
  .is-deck .is-active .sys__name {
    opacity: 0;
  }

  .is-deck .sys__plus {
    display: grid;
    place-items: center;
    flex: none;
    width: 2.75rem;
    height: 2.75rem;
    border: 1px solid var(--amber);
    border-radius: 50%;
    color: var(--on-dark);
    transition:
      background-color var(--dur-1) var(--ease-out),
      color var(--dur-1) var(--ease-out);
  }

  .is-deck .sys__plus .icon {
    width: 1.125rem;
    height: 1.125rem;
  }

  .sys__toggle:not([aria-disabled="true"]):hover .sys__plus {
    background: var(--amber);
    color: var(--ink);
  }

  .is-deck .icon__v {
    transform-box: fill-box;
    transform-origin: center;
    transition: transform var(--dur-3) var(--ease-out);
  }

  .is-deck .is-active .icon__v {
    transform: scaleY(0);
  }

  .is-deck .sys__body {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    align-items: center;
    gap: clamp(2rem, 3vw, 3rem);
    padding: 2.5rem clamp(2rem, 3vw, 3rem);
  }

  .is-deck .sys--text .sys__body {
    grid-template-columns: minmax(0, 1fr);
  }

  /* A leaf with a figure gives the image the room: a set text column, and a figure that runs to
     the leaf's right edge with squared corners, so the next card's spine tucks over it. The image
     is drawn 1rem wider than its column: only the screenshot's own blank margin is cut (the Axis
     summary panel stays whole). The caption keeps clear of the edge. */
  .is-deck .sys:not(.sys--text) .sys__body {
    grid-template-columns: minmax(15rem, 18rem) minmax(0, 1fr);
    gap: 1.75rem;
    padding-inline: 2rem 0;
  }

  .is-deck .sys__figure img {
    width: calc(100% + 1rem);
    max-width: none;
    border-radius: var(--r-img) 0 0 var(--r-img);
  }

  .is-deck .sys__figure figcaption {
    padding-right: 2rem;
  }

  .is-deck .sys__heading {
    display: block;
    margin-top: 0.875rem;
    color: var(--on-dark);
    font: 800 var(--fs-display) / 0.88 var(--font-cond);
    letter-spacing: 0.005em;
    text-transform: uppercase;
  }

  .is-deck .sys__problem-title {
    margin-top: 1rem;
  }

  /* Content of the newly opened leaf fades and rises 12px (plan 4.4, item 2). */
  .is-deck .sys__text,
  .is-deck .sys__figure {
    transition:
      opacity var(--dur-3) var(--ease-out),
      transform var(--dur-3) var(--ease-out);
  }

  .is-deck .sys:not(.is-active) .sys__text,
  .is-deck .sys:not(.is-active) .sys__figure {
    opacity: 0;
    transform: translateY(12px);
  }

  .is-deck .sys.is-active .sys__text {
    transition-delay: 120ms;
  }

  .is-deck .sys.is-active .sys__figure {
    transition-delay: 180ms;
  }

  /* Text leaves: a set text column (a little wider than an image leaf's, so the case-study link stays on
     one line) and the statement panel where the figure goes. */
  .is-deck .sys.sys--text .sys__text {
    display: grid;
    grid-template-columns: minmax(17rem, 21rem) minmax(0, 1fr);
    column-gap: 2.5rem;
    align-content: center;
    height: 100%;
  }

  .is-deck .sys.sys--text .sys__text > * {
    grid-column: 1;
  }

  .is-deck .sys.sys--text .sys__statement {
    grid-column: 2;
    grid-row: 1 / span 6;
    align-self: center;
    max-width: none;
    margin: 0;
    padding: clamp(2rem, 3vw, 3rem);
  }

  .is-deck .sys.sys--text .sys__statement .sys__challenge {
    font-size: clamp(2rem, 2.8vw, 2.75rem);
    line-height: 1.12;
  }
}

/* One composed page transition: a system's panel morphs into its page header (no script). The
   per-system view-transition-name rules (#slug, #case-slug) are generated by the build for every
   system that has a page; see deckCss() in src/templates/components/deck.ts. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }

  /* The panel's morph uses the deck's own timing; the rest of the page cross-fades quickly beneath it. */
  ::view-transition-group(*) {
    animation-duration: var(--dur-4);
    animation-timing-function: var(--ease-out);
  }

  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: var(--dur-2);
  }
}

/* ledger.css */
/*
 * From operations to software (plan 6.3; reel 1's numbered rows with hairlines). Each row is one live
 * pair: the job by hand (with its compile step as an italic margin note), an arrow, the software it became.
 * Phones: the arrow moves into the number column on the "in software" line, so the relation still reads.
 */
.ops__grid {
  display: grid;
  gap: clamp(2rem, 4vw, 3rem);
}

.ops__lead {
  max-width: 26rem;
  margin-top: 1.25rem;
}

@media (min-width: 64rem) {
  .ops__grid {
    grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
    gap: 4rem;
    align-items: start;
  }
}

.ledger {
  --ledger-cols: 2.25rem minmax(0, 1fr);
}

.ledger__cols {
  display: none;
}

.ledger__rows {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--ink);
}

.ledger__row {
  display: grid;
  grid-template-columns: var(--ledger-cols);
  grid-template-areas:
    "num hand"
    ". step"
    "arrow soft";
  column-gap: 0.75rem;
  padding: 1.125rem 0 1.25rem;
  border-bottom: 1px solid var(--rule);
}

.ledger__num {
  grid-area: num;
  padding-top: 0.3em;
  color: var(--ink-3);
  font: 600 0.8125rem / 1 var(--font-sans);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
}

.ledger__hand {
  grid-area: hand;
  color: var(--ink-2);
  font-size: var(--fs-body);
  line-height: 1.4;
}

.ledger__step {
  grid-area: step;
  margin-top: 0.125rem;
  color: var(--ink-3);
  font: italic 400 1.0625rem / 1.35 var(--font-serif);
}

.ledger__arrow {
  grid-area: arrow;
  align-self: center;
  margin-top: 0.625rem;
  color: var(--amber-ink);
}

.ledger__arrow .icon {
  width: 1.25rem;
  height: 1.25rem;
  transition: transform var(--dur-2) var(--ease-out);
}

/* Phones: the column names, as a small tag on each side of the row. */
.ledger__tag {
  display: block;
  margin-bottom: 0.25rem;
  color: var(--ink-3);
  font: 600 var(--fs-label) / 1.2 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.ledger__soft .ledger__tag {
  color: var(--amber-ink);
}

.ledger__soft {
  grid-area: soft;
  margin-top: 0.625rem;
  color: var(--ink);
  font: 700 clamp(1.25rem, 1.9vw, 1.625rem) / 1.15 var(--font-sans);
  letter-spacing: -0.02em;
}

@media (min-width: 48rem) {
  .ledger {
    --ledger-cols: 2.5rem minmax(0, 1fr) 3rem minmax(0, 1.1fr);
  }

  .ledger__cols {
    display: grid;
    grid-template-columns: var(--ledger-cols);
    padding-bottom: 0.75rem;
    color: var(--ink-3);
    font: 600 var(--fs-label) / 1 var(--font-sans);
    letter-spacing: 0.14em;
    text-transform: uppercase;
  }

  .ledger__cols span:first-child {
    grid-column: 2;
  }

  .ledger__cols span:last-child {
    grid-column: 4;
  }

  .ledger__row {
    grid-template-areas:
      "num hand arrow soft"
      ". step arrow soft";
    align-items: start;
    padding-block: 1.25rem;
  }

  .ledger__arrow {
    align-self: start;
    margin-top: 0.125rem;
  }

  .ledger__soft {
    margin-top: 0;
  }

  /* The column heads carry the names here; the tags stay for assistive tech only (as .vh). */
  .ledger__tag {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@media (hover: hover) {
  .ledger__row:hover .ledger__arrow .icon {
    transform: translateX(4px);
  }
}

/* about.css */
/*
 * About (plan 6.4; reel 1): the live text on the left, an ID card hanging from a lanyard on the right.
 * Without JS the card's two faces are stacked, both readable. With JS (.is-enhanced) they share one cell
 * and the card turns over (rotateY, 420ms) from the button under it; reduced motion makes the swap instant.
 */
.about {
  border-top: 1px solid var(--rule);
}

.about__grid {
  display: grid;
  gap: 3.5rem;
}

@media (min-width: 60rem) {
  .about__grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: 4rem;
    align-items: start;
  }
}

.about__intro {
  margin-top: 1.5rem;
}

.about__summary {
  max-width: 34rem;
  margin-top: 1.25rem;
  color: var(--ink-2);
}

.about__blocks {
  max-width: 40rem;
  margin-top: 2.25rem;
  border-top: 1px solid var(--ink);
}

.about__block {
  display: grid;
  gap: 0.5rem;
  padding-block: 1.25rem;
  border-bottom: 1px solid var(--rule);
}

.about__label {
  color: var(--ink-3);
  font: 600 var(--fs-label) / 1.7 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

@media (min-width: 48rem) {
  .about__block {
    grid-template-columns: 9rem minmax(0, 1fr);
    gap: 1.5rem;
  }
}

/* ---- ID card ---- */
.idcard-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  padding-top: 5.5rem;
}

.idcard {
  position: relative;
  width: min(100%, 19rem);
  perspective: 1600px;
  rotate: -1.5deg;
  transform-origin: 50% -5.5rem;
}

/* The lanyard: an amber strap down to a dark clip that holds the card's punched slot. Decorative. */
.idcard__strap {
  position: absolute;
  bottom: calc(100% - 0.875rem);
  left: 50%;
  width: 1.375rem;
  height: 6.25rem;
  translate: -50% 0;
  border-inline: 1px solid var(--amber-ink);
  background: repeating-linear-gradient(180deg, var(--amber) 0 6px, #c69a59 6px 12px);
}

.idcard__strap::after {
  content: "";
  position: absolute;
  bottom: -0.375rem;
  left: 50%;
  width: 2.25rem;
  height: 1.125rem;
  translate: -50% 0;
  border-radius: 0.3rem;
  background: var(--ink-2);
}

/* Without JS both faces stack into one tall card, whose tilt would push a corner past a phone's
   edge; it hangs straight instead. */
@media (scripting: none) {
  .idcard {
    rotate: none;
  }
}

.idcard__inner {
  display: grid;
  gap: 0.75rem;
}

.idcard__face {
  position: relative;
  padding: 1.75rem 1.125rem 1.25rem;
  border: 1px solid var(--rule);
  border-radius: var(--r-img);
  background: var(--paper-raised);
  box-shadow: var(--shadow-float);
}

/* The punched slot the clip passes through. */
.idcard__face::before {
  content: "";
  position: absolute;
  top: 0.625rem;
  left: 50%;
  width: 2.5rem;
  height: 0.4375rem;
  translate: -50% 0;
  border-radius: var(--r-pill);
  background: var(--paper-sunk);
  box-shadow: inset 0 1px 2px rgb(23 23 20 / 0.25);
}

.idcard__band {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--rule);
  color: var(--ink-3);
  font: 600 0.75rem / 1 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.idcard__mark {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  font: 700 0.6875rem / 1 var(--font-sans);
  letter-spacing: 0.06em;
}

.idcard__photo img {
  width: 100%;
  margin-top: 0.875rem;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 0.5rem;
}

.idcard__name {
  margin-top: 0.875rem;
  color: var(--ink);
  font: 800 2.125rem / 0.9 var(--font-cond);
  text-transform: uppercase;
}

.idcard__role {
  margin-top: 0.5rem;
  color: var(--ink-2);
  font-size: 0.9375rem;
  line-height: 1.4;
}

.idcard__based {
  margin-top: 0.25rem;
  padding-block: 0.875rem;
  border-bottom: 1px solid var(--rule);
  color: var(--ink);
  font-weight: 500;
}

.idcard__facts {
  margin-top: 0.25rem;
}

.idcard__fact {
  padding-block: 0.875rem;
  border-bottom: 1px solid var(--rule);
}

.idcard__fact dt {
  color: var(--ink-3);
  font: 600 0.75rem / 1.3 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.idcard__fact dd {
  margin-top: 0.25rem;
  color: var(--ink);
  font-weight: 500;
  overflow-wrap: anywhere;
}

.idcard__fact .link {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
}

/* Enhanced: the faces share one cell and the card turns over. */
.idcard.is-enhanced .idcard__inner {
  gap: 0;
  transform-style: preserve-3d;
  transition: transform var(--dur-3) var(--ease-in-out);
}

.idcard.is-enhanced .idcard__face {
  grid-area: 1 / 1;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.idcard.is-enhanced .idcard__back {
  transform: rotateY(180deg);
}

.idcard.is-flipped .idcard__inner {
  transform: rotateY(180deg);
}

@media (prefers-reduced-motion: reduce) {
  .idcard {
    rotate: none;
  }

  .idcard.is-enhanced .idcard__inner {
    transition: none;
  }
}

/* capabilities.css */
/*
 * Capabilities (plan 6.5; reel 1's periodic-table tiles). Two families: Operating (ink tiles) and
 * Building (outlined tiles), each named by a heading with a swatch, so colour is never the only signal.
 * Default (no JS, < 48rem): each tile shows its example. Enhanced (.is-enhanced): tiles are buttons and the
 * selected one is mirrored in the detail card; the examples stay in the DOM, visually hidden.
 */
.caps {
  border-top: 1px solid var(--rule);
}

.caps__layout {
  display: grid;
  gap: 2rem;
  margin-top: clamp(2rem, 4vw, 3rem);
}

@media (min-width: 64rem) {
  .caps__layout.is-enhanced {
    grid-template-columns: minmax(0, 1fr) 19rem;
    gap: 3rem;
    align-items: start;
  }
}

.caps__families {
  display: grid;
  gap: 2.25rem;
}

.caps__family-title {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  color: var(--ink);
  font: 600 var(--fs-label) / 1.3 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.caps__swatch {
  width: 0.875rem;
  height: 0.875rem;
  border-radius: 3px;
}

.caps__family--operating .caps__swatch {
  background: var(--ink);
}

.caps__family--building .caps__swatch {
  border: 1.5px solid var(--ink);
  background: var(--paper-raised);
}

.caps__family-eg {
  max-width: 40rem;
  margin-top: 0.5rem;
  color: var(--ink-2);
}

.caps__tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 9.75rem), 1fr));
  gap: 0.625rem;
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
}

.tile {
  display: flex;
  flex-direction: column;
  border-radius: var(--r-tile);
  transition:
    box-shadow var(--dur-1) var(--ease-out),
    transform var(--dur-1) var(--ease-out);
}

.tile--operating {
  background: var(--ink);
  color: var(--paper);
}

.tile--building {
  border: 1px solid var(--rule-strong);
  background: var(--paper-raised);
  color: var(--ink);
}

.tile__face {
  display: grid;
  grid-template-rows: auto 1fr auto;
  flex: 1;
  min-height: 8.25rem;
  padding: 0.75rem 0.875rem 0.875rem;
}

.tile__num {
  font: 600 0.75rem / 1 var(--font-sans);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
}

.tile--operating .tile__num {
  color: var(--on-dark-3);
}

.tile--building .tile__num {
  color: var(--ink-3);
}

.tile__sym {
  margin-top: 0.375rem;
  font: 800 2.5rem / 1 var(--font-cond);
}

.tile__label {
  align-self: end;
  font: 600 0.9375rem / 1.25 var(--font-sans);
  letter-spacing: -0.005em;
}

.tile__eg {
  padding: 0 0.875rem 0.875rem;
  color: var(--ink-2);
  font-size: 0.875rem;
  line-height: 1.4;
}

.tile__eg-label {
  font-weight: 600;
  color: var(--ink);
}

/* ---- Enhanced ---- */
.caps__layout.is-enhanced .tile__eg {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.tile__btn {
  display: flex;
  flex: 1;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: inherit;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.tile__btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* Selected: an ink ring on a paper gap (reads on both tile families). */
.tile.is-selected {
  box-shadow:
    0 0 0 3px var(--paper),
    0 0 0 4.5px var(--ink);
}

@media (hover: hover) {
  .tile:has(.tile__btn):hover {
    transform: translateY(-2px);
  }
}

.caps__detail {
  padding: 1.5rem;
  border: 1px solid var(--rule);
  border-radius: var(--r-card);
  background: var(--paper-raised);
  box-shadow: var(--shadow-float);
}

.caps__detail-sym {
  color: var(--ink);
  font: 800 4.5rem / 0.9 var(--font-cond);
}

.caps__detail[data-family="building"] .caps__detail-sym {
  color: transparent;
  -webkit-text-stroke: 1.5px var(--ink);
}

.caps__detail-label {
  margin-top: 1rem;
  color: var(--ink);
  font: 700 1.375rem / 1.2 var(--font-sans);
  letter-spacing: -0.02em;
}

.caps__detail-eg {
  margin-top: 0.75rem;
  color: var(--ink-2);
}

@media (min-width: 64rem) {
  .caps__detail {
    margin-top: 2.25rem;
  }
}

/* track-record.css */
/*
 * Track record (plan 6.6): the live sentence set large against a thin vertical rule (reel 1), the four
 * clauses alternating the site's two heading voices, then the three live figures with their qualifiers.
 * The figures stay at section scale: no hero-sized proof block.
 */
.record {
  border-top: 1px solid var(--rule);
}

.record__grid {
  display: grid;
  gap: 3rem;
  margin-top: clamp(2rem, 4vw, 3.5rem);
}

@media (min-width: 64rem) {
  .record__grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: 4rem;
    align-items: end;
  }
}

.record__statement {
  padding-left: clamp(1rem, 3vw, 2rem);
  border-left: 1px solid var(--ink);
}

.record__body {
  max-width: 34rem;
  color: var(--ink-2);
  font-size: var(--fs-lead);
  line-height: 1.45;
}

.record__clauses {
  margin-top: 1.5rem;
  color: var(--ink);
  font: 700 clamp(2rem, 5vw, 4rem) / 1.04 var(--font-sans);
  letter-spacing: -0.035em;
}

.record__clauses span {
  display: block;
}

.record__clauses span:nth-child(even) {
  color: var(--ink-3);
  font: italic 400 1.08em / 1.04 var(--font-serif);
  letter-spacing: -0.01em;
}

.record__stats {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--ink);
}

.record__stat {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  gap: 1rem;
  align-items: baseline;
  padding-block: 1.125rem;
  border-bottom: 1px solid var(--rule);
}

.record__value {
  color: var(--ink);
  font: 800 clamp(2.5rem, 4vw, 3.25rem) / 0.9 var(--font-cond);
}

.record__label {
  color: var(--ink-2);
}

/* Confirmed context for a figure (G6, G7). No employer, no dates. */
.record__source {
  display: block;
  margin-top: 0.25rem;
  color: var(--ink-3);
  font: italic 400 1.0625rem / 1.3 var(--font-serif);
}

/* contact.css */
/*
 * Contact (plans 6.7 and 8). Left: heading, intro, the address as large linked text, the copy button
 * and its status, the Based row. Right: the enquiry composer in a raised card. Below: Mendwell between
 * rules, kept apart from the systems.
 */
.contact {
  border-top: 1px solid var(--rule);
}

.contact__grid {
  display: grid;
  gap: 3rem;
}

@media (min-width: 64rem) {
  .contact__grid {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    gap: 4rem;
    align-items: start;
  }
}

.contact__intro {
  max-width: 32rem;
  margin-top: 1.5rem;
}

.contact-email {
  margin-top: 2rem;
}

.copy-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-top: 0.75rem;
}

.copy-status {
  color: var(--ink-2);
  font-size: var(--fs-small);
}

.contact-based {
  margin-top: 1.5rem;
}

/* ---- Enquiry composer ---- */
.enquiry {
  padding: clamp(1.25rem, 3vw, 2.25rem);
  border: 1px solid var(--rule);
  border-radius: var(--r-card);
  background: var(--paper-raised);
  box-shadow: var(--shadow-float);
}

.enquiry__title {
  color: var(--ink);
  font: 700 1.5rem / 1.2 var(--font-sans);
  letter-spacing: -0.02em;
}

.enquiry__fallback {
  margin-top: 1rem;
  color: var(--ink-2);
}

.enquiry__form {
  margin-top: 1.25rem;
}

.enquiry__fields {
  display: grid;
  gap: 1rem;
}

@media (min-width: 40rem) {
  .enquiry__fields {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .field--wide {
    grid-column: 1 / -1;
  }
}

.field {
  display: grid;
  align-content: start;
  gap: 0.375rem;
}

.field__label {
  color: var(--ink);
  font-size: 0.9375rem;
  font-weight: 600;
}

.field__control {
  width: 100%;
  min-height: 2.875rem;
  padding: 0.625rem 0.75rem;
  border: 1px solid var(--rule-strong);
  border-radius: 0.5rem;
  background: var(--paper);
  color: var(--ink);
  font: 400 1rem / 1.4 var(--font-sans);
}

textarea.field__control {
  min-height: 8rem;
  line-height: 1.5;
  resize: vertical;
}

.field__control:focus-visible {
  border-color: var(--ink);
  outline: 2px solid var(--ink);
  outline-offset: 1px;
}

.field__control[aria-invalid="true"] {
  border: 2px solid var(--error);
}

.field__error {
  color: var(--error);
  font-size: 0.875rem;
  font-weight: 600;
}

.field__error:empty {
  display: none;
}

.enquiry__summary {
  margin-bottom: 1.25rem;
  padding: 1rem 1.125rem;
  border: 2px solid var(--error);
  border-radius: 0.5rem;
  background: var(--paper);
}

.enquiry__summary:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.enquiry__summary-title {
  color: var(--ink);
  font-weight: 700;
}

.enquiry__summary-list {
  margin: 0.375rem 0 0;
  padding-left: 1.25rem;
}

.enquiry__summary-list a {
  color: var(--error);
  font-weight: 600;
  text-underline-offset: 0.2em;
}

.enquiry__note {
  max-width: 36rem;
  margin-top: 1.25rem;
  color: var(--ink-2);
  font-size: var(--fs-small);
  line-height: 1.5;
}

.enquiry__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1rem;
}

.enquiry__status {
  margin-top: 1rem;
  color: var(--ink);
  font-weight: 500;
}

.enquiry__status:empty {
  margin-top: 0;
}

.enquiry__after {
  display: grid;
  gap: 0.375rem;
  margin-top: 1rem;
}

.enquiry__draft {
  min-height: 10rem;
}

@media (max-width: 29.99rem) {
  .enquiry__actions {
    flex-direction: column;
    gap: 0.625rem;
  }
}

/* ---- Mendwell ---- */
.mendwell {
  display: grid;
  gap: 0.5rem 2rem;
  margin-top: clamp(3rem, 6vw, 5rem);
  padding-block: 1.5rem;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--rule);
}

@media (min-width: 48rem) {
  .mendwell {
    grid-template-columns: 12rem minmax(0, 1fr) auto;
    align-items: center;
  }
}

.mendwell__name {
  color: var(--ink);
  font: 800 2rem / 1 var(--font-cond);
  text-transform: uppercase;
}

.mendwell__blurb {
  max-width: 34rem;
  color: var(--ink-2);
}

.mendwell__link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  justify-self: start;
  min-height: 2.75rem;
  color: var(--ink);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--amber);
  text-underline-offset: 0.22em;
}

.mendwell__link .icon {
  width: 1.125rem;
  height: 1.125rem;
  transition: transform var(--dur-2) var(--ease-out);
}

.mendwell__link:hover {
  text-decoration-color: currentColor;
}

.mendwell__link:hover .icon {
  transform: translateX(3px);
}

/* project.css */
/*
 * Project page. The header reuses the work panel's material (reel 2): warm dark gradient, 1px amber
 * border, condensed white title, outlined amber numeral top right, facts split by thin amber
 * dividers (reel 2's education rows). The body returns to reel 1's light page: two-column rows
 * separated by hairlines, like its quick-facts list.
 */
.case {
  padding-top: calc(var(--header-h) + 0.5rem);
}

.crumbs__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 0.625rem;
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--ink-3);
  font: 500 0.9375rem / 1.2 var(--font-sans);
}

.crumbs__list li {
  display: flex;
  align-items: center;
  gap: 0.625rem;
}

.crumbs__list li + li::before {
  content: "/";
  color: var(--rule-strong);
}

.crumbs__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;
  min-height: 2.75rem;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--amber);
  text-underline-offset: 0.22em;
}

.crumbs__link:hover {
  text-decoration-color: currentColor;
}

.case-head {
  margin-top: 0.25rem;
}

.case-head__panel {
  position: relative;
  overflow: clip;
  padding: clamp(1.5rem, 4vw, 3rem);
  border: 1px solid var(--amber);
  border-radius: var(--r-panel);
  background: linear-gradient(100deg, var(--panel) 0%, var(--panel-hi) 100%);
  color: var(--on-dark-2);
}

.case-head__num {
  position: absolute;
  top: clamp(1.25rem, 3.5vw, 2.75rem);
  right: clamp(1.5rem, 4vw, 3rem);
  color: transparent;
  font: 800 clamp(3rem, 7vw, 5.5rem) / 0.85 var(--font-cond);
  -webkit-text-stroke: 1.25px var(--amber);
}

.case-head__sector {
  max-width: calc(100% - 6rem);
  color: var(--amber-bright);
  font: 600 var(--fs-label) / 1.3 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.case-head__title {
  margin-top: clamp(2.5rem, 7vw, 5.5rem);
  color: var(--on-dark);
  font: 800 clamp(3.5rem, 9vw, 6rem) / 0.86 var(--font-cond);
  letter-spacing: 0.005em;
  text-transform: uppercase;
}

.case-head__problem {
  margin-top: 1rem;
  color: var(--on-dark);
  font: italic 400 var(--fs-h3) / 1.1 var(--font-serif);
}

.case-head__facts {
  display: grid;
  margin-top: clamp(2rem, 5vw, 3.5rem);
  border-top: 1px solid var(--amber-line);
}

.case-head__fact {
  padding: 1rem 0;
}

.case-head__fact + .case-head__fact {
  border-top: 1px solid var(--amber-line);
}

.case-head__fact dt {
  color: var(--amber-bright);
  font: 600 var(--fs-label) / 1.3 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.case-head__fact dd {
  margin-top: 0.375rem;
  color: var(--on-dark);
  font-weight: 500;
}

@media (min-width: 48rem) {
  .case-head__facts {
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
  }

  .case-head__fact {
    padding: 1.125rem 1.5rem 0.25rem;
  }

  .case-head__fact:first-child {
    padding-left: 0;
  }

  .case-head__fact + .case-head__fact {
    border-top: 0;
    border-left: 1px solid var(--amber-line);
  }
}

.case-body {
  padding-block: clamp(2.5rem, 6vw, 5rem) var(--section-pad);
}

.case-row {
  display: grid;
  gap: 0.75rem 2rem;
  padding-block: clamp(1.75rem, 4vw, 3rem);
  border-top: 1px solid var(--rule);
}

.case-row:first-child {
  border-top-color: var(--ink);
}

.case-row__label {
  color: var(--ink);
  font: 600 1.0625rem / 1.4 var(--font-sans);
  letter-spacing: -0.005em;
}

.case-row__body .lead {
  max-width: 40rem;
  color: var(--ink);
}

@media (min-width: 60rem) {
  .case-row {
    grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  }

  .case-row__label {
    padding-top: 0.2em;
  }
}

.case-figure img {
  width: 100%;
  border: 1px solid var(--rule);
  border-radius: var(--r-img);
  background: #fff;
  box-shadow: var(--shadow-float);
}

.case-figure figcaption {
  max-width: 40rem;
  margin-top: 0.875rem;
  color: var(--ink-3);
  font-size: var(--fs-small);
  line-height: 1.45;
}

/* No screenshot: the problem statement as a typographic panel. An amber rule beside ink text only. */
.case-statement {
  padding: clamp(1.5rem, 4vw, 2.5rem);
  border-left: 3px solid var(--amber);
  border-radius: 0 var(--r-card) var(--r-card) 0;
  background: var(--paper-sunk);
}

.case-statement__text {
  max-width: 36rem;
  color: var(--ink);
  font: italic 400 clamp(1.75rem, 3.4vw, 2.75rem) / 1.15 var(--font-serif);
}

.case-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  padding-top: clamp(1.75rem, 4vw, 3rem);
  border-top: 1px solid var(--rule);
}

/* Phones: full width, as in the hero. */
@media (max-width: 29.99rem) {
  .case-actions {
    flex-direction: column;
    gap: 0.625rem;
  }
}

/* Previous / next system. */
.case-nav {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 0.75rem;
  margin-top: 1.5rem;
}

.case-nav__link {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.375rem;
  min-height: 5rem;
  padding: 1rem 1.25rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-card);
  color: var(--ink);
  text-decoration: none;
  transition:
    background-color var(--dur-1) var(--ease-out),
    border-color var(--dur-1) var(--ease-out);
}

.case-nav__link--next {
  align-items: flex-end;
  text-align: right;
}

.case-nav__link:hover {
  border-color: var(--ink);
  background: var(--paper-raised);
}

.case-nav__kicker {
  color: var(--ink-3);
  font: 600 var(--fs-label) / 1.2 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.case-nav__title {
  font: 800 clamp(1.5rem, 3vw, 2rem) / 0.95 var(--font-cond);
  text-transform: uppercase;
}

/* footer.css */
.site-footer {
  border-top: 1px solid var(--rule);
}

.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.25rem 2rem;
  width: 100%;
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin-inline: auto;
  padding: 1.5rem var(--gutter) 2rem;
  color: var(--ink-3);
  font-size: var(--fs-small);
}

.site-footer__mail a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
}

/* generated from src/content/systems.ts (deckCss) */
@media (min-width: 75rem) {
  .deck.is-deck {
    --leaves: 4;
  }

  .is-deck > .sys:nth-child(1) {
    --i: 0;
  }

  .is-deck > .sys:nth-child(2) {
    --i: 1;
  }

  .is-deck > .sys:nth-child(3) {
    --i: 2;
  }

  .is-deck > .sys:nth-child(4) {
    --i: 3;
  }
}

#axis-crm,
#case-axis-crm {
  view-transition-name: sys-axis-crm;
}

#claimflow,
#case-claimflow {
  view-transition-name: sys-claimflow;
}

#knowledge-os,
#case-knowledge-os {
  view-transition-name: sys-knowledge-os;
}

#prompt-platform,
#case-prompt-platform {
  view-transition-name: sys-prompt-platform;
}
