/* ==========================================================================
   Smokke Ventures — site styles (V3 "Product Studio")
   Plain CSS, no framework or build step. Order: fonts, tokens, base, layout,
   components, drawings, preference media queries.
   Built on V2's flat construction: 1px rules, no shadows, no CSS gradients.
   V3 adds a display type scale, mono technical labels and inline-SVG drawings.
   Orange is reserved for the logo, the headline accent, the primary action,
   focus rings, and the one highlighted element in each drawing.
   ========================================================================== */

/* Inter 5.3.0 (latin subset, opsz + wght axes). SIL OFL 1.1 — see ../fonts/LICENSE-Inter.txt */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/inter-latin-opsz-5.3.0.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

/* Martian Mono 1.000, static instance (width 87.5, weight 500), Basic Latin subset.
   SIL OFL 1.1 — see ../fonts/LICENSE-MartianMono.txt */
@font-face {
  font-family: "Martian Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/martian-mono-latin-500-1.000.woff2") format("woff2");
  unicode-range: U+0020-007E, U+00A0, U+00A9, U+00B7, U+00D7, U+2013-2014, U+2018-2019,
    U+201C-201D, U+2022, U+2026, U+2192-2193;
}

/* ---------- Tokens ------------------------------------------------------ */

:root {
  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Martian Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --container: 75rem;
  --gutter: clamp(1rem, 4vw, 2.5rem);
  --header-height: 3.5rem;
  --radius: 0.375rem;
  --ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);

  /* Light theme: used when the system has no dark preference. Warm paper and ink. */
  color-scheme: light;
  --bg: #f4f3ef;
  --surface: #fbfbf9;
  --surface-hover: #eae9e4;
  --border: #dcdad3;
  --border-strong: #c6c3ba;
  --text: #161615;
  --text-muted: #57554e;
  --accent: #c2410c; /* small orange text and focus rings */
  --accent-display: #e2530a; /* the headline word only (large text) */
  --accent-fill: #ff8a3d; /* Smokke orange: primary action background */
  --on-accent: #0a0a0b;
  --live-dot: #16a34a;
  --dev-dot: #ca8a04;
  /* Drawings: hairlines, construction lines, neutral fills, and the one accent. */
  --fig-grid: #e4e2dc;
  --fig-rule: #a8a59c;
  --fig-fill: #e7e5df;
  --fig-ink: #bab7ae;
  --fig-accent: #e2530a;
}

/* Dark theme tokens. Duplicated on purpose: once for the system preference
   (unless the visitor chose light), once for an explicit dark choice. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #0d0d0e;
    --surface: #141416;
    --surface-hover: #1c1c1f;
    --border: #252529;
    --border-strong: #3b3b41;
    --text: #eeeeec;
    --text-muted: #a3a3a0;
    --accent: #ff8a3d;
    --accent-display: #ff8a3d;
    --live-dot: #22c55e;
    --dev-dot: #eab308;
    --fig-grid: #202024;
    --fig-rule: #5a5a61;
    --fig-fill: #232327;
    --fig-ink: #46464c;
    --fig-accent: #ff8a3d;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0d0d0e;
  --surface: #141416;
  --surface-hover: #1c1c1f;
  --border: #252529;
  --border-strong: #3b3b41;
  --text: #eeeeec;
  --text-muted: #a3a3a0;
  --accent: #ff8a3d;
  --accent-display: #ff8a3d;
  --live-dot: #22c55e;
  --dev-dot: #eab308;
  --fig-grid: #202024;
  --fig-rule: #5a5a61;
  --fig-fill: #232327;
  --fig-ink: #46464c;
  --fig-accent: #ff8a3d;
}

/* ---------- Base -------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* Anchor jumps and keyboard focus stop below the sticky header (WCAG 2.4.11). */
  scroll-padding-top: calc(var(--header-height) + 1px);
}

body {
  display: flex;
  flex-direction: column;
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

:where(h1, h2, h3, p, ul, ol, dl, dd, figure) {
  margin: 0;
}

svg {
  display: block;
}

a {
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius);
}

::selection {
  background: color-mix(in srgb, var(--accent-fill) 30%, transparent);
}

.svg-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Fixed, so it appears above the sticky header wherever the page is scrolled. */
.skip-link {
  position: fixed;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 20;
  padding: 0.625rem 1rem;
  border-radius: var(--radius);
  background: var(--text);
  color: var(--bg);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: none;
}

main {
  flex: 1 0 auto;
}

/* <main> receives focus from the skip link; the content itself is the indicator. */
main:focus {
  outline: none;
}

.container {
  width: min(100% - 2 * var(--gutter), var(--container));
  margin-inline: auto;
}

/* Technical labels: section heads, numbers, captions, status words. */
.mono,
.section-label,
.section-num,
.app-kicker,
.figure-caption,
.index-num,
.index-status,
.badges,
.app-spec dt,
.about-spec dt {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.6875rem;
  line-height: 1.5;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ---------- Header ------------------------------------------------------ */

/* Sticky while it is one line. Where the screen is narrower than 19.5rem (large text, or under
   312 px), it wraps (see below) and would cover too much of the page and of keyboard focus, so
   the offset turns hugely negative and the header scrolls away with the page. */
.site-header {
  position: sticky;
  top: min(0px, (100vw - 19.5rem) * 1000);
  z-index: 10;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}

/* With large text on a narrow screen, the navigation and the toggle wrap under the brand,
   to the right as before, instead of running off the screen. */
.header-inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
  gap: 0.25rem;
  min-height: var(--header-height);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  margin-right: auto;
  text-decoration: none;
}

.brand-mark {
  width: 1.75rem;
  height: 1.75rem;
  flex: none;
}

.wordmark {
  display: inline-flex;
  flex-wrap: wrap;
  column-gap: 0.5em;
  font-size: 0.8125rem;
  line-height: 1.15;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.wordmark-primary {
  font-weight: 800;
}

.wordmark-secondary {
  font-weight: 500;
  color: var(--text-muted);
}

.site-nav ul,
.footer-nav ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  padding: 0;
}

.site-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 0.75rem;
  border-radius: var(--radius);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  transition: color 0.15s, background-color 0.15s;
}

.site-nav a:hover {
  color: var(--text);
  background: var(--surface-hover);
}

.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  flex: none;
  padding: 0;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 0.15s, background-color 0.15s;
}

.theme-toggle[hidden] {
  display: none;
}

.theme-toggle:hover {
  color: var(--text);
  background: var(--surface-hover);
}

.theme-toggle svg {
  width: 1.125rem;
  height: 1.125rem;
}

/* Show the icon of the theme the button switches to. */
.theme-toggle .icon-sun,
.theme-toggle .icon-moon {
  display: none;
}

.theme-toggle[data-current="dark"] .icon-sun,
.theme-toggle[data-current="light"] .icon-moon {
  display: block;
}

@media (max-width: 34.99rem) {
  .wordmark {
    flex-direction: column;
    font-size: 0.75rem;
  }

  .wordmark-secondary {
    font-size: 0.5625rem;
    letter-spacing: 0.29em;
  }

  .site-nav a {
    padding: 0 0.625rem;
  }
}

/* ---------- Hero -------------------------------------------------------- */

.hero {
  /* The headline's font size. The cap keeps "SMOKKE" (4.03em wide) within the screen with large
     text on a narrow screen; at the default text size it never applies. */
  --hero-size: min(clamp(2.875rem, 0.9rem + 8.1vw, 6.25rem), (100vw - 2 * var(--gutter)) / 4.2);
  padding-top: clamp(1.75rem, 0.75rem + 3.5vw, 4rem);
}

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.5rem;
}

.hero-title {
  font-size: var(--hero-size);
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: -0.055em;
}

/* Three fixed lines, "The home of / SMOKKE / software.": the first is set light,
   so the brand line carries the weight. */
.hero-title-lead {
  display: block;
  font-weight: 300;
  letter-spacing: -0.045em;
}

.hero-title .accent-text {
  display: block;
}

.accent-text {
  color: var(--accent-display);
}

.lead {
  max-width: 30rem;
  margin-top: clamp(1.25rem, 1rem + 1vw, 2rem);
  color: var(--text-muted);
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
  line-height: 1.5;
  text-wrap: pretty;
}

.hero-figure {
  display: grid;
  gap: 0.5rem;
  justify-items: center;
}

.hero-drawing {
  width: 100%;
  max-width: 26rem;
  height: auto;
}

.figure-caption {
  display: flex;
  gap: 0.75em;
  color: var(--text-muted);
}

.figure-caption > span:first-child {
  color: var(--text);
}

/* App index: every app on the first screen, linked to its showcase below. */
.app-index {
  margin-top: clamp(1.5rem, 1rem + 2vw, 2.5rem);
}

/* Phones: the drawing becomes a seal beside the headline's last two lines, which are
   narrower than the first, so it costs no height and the app index and the first app
   follow the lead directly. Sized in headline lines: two lines tall, one line down. It
   shows the tile only (the view is cropped from -16..80 to -4..68), without the
   dimensions and labels, which would be too small to read. */
@media (max-width: 47.99rem) {
  .hero {
    container: hero / inline-size;
  }

  .app-index {
    margin-top: 0.5rem;
  }

  /* Left out where there is no room beside the headline (see below). */
  .hero-figure {
    display: none;
  }

  /* The seal needs about six headline sizes of width ("SMOKKE" is 4em, the seal 1.8em), which
     the hero has from 20rem. A container query measures the hero, with rem taken from the page's
     actual text size, so larger text (a browser setting, zoom or a user style sheet) leaves the
     seal out instead of letting it cover the headline. Browsers without container queries leave
     it out too. */
  @container hero (min-width: 20rem) {
    .hero-grid {
      grid-template-columns: minmax(0, 1fr) auto;
    }

    .hero-copy {
      grid-area: 1 / 1 / 2 / -1;
      z-index: 1; /* the headline stays above the drawing, whatever the metrics */
    }

    .app-index {
      grid-area: 2 / 1 / 3 / -1;
    }

    .hero-figure {
      display: block;
      grid-area: 1 / 2 / 2 / 3;
      width: calc(var(--hero-size) * 1.8);
      height: calc(var(--hero-size) * 1.8);
      margin-top: calc(var(--hero-size) * 0.9);
      overflow: hidden;
      pointer-events: none;
    }

    .hero-drawing {
      width: calc(100% * 96 / 72);
      max-width: none;
      margin: calc(-100% * 12 / 72);
    }

    .hero-figure .figure-caption,
    .hero-drawing .f-callout {
      display: none;
    }
  }
}

@media (min-width: 48rem) {
  .hero-grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    column-gap: clamp(1.5rem, 4vw, 4rem);
    align-items: center;
  }

  .app-index {
    grid-column: 1 / -1;
  }
}

.app-index ul {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  column-gap: clamp(1.5rem, 4vw, 4rem);
  list-style: none;
  padding: 0;
  border-top: 1px solid var(--border-strong);
}

.index-link {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 0.875rem;
  min-height: 4.5rem;
  padding-block: 0.75rem;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  transition: background-color 0.15s;
}

.index-num {
  color: var(--text-muted);
}

.index-icon {
  width: 2rem;
  height: 2rem;
}

.index-name {
  font-size: 1.0625rem;
  font-weight: 650;
  letter-spacing: -0.015em;
  line-height: 1.25;
}

/* With large text the second word wraps under the first. The rule between them sits in the
   gap and is clipped when the word starts a line. */
.index-status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: calc(1.25rem + 1px);
  overflow-x: clip;
  color: var(--text-muted);
  white-space: nowrap;
}

.index-status > span + span {
  position: relative;
}

.index-status > span + span::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(-0.625rem - 1px);
  border-left: 1px solid var(--border-strong);
}

.index-arrow {
  width: 1rem;
  height: 1rem;
  color: var(--text-muted);
  transition: transform 0.15s var(--ease-out), color 0.15s;
}

.index-link:hover .index-name {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

.index-link:hover .index-arrow {
  color: var(--text);
  transform: translateY(2px);
}

@media (max-width: 29.99rem) {
  /* Phones: status drops under the name. */
  .index-link {
    grid-template-columns: auto auto minmax(0, 1fr) auto;
    grid-template-areas: "num icon name arrow" "num icon status arrow";
    row-gap: 0.125rem;
    column-gap: 0.75rem;
    min-height: 3.5rem;
    padding-block: 0.5rem;
  }

  .index-num {
    grid-area: num;
  }

  .index-icon {
    grid-area: icon;
  }

  .index-name {
    grid-area: name;
    align-self: end;
  }

  .index-status {
    grid-area: status;
    align-self: start;
  }

  .index-arrow {
    grid-area: arrow;
  }

  /* Large text on a narrow screen: the name and status take the full width, under the
     number, icon and arrow. 14rem is where "Operational" no longer fits beside them. */
  @container hero (max-width: 13.99rem) {
    .index-link {
      grid-template-columns: auto minmax(0, 1fr) auto;
      grid-template-areas: "num icon arrow" "name name name" "status status status";
    }
  }
}

/* The primary action: Smokke orange with near-black text in both themes (8.44:1). */
.button,
.app-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  padding: 0 1.125rem;
  border-radius: var(--radius);
  background: var(--accent-fill);
  color: var(--on-accent);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
  transition: background-color 0.15s;
}

.button:hover,
.app-link:hover {
  background: color-mix(in srgb, var(--accent-fill) 86%, var(--text));
}

.app-link svg {
  width: 0.875rem;
  height: 0.875rem;
  transition: transform 0.15s var(--ease-out);
}

.app-link:hover svg {
  transform: translate(2px, -2px);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 2rem;
}

/* ---------- Sections ---------------------------------------------------- */

.section {
  padding-block: clamp(3rem, 2rem + 3vw, 4.75rem);
}

.hero + .section {
  padding-top: clamp(2.5rem, 1.5rem + 3vw, 4.5rem);
}

/* A running head: number, label, and an optional note, between rules. */
.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 2rem;
  padding-block: 0.875rem;
  border-block: 1px solid var(--border);
  margin-bottom: clamp(1.75rem, 1rem + 2.5vw, 3.25rem);
}

.section-label {
  display: flex;
  gap: 1.25em;
  color: var(--text);
  font-size: 0.75rem;
}

.section-num {
  color: var(--text-muted);
  font-size: inherit;
}

.section-note {
  color: var(--text-muted);
  font-size: 0.875rem;
}

/* The cap keeps "Independent" (5.46em wide) within the screen with large text on a narrow
   screen; at the default text size it never applies. */
.section-title {
  font-size: min(clamp(2rem, 1rem + 4vw, 4.25rem), (100vw - 2 * var(--gutter)) / 5.7);
  font-weight: 800;
  line-height: 0.98;
  letter-spacing: -0.05em;
  text-wrap: balance;
}

/* ---------- App showcases ----------------------------------------------- */

.app-grid {
  display: grid;
  gap: clamp(3.5rem, 2rem + 5vw, 7rem);
  list-style: none;
  padding: 0;
}

.app-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.75rem;
}

/* Stacked (phones and tablets): the app's text and action come first, its plate follows. */
@media (max-width: 59.99rem) {
  .app-figure {
    order: 1;
  }
}

@media (min-width: 60rem) {
  .app-card {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    column-gap: clamp(2.5rem, 5vw, 5rem);
    align-items: center;
  }

  /* Alternate sides down the page. */
  .app-grid > li:nth-child(even) .app-card {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  }

  .app-grid > li:nth-child(even) .app-figure {
    order: 2;
  }
}

/* The plate: a schematic of what the app does, never a screenshot. */
.app-figure {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.app-drawing {
  width: 100%;
  height: auto;
}

/* Stacked on tablets, a 4:3 plate would fill the screen: letterbox it to 16:9. */
@media (min-width: 40rem) and (max-width: 59.99rem) {
  .app-figure {
    aspect-ratio: 16 / 9;
  }

  .app-drawing {
    height: 100%;
  }
}

/* Title block, as on a technical drawing: figure number and title, then "Schematic". */
.app-figure .figure-caption {
  position: absolute;
  inset-inline: clamp(0.875rem, 2vw, 1.25rem);
  bottom: clamp(0.75rem, 1.6vw, 1.125rem);
}

.figure-note {
  margin-left: auto;
}

/* For an app with nothing running yet: dashed outline, no link. */
.app-card.is-upcoming .app-figure {
  border-style: dashed;
  background: transparent;
}

.app-kicker {
  display: flex;
  gap: 1.25em;
  color: var(--text-muted);
}

.app-num {
  color: var(--text);
}

/* The name and status wrap under the icon only when they do not fit beside it (large text). */
.app-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  min-width: 0;
  margin-top: 1rem;
}

.app-card-head > div {
  flex: 1 1 0;
}

.app-icon {
  width: 3.25rem;
  height: 3.25rem;
  flex: none;
}

.app-icon-placeholder {
  color: var(--text-muted);
}

.app-name {
  font-size: clamp(1.625rem, 1.1rem + 1.75vw, 2.625rem);
  font-weight: 750;
  line-height: 1.08;
  letter-spacing: -0.04em;
  text-wrap: balance;
}

/* Status: short words under the name, separated by thin rules. A rule sits in the gap
   before its word and is clipped when the word starts a line (large text). */
.badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem calc(1.5rem + 1px);
  margin-top: 0.5rem;
  list-style: none;
  padding: 0;
  overflow-x: clip;
  color: var(--text-muted);
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  white-space: nowrap;
}

.badge + .badge {
  position: relative;
}

.badge + .badge::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(-0.75rem - 1px);
  border-left: 1px solid var(--border-strong);
}

.badge svg {
  width: 0.75rem;
  height: 0.75rem;
}

.badge-live,
.badge-dev {
  color: var(--text);
}

.badge-live::before,
.badge-dev::before {
  content: "";
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
}

.badge-live::before {
  background: var(--live-dot);
}

.badge-dev::before {
  border: 2px solid var(--dev-dot);
}

.app-desc {
  max-width: 30rem;
  margin-top: 1.5rem;
  font-size: clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem);
  line-height: 1.5;
  text-wrap: pretty;
}

/* Availability: who can use the app today. Required on every card. The label sits beside the
   note, or above it when the note would be narrower than 9rem (large text). */
.app-spec {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  max-width: 30rem;
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}

.app-spec dt {
  flex: 0 0 5rem;
  padding-top: 0.25em;
  color: var(--text-muted);
}

.app-spec dd {
  flex: 1 1 0;
  min-width: min(100%, 9rem);
}

.app-note {
  color: var(--text-muted);
  font-size: 0.9375rem;
  line-height: 1.55;
}

ul.app-note {
  list-style: none;
  padding-inline: 0;
}

ul.app-note li + li {
  margin-top: 0.625rem;
  padding-top: 0.625rem;
  border-top: 1px solid var(--border);
}

.app-note strong {
  color: var(--text);
  font-weight: 600;
}

.app-card-foot {
  display: flex;
  margin-top: 1.75rem;
}

/* Phones: slightly tighter vertical rhythm, so the first app's name, description,
   availability and action fit on the first screen (390x844). Type sizes are unchanged. */
@media (max-width: 47.99rem) {
  .hero + .section {
    padding-top: 1.75rem;
  }

  /* The index's bottom rule already closes the hero; a second rule just below it read as an
     empty extra row. */
  .hero + .section .section-head {
    border-top: 0;
  }

  .section-head {
    margin-bottom: 1.25rem;
  }

  .app-desc,
  .app-spec {
    margin-top: 1rem;
  }

  .app-card-foot {
    margin-top: 1.25rem;
  }

  .app-figure {
    container: plate / inline-size;
  }

  /* Large text on a narrow screen: the caption moves under the drawing and wraps, instead of
     covering it or running off the screen. */
  @container plate (max-width: 15rem) {
    .app-figure .figure-caption {
      position: static;
      flex-wrap: wrap;
      gap: 0.25em 0.75em;
      padding: 0 0.875rem 0.75rem;
    }
  }
}

/* ---------- About ------------------------------------------------------- */

.about-grid {
  display: grid;
  gap: clamp(2rem, 1.25rem + 3vw, 4rem);
}

.about-spec {
  display: grid;
  gap: 1.5rem;
}

@media (min-width: 48rem) {
  .about-spec {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(1.5rem, 3vw, 3rem);
  }
}

.about-spec > div {
  padding-top: 1rem;
  border-top: 1px solid var(--border-strong);
}

.about-spec dt {
  color: var(--text-muted);
}

.about-spec dd {
  margin-top: 0.625rem;
  font-size: 1.0625rem;
  line-height: 1.5;
  text-wrap: pretty;
}

/* ---------- Footer ------------------------------------------------------ */

.site-footer {
  padding-block: 1.5rem 2.5rem;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 0.875rem;
}

.footer-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 2rem;
}

.footer-top .brand {
  margin-right: 0;
  color: var(--text);
}

.footer-top .brand-mark {
  width: 1.5rem;
  height: 1.5rem;
}

.footer-nav ul {
  gap: 0 1.5rem;
}

.footer-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
}

.footer-nav a:hover {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.footer-legal {
  display: grid;
  gap: 0.375rem;
  margin-top: 1rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
}

/* ---------- Not-found page ---------------------------------------------- */

.not-found {
  min-height: 60vh;
  display: grid;
  align-content: center;
  padding-block: clamp(3rem, 2rem + 4vw, 6rem);
}

.not-found .hero-title {
  margin-top: 1.25rem;
  font-size: clamp(2.75rem, 1rem + 7vw, 5.5rem);
}

.not-found .lead {
  margin-top: 1.25rem;
  max-width: 32rem;
}

/* ---------- Drawings ---------------------------------------------------- */
/* Inline SVG, styled here so they follow the theme. Hairlines stay 1px at any size. */

.f-grid,
.f-rule,
.f-dash,
.f-centre,
.f-handle,
.f-guide,
.f-dots,
.f-cell,
.f-accent-ring,
.f-anchor,
.f-handle-end,
.f-s-centre {
  fill: none;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.f-grid {
  stroke: var(--fig-grid);
}

.f-rule,
.f-handle {
  stroke: var(--fig-rule);
}

.f-dash {
  stroke: var(--fig-rule);
  stroke-dasharray: 3 3;
}

.f-centre {
  stroke: var(--fig-rule);
  stroke-dasharray: 12 3 2 3;
}

.f-knock {
  fill: var(--bg);
}

.f-label {
  fill: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 3.4px;
  font-weight: 500;
}

.f-s {
  fill: none;
  stroke: var(--fig-accent);
  stroke-width: 6.5;
  stroke-linecap: round;
}

.f-s-centre {
  stroke: var(--bg);
}

.f-handle-end {
  fill: var(--bg);
  stroke: var(--fig-rule);
}

.f-anchor {
  fill: var(--bg);
  stroke: var(--text);
}

.f-cell {
  stroke: var(--fig-ink);
}

.f-fill {
  fill: var(--fig-fill);
}

.f-team {
  fill: var(--fig-ink);
}

.f-accent-fill {
  fill: var(--fig-accent);
}

.f-accent-ring {
  stroke: var(--fig-accent);
  stroke-width: 2;
}

.f-guide {
  stroke: var(--fig-accent);
  stroke-dasharray: 2 4;
}

.f-bar,
.f-bar-accent {
  fill: none;
  stroke: var(--fig-ink);
  stroke-width: 12;
  stroke-dasharray: 24 6;
}

.f-bar-accent {
  stroke: var(--fig-accent);
}

.f-x {
  fill: none;
  stroke: var(--fig-rule);
  stroke-width: 1.5;
  stroke-linecap: round;
}

.f-dots {
  stroke: var(--fig-rule);
  stroke-dasharray: 1 5;
  stroke-linecap: round;
}

/* ---------- Preferences & environments ---------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }

  /* A short cross-fade while the toggle switches themes (class set by site.js). */
  .theme-switching,
  .theme-switching *,
  .theme-switching *::before,
  .theme-switching *::after {
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, fill 0.2s ease,
      stroke 0.2s ease !important;
  }
}

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

@media (prefers-contrast: more) {
  :root {
    --accent-display: var(--accent);
  }

  .wordmark-secondary,
  .site-nav a,
  .lead,
  .section-num,
  .section-note,
  .app-kicker,
  .figure-caption,
  .index-num,
  .index-status,
  .badges,
  .app-spec dt,
  .app-note,
  .about-spec dt,
  .site-footer {
    color: var(--text);
  }

  .site-header,
  .section-head,
  .site-footer,
  .footer-legal,
  .app-figure,
  .app-spec,
  .app-index ul,
  .index-link,
  .about-spec > div,
  ul.app-note li + li,
  .badge + .badge::after,
  .index-status > span + span::before {
    border-color: var(--border-strong);
  }
}

@media (forced-colors: active) {
  .button,
  .app-link {
    border: 1px solid ButtonText;
  }

  .badge-live::before {
    forced-color-adjust: none;
    background: CanvasText;
  }

  .badge-dev::before {
    border-color: CanvasText;
  }
}

@media print {
  .site-header {
    position: static;
  }

  .theme-toggle,
  .skip-link {
    display: none;
  }

  .app-card {
    break-inside: avoid;
  }
}
