/* Built by www/build.mjs: Capsomer's fonts, tokens, base, link system, Carrel's family, the manual theme and the family footer, then www/site.css. */

/* Generated by tokens/fonts.mjs. Do not edit: change the script and run `npm run tokens`.
   The network's faces, one file each with every weight (variable where the face is, the latin subset and its
   unicode-range). OFL 1.1, fonts/OFL-*.txt. A site that inlines this file copies ../fonts/ beside it.
   - Inter: the UI and display face. Fontsource 5.3.0's latin opsz file with its optical size fixed at 14, the text cut, and its weight axis cut to 300 to 800, the weights the network sets (scripts/narrow-font.py): 45.7 KB where the opsz file was 68.9 KB, which put dustinedwards.info's /systems past its 2.5 s LCP limit (Dustin, 2026-11-05).
   - Martian Mono: labels and code.
   - Overpass: wayfinding links only (--wayfinding): breadcrumbs, footer links, next and back. Delve Fonts' Highway Gothic, the FHWA sign face FAA AC 150/5345-44L Appendix A sets airport signs in. Fontsource 5.3.0, its weight axis cut to 600 to 700, the two weights wayfinding sets, and its characters to plain English text, dashes, quotes and arrows (scripts/narrow-font.py, 14.8 KB): a breadcrumb's accented letter draws in the fallback.
   - Jost: standalone pieces with lettering (--poster): share cards, title images, banners, flyers, a 404 title; never text under Inter headings (NASA NHB 1430.2 section 5.4). The free Futura. Fontsource 5.3.0.
   - Capsomer Drafting: labels in line drawings and plates, and words on lit panels (--drafting): Routed Gothic's Leroy and Gorton lettering with the 1 redrawn with a flag (scripts/drafting-font.py).
   - DSEG7 Classic: lit instrument readouts (--readout), the Apollo DSKY's seven-segment digits. DSEG 0.46.0.
   - DSEG7 Classic italic: countdowns and elapsed time (--countdown), the KSC press-site clock's italic bulb digits.
   A face downloads only when a page draws text in it, so the faces a page does not use cost their rules alone.
   Every site loads these same files, so a bold name is the same bold on every site (Dustin, 2026-10-28: "the
   footer dustin edwards is not exact in all of the sites").
   font-display: optional (web.dev, "Best practices for fonts": the one value with no font swap): the browser
   waits about 100ms for a face, and a visit it misses stays in the fallback, so text never reflows once drawn.
   Even a fallback within 1% of the face's width moves a line break now and then, and the page under it
   (D5, 2026-11-04). Preload the face a page draws first so it arrives in time; the cache serves it after that.
   Each face has a size-matched fallback, listed second in the font stacks: a local face scaled to its
   width and line metrics, so a visit drawn in it looks like the face (Astro's Fonts API). */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 300 800;
  font-display: optional;
  src: url("fonts/inter-latin-wght-normal.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;
}
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial"), local("Liberation Sans"), local("Arimo Regular");
  font-weight: 1 549;
  size-adjust: 107.1194%;
  ascent-override: 90.4365%;
  descent-override: 22.518%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial Bold"), local("Liberation Sans Bold"), local("Arimo Bold");
  font-weight: 550 649;
  size-adjust: 101.5259%;
  ascent-override: 95.419%;
  descent-override: 23.7586%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial Bold"), local("Liberation Sans Bold"), local("Arimo Bold");
  font-weight: 650 1000;
  size-adjust: 102.5432%;
  ascent-override: 94.4723%;
  descent-override: 23.5229%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Martian Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: optional;
  src: url("fonts/martian-mono-latin-wght-normal.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;
}
@font-face {
  font-family: "Martian Mono Fallback";
  src: local("Courier New"), local("Liberation Mono"), local("Cousine Regular");
  size-adjust: 116.6477%;
  ascent-override: 85.7282%;
  descent-override: 17.1456%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Overpass";
  font-style: normal;
  font-weight: 600 700;
  font-display: optional;
  src: url("fonts/overpass-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0020-007E, U+00A0, U+00B7, U+2013-2014, U+2018-201D, U+2022, U+2026, U+2190-2193;
}
@font-face {
  font-family: "Overpass Fallback";
  src: local("Arial"), local("Liberation Sans"), local("Arimo Regular");
  font-weight: 1 549;
  size-adjust: 103.9702%;
  ascent-override: 84.9282%;
  descent-override: 36.8375%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Overpass Fallback";
  src: local("Arial Bold"), local("Liberation Sans Bold"), local("Arimo Bold");
  font-weight: 550 649;
  size-adjust: 96.5664%;
  ascent-override: 91.4396%;
  descent-override: 39.6618%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Overpass Fallback";
  src: local("Arial Bold"), local("Liberation Sans Bold"), local("Arimo Bold");
  font-weight: 650 1000;
  size-adjust: 98.129%;
  ascent-override: 89.9836%;
  descent-override: 39.0303%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Jost";
  font-style: normal;
  font-weight: 100 900;
  font-display: optional;
  src: url("fonts/jost-latin-wght-normal.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;
}
@font-face {
  font-family: "Jost Fallback";
  src: local("Arial"), local("Liberation Sans"), local("Arimo Regular");
  font-weight: 1 549;
  size-adjust: 96.007%;
  ascent-override: 111.4502%;
  descent-override: 39.0596%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Jost Fallback";
  src: local("Arial Bold"), local("Liberation Sans Bold"), local("Arimo Bold");
  font-weight: 550 649;
  size-adjust: 95.4205%;
  ascent-override: 112.1352%;
  descent-override: 39.2997%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Jost Fallback";
  src: local("Arial Bold"), local("Liberation Sans Bold"), local("Arimo Bold");
  font-weight: 650 1000;
  size-adjust: 98.3373%;
  ascent-override: 108.8091%;
  descent-override: 38.134%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Capsomer Drafting";
  font-style: normal;
  font-weight: 400;
  font-display: optional;
  src: url("fonts/capsomer-drafting-latin.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;
}
@font-face {
  font-family: "Capsomer Drafting Fallback";
  src: local("Arial"), local("Liberation Sans"), local("Arimo Regular");
  size-adjust: 104.0526%;
  ascent-override: 119.85%;
  descent-override: 35.6641%;
  line-gap-override: 8.6345%;
}
@font-face {
  font-family: "DSEG7 Classic";
  font-style: normal;
  font-weight: 400;
  font-display: optional;
  src: url("fonts/dseg7-classic-regular.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;
}
@font-face {
  font-family: "DSEG7 Classic Fallback";
  src: local("Courier New"), local("Liberation Mono"), local("Cousine Regular");
  size-adjust: 117.4809%;
  ascent-override: 85.1202%;
  descent-override: 0%;
  line-gap-override: 7.6608%;
}
@font-face {
  font-family: "DSEG7 Classic";
  font-style: italic;
  font-weight: 300;
  font-display: optional;
  src: url("fonts/dseg7-classic-light-italic.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;
}


@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url("fonts/source-serif-4-latin-wght-normal.woff2") format("woff2");
}

/* Capsomer's tokens: the color palette (generated by tokens/palette.mjs) and every other
   scale (generated by tokens/scale.mjs), inside the cap.tokens layer. Import this once,
   before any component CSS: `import "capsomer/tokens.css"`. */
/* The one layer order. Every Capsomer rule sits in one of these layers, and an app's own
   CSS stays unlayered, so an app's rule always wins without !important (design 1.4).

   An app still on Tailwind v4 declares its own order before importing anything, so its
   utilities keep winning while screens move over:
     @layer cap, theme, base, components, utilities;
   Nested names (cap.tokens and the rest) then sort inside "cap". */
@layer cap.reset, cap.tokens, cap.base, cap.components, cap.utilities;

@layer cap.tokens {
/* Generated by tokens/palette.mjs: step 9 #8c5fd2 (oklch 0.587 0.172 299.1), step 11 anchored at #4f2d7f.
   Do not edit: change the script and run `npm run tokens`. `npm run check` refuses a file
   that differs from what the script writes, and any pair below WCAG 2.2's bar or its APCA floor. */
:root {
  --ground: #fbf9ff;
  --surface: #fdfdfe;
  --raised: #f7f6fc;
  --sunken: #e9e6ef;
  --line: #dfdce5;
  --line-strong: #918e96;
  --text: #1c1727;
  --muted: #686471;
  --dim: #696571;
  --accent: #8c5fd2;
  --accent-hover: #1d162c;
  --accent-text: #4f2d7f;
  --accent-visited: #832151;
  --accent-soft: #ece5ff;
  --accent-line: #9780c3;
  --sel: #f4efff;
  --primary: #7d50c1;
  --primary-hover: #4f2d7f;
  --primary-fg: #fdfdfe;
  --primary-line: #7d50c1;
  --on: #7d50c1;
  --on-hover: #4f2d7f;
  --ring: #8c5fd2;
  --ok: #047735;
  --ok-soft: #d6f7dc;
  --warn: #8a5f01;
  --warn-soft: #ffeaca;
  --crit: #ae453f;
  --crit-soft: #fee7e4;
  --info: #2668b6;
  --info-soft: #e2eeff;
  --nodata: #696571;
  --nodata-soft: #ebeaef;
  --sign: #1c1727;
  --on-sign: #fbf9ff;
  --sign-edge: #1c1727;
  --sign-here: #2d2934;
  --on-sign-here: #cdb6fc;
  --lit-bulb: #ffe4b5;
  --accent-1: #fdfcff;
  --accent-2: #faf8fe;
  --accent-3: #f4efff;
  --accent-4: #ece5ff;
  --accent-5: #e4d9fe;
  --accent-6: #d8caf6;
  --accent-7: #c8b6ed;
  --accent-8: #b29ae3;
  --accent-9: #8c5fd2;
  --accent-10: #7d50c1;
  --accent-11: #4f2d7f;
  --accent-12: #1d162c;
  --series-1: #8c5fd2;
  --series-2: #cc4f0c;
  --series-3: #008489;
  --series-4: #709161;
  --series-5: #51579a;
  --series-6: #016a5c;
  --series-7: #c06caa;
  --series-8: #9d412a;
  --series-text-1: #000000;
  --series-text-2: #000000;
  --series-text-3: #000000;
  --series-text-4: #1c1727;
  --series-text-5: #fdfdfe;
  --series-text-6: #fdfdfe;
  --series-text-7: #1c1727;
  --series-text-8: #fdfdfe;
  --series-ink-1: #8558ca;
  --series-ink-2: #c24903;
  --series-ink-3: #007c81;
  --series-ink-4: #59784a;
  --series-ink-5: #51579a;
  --series-ink-6: #016a5c;
  --series-ink-7: #a55391;
  --series-ink-8: #9d412a;
  --ramp-1: #9478c7;
  --ramp-2: #805cbb;
  --ramp-3: #6c41ab;
  --ramp-4: #572c8f;
  --ramp-5: #411b70;
  --ramp-text-1: #1c1727;
  --ramp-text-2: #fdfdfe;
  --ramp-text-3: #fdfdfe;
  --ramp-text-4: #fdfdfe;
  --ramp-text-5: #fdfdfe;
  --shadow-xs: 0 1px 2px 0 rgba(28, 23, 39, 0.05);
  --shadow-s: 0 1px 3px 0 rgba(28, 23, 39, 0.1), 0 1px 2px -1px rgba(28, 23, 39, 0.1);
  --shadow-m: 0 4px 6px -1px rgba(28, 23, 39, 0.1), 0 2px 4px -2px rgba(28, 23, 39, 0.1);
  --shadow-l: 0 10px 15px -3px rgba(28, 23, 39, 0.1), 0 4px 6px -4px rgba(28, 23, 39, 0.1);
  --ring-soft: rgba(140, 95, 210, 0.5);
  --shadow-ring: 0 0 0 var(--ring-width) rgba(140, 95, 210, 0.5);
  --shadow: var(--shadow-l);
  --scrim: rgba(28, 23, 39, 0.28);
  --img-filter: none;
  color-scheme: light;
  --ui: "Inter", "Inter Fallback", "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --mono: "Martian Mono", "Martian Mono Fallback", ui-monospace, "Cascadia Mono", Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground: #0e0c12;
    --surface: #18161c;
    --raised: #211f25;
    --sunken: #09070c;
    --line: #343238;
    --line-strong: #7d7b82;
    --text: #efedf3;
    --muted: #b7b5bf;
    --dim: #b7b5be;
    --accent: #8c5fd2;
    --accent-hover: #ede8f7;
    --accent-text: #d8c7ff;
    --accent-visited: #ffbdd5;
    --accent-soft: #2c243c;
    --accent-line: #8670b0;
    --sel: #211c2c;
    --primary: #c09eff;
    --primary-hover: #d8c7ff;
    --primary-fg: #0e0c12;
    --primary-line: #c09eff;
    --on: #c09eff;
    --on-hover: #d8c7ff;
    --ring: #d8c7ff;
    --ok: #72cc87;
    --ok-soft: #15301b;
    --warn: #e7ae4e;
    --warn-soft: #362508;
    --crit: #fe9e94;
    --crit-soft: #3e1e1c;
    --info: #88bcfe;
    --info-soft: #172a41;
    --nodata: #b7b5be;
    --nodata-soft: #272629;
    --sign: #211f25;
    --on-sign: #efedf3;
    --sign-edge: #7d7b82;
    --sign-here: #2f2c37;
    --on-sign-here: #cdb6fc;
    --lit-bulb: #ffe4b5;
    --accent-1: #0e0c11;
    --accent-2: #151219;
    --accent-3: #211c2c;
    --accent-4: #2c243c;
    --accent-5: #372c4b;
    --accent-6: #44385c;
    --accent-7: #584976;
    --accent-8: #745d9f;
    --accent-9: #8c5fd2;
    --accent-10: #c09eff;
    --accent-11: #d8c7ff;
    --accent-12: #ede8f7;
    --series-1: #8c5fd2;
    --series-2: #cc4f0c;
    --series-3: #008489;
    --series-4: #abce9b;
    --series-5: #a6b0fb;
    --series-6: #59cdb7;
    --series-7: #bf6ba9;
    --series-8: #e58168;
    --series-text-1: #000000;
    --series-text-2: #000000;
    --series-text-3: #000000;
    --series-text-4: #18161c;
    --series-text-5: #18161c;
    --series-text-6: #18161c;
    --series-text-7: #18161c;
    --series-text-8: #18161c;
    --series-ink-1: #c4a7fe;
    --series-ink-2: #ff9c74;
    --series-ink-3: #5fc5c9;
    --series-ink-4: #abce9b;
    --series-ink-5: #a6b1fc;
    --series-ink-6: #59cdb7;
    --series-ink-7: #f199d8;
    --series-ink-8: #ff9b82;
    --ramp-1: #8768bd;
    --ramp-2: #a180dd;
    --ramp-3: #ba9ef1;
    --ramp-4: #d3beff;
    --ramp-5: #eae1ff;
    --ramp-text-1: #000000;
    --ramp-text-2: #18161c;
    --ramp-text-3: #18161c;
    --ramp-text-4: #18161c;
    --ramp-text-5: #18161c;
    --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
    --shadow-s: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.4);
    --shadow-m: 0 4px 6px -1px rgba(0, 0, 0, 0.45), 0 2px 4px -2px rgba(0, 0, 0, 0.45);
    --shadow-l: 0 10px 15px -3px rgba(0, 0, 0, 0.55), 0 4px 6px -4px rgba(0, 0, 0, 0.55);
    --ring-soft: rgba(216, 199, 255, 0.5);
    --shadow-ring: 0 0 0 var(--ring-width) rgba(216, 199, 255, 0.5);
    --shadow: var(--shadow-l);
    --scrim: rgba(0, 0, 0, 0.55);
    --img-filter: brightness(0.88);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --ground: #0e0c12;
  --surface: #18161c;
  --raised: #211f25;
  --sunken: #09070c;
  --line: #343238;
  --line-strong: #7d7b82;
  --text: #efedf3;
  --muted: #b7b5bf;
  --dim: #b7b5be;
  --accent: #8c5fd2;
  --accent-hover: #ede8f7;
  --accent-text: #d8c7ff;
  --accent-visited: #ffbdd5;
  --accent-soft: #2c243c;
  --accent-line: #8670b0;
  --sel: #211c2c;
  --primary: #c09eff;
  --primary-hover: #d8c7ff;
  --primary-fg: #0e0c12;
  --primary-line: #c09eff;
  --on: #c09eff;
  --on-hover: #d8c7ff;
  --ring: #d8c7ff;
  --ok: #72cc87;
  --ok-soft: #15301b;
  --warn: #e7ae4e;
  --warn-soft: #362508;
  --crit: #fe9e94;
  --crit-soft: #3e1e1c;
  --info: #88bcfe;
  --info-soft: #172a41;
  --nodata: #b7b5be;
  --nodata-soft: #272629;
  --sign: #211f25;
  --on-sign: #efedf3;
  --sign-edge: #7d7b82;
  --sign-here: #2f2c37;
  --on-sign-here: #cdb6fc;
  --lit-bulb: #ffe4b5;
  --accent-1: #0e0c11;
  --accent-2: #151219;
  --accent-3: #211c2c;
  --accent-4: #2c243c;
  --accent-5: #372c4b;
  --accent-6: #44385c;
  --accent-7: #584976;
  --accent-8: #745d9f;
  --accent-9: #8c5fd2;
  --accent-10: #c09eff;
  --accent-11: #d8c7ff;
  --accent-12: #ede8f7;
  --series-1: #8c5fd2;
  --series-2: #cc4f0c;
  --series-3: #008489;
  --series-4: #abce9b;
  --series-5: #a6b0fb;
  --series-6: #59cdb7;
  --series-7: #bf6ba9;
  --series-8: #e58168;
  --series-text-1: #000000;
  --series-text-2: #000000;
  --series-text-3: #000000;
  --series-text-4: #18161c;
  --series-text-5: #18161c;
  --series-text-6: #18161c;
  --series-text-7: #18161c;
  --series-text-8: #18161c;
  --series-ink-1: #c4a7fe;
  --series-ink-2: #ff9c74;
  --series-ink-3: #5fc5c9;
  --series-ink-4: #abce9b;
  --series-ink-5: #a6b1fc;
  --series-ink-6: #59cdb7;
  --series-ink-7: #f199d8;
  --series-ink-8: #ff9b82;
  --ramp-1: #8768bd;
  --ramp-2: #a180dd;
  --ramp-3: #ba9ef1;
  --ramp-4: #d3beff;
  --ramp-5: #eae1ff;
  --ramp-text-1: #000000;
  --ramp-text-2: #18161c;
  --ramp-text-3: #18161c;
  --ramp-text-4: #18161c;
  --ramp-text-5: #18161c;
  --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
  --shadow-s: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.4);
  --shadow-m: 0 4px 6px -1px rgba(0, 0, 0, 0.45), 0 2px 4px -2px rgba(0, 0, 0, 0.45);
  --shadow-l: 0 10px 15px -3px rgba(0, 0, 0, 0.55), 0 4px 6px -4px rgba(0, 0, 0, 0.55);
  --ring-soft: rgba(216, 199, 255, 0.5);
  --shadow-ring: 0 0 0 var(--ring-width) rgba(216, 199, 255, 0.5);
  --shadow: var(--shadow-l);
  --scrim: rgba(0, 0, 0, 0.55);
  --img-filter: brightness(0.88);
  color-scheme: dark;
}
/* The viewer's "increase contrast" setting: muted text, status words and links at APCA Lc 75,
   rings at Lc 60 and borders at Lc 45 (the dark mode plan, 2026-10-29). */
@media (prefers-contrast: more) {
  :root {
    --line: #d9d6df;
    --muted: #5c5865;
    --dim: #4e4a56;
    --accent-text: #4a2779;
    --primary-hover: #4a2779;
    --on-hover: #4a2779;
    --ok: #015926;
    --warn: #684702;
    --crit: #8c2523;
    --info: #014b95;
    --nodata: #4e4a56;
    --on-sign-here: #dbcbff;
    --accent-11: #4a2779;
    --series-ink-1: #7647b9;
    --series-ink-2: #a73d02;
    --series-ink-3: #056b70;
    --series-ink-4: #4b6a3c;
    --series-ink-7: #944380;
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --line: #5a585e;
      --line-strong: #9b99a0;
      --muted: #d0ced9;
      --dim: #d1ced8;
      --accent-text: #ebe4fe;
      --accent-line: #a58fd1;
      --primary: #d5c2ff;
      --primary-hover: #ebe4fe;
      --primary-line: #d5c2ff;
      --on: #d5c2ff;
      --on-hover: #ebe4fe;
      --ring: #ebe4fe;
      --ok: #8be69f;
      --warn: #ffc96f;
      --crit: #fec4bd;
      --info: #b4d5ff;
      --nodata: #d1ced8;
      --sign-edge: #9b99a0;
      --on-sign-here: #dcccff;
      --accent-10: #d5c2ff;
      --accent-11: #ebe4fe;
      --series-ink-1: #d8c7ff;
      --series-ink-2: #ffc2aa;
      --series-ink-3: #7adfe3;
      --series-ink-4: #b6daa6;
      --series-ink-5: #c5cdfe;
      --series-ink-6: #70e3cc;
      --series-ink-7: #ffbbeb;
      --series-ink-8: #ffc1b1;
      --ring-soft: rgba(235, 228, 254, 0.5);
      --shadow-ring: 0 0 0 var(--ring-width) rgba(235, 228, 254, 0.5);
    }
  }
  :root[data-theme="dark"] {
    --line: #5a585e;
    --line-strong: #9b99a0;
    --muted: #d0ced9;
    --dim: #d1ced8;
    --accent-text: #ebe4fe;
    --accent-line: #a58fd1;
    --primary: #d5c2ff;
    --primary-hover: #ebe4fe;
    --primary-line: #d5c2ff;
    --on: #d5c2ff;
    --on-hover: #ebe4fe;
    --ring: #ebe4fe;
    --ok: #8be69f;
    --warn: #ffc96f;
    --crit: #fec4bd;
    --info: #b4d5ff;
    --nodata: #d1ced8;
    --sign-edge: #9b99a0;
    --on-sign-here: #dcccff;
    --accent-10: #d5c2ff;
    --accent-11: #ebe4fe;
    --series-ink-1: #d8c7ff;
    --series-ink-2: #ffc2aa;
    --series-ink-3: #7adfe3;
    --series-ink-4: #b6daa6;
    --series-ink-5: #c5cdfe;
    --series-ink-6: #70e3cc;
    --series-ink-7: #ffbbeb;
    --series-ink-8: #ffc1b1;
    --ring-soft: rgba(235, 228, 254, 0.5);
    --shadow-ring: 0 0 0 var(--ring-width) rgba(235, 228, 254, 0.5);
  }
}

}
@layer cap.tokens {
/* Generated by tokens/scale.mjs (space, radius, type, density, motion, layers, focus, layout). Do not edit: change the script and run
   `npm run tokens`. `npm run check` refuses a file that differs from what it writes. */
:root {
  /* space */
  --space-1: 2px;
  --space-2: 4px;
  --space-3: 8px;
  --space-4: 12px;
  --space-5: 16px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 48px;
  --space-9: 64px;
  /* radius */
  --radius-s: 3px;
  --radius-m: 6px;
  --radius-l: 10px;
  --radius-xl: 14px;
  --radius-full: 999px;
  /* type */
  --fs-h3: 1.125rem;
  --fs-h2: 1.375rem;
  --fs-prose: clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem);
  --fs-prose-h2: clamp(1.375rem, 1.2rem + 1.2vw, 1.875rem);
  --fs-input-coarse: max(1rem, 16px);
  --prose: "Source Serif 4", "Iowan Old Style", Charter, Georgia, serif;
  --display: "Inter", "Inter Fallback", "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --weight-title: 300;
  --weight-heading: 500;
  --wayfinding: "Overpass", "Overpass Fallback", "Segoe UI", Arial, sans-serif;
  --poster: "Jost", "Jost Fallback", Futura, "Century Gothic", sans-serif;
  --drafting: "Capsomer Drafting", "Capsomer Drafting Fallback", "Segoe UI", Arial, sans-serif;
  --readout: "DSEG7 Classic", "DSEG7 Classic Fallback", ui-monospace, monospace;
  /* motion */
  --dur-fast: 100ms;
  --dur-base: 200ms;
  --dur-slow: 400ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: linear(0, 0.005 1%, 0.028 2.5%, 0.117 5.5%, 0.572 16%, 0.77 21.5%, 0.839 24%, 0.906 27%, 0.956 30%, 0.992 33%, 1.012 35.5%, 1.026 38%, 1.035 41%, 1.038 44.5%, 1.035 49.5%, 1.012 63.5%, 1.003 72.5%, 0.999 84.5%, 1);
  /* layer */
  --z-base: 0;
  --z-sticky: 20;
  --z-tabbar: 30;
  --z-overlay: 40;
  --z-message: 70;
  --z-tip: 80;
  /* focus */
  --focus-width: 2px;
  --focus-offset: 2px;
  --ring-width: 3px;
  /* layout */
  --measure: 80ch;
  --page-max: 1440px;
  --fs-page: 1.0625rem;
  --page-gutter: 16px;
  --rail-w: 208px;
  --rail-w-collapsed: 56px;
  --top-h: 44px;
  --figures: tabular-nums;
  --figures-column: tabular-nums;
  --faa-arrow: polygon(0% 41.32%, 52% 41.32%, 52% 5.56%, 96% 50%, 52% 94.44%, 52% 58.68%, 0% 58.68%);
  --faa-arrow-out: polygon(6% 38%, 52% 38%, 52% 14%, 92% 50%, 52% 86%, 52% 62%, 6% 62%);
  --header-h: 3.5rem;
  --cap-arrow: polygon(8.3% 41.7%, 59.2% 41.7%, 40% 22.5%, 50% 12.5%, 87.5% 50%, 50% 87.5%, 40% 77.5%, 59.2% 58.3%, 8.3% 58.3%);
  /* link */
  --link-weight: 600;
  --link-decoration: none;
  --link-hover-bg: var(--accent-soft);
  --link-pressed-bg: var(--accent-5);
  --link-tint-pad: 2px;
  /* touch */
  --link-rule: 0px;
  --icon-radius: 6px;
  --icon-border: 0px;
  --theme-turn: 0deg;
  --arrow-rest: 1;
  --arrow-shift: 0px;
  --card-lift: 0px;
  --card-edge: 0;
  --card-shadow: none;
  --btn-sweep: 0;
  --control-h-coarse: 44px;
  --face: var(--ui);
}
/* Density: compact is the default, on the root or on any element; comfortable on any element
   changes its subtree. Literals in every block, so a wrapper never inherits a stale value. */
:root,
[data-density="compact"] {
  --control: 34px;
  --control-h: 34px;
  --target: 24px;
  --pad-x: 12px;
  --pad-y: 7px;
  --pad-card: 20px;
  --fs-label: 0.6875rem;
  --fs-detail: 0.8125rem;
  --fs-body: 0.875rem;
  --fs-lead: 0.9375rem;
  --gap: 14px;
  --row-h: 40px;
  --text-size: var(--fs-body);
  --leading: 1.5;
}
[data-density="comfortable"] {
  --control: 36px;
  --control-h: 36px;
  --target: 28px;
  --pad-x: 12px;
  --pad-y: 8px;
  --pad-card: 24px;
  --fs-label: 0.75rem;
  --fs-detail: 0.8125rem;
  --fs-body: 0.875rem;
  --fs-lead: 1rem;
  --gap: 16px;
  --row-h: 44px;
  --text-size: var(--fs-body);
  --leading: 1.5;
}
[data-context="prose"] {
  --text-size: var(--fs-prose);
  --leading: 1.6;
  --gap: var(--space-6);
  --control: 40px;
  --face: var(--prose);
}
@media (pointer: coarse) {
  :root,
  [data-density] {
    --control: var(--control-h-coarse);
    --control-h: var(--control-h-coarse);
    --target: 44px;
    --row-h: 44px;
  }
  [data-context="prose"] {
    --control: var(--control-h-coarse);
  }
}

}
/* Every family's one color, so a page can mark the others (tokens/family-marks.css). */
@layer cap.tokens {
/* Generated by tokens/palette.mjs: each family's color (its --on), on every page.
   Do not edit: change the script and run `npm run tokens`. Marks are decoration (a strip of
   sites), so they keep their standard colors under prefers-contrast: more. */
:root {
  --family-purple: #7d50c1;
  --family-fox: #b64404;
  --family-teal: #077478;
  --family-amber: #b68508;
  --family-navy: #2a68cf;
  --family-forest: #028445;
  --family-magenta: #a53d96;
  --family-cerulean: #0478a0;
  --family-olive: #687603;
  --family-rose: #b83466;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --family-purple: #c09eff;
    --family-fox: #ff9266;
    --family-teal: #58bec2;
    --family-amber: #f0b429;
    --family-navy: #80b0ff;
    --family-forest: #50c57b;
    --family-magenta: #f688e2;
    --family-cerulean: #52bae8;
    --family-olive: #a6b84b;
    --family-rose: #ff8bad;
  }
}
:root[data-theme="dark"],
[data-cap-theme="dark"] {
  --family-purple: #c09eff;
  --family-fox: #ff9266;
  --family-teal: #58bec2;
  --family-amber: #f0b429;
  --family-navy: #80b0ff;
  --family-forest: #50c57b;
  --family-magenta: #f688e2;
  --family-cerulean: #52bae8;
  --family-olive: #a6b84b;
  --family-rose: #ff8bad;
}

}
/* Enarratio's custom properties, mapped onto the tokens above (css/enarratio-tokens.css; charts import css/enarratio.css). */
@layer cap.reset, cap.tokens, cap.base, cap.components, cap.utilities;

/* Enarratio's custom properties on Capsomer's tokens. Enarratio (https://github.com/DrDustinEdwards/enarratio)
   reads every color, font, size and timing from --enarratio-* custom properties and never
   imports Capsomer; this maps each onto a Capsomer token, so a change to a token reaches every
   chart, and both themes, every family and both densities follow with no chart code.
   capsomer/tokens.css loads it; a page with charts imports capsomer/enarratio.css, which loads
   it with Enarratio's base rules, the gridlines, each series' ink and the color-pair rules.
   The selector list re-resolves the chain on a wrapper that sets data-family or data-density,
   because a custom property that names another is substituted where it is declared.
   Reader settings need nothing more here: under prefers-contrast: more Capsomer's stronger
   text, muted text and lines reach the charts through these same properties (and Enarratio's
   base rules add full textures, wider gaps and gridlines in the muted color), and under
   forced-colors: active Enarratio's base rules repaint the drawing and legend in system
   colors on the elements themselves, so they win over this mapping. */
@layer cap.tokens {
  :root,
  [data-family],
  [data-density] {
    /* colors */
    --enarratio-background: var(--surface);
    --enarratio-text: var(--text);
    --enarratio-text-muted: var(--muted);
    --enarratio-grid: var(--line);
    --enarratio-focus: var(--ring);

    /* the eight series, then the label that reads best on each */
    --enarratio-series-1: var(--series-1);
    --enarratio-series-2: var(--series-2);
    --enarratio-series-3: var(--series-3);
    --enarratio-series-4: var(--series-4);
    --enarratio-series-5: var(--series-5);
    --enarratio-series-6: var(--series-6);
    --enarratio-series-7: var(--series-7);
    --enarratio-series-8: var(--series-8);
    --enarratio-series-text-1: var(--series-text-1);
    --enarratio-series-text-2: var(--series-text-2);
    --enarratio-series-text-3: var(--series-text-3);
    --enarratio-series-text-4: var(--series-text-4);
    --enarratio-series-text-5: var(--series-text-5);
    --enarratio-series-text-6: var(--series-text-6);
    --enarratio-series-text-7: var(--series-text-7);
    --enarratio-series-text-8: var(--series-text-8);

    /* the five-step ramp, least to most, in the family's hue */
    --enarratio-sequential-1: var(--ramp-1);
    --enarratio-sequential-2: var(--ramp-2);
    --enarratio-sequential-3: var(--ramp-3);
    --enarratio-sequential-4: var(--ramp-4);
    --enarratio-sequential-5: var(--ramp-5);
    --enarratio-sequential-text-1: var(--ramp-text-1);
    --enarratio-sequential-text-2: var(--ramp-text-2);
    --enarratio-sequential-text-3: var(--ramp-text-3);
    --enarratio-sequential-text-4: var(--ramp-text-4);
    --enarratio-sequential-text-5: var(--ramp-text-5);

    /* status: the same colors as the status component, never the series */
    --enarratio-status-good: var(--ok);
    --enarratio-status-warning: var(--warn);
    --enarratio-status-bad: var(--crit);
    --enarratio-status-unknown: var(--nodata);

    /* fonts: figures are tabular in the interface face */
    --enarratio-font: var(--ui);
    --enarratio-font-numeric: var(--ui);

    /* sizes follow density */
    --enarratio-font-size: var(--text-size);
    /* never under the reader's own text size (Enarratio's 0.75rem), so mark text follows it */
    --enarratio-font-size-mark: max(var(--fs-detail), 0.75rem);
    --enarratio-font-size-small: var(--fs-detail);
    --enarratio-font-size-tooltip: var(--fs-body);
    --enarratio-line-height-tooltip: var(--leading);

    /* spacing and shape */
    --enarratio-space: var(--space-3);
    --enarratio-gap: var(--space-5);
    --enarratio-gap-row: var(--space-2);
    --enarratio-gap-inline: calc(var(--space-2) + var(--space-1));
    /* a button's padding makes up the family's target height (44px on a touch screen) */
    --enarratio-padding-button: max(var(--space-1), (var(--target) - 1lh) / 2) var(--space-2);
    --enarratio-cell-padding: var(--space-2) var(--space-4) var(--space-2) 0;
    --enarratio-radius: var(--radius-s);
    --enarratio-radius-swatch: var(--radius-s);
    --enarratio-radius-tooltip: var(--radius-m);
    --enarratio-swatch-size: var(--space-4);
    --enarratio-tooltip-padding: var(--space-2) var(--space-3);
    --enarratio-tooltip-shadow: var(--shadow-m);
    --enarratio-z-tooltip: var(--z-tip);

    /* focus: the shared ring's width and offset on a focused chart or legend button */
    --enarratio-focus-outline-width: var(--ring-width);
    --enarratio-focus-outline-offset: var(--focus-offset);

    /* timings: 100 and 400 ms, the family's motion; Enarratio stops them under reduced motion */
    --enarratio-duration-hover: var(--dur-fast);
    --enarratio-duration-grow: var(--dur-slow);
    --enarratio-duration-fade: var(--dur-slow);
    --enarratio-duration-draw: var(--dur-slow);
    --enarratio-ease-grow: var(--ease-out);
    --enarratio-ease-out: var(--ease-out);
  }
}



/* The layer order, repeated so this file is safe whatever order an app imports it in: the first statement a browser reads fixes it (css/layers.css has the full note). */
@layer cap.reset, cap.tokens, cap.base, cap.components, cap.utilities;

/* The utility classes (.cap-sr-only and friends), also exported alone as capsomer/utilities.css. */
/* Capsomer's utility classes, alone: for an app that keeps its own reset and body styles and does
   not load capsomer/base.css (which imports this file), but still wants .cap-sr-only and the rest.
   `import "capsomer/utilities.css"`. The layer order is repeated so it is safe in any order (css/layers.css). */
@layer cap.reset, cap.tokens, cap.base, cap.components, cap.utilities;

@layer cap.utilities {
  /* A flat image, a screenshot or a diagram on white: an edge so it sits on the page, and in dark
     a little dimmer so it does not glow (--img-filter). Photos need neither and go without it. An
     image with its own dark version uses <picture> with a (prefers-color-scheme: dark) source,
     which follows the system setting rather than the switch. */
  .cap-img-flat {
    border: 1px solid var(--line);
    filter: var(--img-filter);
  }

  /* Text a screen reader announces and the eye does not see. The focusable variant shows
     while it, or something in it, has focus. Prelum's footnotes heading carries GFM's own name
     for it, .sr-only (components/prose-blocks). */
  .cap-sr-only,
  .cap-sr-only-focusable:not(:focus-within),
  :where([data-context="prose"]) .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  /* Identifiers only: ids, shas, commands, paths. Times and counts are .cap-num. */
  .cap-mono {
    font-family: var(--mono);
    font-size: 0.75rem;
    letter-spacing: -0.01em;
  }
  .cap-num {
    font-variant-numeric: var(--figures-column);
  }
  .cap-muted {
    color: var(--muted);
  }
  /* The family page: one width and one body size on every site (--page-max, --fs-page), so a
     page's content and footer line up with the letterhead above them, and with every other site's. */
  .cap-page {
    font-size: var(--fs-page);
    line-height: 1.55;
    box-sizing: border-box;
    inline-size: 100%;
    max-inline-size: var(--page-max);
    margin-inline: auto;
    padding-inline: max(var(--page-gutter), env(safe-area-inset-left, 0px)) max(var(--page-gutter), env(safe-area-inset-right, 0px));
  }
  .cap-label {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--muted);
  }
}

/* The family arrow (Dustin, 2026-10-27): one bold arrow, square shaft and wide solid head, for every
   link that takes you somewhere, after the transit signs (New York City Transit Authority 1970,
   British Rail 1965) that drew one arrow and turned it. Turned only in 45-degree steps: on (the
   default) points right, back points left, out (leaves the site) points up and right. A clip path,
   not an image, so it needs no file and takes the text's color. Links in running text and the
   header's section links keep none: an arrow on everything stops meaning "this goes somewhere". A utility, so
   a page that keeps its own base (dustinedwards.info) still draws the footer's arrows. */
@layer cap.utilities {
  /* The shape is the --cap-arrow token (tokens/scale.css). The link system's next and title
     links take it too (components/link/link.md): a title's waits for the pointer or focus. */
  .cap-go::after,
  .cap-go[data-go="back"]::before,
  a[data-link="next"]::after,
  :is(a[data-link="title"], :is(h1, h2, h3, h4) > a:not([class*="cap-"]))::after {
    content: "";
    display: inline-block;
    flex: none;
    inline-size: 0.85em;
    block-size: 0.85em;
    margin-inline-start: 0.3em;
    vertical-align: -0.08em;
    background: currentColor;
    clip-path: var(--cap-arrow);
  }
  .cap-go[data-go="out"]::after {
    rotate: -45deg;
  }
  :is(a[data-link="title"], :is(h1, h2, h3, h4) > a:not([class*="cap-"])):not(:hover, :focus-visible, [data-force="hover"])::after {
    opacity: 0;
  }
  /* "Back" and "next" are wayfinding: the airport sign face (Overpass, --wayfinding), bold. */
  .cap-go:is([data-go="back"], [data-go="next"]) {
    font-family: var(--wayfinding);
    font-weight: 700;
  }
  .cap-go[data-go="back"] {
    &::after {
      content: none;
    }
    &::before {
      margin-inline: 0 0.3em;
      rotate: 180deg;
    }
  }
  /* Under the pointer or focus the arrow steps 3px the way it points, and back when you leave:
     the one motion it has, and none under reduced motion. */
  @media (prefers-reduced-motion: no-preference) {
    /* 200ms, ease-out (Material's and NN/g's range for a small hover motion: under 100ms reads as a
       jump). Pseudo-elements cannot sit inside :is(), so each is named. */
    .cap-go::before,
    .cap-go::after,
    a[data-link="next"]::after,
    .cap-sign::before,
    .cap-sign::after,
    .cap-site-header-view::after {
      transition: translate var(--dur-base) var(--ease-out);
    }
    :is(.cap-go, .cap-sign[rel~="next"], .cap-sign[data-variant="forward"], a[data-link="next"]):is(:hover, :focus-visible)::after {
      translate: 3px 0;
    }
    :is(.cap-go[data-go="out"], .cap-site-header-view):is(:hover, :focus-visible)::after {
      translate: 2px -2px;
    }
    :is(.cap-go[data-go="back"], .cap-sign[rel~="prev"]):is(:hover, :focus-visible)::before {
      translate: -3px 0;
    }
  }
  @media (forced-colors: active) {
    .cap-go::after,
    .cap-go[data-go="back"]::before,
    a[data-link="next"]::after,
    :is(a[data-link="title"], :is(h1, h2, h3, h4) > a:not([class*="cap-"]))::after {
      forced-color-adjust: none;
      background: LinkText;
    }
  }
}

/* The panel lamp (Dustin, 2026-11-04), the hover of wayfinding links (the family footer's link columns and a
   next link): under the pointer or focus a small square lamp in the family's color lights just left of the
   link, as a lamp on an instrument panel, while the link's own rules turn its words to the accent. The lamp
   is positioned outside the flow, so nothing moves; the link sets position: relative. */
@layer cap.utilities {
  :is(.cap-family-footer-links a, a[data-link="next"])::before {
    content: "";
    position: absolute;
    inset-inline-start: -13px;
    inset-block-start: calc(50% - 3.5px);
    inline-size: 7px;
    block-size: 7px;
    border-radius: 1px;
    background: var(--on);
    box-shadow: 0 0 6px var(--on);
    opacity: 0;
    pointer-events: none;
  }
  :is(.cap-family-footer-links a, a[data-link="next"]):is(:hover, :focus-visible)::before {
    opacity: 1;
  }
  @media (prefers-reduced-motion: no-preference) {
    :is(.cap-family-footer-links a, a[data-link="next"])::before {
      transition: opacity var(--dur-fast) var(--ease-out);
    }
  }
  @media (forced-colors: active) {
    :is(.cap-family-footer-links a, a[data-link="next"])::before {
      forced-color-adjust: none;
      background: Highlight;
      box-shadow: none;
    }
  }
}

/* In the components layer, where the shell and the site header drew their own copies, so a
   component can still move it (the letterhead does). */
@layer cap.components {
  /* The skip link, the first thing a keyboard reaches: hidden until focused, then a primary
     button in the corner (the shell's .cap-shell-skip and the site header's .cap-site-header-skip
     are the same link). */
  :is(.cap-skip, .cap-shell-skip, .cap-site-header-skip) {
    position: absolute;
    inset-inline-start: var(--space-3);
    inset-block-start: var(--space-3);
    z-index: var(--z-tip);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-m);
    background: var(--primary);
    color: var(--primary-fg);
    box-shadow: var(--shadow-m);
    font-weight: 600;
    text-decoration: none;

    &:not(:focus-visible) {
      transform: translateY(-200%);
    }
  }
}


/* Element defaults every component assumes. Layered, so an app that keeps its own body
   or link styles wins without a fight. */
@layer cap.reset {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }
  button,
  input,
  select,
  textarea {
    font: inherit;
    color: inherit;
  }
  [hidden] {
    display: none !important;
  }
}

@layer cap.base {
  /* An image with width and height attributes reserves its box before it loads. The browser's own ratio from them is
     `auto w / h`, and Chrome flags a lazy image whose height is auto and whose ratio is only that (DevTools
     LazyLoadImageIssue; the fix it asks for is an explicit aspect-ratio, web.dev/articles/cls). Naming the ratio from the
     same attributes settles it. A browser without typed attr() keeps the `auto w / h` it already had. */
  @supports (aspect-ratio: attr(width type(<number>)) / attr(height type(<number>))) {
    :where(img[width][height]) {
      aspect-ratio: attr(width type(<number>)) / attr(height type(<number>));
    }
  }
  body {
    margin: 0;
    background: var(--ground);
    color: var(--text);
    font: 400 var(--text-size) / var(--leading) var(--face);
    -webkit-font-smoothing: antialiased;
    /* A word longer than its line (an address written out as a link, a tool's name) breaks
       rather than pushing a phone's page sideways (WCAG 1.4.10 Reflow). break-word, not
       anywhere: it changes no box's min-content size, so tables and flex rows lay out as before. */
    overflow-wrap: break-word;
  }
  /* The reading context sets its own face and size where it is declared, not only on body. */
  /* A density wrapper sets its own reading size (the root keeps rem sizing). */
  [data-density]:where(:not(:root)) {
    font-size: var(--text-size);
    line-height: var(--leading);
  }
  [data-context] {
    font-family: var(--face);
    font-size: var(--text-size);
    line-height: var(--leading);
  }
  /* A link is told by weight, not a line (DEFAULTS.md). Every link takes the link color and the
     focus ring; a text link (no component class, or a kind of the link system: components/link)
     is semibold, turns the visited color once followed (outside a nav), and under the pointer darkens on a soft
     tint, which a press makes stronger. The tint is a background and a 2px shadow of the same
     color, cloned onto each line a link wraps to. A link that is a control is drawn by its component.
     A chart's Download SVG and PNG buttons (Enarratio's .enarratio-export) sit beside its links
     and are drawn as one, every state but visited; css/enarratio.css hands them back here. */
  a,
  :where(.enarratio-export) {
    color: var(--accent-text);
    text-decoration: var(--link-decoration);
    &:is(:not([class*="cap-"]), [data-link], .cap-footnote-ref) {
      font-weight: var(--link-weight);
    }
    /* Not in a nav: a menu is told by its place, and draws its own tint (link.md). */
    &:is([href], .enarratio-export):is(:not([class*="cap-"]), [data-link], .cap-footnote-ref):not(nav a) {
      border-radius: 3px;
      -webkit-box-decoration-break: clone;
      box-decoration-break: clone;
      /* :visited may set colors only, and getComputedStyle hides it, so a specimen forces it. */
      &:visited,
      &[data-force="visited"] {
        color: var(--accent-visited);
      }
      &:hover,
      &[data-force="hover"] {
        color: var(--accent-hover);
        background: var(--link-hover-bg);
        box-shadow: 0 0 0 var(--link-tint-pad) var(--link-hover-bg);
      }
      &:active,
      &[data-force="pressed"] {
        color: var(--accent-hover);
        background: var(--link-pressed-bg);
        box-shadow: 0 0 0 var(--link-tint-pad) var(--link-pressed-bg);
      }
      /* Forced colors paint no tint, so the pointer gets the system's own cue. */
      @media (forced-colors: active) {
        &:hover {
          text-decoration: underline;
        }
      }
    }
    &:hover {
      color: var(--accent-hover);
    }
    @media (prefers-reduced-motion: no-preference) {
      transition:
        color var(--dur-fast) var(--ease-out),
        background-color var(--dur-fast) var(--ease-out),
        box-shadow var(--dur-fast) var(--ease-out);
    }
  }
  /* A trailing arrow in a link or button. A site's --arrow-rest and --arrow-shift (shown and in place
     by default) can hide it until the pointer or focus arrives, when it slides in. */
  .cap-arrow {
    inline-size: 1.1em;
    block-size: 1.1em;
    flex: none;
    opacity: var(--arrow-rest);
    translate: var(--arrow-shift) 0;
    :is(a, button):is(:hover, :focus-visible) > & {
      opacity: 1;
      translate: 0 0;
    }
    @media (prefers-reduced-motion: no-preference) {
      transition:
        opacity var(--dur-base) var(--ease-out),
        translate var(--dur-base) var(--ease-out);
    }
  }
  button {
    cursor: pointer;
  }
  :focus-visible,
  a[data-force="focus"] {
    /* The shared focus indicator: a 2 px solid --ring outline, 3:1 against every surface
       (palette.mjs checks it). A field may add --shadow-ring, the soft 3 px glow, beside it. */
    outline: var(--focus-width) solid var(--ring);
    outline-offset: var(--focus-offset);
  }
  /* A scroll region (a code box or wide table: tabindex="0", role="region", a name) draws the ring
     inside its edge, so a parent that clips its overflow cannot hide it (the table's and dialog's rule). */
  [role="region"][tabindex="0"]:focus-visible {
    outline-offset: calc(var(--focus-width) * -1);
  }
  h1,
  h2,
  h3 {
    text-wrap: balance;
  }
  /* The type plan's weights (tokens/scale.mjs): a page title in Inter Light, a heading in Medium, in
     place of the browser's bold. A site or component that sets its own still wins over this layer. */
  h1 {
    font-weight: var(--weight-title);
  }
  h2,
  h3,
  h4 {
    font-weight: var(--weight-heading);
  }
  /* A touch screen gets 16 px inputs, so iOS does not zoom into the field (decision 5). */
  @media (pointer: coarse) {
    input,
    select,
    textarea {
      font-size: max(var(--fs-input-coarse), 1em);
    }
  }
  /* Still by default (design 4.1): a component's motion is written inside
     prefers-reduced-motion: no-preference, and this catches anything that is not. */
  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      transition-duration: 0s !important;
      transition-delay: 0s !important;
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      scroll-behavior: auto !important;
    }
  }
}

/* Between pages, and when the theme changes, the old view fades into the new one in 200 ms
   instead of cutting (a view transition; the browser keeps whatever is the same on both still).
   Same-origin page loads take part on their own (cross-document view transitions); a client-side
   router or theme-switch.ts starts one itself. A page change, typed cap-page, also lets the main
   content rise 6 px into place while the header and menus stay put (Arc's dialog rise, applied to
   the page). Only with motion allowed; a browser without view transitions just shows the new
   page, as before. An app that wants none writes `@view-transition { navigation: none; }`. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
    types: cap-page;
  }
  ::view-transition-group(root) {
    animation-duration: var(--dur-base);
    animation-timing-function: var(--ease-out);
  }
  :active-view-transition-type(cap-page) main {
    view-transition-name: cap-main;
  }
  ::view-transition-group(cap-main) {
    animation: none;
  }
  ::view-transition-old(cap-main) {
    animation: var(--dur-fast) var(--ease-out) both cap-page-out;
  }
  ::view-transition-new(cap-main) {
    animation: var(--dur-base) var(--ease-out) both cap-page-in;
  }
  @keyframes cap-page-out {
    to {
      opacity: 0;
    }
  }
  @keyframes cap-page-in {
    from {
      opacity: 0;
      transform: translateY(6px);
    }
  }
}



/* The layer order, repeated so this file is safe whatever order an app imports it in: the first statement a browser reads fixes it (css/layers.css has the full note). */
@layer cap.reset, cap.tokens, cap.base, cap.components, cap.utilities;

/* The link system (link.md). css/base.css gives every link its four cues (the link color,
   semibold, the hover tint, the focus ring) and the visited and pressed states; this file gives
   each kind of link one cue more, named by data-link="<kind>" on the a, or found by CSS where the
   kind shows in the markup (an a with a component class keeps only its component's look). Every
   mark is hidden from assistive technology: alt text "" on a glyph, no content on a drawn icon; the
   words a mark stands for are in the contract (visually hidden text, or the meta). */
@layer cap.components {
  /* A kind names its glyph in --link-after or --link-before; two rules of no specificity draw them,
     so a component's own ::before and ::after always win. A fallback (no data-link) speaks its
     words as alt text, since its author wrote none. */
  /* An outside site's own icon (.cap-link-icon, below) replaces the arrow. Prelum puts rel="external"
     on every off-family link whatever its kind, so rel and target count only with no data-link. */
  a[data-link="away"]:not(:has(.cap-link-icon)),
  a:not([data-link], [class*="cap-"]):is([rel~="external"], [target="_blank"]) {
    --link-after: "\2197";
  }
  a:not([data-link], [class*="cap-"])[rel~="external"] {
    --link-alt: ", opens another site";
  }
  a:not([data-link], [class*="cap-"], [rel~="external"])[target="_blank"] {
    --link-alt: ", opens in a new tab";
  }
  a[data-link="file"],
  a:not([data-link], [class*="cap-"]):is([download], [href$=".pdf" i], [href$=".zip" i], [href$=".csv" i], [href$=".epub" i], [href$=".docx" i], [href$=".xlsx" i], [href$=".pptx" i]) {
    --link-after: "\2193";
  }
  /* "#", the fragment's own character: a place on this page. A down arrow would repeat the
     download's mark, and point the wrong way to a place above. Found in running text only, never
     in a nav (a table of contents), a footnote or a component. */
  a[data-link="jump"],
  :is(p, li, dd, td, blockquote, figcaption) > a:not([data-link], [class*="cap-"], [href="#"], [data-footnote-ref], [data-footnote-backref], nav a)[href^="#"] {
    --link-after: "#";
  }
  a[data-link="email"],
  a:not([data-link], [class*="cap-"])[href^="mailto:" i] {
    --link-before: "\2709\FE0E";
  }
  a[data-link="phone"],
  a:not([data-link], [class*="cap-"])[href^="tel:" i] {
    --link-before: "\260E\FE0E";
  }
  :where(a[data-link], a:not([class*="cap-"]))::after {
    content: var(--link-after) / var(--link-alt, "");
    margin-inline-start: 0.2em;
    font-weight: 400;
    font-variant-emoji: text;
  }
  :where(a[data-link], a:not([class*="cap-"]))::before {
    content: var(--link-before) / "";
    margin-inline-end: 0.25em;
    font-weight: 400;
    font-variant-emoji: text;
  }

  /* The meta: a file's format and size, or a language's name, as a sibling after the link (a
     space between), in the mono face, smaller and muted. Outside the link, so the link's name
     stays the words and the meta is read after it. */
  .cap-link-meta {
    color: var(--muted);
    font: 400 0.75em / 1 var(--mono);
    letter-spacing: -0.01em;
    white-space: nowrap;
  }

  /* An outside site's icon, fetched by the site (Prelum), as the link's first child: the family
     icons' size and place. In dark it sits on a light plate so a dark mark still shows; in forced
     colors, where its colors may vanish, it gives way to the arrow. */
  .cap-link-icon {
    display: inline-block;
    inline-size: 1em;
    block-size: 1em;
    margin-inline-end: 0.3em;
    vertical-align: -0.14em;
    border-radius: 3px;
    object-fit: contain;
    background: light-dark(transparent, var(--text));
    padding: 1px;
  }

  /* A family site: its icon before the name, drawn from the list below as a mask in the link's
     color (never loaded from the site). A site with no icon here keeps the family arrow turned out. */
  a[data-link="family"]::before {
    content: "";
    display: inline-block;
    inline-size: 1em;
    block-size: 1em;
    margin-inline-end: 0.3em;
    vertical-align: -0.14em;
    background: currentColor;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath transform='rotate(-45 12 12)' d='M2 10h12.2L9.6 5.4 12 3l9 9-9 9-2.4-2.4 4.6-4.6H2z'/%3E%3C/svg%3E") center / contain no-repeat;
  }
  /* One icon per site in FAMILY_LINK_SITES (components/family-footer/family-footer.ts), each its
     site's own favicon or mark reduced to one color on a 24-unit grid. */
  a[data-link="family"][data-site="dustinedwards"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M17.4 20.9 14.7 22.7 11.5 23.2 8.4 22.4 5.9 20.5 4.9 19.1 4 16.1 4.4 12.9 6 10.1 7.2 9 10.1 7.7 10.8 10.6 8.2 11.9 6.7 14.4 7 17.3 8.1 18.9 9.7 19.9 11.7 20.3 13.5 19.8 15.1 18.6z'/%3E%3Cpath d='M13.2 18.6 18.7 18.6 18.5 19.6 17.9 20.5 17 21.1 16 21.3 14.9 21.1 14 20.5 13.4 19.6z'/%3E%3Cpath d='M4.1 23.4 4.8 22.2 6.7 21.3 17.4 21.3 19.3 22.2 20 23.4z'/%3E%3Cpath d='M10.5 7.6 13.6 7.7 16.5 9.1 17.6 10.1 19.9 13.6 17.7 14.8 15.8 11.8 14 10.5 11.9 10.1z'/%3E%3Cpath d='M6 5.5 8.4 4.1 13.6 12.9 11.2 14.3z'/%3E%3Cpath d='M14.2 14 16.4 12.7 17.7 14.8 15.5 16.1z'/%3E%3Cpath d='M11.8 15.3 14.2 14 15.5 16.1 13.1 17.5z'/%3E%3Cpath d='M7.8 3 5.4 4.5 4 2 6.4 .6z'/%3E%3C/svg%3E"); }
  a[data-link="family"][data-site="germomics"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 .4 23.6 6.2 23.6 17.8 12 23.6 .4 17.8 .4 6.2zM11.9 19.5 10.2 19.3 8.7 18.8 6.6 17.2 5.6 15.9 5 14.5 4.7 13.1 4.6 11.5 4.9 10 5.4 8.8 6.4 7.3 7.8 6.1 10.3 5 12.8 4.9 15.6 5.6 18.1 7.5 16.2 9.3 14.8 8.1 12.9 7.5 10.8 7.6 9.2 8.3 8 9.6 7.3 11.1 7.3 13.1 8.1 14.9 9.8 16.4 11.4 16.9 13 16.9 14.8 16.2 15.6 15.4 16.1 14.6 12.1 14.6 12.1 12.1 19 12.1 19 13.5 18.8 14.7 18.1 16.2 16.4 18.2 14.4 19.2z'/%3E%3C/svg%3E"); }
  a[data-link="family"][data-site="julieedwards"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M2.3 0 4.6 .5 6.4 1.4 8.8 3.7 9.3 4.9 10.5 3.6 12.1 2.6 9.3 6.6 12.2 5.8 14.4 5.9 16.5 7.1 17.9 9.1 18.7 12.1 18.1 16.6 16 20.9 14.7 22.6 13.1 23.7 11.2 24 9.3 23.3 7.5 23.9 5.8 23.6 3.3 22 1.1 18.9 -.6 13.7 -.5 10.8 .3 8.2 1.4 6.7 3 5.9 5.8 5.8 8.6 6.9 8.9 5.7 6.8 5.3 4.1 3.8 1.7 .6 1.8 .1zM5.3 8.6 5.3 20.9 12.5 20.9 12.5 19.4 6.9 19.4 6.9 14.9 11.1 14.9 11 13.5 6.9 13.5 6.9 10.1 12.6 10.1 12.6 8.6z'/%3E%3C/svg%3E"); }
  a[data-link="family"][data-site="foxing"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M5.2 0 19.8 .1 21.7 .9 23.1 2.3 23.6 3.2 24 5.2 24 18.8 23.6 20.8 23.1 21.7 21.7 23.1 20.8 23.6 18.8 24 5.2 24 3.2 23.6 2.3 23.1 .9 21.7 .1 19.8 0 18.8 .1 4.2 .9 2.3 1.5 1.5 3.2 .4zM6.8 4.9 17.6 4.9 17.6 8.2 16.1 8.2 15.8 7.1 11.2 7.1 11.2 10.9 15 10.9 15 13.5 11.2 13.5 11.2 18 13.1 18.4 13.1 19.5 6.4 19.5 6.4 18.4 7.9 18 7.9 6.4 6.8 6z'/%3E%3C/svg%3E"); }
  a[data-link="family"][data-site="foxhound"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M3 4 4.2 2.9 5.5 2.1 7.1 1.6 8.7 1.5 10.2 1.8 11.6 2.4 13.8 4.6 20.2 5.6 21 5.3 21.9 5.3 22.9 6 23.3 7.1 23.2 8.3 22.6 9.2 22.5 10.9 21.9 11.7 20.5 12.3 18.3 12.6 16.4 12.5 15.5 13.8 14.2 14.5 13 14.5 11.8 14 9 14.2 8.4 18.5 7.2 21.3 5.8 22.7 5 23 3.7 22.8 2.7 22.1 1.8 20.2 1.1 17.4 .8 14.1 .8 10.7 1.1 7.9 1.8 5.9zM12.4 6.4 11.6 6.8 11.3 7.6 11.7 8.4 12.5 8.7 13.3 8.3 13.5 7.4 13.1 6.6zM6.3 5.6 7.1 7.7 7.6 9.9 7.8 12.2 7.6 14.5 9 14.3 9.2 10.4 8.6 7.4 7.8 5.2z'/%3E%3C/svg%3E"); }
  a[data-link="family"][data-site="txasm"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M11.4 22.4 11.4 23.6 12.6 23.6 12.6 22.4z'/%3E%3Cpath d='M13.7 6.3 13.7 .4 10.3 .4 10.3 3.1 7.3 4.2 5.6 5.4 4.2 7 2.9 10 2.7 12.2 3.9 12.2 4.1 10.3 4.7 8.6 5.7 7.1 7.8 5.3 10.3 4.3 10.3 6.3z'/%3E%3Cpath d='M6.8 22.1 7.9 22.6 8.5 21.6 7.4 21z'/%3E%3Cpath d='M19.8 19.5 20.4 18.4 19.3 17.8 18.7 18.9z'/%3E%3Cpath d='M16.1 22.6 17.2 22.1 16.6 21 15.5 21.6z'/%3E%3Cpath d='M3.6 18.4 4.2 19.5 5.3 18.9 4.7 17.8z'/%3E%3Cpath d='M3.9 13.7 2.7 13.7 2.7 14.9 3.9 14.9z'/%3E%3Cpath d='M20.1 14.9 21.3 14.9 21.3 13.7 20.1 13.7z'/%3E%3Cpath d='M19.2 13.7 4.8 13.7 4.8 14.9 8.5 15 8.6 15.6 5.4 17.4 5.8 18.1 6 18.4 9.4 16.6 9.7 17.1 7.9 20.2 8.9 20.8 10.7 17.8 11.1 17.6 11.4 18 11.4 21.5 12.6 21.5 12.7 17.7 13.3 17.7 15.1 20.8 15.8 20.5 16.1 20.2 14.4 16.9 14.8 16.6 18 18.4 18.6 17.4 15.5 15.6 15.3 15.2 15.7 14.9 19.2 14.9z'/%3E%3Cpath d='M11.2 9.6 13 9.6 13 7.1 11 7.1 11 9.4z'/%3E%3C/svg%3E"); }
  a[data-link="family"][data-site="bsw"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6.3 1 11.3 3.9v5.8L6.3 12.6 1.3 9.7V3.9zM17.7 1l5 2.9v5.8l-5 2.9-5-2.9V3.9zM6.3 11.4l5 2.9v5.8L6.3 23l-5-2.9v-5.8zM17.7 11.4l5 2.9v5.8l-5 2.9-5-2.9v-5.8z'/%3E%3C/svg%3E"); }
  a[data-link="family"][data-site="carrel"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M4.5 0 20.4 .1 22 .8 23.2 2 23.7 2.8 24 4.5 24 19.5 23.7 21.2 22.7 22.7 22 23.2 21.2 23.7 19.5 24 4.5 24 2.8 23.7 2 23.2 .8 22 .3 21.2 0 19.5 .1 3.6 .8 2 1.3 1.3 2.8 .3zM6.4 7.7 7.9 7.2 9.4 7.1 10.8 7.5 12 8.2 13.2 7.5 14.6 7.1 16.1 7.2 17.6 7.7 17.6 16.4 16.1 15.9 14.6 15.8 13.2 16.2 12 17 10.8 16.2 9.4 15.8 7.9 15.9 6.4 16.4zM11.4 8.7 11.4 16.2 12.6 16.2 12.6 8.7z'/%3E%3C/svg%3E"); }
  a[data-link="family"][data-site="capsid"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M23.5 12 17.75 22H6.25L.5 12 6.25 2h11.5zM20.6 12 16.1 4.5H7.9L3.4 12l4.5 7.5h8.2z'/%3E%3C/svg%3E"); }
  a[data-link="family"][data-site="capsomer"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 1 21.5 6.5v11L12 23l-9.5-5.5v-11z'/%3E%3C/svg%3E"); }
  a[data-link="family"][data-site="prelum"]::before { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M4.5 0 20.4 .1 22 .8 23.2 2 23.7 2.8 24 4.5 24 19.5 23.7 21.2 22.7 22.7 22 23.2 21.2 23.7 19.5 24 4.5 24 2.8 23.7 2 23.2 .8 22 .3 21.2 0 19.5 .1 3.6 .8 2 1.3 1.3 2.8 .3zM7.5 5.2 13.5 5.2 15.2 5.6 16.7 6.6 17.7 8 17.9 8.9 17.9 10.6 17.7 11.5 17.2 12.3 16 13.5 14.4 14.2 10.5 14.2 10.5 18.8 7.5 18.8z'/%3E%3C/svg%3E"); }

  /* A footnote: the superscript number, and the way back from the note (GFM writes both). */
  :is(.cap-footnote-ref, a[data-link="footnote"], a[data-footnote-ref]) {
    padding-inline: 0.1em;
    font-variant-numeric: lining-nums;
    &:not(sup > *) {
      vertical-align: super;
      font-size: 0.75em;
      line-height: 0;
    }
  }
  a[data-footnote-backref] {
    padding-inline: 0.15em;
    font: 600 1.1em / 1 var(--ui);
    font-variant-emoji: text;
  }

  /* A cross-reference on the same site; an address written out (a URL, a DOI, an email), which
     may break anywhere rather than run past a phone's edge. */
  a[data-link="xref"] {
    font-style: italic;
  }
  /* A next link stands alone, so it is a whole target, not a word in a sentence. It is wayfinding,
     so it is set in the airport sign face (Overpass, --wayfinding), as breadcrumbs and footer links are.
     Its box is trimmed to the capitals and padded back out to the target, so the panel lamp centers
     on the letters (family-footer.css says why). */
  a[data-link="next"] {
    display: inline-block;
    padding-block: calc((var(--target) - 1cap) / 2);
    min-block-size: var(--target);
    text-box: trim-both cap alphabetic;
    position: relative;
    font-family: var(--wayfinding);
    font-weight: 700;

    /* The panel lamp hover (css/utilities.css): the words in the accent, no tint. */
    &:is(:hover, :focus-visible) {
      background: none;
      box-shadow: none;
      color: var(--accent-text);
    }
  }
  a[data-link="address"] {
    font-family: var(--mono);
    font-size: 0.875em;
    overflow-wrap: anywhere;
  }

  /* A tag or category: a pill. The catalog's active-filter chip is the same pill. */
  :is(a[data-link="tag"], .cap-catalog-chip) {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-block-size: max(var(--target), 26px);
    padding: 0 var(--pad-x);
    border: 1px solid var(--ring);
    border-radius: var(--radius-full);
    background: var(--accent-soft);
    color: var(--accent-text);
    font: 600 var(--fs-detail) / 1.2 var(--ui);
    white-space: nowrap;
    vertical-align: middle;
    &:visited,
    &[data-force="visited"] {
      color: var(--accent-visited);
    }
    &:is(:hover, [data-force="hover"]) {
      background: var(--accent-5);
      box-shadow: none;
      color: var(--accent-hover);
    }
    &:is(:active, [data-force="pressed"]) {
      background: var(--accent-6);
      box-shadow: none;
    }
  }

  @media (forced-colors: active) {
    a[data-link="family"]::before {
      forced-color-adjust: none;
      background: LinkText;
    }
    .cap-link-icon {
      display: none;
    }
    a[data-link="away"] {
      --link-after: "\2197";
    }
  }
}


@layer cap.tokens {
/* Generated by tokens/palette.mjs: the olive family, step 9 #768602 (oklch 0.586 0.136 117.8).
   Put data-family="olive" on the root or on any element to switch its subtree.
   Import after tokens.css. Do not edit: change the script and run `npm run tokens`. */
[data-family="olive"] {
  --ground: #f9fbf2;
  --surface: #fdfefb;
  --raised: #f6f8f2;
  --sunken: #e7e9e0;
  --line: #dddfd6;
  --line-strong: #8f9088;
  --text: #191c0c;
  --muted: #65675b;
  --dim: #66685c;
  --accent: #768602;
  --accent-hover: #191d0a;
  --accent-text: #495303;
  --accent-visited: #753c03;
  --accent-soft: #e7edd6;
  --accent-line: #859249;
  --sel: #f0f4e6;
  --primary: #687603;
  --primary-hover: #495303;
  --primary-fg: #fdfefb;
  --primary-line: #687603;
  --on: #687603;
  --on-hover: #495303;
  --ring: #768602;
  --ok: #037936;
  --ok-soft: #d6f7dc;
  --warn: #8b6003;
  --warn-soft: #ffeaca;
  --crit: #b04641;
  --crit-soft: #fee7e4;
  --info: #2769b8;
  --info-soft: #e2eeff;
  --nodata: #66685c;
  --nodata-soft: #ebece7;
  --sign: #191c0c;
  --on-sign: #f9fbf2;
  --sign-edge: #191c0c;
  --sign-here: #2a2d22;
  --on-sign-here: #becd82;
  --lit-bulb: #ffe4b5;
  --accent-1: #fcfdfb;
  --accent-2: #f8faf4;
  --accent-3: #f0f4e6;
  --accent-4: #e7edd6;
  --accent-5: #dde4c6;
  --accent-6: #cfd7b4;
  --accent-7: #bdc799;
  --accent-8: #a4b173;
  --accent-9: #768602;
  --accent-10: #687603;
  --accent-11: #495303;
  --accent-12: #191d0a;
  --series-1: #8c5fd2;
  --series-2: #cc4f0c;
  --series-3: #008489;
  --series-4: #709161;
  --series-5: #51579a;
  --series-6: #016a5c;
  --series-7: #c06caa;
  --series-8: #9d412a;
  --series-text-1: #000000;
  --series-text-2: #000000;
  --series-text-3: #000000;
  --series-text-4: #191c0c;
  --series-text-5: #fdfefb;
  --series-text-6: #fdfefb;
  --series-text-7: #191c0c;
  --series-text-8: #fdfefb;
  --series-ink-1: #8558cb;
  --series-ink-2: #c24904;
  --series-ink-3: #037d82;
  --series-ink-4: #59794b;
  --series-ink-5: #51579a;
  --series-ink-6: #016a5c;
  --series-ink-7: #a55391;
  --series-ink-8: #9d412a;
  --ramp-1: #84914c;
  --ramp-2: #6e7b1f;
  --ramp-3: #596501;
  --ramp-4: #454f00;
  --ramp-5: #323a00;
  --ramp-text-1: #191c0c;
  --ramp-text-2: #fdfefb;
  --ramp-text-3: #fdfefb;
  --ramp-text-4: #fdfefb;
  --ramp-text-5: #fdfefb;
  --shadow-xs: 0 1px 2px 0 rgba(25, 28, 12, 0.05);
  --shadow-s: 0 1px 3px 0 rgba(25, 28, 12, 0.1), 0 1px 2px -1px rgba(25, 28, 12, 0.1);
  --shadow-m: 0 4px 6px -1px rgba(25, 28, 12, 0.1), 0 2px 4px -2px rgba(25, 28, 12, 0.1);
  --shadow-l: 0 10px 15px -3px rgba(25, 28, 12, 0.1), 0 4px 6px -4px rgba(25, 28, 12, 0.1);
  --ring-soft: rgba(118, 134, 2, 0.5);
  --shadow-ring: 0 0 0 var(--ring-width) rgba(118, 134, 2, 0.5);
  --shadow: var(--shadow-l);
  --scrim: rgba(25, 28, 12, 0.28);
  --img-filter: none;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) [data-family="olive"],
  :root:not([data-theme="light"])[data-family="olive"] {
    --ground: #0d0e08;
    --surface: #171812;
    --raised: #20211b;
    --sunken: #080904;
    --line: #32342d;
    --line-strong: #7a7d75;
    --text: #eeefe9;
    --muted: #b4b8ac;
    --dim: #b4b8ac;
    --accent: #768602;
    --accent-hover: #eaede1;
    --accent-text: #c9d69e;
    --accent-visited: #ffc397;
    --accent-soft: #272b17;
    --accent-line: #748237;
    --sel: #1e2114;
    --primary: #a6b84b;
    --primary-hover: #c9d69e;
    --primary-fg: #0d0e08;
    --primary-line: #a6b84b;
    --on: #a6b84b;
    --on-hover: #c9d69e;
    --ring: #c9d69e;
    --ok: #72cc87;
    --ok-soft: #15301b;
    --warn: #e6af4e;
    --warn-soft: #362508;
    --crit: #ff9e95;
    --crit-soft: #3e1e1c;
    --info: #88bcfe;
    --info-soft: #172a41;
    --nodata: #b4b8ac;
    --nodata-soft: #262724;
    --sign: #20211b;
    --on-sign: #eeefe9;
    --sign-edge: #7a7d75;
    --sign-here: #2d2f24;
    --on-sign-here: #becd82;
    --lit-bulb: #ffe4b5;
    --accent-1: #0d0e0a;
    --accent-2: #13140f;
    --accent-3: #1e2114;
    --accent-4: #272b17;
    --accent-5: #31361c;
    --accent-6: #3d4325;
    --accent-7: #505730;
    --accent-8: #687239;
    --accent-9: #768602;
    --accent-10: #a6b84b;
    --accent-11: #c9d69e;
    --accent-12: #eaede1;
    --series-1: #8c5fd2;
    --series-2: #cc4f0c;
    --series-3: #008489;
    --series-4: #abce9b;
    --series-5: #a6b0fb;
    --series-6: #59cdb7;
    --series-7: #bf6ba9;
    --series-8: #e58168;
    --series-text-1: #000000;
    --series-text-2: #000000;
    --series-text-3: #000000;
    --series-text-4: #171812;
    --series-text-5: #171812;
    --series-text-6: #171812;
    --series-text-7: #171812;
    --series-text-8: #171812;
    --series-ink-1: #c4a7fe;
    --series-ink-2: #ff9c74;
    --series-ink-3: #5fc5c9;
    --series-ink-4: #abce9b;
    --series-ink-5: #a6b1fc;
    --series-ink-6: #59cdb7;
    --series-ink-7: #f199d8;
    --series-ink-8: #ff9b82;
    --ramp-1: #778438;
    --ramp-2: #909e4c;
    --ramp-3: #aab871;
    --ramp-4: #c6d29a;
    --ramp-5: #e3ebc8;
    --ramp-text-1: #000000;
    --ramp-text-2: #171812;
    --ramp-text-3: #171812;
    --ramp-text-4: #171812;
    --ramp-text-5: #171812;
    --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
    --shadow-s: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.4);
    --shadow-m: 0 4px 6px -1px rgba(0, 0, 0, 0.45), 0 2px 4px -2px rgba(0, 0, 0, 0.45);
    --shadow-l: 0 10px 15px -3px rgba(0, 0, 0, 0.55), 0 4px 6px -4px rgba(0, 0, 0, 0.55);
    --ring-soft: rgba(201, 214, 158, 0.5);
    --shadow-ring: 0 0 0 var(--ring-width) rgba(201, 214, 158, 0.5);
    --shadow: var(--shadow-l);
    --scrim: rgba(0, 0, 0, 0.55);
    --img-filter: brightness(0.88);
  }
}
:root[data-theme="dark"] [data-family="olive"],
:root[data-theme="dark"][data-family="olive"],
[data-cap-theme="dark"] [data-family="olive"],
[data-cap-theme="dark"][data-family="olive"] {
  --ground: #0d0e08;
  --surface: #171812;
  --raised: #20211b;
  --sunken: #080904;
  --line: #32342d;
  --line-strong: #7a7d75;
  --text: #eeefe9;
  --muted: #b4b8ac;
  --dim: #b4b8ac;
  --accent: #768602;
  --accent-hover: #eaede1;
  --accent-text: #c9d69e;
  --accent-visited: #ffc397;
  --accent-soft: #272b17;
  --accent-line: #748237;
  --sel: #1e2114;
  --primary: #a6b84b;
  --primary-hover: #c9d69e;
  --primary-fg: #0d0e08;
  --primary-line: #a6b84b;
  --on: #a6b84b;
  --on-hover: #c9d69e;
  --ring: #c9d69e;
  --ok: #72cc87;
  --ok-soft: #15301b;
  --warn: #e6af4e;
  --warn-soft: #362508;
  --crit: #ff9e95;
  --crit-soft: #3e1e1c;
  --info: #88bcfe;
  --info-soft: #172a41;
  --nodata: #b4b8ac;
  --nodata-soft: #262724;
  --sign: #20211b;
  --on-sign: #eeefe9;
  --sign-edge: #7a7d75;
  --sign-here: #2d2f24;
  --on-sign-here: #becd82;
  --lit-bulb: #ffe4b5;
  --accent-1: #0d0e0a;
  --accent-2: #13140f;
  --accent-3: #1e2114;
  --accent-4: #272b17;
  --accent-5: #31361c;
  --accent-6: #3d4325;
  --accent-7: #505730;
  --accent-8: #687239;
  --accent-9: #768602;
  --accent-10: #a6b84b;
  --accent-11: #c9d69e;
  --accent-12: #eaede1;
  --series-1: #8c5fd2;
  --series-2: #cc4f0c;
  --series-3: #008489;
  --series-4: #abce9b;
  --series-5: #a6b0fb;
  --series-6: #59cdb7;
  --series-7: #bf6ba9;
  --series-8: #e58168;
  --series-text-1: #000000;
  --series-text-2: #000000;
  --series-text-3: #000000;
  --series-text-4: #171812;
  --series-text-5: #171812;
  --series-text-6: #171812;
  --series-text-7: #171812;
  --series-text-8: #171812;
  --series-ink-1: #c4a7fe;
  --series-ink-2: #ff9c74;
  --series-ink-3: #5fc5c9;
  --series-ink-4: #abce9b;
  --series-ink-5: #a6b1fc;
  --series-ink-6: #59cdb7;
  --series-ink-7: #f199d8;
  --series-ink-8: #ff9b82;
  --ramp-1: #778438;
  --ramp-2: #909e4c;
  --ramp-3: #aab871;
  --ramp-4: #c6d29a;
  --ramp-5: #e3ebc8;
  --ramp-text-1: #000000;
  --ramp-text-2: #171812;
  --ramp-text-3: #171812;
  --ramp-text-4: #171812;
  --ramp-text-5: #171812;
  --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
  --shadow-s: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.4);
  --shadow-m: 0 4px 6px -1px rgba(0, 0, 0, 0.45), 0 2px 4px -2px rgba(0, 0, 0, 0.45);
  --shadow-l: 0 10px 15px -3px rgba(0, 0, 0, 0.55), 0 4px 6px -4px rgba(0, 0, 0, 0.55);
  --ring-soft: rgba(201, 214, 158, 0.5);
  --shadow-ring: 0 0 0 var(--ring-width) rgba(201, 214, 158, 0.5);
  --shadow: var(--shadow-l);
  --scrim: rgba(0, 0, 0, 0.55);
  --img-filter: brightness(0.88);
}
/* The viewer's "increase contrast" setting: muted text, status words and links at APCA Lc 75,
   rings at Lc 60 and borders at Lc 45 (the dark mode plan, 2026-10-29). */
@media (prefers-contrast: more) {
  [data-family="olive"] {
    --line: #d8d9d1;
    --muted: #5b5c51;
    --dim: #4c4e43;
    --accent-text: #384001;
    --primary-hover: #384001;
    --on-hover: #384001;
    --ok: #005b27;
    --warn: #6b4901;
    --crit: #8f2726;
    --info: #014d9a;
    --nodata: #4c4e43;
    --on-sign-here: #cbdb8f;
    --accent-11: #384001;
    --series-ink-1: #7748ba;
    --series-ink-2: #a83e01;
    --series-ink-3: #076c71;
    --series-ink-4: #4b6a3c;
    --series-ink-7: #944481;
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) [data-family="olive"],
    :root:not([data-theme="light"])[data-family="olive"] {
      --line: #585a52;
      --line-strong: #999b93;
      --muted: #ced1c5;
      --dim: #ced1c5;
      --accent-text: #e1eeb5;
      --accent-line: #92a156;
      --primary: #c2d469;
      --primary-hover: #e1eeb5;
      --primary-line: #c2d469;
      --on: #c2d469;
      --on-hover: #e1eeb5;
      --ring: #e1eeb5;
      --ok: #8be69f;
      --warn: #ffc96f;
      --crit: #ffc4bd;
      --info: #b4d5ff;
      --nodata: #ced1c5;
      --sign-edge: #999b93;
      --on-sign-here: #ccdb8f;
      --accent-10: #c2d469;
      --accent-11: #e1eeb5;
      --series-ink-1: #d9c7fe;
      --series-ink-2: #ffc2aa;
      --series-ink-3: #7adfe3;
      --series-ink-4: #b6daa6;
      --series-ink-5: #c5cdfe;
      --series-ink-6: #70e3cc;
      --series-ink-7: #ffbbeb;
      --series-ink-8: #ffc1b1;
      --ring-soft: rgba(225, 238, 181, 0.5);
      --shadow-ring: 0 0 0 var(--ring-width) rgba(225, 238, 181, 0.5);
    }
  }
  :root[data-theme="dark"] [data-family="olive"],
  :root[data-theme="dark"][data-family="olive"],
  [data-cap-theme="dark"] [data-family="olive"],
  [data-cap-theme="dark"][data-family="olive"] {
    --line: #585a52;
    --line-strong: #999b93;
    --muted: #ced1c5;
    --dim: #ced1c5;
    --accent-text: #e1eeb5;
    --accent-line: #92a156;
    --primary: #c2d469;
    --primary-hover: #e1eeb5;
    --primary-line: #c2d469;
    --on: #c2d469;
    --on-hover: #e1eeb5;
    --ring: #e1eeb5;
    --ok: #8be69f;
    --warn: #ffc96f;
    --crit: #ffc4bd;
    --info: #b4d5ff;
    --nodata: #ced1c5;
    --sign-edge: #999b93;
    --on-sign-here: #ccdb8f;
    --accent-10: #c2d469;
    --accent-11: #e1eeb5;
    --series-ink-1: #d9c7fe;
    --series-ink-2: #ffc2aa;
    --series-ink-3: #7adfe3;
    --series-ink-4: #b6daa6;
    --series-ink-5: #c5cdfe;
    --series-ink-6: #70e3cc;
    --series-ink-7: #ffbbeb;
    --series-ink-8: #ffc1b1;
    --ring-soft: rgba(225, 238, 181, 0.5);
    --shadow-ring: 0 0 0 var(--ring-width) rgba(225, 238, 181, 0.5);
  }
}

}

/* The layer order, repeated so this file is safe whatever order an app imports it in: the first statement a browser reads fixes it (css/layers.css has the full note). */
@layer cap.reset, cap.tokens, cap.base, cap.components, cap.utilities;

/* The manual theme: the public pages of the dustinedwards.info sites set after the NASA Graphics
   Standards Manual (Danne & Blackburn, 1975). Opt-in: an app imports capsomer/manual.css only on
   its public pages; nothing else in Capsomer reads it. Every color comes from the page's family, so
   dustinedwards.info is purple and Capsid teal. Lifted from Capsid's explorer (capsid #560, #562,
   #583). Its parts, in the order a page uses them: */

/* The running head over a page: its section's number and name on the left in bold, the folio or
   date on the right, over a hairline (the manual's index, page i). The sign variant sets it as
   one of the manual's building signs (6.1): a dark panel of light type, the family's color in a
   strip along its top, the number on a plate of its own. The signs take --sign and --on-sign, so
   in dark they stay dark panels with an edge instead of turning into white slabs. */
@layer cap.components {
  .cap-running-head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--space-2) var(--space-6);
    padding-block-end: var(--space-3);
    border-block-end: 1px solid var(--text);
    font: 400 0.9375rem / 1.3 var(--ui);
  }

  .cap-running-head-name {
    display: flex;
    align-items: baseline;
    gap: 0.6em;
    font-weight: 700;
  }

  .cap-running-head-no {
    min-inline-size: 2.5ch;
  }

  .cap-running-head[data-variant="sign"] {
    padding: var(--space-3) var(--space-5) var(--space-4);
    border: 1px solid var(--sign-edge);
    border-block-start: 10px solid var(--on);
    background: var(--sign);
    color: var(--on-sign);
    font-size: clamp(1.25rem, 2.4vw, 1.75rem);

    .cap-running-head-name {
      letter-spacing: -0.01em;
    }

    .cap-running-head-no {
      min-inline-size: 1.5em;
      padding-inline: 0.2em;
      background: var(--ground);
      color: var(--text);
      text-align: center;
    }

    .cap-running-head-folio {
      font-size: 0.9375rem;
    }
  }

  @media (forced-colors: active) {
    .cap-running-head[data-variant="sign"] {
      border: 1px solid CanvasText;
    }
  }
}

/* A numbered part of a page, set as the NASA Graphics Standards Manual sets its pages (1975,
   5.1): the number and title on the left over a rule across the whole width, what the part says
   beside it, and its figures and lists full width below. */
@layer cap.components {
  .cap-part {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    column-gap: var(--space-7);
    margin-block-start: var(--space-9);
    padding-block-start: var(--space-4);
    border-block-start: 1px solid var(--text);
    container-type: inline-size;

    > * {
      grid-column: 1 / -1;
      min-inline-size: 0;
    }
  }

  .cap-part-title {
    display: flex;
    gap: var(--space-4);
    margin: 0;
    font-family: var(--display);
    font-size: clamp(1.25rem, 1.8vw, 1.625rem);
    font-weight: var(--weight-heading);
    letter-spacing: -0.01em;
    line-height: 1.15;
    text-wrap: balance;
  }

  .cap-part-no {
    flex: none;
    min-inline-size: 2.5ch;
    font-size: 0.9375rem;
    font-weight: 400;
    letter-spacing: 0;
    line-height: 1.7;
  }

  .cap-part-lead {
    margin: var(--space-3) 0 0;
    max-inline-size: 62ch;
    line-height: 1.35;
    font-size: 1.25rem;
  }

  /* Two columns once the page is wide enough: the title on the left third. */
  @media (min-width: 52rem) {
    .cap-part {
      grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    }

    .cap-part > .cap-part-title {
      grid-column: 1;
    }

    .cap-part > .cap-part-title + .cap-part-lead {
      grid-column: 2;
      margin-block-start: 0;
    }
  }
}

/* Facts as a form's ruled boxes: a small label in the mono over each value, the boxes sharing
   their rules (the manual's forms, 4.1; the Apollo flight plan's title block, MSC Form 29). Used
   for a page's title block, a post's report documentation and a row of readings. The tones
   variant steps the boxes from light to dark through one ink, as the manual sets type on stepped
   grays (7.2). */
@layer cap.components {
  .cap-form-boxes {
    --cols: 4;
    display: grid;
    grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
    margin: 0;
    border-block-start: 1px solid var(--text);
    border-inline-start: 1px solid var(--text);
    font-family: var(--ui);
    container-type: inline-size;
  }

  .cap-form-boxes-box {
    min-inline-size: 0;
    padding: 6px var(--space-4) var(--space-3);
    border-inline-end: 1px solid var(--text);
    border-block-end: 1px solid var(--text);

    > dt {
      color: var(--muted);
      font: 500 0.6875rem / 1.4 var(--mono);
      letter-spacing: 0.08em;
      text-transform: uppercase;
    }

    > dd {
      margin: 2px 0 0;
      overflow-wrap: anywhere;
    }

    &[data-span="2"] {
      grid-column: span 2;
    }

    &[data-span="all"] {
      grid-column: 1 / -1;
    }

    &[data-weight="bold"] > dd {
      font-weight: 700;
    }
  }

  /* A reading: the figure large and bold under its label. The figures of a row share one line at
     the boxes' foot, so a label that wraps to two lines never pushes its figure below the rest. */
  .cap-form-boxes:is([data-variant="readings"], [data-variant="tones"], [data-variant="panel"]) .cap-form-boxes-box {
    display: flex;
    flex-direction: column;

    > dd {
      margin-block-start: auto;
      padding-block-start: var(--space-3);
    }
  }

  .cap-form-boxes[data-variant="readings"] .cap-form-boxes-box > dd,
  .cap-form-boxes[data-variant="tones"] .cap-form-boxes-box > dd {
    font-size: clamp(1.5rem, 3vw, 2.25rem);
    font-weight: 700;
    font-variant-numeric: var(--figures);
    line-height: 1;
  }

  .cap-form-boxes[data-variant="tones"] .cap-form-boxes-box {
    /* The label takes the value's color: the muted gray does not hold 4.5:1 on the gray steps. */
    > dt {
      color: var(--text);
    }

    &:nth-child(4n + 1) {
      background: color-mix(in srgb, var(--text) 6%, var(--ground));
    }

    &:nth-child(4n + 2) {
      background: color-mix(in srgb, var(--text) 22%, var(--ground));
    }

    &:nth-child(4n + 3) {
      background: color-mix(in srgb, var(--text) 62%, var(--ground));
    }

    &:nth-child(4n + 4) {
      background: var(--text);
    }

    &:is(:nth-child(4n + 3), :nth-child(4n + 4)) > :is(dt, dd) {
      color: var(--ground);
    }
  }

  /* Readings as an instrument panel (the Apollo DSKY, study section 7b; Dustin, 2026-11-04): the dark
     sign in both themes, legends in drafting capitals as the DSKY's engraved Gorton markings, and each
     value lit in seven segments (--readout) in the family's light color, the current-page sign's
     (--on-sign-here), with a soft glow: the site's own hue, not the DSKY's green (Dustin, 2026-11-04).
     DSEG7 draws digits, minus, colon and period only: a value with letters keeps the UI face. */
  .cap-form-boxes[data-variant="panel"] {
    border-color: var(--sign-edge);
    background: var(--sign);

    .cap-form-boxes-box {
      border-color: color-mix(in srgb, var(--on-sign) 14%, var(--sign));

      > dt {
        color: var(--on-sign);
        font: 400 0.75rem / 1.4 var(--drafting);
        letter-spacing: 0.1em;
      }

      > dd {
        color: var(--on-sign-here);
        font: 400 clamp(1.5rem, 3vw, 2.25rem) / 1 var(--readout);
        text-shadow: 0 0 0.35em color-mix(in srgb, var(--on-sign-here) 55%, transparent);
      }
    }
  }

  @media (forced-colors: active) {
    .cap-form-boxes[data-variant="panel"] .cap-form-boxes-box > dd {
      text-shadow: none;
    }
  }

  @container (max-width: 36rem) {
    .cap-form-boxes-box[data-span="2"] {
      grid-column: 1 / -1;
    }
  }

  @media (max-width: 40rem) {
    .cap-form-boxes {
      --cols: 2;
    }
  }
}

/* A contents list set as the manual's index (page i): number and name in bold, a dotted leader,
   the page or the count at the right. */
@layer cap.components {
  .cap-leader-index {
    margin: 0;
    padding: 0;
    border-block-start: 1px solid var(--text);
    list-style: none;
    font-family: var(--ui);
  }

  .cap-leader-index-link {
    display: flex;
    align-items: baseline;
    gap: var(--space-4);
    min-block-size: var(--target);
    padding-block: var(--space-3);
    border-block-end: 1px solid var(--line);
    color: var(--text);
    text-decoration: none;

    &:hover .cap-leader-index-name,
    &:focus-visible .cap-leader-index-name {
      color: var(--accent-text);
    }

    &[aria-current] .cap-leader-index-name {
      color: var(--accent-text);
    }
  }

  .cap-leader-index-no {
    flex: none;
    min-inline-size: 3ch;
    font-variant-numeric: var(--figures);
  }

  /* A long name or fact wraps inside the row instead of pushing it past a narrow screen. */
  .cap-leader-index-name {
    min-inline-size: 0;
    font-weight: 700;
    overflow-wrap: anywhere;
  }

  .cap-leader-index-dots {
    flex: 1 1 2rem;
    min-inline-size: 1rem;
    border-block-end: 2px dotted var(--muted);
  }

  .cap-leader-index-fact {
    flex: 0 1 auto;
    min-inline-size: 0;
    overflow-wrap: anywhere;
    font-variant-numeric: var(--figures);
    text-align: end;
  }
}

/* A list of procedures as an Apollo checklist card: a ruled box, a dark strip naming the card,
   and per step a box to tick, its number, its name, a dotted leader to what kind of step it is,
   and a line under it. The box to tick is drawn, not a control: the card is a list of links.
   */
@layer cap.components {
  .cap-checklist {
    border: 2px solid var(--text);
    background: var(--ground);
    font-family: var(--ui);
  }

  .cap-checklist-strip {
    display: flex;
    justify-content: space-between;
    gap: var(--space-4);
    margin: 0;
    padding: var(--space-3) var(--space-5);
    background: var(--sign);
    color: var(--on-sign);
    font: 700 0.75rem / 1.4 var(--mono);
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }

  .cap-checklist-items {
    margin: 0;
    padding: var(--space-2) var(--space-5) var(--space-3);
    list-style: none;
    counter-reset: cap-step;
  }

  .cap-checklist-item {
    display: grid;
    grid-template-columns: 1.25rem 2rem minmax(0, 1fr);
    align-items: baseline;
    gap: var(--space-2) var(--space-4);
    padding-block: var(--space-4);
    border-block-end: 1px solid var(--line);
    counter-increment: cap-step;

    &:last-child {
      border-block-end: 0;
    }

    &::before {
      content: "";
      inline-size: 14px;
      block-size: 14px;
      border: 1.5px solid var(--text);
      transform: translateY(2px);
    }

    &::after {
      content: counter(cap-step, decimal-leading-zero) / "";
      grid-column: 2;
      grid-row: 1;
      color: var(--muted);
      font: 500 0.75rem var(--mono);
    }
  }

  .cap-checklist-line {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2) var(--space-4);
    grid-column: 3;
    grid-row: 1;
    min-inline-size: 0;

    > a {
      display: inline-block;
      min-block-size: 24px;
      color: var(--text);
      font-weight: 700;
      text-decoration: none;

      &:hover,
      &:focus-visible {
        color: var(--accent-text);
      }
    }
  }

  .cap-checklist-dots {
    flex: 1 1 2rem;
    min-inline-size: 1rem;
    border-block-end: 2px dotted var(--muted);
  }

  .cap-checklist-kind {
    font: 500 0.6875rem var(--mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
  }

  .cap-checklist-note {
    grid-column: 3;
    margin: 0;
    color: var(--muted);
    font-size: 0.875rem;
    line-height: 1.45;
  }

  @media (max-width: 40rem) {
    .cap-checklist-dots {
      display: none;
    }
  }
}

/* A figure as a plate: the drawing or photograph in a ruled box on the raised surface, its plate
   number in the mono at the top left, the caption under the box with the figure number at the
   right. The manual boxes every diagram (5.17), as NASA's photo plates were boxed and numbered. */
@layer cap.components {
  .cap-plate {
    margin: 0;
    min-inline-size: 0;
    font-family: var(--ui);
  }

  .cap-plate-box {
    position: relative;
    border: 1px solid var(--text);
    background: var(--raised);

    > :is(svg, img, picture, canvas) {
      display: block;
      inline-size: 100%;
      max-inline-size: 100%;
      block-size: auto;
    }
  }

  .cap-plate-no {
    position: absolute;
    inset-block-start: var(--space-4);
    inset-inline-start: var(--space-4);
    font: 700 0.75rem / 1 var(--mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .cap-plate-caption {
    display: flex;
    justify-content: space-between;
    gap: var(--space-5);
    padding-block-start: var(--space-2);
    font-size: 0.875rem;
    line-height: 1.4;

    > b {
      font-weight: 700;
    }
  }

  .cap-plate-fig {
    flex: none;
    color: var(--muted);
  }
}

/* The ways on from a page, as the manual's directional signs (6.1, 6.2): a dark panel of light
   type with an arrow, the way back pointing left and the way forward right, and the way forward
   carrying the family's color along its top. */
@layer cap.components {
  .cap-signs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
  }

  .cap-sign {
    display: inline-flex;
    align-items: center;
    gap: var(--space-4);
    max-inline-size: 100%;
    min-block-size: 48px;
    padding: var(--space-3) var(--space-5);
    border: 1px solid var(--sign-edge);
    background: var(--sign);
    color: var(--on-sign);
    /* A way on is wayfinding: the airport sign face, bold (Dustin, 2026-11-04). */
    font: 700 1rem / 1.3 var(--wayfinding);
    text-decoration: none;
    overflow-wrap: anywhere;

    /* The family arrow (css/base.css), at the sign's outer edge in the way you go. */
    &[rel~="prev"]::before,
    &[rel~="next"]::after,
    &[data-variant="forward"]::after {
      content: "";
      flex: none;
      inline-size: 1.1em;
      block-size: 1.1em;
      background: currentColor;
      clip-path: var(--cap-arrow);
    }

    &[rel~="prev"]::before {
      rotate: 180deg;
    }

    &[rel~="next"],
    &[data-variant="forward"] {
      box-shadow: inset 0 6px 0 var(--on);
    }

    /* No underline: under the pointer the arrow steps the way it goes (css/base.css), and that is
       the sign's whole answer. Where motion is reduced the panel lightens a little instead. */
    @media (prefers-reduced-motion: reduce) {
      &:hover {
        background: color-mix(in srgb, var(--sign) 86%, var(--on-sign));
      }
    }

    &:focus-visible {
      outline: 2px solid var(--ring);
      outline-offset: 2px;
    }
  }

  @media (forced-colors: active) {
    .cap-sign {
      border: 1px solid LinkText;

      &::before,
      &::after {
        forced-color-adjust: none;
        background: LinkText;
      }
    }
  }
}

/* A round patch for a project, as each Apollo crew wore its mission's: the name round the top,
   a line round the foot, the count on a disc of the family's color, a dot round the disc for
   each of the things counted. Drawn by patchSvg() (manual.ts). */
@layer cap.components {
  .cap-patch {
    display: block;
    flex: none;
    inline-size: 140px;
    block-size: 140px;
    max-inline-size: 100%;
  }

  .cap-patch-rim {
    fill: var(--text);
  }

  .cap-patch-field {
    fill: var(--ground);
    stroke: var(--on);
    stroke-width: 3;
  }

  .cap-patch-disc {
    fill: var(--on);
  }

  .cap-patch-dot {
    fill: var(--ground);
    stroke: var(--text);
    stroke-width: 1.2;
  }

  .cap-patch-name,
  .cap-patch-foot {
    fill: var(--text);
    font: 700 10px var(--mono);
    letter-spacing: 1.4px;
  }

  .cap-patch-foot {
    font-size: 9px;
    letter-spacing: 2px;
  }

  .cap-patch-count {
    fill: var(--primary-fg);
    font: 700 24px var(--display);
  }

  .cap-patch-unit {
    fill: var(--primary-fg);
    font: 700 7px var(--mono);
    letter-spacing: 1px;
  }

  .cap-patch[data-size="s"] {
    inline-size: 96px;
    block-size: 96px;
  }
}

/* The foot of a page as the manual's letterhead (3.1): the site's name as the logotype, large and
   bold, the address beside it in regular and medium, and the folio at the right. */
@layer cap.components {
  .cap-letterhead {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: end;
    gap: var(--space-5) var(--space-8);
    padding-block: var(--space-7);
    border-block-start: 4px solid var(--text);
    font-family: var(--ui);

    p {
      margin: 0;
    }
  }

  .cap-letterhead-logo {
    font: 700 clamp(2.5rem, 6vw, 4.5rem) / 0.82 var(--display);
    letter-spacing: -0.045em;
  }

  .cap-letterhead-address {
    font-size: 0.9375rem;
    line-height: 1.45;

    b {
      font-weight: 600;
    }
  }

  .cap-letterhead-folio {
    font-weight: 700;
    font-variant-numeric: var(--figures);
  }

  @media (max-width: 46rem) {
    .cap-letterhead {
      grid-template-columns: minmax(0, 1fr);
    }
  }
}

/* The head of a page drawn on the manual's layout grid (5.1), as it prints its grids in fine red
   lines: twelve columns with their gutters and a baseline every 24 pixels, four columns on a
   phone, and, where `data-labeled` is set, the grid's own label at its foot on the right. Red is the
   manual's, not the family's: the grid is the printer's, under the page, never a mark on it. */
@layer cap.components {
  .cap-layout-grid {
    --cols: 12;
    --gap: 24px;
    --grid-line: color-mix(in oklab, var(--crit) 45%, transparent);
    --grid-soft: color-mix(in oklab, var(--crit) 14%, transparent);
    --grid-fill: color-mix(in oklab, var(--crit) 4%, transparent);
    position: relative;
    isolation: isolate;
    padding-block: var(--space-3) var(--space-6);

    &::before {
      content: "";
      position: absolute;
      inset: 0;
      z-index: -1;
      background:
        repeating-linear-gradient(to bottom, transparent 0 23px, var(--grid-soft) 23px 24px),
        linear-gradient(to right, var(--grid-line) 0 1px, var(--grid-fill) 1px calc(100% - var(--gap) - 1px), var(--grid-line) calc(100% - var(--gap) - 1px) calc(100% - var(--gap)), transparent calc(100% - var(--gap))) 0 0 / calc((100% + var(--gap)) / var(--cols)) 100% repeat-x;
    }

    &[data-labeled]::after {
      content: "12 columns, 24 px baseline" / "";
      position: absolute;
      inset-block-end: 4px;
      inset-inline-end: 0;
      color: var(--crit);
      font: 500 0.625rem / 1 var(--mono);
      letter-spacing: 0.08em;
      text-transform: uppercase;
    }
  }

  @media (max-width: 40rem) {
    .cap-layout-grid {
      --cols: 4;
      --gap: 16px;

      &[data-labeled]::after {
        content: "4 columns, 24 px baseline" / "";
      }
    }
  }

  @media (forced-colors: active) {
    .cap-layout-grid::before {
      display: none;
    }
  }
}

/* The trail to a page as an airport's direction signs (Dustin, 2026-11-04): Overpass Bold, the free
   Highway Gothic that FAA airport signs are lettered in (AC 150/5345-44L, Appendix A), on a dark band,
   white FAA arrows between the ways, and the page you are on as a location sign: light type and a light
   outline on a dark gray box (a location sign is outlined; a filled one means "hold"). */
@layer cap.components {
  .cap-direction {
    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--sign-edge);
    background: var(--sign);
    color: var(--on-sign);
    font: 700 0.9375rem / 1.4 var(--wayfinding);

    > ol {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      margin: 0;
      padding: 0;
      list-style: none;
    }

    li {
      display: flex;
      align-items: center;
      min-inline-size: 0;
    }

    /* The way on: the FAA arrow (--faa-arrow, a clip path, so it is the same on every platform, takes
       the type's color, white as the legend is, and needs no image a CSP could refuse). 1em wide, its
       shaft Overpass Bold's stem. */
    li + li::before {
      content: "";
      flex: none;
      inline-size: 1em;
      block-size: 0.72em;
      margin-inline: 0.6em;
      background: currentColor;
      clip-path: var(--faa-arrow);
    }
    li + li:dir(rtl)::before, :where([dir="rtl"]) & li + li::before {
      rotate: 180deg;
    }

    a {
      display: inline-block;
      min-block-size: 24px;
      line-height: 24px;
      padding-inline: 0.25em;
      border-radius: var(--radius-s);
      color: var(--on-sign);
      /* The sign's Overpass Bold: base.css gives a text link --link-weight (600), which would set the
         ways a step lighter than the page you are on. */
      font-weight: inherit;
      text-decoration: none;
      overflow-wrap: anywhere;

      /* Every link's hover, on the dark band: a white tint behind the words. */
      &:hover {
        background: color-mix(in srgb, var(--on-sign) 18%, transparent);
      }
      &:focus-visible {
        outline: 2px solid var(--ring);
        outline-offset: 2px;
      }
    }

    /* You are here: a location sign, 2px light outline inside a 3px corner (the sign face's 1.5in
       radius on an 18in face, scaled), its type at AAA on the box (palette.mjs checks 7:1). */
    [aria-current] {
      padding: 0 0.5em;
      border-radius: var(--radius-s);
      background: var(--sign-here);
      box-shadow: inset 0 0 0 2px var(--on-sign-here);
      color: var(--on-sign-here);
      line-height: 28px;
    }
  }

  /* On a phone the sign is one line, as a breadcrumb is (components/breadcrumb): the page you
     are on leaves the line, since the heading names it, but stays for a screen reader, and a
     trail still too long scrolls sideways inside the sign rather than wrapping. */
  @media (max-width: 40rem) {
    .cap-direction {
      > ol {
        position: relative;
        flex-wrap: nowrap;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
      }
      li {
        flex: none;
        white-space: nowrap;
      }
      li:has(> [aria-current]) {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
      }
    }
  }

  @media (forced-colors: active) {
    .cap-direction {
      border: 1px solid CanvasText;

      li + li::before {
        background: CanvasText;
        forced-color-adjust: none;
      }
      /* The inset shadow is dropped in forced colors; an outline keeps the location sign's frame. */
      [aria-current] {
        outline: 2px solid CanvasText;
        outline-offset: -2px;
      }
    }
  }
}

/* The livery: an airliner's cheatline, three stripes wide to thin along the fuselage (Wikipedia,
   "Aircraft livery"), across the foot of a page. The stripes are the family's chart ramp, steps 3, 2
   and 1, so the foot of a page and its sequential charts share their tones and each site's stripes
   come out in its own color (Dustin, 2026-11-04). A card carries a short length of the band along its
   top as data-livery. */
@layer cap.components {
  .cap-livery {
    block-size: 43px;
    margin-block-start: var(--space-8);
    background: linear-gradient(
      to bottom,
      var(--ramp-3) 0 22px,
      transparent 22px 28px,
      var(--ramp-2) 28px 36px,
      transparent 36px 40px,
      var(--ramp-1) 40px
    );
  }

  [data-livery] {
    border-block-start: 6px solid var(--on);
  }
}

/* The roll blocks painted round a Saturn V, so the cameras could see how far it had turned: one
   block a step, its opposite quarters filled for a step done and lit in the family's color for the
   one you are on, a step ahead faint. Drawn, so it is hidden from screen readers and the page says
   which step it is in words. */
@layer cap.components {
  .cap-roll {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;

    > li {
      inline-size: 22px;
      block-size: 22px;
      border: 2px solid var(--text);
    }

    > [data-state="done"] {
      background: conic-gradient(var(--text) 0 25%, transparent 0 50%, var(--text) 0 75%, transparent 0);
    }

    > [data-state="now"] {
      border-color: var(--on);
      background: conic-gradient(var(--on) 0 25%, transparent 0 50%, var(--on) 0 75%, transparent 0);
    }

    > [data-state="ahead"] {
      opacity: 0.4;
    }
  }
}

/* Dated steps on the Apollo flight plan's time line: a ruled scale down the left, ticked every
   10px, each step's mark (a year, a time or a number) at its tick, the step beside it. */
@layer cap.components {
  .cap-timeline {
    margin: 0 0 0 1.25rem;
    padding: 0;
    border-inline-start: 1px solid var(--text);
    background: repeating-linear-gradient(var(--line-strong) 0 1px, transparent 1px 10px) 0 0 / 6px 100% no-repeat;
    list-style: none;
    font-family: var(--ui);

    > li {
      position: relative;
      display: grid;
      grid-template-columns: 5.5rem minmax(0, 1fr);
      gap: var(--space-2) var(--space-4);
      padding: var(--space-4) 0 var(--space-4) var(--space-6);
      border-block-end: 1px solid var(--line);

      &::before {
        content: "";
        position: absolute;
        inset-block-start: calc(var(--space-4) + 0.7em);
        inset-inline-start: 0;
        inline-size: 14px;
        border-block-start: 1px solid var(--text);
      }
    }
  }

  .cap-timeline-mark {
    font: 500 0.8125rem / 1.6 var(--mono);
    font-variant-numeric: var(--figures);
    letter-spacing: 0.04em;
  }

  .cap-timeline-body {
    min-inline-size: 0;

    > :first-child {
      margin-block-start: 0;
    }

    > :last-child {
      margin-block-end: 0;
    }
  }

  @media (max-width: 40rem) {
    .cap-timeline > li {
      grid-template-columns: minmax(0, 1fr);
    }
  }
}

/* One step as an Apollo cue card: a ruled box, a dark strip naming the procedure and the card, the
   step's title in capitals in the mono, and its lines each with a drawn box, a name in capitals, a
   dotted leader and its value. The roll blocks may sit under the strip. */
@layer cap.components {
  .cap-cue {
    padding-block-end: var(--space-4);
    border: 2px solid var(--text);
    background: var(--ground);
    font-family: var(--ui);

    > :not(.cap-cue-strip) {
      margin-inline: var(--space-4);
    }

    > .cap-roll {
      margin-block-end: var(--space-3);
    }
  }

  .cap-cue-strip {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    margin: 0 0 var(--space-3);
    padding: var(--space-2) var(--space-4);
    background: var(--sign);
    color: var(--on-sign);
    font: 700 0.75rem / 1.2 var(--mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .cap-cue-title {
    margin-block: 0 var(--space-3);
    font: var(--weight-heading) clamp(1.25rem, 2vw, 1.5rem) / 1.2 var(--mono);
    letter-spacing: 0.02em;
    text-transform: uppercase;
  }

  .cap-cue-lines {
    display: grid;
    gap: var(--space-1);
    margin-block: var(--space-3) 0;
    padding: var(--space-3) 0 0;
    border-block-start: 1px solid var(--text);
    list-style: none;
    font: 500 0.8125rem / 1.5 var(--mono);
    text-transform: uppercase;

    > li {
      display: grid;
      grid-template-columns: auto auto minmax(1rem, 1fr) minmax(0, max-content);
      align-items: baseline;
      gap: var(--space-2);
      min-block-size: 24px;

      &::before {
        content: "";
        inline-size: 12px;
        block-size: 12px;
        border: 1.5px solid var(--text);
        transform: translateY(1px);
      }

      &::after {
        content: "";
        grid-column: 3;
        grid-row: 1;
        border-block-end: 1.5px dotted var(--text);
      }
    }
  }

  .cap-cue-name {
    grid-column: 2;
    font-weight: 700;

    &:is(a) {
      display: inline-flex;
      align-items: center;
      min-block-size: var(--target);
      color: var(--text);

      &:hover,
      &:focus-visible {
        color: var(--accent-text);
      }
    }
  }

  /* A value keeps its case: a unit (µL, mL) changes meaning in capitals. */
  .cap-cue-value {
    grid-column: 4;
    grid-row: 1;
    text-align: end;
    text-transform: none;
  }

  @media (max-width: 40rem) {
    .cap-cue-lines > li {
      grid-template-columns: auto minmax(0, 1fr);

      &::after {
        display: none;
      }
    }

    .cap-cue-value {
      grid-column: 2;
      grid-row: auto;
      text-align: start;
    }
  }
}

/* The runway holding position marking (FAA AIM 2-3-5): two solid lines on the side that holds and two
   dashed lines on the side toward the runway. A divider at the end of a post, before what other sites
   said; drawn in the page's ink, with no words (Dustin, 2026-11-04). On an hr it keeps the separator's
   meaning; on any other element mark it aria-hidden. */
@layer cap.components {
  .cap-hold {
    block-size: 26px;
    inline-size: 100%;
    margin: var(--space-8) 0 var(--space-6);
    border: 0;
    background:
      linear-gradient(var(--text), var(--text)) 0 0 / 100% 3px no-repeat,
      linear-gradient(var(--text), var(--text)) 0 7px / 100% 3px no-repeat,
      repeating-linear-gradient(90deg, var(--text) 0 18px, transparent 18px 30px) 0 16px / 100% 3px no-repeat,
      repeating-linear-gradient(90deg, var(--text) 0 18px, transparent 18px 30px) 0 23px / 100% 3px no-repeat;
  }

  @media (forced-colors: active) {
    .cap-hold {
      border-block: 3px solid CanvasText;
      background: none;
      block-size: 16px;
    }
  }
}

/* An annunciator panel: a cockpit's caution and warning panel, one labeled light per system in rows
   and columns (SKYbrary, "Caution and Warning Panel"), lit amber for a caution and red for a warning
   (14 CFR 27.1322). The dark sign panel in both themes. A tile at rest is unlit and says its state;
   a lit tile takes the status color as its fill and edge and says its state too, so the state is shape,
   word and color. Legends in the drafting face where the site loads it. */
@layer cap.components {
  .cap-annunciator {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 7.5rem), 1fr));
    gap: 4px;
    margin: 0;
    padding: 6px;
    border: 1px solid var(--sign-edge);
    border-radius: var(--radius-s);
    background: var(--sign);
    list-style: none;

    > li {
      display: grid;
      place-content: center;
      gap: var(--space-1);
      min-block-size: 3.75rem;
      padding: var(--space-2);
      border-radius: 2px;
      background: color-mix(in oklab, var(--on-sign) 7%, var(--sign));
      color: var(--on-sign);
      font: 700 0.75rem / 1.15 var(--drafting, var(--mono));
      letter-spacing: 0.06em;
      text-align: center;
      text-transform: uppercase;
      overflow-wrap: anywhere;
    }

    > [data-state="caution"] {
      background: color-mix(in oklab, var(--warn) 32%, var(--sign));
      box-shadow: inset 0 0 0 2px var(--warn);
    }

    > [data-state="warning"] {
      background: color-mix(in oklab, var(--crit) 32%, var(--sign));
      box-shadow: inset 0 0 0 2px var(--crit);
    }

    > [data-state="off"] {
      background: var(--sign);
      box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--on-sign) 18%, var(--sign));
    }
  }

  .cap-annunciator-state {
    font-weight: 400;
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
  }

  @media (forced-colors: active) {
    .cap-annunciator > li {
      border: 1px solid CanvasText;
    }

    .cap-annunciator > :is([data-state="caution"], [data-state="warning"]) {
      border-width: 3px;
    }
  }
}


/* The layer order, repeated so this file is safe whatever order an app imports it in: the first statement a browser reads fixes it (css/layers.css has the full note). */
@layer cap.reset, cap.tokens, cap.base, cap.components, cap.utilities;

/* The family footer (family-footer.ts), the one footer of every dustinedwards.info site: a thin
   stripe over the site's own part and the strip of sites, then the manual theme's double stripe
   (the livery) over the letterhead (components/manual/manual.css, which a page loads with it),
   without the letterhead's heavy rule (Dustin, 2026-10-26). Both stripes are the page family's --on,
   so each site draws them in its own color; the strip marks every site in its family's color
   (tokens/family-marks.css). The two parts share one grid: a name column, then three. */
@layer cap.components {
  /* Its own type and spacing, never the page's, so it is the same to the pixel on every site: a
     site's body size (14px to 17px) and its wrapper's margins stay out of it. */
  .cap-family-footer {
    margin-block-start: var(--space-8);
    padding-block-end: var(--space-6);
    font: 400 var(--fs-body) / 1.5 var(--ui);

    --family-footer-name: minmax(0, 20rem);

    & > .cap-livery {
      margin-block: 0 var(--space-5);
    }

    & a,
    & a:visited {
      color: var(--text);
      text-decoration: none;
    }

    & a:hover,
    & a:focus-visible {
      color: var(--accent-text);
    }
    /* No tint behind any footer link on hover (Dustin, 2026-11-07): the wordmark and the social icons
       carried one while the word links and site tiles already had none. The color change is the cue. */
  }

  /* The site's own part: under the thin stripe, on the same columns as the letterhead below. */
  .cap-family-footer-local {
    padding-block-start: var(--space-6);
    border-block-start: 6px solid var(--on);
  }

  .cap-family-footer-center {
    display: grid;
    grid-template-columns: var(--family-footer-name) minmax(0, 1fr);
    gap: var(--space-5) var(--space-8);
    padding-block-end: var(--space-6);

    & p {
      margin: 0;
    }
  }

  .cap-family-footer-center-name {
    font: 700 2.25rem / 0.95 var(--display);
    letter-spacing: -0.04em;
  }

  .cap-family-footer-about {
    margin-block-start: var(--space-3) !important;
    color: var(--muted);
    font-size: 0.875rem;
  }

  /* A line of facts about the site's build, as a plate's small print. */
  .cap-family-footer-stamp {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-6);
    color: var(--muted);
    font: 500 0.6875rem / 1.6 var(--mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  /* The family's sites, each marked in its family's color; the one you are on carries a heavy top
     edge in it, so the double stripe below stays the one strong mark. */
  .cap-family-footer-sites {
    padding-block: var(--space-5) var(--space-7);
    border-block-start: 1px solid var(--line);

    /* With no site part above it, the stripe is the strip's only top edge. */
    &:first-child {
      padding-block-start: 0;
      border-block-start: 0;
    }

    & ul {
      display: grid;
      /* Six sites: two rows of three, or one row of six on a wide page, never five and one. */
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: var(--space-3);
      margin: 0;
      padding: 0;
      list-style: none;
    }

    @media (min-width: 40rem) {
      & ul {
        grid-template-columns: repeat(3, minmax(0, 1fr));
      }
    }

    @media (min-width: 72rem) {
      & ul {
        grid-template-columns: repeat(6, minmax(0, 1fr));
      }
    }

    & a {
      display: grid;
      align-content: center;
      min-block-size: var(--target);
      padding: calc(var(--space-3) + 3px) var(--space-4) var(--space-3) calc(var(--space-4) + 14px);
      border: 1px solid var(--line);
      background: linear-gradient(var(--mark), var(--mark)) var(--space-4) 50% / 6px calc(100% - 2 * var(--space-4)) no-repeat;
    }

    /* A site tile answers the pointer with its mark's outline only, no tint behind (Dustin,
       2026-11-04). */
    & a:hover {
      border-color: var(--mark);
      background-color: transparent;
    }

    & a[aria-current] {
      padding-block-start: var(--space-3);
      border-color: var(--mark);
      border-block-start-width: 4px;
    }
  }

  [data-family-mark="purple"] { --mark: var(--family-purple); }
  [data-family-mark="teal"] { --mark: var(--family-teal); }
  [data-family-mark="magenta"] { --mark: var(--family-magenta); }
  [data-family-mark="cerulean"] { --mark: var(--family-cerulean); }
  [data-family-mark="olive"] { --mark: var(--family-olive); }
  [data-family-mark="rose"] { --mark: var(--family-rose); }

  .cap-family-footer-site-name {
    font-weight: 600;
    font-size: 0.9375rem;
  }

  .cap-family-footer-site-role {
    color: var(--muted);
    font: 500 0.6875rem / 1.5 var(--mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .cap-family-footer-head {
    grid-template-columns: var(--family-footer-name) minmax(0, 1fr);
    align-items: start;
    padding-block-start: 0;
    border-block-start: 0;
  }

  .cap-family-footer-logo {
    display: flex;
    flex-direction: column;
  }

  .cap-family-footer-columns {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
  }

  @media (min-width: 48rem) {
    .cap-family-footer-columns {
      grid-template-columns: repeat(4, minmax(0, 1fr));
      column-gap: var(--space-6);
    }
  }

  @media (max-width: 46rem) {
    .cap-family-footer-head,
    .cap-family-footer-center {
      grid-template-columns: minmax(0, 1fr);
    }
  }

  .cap-family-footer-social {
    display: flex;
    gap: var(--space-4);
    margin: 0 0 var(--space-4);
    padding: 0;
    list-style: none;
  }

  .cap-family-footer-social-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: var(--target);
    min-block-size: var(--target);
  }

  /* Visually hidden until hover or focus, never display:none, so it stays the link's name. */
  .cap-family-footer-social-label {
    position: absolute;
    inset-block-start: 100%;
    inset-inline-start: 50%;
    translate: -50% var(--space-2);
    padding: 2px var(--space-3);
    border: 1px solid var(--line);
    background: var(--ground);
    color: var(--text);
    font-size: 0.75rem;
    white-space: nowrap;
    pointer-events: none;
    clip-path: inset(50%);
    opacity: 0;
  }

  /* The end icons' names open inward, so the first one's never runs off a phone's left edge. */
  .cap-family-footer-social > li:first-child .cap-family-footer-social-label {
    inset-inline-start: 0;
    translate: 0 var(--space-2);
  }
  .cap-family-footer-social > li:last-child .cap-family-footer-social-label {
    inset-inline: auto 0;
    translate: 0 var(--space-2);
  }

  .cap-family-footer-social-link:is(:hover, :focus-visible) .cap-family-footer-social-label {
    clip-path: none;
    opacity: 1;
  }

  .cap-family-footer-mark {
    display: block;
    inline-size: auto;
    block-size: 1.5rem;
  }

  .cap-family-footer-knockout {
    fill: var(--ground);
  }

  .cap-family-footer-heading {
    margin: 0 0 var(--space-3);
    color: var(--muted);
    font: 500 0.6875rem / 1.6 var(--mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .cap-family-footer-links {
    margin: 0;
    padding: 0;
    list-style: none;

    /* Footer links are wayfinding: the airport sign face (Overpass, --wayfinding) at 600 (Dustin,
       2026-11-04), hovering as every link does. The words' box is trimmed to the capitals, top to
       baseline (text-box, Baseline 2026), and padded back out to the target (with the target as a floor,
       since the trimmed box can round a hair under the capitals), so the box's middle is
       the capitals' middle and the panel lamp and arrow center on the letters. Centering the line
       box instead put the letters about 1.5px high: Overpass's ascent (0.883em) sits far above its
       capitals (0.7em) while its descent is 0.383em, so its line box's middle is 0.1em under theirs. */
    & a {
      display: inline-block;
      padding-block: calc((var(--target) - 1cap) / 2);
      min-block-size: var(--target);
      position: relative;
      font: 600 0.875rem / 1.5 var(--wayfinding);
      text-box: trim-both cap alphabetic;
    }

    /* The panel lamp hover (css/utilities.css): no tint behind. */
    & a:hover {
      background-color: transparent;
    }
  }

  /* A login: its icon, word and lock in a row, centered on the word's capitals (the word's own box
     is trimmed to them, as above), so the lamp, icon, word and lock share one middle. */
  .cap-family-footer-links .cap-family-footer-private {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    min-block-size: var(--target);
    padding-block: 0;
  }

  .cap-family-footer-label {
    text-box: trim-both cap alphabetic;
  }

  .cap-family-footer-icon {
    flex: none;
    inline-size: 1rem;
    block-size: 1rem;
  }

  /* The sign-in lock: small and muted after the label, so the name still leads. */
  .cap-family-footer-lock {
    flex: none;
    inline-size: 0.75rem;
    block-size: 0.75rem;
    color: var(--muted);
  }

  /* The copyright sits right under the name. */
  .cap-family-footer-note {
    margin: var(--space-3) 0 0;
    color: var(--muted);
    font: 500 0.6875rem / 1.6 var(--mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  /* Forced colors drop the family's color mark (a background): the current site keeps its thick
     top edge, in the system's highlight. */
  @media (forced-colors: active) {
    .cap-family-footer-sites a[aria-current] {
      border-color: Highlight;
    }
  }
}

/* The footer's outbound arrow as an FAA sign arrow (Dustin, 2026-11-04): the thick shaft and
   triangular head (--faa-arrow-out), 1.25em, turned up and right. In the utilities layer, where the
   family arrow it replaces is drawn (css/utilities.css). */
@layer cap.utilities {
  .cap-family-footer-links .cap-go[data-go="out"]::after {
    inline-size: 1.25em;
    block-size: 1.25em;
    margin-inline-start: 0.1em;
    vertical-align: -0.3em;
    clip-path: var(--faa-arrow-out);
  }
}


/* The layer order, repeated so this file is safe whatever order an app imports it in: the first statement a browser reads fixes it (css/layers.css has the full note). */
@layer cap.reset, cap.tokens, cap.base, cap.components, cap.utilities;

/* The one floating surface. `.cap-popover` is the look (background, ring, shadow, radius,
   padding, open and close motion, arrow, the inverted tooltip form). It depends on no
   behavior, so Base UI's combobox, menu and select popups wear it too: they position
   themselves and set data-side, data-starting-style and data-ending-style, which this file
   reads. On a native popover (`popover` attribute) it also places itself, by CSS anchor
   positioning where the browser has it, otherwise at the numbers popover.ts sets through the
   CSSOM (--cap-popover-x, --cap-popover-y). Reference: shadcn Popover, Tooltip, Hover Card. */
@layer cap.components {
  [data-cap="popover"] {
    display: contents;
  }

  /* Shown as a flex column only while open: a display on a closed native popover would
     show it (Base UI's popups have no popover attribute and are always laid out). */
  .cap-popover:where(:not([popover]), :popover-open) {
    display: flex;
  }
  .cap-popover[data-variant="tooltip"]:where(:not([popover]), :popover-open) {
    display: inline-flex;
  }
  .cap-popover {
    --_side: bottom;
    --_tx: 0px;
    --_ty: 0px;
    --_arrow: 0px;
    --_line: var(--line);
    box-sizing: border-box;
    flex-direction: column;
    gap: var(--space-3);
    max-inline-size: calc(100vw - 16px);
    margin: 0;
    padding: var(--pad-card);
    border: 0;
    border-radius: var(--radius-l);
    background: var(--raised);
    color: var(--text);
    /* The ring is a hairline (decorative); the shadow lifts it. */
    box-shadow:
      0 0 0 1px var(--line),
      var(--shadow-m);
    font-size: var(--fs-body);
    line-height: 1.4;
    text-align: start;
    overflow: visible;
    transform-origin: var(--transform-origin, var(--_origin, center));

    /* Focus moves onto the surface itself when it holds nothing to focus; it is not a
       control, so it takes no ring (shadcn does the same). */
    &:focus {
      outline: none;
    }

    /* Width: a native popover or an explicit size gets shadcn's w-72; a Base UI popup that
       sets no size keeps the width its own CSS gives it. */
    &:where([popover], [data-size]) {
      inline-size: 18rem;
    }
    &[data-size="sm"] {
      inline-size: 14rem;
    }
    &[data-size="lg"] {
      inline-size: 24rem;
    }
    &[data-size="auto"] {
      inline-size: fit-content;
    }

    /* A list popup (menu, select, combobox) pads its own items. */
    &[data-flush] {
      padding: 0;
      gap: 0;
    }
  }

  /* The side the surface really sits on: Base UI writes it as data-side; our module writes
     data-placed (after any flip), which wins over the side an author asked for. It only
     steers the motion (slide in from the trigger's side) and the arrow. */
  .cap-popover:is([data-side="bottom"]:not([data-placed]), [data-placed="bottom"]) {
    --_ty: -4px;
    --_origin: top;
  }
  .cap-popover:is([data-side="top"]:not([data-placed]), [data-placed="top"]) {
    --_ty: 4px;
    --_origin: bottom;
  }
  .cap-popover:is([data-side="left"]:not([data-placed]), [data-side="inline-start"]:not([data-placed]), [data-placed="left"]) {
    --_tx: 4px;
    --_origin: right;
  }
  .cap-popover:is([data-side="right"]:not([data-placed]), [data-side="inline-end"]:not([data-placed]), [data-placed="right"]) {
    --_tx: -4px;
    --_origin: left;
  }

  .cap-popover-header {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
  }
  .cap-popover-title {
    margin: 0;
    font-size: inherit;
    font-weight: 600;
    color: var(--text);
  }
  .cap-popover-description {
    margin: 0;
    color: var(--muted);
  }

  /* The arrow: a square turned 45 degrees, half hidden behind the surface. Its two outer
     edges carry the ring. popover.ts sets --cap-arrow-x / --cap-arrow-y so it points at
     the trigger's center; Base UI's Arrow sets left/top itself. */
  .cap-popover-arrow {
    position: absolute;
    inline-size: 8px;
    block-size: 8px;
    background: inherit;
    border: 1px solid transparent;
    border-radius: 1px;
    rotate: 45deg;
    pointer-events: none;
  }
  .cap-popover:is([data-side="bottom"]:not([data-placed]), [data-placed="bottom"]) > .cap-popover-arrow {
    top: -5px;
    left: var(--cap-arrow-x, 50%);
    translate: -50% 0;
    border-color: var(--_line) transparent transparent var(--_line);
  }
  .cap-popover:is([data-side="top"]:not([data-placed]), [data-placed="top"]) > .cap-popover-arrow {
    bottom: -5px;
    left: var(--cap-arrow-x, 50%);
    translate: -50% 0;
    border-color: transparent var(--_line) var(--_line) transparent;
  }
  .cap-popover:is([data-side="left"]:not([data-placed]), [data-side="inline-start"]:not([data-placed]), [data-placed="left"]) > .cap-popover-arrow {
    right: -5px;
    top: var(--cap-arrow-y, 50%);
    translate: 0 -50%;
    border-color: var(--_line) var(--_line) transparent transparent;
  }
  .cap-popover:is([data-side="right"]:not([data-placed]), [data-side="inline-end"]:not([data-placed]), [data-placed="right"]) > .cap-popover-arrow {
    left: -5px;
    top: var(--cap-arrow-y, 50%);
    translate: 0 -50%;
    border-color: transparent transparent var(--_line) var(--_line);
  }
  .cap-popover:has(> .cap-popover-arrow) {
    --_arrow: 4px;
  }

  /* The tooltip form: a small raised surface with a visible edge in both themes, so it never
     reads as a selected item (the admin menu's current page is a dark fill in light and a light
     fill in dark; a tooltip is neither). No padding of a card. Keys are key caps. One look for
     every tooltip in Capsomer, the admin shell's included. */
  .cap-popover[data-variant="tooltip"] {
    --_line: var(--line-strong);
    flex-direction: row;
    align-items: center;
    gap: var(--space-3);
    inline-size: fit-content;
    max-inline-size: min(20rem, calc(100vw - 16px));
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-m);
    background: var(--raised);
    color: var(--text);
    box-shadow:
      0 0 0 1px var(--_line),
      var(--shadow-m);
    font-size: var(--fs-detail);
    font-weight: 500;
    white-space: nowrap;

    &:has(kbd) {
      padding-inline-end: var(--space-3);
    }
    & .cap-keys {
      display: inline-flex;
      gap: var(--space-1);
    }
    & kbd {
      display: inline-grid;
      place-items: center;
      min-inline-size: 1.6em;
      padding: 0 var(--space-2);
      border: 1px solid var(--line-strong);
      border-block-end-width: 2px;
      border-radius: var(--radius-s);
      background: var(--surface);
      color: var(--text);
      font: 600 var(--fs-label) / 1.5 var(--ui);
    }
  }

  /* A native popover places itself. The default: below its trigger, centered. */
  .cap-popover[popover] {
    position: fixed;
    inset: auto;
    top: var(--cap-popover-y, 0px);
    left: var(--cap-popover-x, 0px);
    max-block-size: calc(100dvh - 16px);

    &[data-placed-by="pending"] {
      visibility: hidden;
    }
  }

  /* Anchor positioning: popover.ts names the trigger and the popup (CSSOM). The side and
     the alignment pick the position-area; flip-block and flip-inline do the collision
     flip; the offset is a margin on the side facing the trigger. */
  @supports (position-area: bottom) {
    .cap-popover[popover]:not([data-placed-by="js"], [data-placed-by="pending"]) {
      --_ax: ;
      --_ay: ;
      --_al: ;
      --_off: calc(var(--cap-offset, 4px) + var(--_arrow));
      top: auto;
      left: auto;
      position-area: block-end var(--_ax);
      position-try-fallbacks: flip-block, flip-inline;
      margin-block-start: var(--_off);

      &[data-align="start"] {
        --_ax: span-inline-end;
        --_ay: span-bottom;
        --_al: span-block-end;
      }
      &[data-align="end"] {
        --_ax: span-inline-start;
        --_ay: span-top;
        --_al: span-block-start;
      }
      &[data-variant="tooltip"]:not([data-side]),
      &[data-side="top"] {
        position-area: block-start var(--_ax);
        margin-block: 0 var(--_off);
      }
      &[data-side="left"] {
        position-area: left var(--_ay);
        margin-block: 0;
        margin-inline: 0 var(--_off);
      }
      &[data-side="right"] {
        position-area: right var(--_ay);
        margin-block: 0;
        margin-inline: var(--_off) 0;
      }
      &[data-side="inline-start"] {
        position-area: inline-start var(--_al);
        margin-block: 0;
        margin-inline: 0 var(--_off);
      }
      &[data-side="inline-end"] {
        position-area: inline-end var(--_al);
        margin-block: 0;
        margin-inline: var(--_off) 0;
      }
    }
  }

  /* Open and close. Opening, it fades in 100 ms while it grows from 96% and slides 4 px out of
     the trigger's side over 200 ms on the long ease-out; closing is quicker and shorter, 100 ms to
     98% and half the slide, so it gets out of the way (Radix Themes and Arc: what leaves goes
     faster than it came). Transitions, not keyframes, so a close during the open reverses from
     where it is. A native popover animates through @starting-style and allow-discrete (display
     and overlay); Base UI's popups through data-starting-style and data-ending-style. A tooltip
     keeps 100 ms both ways: the next one opens at once anyway. */
  @media (prefers-reduced-motion: no-preference) {
    .cap-popover {
      --_in: var(--dur-base);
      transition:
        opacity var(--dur-fast) var(--ease-out),
        scale var(--dur-fast) var(--ease-out),
        translate var(--dur-fast) var(--ease-out),
        display var(--dur-fast) allow-discrete,
        overlay var(--dur-fast) allow-discrete;

      &[data-variant="tooltip"] {
        --_in: var(--dur-fast);
      }
      &[popover]:not(:popover-open),
      &[data-ending-style] {
        opacity: 0;
        scale: 0.98;
        translate: calc(var(--_tx) / 2) calc(var(--_ty) / 2);
      }
      &[data-starting-style] {
        opacity: 0;
        scale: 0.96;
        translate: var(--_tx) var(--_ty);
      }
      &:is([popover]:popover-open, :not([popover], [data-ending-style])) {
        transition-duration: var(--dur-fast), var(--_in), var(--_in), var(--dur-fast), var(--dur-fast);
      }
      &[popover]:popover-open {
        opacity: 1;
        scale: 1;
        translate: 0 0;

        @starting-style {
          opacity: 0;
          scale: 0.96;
          translate: var(--_tx) var(--_ty);
        }
      }
    }
  }

  /* Forced colors drop shadows and fills: the surface keeps an edge, the arrow its lines. */
  @media (forced-colors: active) {
    .cap-popover {
      border: 1px solid CanvasText;
      background: Canvas;
      color: CanvasText;
    }
    .cap-popover-arrow {
      display: none;
    }
  }
}


/* The layer order, repeated so this file is safe whatever order an app imports it in: the first statement a browser reads fixes it (css/layers.css has the full note). */
@layer cap.reset, cap.tokens, cap.base, cap.components, cap.utilities;

/* The theme switch: Light and Dark as a segmented pair with a sun and a moon, rebuilt from
   shadcn/ui's Toggle Group (outline variant, spacing 0: items flush in one rounded box, the
   chosen one filled) and its Mode Toggle's sun and moon. The inputs are real radios laid over
   each segment, so arrows, Space and forms are the browser's. It sits in the top bar, on the
   ground tone, where --line-strong is 2.9:1, so the control's edge is --dim (5:1 on it in
   both themes). The chosen segment has one marker, a fill: the same dark fill as the admin
   menu's selected page (--accent-12, its word in --ground, set heavier), at well over 3:1
   against the ground, so it needs no second mark. */
@layer cap.components {
  .cap-theme {
    flex: none;
    min-inline-size: 0;
    margin: 0;
    padding: 0;
    border: 0;
  }

  .cap-theme-options {
    display: inline-flex;
    overflow: hidden;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-m);
    background: transparent;

    & > label {
      position: relative;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: var(--space-3);
      min-height: max(var(--target), calc(var(--control) - 2px));
      min-width: max(var(--target), calc(var(--control) - 2px));
      padding-inline: var(--pad-x);
      color: var(--muted);
      font-size: var(--fs-body);
      font-weight: 500;
      white-space: nowrap;
      cursor: pointer;

      /* Items are flush; a hairline sets the second apart from the first. */
      & + label {
        border-inline-start: 1px solid var(--line);
      }
      &:hover,
      &[data-force="hover"] {
        background: var(--sunken);
        color: var(--text);
      }
      &:has(input:checked) {
        background: var(--accent-12);
        color: var(--ground);
        font-weight: 600;
      }
      /* Inside the box, so the box's edge does not clip it. */
      &:has(input:focus-visible) {
        outline: var(--focus-width) solid var(--ring);
        outline-offset: -2px;
      }
      &:has(input:disabled) {
        background: none;
        color: var(--dim);
        cursor: not-allowed;
      }
    }

    /* The radio covers its segment, unseen, so a click anywhere on it chooses it. */
    & input {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      margin: 0;
      opacity: 0;
      cursor: inherit;
    }
  }

  .cap-theme-icon {
    flex: none;
    width: 16px;
    height: 16px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  /* The button form (data-variant="button"): one icon button that switches to the other theme,
     the site header's control. A 36px target with an 18px glyph, like every header control. It
     shows a moon while the page is light and a sun while it is dark (both are in the markup, so the
     picture is right before any script runs); its name says what a press does. */
  .cap-theme-button {
    position: relative;
    display: inline-grid;
    place-items: center;
    flex: none;
    width: 36px;
    height: 36px;
    padding: 0;
    border: var(--icon-border) solid var(--line);
    border-radius: var(--icon-radius);
    background: none;
    color: var(--muted);
    cursor: pointer;

    &:hover,
    &[data-force="hover"] {
      background: var(--sunken);
      color: var(--text);
      rotate: var(--theme-turn);
    }
    &:focus-visible {
      outline: var(--focus-width) solid var(--ring);
      outline-offset: var(--focus-offset);
    }
    & .cap-theme-icon {
      width: 18px;
      height: 18px;
      stroke-width: 1.6;
    }
    & [data-show="dark"] {
      display: none;
    }
  }
  :root[data-theme="dark"] .cap-theme-button {
    & [data-show="light"] {
      display: none;
    }
    & [data-show="dark"] {
      display: block;
    }
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .cap-theme-button {
      & [data-show="light"] {
        display: none;
      }
      & [data-show="dark"] {
        display: block;
      }
    }
  }

  /* The form (data-variant="form"): the button form as two submit buttons, for a site that keeps
     the choice in a cookie and works with no script. CSS shows the one that switches away from the
     theme showing, before any script runs. */
  .cap-theme-form {
    display: inline-flex;
    align-items: center;
    margin: 0;
  }
  .cap-theme-form > .cap-theme-button[data-show="dark"] {
    display: none;
  }
  :root[data-theme="dark"] .cap-theme-form > .cap-theme-button {
    &[data-show="light"] {
      display: none;
    }
    &[data-show="dark"] {
      display: inline-grid;
    }
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .cap-theme-form > .cap-theme-button {
      &[data-show="light"] {
        display: none;
      }
      &[data-show="dark"] {
        display: inline-grid;
      }
    }
  }

  /* On a phone the top bar has no room for the words: the icons stay, and the words stay for a
     screen reader. */
  @media (max-width: 820px) {
    .cap-theme-text {
      position: absolute;
      width: 1px;
      height: 1px;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
    }
    .cap-theme-options > label {
      min-width: var(--target);
      padding-inline: var(--space-3);
    }
  }

  @media (prefers-reduced-motion: no-preference) {
    .cap-theme-options > label,
    .cap-theme-button {
      transition:
        background-color var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out),
        rotate var(--dur-slow) var(--ease-out);
    }
  }

  @media (forced-colors: active) {
    .cap-theme-options {
      border-color: CanvasText;
    }
    .cap-theme-options > label:has(input:checked) {
      forced-color-adjust: none;
      background: Highlight;
      color: HighlightText;
    }
    .cap-theme-options > label:has(input:disabled) {
      color: GrayText;
    }
  }
}


/* The layer order, repeated so this file is safe whatever order an app imports it in: the first statement a browser reads fixes it (css/layers.css has the full note). */
@layer cap.reset, cap.tokens, cap.base, cap.components, cap.utilities;

/* The site header: one header across the top of every public, app and admin page in the family
   (docs/design/design-site-header.md; Dustin's ten answers of 2026-10-13). Capsomer fixes the
   frame: the order, 56px tall at every width, sticky, full width with the logo 24px from the
   window's edge (16px on a phone), the spacing, the type, the controls and how the panels behave.
   Each site fills its slots: the logo, its color family, the band (--header-bg, --header-fg,
   --header-fg-muted, --header-line; data-band="dark", data-translucent), its UI face (--font-ui),
   up to two icon extras and one button, where the section links sit (data-links) and what each
   panel holds. On a phone (under 768px) it is one row, with everything else in one sheet. */
@layer cap.components {
  .cap-site-header {
    /* The band: the page's own ground by default. A site sets these four, or data-band="dark". */
    --header-bg: var(--ground);
    --header-fg: var(--text);
    --header-fg-muted: var(--muted);
    --header-line: var(--line);
    /* A hovered control: a clear step off the band, in the band's own colors. */
    --header-hover: color-mix(in srgb, var(--header-bg), var(--header-fg) 12%);
    /* The current link's underline (3:1 against the band), the one button, the avatar. */
    --header-accent: var(--accent);
    --header-cta: var(--primary);
    --header-cta-fg: var(--primary-fg);
    --header-avatar: var(--accent-12);
    --header-avatar-fg: var(--ground);
    --header-fs: 14px;
    --header-side: var(--space-6);
    position: sticky;
    top: 0;
    z-index: calc(var(--z-sticky) + 3);
    display: flex;
    align-items: center;
    box-sizing: border-box;
    inline-size: 100%;
    block-size: var(--header-h);
    padding-inline: var(--header-side);
    background: var(--header-bg);
    color: var(--header-fg);
    border-block-end: 1px solid var(--header-line);
    font-family: var(--font-ui, var(--ui));
    font-size: var(--header-fs);
    line-height: 1.3;

    &[data-sticky="false"] {
      position: relative;
    }
    /* The page's ground at 85%, blurred: the content shows through as it scrolls under. */
    &[data-translucent] {
      background: color-mix(in srgb, var(--header-bg) 85%, transparent);
      backdrop-filter: blur(12px);
    }
    & :focus-visible {
      outline: var(--focus-width) solid var(--ring);
      outline-offset: var(--focus-offset);
    }
  }

  /* Dark in both themes (Foxhound): the darkest step of the site's family in light, the dark
     theme's own surface in dark. The controls on it read in the band's colors. */
  .cap-site-header[data-band="dark"] {
    color-scheme: dark;
    --header-bg: var(--accent-12);
    --header-fg: var(--accent-1);
    --header-fg-muted: color-mix(in srgb, var(--accent-1) 74%, var(--accent-12));
    --header-line: color-mix(in srgb, var(--accent-1) 18%, var(--accent-12));
    --header-avatar: var(--primary);
    --header-avatar-fg: var(--primary-fg);
  }
  :root[data-theme="dark"] .cap-site-header[data-band="dark"] {
    --header-bg: var(--surface);
    --header-fg: var(--text);
    --header-fg-muted: var(--muted);
    --header-line: var(--line);
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .cap-site-header[data-band="dark"] {
      --header-bg: var(--surface);
      --header-fg: var(--text);
      --header-fg-muted: var(--muted);
      --header-line: var(--line);
    }
  }

  /* A focused control or an anchor never lands under the header (WCAG 2.4.11). */
  :root:has(.cap-site-header:not([data-sticky="false"])) {
    scroll-padding-top: calc(var(--header-h) + var(--space-3));
  }

  /* The logo: the site's mark and name, at most 24px tall and 160px wide; it links home. */
  .cap-site-header-logo {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    /* It gives way before the controls do, so the header never runs past a 320px window
       (WCAG 1.4.10, reflow); the mark itself never shrinks, and is the part held to 160px, so
       a written name keeps its room under a reader's own text spacing (WCAG 1.4.12). */
    flex: 0 1 auto;
    min-inline-size: 0;
    min-block-size: 24px;
    overflow: hidden;
    border-radius: var(--radius-s);
    color: var(--header-fg);
    text-decoration: none;
    white-space: nowrap;

    & :is(svg, img) {
      flex: none;
      block-size: 24px;
      inline-size: auto;
      max-inline-size: 160px;
    }
  }

  /* The switcher: buttons showing where you are, each opening the site's panel. 12px after the
     logo; a thin slash between two (Foxhound: the business, then the product). */
  .cap-site-header-switcher {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-inline-start: var(--space-4);
    min-inline-size: 0;
  }
  .cap-site-header-sep {
    color: var(--header-fg-muted);
    font-size: 18px;
  }
  .cap-site-header-switch {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    block-size: 32px;
    padding: 0 10px;
    border: 1px solid var(--header-line);
    border-radius: var(--radius-m);
    background: none;
    color: var(--header-fg);
    font: inherit;
    white-space: nowrap;
    cursor: pointer;

    &:hover,
    &[aria-expanded="true"],
    &[data-force="hover"] {
      background: var(--header-hover);
    }
    & > svg {
      flex: none;
      inline-size: 16px;
      block-size: 16px;
    }
  }
  /* A square is the business you are in, a circle is you (Dustin's answer 3). */
  .cap-site-header-switch-tile {
    display: grid;
    place-items: center;
    flex: none;
    inline-size: 22px;
    block-size: 22px;
    border-radius: var(--radius-m);
    background: var(--header-cta);
    color: var(--header-cta-fg);
    font-size: 11px;
    font-weight: 600;

    /* The letter is drawn, not text: the button is named by the business, and a letter in the
       HTML would be read as part of its visible label (WCAG 2.5.3). */
    &::before {
      content: attr(data-tile);
    }
  }
  .cap-site-header-chev {
    flex: none;
    inline-size: 12px;
    block-size: 12px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  /* An open panel turns its chevron up, as the combobox's does (combobox.css): the button's
     aria-expanded, which wirePanel keeps in step with the panel, is the one state it reads. */
  [aria-expanded="true"] > .cap-site-header-chev {
    rotate: 180deg;
  }

  /* The section links: 24px after the switcher (left), centered in the header, or on the right
     before the extras after a thin divider; 20px apart. The current page is weight 500 with a 2px
     underline in the accent, so it is not told by color alone. */
  .cap-site-header-sections {
    margin-inline-start: var(--space-6);
    min-inline-size: 0;

    & > ul {
      display: flex;
      align-items: center;
      gap: 20px;
      margin: 0;
      padding: 0;
      list-style: none;
    }
  }
  .cap-site-header[data-links="center"] .cap-site-header-sections {
    position: absolute;
    left: 50%;
    margin: 0;
    translate: -50% 0;
  }
  .cap-site-header[data-links="right"] .cap-site-header-sections {
    margin-inline-start: auto;
  }
  .cap-site-header-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-block-size: max(36px, var(--target));
    padding: 0;
    border: 0;
    border-radius: var(--radius-s);
    background: none;
    color: var(--header-fg-muted);
    font: inherit;
    font-weight: 400;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;

    &:hover,
    &[aria-expanded="true"],
    &[data-force="hover"] {
      color: var(--header-fg);
    }
    /* A site's --link-rule (off by default) grows an underline in under the pointer. */
    &:not([aria-current="page"], [data-current])::after {
      content: "";
      position: absolute;
      inset-inline-start: 0;
      bottom: 4px;
      inline-size: 0;
      block-size: var(--link-rule);
      background: var(--header-accent);
    }
    &:not([aria-current="page"], [data-current]):is(:hover, :focus-visible)::after {
      inline-size: 100%;
    }
    &[aria-current="page"],
    &[data-current] {
      color: var(--header-fg);
      font-weight: 500;

      &::after {
        content: "";
        position: absolute;
        inset-inline: 0;
        bottom: 4px;
        block-size: 2px;
        background: var(--header-accent);
      }
    }
  }

  /* The right side: the site's extras, the theme, the account (always last), 8px apart. After
     section links on the right, a thin divider. */
  .cap-site-header-tools {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-inline-start: auto;
  }
  .cap-site-header[data-links="right"] .cap-site-header-sections + .cap-site-header-tools {
    margin-inline-start: var(--space-4);

    &::before {
      content: "";
      inline-size: 1px;
      block-size: 16px;
      margin-inline-end: var(--space-2);
      background: var(--header-line);
    }
  }
  .cap-site-header-extras {
    display: flex;
    align-items: center;
    gap: var(--space-3);
  }

  /* Every icon control: a 36px target, an 18px glyph from the family's icon set (24 box, 1.6
     stroke), a name and a tip naming it and its key. The theme button wears this too. */
  .cap-site-header .cap-site-header-icon {
    position: relative;
    display: inline-grid;
    place-items: center;
    flex: none;
    inline-size: 36px;
    block-size: 36px;
    padding: 0;
    border: var(--icon-border) solid var(--header-line);
    border-radius: var(--icon-radius);
    background: none;
    color: var(--header-fg-muted);
    font: inherit;
    text-decoration: none;
    cursor: pointer;

    &:hover,
    &[aria-expanded="true"],
    &[data-force="hover"] {
      background: var(--header-hover);
      color: var(--header-fg);
    }
    & > svg {
      inline-size: 18px;
      block-size: 18px;
      fill: none;
      stroke: currentColor;
      stroke-width: 1.6;
      stroke-linecap: round;
      stroke-linejoin: round;
    }
  }

  /* A count on an icon: one bubble, as in the admin shell (16px, 10px figures, 99+ past 99), its
     left edge 2px past the glyph and its middle on the glyph's top edge, ringed in the band. */
  .cap-site-header-badge {
    --_bubble: 16px;
    position: absolute;
    top: calc(50% - 9px - var(--_bubble) / 2);
    inset-inline-start: calc(50% + 9px + 2px);
    display: inline-grid;
    place-items: center;
    box-sizing: border-box;
    min-inline-size: var(--_bubble);
    block-size: var(--_bubble);
    padding-inline: 3px;
    border-radius: var(--radius-full);
    background: var(--primary);
    color: var(--primary-fg);
    box-shadow: 0 0 0 2px var(--header-bg);
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: var(--figures);
    white-space: nowrap;
  }

  /* The one button extra (Free audit, Join free). */
  .cap-site-header-cta {
    display: inline-flex;
    align-items: center;
    block-size: 32px;
    padding: 0 14px;
    border: 0;
    border-radius: var(--radius-m);
    background: var(--header-cta);
    color: var(--header-cta-fg);
    font: inherit;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;

    &:hover,
    &[data-force="hover"] {
      background: color-mix(in srgb, var(--header-cta), var(--header-cta-fg) 12%);
    }
  }

  /* The account: last on every site. Signed out, Sign in holds its place. */
  .cap-site-header-account {
    display: flex;
    align-items: center;
  }
  .cap-site-header .cap-site-header-avatar {
    border-radius: var(--radius-full);

    /* The initials are drawn, not text, for the same reason as the business tile's letter: the
       button is named "Your account". A picture, when the site gives one, covers them. */
    & > .cap-site-header-initials {
      position: relative;
      display: grid;
      place-items: center;
      inline-size: 32px;
      block-size: 32px;
      border-radius: var(--radius-full);
      background: var(--header-avatar);
      color: var(--header-avatar-fg);
      font-size: 12px;
      font-weight: 600;
      letter-spacing: 0.02em;
    }
    & > .cap-site-header-initials::before {
      content: attr(data-initials);
    }
    & .cap-site-header-avatar-image {
      position: absolute;
      inset: 0;
      inline-size: 100%;
      block-size: 100%;
      border-radius: inherit;
      object-fit: cover;
    }
    &:hover > .cap-site-header-initials {
      opacity: 0.88;
    }
  }
  .cap-site-header-signin {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-block-size: 36px;
    padding: 0 var(--space-2);
    border-radius: var(--radius-m);
    color: var(--header-fg);
    text-decoration: none;
    white-space: nowrap;

    &:hover {
      background: var(--header-hover);
    }
    & > svg {
      display: none;
      inline-size: 18px;
      block-size: 18px;
      fill: none;
      stroke: currentColor;
      stroke-width: 1.6;
      stroke-linecap: round;
      stroke-linejoin: round;
    }
  }

  /* The phone's menu button: hidden on a desktop. */
  .cap-site-header .cap-site-header-menu {
    display: none;
  }

  /* A panel: the site's contents under its button, in the top layer, lined up with the button's
     edge and starting under the header's bottom edge, so it never covers the header. */
  .cap-site-header-panel {
    position: fixed;
    inset: auto;
    top: var(--cap-popover-y, 0px);
    left: var(--cap-popover-x, 0px);
    box-sizing: border-box;
    min-inline-size: 220px;
    max-inline-size: calc(100vw - 2 * var(--space-3));
    max-block-size: calc(100dvh - var(--header-h) - var(--space-5));
    margin: 0;
    padding: var(--space-2);
    overflow: auto;
    border: 1px solid var(--line);
    border-radius: var(--radius-l);
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-l);
    font-family: var(--font-ui, var(--ui));
    font-size: var(--header-fs, 14px);
    line-height: 1.35;
  }
  /* The default contents: who you are, labeled groups of links, Sign out last. */
  .cap-site-header-panel-list {
    display: grid;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;

    & :is(a, button) {
      display: flex;
      align-items: center;
      gap: var(--space-4);
      inline-size: 100%;
      min-block-size: max(var(--control), var(--target));
      padding: 0 var(--space-4);
      border: 0;
      border-radius: var(--radius-m);
      background: none;
      color: var(--text);
      font: inherit;
      text-align: start;
      text-decoration: none;
      cursor: pointer;

      &:hover,
      &:focus-visible {
        background: var(--sunken);
      }
      &[aria-current] {
        background: var(--sunken);
        font-weight: 600;
      }
      &:focus-visible {
        outline: var(--focus-width) solid var(--ring);
        outline-offset: -2px;
      }
    }
  }
  .cap-site-header-panel-label {
    padding: var(--space-3) var(--space-4) var(--space-2);
    color: var(--muted);
    font-size: var(--fs-detail);
    font-weight: 500;
  }
  .cap-site-header-panel hr {
    margin: var(--space-2) var(--space-2);
    border: 0;
    border-block-start: 1px solid var(--line);
  }
  .cap-site-header-who {
    display: grid;
    gap: var(--space-1);
    padding: var(--space-3) var(--space-4) var(--space-3);

    & small {
      color: var(--muted);
      font-size: var(--fs-detail);
      overflow-wrap: anywhere;
    }
  }
  .cap-site-header-mark {
    display: grid;
    place-items: center;
    flex: none;
    inline-size: 20px;
    block-size: 20px;
    color: var(--accent-text);

    & svg {
      inline-size: 18px;
      block-size: 18px;
    }
  }
  .cap-site-header-count {
    margin-inline-start: auto;
    min-inline-size: 16px;
    block-size: 16px;
    padding-inline: 3px;
    border-radius: var(--radius-full);
    background: var(--primary);
    color: var(--primary-fg);
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    font-variant-numeric: var(--figures);
  }

  /* The phone's sheet: the shared dialog from the bottom, holding everything the top row does not:
     the site's own rows first (the family's apps in your admin), the switchers, the section links
     grouped as the desktop menus group them, the button extra full width; the account rows are
     pinned under the list so Sign out is always in view. */
  .cap-site-header-sheet > .cap-dialog-body {
    padding: var(--space-3);
    padding-block-end: var(--space-5);
  }
  .cap-site-header-sheet .cap-site-header-sheet-title {
    font-size: var(--fs-lead);

    /* Focus starts here when the sheet opens, so a screen reader begins at its name; it is not
       a control, so it shows no ring. */
    &:focus {
      outline: none;
    }
  }
  .cap-site-header-sheet-label {
    padding: var(--space-4) var(--space-4) var(--space-2);
    color: var(--muted);
    font-size: var(--fs-detail);
    font-weight: 500;
  }
  .cap-site-header-sheet .cap-site-header-sheet-list {
    display: grid;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;

    & :is(a, button) {
      display: flex;
      align-items: center;
      gap: var(--space-4);
      inline-size: 100%;
      min-block-size: max(var(--control), var(--target));
      padding: 0 var(--space-4);
      border: 0;
      border-radius: var(--radius-m);
      background: none;
      color: var(--text);
      font: inherit;
      font-size: var(--fs-body);
      text-align: start;
      text-decoration: none;

      &:hover {
        background: var(--sunken);
      }
      &[aria-current="page"],
      &[aria-current="true"] {
        background: var(--accent-12);
        color: var(--ground);
        font-weight: 600;
      }
    }
    & .cap-site-header-count {
      margin-inline-start: auto;
    }
  }
  .cap-site-header-sheet-name {
    flex: 1;
    min-inline-size: 0;
  }
  /* One label column: every row, with an icon or without, starts its label after the same 24px. */
  .cap-site-header-sheet-icon {
    display: grid;
    place-items: center;
    flex: none;
    inline-size: 24px;
    block-size: 24px;
    color: var(--accent-text);

    & svg {
      inline-size: 20px;
      block-size: 20px;
    }
  }
  [aria-current] > .cap-site-header-sheet-icon {
    color: inherit;
  }
  /* Two classes, so the dialog's own link color (.cap-dialog-body nav a) does not win. */
  .cap-dialog-body .cap-site-header-sheet-cta {
    display: flex;
    justify-content: center;
    align-items: center;
    margin: var(--space-5) var(--space-3) 0;
    min-block-size: max(var(--control), var(--target));
    border-radius: var(--radius-m);
    background: var(--primary);
    color: var(--primary-fg);
    font-weight: 600;
    text-decoration: none;
  }
  .cap-site-header-sheet-account {
    flex: none;
    padding: var(--space-2) var(--space-3) var(--space-3);
    border-block-start: 1px solid var(--line);
  }

  /* The bottom bar of a signed-in area on a phone: up to five of its top pages, and no More,
     because the menu button opens the full list (Dustin's answer 5). Hidden on a desktop. */
  .cap-site-tabs {
    display: none;
  }

  /* Under 360px a logo with a mark shows the mark alone; the link's label keeps the name. */
  @media (max-width: 359.98px) {
    .cap-site-header-logo > :is(svg, img) ~ * {
      display: none;
    }
  }

  @media (max-width: 767.98px) {
    .cap-site-header {
      --header-side: var(--space-5);
    }
    .cap-site-header :is(.cap-site-header-switcher, .cap-site-header-sections, .cap-site-header-cta) {
      display: none;
    }
    .cap-site-header .cap-site-header-tools {
      gap: var(--space-2);

      &::before {
        display: none;
      }
    }
    /* The links on the right are hidden here, so the tools keep to the window's edge. */
    .cap-site-header[data-links="right"] .cap-site-header-sections + .cap-site-header-tools {
      margin-inline-start: auto;
    }
    .cap-site-header .cap-site-header-menu {
      display: inline-grid;
    }
    .cap-site-header-signin {
      inline-size: 36px;
      justify-content: center;
      padding: 0;

      & > svg {
        display: block;
      }
      & > .cap-site-header-signin-text {
        position: absolute;
        inline-size: 1px;
        block-size: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
      }
    }
    /* A focused control never lands under the tab bar (WCAG 2.4.11): the bar is 61 to 79px. */
    :root:has(.cap-site-tabs) {
      scroll-padding-bottom: calc(5.5rem + env(safe-area-inset-bottom, 0px));
    }
    /* A result sits above the bar, not under it: the region is sticky at the foot of the page, as the bar is. */
    :root:has(.cap-site-tabs) .cap-message {
      inset-block-end: calc(5.5rem + env(safe-area-inset-bottom, 0px));
    }
    .cap-site-tabs {
      position: sticky;
      inset-block-end: 0;
      z-index: var(--z-tabbar);
      display: grid;
      grid-auto-flow: column;
      grid-auto-columns: minmax(0, 1fr);
      padding: var(--space-2) var(--space-2) calc(var(--space-2) + env(safe-area-inset-bottom, 0px));
      background: var(--surface);
      border-block-start: 1px solid var(--line);

      & a {
        position: relative;
        display: grid;
        justify-items: center;
        gap: var(--space-1);
        min-block-size: var(--target);
        padding: var(--space-2) 0;
        border-radius: var(--radius-m);
        color: var(--muted);
        font-size: max(12px, var(--fs-label));
        font-weight: 600;
        text-decoration: none;
        outline-offset: -2px;

        &[aria-current="page"] {
          color: var(--accent-text);
        }
      }
      /* The icon sits in a pill (Material 3's active indicator): quiet until the tab is current,
         where it takes the accent tint as well as the color. */
      & svg {
        box-sizing: content-box;
        inline-size: 20px;
        block-size: 20px;
        padding: 2px 14px;
        border-radius: var(--radius-full);
        fill: none;
        stroke: currentColor;
        stroke-width: 1.6;
        stroke-linecap: round;
        stroke-linejoin: round;
      }
      & a[aria-current="page"] svg {
        background: var(--accent-4);
      }
      /* The badge rides the pill's top end corner, clear of the glyph. */
      & .cap-site-header-badge {
        top: 0;
        inset-inline-start: calc(50% + 12px);
        box-shadow: 0 0 0 2px var(--surface);
      }
      /* Under 360px a tab is 62px: the badge sits flush on the glyph's edge with tighter padding,
         so the last tab's "99+" stays clear of the glyph and inside the window. */
      @media (max-width: 359.98px) {
        & .cap-site-header-badge {
          inset-inline-start: calc(50% + 10px);
          padding-inline: 2px;
        }
      }
    }
  }

  /* The family letterhead (data-variant="letterhead"): the header of dustinedwards.info and its
     *.dustinedwards.info sites, public pages and admins alike (Dustin, 2026-10-27). The names follow
     the center letterhead of the NASA Graphics Standards Manual (1975, page 3.2): the agency's name
     small, the center's name bold under it. The band is the Park Service's Unigrid (Massimo
     Vignelli, 1977), whose brochures open with a black band carrying the park's name in white: here
     in the page's text color (in dark mode the raised dark surface), under an 8px stripe of the site's
     family color. The top row is the same 64px on every
     site and in every admin, everything in it centered on the row's middle. The section
     links sit beside the names where they fit and take a second row where they do not, so they
     are never hidden behind a menu. The utilities run search, theme, inbox, account, with the account in the corner as in
     Carbon, Fiori and most products; a page without an inbox or account leaves their slots empty,
     so search and the theme keep their places. One default changes here: the phone keeps the
     links row, which swipes, instead of the sheet. */
  .cap-site-header[data-variant="letterhead"] {
    --header-stripe: var(--space-3);
    /* Roomier than the 56px one-row header: a 64px top row and a 48px second row (Dustin, 2026-10-27). */
    --header-row: 4rem;
    --header-row-2: 3rem;
    --header-bg: var(--text);
    --header-fg: var(--ground);
    --header-fg-muted: color-mix(in srgb, var(--header-fg) 78%, var(--header-bg));
    --header-line: color-mix(in srgb, var(--header-fg) 26%, var(--header-bg));
    --header-hover: color-mix(in srgb, var(--header-bg), var(--header-fg) 14%);
    --header-accent: var(--header-fg);
    --header-avatar: var(--header-fg);
    --header-avatar-fg: var(--header-bg);
    color-scheme: dark;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: var(--header-row) auto;
    align-items: center;
    column-gap: var(--space-4);
    block-size: auto;
    border-block-start: var(--header-stripe) solid var(--on);
    border-block-end: 0;

    & > .cap-site-header-logo {
      grid-area: 1 / 1;
      justify-self: start;
      gap: var(--space-4);
      block-size: auto;
      max-inline-size: 100%;
      overflow: visible;

      /* The mark fills one 32px square on every site, so the names start at the same place
         whatever the mark's shape. */
      & > :is(svg, img) {
        flex: none;
        inline-size: 32px;
        block-size: 32px;
        object-fit: contain;
      }
      /* A mark drawn without its own fill takes the site's color. */
      & > svg:not([fill]) {
        fill: var(--on);
      }
    }
    & > .cap-site-header-switcher {
      display: none;
    }
    & > .cap-site-header-tools {
      --header-slot: calc(36px + var(--space-4));
      grid-area: 1 / 2;
      gap: var(--space-4);
      margin: 0;

      /* Search and the theme keep the places the admin gives them (Dustin, 2026-10-27): where the
         inbox or the account is missing, its slot in the corner stays empty. Not on a phone. */
      & > .cap-site-header-account:empty {
        display: none;
      }
      @media (min-width: 768px) {
        &:not(:has(.cap-site-header-account > *)) {
          padding-inline-end: var(--header-slot);
        }
        &:not(:has(.cap-site-header-extras > *)) {
          &:has(.cap-site-header-account > *) > .cap-site-header-account {
            margin-inline-start: var(--header-slot);
          }
          &:not(:has(.cap-site-header-account > *)) {
            padding-inline-end: calc(2 * var(--header-slot));
          }
        }
      }

      &::before {
        display: none;
      }
    }
    & > :is(.cap-site-header-sections, .cap-site-header-trail) {
      grid-area: 2 / 1 / 3 / -1;
      display: flex;
      align-items: center;
      position: static;
      translate: none;
      block-size: var(--header-row-2);
      box-sizing: border-box;
      margin: 0 calc(-1 * var(--header-side));
      padding-inline: var(--header-side);
      overflow-x: auto;
      scrollbar-width: none;
      /* No hairline between the rows (Dustin, 2026-10-27): the band is one sign. */
      border-block-start: 0;
      font-size: 15px;
      font-weight: 500;

      & > ul {
        gap: var(--space-6);
      }
    }
    & .cap-site-header-extras {
      order: 3;
    }
    & .cap-site-header-account {
      order: 4;
    }
    & .cap-site-header-menu {
      order: 5;
    }
    & .cap-site-header-search-button {
      order: 1;
    }
    & .cap-site-header-theme {
      order: 2;
    }
    /* The current page keeps its 2px underline; hover is a faint tint, so it never looks like
       "you are here" and never like the focus ring (Carbon's split). The padding the tint needs
       is taken back by the margin, so the words stay where they were. */
    & .cap-site-header-link {
      font-weight: inherit;
    }
    & .cap-site-header-sections .cap-site-header-link {
      padding-inline: var(--space-2);
      margin-inline: calc(-1 * var(--space-2));

      &:hover {
        background: var(--header-hover);
      }
      &:is([aria-current="page"], [data-current])::after {
        inset-inline: var(--space-2);
      }
    }
  }
  /* In dark mode the band stays dark rather than flipping to white (Dustin, 2026-10-27): it is the
     same sign at night, lifted off the darker page as a raised surface (Material's dark theme
     lightens what sits higher). Its stripe keeps the site's color. */
  :root[data-theme="dark"] .cap-site-header[data-variant="letterhead"] {
    --header-bg: var(--raised);
    --header-fg: var(--text);
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .cap-site-header[data-variant="letterhead"] {
      --header-bg: var(--raised);
      --header-fg: var(--text);
    }
  }
  /* The whole band stays at the top of the window, on public pages and in the admin alike
     (Dustin, 2026-10-27). Where the band would cover more
     than a quarter of the window (a phone held sideways, a page zoomed to 400%), it scrolls away
     with the page instead, so reading is never left a few lines (WCAG 1.4.10's zoom, testers'
     quarter rule). A focused link never lands under it (WCAG 2.2, 2.4.11). */
  .cap-site-header[data-variant="letterhead"]:has(> .cap-site-header-sections) {
    grid-template-rows: var(--header-row) var(--header-row-2);
  }
  /* From 768px a public page's band sits inside the page's margins, at the content's width
     (--page-max, one width for the whole family), as a letterhead is printed inside the sheet's: it lines up
     with the content and the family footer and reads as a sign on the page, not the browser's bar
     (Dustin, 2026-10-27). It stays pinned 16px below the top of the window; the page's ground covers the
     margins beside it, so nothing scrolling under shows there (a shadow is never painted under its
     own box and adds nothing to scroll). In an admin the band runs the full width, but everything in it
     keeps the public page's pixels, so nothing moves between a site and its admin (Dustin, 2026-10-28):
     the inbox and the account fill the slots a public page leaves empty. */
  @media (min-width: 768px) {
    .cap-site-header[data-variant="letterhead"]:has(> .cap-site-header-sections) {
      inline-size: calc(min(100%, var(--page-max)) - 2 * var(--page-gutter));
      margin: var(--space-3) auto 0;
      inset-block-start: var(--space-3);

      &::before {
        content: "";
        position: absolute;
        inset: calc(-1 * var(--header-stripe)) 0 0;
        z-index: -1;
        pointer-events: none;
        box-shadow: 0 0 0 100vmax var(--ground);
        clip-path: inset(-100vmax -100vmax 0);
      }
      /* The skip link keeps to the page's top corner, above the margin. */
      & > .cap-site-header-skip {
        inset-block-start: calc(var(--space-3) - var(--space-3) - var(--space-3));
      }
    }
    .cap-site-header[data-variant="letterhead"]:has(> .cap-site-header-trail) {
      padding-inline: calc((100% - min(100%, var(--page-max))) / 2 + var(--page-gutter) + var(--header-side));
      margin-block-start: var(--space-3);
      inset-block-start: var(--space-3);

      /* The 16px above the stripe, as on a public page, in the band's own color (Dustin, 2026-10-28),
         so the admin's bar reads as one block to the window's top edge. */
      &::before {
        content: "";
        position: absolute;
        inset: auto 0 calc(100% + var(--header-stripe));
        block-size: var(--space-3);
        pointer-events: none;
        background: var(--header-bg);
      }
      & > .cap-site-header-skip {
        inset-block-start: calc(var(--space-3) - var(--space-3) - var(--space-3));
      }
    }
  }
  /* Where the links fit beside the names (from 1080px: the longest row, Capsomer's seven, is 545px),
     the band is one 64px row (Dustin, 2026-10-28, once search became an icon): a public page's links,
     or an admin's trail with View site, after the names; narrower, they keep their own row. Home and
     an admin's first crumb start at one place on every site, whatever the name's length (Dustin,
     2026-10-28): --header-names clears the longest name, "Dustin Edwards Lab bench"
     (it ends at x462 at 1536 wide), by 34px. */
  @media (min-width: 1080px) {
    .cap-site-header[data-variant="letterhead"]:has(> :is(.cap-site-header-sections, .cap-site-header-trail)) {
      --header-names: 19.75rem;
      grid-template-columns: minmax(var(--header-names), max-content) minmax(0, 1fr) auto;
      grid-template-rows: var(--header-row);

      & > :is(.cap-site-header-sections, .cap-site-header-trail) {
        grid-area: 1 / 2;
        block-size: var(--header-row);
        margin: 0;
        padding-inline: 0;
        overflow: visible;
      }
      & > .cap-site-header-trail {
        padding-inline-end: var(--space-6);
      }
      & > .cap-site-header-tools {
        grid-area: 1 / 3;
      }
    }
  }
  /* Under a public page's pinned band, a fade, so text never looks cut off at its edge: as wide as
     the window (a border image's outset paints without adding to scroll), and only once the page
     has scrolled, so at rest nothing under the band is dimmed. It moves with the scroll, so under
     reduced motion, and where scroll timelines are not supported, there is no fade. */
  @media (prefers-reduced-motion: no-preference) {
    @supports (animation-timeline: scroll()) {
      .cap-site-header[data-variant="letterhead"]:has(> .cap-site-header-sections)::after {
        content: "";
        position: absolute;
        inset: 100% 0 auto;
        block-size: 56px;
        pointer-events: none;
        border-image: linear-gradient(var(--ground) 20%, color-mix(in srgb, var(--ground) 60%, transparent) 55%, transparent) fill 0 / 0 / 0 100vmax;
        animation: cap-header-fade linear both;
        animation-timeline: scroll(root);
        animation-range: 0 48px;
      }
    }
  }
  @keyframes cap-header-fade {
    from {
      opacity: 0;
    }
  }
  @media (max-height: 479.98px) {
    .cap-site-header[data-variant="letterhead"] {
      position: relative;
    }
  }
  /* --header-h is what the pinned letterhead covers: its stripe and its rows, and on a public page from 768px the 16px
     above it. A page's own sticky parts and anchors read it, so no site works it out again. */
  :root:has(.cap-site-header[data-variant="letterhead"]) {
    --header-h: calc(var(--space-3) + 4rem + 3rem);
    /* Every page keeps the scrollbar's room, so a short page with no scrollbar centers the letterhead on
       the same pixels as a long one; without it a short admin page sat half a scrollbar to the right
       (Dustin, 2026-10-28). */
    scrollbar-gutter: stable;
    scroll-padding-top: calc(var(--header-h) + var(--space-3));

    @media (min-width: 768px) {
      --header-h: calc(var(--space-3) + var(--space-3) + 4rem + 3rem);
    }
    @media (min-width: 1080px) {
      &:has(.cap-site-header[data-variant="letterhead"] > :is(.cap-site-header-sections, .cap-site-header-trail)) {
        --header-h: calc(var(--space-3) + var(--space-3) + 4rem);
      }
    }

    @media (max-height: 479.98px) {
      scroll-padding-top: 0;
    }
  }
  @media print {
    .cap-site-header[data-variant="letterhead"] {
      position: relative;
    }
  }

  /* The names beside the mark: the agency small, the site's name bold under it, an admin's name
     after it in the regular weight ("Capsid Portal"). The headquarters site has its name alone, at
     the same size. Each line is trimmed to its capitals (text-box), so the letters themselves
     center on the row, not their line spacing. */
  .cap-site-header-names {
    display: flex;
    flex-direction: column;
    gap: 7px;
    min-inline-size: 0;
  }
  .cap-site-header-agency {
    color: var(--header-fg-muted);
    font-size: 12.5px;
    line-height: 1;
    text-box: trim-both cap alphabetic;
  }
  .cap-site-header-name {
    color: var(--header-fg);
    font-size: 20px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.01em;
    text-box: trim-both cap alphabetic;
  }
  .cap-site-header-app {
    font-weight: 400;
  }
  /* The headquarters site (dustinedwards.info) has no site name: "Dustin Edwards" is the only line. It is
     centered on the row beside the mark, at 22px (Dustin, 2026-11-08: alone it read small and low). Before it
     took the second line's place under an empty agency line, so it sat where "Capsid" or "Prelum" sits on the
     other sites. Its admin, "Dustin Edwards Admin", has a name and no agency and is centered the same way; 22px
     is the most the longest admin name ("Dustin Edwards Lab bench") takes without crowding the links. */
  .cap-site-header-names:not(:has(.cap-site-header-name)),
  .cap-site-header-names:not(:has(.cap-site-header-agency)) {
    justify-content: center;

    & > :is(.cap-site-header-agency, .cap-site-header-name) {
      color: var(--header-fg);
      font-size: 22px;
      font-weight: 700;
      letter-spacing: -0.01em;
    }
  }

  /* An admin's trail: where you are ("Watch / Overview") where a public page has its links, and View
     site at its end, so the admin's band is as tall as its public pages'. */
  .cap-site-header-trail {
    gap: var(--space-4);
    font-size: 15px;

    & ol {
      display: flex;
      align-items: center;
      gap: var(--space-3);
      margin: 0;
      padding: 0;
      list-style: none;
      font-weight: 500;
    }
    & li + li::before {
      content: "/";
      margin-inline-end: var(--space-3);
      color: var(--header-fg-muted);
      font-weight: 400;
    }
    & a {
      color: var(--header-fg-muted);
      font-weight: 400;
      text-decoration: none;

      &:hover {
        color: var(--header-fg);
      }
    }
    /* View site leaves the admin: the family arrow, turned out (css/base.css). */
    & > .cap-site-header-view {
      display: inline-flex;
      align-items: center;
      gap: 0.35em;
      margin-inline-start: auto;

      &::after {
        content: "";
        inline-size: 0.8em;
        block-size: 0.8em;
        background: currentColor;
        clip-path: var(--cap-arrow);
        rotate: -45deg;

        @media (forced-colors: active) {
          forced-color-adjust: none;
          background: LinkText;
        }
      }
    }
  }

  /* Search: a magnifier icon beside the theme, on the sites that have search (Dustin, 2026-10-28;
     a box on half the sites made the header differ from tab to tab). The icon is a link to the
     search page; with script it opens this panel under it, the field focused, and the site's
     matches drop down under the field as the person types (site-header.ts, wireSearch). The panel
     wears the section panels' surface. */
  .cap-site-header-search {
    display: contents;
  }
  .cap-site-header-search-panel {
    position: fixed;
    inset: auto;
    top: var(--cap-popover-y, 0px);
    left: var(--cap-popover-x, 0px);
    box-sizing: border-box;
    inline-size: min(26rem, 100vw - 2 * var(--page-gutter));
    margin: 0;
    padding: var(--space-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-l);
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-l);
    font-family: var(--font-ui, var(--ui));
    font-size: var(--fs-body);
    line-height: 1.35;

    & > form {
      display: flex;
      align-items: center;
      gap: var(--space-2);
      block-size: var(--control);
      margin: 0;
      padding-inline: var(--space-3);
      border: 1px solid var(--line-strong);
      border-radius: var(--radius-s);
      background: var(--surface);

      &:focus-within {
        border-color: var(--accent);
        outline: var(--focus-width) solid var(--ring);
        outline-offset: var(--focus-offset);
      }
      & > svg {
        flex: none;
        inline-size: 18px;
        block-size: 18px;
        fill: none;
        stroke: var(--muted);
        stroke-width: 1.6;
        stroke-linecap: round;
        stroke-linejoin: round;
      }
      & > input {
        flex: 1;
        min-inline-size: 0;
        block-size: 100%;
        padding: 0;
        border: 0;
        background: none;
        color: var(--text);
        font: inherit;

        &::placeholder {
          color: var(--muted);
        }
        &:focus-visible {
          outline: none;
        }
      }
    }
  }
  /* The matches: one row each, the kind small before the title, a line of detail under it. The
     marked row (Up and Down) is --accent-soft with a 3px accent edge, as in every Capsomer list,
     so the cue is not the tint alone. The last row opens the full results page. */
  .cap-site-header-results {
    margin-block-start: var(--space-2);

    & > [role="listbox"] {
      display: grid;
      max-block-size: min(60dvh, 28rem);
      overflow-y: auto;
    }
    & [role="option"] {
      display: grid;
      grid-template-columns: auto minmax(0, 1fr);
      column-gap: var(--space-2);
      padding: var(--space-2) var(--space-3);
      border-radius: var(--radius-s);
      border-inline-start: 3px solid transparent;
      color: var(--text);
      text-decoration: none;

      &:hover {
        background: var(--sunken);
      }
      &[data-highlighted] {
        border-inline-start-color: var(--accent);
        background: var(--accent-soft);
      }
    }
    & .cap-site-header-result-kind {
      color: var(--muted);
      font-size: var(--fs-detail);
      line-height: inherit;
    }
    & .cap-site-header-result-title {
      grid-column: 2;
      font-weight: 600;
      overflow-wrap: anywhere;
    }
    & .cap-site-header-result-detail {
      grid-column: 2;
      color: var(--muted);
      font-size: var(--fs-detail);
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    & .cap-site-header-result-all {
      grid-template-columns: minmax(0, 1fr);
      margin-block-start: var(--space-1);
      color: var(--accent-text);
      font-weight: 600;
    }
    & .cap-site-header-results-empty {
      margin: 0;
      padding: var(--space-2) var(--space-3);
      color: var(--muted);
    }
  }

  /* On a phone the letterhead keeps its links row, which swipes and fades at its end to show there
     is more; the menu button and its sheet stay only where there is no links row (an admin). The
     search icon stays. */
  @media (max-width: 767.98px) {
    .cap-site-header[data-variant="letterhead"] {
      /* An admin's name keeps the site's name whole and moves the app's to the next line where the
         two do not fit ("Dustin Edwards" over "Admin", never "Dustin" over "Edwards"). The account is in
         the menu's sheet here, so the bar holds search, theme and the menu and the names have room. */
      & > .cap-site-header-logo {
        min-inline-size: 0;
      }
      & .cap-site-header-name {
        white-space: nowrap;
        line-height: 1.1;
        text-box: none;
      }
      & .cap-site-header-app {
        white-space: normal;
      }
      &:not(:has(> .cap-site-header-sections)) .cap-site-header-tools:has(> .cap-site-header-menu) > .cap-site-header-account {
        display: none;
      }
      & > .cap-site-header-sections {
        display: flex;
        mask-image: linear-gradient(to right, #000 calc(100% - var(--space-6)), transparent);
      }
      & > .cap-site-header-trail > .cap-site-header-view {
        display: none;
      }
      & .cap-site-header-tools {
        gap: var(--space-2);
      }
    }
    .cap-site-header[data-variant="letterhead"]:has(> .cap-site-header-sections) .cap-site-header-menu {
      display: none;
    }
  }

  @media (prefers-reduced-motion: no-preference) {
    .cap-site-header :is(.cap-site-header-icon, .cap-site-header-link, .cap-site-header-switch, .cap-site-header-cta, .cap-site-header-signin),
    .cap-site-header-panel-list :is(a, button),
    .cap-site-header-sheet-list :is(a, button) {
      transition:
        background-color var(--dur-fast) var(--ease-out),
        color var(--dur-fast) var(--ease-out);
    }
    .cap-site-header-link::after {
      transition: inline-size var(--dur-base) var(--ease-out);
    }
    .cap-site-header-chev {
      transition: rotate var(--dur-fast) var(--ease-out);
    }
    :is(.cap-site-header-panel, .cap-site-header-search-panel) {
      transition:
        opacity var(--dur-fast) var(--ease-out),
        overlay var(--dur-fast) allow-discrete,
        display var(--dur-fast) allow-discrete;
      @starting-style {
        opacity: 0;
      }
      &:not(:popover-open) {
        opacity: 0;
      }
    }
  }

  @media (forced-colors: active) {
    .cap-site-header {
      border-block-end-color: CanvasText;
    }
    .cap-site-header-link:is([aria-current="page"], [data-current])::after {
      forced-color-adjust: none;
      background: CanvasText;
    }
    .cap-site-header-badge,
    .cap-site-header-count {
      forced-color-adjust: none;
      background: CanvasText;
      color: Canvas;
    }
    .cap-site-header-sheet-list [aria-current],
    .cap-site-tabs a[aria-current] {
      outline: 2px solid CanvasText;
    }
  }
}


/* The public site's own layout on Capsomer's tokens, in the NASA manual theme (capsomer/manual.css) in olive: the family letterhead,
   an example post's checks as an Apollo cue card, the features as a checklist card, a post's path as the
   flight plan's time line, the facts in form boxes, Carrel's patch and the family footer. Unlayered, so it wins where it
   meets Capsomer's layers. */

.hero {
  display: grid;
  gap: 40px;
  margin-block-end: 48px;
}
@media (min-width: 60rem) {
  .hero {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    align-items: start;
  }
}
.hero h1 {
  margin: 0 0 20px;
  font-size: clamp(2.5rem, 1.6rem + 3.6vw, 4.25rem);
  line-height: 1;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
.hero-lead {
  max-inline-size: var(--measure);
  margin: 0 0 28px;
  font: 400 1.375rem / 1.45 var(--prose);
}
.hero .cap-signs {
  margin-block-end: 16px;
}
.hero-note,
.hero-card-note {
  max-inline-size: 36rem;
  margin: 0;
  color: var(--muted);
  font-size: 0.875rem;
}
.hero-card-note {
  padding: 12px 16px 16px;
}
.hero-card .cap-cue-title {
  font-family: var(--prose);
}

.cap-part {
  margin-block: 64px;
}
.cap-part-lead a {
  color: var(--accent-text);
}

.rules {
  display: grid;
  gap: 0;
  border-block-start: 1px solid var(--text);
}
.rules p {
  max-inline-size: var(--measure);
  margin: 0;
  padding: 16px 0;
  border-block-end: 1px solid var(--line);
  font: 400 1.125rem / 1.55 var(--prose);
}
.rules b {
  font-family: var(--ui);
  font-weight: 600;
}

.run {
  display: grid;
  gap: 32px;
  align-items: center;
  margin-block-end: 24px;
}
@media (min-width: 52rem) {
  .run {
    grid-template-columns: minmax(0, 1fr) 260px;
  }
}
.patch {
  display: grid;
  justify-items: center;
  gap: 12px;
  margin: 0;
}
.patch .cap-patch {
  inline-size: 180px;
  block-size: 180px;
}
.patch figcaption {
  max-inline-size: 260px;
  color: var(--muted);
  font-size: 0.875rem;
  text-align: center;
}

/* The family's top space under the letterhead, as on the Enarratio gallery's main column, so the first heading sits at
   the same place on every site. */
.cap-page > main {
  padding-block-start: var(--space-6);
}
