/* Shared visual system: warm cream, deep green, quiet navigation. */
@font-face {
  font-family: "Syne";
  src: url("../assets/fonts/syne-latin-wght-normal.woff2") format("woff2");
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Instrument Sans";
  src: url("../assets/fonts/instrument-sans-latin-wght-normal.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../assets/fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../assets/fonts/ibm-plex-mono-latin-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* ---------- tokens ---------- */
:root {
  --font-wordmark: "Syne", sans-serif;
  --wordmark-size: 1.5rem;
  --wordmark-weight: 750;
  --wordmark-tracking: -0.09375rem;
  --nav-size: 0.75rem;
  --nav-gap: 1.875rem;
  --space-sm: 0.75rem;
  --space-md: 1.5rem;
  --space-lg: 1.75rem;
  --content-width: 93.75rem;
  --link-hover: #945034;
  --motion-duration: 200ms;
  --frame-sage: #d6e0d6;
  --frame-sand: #e5dfd4;
  --scene-text: #fff9ed;
  --wall: #f5f2e9;
  --mat: #eeeee3;
  --ink: #233e35;
  --ash: #626e61;
  --safelight: #945034;
  --amber: #d9bb89;
  --seam: #cfd3c6;
  --screen-ground: #23332e;
  --fog: #b7c2b4;

  --font-display: "Instrument Sans", sans-serif;
  --font-body: "Instrument Sans", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: "IBM Plex Mono", "SF Mono", Menlo, Consolas, monospace;

  --t-hero: clamp(2.27rem, 5.01vw + 0.96rem, 4.24rem);
  --t-h1: clamp(1.93rem, 3.47vw + 0.77rem, 3.08rem);
  --t-h2: clamp(1.4rem, 1.54vw + 0.87rem, 1.93rem);
  --t-h3: 1.2rem;
  --t-body: 1.0625rem;
  --t-mono: 0.8125rem;
  --t-mono-sm: 0.75rem;

  --measure: 66ch;
  --gutter: clamp(1.171875rem, 5vw, 5rem);
  --band: clamp(2.5rem, 5vw, 4.375rem);
  --radius: 4px;
  --frame-shadow: none;
}

/* ---------- base ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  scroll-behavior: smooth;
}
body {
  margin: 0;
  background: var(--wall);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.68;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
::selection {
  background: var(--ink);
  color: var(--wall);
}
img,
video,
iframe {
  max-width: 100%;
  display: block;
}
a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--seam);
  text-underline-offset: 0.2em;
  transition: text-decoration-color var(--motion-duration) ease, color var(--motion-duration) ease;
}
a:hover {
  color: var(--link-hover);
  text-decoration-color: var(--link-hover);
}
:focus-visible {
  outline: 2px solid var(--safelight);
  outline-offset: 3px;
  border-radius: 2px;
}
.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--ink);
  color: var(--wall);
  padding: 0.5rem 1rem;
  z-index: 20;
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  text-decoration: none;
}
.skip-link:focus {
  left: var(--gutter);
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.012em;
  margin: 0 0 0.6em;
  text-wrap: balance;
}
h1 {
  font-size: var(--t-h1);
}
h2 {
  font-size: var(--t-h2);
}
h3 {
  font-size: var(--t-h3);
  font-weight: 540;
}
p {
  margin: 0 0 1.1em;
  max-width: var(--measure);
}
.muted {
  color: var(--ash);
}
.em {
  font-style: italic;
}

/* ---------- the slate (signature element, quieter) ----------
   A gallery label: safelight tick, ash mono text. Sits at the top of
   pages and under imagery as a caption. */
/* Slates flow as normal inline text, not flex.
   They were display:flex with a gap, which made the label and the .dim span
   independent flex items: fine on screen, but any engine that lays the line
   out narrow (print export, or a very tight column) stacks them into two
   columns. Inline text can only ever wrap as a sentence. The tick is an
   inline-block ::before with a right margin instead of a flex gap. */
.slate {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ash);
  margin: 0 0 1.4rem;
  line-height: 1.5;
  text-wrap: pretty;
}
.slate::before {
  content: "";
  display: inline-block;
  vertical-align: middle;
  width: 16px;
  height: 9px;
  margin-right: 0.65rem;
  /* nudge up: inline-block sits on the baseline, flex centred it */
  position: relative;
  top: -0.05em;
  border-radius: 2px;
  background: repeating-linear-gradient(
    -55deg,
    var(--safelight) 0 3px,
    transparent 3px 7px
  );
}
.slate .dim {
  white-space: normal;
}
.slate .dim {
  color: var(--ash);
  opacity: 1;
}

/* ---------- layout ---------- */
.wrap {
  width: min(100% - 2 * var(--gutter), var(--content-width));
  margin-inline: auto;
}
.band {
  padding-block: var(--band);
  border-top: 1px solid var(--seam);
}
.band:first-of-type {
  border-top: 0;
}

/* Shared chrome, rendered from templates/partials at build time. */
.site-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-lg) var(--gutter);
  max-width: calc(var(--content-width) + 2 * var(--gutter));
  margin-inline: auto;
}
.wordmark {
  font-family: var(--font-wordmark);
  font-size: var(--wordmark-size);
  font-weight: var(--wordmark-weight);
  letter-spacing: var(--wordmark-tracking);
  line-height: 1.2;
  white-space: nowrap;
  text-decoration: none;
}
.wordmark > span {
  font-family: var(--font-body);
  vertical-align: super;
  font-size: 0.625rem;
  margin-left: 4px;
}
.site-nav, .site-footer nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm) var(--nav-gap);
  font-family: var(--font-body);
  font-size: var(--nav-size);
}
.site-header a, .site-footer a {
  color: var(--ink);
  text-decoration: none;
  transition: color var(--motion-duration) ease;
}
.site-header a:hover, .site-footer a:hover { color: var(--link-hover); }
.site-nav a { padding-block: 0.375rem; }
.site-nav a[aria-current] { text-decoration: underline; text-underline-offset: 0.4em; }
@media (max-width: 700px) {
  :root { --wordmark-size: 1.25rem; --nav-gap: 1rem; --nav-size: 0.6875rem; }
  .site-header { flex-wrap: wrap; gap: var(--space-sm); padding-block: var(--space-md); }
  .site-nav { width: 100%; justify-content: space-between; gap: 0.25rem 0.75rem; }
}

/* ---------- hero ---------- */
.hero {
  padding-block: clamp(4rem, 10vw, 7.5rem) clamp(3rem, 6vw, 4.5rem);
}
.hero h1 {
  font-size: var(--t-hero);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.022em;
  max-width: 21ch;
  margin-bottom: 1.6rem;
}
.hero h1 .accent {
  color: var(--safelight);
}
.hero .subline {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  color: var(--ash);
  letter-spacing: 0.03em;
  max-width: none;
}
/* Load sequence, retuned for the pale ground.
   On Ink, fading text in from opacity 0 read as "emerging from the dark".
   On Wall, part-opacity Ink text just looks light grey, which the eye reads
   as disabled rather than arriving. So the text steps carry the reveal with
   distance and a shorter fade, and the loud moment moves to the frame:
   a dark plate wiping up against a light ground is the highest-contrast
   event available here, and it lands last. */
.hero .slate,
.hero h1,
.hero .subline {
  animation: rise 420ms cubic-bezier(0.22, 0.72, 0.2, 1) both;
}
.hero h1 {
  animation-delay: 90ms;
}
.hero .subline {
  animation-delay: 190ms;
}
.hero figure.hung {
  animation: plate-in 640ms cubic-bezier(0.22, 0.72, 0.2, 1) 260ms both;
}
@keyframes plate-in {
  from {
    opacity: 0;
    clip-path: inset(14% 0 0 0);
  }
  to {
    opacity: 1;
    clip-path: inset(0 0 0 0);
  }
}
@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------- frames: media as hung objects ----------
   Imagery sits in an Ink letterbox with its own margin (the
   letterbox reveal), lifted off the wall by a soft shadow.
   Captions are slates, hung beneath like gallery labels. */
.frame {
  background: var(--screen-ground);
  border-radius: var(--radius);
  padding: clamp(10px, 1.6vw, 18px);
  box-shadow: var(--frame-shadow);
  margin: 0;
}
a.frame {
  display: block;
  transition: transform 200ms ease, box-shadow 200ms ease;
}
a.frame:hover {
  transform: translateY(-3px);
  box-shadow: var(--frame-shadow);
}
.screen16 {
  display: block; /* required: these are <span>s, and aspect-ratio
                     and overflow do not apply to inline boxes */
  width: 100%;
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--screen-ground);
}
.screen16 > iframe,
.screen16 > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  object-fit: cover;
}
figure.hung {
  margin: 2.2rem 0 2.6rem;
}
figure.hung > figcaption {
  margin-top: 1rem;
}
figure.hung > figcaption .slate {
  margin-bottom: 0.35rem;
  font-size: var(--t-mono-sm);
}
figure.hung > figcaption .title {
  font-family: var(--font-display);
  font-size: var(--t-h3);
  font-weight: 560;
}
figure.hung > figcaption .title a {
  text-decoration: none;
}
figure.hung > figcaption .title a:hover {
  color: var(--safelight);
}
figure.hung > figcaption p {
  color: var(--ash);
  margin: 0.3rem 0 0;
  max-width: 58ch;
}



/* Fallback for engines without aspect-ratio. Keeps the plates from
   collapsing again if one property fails to apply. */
@supports not (aspect-ratio: 16 / 9) {
  .screen16::before, .screen21::before, .screen45::before, .screen-diagram::before {
    content: "";
    display: block;
  }
  .screen16::before { padding-top: 56.25%; }
  .screen21::before { padding-top: 42.857%; }
  .screen45::before,
  .screen-diagram::before { padding-top: 125%; }
  @media (min-width: 640px) {
    .screen-diagram::before { padding-top: 56.25%; }
  }
}

/* Labeled placeholder plates retain their intrinsic ratios and dark green ground. */
.screen21 {
  display: block; /* required: these are <span>s, and aspect-ratio
                     and overflow do not apply to inline boxes */
  width: 100%;
  position: relative;
  aspect-ratio: 21 / 9;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--screen-ground);
}
.screen45 {
  display: block; /* required: these are <span>s, and aspect-ratio
                     and overflow do not apply to inline boxes */
  width: 100%;
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--screen-ground);
}
.screen21 > iframe, .screen21 > img,
.screen45 > iframe, .screen45 > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  object-fit: cover;
}
.awaiting::after {
  content: attr(data-awaiting);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 1rem;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fog);
  line-height: 1.6;
}
.awaiting::before {
  content: "";
  position: absolute;
  inset: 10px;
  border: 1px dashed color-mix(in srgb, var(--fog) 32%, transparent);
  border-radius: 3px;
}

/* sheet: contact-sheet grid of small plates */
.sheet {
  list-style: none;
  margin: 1.6rem 0 0;
  padding: 0;
  display: grid;
  gap: clamp(0.7rem, 1.6vw, 1.2rem);
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 760px) {
  .sheet { grid-template-columns: repeat(4, 1fr); }
  .sheet--3 { grid-template-columns: repeat(3, 1fr); }
}
.sheet .frame { border-radius: var(--radius); padding: 8px; }
.sheet .slate { margin: 0.55rem 0 0; font-size: 0.6875rem; letter-spacing: 0.1em; }

/* portrait: framed, narrower, sits beside prose on wide screens */
.portrait { max-width: 22rem; margin: 0 0 2rem; }
@media (min-width: 900px) {
  .with-portrait { display: grid; grid-template-columns: 22rem 1fr; gap: clamp(2rem, 4vw, 3.5rem); align-items: start; }
  .with-portrait .portrait { margin-bottom: 0; }
}


/* ---------- wide figures: authored diagrams break the prose measure ----------
   .prose caps at 66ch, which is right for reading and too narrow for a
   diagram. A .hung--wide figure keeps its left edge aligned with the prose
   but runs out to the full .wrap width, capped at the viewport so it can
   never cause a horizontal scrollbar. */
/* Diagram plates carry authored artwork, not photography. A 16:9 diagram is
   unreadable at the 315px a 375px phone gives it, so the plate turns portrait
   below 640px and takes a 4:5 companion export via <picture>. */
/* ---------- inline SVG diagrams ----------
   Two layout groups per diagram, one shown at a time. SVG cannot reflow (a
   viewBox is fixed and CSS cannot change it), so the generator emits a wide
   16:9 arrangement and a tall 4:5 one, both from the same data definition.
   The breakpoint is 760px, not 640: at 640 the plate is 568px and the
   smallest 34-unit label would render 12.1px, which is on the floor. At 760
   the plate is 674px and the same label renders 14.3px. */
.screen-diagram {
  display: block;
  width: 100%;
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--screen-ground);
}
/* the home page reuses the same diagrams in its 21:9 and 16:9 plates. The
   16:9 wide group centres with `meet`, and since the plate ground and the
   diagram ground are the same value, the extra width simply reads as more
   letterbox. */
.plate-diagram > .diagram,
.screen-diagram > .diagram {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.diagram--wide { display: none; }
.diagram--tall { display: block; }

/* Below the breakpoint the tall diagram is capped, or on a large phone /
   small tablet it would become an enormous portrait slab. */
@media (max-width: 759px) {
  .diagram-figure .frame { max-width: 34rem; margin-inline: auto; }
}
@media (min-width: 760px) {
  .screen-diagram { aspect-ratio: 16 / 9; }
  .diagram--wide { display: block; }
  .diagram--tall { display: none; }
}

/* Colours come from the palette tokens, so the diagrams re-theme themselves
   if the palette ever moves. A PNG pair could not do that. */
.d-label,
.d-meta { font-family: var(--font-mono); fill: var(--fog); }
.d-label { font-weight: 500; letter-spacing: 0.12em; }
/* Use the light accent for diagram emphasis on dark media surfaces. */
.d-label-accent {
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: 0.12em;
  fill: var(--amber);
}
.d-display,
.d-name { font-family: var(--font-wordmark); font-weight: 560; fill: var(--wall); }
.d-name-hot { font-family: var(--font-wordmark); font-weight: 560; fill: var(--amber); }
.d-body { font-family: var(--font-wordmark); font-weight: 500; fill: var(--fog); }
.d-tick { stroke: var(--fog); stroke-width: 3; }
.d-rule { stroke: var(--fog); stroke-width: 1; opacity: 0.4; }
.d-rule-accent { stroke: var(--amber); stroke-width: 3; }
.d-axis { stroke: var(--amber); stroke-width: 3; }
.d-axis-cap { fill: var(--amber); }
.d-drop { stroke: var(--fog); stroke-width: 1.5; opacity: 0.5; }
.d-link { stroke: var(--fog); stroke-width: 1.5; fill: none; opacity: 0.55; }
.d-node { fill: var(--fog); }
.d-band { fill: none; stroke: var(--wall); stroke-width: 2; }
.d-band-hot { fill: none; stroke: var(--amber); stroke-width: 3; }
.d-bar { fill: var(--fog); }
.d-bar-hot { fill: var(--amber); }
.d-family { fill: none; stroke: var(--fog); stroke-width: 1.5; opacity: 0.65; }
.d-dot { fill: var(--amber); }

figure.hung--wide {
  width: min(72rem, calc(100vw - 2 * var(--gutter)));
  max-width: none;
}
figure.hung--wide > figcaption {
  max-width: 58ch;
}

/* ---------- selected work: editorial entries, no containers ----------
   Deliberately not cards. Entries sit straight on the wall at three
   different widths, so the eye reads a composition rather than a grid.
   No mono metric strings: if a number matters it goes in the sentence. */
.section-title {
  margin-bottom: clamp(2rem, 4vw, 3.25rem);
}
.work-entry {
  margin: 0 0 clamp(3.5rem, 8vw, 7rem);
}
.work-entry:last-child {
  margin-bottom: 0;
}
.work-entry > figcaption {
  margin-top: 1.15rem;
  max-width: 46ch;
}
.work-entry > figcaption .title {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 1.45vw + 0.92rem, 1.83rem);
  font-weight: 560;
  line-height: 1.18;
  letter-spacing: -0.012em;
  margin: 0 0 0.45rem;
  max-width: 26ch;
}
.work-entry > figcaption .title a {
  text-decoration: none;
  color: var(--ink);
}
.work-entry > figcaption .title a:hover {
  color: var(--safelight);
}
.work-entry > figcaption p:not(.title) {
  color: var(--ash);
  margin: 0;
}
/* unequal widths so three entries do not stack as identical blocks */
@media (min-width: 900px) {
  .work-entry--offset {
    width: 62%;
    margin-left: auto;
  }
  .work-entry--narrow {
    width: 48%;
  }
}

/* hero subline in the body face: mono was carrying too much on this page */
.subline--prose {
  font-family: var(--font-body);
  font-size: 0.95rem;
  letter-spacing: 0;
  color: var(--ash);
  max-width: 52ch;
}

/* ---------- lanes ---------- */
.lanes {
  display: grid;
  gap: 1rem;
  list-style: none;
  padding: 0;
  margin: 0;
}
@media (min-width: 700px) {
  .lanes {
    grid-template-columns: 1fr 1fr;
  }
  }
.lane {
  border-top: 1px solid var(--seam);
  padding: 1.2rem 0.2rem 0.4rem;
  text-decoration: none;
  display: block;
}
.lane:hover .lane-title {
  color: var(--safelight);
}
.lane-title {
  font-family: var(--font-display);
  font-size: var(--t-h3);
  font-weight: 560;
  transition: color 160ms ease;
}
.lane p {
  color: var(--ash);
  margin: 0.25rem 0 0.5rem;
}
/* ---------- article / case study ---------- */
.article-header {
  padding-block: clamp(3.5rem, 8vw, 6rem) 2.5rem;
}
.article-header h1 {
  max-width: 20ch;
}
.standfirst {
  font-size: 1.2rem;
  line-height: 1.55;
  color: var(--ash);
  max-width: 58ch;
}
.spec {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.45rem 1.5rem;
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  margin: 2.2rem 0 0;
  padding: 1.2rem 0 0;
  border-top: 1px solid var(--seam);
  max-width: 46rem;
}
.spec dt {
  color: var(--ash);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.spec dd {
  margin: 0;
}
.prose {
  max-width: var(--measure);
}
.prose .kicker {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--safelight);
  margin: 2.8rem 0 0.8rem;
}
.prose h2 {
  margin-top: 0.1rem;
}
.pullquote {
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: -0.014em;
  font-size: clamp(1.3rem, 1.93vw + 0.87rem, 1.74rem);
  line-height: 1.35;
  border-left: 3px solid var(--safelight);
  padding: 0.35rem 0 0.35rem 1.3rem;
  margin: 2.4rem 0;
  max-width: 34ch;
  text-wrap: balance;
}
.callout {
  background: var(--mat);
  border: 1px solid var(--seam);
  border-left: 3px solid var(--safelight);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: 1.1rem 1.3rem 0.9rem;
  margin: 2rem 0;
  max-width: var(--measure);
}
.callout .label {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--safelight);
  margin: 0 0 0.4rem;
}
.callout p:last-child {
  margin-bottom: 0.2rem;
}

/* stat row */
.stats {
  display: flex;
  flex-wrap: wrap;
  gap: 2.2rem;
  margin: 2.2rem 0;
  padding: 0;
  list-style: none;
}
.stats .n {
  font-family: var(--font-display);
  font-size: clamp(1.93rem, 2.89vw + 0.96rem, 2.89rem);
  font-weight: 560;
  letter-spacing: -0.018em;
  line-height: 1;
  display: block;
}
.stats .l {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ash);
  display: block;
  margin-top: 0.4rem;
}

/* framework / process rows */
.rows {
  margin: 1.6rem 0 2.2rem;
  padding: 0;
  list-style: none;
  max-width: 46rem;
}
.rows li {
  display: grid;
  gap: 0.15rem 1.5rem;
  padding: 0.85rem 0.2rem;
  border-top: 1px solid var(--seam);
}
.rows li:last-child {
  border-bottom: 1px solid var(--seam);
}
@media (min-width: 640px) {
  .rows li {
    grid-template-columns: 15rem 1fr;
  }
}
.rows .k {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--ink);
}
.rows .v {
  color: var(--ash);
}

/* caption line under a frame (legacy) */
.caption {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.03em;
  color: var(--ash);
  margin-top: 1rem;
  margin-bottom: 2rem;
}

/* credit block */
.credits {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.4rem 1.5rem;
  max-width: 40rem;
  margin: 1.8rem 0;
}
.credits dt {
  color: var(--ash);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.credits dd {
  margin: 0;
}

/* ---------- notes index ---------- */
.note-list {
  list-style: none;
  padding: 0;
  margin: 0;
  max-width: 46rem;
}
.note-list li {
  border-top: 1px solid var(--seam);
  padding: 1.3rem 0.2rem;
}
.note-list li:last-child {
  border-bottom: 1px solid var(--seam);
}
.note-list h3 {
  margin-bottom: 0.3rem;
}
.note-list h3 a {
  text-decoration: none;
}
.note-list h3 a:hover {
  color: var(--safelight);
}
.note-list p {
  color: var(--ash);
  margin: 0 0 0.4rem;
}
.note-list .meta {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ash);
}
.note-list .upcoming h3 {
  color: var(--ash);
}

/* essay body */
.essay {
  max-width: var(--measure);
}
.essay p:first-of-type::first-letter {
  font-family: var(--font-display);
  font-weight: 560;
  font-size: 3.1em;
  float: left;
  line-height: 0.82;
  padding: 0.06em 0.12em 0 0;
  color: var(--safelight);
}

/* ---------- Spotify embed (kept inside an Ink frame elsewhere) ---------- */
.embed-spotify {
  border: 0;
  width: 100%;
  max-width: 46rem;
  height: 352px;
  border-radius: var(--radius);
  margin: 0 0 2rem;
}

/* ---------- contact / footer ---------- */
.contact-list {
  list-style: none;
  padding: 0;
  margin: 1.4rem 0 0;
  display: grid;
  gap: 0.55rem;
  font-family: var(--font-mono);
  font-size: var(--t-mono);
}
.contact-list .k {
  color: var(--ash);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  display: inline-block;
  min-width: 6.5rem;
}
.site-footer {
  width: min(100% - 2 * var(--gutter), var(--content-width));
  margin-inline: auto;
  border-top: 1px solid var(--seam);
  padding-block: var(--space-lg) calc(var(--space-lg) + 0.5rem);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-md);
  font-size: var(--nav-size);
}
.site-footer nav { justify-content: flex-end; }
@media (max-width: 700px) {
  .site-footer { align-items: flex-start; }
  .site-footer > a { white-space: nowrap; }
  .site-footer nav { gap: var(--space-sm) 1rem; }
}

/* section headers on index pages */
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.8rem;
}
.section-head h2 {
  margin: 0;
}
.section-head .more {
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ash);
  white-space: nowrap;
}
.section-head .more:hover {
  color: var(--safelight);
}

/* TODO placeholders. hidden from visitors; preview with ?draft */
.todo {
  display: none;
  border: 1px dashed color-mix(in srgb, var(--safelight) 55%, transparent);
  border-radius: var(--radius);
  padding: 1rem 1.2rem;
  font-family: var(--font-mono);
  font-size: var(--t-mono);
  color: var(--safelight);
  max-width: var(--measure);
  margin: 1.5rem 0;
}
html.show-drafts .todo {
  display: block;
}


/* ---------- case pager: the way between cases now the index is gone ---------- */
.case-pager {
  border-top: 1px solid var(--seam);
  padding: 2.4rem 0 0.5rem;
  margin-top: var(--band);
}
.case-pager > .wrap > .slate { margin-bottom: 1.2rem; }
.case-pager ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
}
@media (min-width: 760px) {
  .case-pager ul { grid-template-columns: 1fr 1fr; }
}
.case-pager a {
  display: block;
  background: var(--mat);
  border: 1px solid var(--seam);
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
  text-decoration: none;
  transition: border-color 180ms ease;
}
.case-pager a:hover { border-color: color-mix(in srgb, var(--safelight) 45%, var(--seam)); }
.case-pager .n {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--safelight);
  margin-bottom: 0.3rem;
}
.case-pager .t {
  display: block;
  font-family: var(--font-display);
  font-size: var(--t-h3);
  font-weight: 560;
  color: var(--ink);
  margin-bottom: 0.2rem;
}
.case-pager .d {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.04em;
  color: var(--ash);
}
/* the case you are already on: present for orientation, not a live target */
.case-pager li.here a {
  background: transparent;
  border-style: dashed;
  pointer-events: none;
}
.case-pager li.here .t { color: var(--ash); }

@media (prefers-reduced-motion: reduce) {
  .case-pager a { transition: none; }
}


/* ---------- audio visualizer (/sound/) ----------
   Lives inside a normal .screen21 plate, so it inherits the frame, ratio
   and letterbox ground. Controls sit on the plate rather than beside it,
   because the plate is the object and chrome around it would add furniture
   the sound page is meant to avoid. */
.vis-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
.vis-controls {
  position: absolute;
  left: clamp(0.75rem, 2vw, 1.25rem);
  bottom: clamp(0.75rem, 2vw, 1.25rem);
  display: flex;
  align-items: center;
  gap: 0.85rem;
}
.vis-play {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--wall);
  background: color-mix(in srgb, var(--wall) 8%, transparent);
  /* A visible border against the dark media surface. */
  border: 1px solid color-mix(in srgb, var(--wall) 50%, transparent);
  border-radius: 999px;
  padding: 0.42rem 0.9rem 0.42rem 0.75rem;
  cursor: pointer;
  transition: background-color 160ms ease, border-color 160ms ease;
}
.vis-play:hover {
  background: color-mix(in srgb, var(--wall) 16%, transparent);
  border-color: color-mix(in srgb, var(--wall) 62%, transparent);
}
.vis-play:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
}
/* triangle when paused, two bars when playing */
/* Use the light accent inside the dark player. */
.vis-icon {
  width: 9px;
  height: 10px;
  background: var(--amber);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}
.vis-play[aria-pressed="true"] .vis-icon {
  clip-path: polygon(0 0, 34% 0, 34% 100%, 0 100%, 66% 0, 100% 0, 100% 100%, 66% 100%);
}
.vis-time {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.06em;
  color: var(--fog);
}
.vis-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fog);
  text-align: center;
  padding: 1rem;
}
.vis-status {
  font-family: var(--font-mono);
  font-size: var(--t-mono-sm);
  letter-spacing: 0.04em;
  color: var(--ash);
  margin: 0.35rem 0 0;
}
/* Before JS runs, and if Web Audio is unavailable, show the native player
   and no dead controls. The page is never left with a button that does
   nothing. */
[data-visualizer] audio { display: none; }
[data-vis-mode="static"] .vis-controls,
[data-vis-mode="fallback"] .vis-controls { display: none; }
[data-vis-mode="fallback"] audio {
  display: block;
  width: calc(100% - 2rem);
  position: absolute;
  left: 1rem;
  bottom: 1rem;
}
[data-vis-mode="ready"] .vis-empty { display: none; }

@media (prefers-reduced-motion: reduce) {
  .vis-play { transition: none; }
}

/* ---------- scroll reveals (JS adds .js to <html>) ---------- */
/* Scroll reveals: shorter fade, longer travel than the dark build.
   Opacity does less perceptual work on a light ground, so distance does it
   instead, and the fade finishes early so nothing lingers as pale grey. */
html.js .reveal {
  opacity: 0;
  transform: translateY(16px);
}
html.js .reveal.in {
  opacity: 1;
  transform: none;
  transition: opacity 220ms ease-out, transform 380ms cubic-bezier(0.22, 0.72, 0.2, 1);
}
/* frames reveal by wipe, not fade: keeps the shadow from ghosting */
html.js figure.hung.reveal {
  opacity: 1;
  transform: none;
  clip-path: inset(12% 0 0 0);
  transition: clip-path 520ms cubic-bezier(0.22, 0.72, 0.2, 1);
}
html.js figure.hung.reveal.in {
  clip-path: inset(0 0 0 0);
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .hero .slate,
  .hero h1,
  .hero .subline,
  .hero figure.hung {
    animation: none;
  }
  html.js figure.hung.reveal {
    clip-path: none;
    transition: none;
  }
  html.js .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
  a.frame,
  a.frame:hover {
    transform: none;
    transition: none;
  }
}

/* Readable inner pages use the same grid as the homepage gallery. */
.wrap > *, .with-portrait > *, .spec > *, .credits > * { min-width: 0; }
.prose, .essay, .standfirst, .contact-list, .spec, .credits { overflow-wrap: anywhere; }
.sheet .frame { border-radius: var(--radius); }
.slate::before { display: none; }
@media (max-width: 600px) {
  .spec, .credits { grid-template-columns: 1fr; gap: 0.25rem; }
  .spec dd, .credits dd { margin-bottom: 0.75rem; }
  .contact-list .k { display: block; }
  .standfirst { font-size: 1.0625rem; }
}

/* ---------- chart pairs: report figures hung in a letterbox ---------- */
.chart-pair {
  display: grid;
  grid-template-columns: 1.17fr 1fr;
  gap: clamp(8px, 1.6vw, 18px);
  align-items: center;
}
.chart-pair img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 2px;
  background: #fff;
}
@media (max-width: 700px) {
  .chart-pair { grid-template-columns: 1fr; }
}

/* Wide figures break out of the prose column symmetrically (centered on it),
   so they never push past the right edge of the viewport. */
figure.hung--wide {
  margin-left: calc((100% - min(72rem, calc(100vw - 2 * var(--gutter)))) / 2);
  margin-right: 0;
}
