/* Richy Koshy portfolio: the one shared stylesheet. Governed by DESIGN_RULES.md. */
@layer tokens, base, layout, components, utilities;

/* Plex Sans (variable) for 400 and 600, Latin subset. */
@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/plex-sans.woff2") format("woff2");
  font-weight: 100 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/plex-sans-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../fonts/plex-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Metric-matched fallbacks, so the swap to Plex doesn't shift the layout. */
@font-face {
  font-family: "Plex Sans Fallback";
  src: local("Arial"), local("ArialMT"), local("Liberation Sans"), local("Arimo");
  font-weight: 400;
  font-style: normal;
  size-adjust: 100.78%;
  ascent-override: 101.7%;
  descent-override: 27.29%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Plex Sans Fallback";
  src: local("Arial Italic"), local("Arial-ItalicMT"), local("Liberation Sans Italic"), local("Arimo Italic");
  font-weight: 400;
  font-style: italic;
  size-adjust: 100.78%;
  ascent-override: 101.7%;
  descent-override: 27.29%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Plex Sans Fallback";
  src: local("Arial Bold"), local("Arial-BoldMT"), local("Liberation Sans Bold"), local("Arimo Bold");
  font-weight: 600;
  font-style: normal;
  size-adjust: 96.97%;
  ascent-override: 105.71%;
  descent-override: 28.36%;
  line-gap-override: 0%;
}
/* Android: Roboto, tuned on its own. */
@font-face {
  font-family: "Plex Sans Fallback Android";
  src: local("Roboto"), local("Roboto Regular"), local("Roboto-Regular");
  font-weight: 400;
  font-style: normal;
  size-adjust: 101.38%;
  ascent-override: 101.1%;
  descent-override: 27.13%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Plex Sans Fallback Android";
  src: local("Roboto Bold"), local("Roboto-Bold");
  font-weight: 600;
  font-style: normal;
  size-adjust: 103.14%;
  ascent-override: 99.38%;
  descent-override: 26.66%;
  line-gap-override: 0%;
}
/* Mono candidates all advance 0.6em, so one override set fits. */
@font-face {
  font-family: "Plex Mono Fallback";
  src: local("Courier New"), local("CourierNewPSMT"), local("Liberation Mono"), local("Cousine"), local("Droid Sans Mono"), local("DroidSansMono"), local("Roboto Mono");
  font-weight: 400;
  font-style: normal;
  size-adjust: 100%;
  ascent-override: 102.52%;
  descent-override: 27.5%;
  line-gap-override: 0%;
}

/* Cross-document view transitions, only without reduced motion. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
}

@layer tokens {
  :root {
    /* Colour. Dark is Richy's palette and the fallback without light-dark(). */
    color-scheme: dark;
    --bg: #0B0E1C;
    --surface: #141A2E;
    --text: #DDE7E4;                /* 15.20:1 on bg, 13.66:1 on surface; APCA Lc 90 */
    --text-strong: #FFFFFF;         /* headings and bold keywords only */
    --text-muted: #AEC3BE;          /* 10.38:1 on bg, 9.33:1 on surface; APCA Lc 67 */
    --border: #232B47;              /* decorative hairlines only (1.38:1) */
    --border-strong: #6A7391;       /* UI borders; fails as small text, so never used for text */
    --accent: #5FD4B0;
    --accent-hover: #83E3C6;
    --accent-pressed: #A3EAD5;      /* a step past hover in the same hue */
    --accent-contrast: #04241A;     /* 9.06:1 on accent */
    --rule-accent: #5FD4B0;         /* non-text accents only: the title rule and keyword underline */
    /* Links: the accent's lighter tint (Lc 78; #5FD4B0 is Lc 68). */
    --link: #83E3C6;                /* 12.59:1 on bg, 11.31:1 on surface */
    --focus: #5FD4B0;
    --shadow-colour: rgb(4 6 14 / 0.55);

    /* Type */
    --font-sans: "IBM Plex Sans", "Plex Sans Fallback", "Plex Sans Fallback Android", sans-serif;
    --font-mono: "IBM Plex Mono", "Plex Mono Fallback", ui-monospace, monospace;
    --weight-regular: 400;
    --weight-strong: 600;
    /* Fluid modular scale: ratio 1.25 at 320px (17px base), 1.333 at 1440px (18px). */
    --step--1: 0.875rem;
    --step-0: clamp(1.0625rem, 1.0446rem + 0.0893vw, 1.125rem);
    --step-1: clamp(1.3281rem, 1.2791rem + 0.245vw, 1.5rem);
    --step-2: clamp(1.6602rem, 1.5633rem + 0.4841vw, 2rem);
    --step-3: clamp(2.0752rem, 1.9068rem + 0.8421vw, 2.6667rem);
    --step-4: clamp(2.594rem, 2.3203rem + 1.3686vw, 3.5556rem);
    --leading-body: 1.6;
    --leading-prose: 1.65;
    --leading-snug: 1.25;
    --leading-heading: 1.2;
    --leading-tight: 1.1;
    --tracking-display: -0.01em;
    /* 55ch sets about 66 real characters; a ch is the width of "0". */
    --measure: 55ch;

    /* Spacing: the only scale. */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;
    --space-8: 4rem;
    --space-9: 6rem;
    --space-10: 8rem;

    /* Layout. The ch measures resolve in each element's own font. */
    --container: 72rem;
    --gutter: var(--space-4);
    --section-space: var(--space-7);
    --header-size: 3.5rem;
    --target: 2.75rem;              /* 44px touch target */
    --hero-width: 48rem;            /* 8 of 12 columns; the right third stays empty on purpose */
    --measure-claim: 20ch;
    --measure-standfirst: 52ch;
    --measure-outcome: 40ch;
    --measure-case-claim: 24ch;
    --column-min: 14rem;
    --scan-width: 52rem;
    --diagram-min: 52.5rem;         /* the wide diagrams stay legible; narrower screens scroll */

    /* Shape: two radii, one elevation */
    --radius-sm: 0.25rem;           /* buttons, inline code, skip link */
    --radius-md: 0.5rem;            /* code blocks, figures, letter scans */
    --border-width: 1px;
    --rule-width: 2px;
    --focus-width: 2px;
    --focus-offset: 3px;
    --underline-offset: 0.2em;
    --underline-offset-current: 0.35em;
    --keyword-underline: 0.11em;
    --keyword-underline-offset: 0.16em;
    /* em-based, so both view-transition snapshots scale together. */
    --title-rule: 0.0625em;
    --title-rule-gap: 0.125em;
    --icon-size: 1.25rem;
    --icon-size-sm: 1.125rem;
    --glow-size: 0.375rem;
    --icon-stroke: 1.75;
    --z-header: 50;
    --z-skip-link: 100;
    /* The single elevation level, for the letter scans. */
    --shadow-raised: 0 1px 2px var(--shadow-colour), 0 8px 24px var(--shadow-colour);
    --inline-icon: 0.85em;
    --logo-size: 1em;

    /* Motion */
    --ease-out: cubic-bezier(0.2, 0, 0, 1);
    --duration-morph: 300ms;
    --duration-fade-out: 150ms;
    --duration-fade-in: 250ms;
    --duration-hover: 150ms;
  }

  /* One declaration per token for both themes; color-scheme picks the branch. */
  @supports (color: light-dark(#000, #fff)) {
    :root {
      color-scheme: light dark;
      --bg: light-dark(#F5F6FA, #0B0E1C);
      --surface: light-dark(#FFFFFF, #141A2E);
      --text: light-dark(#0B0E1C, #DDE7E4);
      --text-strong: light-dark(#0B0E1C, #FFFFFF);
      --text-muted: light-dark(#42517F, #AEC3BE);     /* light: 7.16:1 on bg, 7.73:1 on surface */
      --border: light-dark(#DCE0F0, #232B47);
      --border-strong: light-dark(#6A7391, #6A7391);  /* light: 4.35:1 on bg */
      --accent: light-dark(#0A7C5F, #5FD4B0);         /* teal fails on light (1.69:1); #0A7C5F is 4.79:1 */
      --accent-hover: light-dark(#086A51, #83E3C6);
      --accent-pressed: light-dark(#065541, #A3EAD5);
      --accent-contrast: light-dark(#FFFFFF, #04241A);
      /* Non-text teal in light mode: 3.12:1 on bg, 3.37:1 on surface. */
      --rule-accent: light-dark(#1F9E7A, #5FD4B0);
      --link: light-dark(#0A7C5F, #83E3C6);
      --focus: light-dark(#0A7C5F, #5FD4B0);
      --shadow-colour: light-dark(rgb(11 14 28 / 0.08), rgb(4 6 14 / 0.55));
    }
    :root[data-theme="light"] { color-scheme: light; }
    :root[data-theme="dark"] { color-scheme: dark; }
  }

  @media (min-width: 48rem) {
    :root {
      --gutter: var(--space-5);
      --section-space: var(--space-8);
    }
  }
  @media (min-width: 64rem) {
    :root {
      --gutter: var(--space-6);
      --section-space: var(--space-9);
    }
  }
}

@layer base {
  *, *::before, *::after { box-sizing: border-box; }
  * { margin: 0; }

  html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    /* The sticky header never covers focus; --header-offset is measured by
       js/site.js. */
    scroll-padding-block-start: calc(var(--header-offset, var(--header-size)) + var(--space-4));
  }

  body {
    min-block-size: 100vh;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-sans);
    font-size: var(--step-0);
    font-weight: var(--weight-regular);
    line-height: var(--leading-body);
    font-synthesis: none;
    -webkit-font-smoothing: antialiased;
  }

  h1, h2, h3, h4 {
    color: var(--text-strong);
    font-weight: var(--weight-strong);
    line-height: var(--leading-heading);
    text-wrap: balance;
  }
  h1 { font-size: var(--step-3); letter-spacing: var(--tracking-display); }
  h2 { font-size: var(--step-2); }
  h3 { font-size: var(--step-1); line-height: var(--leading-snug); }
  h4 { font-size: var(--step-0); }

  p, li, dd, dt, figcaption, blockquote { text-wrap: pretty; }
  strong, b {
    color: var(--text-strong);
    font-weight: var(--weight-strong);
  }

  a {
    color: var(--link);
    text-decoration-line: underline;
    text-decoration-thickness: var(--border-width);
    text-underline-offset: var(--underline-offset);
  }
  a:hover { text-decoration-thickness: var(--rule-width); }

  :focus-visible {
    outline: var(--focus-width) solid var(--focus);
    outline-offset: var(--focus-offset);
  }

  ul, ol { padding-inline-start: var(--space-5); }
  li::marker { color: var(--text-muted); }

  img, svg, picture, video { display: block; max-inline-size: 100%; }
  img { block-size: auto; }

  code { font-family: var(--font-mono); font-size: 1em; }
  button, input, select, textarea { font: inherit; color: inherit; }
  button { cursor: pointer; }

  hr { border: 0; border-block-start: var(--border-width) solid var(--border); }
  table { border-collapse: collapse; font-variant-numeric: tabular-nums; }

  [hidden] { display: none !important; }

  @media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }
  }
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
    }
  }

  /* The header stays still while the page cross-fades beneath it. */
  ::view-transition-old(root) {
    animation-duration: var(--duration-fade-out);
    animation-timing-function: ease-out;
  }
  ::view-transition-new(root) {
    animation-duration: var(--duration-fade-in);
    animation-timing-function: ease-out;
  }
  ::view-transition-group(site-header) { animation: none; z-index: 1; }
  ::view-transition-old(site-header) { display: none; }
  ::view-transition-new(site-header) { animation: none; }
  ::view-transition-group(*) {
    animation-duration: var(--duration-morph);
    animation-timing-function: var(--ease-out);
  }
}

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

  .section { padding-block: var(--section-space); }
  /* Adjacent sections share one gap. */
  .section + .section { padding-block-start: 0; }

  .prose {
    max-inline-size: var(--measure);
    line-height: var(--leading-prose);
  }
  .prose > * + * { margin-block-start: var(--space-4); }
  .prose > * + :is(h2, h3) { margin-block-start: var(--space-7); }
  .prose > :is(h2, h3) + * { margin-block-start: var(--space-3); }

  .flow > * + * { margin-block-start: var(--flow-space, var(--space-4)); }

  .skip-link {
    position: absolute;
    inset-block-start: var(--space-2);
    inset-inline-start: var(--space-2);
    z-index: var(--z-skip-link);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--accent-contrast);
    font-weight: var(--weight-strong);
    text-decoration: none;
    transform: translateY(calc(-100% - var(--space-4)));
  }
  .skip-link:focus { transform: none; }

  /* Sticky and identical on every page, so it holds still in view transitions. */
  .site-header {
    position: sticky;
    inset-block-start: 0;
    z-index: var(--z-header);
    background: var(--bg);
    border-block-end: var(--border-width) solid var(--border);
    view-transition-name: site-header;
  }
  /* Below 20rem the header may wrap, so it scrolls away instead of covering
     focus. */
  @media (max-width: 19.99rem) {
    .site-header { position: relative; }
  }
  /* At 320px the header fits one row only with compact links. */
  .site-header__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: var(--space-2);
    min-block-size: var(--header-size);
  }
  .site-header__brand {
    margin-inline-end: auto;
    color: var(--text-strong);
    font-weight: var(--weight-strong);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    min-block-size: var(--target);
  }
  .site-header__brand:hover {
    text-decoration-line: underline;
    text-decoration-thickness: var(--rule-width);
    text-underline-offset: var(--underline-offset-current);
  }
  .site-nav__list {
    display: flex;
    gap: var(--space-1);
    padding: 0;
    list-style: none;
  }
  .site-nav__list a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-block-size: var(--target);
    min-inline-size: var(--space-6);
    font-size: var(--step--1);
    color: var(--text-muted);
    text-decoration: none;
  }
  .site-nav__list a:hover { color: var(--text); }

  /* Header marks with Richy's teal hover glow, from 30rem. */
  .site-header__social {
    display: none;
    gap: var(--space-1);
    padding: 0;
    list-style: none;
  }
  .site-header__social a {
    display: inline-grid;
    place-items: center;
    inline-size: var(--target);
    block-size: var(--target);
    color: var(--text-muted);
  }
  .site-header__social a:hover { color: var(--text); }
  .site-header__social a:hover svg { filter: drop-shadow(0 0 var(--glow-size) var(--accent)); }
  @media (min-width: 30rem) {
    .site-header__social { display: flex; }
  }
  .site-nav__list a[aria-current] {
    color: var(--text);
    text-decoration-line: underline;
    text-decoration-thickness: var(--rule-width);
    text-underline-offset: var(--underline-offset-current);
  }

  .site-footer {
    padding-block: var(--space-7);
    border-block-start: var(--border-width) solid var(--border);
    color: var(--text-muted);
  }
  .site-footer__inner {
    display: grid;
    gap: var(--space-5);
  }
  .site-footer__links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-5);
    padding: 0;
    list-style: none;
  }
  /* The footer stays monochrome, its focus ring included. */
  .site-footer :focus-visible { outline-color: var(--text-strong); }
  .site-footer__meta {
    font-size: var(--step--1);
    max-inline-size: var(--measure);
  }

  @media (min-width: 22.5rem) {
    .site-nav__list a { font-size: inherit; padding-inline: var(--space-1); }
  }
  @media (min-width: 48rem) {
    .site-header__inner { column-gap: var(--space-5); }
    .site-nav__list { gap: var(--space-4); }
  }
}

@layer components {
  /* Buttons: colour-only states; tertiary is a text link. */
  .button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-block-size: var(--target);
    padding: var(--space-2) var(--space-5);
    border: var(--border-width) solid transparent;
    border-radius: var(--radius-sm);
    font-weight: var(--weight-strong);
    line-height: var(--leading-snug);
    text-decoration: none;
    text-align: center;
  }
  /* A cap-to-baseline trim centres the label; padding is the fallback. */
  .button__label { text-box: trim-both cap alphabetic; }
  @media (min-width: 22.5rem) {
    .button { white-space: nowrap; }
  }
  .button--primary {
    background: var(--accent);
    color: var(--accent-contrast);
  }
  .button--secondary {
    border-color: var(--border-strong);
    background: transparent;
    color: var(--text);
  }
  @media (hover: hover) {
    .button--primary:hover { background: var(--accent-hover); }
    .button--secondary:hover { border-color: var(--text-strong); color: var(--text-strong); }
  }
  .button--primary:active { background: var(--accent-pressed); }
  .button--secondary:active {
    border-color: var(--text-strong);
    background: var(--surface);
    color: var(--text-strong);
  }
  @media (prefers-reduced-motion: no-preference) {
    .button,
    .contact-link { transition: background-color var(--duration-hover), border-color var(--duration-hover), color var(--duration-hover); }
  }

  /* Icons come from images/icons.svg and take the text colour. */
  .icon {
    inline-size: var(--icon-size);
    block-size: var(--icon-size);
    flex: none;
    fill: currentColor;
  }
  .button .icon {
    inline-size: var(--icon-size-sm);
    block-size: var(--icon-size-sm);
  }
  .copy-icon {
    inline-size: var(--inline-icon);
    block-size: var(--inline-icon);
    flex: none;
  }
  .copy-icon--done,
  [data-state="copied"] .copy-icon { display: none; }
  [data-state="copied"] .copy-icon--done { display: inline; }

  /* Email links: copy buttons with JS, mailto links without. */
  .email-copy,
  .contact-link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-block-size: var(--target);
  }
  .email-copy {
    flex-wrap: wrap;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    text-align: start;
    cursor: pointer;
  }
  /* With JS, a visible "Copy" label outlined like a control. */
  .email-copy__action { display: none; }
  .js .email-copy__action {
    display: inline-grid;
    grid-template-columns: 1fr auto auto 1fr;
    align-items: center;
    padding-inline: var(--space-2);
    border: var(--border-width) solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    font-size: var(--step--1);
    font-weight: var(--weight-regular);
  }
  .email-copy:hover .email-copy__action { border-color: var(--text); color: var(--text); }
  /* A hidden "Copied" sets the width, so copying shifts nothing. */
  .email-copy__action > svg { grid-area: 1 / 2; }
  .email-copy .copy-label { grid-area: 1 / 3; margin-inline-start: var(--space-1); }
  .email-copy__action::after {
    content: "Copied";
    grid-area: 1 / 1 / 2 / -1;
    padding-inline-start: calc(var(--inline-icon) + var(--space-1));
    block-size: 0;
    visibility: hidden;
  }

  /* Contact links: monochrome icon and label; after .email-copy's reset. */
  .contact-link {
    color: var(--text);
    font-weight: var(--weight-strong);
    text-decoration: none;
  }
  .contact-link--muted { color: var(--text-muted); }
  .contact-link:is(:hover, :focus-visible) { color: var(--text-strong); }

  .button-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
  }

  /* Email actions by device, by media query so it works with JS off. */
  .email-options__web { display: none; }
  @media (min-width: 48rem) {
    .email-options__app { display: none; }
    .email-options__web { display: flex; }
  }

  /* Theme toggle: shows the theme a click switches to. */
  .theme-toggle { display: none; }
  @supports (color: light-dark(#000, #fff)) {
    .js .theme-toggle { display: inline-grid; }
  }
  .theme-toggle {
    place-items: center;
    inline-size: var(--target);
    block-size: var(--target);
    padding: 0;
    border: var(--border-width) solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text);
  }
  .theme-toggle:hover { border-color: var(--text); }
  .theme-toggle svg {
    inline-size: var(--icon-size);
    block-size: var(--icon-size);
    fill: none;
    stroke: currentColor;
    stroke-width: var(--icon-stroke);
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  /* The icon follows the theme shown, not aria-pressed, which JS sets late. */
  .theme-toggle__sun { display: none; }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .theme-toggle__sun { display: block; }
    :root:not([data-theme="light"]) .theme-toggle__moon { display: none; }
  }
  :root[data-theme="dark"] .theme-toggle__sun { display: block; }
  :root[data-theme="dark"] .theme-toggle__moon { display: none; }

  code {
    padding-inline: var(--space-1);
    border-radius: var(--radius-sm);
    background: var(--surface);
    overflow-wrap: anywhere;
  }
  .card code { background: var(--bg); }

  /* minmax(0, 1fr) single columns, so wide content can't widen the page at 320px. */
  :where(.doors, .door__layout, .ledger > article, .ledger__body, .spec, .spec > div, .skills,
         .decisions > div, .letter-scans, .site-footer__inner) {
    grid-template-columns: minmax(0, 1fr);
  }

  .inline-links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-5);
    padding: 0;
    list-style: none;
  }
  .inline-links a {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--target);
  }

  /* Spec list: switches layout on its own width. */
  .spec {
    display: grid;
    gap: var(--space-3);
    container-type: inline-size;
  }
  .spec > div { display: grid; gap: var(--space-1); }
  .spec dt { font-size: var(--step--1); color: var(--text-muted); }
  .spec dd { color: var(--text); font-variant-numeric: tabular-nums; }
  .spec__stack dd { font-size: var(--step--1); color: var(--text-muted); }
  @container (min-width: 30rem) {
    .spec > div {
      grid-template-columns: var(--space-10) minmax(0, 1fr);
      column-gap: var(--space-4);
      align-items: baseline;
    }
  }

  .quote {
    max-inline-size: var(--measure);
    padding-inline-start: var(--space-5);
    border-inline-start: var(--rule-width) solid var(--border-strong);
  }
  .quote blockquote {
    font-size: var(--step-1);
    line-height: var(--leading-snug);
  }
  .quote--pull blockquote { font-style: italic; }
  .quote blockquote p { text-wrap: balance; }
  .quote__link {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--target);
  }
  .quote figcaption {
    margin-block-start: var(--space-3);
    font-size: var(--step--1);
    color: var(--text-muted);
  }
  /* A pull quote repeats a line from the page, so it is aria-hidden. */
  .pull-quote {
    max-inline-size: var(--measure-case-claim);
    font-size: var(--step-2);
    line-height: var(--leading-snug);
    color: var(--text-strong);
  }
  .note { color: var(--text-muted); }

  /* After .quote and .note, so a card wins. */
  .card {
    position: relative;
    padding: var(--space-4);
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
  }
  @media (min-width: 48rem) {
    .card { padding: var(--space-5) var(--space-6); }
  }
  .card--list {
    padding: 0;
    list-style: none;
  }
  .card--list > * { padding: var(--space-4); }
  .card--list > * + * { border-block-start: var(--border-width) solid var(--border); }
  @media (min-width: 48rem) {
    .card--list > * { padding: var(--space-4) var(--space-6); }
  }

  /* One link per card, stretched by ::after; focus ring and hover edge draw on it. */
  .card__link::after {
    content: "";
    position: absolute;
    inset: calc(-1 * var(--border-width));
    border: var(--border-width) solid transparent;
    border-radius: var(--radius-md);
  }
  .card__link:focus-visible { outline: none; }
  .card__link:focus-visible::after {
    outline: var(--focus-width) solid var(--focus);
    outline-offset: var(--focus-offset);
  }
  /* Hover greys the edge, never the accent, so it can't look focused. */
  @media (hover: hover) {
    .card__link:hover::after,
    .next-card:hover { border-color: var(--border-strong); }
  }
  @media (prefers-reduced-motion: no-preference) {
    .card__link::after,
    .next-card,
    .door__cue,
    .door__thumb * { transition: border-color var(--duration-hover), color var(--duration-hover), stroke var(--duration-hover), fill var(--duration-hover); }
  }

  /* Tags: outlined, never mistaken for buttons. */
  .tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: 0;
    list-style: none;
  }
  .tags > li {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-sm);
    font-size: var(--step--1);
    line-height: var(--leading-snug);
  }
  .tags--muted > li { color: var(--text-muted); }
  /* CV skill logos: text colour; width from the viewBox. */
  .skills svg {
    block-size: var(--logo-size);
    overflow: visible;
    flex: none;
    fill: currentColor;
  }

  .figure {
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
  }
  .figure__scroll { overflow-x: auto; padding: var(--space-4) var(--space-2); }
  /* Captions keep the measure; the end padding takes the rest. */
  @media (min-width: 48rem) {
    .figure__scroll { padding: var(--space-4); }
    .figure figcaption { padding-inline: var(--space-6) max(var(--space-6), 100% - var(--measure)); }
  }
  .figure figcaption {
    padding: var(--space-3) max(var(--space-4), 100% - var(--measure)) var(--space-3) var(--space-4);
    border-block-start: var(--border-width) solid var(--border);
    font-size: var(--step--1);
    color: var(--text-muted);
  }

  .diagram {
    inline-size: 100%;
    min-inline-size: var(--diagram-min);
    block-size: auto;
    font-family: var(--font-sans);
  }
  .diagram__node { fill: var(--bg); stroke: var(--border-strong); }
  .diagram__node--key { stroke: var(--text); stroke-width: var(--rule-width); }
  .diagram__node--external { stroke-dasharray: 5 5; }
  .diagram__edge { fill: none; stroke: var(--border-strong); }
  .diagram__edge--dashed { stroke-dasharray: 4 5; }
  .diagram__arrow { fill: var(--border-strong); }
  .diagram__title { fill: var(--text); font-weight: var(--weight-strong); }
  .diagram__label,
  .diagram__note { fill: var(--text-muted); }
  .diagram__lane { fill: var(--text-muted); font-weight: var(--weight-strong); }
  /* The stacked twin shows until the wide one fits, even beside a scrollbar. */
  .diagram--stacked {
    inline-size: auto;
    min-inline-size: 0;
    margin-inline: auto;
  }
  .diagram--wide { display: none; }
  @media (min-width: 59rem) {
    .diagram--wide { display: block; }
    .diagram--stacked { display: none; }
  }

  /* ---------- Home: hero ---------- */
  /* The hero runs tight so a phone's first screen reaches the first door. */
  .hero { padding-block-start: var(--space-5); }
  .hero + .section { padding-block-start: var(--space-7); }
  @media (min-width: 48rem) {
    .hero { padding-block-start: var(--space-6); }
    .hero + .section { padding-block-start: var(--space-8); }
  }
  .hero__title { max-inline-size: var(--hero-width); }
  /* On screen the name is in the header; here it serves screen readers, search
     and print. */
  @media screen {
    .hero__name {
      position: absolute;
      inline-size: 1px;
      block-size: 1px;
      margin: -1px;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
    }
  }
  @media print {
    .hero__name { display: block; font-size: var(--step-3); }
    .hero__name-sep { display: none; }
  }
  /* A real full stop, kept transparent, so the heading reads as sentences. */
  .hero__stop { color: transparent; }
  .hero__role {
    display: block;
    font-size: var(--step-1);
    font-weight: var(--weight-regular);
    line-height: var(--leading-snug);
    letter-spacing: normal;
    color: var(--text-muted);
  }
  .hero__claim {
    display: block;
    max-inline-size: var(--measure-claim);
    margin-block-start: var(--space-2);
    font-size: var(--step-3);
    line-height: var(--leading-tight);
  }
  .hero__proof {
    max-inline-size: var(--measure-standfirst);
    margin-block-start: var(--space-5);
  }
  .hero .button-row { margin-block-start: var(--space-4); }
  @media (min-width: 48rem) {
    .hero__claim { font-size: var(--step-4); }
    .hero .button-row { margin-block-start: var(--space-6); }
  }
  /* Hero keywords: mint, thick and low, so not a link. */
  .hero__keyword {
    text-decoration-line: underline;
    text-decoration-color: var(--rule-accent);
    text-decoration-thickness: var(--keyword-underline);
    text-underline-offset: var(--keyword-underline-offset);
  }

  /* ---------- Home: sections ---------- */
  /* Quiet section labels, so the project names stay louder. */
  .section__label {
    font-size: var(--step-1);
    font-weight: var(--weight-strong);
  }
  .section__lede {
    max-inline-size: var(--measure);
    margin-block-start: var(--space-3);
    color: var(--text-muted);
  }

  /* ---------- Home: doors (ADR 0005, 0006) ---------- */
  .doors {
    display: grid;
    gap: var(--space-4);
    margin-block-start: var(--space-3);
  }
  @media (min-width: 48rem) {
    .doors {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: var(--space-5);
      margin-block-start: var(--space-5);
    }
    .door--featured { grid-column: 1 / -1; }
  }
  /* Miniature beside the text once half the card keeps its titles legible. */
  .door { container-type: inline-size; }
  @container (min-width: 49rem) {
    .door__layout {
      grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
      grid-template-rows: repeat(3, auto) 1fr;
      column-gap: var(--space-6);
    }
    .door__thumb { grid-area: 1 / 1 / -1; }
    .door__layout > :not(.door__thumb) { grid-column: 2; }
  }
  /* Smaller names keep at least the rule width. */
  .door--featured .project__title { font-size: var(--step-3); }
  :is(.door:not(.door--featured), .also) .project__name { border-block-end-width: max(var(--rule-width), var(--title-rule)); }

  .door__layout {
    display: grid;
    align-content: start;
    gap: var(--space-3);
  }
  .project__title { font-size: var(--step-2); }
  /* The title is the link, styled as a title. */
  .project__title .card__link {
    color: inherit;
    text-decoration: none;
  }
  /* The evidence: strong text, no pill or box. */
  .proof {
    color: var(--text-strong);
    font-weight: var(--weight-strong);
    font-variant-numeric: tabular-nums;
  }
  .door__cue {
    font-size: var(--step--1);
    color: var(--cue, var(--text-muted));
  }
  /* Phones: the cue shares the title's short first line, saving a row. */
  @media (max-width: 47.99rem) {
    .door__layout {
      grid-template-columns: minmax(0, 1fr) auto;
      row-gap: var(--space-2);
    }
    .door__layout > * { grid-column: 1 / -1; }
    .door__layout > .project__title { grid-row: 1; }
    .door__cue { grid-area: 1 / 2; padding-block-start: var(--space-2); }
  }
  @media (hover: hover) {
    .door:has(.card__link:hover) { --cue: var(--link); --thumb-line: var(--text-muted); }
  }
  .door:has(.card__link:focus-visible) { --cue: var(--link); --thumb-line: var(--text-muted); }

  /* Door miniatures: from 48rem; their titles drop out under about 11px. */
  .door__thumb {
    display: none;
    container-type: inline-size;
    padding: var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--bg);
  }
  @media (min-width: 48rem) {
    .door__thumb { display: block; }
  }
  .door__thumb svg {
    inline-size: 100%;
    block-size: auto;
    font-family: var(--font-sans);
  }
  .door__thumb :is(.diagram__node:not(.diagram__node--key), .diagram__edge) { stroke: var(--thumb-line, var(--border-strong)); }
  .door__thumb .diagram__arrow { fill: var(--thumb-line, var(--border-strong)); }
  @container (max-width: 22rem) {
    .door__thumb text { display: none; }
  }

  /* The signature title rule, carried by the view transition. */
  .project__name,
  .case-study__name {
    display: inline-block;
    padding-block-end: var(--title-rule-gap);
    border-block-end: var(--title-rule) solid var(--rule-accent);
    letter-spacing: var(--tracking-display);
  }
  .project__name--max-ai,
  .case-study__name--max-ai { view-transition-name: project-max-ai; }
  .project__name--final-docs,
  .case-study__name--final-docs { view-transition-name: project-final-docs; }
  .project__name--encompass,
  .case-study__name--encompass { view-transition-name: project-encompass; }

  .project__outcome { max-inline-size: var(--measure-outcome); }
  .next-card__claim { text-wrap: balance; }

  .doors + .quote {
    max-inline-size: none;
    margin-block-start: var(--space-4);
  }
  .quote.card blockquote {
    max-inline-size: var(--measure-standfirst);
    color: var(--text-strong);
  }
  .quote__mark { color: var(--accent); }
  .quote.card figcaption {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    column-gap: var(--space-5);
    margin-block-start: var(--space-4);
    padding-block-start: var(--space-2);
    border-block-start: var(--border-width) solid var(--border);
  }
  @media (min-width: 48rem) {
    .quote.card blockquote { font-size: var(--step-2); }
  }

  /* ---------- Home: also shipped (ADR 0007) ---------- */
  .also__fold { margin-block-start: var(--space-3); }
  .also__summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    min-block-size: var(--target);
    color: var(--text-muted);
    list-style: none;
    cursor: pointer;
  }
  .also__summary::-webkit-details-marker { display: none; }
  /* A chevron in place of the triangle, pointing up while open. */
  .also__summary::after {
    content: "";
    flex: none;
    inline-size: var(--space-2);
    block-size: var(--space-2);
    border-inline-end: var(--rule-width) solid currentColor;
    border-block-end: var(--rule-width) solid currentColor;
    transform: translateY(-25%) rotate(45deg);
  }
  .also__fold[open] > .also__summary::after { transform: translateY(25%) rotate(-135deg); }
  @media (hover: hover) {
    .also__summary:hover { color: var(--link); }
  }
  .also__summary:focus-visible { color: var(--link); }
  @media (prefers-reduced-motion: no-preference) {
    .also__summary,
    .also__summary::after { transition: color var(--duration-hover), transform var(--duration-hover) var(--ease-out); }
  }
  .also__highlights {
    display: grid;
    gap: var(--space-2);
    margin-block-start: var(--space-2);
    padding: 0;
    list-style: none;
  }
  /* Open, the rows say the same in full. */
  .also__fold[open] + .also__highlights { display: none; }
  .ledger > * {
    padding-block: var(--space-5);
    border-block-start: var(--border-width) solid var(--border);
  }
  .ledger > :last-child { padding-block-end: 0; }
  .ledger > article {
    display: grid;
    gap: var(--space-4);
  }
  .ledger__title { font-size: var(--step-0); }
  .ledger__title--lead { font-size: var(--step-2); }
  .ledger__meta {
    margin-block-start: var(--space-1);
    font-size: var(--step--1);
    color: var(--text-muted);
  }
  .ledger__body { display: grid; gap: var(--space-4); }
  .ledger__body > * { max-inline-size: var(--measure); }
  .ledger__note { font-size: var(--step--1); }
  @media (min-width: 64rem) {
    .ledger > article {
      grid-template-columns: repeat(12, minmax(0, 1fr));
      column-gap: var(--space-6);
    }
    .ledger__head { grid-column: 1 / 5; }
    .ledger__body { grid-column: 5 / -1; }
  }

  /* ---------- Home: contact ---------- */
  /* The intro leads into the email options, so it is body text. */
  .contact .section__lede { color: var(--text); }
  .contact .email-options,
  .contact__links { margin-block-start: var(--space-4); }
  .contact .spec { margin-block-start: var(--space-6); }

  /* ---------- Deep dives ---------- */
  .case-study { padding-block-end: var(--section-space); }
  .case-study__head { padding-block-start: var(--space-6); }
  .case-study__title { font-size: var(--step-3); }
  .case-study__claim {
    display: block;
    max-inline-size: var(--measure-case-claim);
    margin-block-start: var(--space-4);
    font-size: var(--step-2);
    font-weight: var(--weight-regular);
    letter-spacing: normal;
  }
  .case-study__summary {
    max-inline-size: var(--measure-standfirst);
    margin-block-start: var(--space-4);
  }
  .case-study__overview {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--column-min), 1fr));
    gap: var(--space-3) var(--space-6);
    margin-block-start: var(--space-4);
  }
  .case-study__overview .tags { row-gap: var(--space-1); }
  .case-study__overview dt { font-size: var(--step--1); color: var(--text-muted); }
  .case-study__overview > div {
    display: grid;
    grid-template-columns: var(--space-7) minmax(0, 1fr);
    column-gap: var(--space-3);
    align-items: baseline;
  }
  @media (min-width: 48rem) {
    .case-study__overview {
      grid-template-columns: repeat(3, minmax(0, 1fr));
      row-gap: var(--space-5);
    }
    .case-study__overview { margin-block-start: var(--space-6); }
    .case-study__overview > div { display: block; }
    .case-study__overview dd { margin-block-start: var(--space-1); }
    .case-study__overview > .spec__stack { grid-column: 1 / -1; }
  }
  .case-study__brief { margin-block-start: var(--space-4); }
  .case-study__brief .spec { gap: var(--space-4); }
  .case-study__brief dd {
    --flow-space: var(--space-2);
    max-inline-size: var(--measure);
  }
  .case-study__figure { margin-block-start: var(--space-6); }
  .toc {
    max-inline-size: var(--measure);
    margin-block-start: var(--space-6);
  }
  .toc__title { font-size: var(--step--1); color: var(--text-muted); }
  .toc li { text-wrap: balance; }
  /* One column on phones: max-content columns could overflow at 320px. */
  .toc ul {
    display: grid;
    gap: var(--space-1);
    max-inline-size: var(--measure);
    margin-block-start: var(--space-2);
  }
  /* Keeps one-line links past the 24px target floor. */
  .toc a {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--space-6);
  }
  @media (min-width: 48rem) {
    .toc ul {
      display: block;
      columns: 2;
      column-gap: var(--space-6);
    }
    .toc li { break-inside: avoid; }
  }
  .case-study__section { margin-block-start: var(--space-7); }

  /* Before and after panels, side by side from 64rem. */
  .compare {
    display: grid;
    gap: var(--space-4);
    margin-block-start: var(--space-7);
  }
  .compare > .case-study__section { margin-block-start: 0; }
  .compare__after { border-color: var(--rule-accent); }
  @media (min-width: 48rem) {
    .compare { margin-block-start: var(--space-8); }
  }
  @media (min-width: 64rem) {
    .compare {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: var(--space-5);
    }
  }

  /* A real sequence, so numbered. */
  .steps {
    display: grid;
    gap: var(--space-4);
    padding: 0;
    list-style: none;
    counter-reset: step;
  }
  .steps > li {
    position: relative;
    padding-inline-start: calc(var(--space-6) + var(--space-4));
    counter-increment: step;
  }
  .steps > li::before {
    content: counter(step);
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    display: grid;
    place-items: center;
    inline-size: var(--space-6);
    block-size: var(--space-6);
    border: var(--border-width) solid var(--rule-accent);
    border-radius: 50%;
    color: var(--link);
    font-size: var(--step--1);
    font-weight: var(--weight-strong);
    font-variant-numeric: tabular-nums;
  }
  .steps > li:not(:last-child)::after {
    content: "";
    position: absolute;
    inset-block: calc(var(--space-6) + var(--space-1)) calc(var(--space-1) - var(--space-4));
    inset-inline-start: calc(var(--space-6) / 2);
    border-inline-start: var(--border-width) solid var(--border);
  }

  /* Final Docs flow: plain HTML, the animation's static state (ADR 0003). */
  .flow-figure {
    max-inline-size: var(--measure);
    margin-block-start: var(--space-6);
  }
  .flow-steps { padding: var(--space-4); }
  .flow-steps ul { margin-block-start: var(--space-2); }
  .flow-steps__boundary {
    padding-block-end: var(--space-4);
    border-block-end: var(--border-width) dashed var(--border-strong);
  }
  @media (min-width: 48rem) {
    .flow-steps { padding: var(--space-5) var(--space-6); }
  }
  /* Beside its prose once the container is at full width. */
  @media (min-width: 80rem) {
    .case-study__aside {
      display: grid;
      grid-template-columns: minmax(0, var(--measure)) minmax(0, 1fr);
      column-gap: var(--space-8);
      align-items: start;
    }
    .flow-figure {
      position: sticky;
      inset-block-start: calc(var(--header-offset, var(--header-size)) + var(--space-4));
      max-inline-size: none;
      margin-block-start: 0;
    }
  }

  /* A subgrid sizes the number column. */
  .stats {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    column-gap: var(--space-4);
  }
  .stats > li {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    align-items: baseline;
  }
  .stats__value {
    color: var(--text-strong);
    font-size: var(--step-3);
    font-weight: var(--weight-strong);
    line-height: var(--leading-tight);
  }

  /* The next deep dive; its name morphs into that page's title. */
  .case-study__end {
    display: grid;
    gap: var(--space-4);
    margin-block-start: var(--space-8);
  }
  .case-study__end-nav {
    display: grid;
    gap: var(--space-3);
  }
  .next-card {
    display: grid;
    justify-items: start;
    gap: var(--space-2);
    max-inline-size: var(--measure);
    color: var(--text);
    text-decoration: none;
  }
  .next-card__label {
    font-size: var(--step--1);
    color: var(--text-muted);
  }
  .next-card .project__name {
    margin-block-end: var(--space-1);
    color: var(--text-strong);
    font-size: var(--step-2);
    font-weight: var(--weight-strong);
    line-height: var(--leading-heading);
  }
  .decisions > div {
    display: grid;
    gap: var(--space-1);
  }
  .decisions dt {
    color: var(--text-strong);
    font-weight: var(--weight-strong);
  }

  @media (min-width: 48rem) {
    .case-study__head { padding-block-start: var(--space-7); }
    .case-study__summary {
      margin-block-start: var(--space-5);
      font-size: var(--step-1);
      line-height: var(--leading-body);
    }
    .case-study__section { margin-block-start: var(--space-8); }
    .decisions > div {
      grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
      column-gap: var(--space-5);
    }
  }
  @media (min-width: 64rem) {
    .case-study__head { padding-block-start: var(--space-9); }
  }

  /* ---------- CV ---------- */
  .cv__head > :not(.cv__contact),
  .cv__section { max-inline-size: var(--measure); }
  .cv__tagline {
    margin-block-start: var(--space-2);
    font-size: var(--step-1);
    color: var(--text-muted);
  }
  .cv__contact { margin-block-start: var(--space-4); }
  .cv__summary { margin-block-start: var(--space-4); }
  .cv__head .button { margin-block-start: var(--space-5); }
  .cv__section { margin-block-start: var(--space-8); }
  .cv__section > h2 + * { margin-block-start: var(--space-5); }
  .cv-role + .cv-role { margin-block-start: var(--space-7); }
  .cv-role__org { font-weight: var(--weight-strong); }
  .cv-role__meta { font-size: var(--step--1); color: var(--text-muted); }
  .cv-role > ul {
    display: grid;
    gap: var(--space-4);
    margin-block-start: var(--space-4);
  }
  .cv-role ul ul {
    display: grid;
    gap: var(--space-2);
    margin-block-start: var(--space-2);
  }
  .cv-role .quote { margin-block-start: var(--space-5); }
  /* Skills: one group per row, its tags under the label. */
  .skills {
    display: grid;
    gap: var(--space-5);
  }
  .skills dt {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--text-strong);
    font-weight: var(--weight-strong);
  }
  .skills dd { margin-block-start: var(--space-3); }

  /* ---------- Testimonial letter ---------- */
  .letter-page__head { max-inline-size: var(--measure); }
  .letter-page__head > * + * { margin-block-start: var(--space-4); }
  .letter-scans {
    display: grid;
    gap: var(--space-7);
    margin-block-start: var(--space-7);
  }
  .letter-scan { max-inline-size: var(--scan-width); }
  .letter-scan img {
    inline-size: 100%;
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-raised);
  }
  .letter-scan figcaption {
    margin-block-start: var(--space-3);
    font-size: var(--step--1);
    color: var(--text-muted);
  }
  .letter-request {
    max-inline-size: var(--measure);
    margin-block-start: var(--space-8);
  }
  .letter-request > * + * { margin-block-start: var(--space-4); }
}

@layer utilities {
  .visually-hidden {
    position: absolute !important;
    inline-size: 1px !important;
    block-size: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip-path: inset(50%) !important;
    white-space: nowrap !important;
    border: 0 !important;
  }
  .text-muted { color: var(--text-muted); }
  .nowrap { white-space: nowrap; }
}

/* Print: tokens switch to points, so components need no print variants. */
@media print {
  @page { size: A4; margin: 15mm; }
}
@layer tokens {
  @media print {
    :root,
    :root[data-theme] {
      color-scheme: light;
      --bg: #FFFFFF;
      --surface: #FFFFFF;
      --text: #0B0E1C;
      --text-strong: #0B0E1C;
      --text-muted: #42517F;
      --border: #6A7391;
      --border-strong: #6A7391;
      --link: #0B0E1C;
      --accent: #0B0E1C;
      --rule-accent: #0B0E1C;
      --gutter: 0;
      --target: 0;                /* touch targets don't apply on paper */
      --step--1: 9pt;
      --step-0: 10pt;
      --step-1: 11pt;
      --step-2: 12pt;
      --step-3: 20pt;
      --step-4: 20pt;
      --leading-body: 1.4;
      --leading-prose: 1.4;
      --space-1: 1pt;
      --space-2: 3pt;
      --space-3: 4pt;
      --space-4: 6pt;
      --space-5: 8pt;
      --space-6: 8pt;
      --space-7: 8pt;
      --space-8: 10pt;
      --space-9: 16pt;
    }
  }
}
@layer utilities {
  @media print {
    .site-header,
    .site-footer,
    .skip-link,
    .theme-toggle,
    .email-copy__action,
    .cv__contact .icon,
    .skills svg,
    .button,
    .email-options,
    .toc { display: none !important; }
    a,
    .email-copy { color: inherit; text-decoration: none; }
    .cv__contact .contact-link { font-weight: var(--weight-regular); }
    .cv__head,
    .cv__head > *,
    .cv__section { max-inline-size: none; }
    /* Role lists flatten so entries never split. */
    .cv-role > ul { display: block; }
    .cv-role > ul > li + li { margin-block-start: var(--space-4); }
    .cv-role__head,
    .cv-role li,
    .cv__section > ul > li,
    .cv__section > div,
    .skills > div,
    .quote { break-inside: avoid; }
    h2,
    h3 { break-after: avoid; }
    /* The diagrams' screen minimum width would make Chrome shrink the page. */
    .diagram { min-inline-size: 0; }
    .figure { break-inside: avoid; }
    /* Entries split for phones run together on paper, keeping the CV to two
       pages. */
    .print-join > p,
    .print-run-lead,
    .print-run,
    .print-run > li { display: inline; }
    .print-run,
    .print-run > li { padding: 0; border: 0; font-size: inherit; }
    .print-run > li:not(:last-child)::after { content: ","; }
    /* Skills groups print as one run each: "Label: a, b, c". */
    .skills dt,
    .skills dd { display: inline; }
    .skills dt::after { content: ":"; }
    /* Inline, so the printed URL keeps its leading space. */
    .quote__link { display: inline; }
    /* External URLs print after their link text, unless the text is the URL. */
    .cv a[href^="http"]:not([data-no-print-url], [data-print-url])::after { content: " (" attr(href) ")"; }
    .cv a[data-print-url]::after { content: " (" attr(data-print-url) ")"; }
    .figure__scroll { overflow: visible; }
  }
}
@layer base {
  @media print {
    /* The pt spacing scale makes the list indent narrower than the bullet marker. */
    ul, ol { padding-inline-start: 1.25em; }
  }
}
