/* fonts.css */
/* inter-latin-ext-wght-normal */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-display: optional;
  font-weight: 100 900;
  src: url(fonts/inter-latin-ext-wght-normal.woff2) format('woff2-variations');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
/* inter-latin-wght-normal */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-display: optional;
  font-weight: 100 900;
  src: url(fonts/inter-latin-wght-normal.woff2) format('woff2-variations');
  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;
}
/* archivo-latin-ext-wdth-normal */
@font-face {
  font-family: 'Archivo Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  src: url(fonts/archivo-latin-ext-wdth-normal.woff2) format('woff2-variations');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
/* archivo-latin-wdth-normal */
@font-face {
  font-family: 'Archivo Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  src: url(fonts/archivo-latin-wdth-normal.woff2) format('woff2-variations');
  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;
}

/* tokens.css */
/* Wanovix design tokens.
   Working values, not the brand: taken from William's brand handoff of
   7 October 2026 (exploration only). Dark is direction B, graphite with
   orange ("absolutely love how it goes with orange"); light is direction A,
   bone with orange, with cobalt kept structural (focus, the second data
   series). The Design Lab replaces values here and nothing else; the names
   stay. Read by the dashboard, the site and the lab. */

:root {
  color-scheme: light;

  /* Type. Inter for running text and data; Archivo (the brand handoff's
     leaning) for the display voice: titles and big figures, set a touch
     narrow through its width axis so figures stand tall in a tile. */
  --font-sans: "Inter Variable", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-display: "Archivo Variable", var(--font-sans);
  --display-stretch: 87.5%;
  --display-weight: 650;
  --display-tracking: -0.02em;
  /* The wordmark: Archivo condensed bold in caps, the handoff's variant #2. */
  --wordmark-stretch: 62%;
  --wordmark-weight: 700;
  --label-weight: 600;
  --label-tracking: 0.06em;

  /* Scale: ratio 1.2 from 16 px. On a phone nothing is below 16 px; from
     1024 px the two small steps go to 14 and 13 px for dense data. */
  --text-xs: 1rem;
  --text-sm: 1rem;
  --text-md: 1rem;
  --text-lg: 1.2rem;
  --text-xl: 1.44rem;
  --text-2xl: 1.728rem;
  --text-3xl: 2.488rem;
  --text-4xl: 3.583rem;
  --leading: 1.5;
  --leading-tight: 1.15;
  --measure: 68ch;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4.5rem;

  /* Tiles: square-ish modules with thin joints (William: "thin joints"). */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-pill: 999px;
  --joint: 1px;
  --tap: 44px;
  --rail: 15.5rem;
  --bar: 3.5rem;

  /* Light: bone ground, chalk tiles, graphite ink, orange spark. */
  --bg: oklch(94.9% 0.015 90.2);
  --grout: oklch(86.5% 0.02 87.5);
  --surface: oklch(97.6% 0.008 90);
  --surface-2: oklch(92.6% 0.016 88);
  --surface-3: oklch(89.5% 0.018 87);
  --line: oklch(87.7% 0.02 87.5);
  --line-strong: oklch(58% 0.012 85);
  --text: oklch(28.5% 0.004 84.6);
  --text-muted: oklch(44% 0.01 91.6);
  --accent: oklch(70.4% 0.191 44.5);
  --accent-strong: oklch(76% 0.165 52);
  --accent-soft: oklch(91% 0.05 55);
  --accent-text: oklch(48% 0.15 40);
  --on-accent: oklch(28.5% 0.004 84.6);
  --info: oklch(45% 0.18 266);
  --info-soft: oklch(91% 0.04 266);
  --focus: oklch(45% 0.19 266);

  /* States, each with its own hue and always with its word beside it. */
  --run: var(--accent-text);
  --ok: oklch(46% 0.11 150);
  --ok-soft: oklch(92% 0.045 150);
  --warn: oklch(47% 0.1 70);
  --warn-soft: oklch(92% 0.06 88);
  --stop: oklch(46% 0.17 27);
  --stop-soft: oklch(93% 0.035 27);
  --on-stop: oklch(97.6% 0.008 90);

  --shadow: 0 1px 2px oklch(28% 0.01 80 / 0.08), 0 8px 24px oklch(28% 0.01 80 / 0.08);
  --scrim: oklch(20% 0.004 84.6 / 0.55);

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 120ms;
  --dur: 200ms;
  --motion: var(--dur) var(--ease-out);
}

@media (min-width: 1024px) {
  :root {
    --text-xs: 0.8125rem;
    --text-sm: 0.875rem;
  }
}

/* Dark: graphite ground and tiles, bone ink, orange spark. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: oklch(25.2% 0.004 84.6);
    --grout: oklch(21.5% 0.004 84.6);
    --surface: oklch(28.5% 0.004 84.6);
    --surface-2: oklch(31.5% 0.005 84.6);
    --surface-3: oklch(35% 0.005 84.6);
    --line: oklch(36% 0.005 84.6);
    --line-strong: oklch(60% 0.01 85);
    --text: oklch(94.9% 0.015 90.2);
    --text-muted: oklch(80% 0.016 88);
    --accent: oklch(73.1% 0.176 49.2);
    --accent-strong: oklch(78% 0.16 52);
    --accent-soft: oklch(34% 0.06 49);
    --accent-text: oklch(76% 0.16 52);
    --on-accent: oklch(25.2% 0.004 84.6);
    --info: oklch(74% 0.09 268);
    --info-soft: oklch(33% 0.045 268);
    --focus: oklch(84% 0.13 88);
    --ok: oklch(78% 0.13 150);
    --ok-soft: oklch(31% 0.045 150);
    --warn: oklch(85% 0.13 88);
    --warn-soft: oklch(33% 0.05 85);
    --stop: oklch(70% 0.17 27);
    --stop-soft: oklch(32% 0.07 27);
    --on-stop: oklch(21.5% 0.004 84.6);
    --shadow: 0 1px 2px oklch(0% 0 0 / 0.35), 0 12px 32px oklch(0% 0 0 / 0.35);
    --scrim: oklch(12% 0.004 84.6 / 0.7);
  }
}

/* The same values when the page asks for dark itself. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: oklch(25.2% 0.004 84.6);
  --grout: oklch(21.5% 0.004 84.6);
  --surface: oklch(28.5% 0.004 84.6);
  --surface-2: oklch(31.5% 0.005 84.6);
  --surface-3: oklch(35% 0.005 84.6);
  --line: oklch(36% 0.005 84.6);
  --line-strong: oklch(60% 0.01 85);
  --text: oklch(94.9% 0.015 90.2);
  --text-muted: oklch(80% 0.016 88);
  --accent: oklch(73.1% 0.176 49.2);
  --accent-strong: oklch(78% 0.16 52);
  --accent-soft: oklch(34% 0.06 49);
  --accent-text: oklch(76% 0.16 52);
  --on-accent: oklch(25.2% 0.004 84.6);
  --info: oklch(74% 0.09 268);
  --info-soft: oklch(33% 0.045 268);
  --focus: oklch(84% 0.13 88);
  --ok: oklch(78% 0.13 150);
  --ok-soft: oklch(31% 0.045 150);
  --warn: oklch(85% 0.13 88);
  --warn-soft: oklch(33% 0.05 85);
  --stop: oklch(70% 0.17 27);
  --stop-soft: oklch(32% 0.07 27);
  --on-stop: oklch(21.5% 0.004 84.6);
  --shadow: 0 1px 2px oklch(0% 0 0 / 0.35), 0 12px 32px oklch(0% 0 0 / 0.35);
  --scrim: oklch(12% 0.004 84.6 / 0.7);
}

/* White: the main colour of the public site (William, 15 October). The ink
   is graphite, orange is a fill, a line or a mark and never text; the raised
   surfaces take a trace of the orange so they read warm, not grey; the focus
   ring is the ink, as in the Design Lab. Asked for with data-ground="white"
   on a page that is light (data-theme="light"). */
:root[data-ground="white"] {
  color-scheme: light;
  --bg: oklch(100% 0 0);
  --grout: oklch(95.5% 0.02 49);
  --surface: oklch(97.5% 0.018 49);
  --surface-2: oklch(94.5% 0.025 49);
  --surface-3: oklch(92% 0.03 49);
  --line: oklch(89% 0.021 49);
  --line-strong: oklch(58% 0.012 85);
  --text: oklch(28.5% 0.004 84.6);
  --text-muted: oklch(46% 0.008 84.6);
  --accent: oklch(73.1% 0.176 49.2);
  --accent-strong: oklch(68% 0.18 46);
  --accent-soft: oklch(94% 0.04 49);
  --accent-text: oklch(52% 0.15 42);
  --on-accent: oklch(28.5% 0.004 84.6);
  --focus: oklch(28.5% 0.004 84.6);
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: 0ms; --dur: 0ms; --motion: 0ms linear; }
}

/* brand.css */
/* The brand from the Design Lab (his bone and orange until he presses Final choice). Written from packages/tokens/final.json. */
:root, :root[data-ground] {
  color-scheme: light;
  --bg: #F2EEE3;
  --grout: #D6D2C8;
  --surface: #F9F6F0;
  --surface-2: #E6E2D8;
  --surface-3: #E0DCD1;
  --line: #D4D0C6;
  --line-strong: #81807E;
  --text: #2B2A28;
  --text-muted: #605F5D;
  --accent: #FD802E;
  --accent-strong: #FF9A62;
  --accent-soft: #FFE5D8;
  --accent-text: #AF4F00;
  --on-accent: #2B2A28;
  --focus: #2B2A28;
}

/* base.css */
/* Base styles every app shares; values only from @wanovix/tokens. */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--text-md);
  line-height: var(--leading);
  font-feature-settings: "cv11", "ss01";
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, p, ol, ul { margin: 0; }
ol, ul { padding: 0; list-style: none; }
a { color: inherit; }
button { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: var(--radius-sm); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* site.css */
/* wanovix.com: his bone, the Archivo wordmark and orange accents (William,
   15 and 16 October); orange is a fill, a line or a mark and never text. The
   homepage and the portfolio share the header, the globe language menu, the
   button and the footer from here. Values only from the tokens; the colours
   and shapes of the brand come from brand.css, which the Design Lab's Final
   choice writes (packages/tokens/final.json). */

:root { --gutter: var(--space-4); }

/* The header: the way home (on the other pages), the work, the language and
   the one button. Every target is at least --tap high. */
.top {
  /* Above the hero: the wordmark's glyph box reaches up under the header and
     would otherwise take its clicks. */
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--bar);
  padding: var(--space-2) var(--gutter);
}
.top > :first-child { margin-inline-end: auto; }
/* On the homepage the wordmark below is the way home: the rest stays together
   on the right. */
.top > .top-nav:first-child { margin-inline: auto 0; }

.top-home {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--tap);
  font-family: var(--font-display);
  font-stretch: var(--wordmark-stretch);
  font-weight: var(--wordmark-weight);
  font-size: var(--text-lg);
  text-transform: uppercase;
  text-decoration: none;
}

.top-nav a {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--tap);
  padding-inline: var(--space-1);
  font-weight: var(--label-weight);
  text-decoration-line: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.35em;
  transition: text-decoration-color var(--motion);
}
.top-nav a:hover { text-decoration-color: var(--accent); }
/* The current page is marked in graphite: orange on white is under 3:1. */
.top-nav a[aria-current="page"] { text-decoration-color: currentColor; }

/* The language menu: a disclosure that works without script; lang.js adds
   Escape, closing on a click elsewhere and remembering the choice. */
.lang { position: relative; }
.lang-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-block-size: var(--tap);
  min-inline-size: var(--tap);
  padding-inline: var(--space-2);
  border-radius: var(--radius-md);
  font-weight: var(--label-weight);
  list-style: none;
  cursor: pointer;
  user-select: none;
  transition: background-color var(--motion);
}
.lang-btn::-webkit-details-marker { display: none; }
.lang-btn:hover,
.lang[open] > .lang-btn { background: var(--surface-2); }
.globe {
  inline-size: 1.25rem;
  block-size: 1.25rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
}
.lang-list {
  position: absolute;
  inset-block-start: calc(100% + var(--space-1));
  inset-inline-end: 0;
  z-index: 10;
  display: grid;
  min-inline-size: 11rem;
  padding: var(--space-1);
  border: var(--joint) solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--bg);
  box-shadow: var(--shadow);
}
.lang-list a {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-block-size: var(--tap);
  padding-inline: var(--space-3);
  border-radius: var(--radius-md);
  text-decoration: none;
}
.lang-list a::before {
  content: "";
  inline-size: var(--space-4);
  block-size: var(--space-1);
  border-radius: var(--radius-pill);
  background: transparent;
}
.lang-list a:hover { background: var(--surface); }
.lang-list a[aria-current] { font-weight: var(--label-weight); }
.lang-list a[aria-current]::before { background: var(--accent); }

/* The one button: orange with a graphite label. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: var(--tap);
  padding: 0 var(--space-5);
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--on-accent);
  font-weight: var(--label-weight);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--motion);
}
.btn:hover { background: var(--accent-strong); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline-offset: 3px; border-radius: var(--radius-md); }
.top-cta { padding-inline: var(--space-3); }

/* A quiet link beside the button: the same height, an orange underline. */
.next {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--tap);
  font-weight: var(--label-weight);
  text-decoration-line: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.35em;
  transition: text-decoration-thickness var(--motion);
}
.next:hover { text-decoration-thickness: var(--space-1); }

/* The wordmark: caps of Archivo condensed bold, sized by the width of its
   container (7 letters measure 3.33 em), so it spans it from 320 to 1920 px
   and, on a short screen, no more than about a third of the height; trimmed
   to its caps so the space around it is exact. An orange rule draws in under
   it once, on arrival. */
.mark {
  position: relative;
  padding-block-end: var(--space-4);
  font-family: var(--font-display);
  font-stretch: var(--wordmark-stretch);
  font-weight: var(--wordmark-weight);
  text-transform: uppercase;
  font-size: min(29.5cqi, 48dvh);
  line-height: 0.78;
  text-box: trim-both cap alphabetic;
  white-space: nowrap;
}
.mark::before {
  content: "";
  position: absolute;
  inset: auto 0 0;
  block-size: var(--space-1);
  background: var(--accent);
  transform-origin: left;
  animation: draw 900ms var(--ease-out) 150ms both;
}
@keyframes draw { from { transform: scaleX(0); } }

/* The hero: the wordmark and the statement, close under the header, so the
   first screen at every size already shows where the next part begins.
   Three arrangements to choose from (see the script in the page's head):
   a, the name first; b, the statement first; c, side by side. */
.hero {
  container-type: inline-size;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "mark" "line" "lede" "acts";
  gap: var(--space-4);
  padding: var(--space-4) var(--gutter) var(--space-6);
}
.hero .mark { grid-area: mark; margin-block-end: var(--space-2); }
.hero-line {
  grid-area: line;
  max-inline-size: 20ch;
  font-family: var(--font-display);
  font-stretch: var(--display-stretch);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
  text-wrap: balance;
}
/* The words that carry the promise stand on an orange stroke. */
.hero-line em {
  font-style: normal;
  background: linear-gradient(var(--accent), var(--accent)) 0 94% / 100% 0.12em no-repeat;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.hero-lede { grid-area: lede; max-inline-size: 46ch; color: var(--text-muted); text-wrap: pretty; }
.acts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-5);
}
.hero-acts { grid-area: acts; margin-block-start: var(--space-2); }

/* The brand motif in the hero (William, 25 October 2026): Labyrinth 4's still start frame in
   bone, orange and graphite, as the Design Lab's homepage preview shows it. The motif fills the panel,
   and every screen shows the same part of it whole, a square of 900 motif px around its centre: the
   shapes scale with the panel's shorter side, and a wider or taller panel shows the pattern going on
   around it. The name stands in the motif's clearing, 520 motif px wide, in graphite (the Lab's
   composition, frame-brand.js: S0 900, NAME 520). The frame is the Lab's own, its start frame with the
   clearing on, traced once to a vector: motif/labyrinth-4.svg, 4800 x 900 motif px around the centre.
   Its top and bottom are the panel's own edges (a panel wider than tall is 900 motif px high), and there
   the motif ends as it does around the clearing (round 5, William's note 9: "bleed out into the
   background colour"): each band ends in a round cap of its own width, nothing is cut off straight, and
   it flows into the bone ground; the sides run off the screen. A panel taller than wide (a phone) shows
   the same 900 px square whole with bone above and below. The motion stays in the Lab. The hero fills
   the first screen under the header. */
.hero { grid-template-rows: minmax(0, 1fr) auto auto auto; min-block-size: calc(100svh - var(--bar)); }
.brand-panel {
  grid-area: mark; position: relative; overflow: hidden; container-type: size;
  min-block-size: clamp(15rem, 42svh, 40rem);
  margin-inline: calc(var(--gutter) * -1); margin-block: calc(var(--space-4) * -1) var(--space-3);
  background: var(--bg);
}
.brand-motif {
  position: absolute; inset: 0;
  background: url(/motif/labyrinth-4.svg) 50% 50% / calc(min(100cqw, 100cqh) * 48 / 9) auto no-repeat;
}
/* the name: 7 capitals of the wordmark measure 3.331 em (measured in the browser), so 520 of 900 motif px */
.brand-name {
  position: absolute; inset: 0; display: grid; place-items: center; margin: 0;
  font-family: var(--font-display); font-stretch: var(--wordmark-stretch); font-weight: var(--wordmark-weight);
  font-size: calc(min(100cqw, 100cqh) * 520 / 900 / 3.331); line-height: 1;
  text-transform: uppercase; white-space: nowrap; color: var(--text); pointer-events: none;
}

:root[data-hero="b"] .hero { grid-template-areas: "line" "mark" "lede" "acts"; }
:root[data-hero="b"] .hero-line { max-inline-size: 18ch; font-size: var(--text-2xl); }
:root[data-hero="c"] .hero-line { font-size: var(--text-2xl); }

/* The motif William chose in the Design Lab, when his Final choice has one: a full-bleed panel
   at the top of the hero (motif.js draws it), the name inside it where the motif leaves room for
   it: in the river's pool, on the dots' island, on an island the moving blobs flow around, big in
   the band's solid top. A logotype is exempt from text contrast; its two colours are the motif's. */
.mark-panel { position: relative; grid-area: mark; display: grid; place-items: center; overflow: hidden;
  block-size: clamp(16rem, 40svh, 30rem); margin-inline: calc(var(--gutter) * -1); margin-block-start: calc(var(--space-4) * -1);
  background: var(--motif-ground, var(--bg)); }
.mark-panel > .motif { position: absolute; inset: 0; }
.mark-panel > .motif svg, .mark-panel > .motif canvas { display: block; inline-size: 100%; block-size: 100%; }
:root[data-motif="lava"] .mark-panel > .motif, :root[data-motif="labyrinth"] .mark-panel > .motif, :root[data-motif="marble"] .mark-panel > .motif { touch-action: pan-y; }
.mark-panel .mark { grid-area: auto; position: relative; z-index: 1; margin: 0; padding: 0; font-size: min(11cqi, 9rem); color: var(--motif-ink, var(--accent)); pointer-events: none; }
.mark-panel .mark::before { content: none; }
:root[data-motif="river"] .mark-panel .mark { color: var(--motif-ground, var(--bg)); }
:root[data-motif="dots"][data-island="open"] .mark-panel { display: block; block-size: auto; overflow: visible; background: none; }
:root[data-motif="dots"][data-island="open"] .mark-panel > .motif { position: relative; block-size: clamp(12rem, 30svh, 22rem); }
:root[data-motif="dots"][data-island="open"] .mark-panel .mark { padding: var(--space-4) var(--gutter) 0; color: var(--text); font-size: min(29.5cqi, 48dvh); }
:root[data-motif="band"] .mark-panel { block-size: clamp(22rem, 54svh, 40rem); place-items: start center; }
:root[data-motif="band"] .mark-panel .mark { block-size: var(--band-top, 50%); display: grid; place-items: center; color: var(--motif-ground, var(--bg)); font-size: min(15cqi, 12rem); }
:root[data-motif="band"][data-bandmark="graphite"] .mark-panel .mark { color: var(--text); }
@media (min-width: 1024px) {
  :root[data-hero="c"] .mark-panel { margin-inline-end: 0; block-size: auto; min-block-size: clamp(24rem, 60svh, 40rem); grid-row: 1 / span 3; }
}

/* A portrait screen (a phone, a tablet held upright): the brand panel is square, as wide as the screen,
   so its top and bottom are the motif's own round-capped edges (900 motif px high) and no empty bone stands
   above or below it; the hero is then as tall as it needs to be, and the story's start shows under it. */
@media (max-aspect-ratio: 1/1) {
  .hero { min-block-size: 0; grid-template-rows: auto auto auto auto; }
  .brand-panel { aspect-ratio: 1 / 1; min-block-size: 0; }
}

/* The sections: a large line in the display face, and the words beside it
   on a wide screen. */
.band {
  padding: var(--space-7) var(--gutter) var(--space-8);
  border-block-start: var(--joint) solid var(--line);
}
.display {
  font-family: var(--font-display);
  font-stretch: var(--display-stretch);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
  text-wrap: balance;
}
.points { display: grid; gap: var(--space-7); }
.point { display: grid; gap: var(--space-4); }
.point .display { max-inline-size: 18ch; }
.point p { max-inline-size: 52ch; text-wrap: pretty; }

/* The work: short mentions, each a row that leads to the portfolio. */
.work-list { list-style: none; padding: 0; border-block-end: var(--joint) solid var(--line); margin-block: var(--space-5) var(--space-5); }
.work-row {
  display: grid;
  gap: var(--space-2);
  padding-block: var(--space-5);
  border-block-start: var(--joint) solid var(--line);
  text-decoration: none;
}
.work-name {
  font-family: var(--font-display);
  font-stretch: var(--display-stretch);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  font-size: var(--text-xl);
  line-height: var(--leading-tight);
  text-decoration: underline 2px transparent;
  text-underline-offset: 0.2em;
  transition: text-decoration-color var(--motion);
}
.work-who { color: var(--text-muted); }
.work-line { max-inline-size: 46ch; }
.work-go {
  justify-self: start;
  font-weight: var(--label-weight);
  text-decoration: underline 2px var(--accent);
  text-underline-offset: 0.35em;
}
.work-row:hover .work-name { text-decoration-color: var(--accent); }
.work-row:hover .work-go { text-decoration-thickness: var(--space-1); }
.work-row:focus-visible { outline-offset: var(--space-1); }

/* The close: one question, one sentence, the button. */
.close { display: grid; justify-items: start; gap: var(--space-5); }
.close .display { max-inline-size: 16ch; font-size: var(--text-3xl); line-height: 1.05; }
.close p { max-inline-size: 44ch; color: var(--text-muted); text-wrap: pretty; }

/* The page for an address that does not exist (404.html, nl/404.html): the
   close band's shape, a little lower on the screen, with the way back. */
.lost { display: grid; justify-items: start; align-content: center; gap: var(--space-5); min-block-size: 62vh; }
.lost .display { max-inline-size: 16ch; font-size: var(--text-3xl); line-height: 1.05; }
.lost p { max-inline-size: 44ch; color: var(--text-muted); text-wrap: pretty; }
.lost .lost-code { font-weight: var(--label-weight); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text); }
.lost .lost-other a { color: var(--text); }

.foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-5);
  padding: var(--space-4) var(--gutter);
  border-block-start: var(--joint) solid var(--line);
  color: var(--text-muted);
}
.foot-mark {
  font-family: var(--font-display);
  font-stretch: var(--wordmark-stretch);
  font-weight: var(--wordmark-weight);
  font-size: var(--text-lg);
  text-transform: uppercase;
  color: var(--text);
}
.foot a {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--tap);
  text-decoration-color: var(--accent);
  text-underline-offset: 0.35em;
}
.foot a:hover { color: var(--text); }

/* Four header items on a subpage fit a 320 phone, also with "Contacteer
   ons": below 420 the wordmark, the paddings and the gaps are a step smaller,
   and below 360 the wordmark and the gaps are smaller again and the globe
   stands alone (its language code is still read). */
@media (max-width: 359.98px) {
  .top { gap: var(--space-1); }
  .top-home { font-size: var(--text-md); }
  .lang-now {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
}

/* The homepage on a small phone: its header's two links, the globe and the button do not fit one
   line (in Dutch under 445 px, in English under 360 px), so the header leaves its button to the
   hero, which shows the same button just below it. */
@media (max-width: 444.98px) {
  :root[lang="nl"] .top > .top-nav:first-child ~ .top-cta { display: none; }
}
@media (max-width: 359.98px) {
  .top > .top-nav:first-child ~ .top-cta { display: none; }
}
/* The next version: on a subpage the Dutch header leaves its button below 465 px, where the wordmark,
   the link that stays, the globe and "Contacteer ons" no longer share a line (the portfolio's link to
   itself gives way below 535 px, in portfolio.css; every header's button goes below 360 px); the
   page's close holds the same button. */
@media (max-width: 464.98px) { :root[lang="nl"] .top > .top-home:first-child ~ .top-cta { display: none; } }
@media (max-width: 359.98px) { .top-cta { display: none; } }
/* The header's links never wrap to a second line. In English, where the button stays, below 480 px a
   subpage's link to itself gives way (it is the page the visitor is on; the wordmark leads home). */
.top-nav { display: flex; flex-wrap: nowrap; white-space: nowrap; }
@media (max-width: 479.98px) { :root:not([lang="nl"]) .top-nav a[aria-current="page"] { display: none; } }

@media (min-width: 420px) {
  .top { gap: var(--space-3); }
  .top-home { font-size: var(--text-xl); }
  .top-nav a { padding-inline: var(--space-2); }
  .lang-btn { gap: var(--space-2); padding-inline: var(--space-3); }
  .top-cta { padding-inline: var(--space-4); }
}

@media (min-width: 768px) {
  :root { --gutter: var(--space-6); }
  .hero-line { max-inline-size: 22ch; font-size: var(--text-3xl); }
  .hero-lede, .point p, .close p { font-size: var(--text-lg); }
  :root[data-hero="b"] .hero-line,
  :root[data-hero="c"] .hero-line { font-size: var(--text-3xl); }
  .display { font-size: var(--text-3xl); }
  .work-name { font-size: var(--text-2xl); }
  .close .display { font-size: var(--text-4xl); }
  .lost .display { font-size: var(--text-4xl); }
  .lost p { font-size: var(--text-lg); }
  .band { padding-block: var(--space-8); }
  .points { gap: var(--space-8); }
}

@media (min-width: 1024px) {
  .hero {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "mark mark" "line acts" "lede acts";
    grid-template-rows: minmax(0, 1fr) auto auto;
    column-gap: var(--space-7);
  }
  .hero-acts { align-self: end; margin-block-start: 0; }
  :root[data-hero="b"] .hero { grid-template-areas: "line line" "mark mark" "lede acts"; }
  :root[data-hero="c"] .hero {
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    grid-template-rows: 1fr auto auto;
    grid-template-areas: "mark line" "mark lede" "mark acts";
    align-items: end;
  }
  :root[data-hero="c"] .hero .mark { font-size: min(16cqi, 40dvh); margin-block-end: 0; }
  :root[data-hero="c"] .hero-acts { align-self: end; }

  .point { grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); column-gap: var(--space-8); align-items: start; }
  .point p { padding-block-start: var(--space-2); }
  .work-row {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr) auto;
    grid-template-rows: auto auto;
    column-gap: var(--space-7);
    align-items: baseline;
  }
  .work-name { grid-row: 1 / span 2; }
  .work-go { grid-column: 3; grid-row: 1; }
  .work-who { grid-column: 2; grid-row: 1; }
  .work-line { grid-column: 2; grid-row: 2; }
}

@media (min-width: 1280px) {
  /* The statement is the page's h1: never smaller than a section's line. */
  .hero-line { font-size: var(--text-4xl); }
  :root[data-hero="b"] .hero-line,
  :root[data-hero="c"] .hero-line { font-size: var(--text-4xl); }
  .display { font-size: var(--text-4xl); }
  .work-name { font-size: var(--text-3xl); }
}

@media (min-width: 1440px) {
  :root { --gutter: var(--space-7); }
}

@media (prefers-reduced-motion: reduce) {
  .mark::before { animation: none; }
}


/* ======================================================================
   The next homepage (the website rounds of 18 and 19 October 2026). Every
   part below stands complete and still without script or motion: motion.js
   and the scroll timelines only take a part apart and play it back. Orange
   stays a fill, a line or a mark, and the one colour of what can be pressed;
   the ballpoint blue is an ink for drawing, never a control.
   ====================================================================== */

:root { --ink: #24439c; }

.skip {
  position: absolute; inset-inline-start: var(--gutter); inset-block-start: var(--space-2); z-index: 10;
  padding: var(--space-2) var(--space-4); border-radius: var(--radius-md);
  display: inline-flex; align-items: center; min-block-size: var(--tap);
  background: var(--text); color: var(--bg); font-weight: var(--label-weight);
  transform: translateY(-200%);
}
.skip:focus { transform: none; }

/* The header stays at the top on a wide screen and draws its edge once the page has moved. */
@media (min-width: 768px) {
  .top { position: sticky; inset-block-start: 0; background: var(--bg); }
  /* what gets focus or is jumped to lands under the header, not behind it */
  html { scroll-padding-block-start: calc(var(--bar) + 1rem); }
}

/* ---- H2: what you tell us becomes your software (round 6, 26 October 2026: William's OK of the story
   proposal; STORY-PROPOSAL.md in the OS repository). Nothing is pinned and nothing holds the scroll: the three
   titles are ordinary text that scrolls past at the page's own speed, and the picture is sticky: beside them,
   centred under the header, on a screen at least 768 px wide; on top of the screen while they scroll under it
   on a phone (both at least 600 px tall, with motion). Every change in the picture follows the scroll position
   itself (motion.js): the package comes apart, an orange story line draws itself from title to title and on a
   wide screen runs into the picture as the pen that writes the whiteboard, the marker lines straighten into
   their software, Lies's job moves to Wednesday, and the line ends in a dot at the heading. A short runway: one
   title every --step, then --tail and the picture scrolls away with the page. On a short screen and with less
   motion: the stacked version, each title with its own picture (the package, the whiteboard, the software),
   nothing sticky; with less motion everything stands still at its end. Without script: the titles and the
   software. ---- */
.tale { overflow-x: clip; --step: clamp(17rem, 35svh, 26rem); --tail: clamp(8rem, 18svh, 12rem); --pen: var(--accent); }
.tale-grid { display: grid; grid-template-columns: minmax(0, 1fr); align-content: start; }
.tale-title {
  margin: 0; font-family: var(--font-display); font-stretch: var(--display-stretch); font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking); line-height: 1.04; font-size: clamp(2rem, 8.8vw, 2.25rem); text-wrap: balance; color: var(--text);
}
.tale-t1, .tale-t2 { margin-block-start: var(--space-7); }
.tale-pic, .tale-stage { margin-block-start: var(--space-5); }
/* the pictures motion.js draws (the package, the whiteboard) are there only when it draws them */
.tale-pic { display: none; }
:root[data-tale="stacked"] .tale-pic { display: block; }

.field, .tale-pic { position: relative; aspect-ratio: 358 / 330; max-inline-size: 28rem; container: field / inline-size; }
.soft {
  position: absolute; inset: 0; display: grid; gap: var(--joint);
  grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto minmax(0, 1fr);
  background: var(--grout); border-radius: var(--radius-lg); overflow: hidden; cursor: default;
  box-shadow: 0 24px 48px -28px color-mix(in oklch, var(--text) 40%, transparent);
  font-size: var(--text-md); line-height: 1.3;
}
.soft-bar { grid-column: 1 / -1; margin: 0; display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); min-block-size: 3rem; padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4); background: var(--surface); }
.soft-name { display: inline-flex; align-items: center; gap: 0.625rem; font-family: var(--font-display); font-stretch: var(--display-stretch); font-weight: var(--display-weight); font-size: 1.125rem; }
.soft-name b { inline-size: 1.375rem; block-size: 1.375rem; border-radius: 5px; background: var(--text); }
.soft-people { display: flex; gap: 0.25rem; }
.soft-people b, .soft-who b {
  display: inline-grid; place-items: center; flex: none; inline-size: 2rem; block-size: 2rem; border-radius: 50%;
  background: var(--surface-3); color: var(--text); font-size: 1rem; font-weight: 700; letter-spacing: -0.03em;
}
.soft-side { display: none; margin: 0; }
.soft-col { display: flex; flex-direction: column; gap: 0.5rem; padding-block-end: 0.5rem; background: var(--bg); min-inline-size: 0; }
.soft-col-0, .soft-col-3 { display: none; }
.soft-day { margin: 0 0 0.125rem; display: flex; align-items: center; min-block-size: 2.5rem; padding-inline: 0.75rem; background: var(--surface); box-shadow: 0 var(--joint) 0 var(--grout); font-weight: var(--label-weight); }
.soft-card { display: grid; gap: 0.4rem; margin: 0 0.5rem; padding: 0.625rem 0.75rem; border-radius: 6px; background: var(--surface); box-shadow: 0 1px 0 var(--line); min-inline-size: 0; }
.soft-job { font-weight: var(--label-weight); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.soft-who { display: flex; align-items: center; gap: 0.45rem; color: var(--text-muted); }
.soft-urgent { border-inline-start: 3px solid var(--ink); padding-inline-start: calc(0.75rem - 3px); }
.soft-flag { display: inline-flex; align-items: center; gap: 0.3rem; color: var(--ink); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
.soft-flag-mark { inline-size: 0.7em; block-size: 0.85em; flex: none; }
.soft-card.soft-more { display: none; }
/* the place the moved job left on Tuesday */
.soft-gap { visibility: hidden; }
.soft-moved { background: var(--text); color: var(--surface); box-shadow: 0 16px 30px -14px color-mix(in oklch, var(--text) 70%, transparent); }
.soft-moved .soft-who { color: color-mix(in oklch, var(--surface) 78%, transparent); }
.soft-moved .soft-who b { background: color-mix(in oklch, var(--surface) 88%, transparent); color: var(--text); }
.soft-card.soft-cover { position: absolute; inset: 0; margin: 0; border-radius: inherit; color: var(--text); }
.soft-moved .soft-cover .soft-who { color: var(--text-muted); }
.soft-moved .soft-cover .soft-who b { background: var(--surface-3); color: var(--text); }
.soft-lift { position: absolute; inset: 0; border-radius: inherit; pointer-events: none; box-shadow: 0 16px 30px -14px color-mix(in oklch, var(--text) 70%, transparent); }

@media (min-width: 768px) {
  /* the pictures: the whole column's width, a little wider than tall: two days filled to their last card */
  .tale { --field-h: clamp(19.5rem, calc(63svh - 8.5rem), 21rem); }
  .field, .tale-pic { aspect-ratio: auto; inline-size: 100%; block-size: var(--field-h); max-inline-size: none; }
  .tale-title { font-size: clamp(2.25rem, min(3.75vw, 6.2svh), 4.25rem); }
  /* the titles beside the pictures: the stacked version, a row each */
  .tale-grid { grid-template-columns: minmax(0, 0.39fr) minmax(0, 0.61fr); column-gap: clamp(var(--space-6), 3.6vw, 4.5rem); row-gap: var(--space-7); align-items: center; }
  .tale-t0, .tale-t1, .tale-t2 { grid-column: 1; margin: 0; }
  .tale-pic, .tale-stage { grid-column: 2; margin: 0; }
  .tale-t0, .tale-p0 { grid-row: 1; }
  .tale-t1, .tale-p1 { grid-row: 2; }
  .tale-t2 { grid-row: 3; }
  .tale-stage { grid-row: 3; }
  /* without the pictures (no script): the software beside all three titles */
  :root:not([data-tale]) .tale-stage { grid-row: 1 / 4; }
  /* the sticky version: the titles a --step apart, the stage beside them all, held in the middle of
     the screen under the header while they pass, until --tail after the last */
  :root[data-tale="sticky"] .tale-grid { grid-template-rows: var(--step) var(--step) var(--step) var(--tail); row-gap: 0; align-items: center; }
  :root[data-tale="sticky"] .tale-title { color: var(--text-muted); transition: color 400ms var(--ease-out); }
  :root[data-tale="sticky"] .tale-title.is-now { color: var(--text); }
  :root[data-tale="sticky"] .tale-stage {
    grid-row: 1 / 5; align-self: start; position: sticky;
    inset-block-start: calc(var(--bar) + (100svh - var(--bar) - var(--field-h)) / 2);
  }
}
/* the phone's sticky version: the picture on top of the screen (its own row, as tall as the picture: --ph,
   which motion.js measures), the titles a --step apart under it, scrolling under the picture and out of
   sight beneath it, until --tail after the last */
@media (max-width: 767.98px) {
  :root[data-tale="sticky"] .tale { --step: clamp(13rem, 32svh, 19rem); --tail: clamp(7rem, 16svh, 10rem); }
  :root[data-tale="sticky"] .tale-grid { grid-template-rows: var(--ph, 22rem) var(--step) var(--step) var(--step) var(--tail); align-items: center; }
  /* the titles in the picture's column too, under it (placed by hand, so the grid never adds a column) */
  :root[data-tale="sticky"] .tale-title { grid-column: 1; margin: 0; color: var(--text-muted); transition: color 400ms var(--ease-out); }
  :root[data-tale="sticky"] .tale-title.is-now { color: var(--text); }
  :root[data-tale="sticky"] .tale-t0 { grid-row: 2; }
  :root[data-tale="sticky"] .tale-t1 { grid-row: 3; }
  :root[data-tale="sticky"] .tale-t2 { grid-row: 4; }
  :root[data-tale="sticky"] .tale-stage {
    grid-row: 1 / 6; grid-column: 1; align-self: start; position: sticky; inset-block-start: var(--space-3); z-index: 2;
    /* its ground runs from edge to edge, so the story line and what scrolled past go under it too */
    margin: 0 calc(var(--gutter) * -1); padding: 0 var(--gutter) var(--space-3); background: var(--bg);
  }
  /* nothing that has scrolled past peeks out in the gap above the picture */
  :root[data-tale="sticky"] .tale-stage::before { content: ""; position: absolute; inset: calc(var(--space-3) * -1) 0 100%; background: var(--bg); pointer-events: none; }
  /* what scrolls under the picture fades out under its lower edge */
  :root[data-tale="sticky"] .tale-stage::after { content: ""; position: absolute; inset: 100% 0 auto; block-size: var(--space-5); background: linear-gradient(var(--bg), color-mix(in oklch, var(--bg) 0%, transparent)); pointer-events: none; }
}
/* on a phone that will get the sticky version, the picture stands first from the start, so nothing moves
   on the screen when motion.js sets it up (Lighthouse, round 6) */
@media (scripting: enabled) and (prefers-reduced-motion: no-preference) and (max-width: 767.98px) and (min-height: 600px) {
  :root:not([data-motion="reduce"]):not([data-tale]) .tale-stage { order: -1; margin-block: 0 var(--space-5); }
}
/* the story line (motion.js draws it): beside the titles in the band's margin, under the second title, into
   the picture on a wide screen; a dot where it starts and one at the heading */
:root[data-tale="sticky"] .tale-grid { position: relative; }
.tale-line { position: absolute; inset-block-start: 0; inset-inline-start: 0; overflow: visible; pointer-events: none; z-index: 1; }
.tale-line path { fill: none; stroke: var(--pen); stroke-linecap: round; stroke-linejoin: round; }
.tale-line circle { fill: var(--pen); }
/* a tall tablet: room for Wednesday's third job too, so both days run to the panel's foot */
@media (min-width: 768px) and (max-width: 1099.98px) and (min-height: 800px) {
  .tale { --field-h: 22.25rem; }
  .soft-card.soft-more { display: grid; }
}
@media (min-width: 1100px) {
  /* the width sets the panel (the whole column, the week from a laptop's 1280 px up); its height grows
     with the screen and with its width, so the week fills it on a laptop and on a 2560 monitor alike */
  .tale { --field-h: clamp(19.75rem, min(calc(64vh - var(--bar) - 4rem), calc(18vw + 9rem)), 46rem); }
}
/* a wide but short window has the stacked version (motion.js): the pictures are square there, room for two days */
@media (min-width: 1100px) and (max-height: 599.98px) {
  .field, .tale-pic { aspect-ratio: 1 / 1; inline-size: min(100%, 28rem); block-size: auto; }
}
@container field (min-width: 640px) {
  /* a field wide enough for the whole week: dense, like the real thing, and drawn larger the larger the
     field (--u is one pixel of the drawing: 1 up to a field about 1100 px wide, then growing with it) */
  .soft { --u: calc(clamp(14px, 1.27cqi, 21px) / 14); grid-template-columns: repeat(4, minmax(0, 1fr)); font-size: calc(14 * var(--u)); }
  .soft-bar { min-block-size: calc(52 * var(--u)); padding: calc(8 * var(--u)) calc(12 * var(--u)) calc(8 * var(--u)) calc(16 * var(--u)); }
  .soft-name { font-size: calc(19 * var(--u)); gap: calc(10 * var(--u)); }
  .soft-name b { inline-size: calc(22 * var(--u)); block-size: calc(22 * var(--u)); border-radius: calc(5 * var(--u)); }
  .soft-people { gap: calc(4 * var(--u)); }
  .soft-people b { inline-size: calc(28 * var(--u)); block-size: calc(28 * var(--u)); font-size: calc(11 * var(--u)); }
  .soft-who { gap: calc(7 * var(--u)); }
  .soft-who b { inline-size: calc(22 * var(--u)); block-size: calc(22 * var(--u)); font-size: calc(11 * var(--u)); }
  .soft-col-0, .soft-col-3 { display: flex; }
  .soft-card.soft-more { display: grid; }
  .soft-job { white-space: normal; text-wrap: balance; }
  .soft-day { min-block-size: calc(42 * var(--u)); padding-inline: calc(12 * var(--u)); margin-block-end: calc(2 * var(--u)); }
  .soft-card { margin-inline: calc(6 * var(--u)); padding: calc(10 * var(--u)); gap: calc(6.4 * var(--u)); border-radius: calc(6 * var(--u)); }
  .soft-urgent { padding-inline-start: calc(10 * var(--u) - 3px); }
  .soft-col { gap: calc(7 * var(--u)); padding-block-end: calc(8 * var(--u)); }
  .soft-flag { font-size: calc(12 * var(--u)); gap: calc(4.8 * var(--u)); }
}
@container field (min-width: 760px) {
  /* room for the side bar too, as wide as its longest label in either language (never cut) */
  .soft { grid-template-columns: max-content repeat(4, minmax(0, 1fr)); }
  .soft-side { display: grid; align-content: start; gap: calc(6 * var(--u)); padding: calc(14 * var(--u)) calc(8 * var(--u)); background: var(--surface); }
  .soft-side span { display: block; min-block-size: calc(32 * var(--u)); line-height: calc(32 * var(--u)); padding-inline: calc(8 * var(--u)) calc(12 * var(--u)); border-radius: calc(6 * var(--u)); font-size: calc(14 * var(--u)); white-space: nowrap; }
  .soft-side span.is-on { background: var(--surface-2); font-weight: var(--label-weight); }
  .soft-side i { display: inline-block; vertical-align: -0.05em; margin-inline-end: calc(8 * var(--u)); inline-size: calc(10 * var(--u)); block-size: calc(10 * var(--u)); border-radius: 2px; background: var(--surface-3); }
  .soft-side .is-on i { background: var(--text); }
}
/* a laptop's shorter screen caps the panel lower: the week's cards sit closer, all four of
   Thursday's jobs still whole */
@media (min-width: 1100px) and (max-height: 842.98px) {
  @container field (min-width: 640px) {
    .soft-bar { min-block-size: calc(40 * var(--u)); padding-block: calc(4 * var(--u)); }
    .soft-name { font-size: calc(17 * var(--u)); }
    .soft-people b { inline-size: calc(24 * var(--u)); block-size: calc(24 * var(--u)); font-size: calc(10 * var(--u)); }
    .soft-day { min-block-size: calc(32 * var(--u)); }
    .soft-col { gap: calc(5 * var(--u)); padding-block-end: calc(6 * var(--u)); }
    .soft-card { padding: calc(7 * var(--u)) calc(9 * var(--u)); gap: calc(4 * var(--u)); }
    .soft-urgent { padding-inline-start: calc(9 * var(--u) - 3px); }
    .soft-job { line-height: 1.25; }
    .soft-who b { inline-size: calc(18 * var(--u)); block-size: calc(18 * var(--u)); font-size: calc(9 * var(--u)); }
    .soft-side { padding-block: calc(10 * var(--u)); gap: calc(4 * var(--u)); }
    .soft-side span { min-block-size: calc(28 * var(--u)); line-height: calc(28 * var(--u)); }
  }
}

/* The scene's own layer (motion.js builds it inside the field): the package that does not fit, the
   whiteboard and its marker, the trail of the job on its way. */
.tale-fly { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.tale-fly:empty { display: none; }
.fly-pkg { position: absolute; background: var(--surface-2); border: 1.5px solid var(--line-strong); border-radius: 6px; }
.fly-part { position: absolute; inset-block-start: 0; inset-inline-start: 0; border-radius: 4px; box-sizing: border-box; will-change: transform; }
.fly-board { position: absolute; inset: 0; background: var(--surface); border: var(--joint) solid var(--line); border-radius: 6px; box-shadow: 0 20px 40px -26px color-mix(in oklch, var(--text) 45%, transparent); }
.fly-ink { position: absolute; inset-block-start: 0; inset-inline-start: 0; overflow: visible; }
.fly-ink path { fill: none; stroke: var(--pen, var(--ink)); stroke-linecap: round; stroke-linejoin: round; }
.fly-trail { position: absolute; inset-block-start: 0; inset-inline-start: 0; border-radius: 6px; background: var(--text); will-change: transform; }
/* Until the motion is set up, the software waits hidden, so nothing a visitor already sees
   disappears when it starts (motion.js marks the page data-motion-done once it is set up, or once it
   will not be). Without scripts, with less motion asked, and after four seconds whatever happens, it
   stands. The titles never wait: they are the page's text. */
@media (scripting: enabled) and (prefers-reduced-motion: no-preference) {
  :root:not([data-motion="reduce"]):not([data-motion-done]) .field {
    visibility: hidden;
    animation: wait-for-motion 0s 4s forwards;
  }
}
@keyframes wait-for-motion { to { visibility: visible; } }

/* ---- William Cooke (round 4, 25 October 2026): who is behind Wanovix, in his own words, beside his
   headshot (no label, no caption). The photo on top on a phone, beside the words from 768 px. ---- */
.who { display: grid; gap: var(--space-6); align-items: center; }
.who-photo {
  display: block; inline-size: min(100%, 22rem); block-size: auto; aspect-ratio: 3 / 4; object-fit: cover;
  border-radius: var(--radius-lg); background: var(--surface-2);
}
.who-say { display: grid; gap: var(--space-4); max-inline-size: 40rem; }
.who-say p { text-wrap: pretty; }
.who-say em { font-style: italic; }
@media (min-width: 768px) {
  .who { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); column-gap: clamp(var(--space-6), 6vw, 7rem); }
  .who-photo { inline-size: 100%; max-inline-size: 26rem; justify-self: start; }
  .who-say p { font-size: var(--text-lg); }
}

/* ---- H3: the calculator (round 3): a card per task done by hand, how often and how long, what an
   hour is worth, then the year on graphite with a bar per task. ---- */
.calc { display: grid; gap: var(--space-6); }
.calc .display { max-inline-size: 30ch; }
.calc-body { display: grid; gap: var(--space-5); }
.calc-form { display: grid; gap: var(--space-4); align-content: start; min-inline-size: 0; }
.tasks { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.task {
  display: grid; gap: var(--space-2); min-inline-size: 0;
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-4);
  border: var(--joint) solid var(--line); border-radius: var(--radius-lg); background: var(--surface);
}
.task-top { display: flex; align-items: center; gap: var(--space-2); min-inline-size: 0; }
.task-name {
  flex: 1; min-inline-size: 0; min-block-size: var(--tap); padding: 0.55rem var(--space-1) 0.45rem; resize: none; overflow: hidden; field-sizing: content; line-height: 1.3;
  border: 0; border-block-end: 2px dashed var(--line-strong); border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  background: transparent; color: var(--text); font: inherit; font-weight: var(--label-weight); font-size: var(--text-lg);
}
.task-name::placeholder { color: var(--text-muted); font-weight: 400; }
.task-name:hover { border-block-end-color: var(--text); }
.task-name:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-block-end-style: solid; }
.task-del {
  flex: none; display: grid; place-items: center; inline-size: var(--tap); block-size: var(--tap);
  border: 0; border-radius: var(--radius-md); background: transparent; color: var(--text-muted); cursor: pointer;
  transition: background-color var(--motion), color var(--motion);
}
.task-del svg, .task-add svg { inline-size: 1.25rem; block-size: 1.25rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.task-del:hover { background: var(--surface-2); color: var(--text); }
.task-del:focus-visible, .task-add:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.task-nums { display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--space-3); margin: 0; color: var(--text-muted); }
/* where the two figures of a task take two lines, the dot between them goes */
@media (max-width: 479.98px) { .task-nums { gap: 0 var(--space-4); } .task-nums .calc-dot { display: none; } }
.tasks-none { margin: 0; color: var(--text-muted); }
.tasks-none[hidden] { display: none; }
.task-add-row { margin: 0; }
.task-add {
  display: inline-flex; align-items: center; gap: var(--space-2); min-block-size: var(--tap); padding: 0 var(--space-4) 0 var(--space-3);
  border: 2px dashed var(--line-strong); border-radius: var(--radius-md); background: transparent; color: var(--text);
  font: inherit; font-weight: var(--label-weight); cursor: pointer; transition: border-color var(--motion), background-color var(--motion);
}
.task-add:hover { border-color: var(--text); background: var(--surface); }
.task-add[hidden] { display: none; }
.calc-rate { margin: var(--space-2) 0 0; }
.calc-rate .calc-field { flex-wrap: wrap; gap: var(--space-1) var(--space-3); color: var(--text-muted); }
.calc-rate-q { font-weight: var(--label-weight); font-size: var(--text-lg); color: var(--text); }
.calc-rate-in { display: inline-flex; align-items: center; gap: var(--space-1); }
/* The figures: small, in a sentence, and plainly editable. */
.calc-field { display: inline-flex; align-items: center; gap: var(--space-1); min-block-size: var(--tap); cursor: text; }
.calc-field input {
  inline-size: 4.8ch; min-inline-size: 0; block-size: 2.25rem; padding: 0 var(--space-1);
  border: 0; border-block-end: 2px dashed var(--line-strong); border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  background: var(--bg); color: var(--text); font: inherit; font-weight: var(--label-weight);
  font-variant-numeric: tabular-nums; text-align: center;
  -moz-appearance: textfield; appearance: textfield;
}
.calc-field input::-webkit-outer-spin-button, .calc-field input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.calc-field input:hover { border-block-end-color: var(--text); }
.calc-field input:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-block-end-style: solid; }
.calc-dot { color: var(--line-strong); }
/* where the two figures no longer share a line, the dot between them goes */
@media (max-width: 359.98px) { .calc-dot { display: none; } }

/* The year, on graphite (he liked how it looks), a bar per task, the email under it. */
.calc-out {
  display: grid; gap: var(--space-3); align-content: start; min-inline-size: 0;
  padding: var(--space-5); border-radius: var(--radius-lg);
  background: var(--text); color: var(--bg);
}
.calc-big { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--space-3); }
.calc-big output {
  font-family: var(--font-display); font-stretch: var(--display-stretch); font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking); font-size: clamp(2.6rem, 13vw, 4.5rem); line-height: 1; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.calc-big span { font-size: var(--text-lg); }
.calc-human { color: color-mix(in oklch, var(--bg) 82%, var(--text)); font-size: var(--text-lg); text-wrap: pretty; }
.calc-bars { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: grid; gap: var(--space-3); }
.calc-bars:empty { display: none; }
.calc-bar { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-1) var(--space-3); align-items: baseline; }
.calc-bar-name { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: color-mix(in oklch, var(--bg) 82%, var(--text)); }
.calc-bar-hours { font-weight: var(--label-weight); font-variant-numeric: tabular-nums; }
.calc-bar-line { grid-column: 1 / -1; display: block; block-size: 6px; border-radius: var(--radius-pill); background: color-mix(in oklch, var(--bg) 18%, var(--text)); overflow: hidden; }
.calc-bar-line b { display: block; block-size: 100%; inline-size: 0; border-radius: inherit; background: var(--bg); transition: inline-size var(--motion); }
.calc-acts { margin: var(--space-3) 0 0; }
/* on graphite the focus ring is the page's bone, so it shows */
.calc-out .btn:focus-visible { outline: 3px solid var(--bg); outline-offset: 3px; }
.calc-out .btn { white-space: normal; text-wrap: balance; text-align: center; block-size: auto; padding-block: var(--space-2); }
@media (scripting: none) {
  .calc-form, .calc-big, .calc-human[data-out], .calc-bars { display: none; }
}
@media (min-width: 1024px) {
  .calc-body { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); column-gap: var(--space-8); align-items: start; }
  .calc-out { padding: var(--space-6); }
}

/* ---- H4: what we've built. The whole card follows its link. ---- */
.build { display: grid; gap: var(--space-6); }
.cards { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); }
.card {
  position: relative; display: grid;
  grid-template-areas: "art" "name" "line" "go"; grid-template-rows: auto auto 1fr auto;
  gap: var(--space-3); padding: 0 var(--space-5) var(--space-4); border-radius: var(--radius-lg); overflow: hidden;
  border: var(--joint) solid var(--line); background: var(--surface); color: var(--text);
  transition: transform var(--motion), box-shadow var(--motion);
}
.card:has(.card-go:hover) { transform: translateY(-2px); box-shadow: var(--shadow); }
.card:has(.card-go:focus-visible) { outline: 3px solid var(--focus); outline-offset: 3px; }
.card-art {
  grid-area: art; position: relative; display: block;
  margin: 0 calc(var(--space-5) * -1) var(--space-2);
  aspect-ratio: 4 / 3; overflow: hidden; background: var(--surface-2); border-block-end: var(--joint) solid var(--line);
}
.card-art > img { position: absolute; inset: 0; display: block; inline-size: 100%; block-size: 100%; object-fit: cover; }
/* The photo tools: the rough job site photo and the finished one, whole, side by side. */
.card-art-pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--joint); background: var(--line); }
.pair-half { position: relative; display: block; min-inline-size: 0; overflow: hidden; }
.pair-half img { position: absolute; inset: 0; display: block; inline-size: 100%; block-size: 100%; object-fit: cover; object-position: 50% 55%; }
.pair-tag {
  position: absolute; inset-block-start: var(--space-2); inset-inline-start: var(--space-2); padding: 0.125rem var(--space-2);
  border-radius: var(--radius-pill); background: color-mix(in oklch, var(--text) 78%, transparent); color: var(--bg);
  font-size: var(--text-md); font-weight: var(--label-weight); line-height: 1.5;
}
/* The floor plan the documents tool reads, as the portfolio shows it. */
.card-art-plan { background: var(--bg); }
.card-art-plan > img { object-fit: contain; padding: var(--space-3); }
.card-name {
  grid-area: name;
  font-family: var(--font-display); font-stretch: var(--display-stretch); font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking); font-size: var(--text-xl); line-height: var(--leading-tight); text-wrap: balance;
}
.card-line { grid-area: line; color: var(--text-muted); text-wrap: pretty; }
.card-go {
  grid-area: go; justify-self: start; display: inline-flex; align-items: center; min-block-size: var(--tap);
  font-weight: var(--label-weight); text-decoration: underline 2px var(--accent); text-underline-offset: 0.35em;
}
.card-go:focus-visible { outline: none; }
.card-go::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.card-go:hover { text-decoration-thickness: var(--space-1); }
/* The systems' own logos, all in one quiet tone, each in an equal cell. */
.card-art-logos { container-type: inline-size; display: grid; align-content: center; padding: var(--space-4) var(--space-5); background: var(--surface-2); }
/* (WinBooks is Exact WinBooks since Exact took it over; its own site carries Exact's mark, so Exact's logo
   stands for both.) Three to a row, the last row centred. */
.logos { --gap: clamp(1rem, 6cqi, 2.25rem); list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: clamp(0.75rem, 5cqi, 1.5rem) var(--gap); }
/* each logo in an equal cell, drawn whole inside it: a long wordmark by its width, a compact mark by its height */
.logos li { display: block; flex: 0 0 calc((100% - 2 * var(--gap)) / 3); block-size: clamp(1.5rem, 8.5cqi, 2.75rem); min-inline-size: 0; }
.logos img { display: block; inline-size: 100%; block-size: 100%; object-fit: contain; filter: grayscale(1) contrast(1.1); opacity: 0.85; mix-blend-mode: multiply; }
@media (min-width: 640px) and (max-width: 1023.98px) {
  /* a tall photo pair beside the two other cards */
  .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5); }
  .card-photos { grid-row: span 2; grid-template-rows: 1fr auto auto auto; }
  .card-photos .card-art { aspect-ratio: auto; min-block-size: 18rem; }
}
@media (min-width: 1024px) { .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-5); } }

/* ---- The before-and-after (compare.js; the homepage and the portfolio): the finished photo below,
   the job site photo above it, cut at the line. The line follows the scroll until the visitor's
   first touch (motion.js), then it is theirs: dragged, tapped or moved with the keys. ---- */
.compare {
  position: relative; overflow: hidden; isolation: isolate; container-type: inline-size;
  border-radius: var(--radius-lg); background: var(--surface-2);
  touch-action: pan-y; cursor: ew-resize; user-select: none; -webkit-user-select: none;
  --pos: 50%;
}
.compare img { display: block; inline-size: 100%; block-size: auto; pointer-events: none; }
.compare-before { position: absolute; inset: 0; clip-path: inset(0 calc(100% - var(--pos)) 0 0); }
.compare-before img { block-size: 100%; object-fit: cover; }
.compare-line {
  position: absolute; inset-block: 0; inset-inline-start: var(--pos); inline-size: 3px; translate: -50% 0;
  background: var(--bg); box-shadow: 0 0 0 1px color-mix(in oklch, var(--text) 30%, transparent);
  pointer-events: none;
}
.compare-line::after {
  content: ""; position: absolute; inset-block-start: 50%; inset-inline-start: 50%; translate: calc(-50% + clamp(calc(25px - var(--p, 50) * 1cqw), 0px, calc(100cqw - 25px - var(--p, 50) * 1cqw))) -50%;
  inline-size: var(--tap); block-size: var(--tap); border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--bg), var(--shadow);
  /* two small arrows: the line moves both ways */
  background-image: linear-gradient(135deg, transparent 46%, var(--on-accent) 46% 54%, transparent 54%), linear-gradient(45deg, transparent 46%, var(--on-accent) 46% 54%, transparent 54%), linear-gradient(45deg, transparent 46%, var(--on-accent) 46% 54%, transparent 54%), linear-gradient(135deg, transparent 46%, var(--on-accent) 46% 54%, transparent 54%);
  background-size: 9px 9px; background-repeat: no-repeat;
  background-position: 9px 13px, 9px 22px, 26px 13px, 26px 22px;
}
.compare-tag {
  position: absolute; inset-block-start: var(--space-3); padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill); background: color-mix(in oklch, var(--text) 78%, transparent); color: var(--bg);
  font-weight: var(--label-weight); pointer-events: none;
}
.compare-tag-before { inset-inline-start: var(--space-3); }
.compare-tag-after { inset-inline-end: var(--space-3); }
.compare-range {
  position: absolute; inset: 0; inline-size: 100%; block-size: 100%; margin: 0;
  opacity: 0; pointer-events: none; appearance: none; -webkit-appearance: none; background: transparent;
}
.compare:has(.compare-range:focus-visible) { outline: 3px solid var(--focus); outline-offset: 3px; }

/* ---- H5: a job site photo in, a finished photo out: the slider, larger, alone ---- */
.proof { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
.proof-say { display: grid; gap: var(--space-4); align-content: start; justify-items: start; }
.proof-say .display { max-inline-size: 16ch; }
.proof-say p { max-inline-size: 38ch; color: var(--text-muted); text-wrap: pretty; }
.proof-main {
  display: grid; gap: var(--space-3); margin: 0;
  inline-size: min(100%, 46rem, calc((100svh - var(--bar) - var(--space-7)) * 0.75));
}
.proof-main figcaption, .pair-compare figcaption { color: var(--text-muted); max-inline-size: 52ch; text-wrap: pretty; }
.proof-all { margin-block-start: var(--space-2); }
@media (min-width: 768px) { .proof-say p { font-size: var(--text-lg); } }
@media (min-width: 1024px) {
  .proof { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); column-gap: var(--space-8); align-items: start; }
  .proof-say { position: sticky; inset-block-start: calc(var(--bar) + var(--space-7)); }
  .proof-main { justify-self: center; }
}

/* ---- H6: how we work: four promises on a line that draws itself down ---- */
.how { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
.steps { list-style: none; margin: 0; padding: 0 0 0 var(--space-6); display: grid; gap: var(--space-6); position: relative; counter-reset: step; }
.steps::before {
  content: ""; position: absolute; inset-block: var(--space-2); inset-inline-start: var(--space-2); inline-size: 3px;
  border-radius: var(--radius-pill); background: var(--accent); transform-origin: top;
}
.step { display: grid; gap: var(--space-2); counter-increment: step; position: relative; }
.step::before {
  content: counter(step); position: absolute; inset-inline-start: calc(var(--space-6) * -1 - 0.28rem); inset-block-start: 0;
  display: grid; place-items: center; inline-size: 1.75rem; block-size: 1.75rem; border-radius: 50%;
  background: var(--bg); border: 3px solid var(--accent); font-size: 1rem; font-weight: var(--label-weight); line-height: 1;
}
.step-name {
  font-family: var(--font-display); font-stretch: var(--display-stretch); font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking); font-size: var(--text-xl); line-height: var(--leading-tight);
}
.step p { max-inline-size: 48ch; color: var(--text-muted); text-wrap: pretty; }
.how-steps { display: grid; gap: var(--space-6); justify-items: start; min-inline-size: 0; }
.how-act { margin: 0; padding-inline-start: var(--space-6); }
@media (min-width: 768px) { .step p { font-size: var(--text-lg); } .step-name { font-size: var(--text-2xl); } }
@media (min-width: 1024px) {
  .how { grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); column-gap: var(--space-8); align-items: start; }
}

/* ---- H7: the close: two doors of equal weight, each one line and one email ---- */
.doors-band { display: grid; gap: var(--space-7); }
.doors { display: grid; gap: var(--space-7); }
.door { display: grid; gap: var(--space-4); align-content: start; justify-items: start; }
.door + .door { padding-block-start: var(--space-7); border-block-start: var(--joint) solid var(--line-strong); }
.door-title { max-inline-size: 20ch; line-height: 1.05; }
.door p { max-inline-size: 40ch; color: var(--text-muted); text-wrap: pretty; }
.door .door-act { margin-block-start: var(--space-2); }
.doors-mail { margin: 0; }
@media (min-width: 768px) {
  .doors { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto auto auto; gap: 0; }
  .door { grid-row: span 3; grid-template-rows: subgrid; row-gap: var(--space-4); padding-inline-end: var(--space-7); }
  .door + .door { padding-block-start: 0; border-block-start: 0; padding-inline: var(--space-7) 0; border-inline-start: var(--joint) solid var(--line-strong); }
  .door p { font-size: var(--text-lg); }
  .door .door-act { align-self: end; }
}

/* ---- The motion switch in the footer ---- */
.motion-switch {
  display: inline-flex; align-items: center; gap: var(--space-2); min-block-size: var(--tap);
  padding: 0 var(--space-3); border: var(--joint) solid var(--line-strong); border-radius: var(--radius-pill);
  background: transparent; color: var(--text); font: inherit; cursor: pointer;
}
.motion-switch::before {
  content: ""; inline-size: 1.9rem; block-size: 1.1rem; border-radius: var(--radius-pill); flex: none;
  background: radial-gradient(circle at 0.55rem 50%, var(--bg) 0.4rem, transparent 0.42rem) var(--line-strong);
}
.motion-switch[aria-pressed="true"]::before {
  background: radial-gradient(circle at 1.35rem 50%, var(--bg) 0.4rem, transparent 0.42rem) var(--text);
}
.motion-switch:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
/* hidden until motion.js shows it: without scripts the switch could do nothing */
.motion-switch[hidden] { display: none; }

/* ---- The motif's pause button (motif.js adds it while the motif moves; WCAG 2.2.2) ---- */
.motif-pause {
  position: absolute; inset-block-end: var(--space-3); inset-inline-end: var(--space-3); z-index: 2;
  display: inline-flex; align-items: center; gap: var(--space-2); min-block-size: var(--tap); padding: 0 var(--space-4);
  border: 0; border-radius: var(--radius-pill); background: color-mix(in oklch, var(--text) 82%, transparent); color: var(--bg);
  font: inherit; font-weight: var(--label-weight); cursor: pointer;
}
.motif-pause:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

/* ---- Small arrivals, only where the browser ties animation to the scroll and nobody asked for
   less motion. Without that support every part simply stands. ---- */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    :root:not([data-motion="reduce"]) .card,
    :root:not([data-motion="reduce"]) .step {
      animation: rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 100%;
    }
    :root:not([data-motion="reduce"]) .steps::before {
      animation: draw-down linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 60%;
    }
    :root:not([data-motion="reduce"]) .top {
      animation: edge linear both;
      animation-timeline: scroll(root);
      animation-range: 0 8rem;
    }
  }
}
/* (no fading: text keeps its full contrast at every moment of an arrival) */
@keyframes rise { from { translate: 0 1.5rem; } }
@keyframes draw-down { from { transform: scaleY(0); } }
@keyframes edge { to { box-shadow: 0 1px 0 var(--line); } }

@media (prefers-reduced-motion: reduce) {
  .card { transition: none; }
}
:root[data-motion="reduce"] .card { transition: none; }
:root[data-motion="reduce"] .mark::before { animation: none; }

/* ---- The email panel (mail.js): every email button opens the visitor's mail app and shows this beside
   it, the address and a copy button that is an icon (a check once copied). ---- */
.mail-pop {
  position: absolute; z-index: 30; display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-1) var(--space-1) var(--space-1) var(--space-4); border: var(--joint) solid var(--line);
  border-radius: var(--radius-lg); background: var(--bg); color: var(--text); box-shadow: var(--shadow);
  font-weight: var(--label-weight); white-space: nowrap;
}
.mail-pop[hidden] { display: none; }
.mail-pop-addr { user-select: all; -webkit-user-select: all; }
.mail-pop-copy {
  display: grid; place-items: center; inline-size: var(--tap); block-size: var(--tap); flex: none;
  border: 0; border-radius: var(--radius-md); background: var(--surface-2); color: var(--text); cursor: pointer;
  transition: background-color var(--motion);
}
.mail-pop-copy:hover { background: var(--surface-3); }
.mail-pop-copy:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.mail-pop-copy svg { grid-area: 1 / 1; inline-size: 1.25rem; block-size: 1.25rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.mail-pop-copy .mail-pop-done { opacity: 0; }
.mail-pop.is-copied .mail-pop-copy svg:not(.mail-pop-done) { opacity: 0; }
.mail-pop.is-copied .mail-pop-done { opacity: 1; }
