/* SPDX-FileCopyrightText: 2026 Corwin Brust <corwin@bru.st> and Contributors
   SPDX-License-Identifier: GPL-3.0-or-later

   aboutcorwin.com. One stylesheet; no framework, no web fonts. Read from the top:
   tokens, base, the masthead, cards, the parallax portfolio, the display area, the mode-line and
   minibuffer, then the no-script, reduced-motion and forced-colours rules. Everything that moves
   is inside a prefers-reduced-motion: no-preference block (when scripts are off) or behind
   html.motion-on (when they run; the Motion button starts from the same setting). */

/* ---- tokens --------------------------------------------------------------------------------- */
:root {
  --bg: #f4efe4;
  --surface: #fffdf7;
  --ink: #1f1d1a;
  --muted: #59544b;
  --accent: #5b2f91;
  --accent-ink: #ffffff;
  --rule: #d8d0bf;
  --card-rule: #c9dcef;
  --card-margin: #e2a3a3;
  --ml-bg: #cfc7b6;
  --ml-ink: #1a1815;
  --ml-active: #b9ae97;
  --mb-bg: #fbf8f1;
  --focus: #0a64c2;
  --shadow: 0 1px 2px rgb(40 30 10 / 0.12), 0 6px 18px rgb(40 30 10 / 0.08);
  --px-ink: rgb(91 47 145 / 0.10);
  --w1: #0072b2; --w2: #e69f00; --w3: #009e73; --w4: #cc79a7; --w5: #56b4e9; --w6: #d55e00;
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Charter, "Bitstream Charter", Georgia, serif;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "DejaVu Sans", sans-serif;
  --mono: ui-monospace, "DejaVu Sans Mono", "Cascadia Mono", Consolas, Menlo, monospace;
  --measure: 66ch;
  --read-scale: 1;
  --read-lh: 1.6;
  --gutter: 16px;
  --pad-body: #d9d2c3; --pad-arm: #f7f2e7; --pad-ink: #3b2370; --pad-rim: #9b927f; --pad-glow: #e69f00; --pad-g-arm: #43216e;
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #121316;
    --surface: #1c1e23;
    --ink: #ebe8e1;
    --muted: #b0aaa0;
    --accent: #c8adff;
    --accent-ink: #1a1030;
    --rule: #33363d;
    --card-rule: #263345;
    --card-margin: #5a3434;
    --ml-bg: #34373f;
    --ml-ink: #f0ede6;
    --ml-active: #4a4e58;
    --mb-bg: #17181c;
    --focus: #7fb8ff;
    --shadow: 0 1px 2px rgb(0 0 0 / 0.5), 0 8px 22px rgb(0 0 0 / 0.35);
    --px-ink: rgb(200 173 255 / 0.09);
    --pad-body: #2a2d34; --pad-arm: #3d414b; --pad-ink: #e6dcff; --pad-rim: #5a5f6b; --pad-glow: #e69f00; --pad-g-arm: #9d7fe0;
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --pad-body: #2a2d34; --pad-arm: #3d414b; --pad-ink: #e6dcff; --pad-rim: #5a5f6b; --pad-glow: #e69f00; --pad-g-arm: #9d7fe0;
  --bg: #121316; --surface: #1c1e23; --ink: #ebe8e1; --muted: #b0aaa0; --accent: #c8adff;
  --accent-ink: #1a1030; --rule: #33363d; --card-rule: #263345; --card-margin: #5a3434;
  --ml-bg: #34373f; --ml-ink: #f0ede6; --ml-active: #4a4e58; --mb-bg: #17181c; --focus: #7fb8ff;
  --shadow: 0 1px 2px rgb(0 0 0 / 0.5), 0 8px 22px rgb(0 0 0 / 0.35);
  --px-ink: rgb(200 173 255 / 0.09);
  color-scheme: dark;
}

/* High contrast: the egad vivendi pair read from Modus (black, white, bg-dim #1e1e1e, blue-warmer
   #79a8ff), with a yellow focus ring. Picked in Customize; not follow-the-system. */
:root[data-theme="hc"] {
  --pad-body: #1e1e1e; --pad-arm: #000000; --pad-ink: #ffffff; --pad-rim: #ffffff; --pad-glow: #ffd400; --pad-g-arm: #4d7fd6;
  --bg: #000000; --surface: #1e1e1e; --ink: #ffffff; --muted: #d0d0d0; --accent: #79a8ff;
  --accent-ink: #000000; --rule: #9f9f9f; --card-rule: #535353; --card-margin: #8a4a4a;
  --ml-bg: #1e1e1e; --ml-ink: #ffffff; --ml-active: #535353; --mb-bg: #000000; --focus: #ffd400;
  --shadow: 0 0 0 1px #9f9f9f;
  --px-ink: rgb(121 168 255 / 0.08);
  color-scheme: dark;
}
:root[data-theme="hc"] a { text-decoration-thickness: 2px; }

/* ---- base ----------------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-padding-bottom: 3rem; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 1.0625rem/1.6 var(--serif);
  overflow-x: hidden;
}
a { color: var(--accent); text-underline-offset: 0.18em; }
a:hover { text-decoration-thickness: 2px; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
h1, h2, h3, h4, h5 { font-family: var(--sans); line-height: 1.2; letter-spacing: -0.01em; }
h2 { font-size: 1.6rem; margin: 0 0 0.6rem; }
h3 { font-size: 1.2rem; margin: 2.2rem 0 0.4rem; }
kbd { font: 0.85em var(--mono); border: 1px solid var(--rule); border-bottom-width: 2px; border-radius: 4px; padding: 0 0.3em; background: var(--surface); }
.wrap { max-width: 72rem; margin: 0 auto; padding: 0 var(--gutter); }
.prose > p, .prose > ul, .prose > dl, .lede { max-width: var(--measure); }
.lede { color: var(--muted); margin-top: 0; }
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.skip { position: absolute; left: var(--gutter); top: -4rem; z-index: 50; background: var(--accent); color: var(--accent-ink); padding: 0.5rem 0.9rem; border-radius: 6px; }
.skip:focus { top: 0.6rem; }
main > section { padding-top: 3.5rem; }

/* What shows depends on whether site.js ran; it puts class "js" on <html>. */
.js-only, .js-only-flex, .js-only-block { display: none; }
.js .js-only { display: inline-block; }
.js .js-only-flex { display: flex; }
.js .js-only-block { display: block; }
.js-only-inline { display: none; }
.js .js-only-inline { display: inline; }
.js .nojs-only { display: none; }

/* ---- masthead ------------------------------------------------------------------------------- */
.masthead { padding: 4.5rem 0 1rem; border-bottom: 1px solid var(--rule); }
.masthead h1 { font-size: clamp(2.4rem, 7vw, 4.2rem); margin: 0; letter-spacing: -0.03em; }
.say { font-family: var(--mono); color: var(--muted); margin: 0.3rem 0 1rem; font-size: 0.95rem; }
.tagline { font-size: 1.3rem; max-width: 40ch; margin: 0 0 1.5rem; }
.contents ul { display: flex; flex-wrap: wrap; gap: 0.3rem 1.2rem; padding: 0; margin: 0; list-style: none; font-family: var(--sans); font-size: 0.95rem; }
.motion-control { margin: 1rem 0 0; }
.hint { margin: 1rem 0 0; font: 0.9rem/1.5 var(--sans); color: var(--muted); max-width: var(--measure); }
button { font: inherit; }
#motion, .viewbar button, .card-close {
  font: 0.85rem var(--sans); color: var(--ink); background: var(--surface);
  border: 1px solid var(--rule); border-radius: 999px; padding: 0.3rem 0.85rem; min-height: 2rem; cursor: pointer;
}
#motion[aria-pressed="true"], .viewbar button[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.findme { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 0.3rem 1.4rem; font-family: var(--sans); font-size: 0.95rem; }

/* ---- reading settings (Customize) -------------------------------------------------------------
   Set as attributes on <html> by customize.js. They change the reading text (.reading, the card
   views) and the line length; the bars, buttons and headings of the page keep their own sizes. */
html[data-size="1"] { --read-scale: 1.15; }
html[data-size="2"] { --read-scale: 1.3; }
html[data-size="3"] { --read-scale: 1.5; }
html[data-size="4"] { --read-scale: 1.75; }
html[data-measure="narrow"] { --measure: 52ch; }
html[data-measure="wide"] { --measure: 84ch; }
html[data-leading="tight"] { --read-lh: 1.4; }
html[data-leading="loose"] { --read-lh: 1.85; }
html[data-leading="looser"] { --read-lh: 2.1; }
.reading { font-size: calc(1.0625rem * var(--read-scale, 1)); line-height: var(--read-lh, 1.6); }

/* ---- the about section: text, a side column, then the cards ---------------------------------- */
.about-grid { display: grid; gap: 0 3rem; grid-template-columns: minmax(0, 1fr); }
.about-cards { grid-column: 1 / -1; }
.side { display: grid; gap: 1.2rem; align-content: start; font-family: var(--sans); font-size: 0.95rem; margin-top: 1.5rem; }
.side-card { background: var(--surface); border: 1px solid var(--rule); border-radius: 6px; padding: 0.2rem 1rem 0.9rem; box-shadow: var(--shadow); }
.side-card h3 { font-size: 1rem; margin: 0.8rem 0 0.4rem; }
.side ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.35rem; }
.side .findme { display: grid; }
.side .what { color: var(--muted); font-family: var(--mono); font-size: 0.85em; overflow-wrap: anywhere; }
.side .when { color: var(--muted); font-size: 0.85em; white-space: nowrap; }
.side .src { color: var(--muted); font-size: 0.85em; margin: 0.7rem 0 0; }
.builds li, .posts li { display: flex; flex-wrap: wrap; gap: 0 0.5rem; align-items: baseline; }
@media (min-width: 62rem) {
  .about-grid { grid-template-columns: minmax(0, var(--measure)) minmax(17rem, 23rem); justify-content: space-between; }
  .side { margin-top: 4.3rem; position: sticky; top: 3.2rem; align-self: start; }
}

/* ---- Customize: the floating control, as M-x customize is to the mode-line ------------------ */
.custom { display: none; }
.js .custom { display: block; position: fixed; top: 0; right: max(var(--gutter), calc((100vw - 72rem) / 2 + var(--gutter))); z-index: 40; font-family: var(--sans); }
.custom-btn {
  font: 0.8rem var(--mono); color: var(--ml-ink); background: var(--ml-bg); border: 1px solid var(--rule); border-top: 0;
  border-radius: 0 0 8px 8px; padding: 0.2rem 0.8rem; min-height: 1.6rem; cursor: pointer; opacity: 0.85;
}
.custom-btn:hover, .custom-btn[aria-expanded="true"], .custom-btn:focus-visible { opacity: 1; background: var(--ml-active); }
.custom-panel {
  position: absolute; top: 1.6rem; right: 0; width: min(23rem, calc(100vw - 2 * var(--gutter))); max-height: calc(100vh - 3.5rem);
  overflow: auto; background: var(--mb-bg); color: var(--ink); border: 2px solid var(--ml-bg); border-radius: 0 0 8px 8px;
  padding: 0.2rem 1rem 1rem; box-shadow: var(--shadow); font-size: 0.95rem; line-height: 1.4;
}
.custom-panel[hidden] { display: none; }
.custom-panel .c-title { font-size: 1.05rem; margin: 0.7rem 0 0.2rem; font-family: var(--mono); }
.custom-panel .c-note { color: var(--muted); margin: 0 0 0.5rem; font-size: 0.85rem; }
.custom-panel fieldset { border: 0; border-top: 1px solid var(--rule); margin: 0; padding: 0.4rem 0 0.5rem; display: flex; flex-wrap: wrap; gap: 0.15rem 1rem; }
.custom-panel legend { font: 0.9rem var(--mono); color: var(--muted); padding: 0 0.4rem 0 0; float: left; width: 100%; }
.custom-panel label { display: inline-flex; align-items: center; gap: 0.4rem; min-height: 2rem; cursor: pointer; font-family: var(--mono); font-size: 0.9rem; }
.custom-panel input { position: absolute; opacity: 0; width: 1.5rem; height: 1.5rem; margin: 0; }
.custom-panel .box::before { content: "[ ]"; }
.custom-panel input:checked + .box::before { content: "[*]"; font-weight: bold; }
.custom-panel input:focus-visible + .box { outline: 3px solid var(--focus); outline-offset: 2px; }
.c-actions { display: flex; gap: 0.6rem; margin: 0.6rem 0 0.2rem; }
.c-actions button, .forget button { font: 0.95rem var(--mono); color: var(--ink); background: var(--surface); border: 1px solid var(--ink); border-radius: 4px; padding: 0.3rem 0.8rem; min-height: 2.2rem; cursor: pointer; }
.c-actions button:hover, .forget button:hover { background: var(--ml-active); }
.mc-note { margin-left: 0.6rem; font-size: 0.9rem; }
.c-state { font: 0.85rem var(--mono); color: var(--muted); margin: 0.4rem 0 0; }
@media (max-width: 40rem) { .js .custom { right: var(--gutter); } }
@media (forced-colors: active) { .custom-btn, .custom-panel { border: 2px solid CanvasText; } }
@media print { .custom { display: none !important; } }

/* ---- Links: the end credits, beside Customize in the right floating cluster ------------------
   Corwin, 2026-11-02: categories and names run together in one stream, force-aligned, in a font
   that looks like movie credits. League Gothic (SIL OFL 1.1, src/fonts/) is served from this site,
   so the CSP's font-src 'self' holds; it is preloaded with the page, so opening the links fetches
   nothing. A <details>: it opens and closes with scripts off too. The tab sits left of Customize:
   Customize's tab is 9ch + 1.8rem wide in the same 0.8rem mono, so the offset is that plus a gap. */
@font-face { font-family: "League Gothic"; src: url("../fonts/league-gothic-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
.custom-btn { width: calc(9ch + 1.8rem); }
.credits { position: fixed; top: 0; z-index: 41; font: 0.8rem var(--mono); right: max(var(--gutter), calc((100vw - 72rem) / 2 + var(--gutter))); }
.js .credits { right: calc(max(var(--gutter), calc((100vw - 72rem) / 2 + var(--gutter))) + 9ch + 2.1rem); }
.credits-btn {
  list-style: none; color: var(--ml-ink); background: var(--ml-bg); border: 1px solid var(--rule); border-top: 0;
  border-radius: 0 0 8px 8px; padding: 0.2rem 0.8rem; min-height: 1.6rem; line-height: 1.2rem; cursor: pointer; opacity: 0.85;
}
.credits-btn::-webkit-details-marker { display: none; }
.credits-btn:hover, .credits[open] > .credits-btn, .credits-btn:focus-visible { opacity: 1; background: var(--ml-active); }
.credits-btn:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.credits-panel {
  --cr-bg: #121110; --cr-ink: #f4efe4; --cr-role: #c9c1b0; --cr-focus: #7fb8ff;
  position: fixed; top: 1.6rem; right: max(var(--gutter), calc((100vw - 72rem) / 2 + var(--gutter)));
  width: min(30rem, calc(100vw - 2 * var(--gutter))); max-height: calc(100vh - 3.5rem); overflow: auto;
  box-sizing: border-box; background: var(--cr-bg); color: var(--cr-ink); border: 2px solid var(--ml-bg);
  border-radius: 0 0 8px 8px; padding: 0.9rem 1.2rem 1rem; box-shadow: var(--shadow); font: 0.9rem/1.45 var(--sans);
}
.cr-title { margin: 0 0 0.6rem; text-align: center; font: 0.75rem var(--sans); letter-spacing: 0.3em; text-transform: uppercase; color: var(--cr-role); }
.cr-roll, .cr-names { list-style: none; margin: 0; padding: 0; }
.cr-roll { text-align: justify; text-align-last: justify; line-height: 1.1; hyphens: none; overflow-wrap: anywhere; }
.cr-group, .cr-names, .cr-names li { display: inline; }
.cr-role { display: inline-block; text-align: left; font: 0.7rem var(--sans); letter-spacing: 0.14em; text-transform: uppercase; color: var(--cr-role); white-space: nowrap; }
.cr-names a {
  font-family: "League Gothic", "Oswald", "Arial Narrow", "Liberation Sans Narrow", Impact, sans-serif; font-weight: 400;
  font-size: clamp(1.45rem, 6vw, 2rem); letter-spacing: 0.02em; text-transform: uppercase; color: var(--cr-ink); text-decoration: none;
}
.cr-names a:hover { text-decoration: underline; text-underline-offset: 0.12em; }
.credits-panel a:focus-visible { outline: 3px solid var(--cr-focus); outline-offset: 2px; }
.cr-give, .cr-note, .cr-support { margin: 0.8rem 0 0; text-align: center; }
.cr-note { color: var(--cr-role); font-size: 0.8rem; margin-top: 0.3rem; }
.cr-support { border-top: 1px solid #3a3733; padding-top: 0.6rem; }
.cr-give a, .cr-support a { color: var(--cr-ink); text-decoration: underline; text-underline-offset: 0.15em; }
@media (forced-colors: active) { .credits-btn, .credits-panel { border: 2px solid CanvasText; } }
@media print { .credits { display: none !important; } }

/* ---- cards ---------------------------------------------------------------------------------- */
.deck {
  display: grid; gap: 1.4rem;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
  grid-auto-flow: dense;
  margin: 1.2rem 0 1rem;
}
.deck-one { grid-template-columns: minmax(0, 34rem); }
.card { --tilt: 0deg; position: relative; }
.card:nth-child(4n+1) { --tilt: -0.7deg; }
.card:nth-child(4n+2) { --tilt: 0.5deg; }
.card:nth-child(4n+3) { --tilt: -0.3deg; }
.card:nth-child(4n) { --tilt: 0.8deg; }
.face {
  position: relative; display: grid; gap: 0.15rem 0.9rem;
  grid-template-columns: 1fr auto; grid-template-rows: auto 1fr auto;
  grid-template-areas: "title window" "role window" "meta meta";
  min-height: 11rem; padding: 1rem 1.1rem 0.8rem;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 6px 6px 0 0;
  box-shadow: var(--shadow);
}
.face .title { grid-area: title; font-size: 1.1rem; margin: 0; }
.face .role { grid-area: role; margin: 0.2rem 0 0; font-size: 0.95rem; color: var(--muted); }
.face .meta { grid-area: meta; margin: 0.6rem 0 0; font: 0.75rem/1.4 var(--mono); color: var(--muted); }
.window {
  grid-area: window; position: relative; display: block; width: 8.5rem; aspect-ratio: 16 / 11;
  border-radius: 4px; overflow: hidden; background: #0f1218; border: 3px solid var(--ink);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.08);
  padding: 0; cursor: zoom-in; color: inherit;
}
.window canvas, .window .still { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.window .logo {
  position: absolute; inset: 0; margin: auto; width: 56%; height: auto; opacity: 0;
  filter: drop-shadow(0 2px 4px rgb(0 0 0 / 0.6)); pointer-events: none;
}
.window:hover .logo, .window:focus-visible .logo { opacity: 1; }
.more { background: var(--surface); border: 1px solid var(--rule); border-top: 0; border-radius: 0 0 6px 6px; box-shadow: var(--shadow); }
.more > summary { padding: 0.45rem 1.1rem; font: 0.9rem var(--sans); color: var(--accent); cursor: pointer; }
.views { padding: 0 1.1rem 1rem; font-size: calc(1rem * var(--read-scale, 1)); line-height: var(--read-lh, 1.6); }
.view h4, .view h5 { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin: 1rem 0 0.4rem; }
.view p { margin: 0 0 0.7rem; }
.view .how { color: var(--muted); font-size: 0.95em; border-left: 3px solid var(--rule); padding-left: 0.7rem; }
.links { padding-left: 1.1rem; margin: 0.4rem 0 0; font-family: var(--sans); font-size: 0.92em; }
.stats { display: grid; grid-template-columns: max-content 1fr; gap: 0.35rem 1rem; margin: 0; font-size: 0.95em; }
.stats div { display: contents; }
.stats dt { font: 600 0.8rem/1.6 var(--sans); text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.stats dd { margin: 0; }
.scoreboard { border-collapse: collapse; width: 100%; font-family: var(--mono); font-size: 0.9rem; background: #10131a; color: #f2e9c9; border-radius: 4px; overflow: hidden; }
.scoreboard th, .scoreboard td { padding: 0.4rem 0.6rem; text-align: left; border-bottom: 1px solid #262b36; }
.scoreboard thead th { color: #9aa3b5; font-weight: normal; font-size: 0.75rem; text-transform: uppercase; }
.scoreboard .num { font-size: 1.5rem; color: #ffd166; font-variant-numeric: tabular-nums; }
.feature-slot { position: relative; width: 100%; aspect-ratio: 16 / 10; background: #0f1218; border-radius: 4px; overflow: hidden; margin-bottom: 0.7rem; }
.feature-slot canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.js .v-featured .feature-slot:empty::after { content: ""; }
html:not(.js) .v-featured { display: none; }

/* With scripts: cards are business cards until opened, then index cards. */
.js .card { cursor: pointer; }
.js .card .face { transform: rotate(var(--tilt)); transition: transform 0.25s ease, box-shadow 0.25s ease; border-radius: 6px; }
.js .card .more { border: 0; box-shadow: none; background: transparent; }
.js .card .more > summary { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.js .card .more > summary:focus-visible { position: static; width: auto; height: auto; clip-path: none; display: inline-block; margin: 0.4rem 0 0; }
.js .card:not(.is-open) .views { display: none; }
.js .card:hover:not(.is-open) .face { transform: rotate(0deg) translateY(-2px); }
.js .card.is-open {
  grid-column: 1 / -1; cursor: default; z-index: 2;
}
.js .card.is-open .face, .js .card.is-open .views {
  background-color: var(--surface);
  background-image:
    linear-gradient(var(--card-margin), var(--card-margin)),
    repeating-linear-gradient(to bottom, transparent 0 1.55rem, var(--card-rule) 1.55rem calc(1.55rem + 1px));
  background-size: 100% 2px, 100% 100%;
  background-repeat: no-repeat, repeat;
  background-position: 0 2.6rem, 0 0;
}
.js .card.is-open .face { border-radius: 6px 6px 0 0; transform: rotate(calc(var(--tilt) * -1.5)); grid-template-columns: 1fr minmax(10rem, 18rem); }
.js .card.is-open .window { width: 100%; }
.js .card.is-open .views { border: 1px solid var(--rule); border-top: 0; border-radius: 0 0 6px 6px; box-shadow: var(--shadow); transform: rotate(calc(var(--tilt) * -1.5)); max-width: 100%; }
.js .card.is-open .view { display: none; max-width: var(--measure); }
.js .card.is-open .view.is-current { display: block; }
.js .card.is-open .view.v-featured { max-width: none; }
.viewbar { display: flex; flex-wrap: wrap; gap: 0.4rem; padding: 0.7rem 0 0; }
.viewbar .card-close { margin-left: auto; }
.card.is-hidden { display: none; }
.card.is-match .face { box-shadow: 0 0 0 2px var(--accent), var(--shadow); }

/* ---- the parallax portfolio ----------------------------------------------------------------- */
.portfolio { position: relative; overflow: clip; isolation: isolate; padding-bottom: 3rem; }
.px { position: absolute; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; }
.px-layer {
  position: absolute; left: -5%; right: -5%; margin: 0;
  font: 700 3rem/1.5 var(--mono); color: var(--px-ink); word-spacing: 0.6em;
  text-align: justify; user-select: none; will-change: transform;
  transform: translate3d(var(--px-x, 0), var(--px-y, 0), 0);
}
.px-far { top: 0; font-size: 1.5rem; opacity: 0.8; filter: blur(0.6px); }
.px-mid { top: 18%; font-size: 2.6rem; }
.px-near { top: 42%; font-size: 4.6rem; opacity: 0.7; }
.portfolio-inner { position: relative; }
.portfolio h2 { font-size: clamp(2rem, 6vw, 3.4rem); letter-spacing: -0.03em; }

/* Where the browser can tie animation to scrolling, CSS does the parallax by itself, scripts or
   not. site.js checks the same thing and only steps in where this is unsupported.
   Who decides whether things move: without scripts, the system's reduced-motion setting; with
   scripts, the Motion button (which starts from that setting), through motion-on or motion-off
   on <html>. */
.px-far { --d: 12vh; --dx: -2vw; }
.px-mid { --d: 34vh; --dx: 3vw; }
.px-near { --d: 70vh; --dx: -6vw; }
@keyframes px {
  from { transform: translate3d(calc(var(--dx) * -1), calc(var(--d) * -1), 0); }
  to { transform: translate3d(var(--dx), var(--d), 0); }
}
@keyframes rise { from { translate: 0 2.5rem; opacity: 0.3; } to { translate: 0 0; opacity: 1; } }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    html:not(.js) .px-layer { animation: px linear both; animation-timeline: view(); animation-range: cover; }
    html:not(.js) .portfolio .card .face { animation: rise linear both; animation-timeline: view(); animation-range: entry 0% entry 60%; }
  }
  html.motion-on .px-layer { animation: px linear both; animation-timeline: view(); animation-range: cover; }
  html.motion-on .portfolio .card .face { animation: rise linear both; animation-timeline: view(); animation-range: entry 0% entry 60%; }
}
/* While the mode-line flies the page down, cards lean with the speed. */
.flying .card .face { transform: rotate(calc(var(--tilt) + var(--vel, 0) * 1deg)) scale(calc(1 - var(--vel-abs, 0) * 0.02)); transition: none; }

/* ---- the tone d-pads ------------------------------------------------------------------------
   dpad.js swaps each introduction between its written versions; these rules draw the pads. A
   pad is a cross of four arms and a centre on a domed plastic body: a radial gradient for the
   dome, an inset rim, a gloss band across the top, and a soft drop shadow; a pressed arm sinks.
   A glow follows the pointer (--gx, --gy, set by dpad.js with CSSOM, which the CSP allows) and
   lights the arm in its quadrant. The page pad lives in a fixed dock under Customize and drifts
   by --dx and --dy (DESIGN.md, "The tone d-pad"); the section pads float at the head of their
   sections. Without scripts there are no pads and the text is the text as written. */
.prose > .tone-text > p { max-width: var(--measure); }
.keys { overflow-wrap: anywhere; }   /* "Ctrl+Shift+Home" has no break of its own at 175% text */
.privacy-keys { overflow-wrap: anywhere; }   /* nor has "aboutcorwin.customize", at 175% on a phone */
.dpad-wrap, .tone-dock { display: none; }
.js .dpad-wrap { display: block; float: right; margin: 0.15rem 0 0.6rem 1rem; width: min-content; text-align: center; }
.dpad {
  --cell: 1.55rem;
  position: relative; display: grid; grid-template-columns: repeat(3, var(--cell)); grid-template-rows: repeat(3, var(--cell));
  width: max-content; margin: 0 auto; padding: 0.3rem; border-radius: 50%;
  background: radial-gradient(circle at 38% 30%, var(--pad-arm) 0, var(--pad-body) 58%, var(--pad-rim) 100%);
  box-shadow: inset 0 2px 2px rgb(255 255 255 / 0.45), inset 0 -3px 5px rgb(0 0 0 / 0.22), 0 3px 8px rgb(30 20 0 / 0.28);
  touch-action: manipulation;
}
.dpad::after {
  content: ""; position: absolute; left: 20%; right: 20%; top: 7%; height: 30%; border-radius: 50%;
  background: linear-gradient(rgb(255 255 255 / 0.5), rgb(255 255 255 / 0)); pointer-events: none;
}
.dp-arm, .dp-centre {
  margin: 0; padding: 0; min-width: 0; font: 700 0.7rem/1 var(--sans); color: var(--pad-ink); cursor: pointer;
  border: 1px solid var(--pad-rim);
  background: linear-gradient(180deg, var(--pad-arm), var(--pad-body));
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.5), 0 1px 1px rgb(0 0 0 / 0.25);
}
.dp-up { grid-area: 1 / 2; border-radius: 45% 45% 3px 3px; }
.dp-left { grid-area: 2 / 1; border-radius: 45% 3px 3px 45%; }
.dp-centre { grid-area: 2 / 2; border-radius: 50%; margin: 2px; background: radial-gradient(circle at 50% 60%, var(--pad-body), var(--pad-arm)); }
.dp-right { grid-area: 2 / 3; border-radius: 3px 45% 45% 3px; }
.dp-down { grid-area: 3 / 2; border-radius: 3px 3px 45% 45%; }
.dp-arm:active, .dp-centre:active { transform: translateY(1px); box-shadow: inset 0 2px 4px rgb(0 0 0 / 0.35); }
.dp-arm[aria-disabled="true"] { opacity: 0.4; cursor: default; }
.dp-arm:focus-visible, .dp-centre:focus-visible { outline: 3px solid var(--focus); outline-offset: 1px; position: relative; z-index: 2; }
.dp-glow {
  position: absolute; inset: 0; border-radius: 50%; pointer-events: none; opacity: 0; z-index: 1;
  background: radial-gradient(circle at var(--gx, 50%) var(--gy, 50%), var(--pad-glow) 0, rgb(0 0 0 / 0) 1.6rem);
  mix-blend-mode: screen; transition: opacity 0.15s;
}
.dpad[data-hot] .dp-glow { opacity: 0.75; }
.dpad[data-hot="up"] .dp-up, .dpad[data-hot="down"] .dp-down, .dpad[data-hot="left"] .dp-left,
.dpad[data-hot="right"] .dp-right, .dpad[data-hot="reset"] .dp-centre { box-shadow: 0 0 0 2px var(--pad-glow), inset 0 1px 0 rgb(255 255 255 / 0.5); }
.dpad.is-own { box-shadow: inset 0 2px 2px rgb(255 255 255 / 0.45), inset 0 -3px 5px rgb(0 0 0 / 0.22), 0 0 0 2px var(--pad-glow), 0 3px 8px rgb(30 20 0 / 0.28); }
/* The quiet line that says the browser's language started the reader simpler. */
.tone-lang { margin: 0 0 0.6rem; font: 0.8rem/1.4 var(--mono); color: var(--muted); }
.tone-lang[hidden] { display: none; }
.dp-say { margin: 0.3rem 0 0; font: 0.7rem/1.3 var(--mono); color: var(--muted); max-width: 9rem; overflow-wrap: anywhere; }
/* The page pad: bigger, an accent bezel, accent arms; it floats in the dock and dodges. */
.js .tone-dock {
  display: block; position: fixed; z-index: 39; top: 2.4rem;
  right: max(var(--gutter), calc((100vw - 72rem) / 2 + var(--gutter)));
  text-align: center; font-family: var(--sans);
  transform: translate(var(--dx, 0px), var(--dy, 0px)) rotate(var(--tilt, 0deg));
}
/* The dock's caption stays out of the way of the text until the pad is hovered or focused; it is
   always there for screen readers (the pad's aria-describedby). */
.tone-dock .dp-say { position: absolute; left: 50%; top: 100%; translate: -50% 0; width: max-content; max-width: 12rem;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 3px; padding: 0.1rem 0.35rem;
  clip-path: inset(50%); opacity: 0; pointer-events: none; }
.tone-dock.is-home .dp-say { clip-path: none; opacity: 1; }
.dp-global { --cell: 1.75rem; box-shadow: 0 0 0 3px var(--accent), inset 0 2px 2px rgb(255 255 255 / 0.45), inset 0 -3px 5px rgb(0 0 0 / 0.25), 0 4px 12px rgb(30 20 0 / 0.35); }
.dp-global .dp-arm { color: var(--accent-ink); background: linear-gradient(180deg, var(--accent), var(--pad-g-arm)); border-color: var(--pad-g-arm); }
html.motion-off .dp-glow { display: none; }
@media (max-width: 40rem) {
  .js .tone-dock { right: var(--gutter); }
  .dpad { --cell: 1.5rem; }
  .dp-global { --cell: 1.6rem; }
}
@media (forced-colors: active) { .dp-arm, .dp-centre { border: 2px solid ButtonText; } .dpad { border: 1px solid CanvasText; } }
@media print { .dpad-wrap, .tone-dock { display: none !important; } }

/* ---- the display area ----------------------------------------------------------------------- */
.stage { border-top: 1px solid var(--rule); padding-bottom: 1.5rem; }
.stage h2 { font: 600 0.8rem var(--mono); text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); }
.js .stage .wrap { resize: vertical; overflow: auto; min-height: 9rem; max-height: 80vh; }
.filters { border: 0; padding: 0; margin: 0 0 1rem; display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; font-family: var(--sans); font-size: 0.9rem; }
.filters legend { padding: 0; margin-bottom: 0.4rem; color: var(--muted); width: 100%; }
.filters input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.filters label { border: 1px solid var(--rule); border-radius: 999px; padding: 0.3rem 0.85rem; min-height: 2rem; display: inline-flex; align-items: center; cursor: pointer; background: var(--surface); }
.filters input:checked + label { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.filters input:focus-visible + label { outline: 3px solid var(--focus); outline-offset: 2px; }
.results { font-family: var(--mono); font-size: 0.9rem; }
.results ol { padding-left: 1.6rem; margin: 0.3rem 0; }
.results .why { color: var(--muted); }
.results button { font: inherit; color: var(--accent); background: none; border: 0; padding: 0; text-decoration: underline; cursor: pointer; }
.back { font-family: var(--sans); font-size: 0.9rem; }
/* How many cards the filters leave, counted by CSS: hidden cards make no box, so they add nothing. */
body { counter-reset: shown; }
.card { counter-increment: shown; }
.shown { font-family: var(--sans); font-size: 0.9rem; color: var(--muted); margin: 0 0 0.6rem; }
.shown::before { content: counter(shown) " cards shown above."; }
.legend { display: grid; grid-template-columns: max-content 1fr; gap: 0.3rem 1.2rem; }
.legend div { display: contents; }
.legend dt { font-family: var(--sans); font-weight: 600; }
.legend dd { margin: 0; color: var(--muted); }

/* ---- mode-line and minibuffer --------------------------------------------------------------- */
/* The mode-line is the last thing in the page's flow before the footer, and sticky at the bottom
   of the window, so it shows the whole way down. The minibuffer sits after it in the flow, so it
   only appears once you reach the end: the mode-line seems to grow a second line. No script needed. */
.modeline {
  position: sticky; bottom: 0; z-index: 20;
  background: var(--ml-bg); color: var(--ml-ink);
  border-top: 1px solid var(--rule);
  font: 0.85rem/1.9 var(--mono);
}
.ml-link { display: flex; gap: 1.6ch; align-items: baseline; padding: 0 var(--gutter); color: inherit; text-decoration: none; white-space: nowrap; overflow: hidden; }
.ml-link:hover { background: var(--ml-active); }
.ml-buf { font-weight: 700; }
.ml-pos::after { content: "--"; }
.js .ml-pos::after { content: none; }
.ml-sec { overflow: hidden; text-overflow: ellipsis; }
.ml-modes { margin-left: auto; }
@supports (animation-timeline: scroll()) {
  @property --pos { syntax: "<integer>"; inherits: false; initial-value: 0; }
  html:not(.js) .ml-pos::after {
    counter-reset: pos var(--pos);
    content: counter(pos) "%";
    animation: pos linear both;
    animation-timeline: scroll(root);
  }
  @keyframes pos { from { --pos: 0; } to { --pos: 100; } }
}
.minibuffer-wrap { background: var(--mb-bg); color: var(--ink); font: 0.9rem/1.6 var(--mono); padding: 0.35rem var(--gutter) 1.2rem; }
.minibuffer { align-items: baseline; gap: 1ch; }
.minibuffer-wrap .results:not(:empty) { margin: 0.4rem 0 0; max-height: 40vh; overflow: auto; }
.mb-prompt { color: var(--accent); font-weight: 700; white-space: nowrap; }
.minibuffer input {
  flex: 1; min-width: 0; font: inherit; color: var(--ink); background: transparent;
  border: 0; border-bottom: 1px dashed var(--rule); padding: 0.15rem 0; caret-color: var(--accent);
}
.minibuffer input:focus-visible { outline: none; border-bottom: 2px solid var(--focus); }
.echo { margin: 0.2rem 0 0; color: var(--muted); }
.colophon { margin: 0.8rem 0 0; font-size: 0.75rem; color: var(--muted); }
.at-bottom .modeline { background: var(--ml-active); }

html.motion-on .minibuffer-wrap { transition: background-color 0.4s ease; }
html.motion-on.at-bottom .minibuffer-wrap { animation: grow 0.35s ease-out; }
@keyframes grow { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0); } }

/* ---- small screens -------------------------------------------------------------------------- */
@media (max-width: 34rem) {
  .face { grid-template-columns: 1fr; grid-template-areas: "title" "role" "window" "meta"; }
  .window, .js .card.is-open .window { width: 100%; }
  .js .card.is-open .face { grid-template-columns: 1fr; }
  .ml-flags, .ml-modes { display: none; }
  .legend, .stats { grid-template-columns: 1fr; }
  .legend dd { margin-bottom: 0.5rem; }
}

/* ---- still: reduced motion, or Motion turned off --------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-on), html:not(.motion-on) *, html:not(.motion-on) *::before, html:not(.motion-on) *::after { scroll-behavior: auto !important; transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; }
}
html.motion-off, html.motion-off *, html.motion-off *::before, html.motion-off *::after { scroll-behavior: auto !important; transition-duration: 0.01ms !important; animation: none !important; }
@media (prefers-reduced-motion: no-preference) {
  html:not(.js) { scroll-behavior: smooth; }
}
html.motion-on { scroll-behavior: smooth; }

/* ---- forced colours (Windows high contrast) ------------------------------------------------- */
@media (forced-colors: active) {
  .window { border-color: CanvasText; forced-color-adjust: none; }
  .modeline { border-top: 2px solid CanvasText; }
  .filters input:checked + label, .viewbar button[aria-pressed="true"], #motion[aria-pressed="true"] { outline: 2px solid Highlight; }
  .px { display: none; }
}

/* ---- print ---------------------------------------------------------------------------------- */
@media print {
  .modeline, .minibuffer, .stage, .px, .skip, .motion-control { display: none !important; }
  details.more > .views { display: block !important; }
}

/* ---- still frames for the windows, drawn by CSS alone (seen without scripts) ----------------- */
.still { background: #0f1218; }
.w-buffer .still { background:
  linear-gradient(#cfc7b6, #cfc7b6) 0 calc(100% - 10%) / 100% 10% no-repeat,
  repeating-linear-gradient(to bottom, transparent 0 9%, #8fd18f 9% 11%, transparent 11% 16%) 8% 12% / 70% 70% no-repeat,
  #10131a; }
.w-ring .still { background: radial-gradient(circle at 50% 50%, transparent 0 30%, var(--w2) 30% 32%, transparent 32%), #10131a; }
.w-fog .still { background:
  radial-gradient(circle at 40% 55%, transparent 0 18%, #0b0c10 34%),
  repeating-linear-gradient(90deg, #3b3f4a 0 2px, transparent 2px 14%),
  repeating-linear-gradient(0deg, #3b3f4a 0 2px, transparent 2px 18%), #1b1e26; }
.w-coop .still { background:
  radial-gradient(circle at 30% 40%, var(--w1) 0 6%, transparent 7%),
  radial-gradient(circle at 45% 60%, var(--w2) 0 6%, transparent 7%),
  radial-gradient(circle at 60% 35%, var(--w3) 0 6%, transparent 7%),
  radial-gradient(circle at 70% 62%, var(--w4) 0 6%, transparent 7%), #17321f; }
.w-ledger .still { background: repeating-linear-gradient(to bottom, #f2e9c9 0 1px, transparent 1px 14%), #10131a; }
.w-atom .still { background: radial-gradient(circle, var(--w6) 0 9%, transparent 10%), radial-gradient(ellipse 45% 20% at 50% 50%, transparent 90%, var(--w5) 92% 96%, transparent 97%), #0d1020; }
.w-pipeline .still { background: linear-gradient(90deg, var(--w3) 0 22%, transparent 22% 26%, var(--w3) 26% 48%, transparent 48% 52%, #39404d 52% 74%, transparent 74% 78%, #39404d 78%) 50% 50% / 90% 22% no-repeat, #10131a; }
.w-planes .still { background: linear-gradient(135deg, transparent 30%, rgb(86 180 233 / 0.5) 30% 60%, transparent 60%), linear-gradient(135deg, transparent 40%, rgb(204 121 167 / 0.4) 40% 70%, transparent 70%), #10131a; }
.w-shells .still { background: repeating-radial-gradient(circle, transparent 0 14%, rgb(240 228 66 / 0.5) 14% 15%), #10131a; }
.w-strata .still { background: linear-gradient(to bottom, var(--w1) 0 20%, var(--w2) 20% 40%, var(--w3) 40% 60%, var(--w4) 60% 80%, var(--w5) 80%); }
.w-field .still { background: radial-gradient(circle at 30% 40%, #c8adff 0 3%, transparent 4%), radial-gradient(circle at 60% 55%, #f0e442 0 4%, transparent 5%), radial-gradient(circle at 48% 30%, #56b4e9 0 3%, transparent 4%), radial-gradient(circle at 70% 30%, #ffffff 0 2%, transparent 3%), #0b0d14; }
.w-orb .still { background: radial-gradient(circle at 42% 40%, #a98bf0 0 10%, #5b2f91 30%, #1a1030 46%, transparent 47%), #0b0d14; }
