/* ==========================================================================
   ELVIS DS · static class layer
   The design system ships React components with inline styles. This file is
   those components translated to CSS classes, value for value.
   Reference implementations:
     ~/.claude/skills/elvis-ds-design/components/ (the .jsx files)
     ~/.claude/skills/elvis-ds-design/ui_kits/portfolio/_primitives.jsx
   Radius 0 everywhere. No shadow system. Seven-step spacing. Hairlines only.
   ========================================================================== */

/* --- base ---------------------------------------------------------------- */

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

/* Local override of a grid token. tokens.css mirrors upstream and stays untouched.
   Page margin 40px to 64px: measured on About, the rail's content column runs
   1112px while the paragraph inside caps at 506px, so 606px of the middle was
   already empty. The page did not lack white space, it lacked it at the edges,
   which is the half that reads as composed rather than left over. 64px is on the
   seven-step scale. Recorded in HOUSE-RULES.md. */
:root { --page-margin: 64px; }

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

body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-body);
  font-family: var(--font-body);
  font-size: var(--body-size);
  line-height: var(--body-leading);
  font-weight: var(--body-weight);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, video { max-width: 100%; display: block; }
a { color: inherit; }
button { font: inherit; }
::selection { background: var(--green-500); color: var(--ink-900); }

/* Ground colour. The sticky nav is 88% opaque, so the body shows through it;
   it also stops an overscroll bounce flashing the wrong colour on iOS. */
body.ground-green { background: var(--green-500); }
body.ground-forest { background: var(--green-900); }

/* Focus is always visible. On green and ink fields the green ring would
   disappear into the field, so those tones invert it. */
:focus-visible { outline: 2px solid var(--green-500); outline-offset: 3px; }
.field--green :focus-visible { outline-color: var(--ink-900); }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink-900); color: var(--sand-100);
  padding: 12px 16px; text-decoration: none;
}
.skip-link:focus { left: 0; }

/* --- type ---------------------------------------------------------------- */

.ds-display {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(56px, 11vw, 180px);
  letter-spacing: var(--display-tracking);
  line-height: var(--display-leading);
}

.ds-h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--h1-size);
  letter-spacing: var(--h1-tracking);
  line-height: var(--h1-leading);
  text-wrap: balance;
}

/* Local override of two type tokens. On a phone the clamp floors were 34 / 28 /
   24, only 6px and 4px apart, so h1 h2 h3 read as one size. Desktop was always
   fine at 80 / 43 / 24. Lowering the h2 and h3 floors reopens the steps on small
   screens and changes nothing above 900px. Recorded in HOUSE-RULES.md. */
:root { --h2-size: clamp(23px, 3vw, 44px); --h3-size: clamp(19px, 1.6vw, 24px); }

.ds-h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--h2-size);
  letter-spacing: var(--h2-tracking);
  line-height: var(--h2-leading);
  text-wrap: balance;
}

.ds-h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--h3-weight);
  font-size: var(--h3-size);
  letter-spacing: var(--h3-tracking);
  line-height: var(--h3-leading);
}

.ds-body { margin: 0; font-size: var(--body-size); line-height: var(--body-leading); max-width: var(--body-measure); text-wrap: pretty; }
.ds-body--sm { font-size: var(--body-small-size); line-height: var(--body-small-leading); }
.ds-body--lead { font-size: clamp(18px, 1.7vw, 25px); line-height: 1.38; max-width: 32ch; }
.ds-body strong, .ds-strong { font-weight: var(--body-emphasis-weight); }
.ds-muted { opacity: 0.72; }
.ds-muted-6 { opacity: 0.6; }

/* Label rule, luminance-aware. 400 on light, 500 on dark · .tone-dark on any
   ancestor flips every label inside it, which is the whole point of LabelLine. */
.ds-label {
  font-family: var(--font-label);
  font-weight: var(--label-weight-on-light);
  font-variant-numeric: tabular-nums;
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: var(--label-transform);
  margin: 0;
}
.tone-dark .ds-label { font-weight: var(--label-weight-on-dark); }
.ds-label--sm { font-size: var(--label-size-sm); }

.ds-wordmark {
  font-family: var(--font-display);
  font-weight: 800;
  letter-spacing: -0.03em;
  text-decoration: none;
  line-height: 1;
}

/* --- fields and layout --------------------------------------------------- */

.field { padding: var(--section-padding) var(--page-margin); }
.field--tight { padding: var(--space-6) var(--page-margin) var(--section-padding); }
.field--sand   { background: var(--sand-100); color: var(--ink-900); }
.field--green  { background: var(--green-500); color: var(--ink-900); }
.field--forest { background: var(--green-900); color: var(--sand-100); }
.field--ink    { background: var(--ink-900); color: var(--sand-100); }
.field--ruled  { border-bottom: 1px solid var(--border-default); }

.wrap { max-width: 1600px; margin: 0 auto; }

/* SectionHeading: 200px sticky rail + content. The system's default rhythm. */
.ds-rail { display: grid; grid-template-columns: 200px 1fr; gap: 48px; align-items: start; }
.ds-rail__label { position: sticky; top: 92px; }
.tone-dark .ds-rail__label { opacity: 0.6; }
.ds-rail__intro { margin: 18px 0 0; font-size: var(--body-size); line-height: var(--body-leading); max-width: 64ch; opacity: 0.72; text-wrap: pretty; }
.ds-rail__body { margin-top: 48px; }

.cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-5); }
.cols-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-6); }
.stack-3 > * + * { margin-top: var(--space-3); }
.stack-4 > * + * { margin-top: var(--space-4); }
.stack-5 > * + * { margin-top: var(--space-5); }

.hr { height: 1px; background: var(--border-strong); border: 0; margin: 0; }
.tone-dark .hr { background: var(--sand-rule); }

/* --- Button -------------------------------------------------------------- */

.ds-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 15px;
  /* Buttons are set in caps. Negative tracking would jam the caps together,
     so they take a positive step instead, short of the label rule's 0.09em. */
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 15px 26px;
  border: 1px solid transparent;
  border-radius: 0;
  box-shadow: none;
  cursor: pointer;
  text-decoration: none;
  background: none;
  transition: transform var(--dur-quick) var(--ease-out),
              background var(--dur-quick) linear,
              color var(--dur-quick) linear;
}
.ds-btn:hover { transform: translateY(var(--hover-y)); }
.ds-btn--sm { padding: 10px 18px; font-size: 14px; }
.ds-btn--lg { padding: 19px 34px; font-size: 17px; }

.ds-btn--primary { background: var(--green-500); color: var(--ink-900); }
.ds-btn--primary:hover { background: var(--ink-900); color: var(--green-500); }

.ds-btn--secondary { background: transparent; color: var(--ink-900); border-color: var(--ink-900); }
.ds-btn--secondary:hover { background: var(--ink-900); color: var(--sand-100); }

.ds-btn--invert { background: var(--sand-100); color: var(--ink-900); }
/* Was signal green, the exact colour of the field this button sits on, so it
   dissolved into the background on hover. Forest stays in the green family,
   never matches a field, and sand on forest is one of the four legal pairs.
   Rule: a hover colour may never equal the field it sits on. */
.ds-btn--invert:hover { background: var(--green-900); color: var(--sand-100); }

.ds-btn--ghost { background: transparent; color: var(--ink-900); border-color: var(--border-strong); }
.ds-btn--ghost:hover { background: rgba(20, 21, 15, 0.07); }

/* --- TextLink ------------------------------------------------------------
   The component turns the label green on hover. On sand that is the one pair
   the system bans outright ("green type on sand · contrast fails"), so on
   light fields only the underline goes green and the label stays ink. On ink
   and forest, green-on-ink is a legal pair and the whole link turns green. */

.ds-link {
  display: inline-block;
  font-family: var(--font-label);
  font-weight: var(--label-weight-on-light);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  padding-bottom: 3px;
  border-bottom: 1px solid currentColor;
  transition: color var(--dur-quick) linear, border-color var(--dur-quick) linear;
}
.ds-link:hover { border-bottom-color: var(--green-700); }
.tone-dark .ds-link { font-weight: var(--label-weight-on-dark); }
.tone-dark .ds-link:hover { color: var(--green-500); border-bottom-color: var(--green-500); }

/* --- Tag ----------------------------------------------------------------- */

.ds-tag {
  display: inline-block;
  font-family: var(--font-label);
  font-weight: var(--label-weight-on-light);
  font-variant-numeric: tabular-nums;
  font-size: var(--label-size);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 7px 12px;
  border: 1px solid transparent;
  border-radius: 0;
  background: var(--sand-300);
  color: var(--ink-900);
  cursor: pointer;
  transition: background var(--dur-quick) linear, color var(--dur-quick) linear;
}
.ds-tag--outline { background: transparent; border-color: var(--border-strong); }
.ds-tag--dark { background: var(--sand-08); color: var(--sand-100); font-weight: var(--label-weight-on-dark); }
.ds-tag.is-active { background: var(--green-500); color: var(--ink-900); }

/* Filter row. Layout lives here rather than inline so the mobile rule below can
   actually win; an inline display:flex outranks any media query. */
.ds-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--space-5); }

/* Reading panel on a colour field. Padding drops on a phone: 40px of inset on a
   390px screen spends a fifth of the width on nothing. */
.ds-panel { background: var(--sand-100); color: var(--ink-900); padding: var(--space-5); }

/* --- StatusBadge --------------------------------------------------------- */

.ds-badge {
  display: inline-block;
  font-family: var(--font-label);
  font-weight: var(--label-weight-on-dark);
  font-variant-numeric: tabular-nums;
  font-size: var(--label-size);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: var(--ink-900);
  color: var(--sand-100);
  padding: 7px 12px;
  border-radius: 0;
}
.ds-badge--active { color: var(--green-500); }

/* --- IndexRow ------------------------------------------------------------ */

.ds-row {
  display: grid;
  grid-template-columns: 90px 1fr auto;
  gap: var(--space-4);
  align-items: center;
  padding: 26px 8px;
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--border-strong);
  background: transparent;
  transition: background var(--dur-quick) var(--ease-out),
              padding-left var(--dur-base) var(--ease-out);
}
.ds-row:hover, .ds-row:focus-visible { background: rgba(20, 21, 15, 0.07); padding-left: 24px; }
.tone-dark .ds-row { border-bottom-color: var(--sand-rule); }
.tone-dark .ds-row:hover, .tone-dark .ds-row:focus-visible { background: rgba(242, 237, 227, 0.07); }

.ds-row__year, .ds-row__meta {
  font-family: var(--font-label);
  font-weight: var(--label-weight-on-light);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  opacity: 0.6;
}
.tone-dark .ds-row__year, .tone-dark .ds-row__meta {
  font-weight: var(--label-weight-on-dark);
  /* 60% sand on forest lands under AA at 12px. 72% keeps the recessive
     reading and clears it. */
  opacity: 0.72;
}
.ds-row__title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(20px, 2.4vw, 32px);
  letter-spacing: -0.028em;
  line-height: 1.1;
}
/* The client name is the hierarchy. What the job was is support, so it drops to
   body font at label size and loses the slash that was holding the two apart. */
.ds-row__sub {
  display: block;
  margin-top: 6px;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 15px;
  letter-spacing: 0;
  line-height: 1.35;
  opacity: 0.66;
}

.ds-index { border-top: 1px solid var(--border-strong); }
.tone-dark .ds-index { border-top-color: var(--sand-rule); }

/* --- Marquee ------------------------------------------------------------- */

/* Band sized down 30% on 2026-08-25. Padding moved 20px to 16px, which also
   puts it back on the seven-step scale it never belonged to. */
.ds-marquee { overflow: hidden; padding: 16px 0; background: var(--ink-900); color: var(--sand-100); }
.ds-marquee--green { background: var(--green-500); color: var(--ink-900); }
.ds-marquee--forest { background: var(--green-900); color: var(--sand-100); }
.ds-marquee__track { display: flex; width: max-content; animation: elvisMarq 26s linear infinite; }
.ds-marquee__run {
  display: flex;
  gap: 40px;
  padding-right: 40px;
  font-family: var(--font-body);
  font-size: clamp(15px, 2.4vw, 24px);
  font-weight: 500;
  /* Body leading is 1.6, a reading value. A single-line band wants less, and
     1.4 is what lands the band at 30% narrower with padding still on scale. */
  line-height: 1.4;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.ds-marquee__sep { color: var(--green-500); }
.ds-marquee--green .ds-marquee__sep { color: var(--ink-900); }
@keyframes elvisMarq { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* --- Brand strip ---------------------------------------------------------
   Client logos, supplied by Elvis. Each sits on its own 1:1 500x500 canvas and
   the relative sizing inside those squares is his, already balanced. So every
   logo renders in the SAME square box and nothing here re-scales them.

   Rendered as inline <use> from a sprite rather than <img>. An <img> rasterises
   the SVG at its intrinsic size and the compositor then resamples that bitmap at
   a fractional transform offset, which is what made them soft. Inline vectors are
   drawn at final device resolution.

   Full bleed: negative margins cancel the field padding so the strip runs edge to
   edge with no horizontal padding and no visible box around any logo. */

.ds-brandsprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.ds-brandstrip {
  overflow: hidden;
  margin-left: calc(var(--page-margin) * -1);
  margin-right: calc(var(--page-margin) * -1);
}
/* 60s is only the fallback lap time for the no-JS case. site.js overwrites it
   from data-speed so the strip moves at a constant px per second at any width. */
.ds-brandstrip__track {
  display: flex;
  width: max-content;
  animation: elvisMarq 60s linear infinite;
  will-change: transform;
  backface-visibility: hidden;
}
.ds-brandstrip__run { display: flex; align-items: center; gap: 24px; padding-right: 24px; }
.ds-brandstrip__logo {
  width: 104px;
  height: 104px;
  flex: 0 0 auto;
  display: block;
  opacity: 0.8;
  transition: opacity var(--dur-quick) linear;
}
.ds-brandstrip:hover .ds-brandstrip__logo { opacity: 1; }

@media (max-width: 560px) {
  .ds-brandstrip__logo { width: 84px; height: 84px; }
  .ds-brandstrip__run { gap: 16px; padding-right: 16px; }
}

/* --- ImagePlaceholder ---------------------------------------------------- */

.ds-ph {
  aspect-ratio: 4 / 3;
  background: repeating-linear-gradient(45deg, var(--sand-300) 0 10px, var(--sand-100) 10px 20px);
  border: 1px solid var(--border-strong);
  border-radius: 0;
  display: flex;
  align-items: flex-end;
  padding: 12px;
}
.ds-ph--green { background: repeating-linear-gradient(45deg, var(--green-500) 0 8px, var(--green-900) 8px 16px); border: none; }
.ds-ph--ink { background: repeating-linear-gradient(45deg, rgba(242,237,227,0.10) 0 10px, rgba(242,237,227,0.03) 10px 20px); border: none; }
/* The one circle in the system. `readme.md` grants exactly one exception to
   radius 0: the profile photo. Nothing else may use it. */
/* The real portrait. Same circle the placeholder used, which readme.md allows as
   the single exception to radius 0. */
.ds-portrait {
  width: 100%;
  /* height:auto is load-bearing. The img carries a height attribute so the
     browser can reserve space before load, and a specified height makes
     aspect-ratio inert: it only ever computes a MISSING dimension. Without this
     the circle rendered as a 260x640 ellipse. */
  height: auto;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  object-fit: cover;
  object-position: center 22%;
  display: block;
}

.ds-ph--circle {
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  border: none;
  align-items: center;
  justify-content: center;
}
.ds-ph--circle .ds-ph__cap { display: none; }

.ds-ph__cap {
  font-family: var(--font-label);
  font-weight: var(--label-weight-on-dark);
  font-variant-numeric: tabular-nums;
  font-size: var(--label-size-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--ink-900);
  color: var(--sand-100);
  padding: 5px 8px;
}

/* --- Card ---------------------------------------------------------------- */

.ds-card {
  display: block;
  padding: var(--space-5);
  border: 1px solid transparent;
  border-radius: 0;
  box-shadow: none;
  text-decoration: none;
  background: var(--white);
  color: var(--ink-900);
  transition: transform var(--dur-base) var(--ease-out);
}
.ds-card--plain { border-color: var(--border-strong); }
.ds-card--sand { background: var(--sand-300); }
.ds-card--invert { background: var(--ink-900); color: var(--sand-100); }
.ds-card--green { background: var(--green-500); color: var(--ink-900); }
.ds-card--forest { background: var(--green-900); color: var(--sand-100); }
.ds-card.is-lift:hover, .ds-card.is-lift:focus-visible { transform: translateY(-6px); }
.ds-card__meta {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  font-family: var(--font-label);
  font-weight: var(--label-weight-on-light);
  font-variant-numeric: tabular-nums;
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: 14px;
  margin-bottom: var(--space-5);
}
.ds-card--invert .ds-card__meta,
.ds-card--forest .ds-card__meta { border-bottom-color: var(--sand-rule); font-weight: var(--label-weight-on-dark); }

/* --- NavBar --------------------------------------------------------------
   The system asks for backdrop-filter: blur(6px). A blur behind an opaque
   fill does nothing, so the bar carries the field colour at 88% and lets the
   blur do its job. */

.ds-nav {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: 14px var(--page-margin);
  background: rgba(245, 241, 234, 0.88);
  color: var(--ink-900);
  border-bottom: 1px solid var(--border-default);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.ds-nav--dark {
  background: rgba(18, 59, 34, 0.88);
  color: var(--sand-100);
  border-bottom-color: var(--sand-rule);
}
/* Green pages keep the bar on the field rather than cutting a sand strip
   above it. Ink type on green is a legal pair, so the rule goes ink too. */
.ds-nav--green {
  background: rgba(67, 212, 139, 0.88);
  color: var(--ink-900);
  border-bottom-color: rgba(20, 21, 15, 0.3);
}
/* The system's 62% inactive-link opacity clears AA on sand (4.9:1) and forest
   (5.1:1) but lands at 4.0:1 on signal green. Nudged to 72% on this tone only
   (5.2:1); the system value stands everywhere it holds up. */
.ds-nav--green .ds-nav__links a,
.ds-nav--dark .ds-nav__links a { opacity: 0.72; }
.ds-nav--green .ds-nav__links a:hover,
.ds-nav--green .ds-nav__links a.is-active,
.ds-nav--dark .ds-nav__links a:hover,
.ds-nav--dark .ds-nav__links a.is-active { opacity: 1; }
.ds-nav__wordmark { font-size: 15px; }
.ds-nav__links { display: flex; gap: 22px; }
.ds-nav__links a { text-decoration: none; opacity: 0.62; transition: opacity var(--dur-quick) linear; }
.ds-nav__links a:hover, .ds-nav__links a.is-active { opacity: 1; }
.ds-nav__toggle { display: none; }

/* --- forms --------------------------------------------------------------- */

.ds-field { display: grid; gap: var(--space-2); }
.ds-field__req { color: var(--green-700); }
.ds-field__hint { font-size: 13px; line-height: 1.5; opacity: 0.6; }

.ds-input, .ds-select {
  width: 100%;
  background: var(--white);
  color: var(--ink-900);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  padding: 14px 16px;
  border: 1px solid var(--border-strong);
  border-radius: 0;
  outline: none;
  transition: border-color var(--dur-quick) linear;
}
.ds-input:focus, .ds-select:focus { border-color: var(--green-500); }
.ds-input::placeholder { color: var(--ink-60); opacity: 1; }
.ds-input:user-invalid { border-color: var(--green-900); }
textarea.ds-input { resize: vertical; }
.ds-select { appearance: none; padding-right: 40px; }
.ds-select-wrap { position: relative; display: block; }
.ds-select-wrap::after {
  content: "\25BE";
  position: absolute; right: 16px; top: 50%; transform: translateY(-50%);
  pointer-events: none; font-family: var(--font-label); font-size: 12px; opacity: 0.6;
}

.ds-check { display: inline-flex; align-items: center; gap: 12px; cursor: pointer; font-size: 15px; line-height: 1.5; }
.ds-check input { position: absolute; opacity: 0; width: 0; height: 0; }
.ds-check__box {
  width: 20px; height: 20px; flex: 0 0 auto;
  background: var(--white);
  border: 1px solid var(--border-strong);
  border-radius: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-label); font-size: 12px; color: var(--ink-900);
  transition: background var(--dur-quick) linear, border-color var(--dur-quick) linear;
}
.ds-check input:checked + .ds-check__box { background: var(--green-500); border-color: var(--green-500); }
.ds-check input:checked + .ds-check__box::after { content: "\2713"; }
.ds-check input:focus-visible + .ds-check__box { outline: 2px solid var(--green-500); outline-offset: 3px; }

/* --- motion: reveal ------------------------------------------------------
   Opacity 0 → 1, translateY 28px → 0, 720ms ease-out, 70ms stagger in fours.
   Elements never animate out · site.js unobserves after the first entry. */

.reveal {
  opacity: 0;
  transform: translateY(var(--enter-y));
  transition: opacity var(--dur-reveal) var(--ease-out),
              transform var(--dur-reveal) var(--ease-out);
}
.reveal.is-in { opacity: 1; transform: none; }
.no-js .reveal { opacity: 1; transform: none; }

/* --- cursor thumbnail ---------------------------------------------------- */

.cursor-thumb {
  position: fixed; top: 0; left: 0;
  width: 260px; height: 170px;
  pointer-events: none; z-index: 40; opacity: 0;
  background: repeating-linear-gradient(45deg, var(--green-500) 0 8px, var(--green-900) 8px 16px);
  display: flex; align-items: flex-end; padding: 10px;
  transition: opacity var(--dur-quick) linear;
}
.cursor-thumb.is-on { opacity: 1; }

/* --- page furniture ------------------------------------------------------ */

.cover { min-height: 78vh; min-height: 78dvh; display: grid; align-content: center; padding: 96px var(--page-margin) var(--space-6); }
.cover__meta { display: grid; grid-template-columns: 1fr auto; gap: var(--space-4); border-bottom: 1px solid rgba(20, 21, 15, 0.3); padding-bottom: 20px; }

.brandrow { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-6); align-items: baseline; }
.brandrow__name { font-family: var(--font-display); font-weight: 800; font-size: clamp(24px, 3.6vw, 52px); letter-spacing: -0.032em; line-height: 1; }

.stat { border-top: 1px solid var(--sand-rule); padding-top: var(--space-3); }
.stat__figure { font-family: var(--font-display); font-weight: 800; font-size: clamp(30px, 4vw, 56px); letter-spacing: -0.035em; line-height: 1; }

/* --- Approach diagrams ---------------------------------------------------
   All six figures are Elvis's own drawings. The five stage marks are filled
   hand-drawn paths on the same 500x500 canvas his logos use; the master keeps
   the stroked treatment. Both take currentColor so a figure works on any field,
   and the master gets non-scaling-stroke so its hairline stays a hairline at
   every size. Nothing here restyles the artwork. */

.ds-approach-hero { margin-top: var(--space-6); }
.ds-approach-fig { width: 100%; max-width: 860px; height: auto; color: var(--ink-900); display: block; }
.ds-approach-fig .st0 { fill: none; stroke: currentColor; vector-effect: non-scaling-stroke; }

.ds-phase__fig { width: 100%; height: auto; display: block; align-self: center; }

.phase { display: grid; grid-template-columns: 64px 1fr 112px; gap: var(--space-4); padding: var(--space-5) 0; border-bottom: 1px solid var(--border-strong); align-items: center; }
.tone-dark .phase { border-bottom-color: var(--sand-rule); }

.exp-row { display: grid; grid-template-columns: 180px 1fr auto; gap: var(--space-4); align-items: baseline; padding: 22px 0; border-bottom: 1px solid var(--border-strong); }

.site-footer { background: var(--ink-900); color: var(--sand-100); padding: var(--space-6) var(--page-margin) var(--space-5); }
.site-footer__top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-5); align-items: flex-end; }
.site-footer__mark { font-family: var(--font-display); font-weight: 800; font-size: clamp(21px, 3.5vw, 48px); letter-spacing: -0.03em; line-height: 0.9; }
.site-footer__contact { font-family: var(--font-label); font-weight: 500; font-variant-numeric: tabular-nums; font-size: 11px; letter-spacing: 0.07em; line-height: 2; text-transform: uppercase; opacity: 0.7; }
.site-footer__contact a { text-decoration: none; border-bottom: 1px solid transparent; transition: color var(--dur-quick) linear, border-color var(--dur-quick) linear; }
.site-footer__contact a:hover { color: var(--green-500); border-bottom-color: var(--green-500); }
.site-footer__rule { height: 1px; background: rgba(242, 237, 227, 0.2); margin: var(--space-5) 0 var(--space-3); }
.site-footer__legal { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-3); font-family: var(--font-label); font-weight: 500; font-variant-numeric: tabular-nums; font-size: 10px; letter-spacing: 0.08em; opacity: 0.5; text-transform: uppercase; }

/* --- responsive ---------------------------------------------------------- */

@media (max-width: 900px) {
  :root { --page-margin: 24px; --section-padding: 64px; }
  /* !important because several pages set grid-template-columns inline for their
     desktop composition, and an inline style outranks any normal rule. Without
     this the contact form stayed two columns at 390px and rendered 80px wide. */
  .ds-rail, .cols-2 { grid-template-columns: 1fr !important; gap: 28px; }
  .ds-rail__label { position: static; }
  .cover__meta { grid-template-columns: 1fr; }
  .ds-row { grid-template-columns: 64px 1fr; }
  .ds-row__meta { grid-column: 2; opacity: 0.5; }
  .exp-row { grid-template-columns: 1fr; gap: 4px; }
  .phase { grid-template-columns: 44px 1fr; }
  .ds-phase__fig { grid-column: 2; max-width: 112px; margin-top: 16px; }
  .ds-nav { padding: 12px var(--page-margin); }
  .ds-nav__links { gap: 14px; font-size: 10px; }
  .ds-nav__meta { display: none; }
  .ds-card { padding: var(--space-4); }
}

@media (max-width: 560px) {
  /* Wordmark centred on its own line, links centred under it and spread to the
     page padding on both edges, both a step larger than before. */
  .ds-nav {
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 14px var(--page-margin);
  }
  .ds-nav__wordmark { font-size: 17px; }
  .ds-nav__links { width: 100%; justify-content: space-between; gap: 0; font-size: 12px; }

  /* Buttons go full width. Mixed-width buttons stacking unevenly is the single
     ugliest thing on a narrow screen, and a full-width target is easier to hit. */
  .ds-btn { width: 100%; }

  /* Filter chips line up in two even columns instead of ragged wrapping. */
  .ds-filters { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  .ds-filters .ds-tag { text-align: center; padding: 10px 8px; }

  /* Index rows stack. The year stops holding an empty gutter beside the title. */
  .ds-row { grid-template-columns: 1fr; gap: 6px; padding-left: 0; }
  .ds-row:hover, .ds-row:focus-visible { padding-left: 8px; }
  .ds-row__meta { grid-column: 1; }

  .ds-panel { padding: var(--space-4); }

  .cover { min-height: 0; padding: var(--space-6) var(--page-margin); }
  /* Wordmark and contact block sit side by side with their tops level, rather
     than wrapping onto two rows. Both fit: the mark is ~85px wide at 21px and
     the contact column ~200px, inside 342px of usable width. */
  .site-footer__top { gap: var(--space-4); flex-wrap: nowrap; align-items: flex-start; }
  .site-footer__mark { flex: 0 0 auto; }
  /* Box tops are level but the cap heights were not, by 7px. The contact block
     runs line-height 2 on 11px, so ~5.5px of leading sits above its first cap,
     while the wordmark's 0.9 leading lets its cap sit 2px above its own box.
     Both sizes are fixed through this whole breakpoint (mark clamps to 21px,
     contact is 11px), so the correction is a constant, not a magic number. */
  .site-footer__contact { margin-top: -7px; }

  /* Cover label breaks onto two lines and drops the middot, which is only a
     separator for the single-line desktop version. */
  .ds-label__mid { display: none; }
  .ds-label__line { display: block; }
}

/* --- reduced motion ------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .ds-marquee__track, .ds-brandstrip__track { animation: none; }
  /* A frozen strip cut off at both edges looks broken. Under reduced motion it
     becomes a plain centred row that wraps, which reads as a decision. */
  .ds-brandstrip { overflow: visible; margin-left: 0; margin-right: 0; }
  .ds-brandstrip__track { width: auto; }
  .ds-brandstrip__run { flex-wrap: wrap; justify-content: center; row-gap: 8px; }
  .ds-brandstrip__run[aria-hidden="true"] { display: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .ds-btn, .ds-card, .ds-row { transition: none; }
  .ds-btn:hover, .ds-card.is-lift:hover { transform: none; }
  .ds-row:hover { padding-left: 8px; }
}

/* --- print --------------------------------------------------------------- */

@media print {
  .ds-nav, .ds-marquee, .cursor-thumb, .skip-link { display: none; }
  body { background: #fff; }
  .field { padding: 16mm; }
  .reveal { opacity: 1; transform: none; }
}
