
@font-face { font-family: "Atkinson Hyperlegible Next"; src: url("fonts/AtkinsonHyperlegibleNext-VF.0dbb46544a.woff2") format("woff2"); font-weight: 400 700; font-display: swap; }
@font-face { font-family: "Atkinson Hyperlegible Mono"; src: url("fonts/AtkinsonHyperlegibleMono-VF.3efedf93b3.woff2") format("woff2"); font-weight: 400 700; font-display: swap; }

/* Copyright Samuel Krauss (Elchi Studios). All rights reserved.
   SPDX-License-Identifier: LicenseRef-Proprietary */

/* Metric-matched fallbacks, written by fonts/fallbacks.py. */
@font-face { font-family: "Atkinson Fallback"; src: local("Arial"), local("Helvetica"), local("Liberation Sans"); font-weight: 400;
  size-adjust: 98.49%; ascent-override: 99.90%; descent-override: 32.08%; line-gap-override: 0.00%; }
@font-face { font-family: "Atkinson Fallback"; src: local("Arial Bold"), local("Helvetica Bold"), local("Liberation Sans Bold"); font-weight: 700;
  size-adjust: 99.28%; ascent-override: 99.11%; descent-override: 31.83%; line-gap-override: 0.00%; }
@font-face { font-family: "Atkinson Mono Fallback"; src: local("Courier New"), local("Courier"), local("Liberation Mono"); font-weight: 400;
  size-adjust: 105.32%; ascent-override: 93.43%; descent-override: 30.00%; line-gap-override: 0.00%; }

/* Elchi Studios design tokens. Written by build.py from tokens.py; do not edit. */
:root {
  color-scheme: light dark;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;
  --space-9: 6rem;
  --space-10: 8rem;
  --dur-press: 90ms;
  --dur-fast: 150ms;
  --dur-base: 240ms;
  --dur-slow: 600ms;
  --ease: cubic-bezier(.2, .77, .35, 1);
  --ease-in: cubic-bezier(.55, 0, .75, .3);
  --radius-0: 0;
  --radius-1: 2px;
  --radius-2: 4px;
  --radius-round: 999px;
  --font-sans: "Atkinson Hyperlegible Next", "Atkinson Fallback", Arial, sans-serif;
  --font-mono: "Atkinson Hyperlegible Mono", "Atkinson Mono Fallback", "Courier New", monospace;
}
:root {
  color-scheme: light;
  --c-page: #f6f7f9;
  --c-raised: #ffffff;
  --c-sunk: #eceef2;
  --c-text: #111621;
  --c-text-2: #394254;
  --c-text-3: #586176;
  --c-line: #d3d8e1;
  --c-line-strong: #111621;
  --c-rule: #111621;
  --c-control: #7d879a;
  --c-action: #0a6560;
  --c-action-fill: #0a6560;
  --c-action-strong: #074b47;
  --c-on-action: #ffffff;
  --c-action-wash: #e2f1ef;
  --c-focus: #0a6560;
  --c-ok: #3d6514;
  --c-warn: #8a5300;
  --c-danger: #b0261c;
  --c-danger-wash: #fbe9e7;
  --c-warn-wash: #fbf0dc;
  --c-chart-grid: #111621;
  --c-chart-star: #111621;
  --c-chart-figure: #0a6560;
  --c-chart-star-hot: #111621;
  --c-chart-star-cool: #111621;
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --c-page: #0a0e16;
  --c-raised: #121826;
  --c-sunk: #070a10;
  --c-text: #e7ecf4;
  --c-text-2: #b7c0cf;
  --c-text-3: #8d97aa;
  --c-line: #232c3c;
  --c-line-strong: #e7ecf4;
  --c-rule: #33405a;
  --c-control: #5d687d;
  --c-action: #62d3c6;
  --c-action-fill: #2f9488;
  --c-action-strong: #93e6dc;
  --c-on-action: #04201d;
  --c-action-wash: #0f2a2b;
  --c-focus: #62d3c6;
  --c-ok: #b7d77a;
  --c-warn: #f0b54a;
  --c-danger: #ff8f84;
  --c-danger-wash: #2e1414;
  --c-warn-wash: #2b2110;
  --c-chart-grid: #8fa3c4;
  --c-chart-star: #e9eef8;
  --c-chart-figure: #62d3c6;
  --c-chart-star-hot: #cfe0ff;
  --c-chart-star-cool: #ffe2bd;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --c-page: #0a0e16;
    --c-raised: #121826;
    --c-sunk: #070a10;
    --c-text: #e7ecf4;
    --c-text-2: #b7c0cf;
    --c-text-3: #8d97aa;
    --c-line: #232c3c;
    --c-line-strong: #e7ecf4;
    --c-rule: #33405a;
    --c-control: #5d687d;
    --c-action: #62d3c6;
    --c-action-fill: #2f9488;
    --c-action-strong: #93e6dc;
    --c-on-action: #04201d;
    --c-action-wash: #0f2a2b;
    --c-focus: #62d3c6;
    --c-ok: #b7d77a;
    --c-warn: #f0b54a;
    --c-danger: #ff8f84;
    --c-danger-wash: #2e1414;
    --c-warn-wash: #2b2110;
    --c-chart-grid: #8fa3c4;
    --c-chart-star: #e9eef8;
    --c-chart-figure: #62d3c6;
    --c-chart-star-hot: #cfe0ff;
    --c-chart-star-cool: #ffe2bd;
  }
}

/* Copyright Samuel Krauss (Elchi Studios). All rights reserved.
   SPDX-License-Identifier: LicenseRef-Proprietary */

/* Elchi Studios: base layer. Type, rhythm, links, focus, motion. */

*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scrollbar-gutter: stable;
  font-family: var(--font-sans);
  font-size: 100%;
  line-height: 1.55;
  color: var(--c-text);
  background-color: var(--c-page);
  font-variant-numeric: lining-nums;
  hanging-punctuation: first;
  scroll-padding-top: 5rem; /* targets and focus land below the sticky header (WCAG 2.4.11) */
}
body {
  margin: 0;
  min-height: 100dvh;
  font-size: 1.0625rem; /* 17 px: running text never below 16 */
  background-color: var(--c-page);
  color: var(--c-text);
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}
img, svg, video, canvas { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }
[hidden] { display: none !important; }
::selection { background-color: var(--c-action); color: var(--c-on-action); }

/* Page changes within one host: the header stays, the content fades. */
@view-transition { navigation: auto; }
.site-header { view-transition-name: header; }
main { view-transition-name: main; }
::view-transition-old(main) { animation: var(--dur-fast) var(--ease-in) both vt-out; }
::view-transition-new(main) { animation: var(--dur-base) var(--ease) both vt-in; }
@keyframes vt-out { to { opacity: 0; transform: translateY(-4px); } }
@keyframes vt-in { from { opacity: 0; transform: translateY(6px); } }

/* Headings: the type does the hierarchy. */
h1, h2, h3, h4 { margin: 0; line-height: 1.12; font-weight: 700; text-wrap: balance; letter-spacing: -0.01em; }
h1 { font-size: clamp(2.25rem, 1.5rem + 3vw, 4rem); letter-spacing: -0.02em; }
h2 { font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.125rem); }
h3 { font-size: 1.25rem; }
h4 { font-size: 1.0625rem; }
p, ul, ol, dl, blockquote, pre, table, figure { margin: 0; }
p, li { text-wrap: pretty; }
.flow > * + * { margin-block-start: var(--flow, 1em); }
.measure { max-width: 36em; } /* 60 to 75 characters at the base size; em, never ch */
.lede { font-size: clamp(1.125rem, 1rem + 0.5vw, 1.3125rem); color: var(--c-text-2); max-width: 32em; }
small, .small { font-size: 0.875rem; }
.muted { color: var(--c-text-2); }
.subtle { color: var(--c-text-3); }
.num, .tabular { font-variant-numeric: tabular-nums lining-nums; }
code, kbd, samp, pre, .mono { font-family: var(--font-mono); font-size: 0.9em; }
kbd { padding: 0 0.3em; border: 1px solid var(--c-line); border-bottom-width: 2px; border-radius: var(--radius-1); background-color: var(--c-raised); }
hr { border: 0; border-top: 1px solid var(--c-line); margin: var(--space-6) 0; }

/* Links: text links keep their underline (meaning never by colour alone);
   the underline darkens on hover. Single-line links in navigation draw a
   rule from the left instead (.link-rule in components.css). */
a { color: var(--c-action); text-decoration-line: underline; text-decoration-thickness: 1px; text-underline-offset: 0.18em; text-decoration-color: color-mix(in srgb, var(--c-action) 45%, transparent); transition: color var(--dur-fast) var(--ease), text-decoration-color var(--dur-fast) var(--ease); }
a:hover { color: var(--c-action-strong); text-decoration-color: currentColor; }

/* Focus: always visible on keyboard use, never removed. */
:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; border-radius: var(--radius-1); }
:focus:not(:focus-visible) { outline: none; }

/* Skip link: the first thing a keyboard reaches. */
.skip { position: absolute; inset-inline-start: var(--space-4); inset-block-start: -10rem; z-index: 100; padding: var(--space-2) var(--space-4); background-color: var(--c-text); color: var(--c-page); text-decoration: none; }
.skip:focus { inset-block-start: var(--space-3); }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* Layout: one column grid with a gutter that never lets text touch the edge. */
.wrap { width: min(100% - 2 * var(--gutter, 1rem), var(--wrap, 76rem)); margin-inline: auto; }
@media (min-width: 40rem) { :root { --gutter: 2rem; } }
.section { padding-block: var(--space-8); border-top: 1px solid var(--c-line); }
/* A thick rule opens a chapter: ink on paper. At night a white bar would be
   a stripe across the sky, so it is a hairline that starts in the action
   colour and fades into the line, like a trail. It draws across when the
   chapter comes into view (elchi.js). */
.section--open { position: relative; border-top: 0; }
.section--open::before, .site-footer::before { content: ""; position: absolute; inset-inline: 0; top: 0; height: 3px; background: var(--c-rule); transform-origin: left center; }
:root[data-theme="dark"] .section--open::before, :root[data-theme="dark"] .site-footer::before { height: 1px; background: linear-gradient(90deg, var(--c-action) 0, color-mix(in srgb, var(--c-action) 30%, var(--c-rule)) 30%, var(--c-rule) 70%); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .section--open::before, :root:not([data-theme="light"]) .site-footer::before { height: 1px; background: linear-gradient(90deg, var(--c-action) 0, color-mix(in srgb, var(--c-action) 30%, var(--c-rule)) 30%, var(--c-rule) 70%); }
}
.js .section--open.is-drawing::before { animation: rule-draw 900ms var(--ease) both; }
@keyframes rule-draw { from { transform: scaleX(0); } }

/* Coming into view: what starts below the fold fades and rises once as it
   is reached (elchi.js marks it .reveal, then .is-in). Without the script,
   with reduced motion or in print it is simply there. */
.reveal { opacity: 0; transform: translateY(18px); }
.reveal.is-in { opacity: 1; transform: none; transition: opacity 700ms var(--ease), transform 700ms var(--ease); }

/* The top of a page settles in on arrival: eyebrow, heading, lead, one
   after the other. Transform and opacity only, under a second in all. */
@media (prefers-reduced-motion: no-preference) {
  .js .page-hero > :not(.hero-sky), .js .dev-hero > :not(.hero-sky) { animation: settle 640ms var(--ease) both; }
  .js .page-hero > :nth-child(2), .js .dev-hero > :nth-child(2) { animation-delay: 70ms; }
  .js .page-hero > :nth-child(3), .js .dev-hero > :nth-child(3) { animation-delay: 140ms; }
  .js .page-hero > :nth-child(n+4):not(.hero-sky), .js .dev-hero > :nth-child(n+4):not(.hero-sky) { animation-delay: 210ms; }
}
@keyframes settle { from { opacity: 0; transform: translateY(10px); } }
.grid { display: grid; gap: var(--space-5); grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--min, 16rem)), 1fr)); }
.stack { display: flex; flex-direction: column; gap: var(--gap, var(--space-3)); }
.row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap, var(--space-3)); }

/* Density: the same components, tighter in consoles. */
.dense { --flow: 0.6em; font-size: 0.9375rem; }

/* Motion off when asked: no movement, every state change kept as colour. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-property: color, background-color, border-color, text-decoration-color, opacity, outline-color !important; scroll-behavior: auto !important; }
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; }
  @view-transition { navigation: none; }
}

@media print {
  :root { color-scheme: light; }
  .reveal { opacity: 1 !important; transform: none !important; }
  .site-header, .site-footer, .no-print { display: none !important; }
  a { color: inherit; }
}

/* A few utilities, so pages need no style attributes under the CSP. */
.mt-2 { margin-top: var(--space-2); } .mt-4 { margin-top: var(--space-4); } .mt-6 { margin-top: var(--space-6); }
.grid--13 { --min: 13rem; } .grid--18 { --min: 18rem; }
.w-60 { width: 60%; } .w-70 { width: 70%; } .w-80 { width: 80%; }

/* Copyright Samuel Krauss (Elchi Studios). All rights reserved.
   SPDX-License-Identifier: LicenseRef-Proprietary */

/* Elchi Studios: components. Every one has its states: normal, hover,
   focus, active, disabled, error, loading, empty, where they apply.

   The rule for motion: what can be used reacts like it can be used (press,
   hover, focus). What cannot be used never pretends to: no pointer, no
   lift, no link colour. It may reveal information instead (.fact, .anchor). */

/* ---------- Header and the product switcher ---------- */
.site-header { position: sticky; top: 0; z-index: 20; background-color: color-mix(in srgb, var(--c-page) 94%, transparent); border-bottom: 1px solid var(--c-line); transition: background-color var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease); }
/* Once the page moves under it, the header lifts: a soft shadow and the page blurred behind (elchi.js). */
.site-header.is-raised { background-color: color-mix(in srgb, var(--c-page) 82%, transparent); box-shadow: 0 10px 30px -22px rgb(0 0 0 / 0.55); -webkit-backdrop-filter: blur(12px) saturate(1.2); backdrop-filter: blur(12px) saturate(1.2); }
.site-header__in { display: flex; align-items: center; gap: var(--space-4); min-height: 3.75rem; }
.brand { display: inline-flex; white-space: nowrap; flex: none; align-items: center; gap: var(--space-2); color: var(--c-text); text-decoration: none; font-weight: 700; letter-spacing: -0.01em; }
.brand:hover { color: var(--c-text); }
.brand__mark { width: 1.75rem; height: 1.75rem; flex: none; }
.brand__logo { object-fit: contain; transition: transform var(--dur-base) var(--ease); }
.brand:hover .brand__logo { transform: rotate(-8deg) scale(1.06); } /* the spiral turns a little */
@media (prefers-reduced-motion: reduce) { .brand:hover .brand__logo { transform: none; } }
/* The constellation, the system's own sign, on the product switcher. */
.switcher__mark { width: 1.35rem; height: 1.35rem; }
.switcher__mark line { stroke: var(--c-action); stroke-width: 1.5; stroke-dasharray: 40; stroke-dashoffset: 0; }
.switcher__mark circle { fill: currentColor; }
.switcher__mark .ring { fill: none; stroke: currentColor; stroke-width: 1; }
.switcher-button:hover .switcher__mark line { animation: draw var(--dur-slow) var(--ease); }
.brand__mark line { stroke: var(--c-action); stroke-width: 1.4; transition: stroke-dashoffset var(--dur-slow) var(--ease); stroke-dasharray: 40; stroke-dashoffset: 0; }
.brand__mark circle { fill: var(--c-text); }
.brand__mark .ring { fill: none; stroke: var(--c-text); stroke-width: 1; }
.brand:hover .brand__mark line { animation: draw var(--dur-slow) var(--ease); } /* the constellation draws itself again */
@keyframes draw { from { stroke-dashoffset: 40; } }
.brand__product { font-weight: 400; color: var(--c-text-2); }
/* The narrowest phones keep the mark and the product; the company's name
   stays for screen readers. */
@media (max-width: 29.99rem) { .brand:has(.brand__product) .brand__name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } }
.nav { display: flex; gap: var(--space-1); margin-inline-start: auto; align-items: center; }
.nav a { position: relative; padding: var(--space-2) var(--space-3); color: var(--c-text-2); text-decoration: none; border-radius: var(--radius-1); }
.nav a::after, .link-rule::after { content: ""; position: absolute; inset-inline: var(--space-3); bottom: 0.3rem; height: 1px; background-color: currentColor; transform: scaleX(0); transform-origin: left; transition: transform var(--dur-base) var(--ease); }
.nav a:hover, .nav a[aria-current="page"] { color: var(--c-text); }
.nav a:hover::after, .nav a[aria-current="page"]::after, .link-rule:hover::after { transform: scaleX(1); }
.link-rule { position: relative; text-decoration: none; }
@media (max-width: 47.99rem) { .nav--wide { display: none; } }

/* Phones: one "Menü" button opens the links and the colour switch. */
.button.menu-button { display: none; margin-inline-start: auto; }
@media (max-width: 47.99rem) { .button.menu-button { display: inline-flex; } .site-header__in > .theme { display: none; } }
.menu { position: fixed; inset: 0 0 0 auto; margin: 0; width: min(20rem, 100vw); height: 100dvh; max-height: none; padding: var(--space-5); border: 0; border-inline-start: 1px solid var(--c-line); background-color: var(--c-raised); color: var(--c-text); transform: translateX(100%); transition: transform var(--dur-base) var(--ease), overlay var(--dur-base) allow-discrete, display var(--dur-base) allow-discrete; }
.menu:popover-open { transform: none; display: grid; align-content: start; gap: var(--space-5); }
@starting-style { .menu:popover-open { transform: translateX(100%); } }
.menu::backdrop { background-color: rgb(5 8 14 / 0.4); }
.menu nav { display: grid; }
.menu nav a { padding: var(--space-3) 0; border-bottom: 1px solid var(--c-line); color: var(--c-text); text-decoration: none; font-size: 1.125rem; }
.menu nav a:hover { color: var(--c-action); }

/* The switcher: a native popover, so it opens without JavaScript. Built
   for any number of products; it lists only those that exist. */
.switcher-button { flex: none; display: inline-grid; place-items: center; width: 2.75rem; height: 2.75rem; border: 1px solid transparent; border-radius: var(--radius-2); background: none; color: var(--c-text-2); transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), transform var(--dur-press) var(--ease); }
.switcher-button:hover { background-color: var(--c-sunk); color: var(--c-text); }
.switcher-button:active { transform: scale(0.94); }
.switcher-button svg { width: 1.25rem; height: 1.25rem; }
.switcher-button { anchor-name: --switcher; } /* the popover is placed under it where anchor positioning exists */
.switcher { position: fixed; inset: auto; top: 4.5rem; left: max(var(--gutter, 1rem), calc(50% - 38rem)); margin: 0; width: min(24rem, 100vw - 2rem); padding: var(--space-3); border: 1px solid var(--c-line); border-radius: var(--radius-2); background-color: var(--c-raised); color: var(--c-text); box-shadow: 0 12px 32px -12px rgb(0 0 0 / 0.25); opacity: 0; transform: translateY(-4px); transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), overlay var(--dur-base) allow-discrete, display var(--dur-base) allow-discrete; }
.switcher:popover-open { opacity: 1; transform: none; }
@supports (position-anchor: --switcher) { .switcher { position-anchor: --switcher; top: calc(anchor(bottom) + 6px); left: anchor(left); } }
@starting-style { .switcher:popover-open { opacity: 0; transform: translateY(-4px); } }
.switcher h2 { font-size: 0.8125rem; font-weight: 400; color: var(--c-text-3); margin: var(--space-2) var(--space-2) var(--space-3); }
.switcher ul { list-style: none; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-1); }
.switcher a { display: grid; grid-template-columns: auto 1fr; gap: 0 var(--space-3); align-items: center; padding: var(--space-3); border-radius: var(--radius-2); color: var(--c-text); text-decoration: none; transition: background-color var(--dur-fast) var(--ease); }
.switcher a:hover { background-color: var(--c-sunk); }
.switcher a:active { background-color: var(--c-action-wash); }
.switcher .star { grid-row: span 2; width: 0.625rem; height: 0.625rem; border-radius: 50%; background-color: var(--c-action); transition: transform var(--dur-base) var(--ease); }
.switcher a:hover .star { transform: scale(1.35); }
.switcher b { font-weight: 700; }
.switcher span:last-child { font-size: 0.8125rem; color: var(--c-text-3); }
.switcher[aria-current] a[aria-current="true"] { background-color: var(--c-action-wash); }

/* ---------- Theme switch: three words, not an icon ---------- */
.theme { display: inline-flex; border: 1px solid var(--c-line); border-radius: var(--radius-2); padding: 2px; margin: 0; }
.site-footer .theme { margin-top: var(--space-5); }
.site-header__in > .theme { margin-inline-start: auto; }
.nav + .theme { margin-inline-start: 0; }
.site-header__end { display: flex; align-items: center; gap: var(--space-3); margin-inline-start: auto; }
@media (max-width: 63.99rem) { .site-header__end .theme { display: none; } } /* the footer carries it; between phone and desk the header has no room */
.theme input { position: absolute; opacity: 0; pointer-events: none; }
.theme label { padding: 0.3rem 0.6rem; font-size: 0.8125rem; color: var(--c-text-2); border-radius: var(--radius-1); cursor: pointer; transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
.theme label:hover { color: var(--c-text); background-color: var(--c-sunk); }
.theme input:checked + label { background-color: var(--c-text); color: var(--c-page); }
.theme input:focus-visible + label { outline: 2px solid var(--c-focus); outline-offset: 1px; }
.no-js .theme { display: none; } /* without a script the system setting decides */

/* ---------- Buttons ---------- */
.button { --b-bg: var(--c-raised); --b-fg: var(--c-text); --b-line: var(--c-control); display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); min-height: 2.75rem; padding: 0.55rem 1.1rem; border: 1px solid var(--b-line); border-radius: var(--radius-2); background-color: var(--b-bg); color: var(--b-fg); font-weight: 600; line-height: 1.2; text-decoration: none; white-space: nowrap; user-select: none; transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), transform var(--dur-press) var(--ease); }
.button:hover { --b-bg: var(--c-sunk); color: var(--b-fg); }
.button:active { transform: scale(0.97); }
@media (max-width: 29.99rem) { .button { white-space: normal; text-align: center; } } /* a long label wraps on a small phone instead of leaving the screen */
.button--primary { --b-bg: var(--c-action-fill); --b-fg: var(--c-on-action); --b-line: var(--c-action-fill); }
.button--primary:hover { --b-bg: var(--c-action-strong); --b-line: var(--c-action-strong); }
/* The primary action rises a little under the pointer, and lands when pressed. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .button--primary { transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), box-shadow var(--dur-base) var(--ease); }
  .button--primary:hover { transform: translateY(-1px); box-shadow: 0 8px 20px -12px color-mix(in srgb, var(--c-action-fill) 80%, transparent); }
  .button--primary:active { transform: translateY(0) scale(0.97); box-shadow: none; }
}

/* A card that is a link shows where the pointer is: a soft wash of the
   action colour follows it (elchi.js sets --mx and --my). */
@media (hover: hover) {
  .spot { background-image: radial-gradient(28rem circle at var(--mx, 50%) var(--my, -30%), color-mix(in srgb, var(--c-action) 9%, transparent), transparent 60%); }
}
.button--quiet { --b-bg: transparent; --b-line: transparent; color: var(--c-action); }
.button--quiet:hover { --b-bg: var(--c-action-wash); }
.button--danger { --b-bg: var(--c-raised); --b-fg: var(--c-danger); --b-line: var(--c-danger); }
.button--danger:hover { --b-bg: var(--c-danger-wash); }
.button--small { min-height: 2.25rem; padding: 0.3rem 0.75rem; font-size: 0.875rem; }
.button:disabled, .button[aria-disabled="true"] { --b-bg: var(--c-sunk); --b-fg: var(--c-text-3); --b-line: var(--c-line); cursor: not-allowed; transform: none; }
.button[aria-busy="true"] { cursor: progress; color: transparent; position: relative; pointer-events: none; }
.button[aria-busy="true"]::after { content: ""; position: absolute; width: 1rem; height: 1rem; border: 2px solid var(--b-fg); border-right-color: transparent; border-radius: 50%; animation: spin 700ms linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .button[aria-busy="true"]::after { animation: none; border-right-color: var(--b-fg); opacity: 0.6; } }

/* ---------- Forms ---------- */
.field { display: grid; gap: var(--space-1); align-content: start; } /* rows never stretch: a neighbour with an error does not resize this field */
.field > label, .label { font-weight: 600; font-size: 0.9375rem; }
.hint { font-size: 0.875rem; color: var(--c-text-3); }
.input, .select, .textarea { width: 100%; min-height: 2.75rem; padding: 0.55rem 0.75rem; border: 1px solid var(--c-control); border-radius: var(--radius-2); background-color: var(--c-raised); color: var(--c-text); transition: border-color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease); }
.input::placeholder, .textarea::placeholder { color: var(--c-text-3); opacity: 1; }
.input:hover, .select:hover, .textarea:hover { border-color: var(--c-text-2); }
.input:focus-visible, .select:focus-visible, .textarea:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 0; border-color: var(--c-focus); }
.input:disabled, .select:disabled, .textarea:disabled { background-color: var(--c-sunk); color: var(--c-text-3); border-color: var(--c-line); cursor: not-allowed; }
.input[aria-invalid="true"], .select[aria-invalid="true"], .textarea[aria-invalid="true"] { border-color: var(--c-danger); border-width: 2px; padding: calc(0.55rem - 1px) calc(0.75rem - 1px); }
.textarea { min-height: 7rem; resize: vertical; line-height: 1.5; }
.select { appearance: none; padding-inline-end: 2.25rem; background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%); background-position: calc(100% - 1.15rem) 55%, calc(100% - 0.8rem) 55%; background-size: 0.35rem 0.35rem; background-repeat: no-repeat; }
.error { display: flex; gap: var(--space-2); align-items: baseline; color: var(--c-danger); font-size: 0.875rem; font-weight: 600; }
.error::before { content: ""; flex: none; width: 0.55em; height: 0.55em; background-color: currentColor; border-radius: 1px; align-self: center; forced-color-adjust: none; } /* a square: meaning by shape and word, not colour alone */
.check { display: flex; gap: var(--space-3); align-items: center; cursor: pointer; }
.check input { appearance: none; flex: none; width: 1.5rem; height: 1.5rem; margin: 0; border: 1px solid var(--c-control); border-radius: var(--radius-1); background-color: var(--c-raised); display: grid; place-content: center; transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), transform var(--dur-press) var(--ease); }
.check input[type="radio"] { border-radius: 50%; }
.check input::before { content: ""; width: 0.8rem; height: 0.8rem; transform: scale(0); transition: transform var(--dur-fast) var(--ease); background-color: var(--c-on-action); clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); }
.check input[type="radio"]::before { clip-path: circle(50%); width: 0.6rem; height: 0.6rem; }
.check:hover input:not(:checked) { border-color: var(--c-action); } /* a box answers the pointer over its label */
.check input:checked { background-color: var(--c-action-fill); border-color: var(--c-action-fill); }
.check input:checked::before { transform: scale(1); }
.check:hover input:not(:disabled) { border-color: var(--c-text-2); }
.check input:active { transform: scale(0.9); }
.check input:disabled { background-color: var(--c-sunk); border-color: var(--c-control); border-style: dashed; }
.check:has(input:disabled) { color: var(--c-text-3); cursor: not-allowed; }
.switch { display: inline-flex; gap: var(--space-3); align-items: center; cursor: pointer; }
.switch input { appearance: none; width: 2.5rem; height: 1.5rem; border-radius: var(--radius-round); border: 1px solid var(--c-control); background-color: var(--c-sunk); position: relative; transition: background-color var(--dur-fast) var(--ease); }
.switch input::before { content: ""; position: absolute; top: 2px; left: 2px; width: 1.1rem; height: 1.1rem; border-radius: 50%; background-color: var(--c-text-2); transition: transform var(--dur-base) var(--ease), background-color var(--dur-fast) var(--ease); }
.switch input:checked { background-color: var(--c-action-fill); border-color: var(--c-action-fill); }
.switch input:checked::before { transform: translateX(1rem); background-color: var(--c-on-action); }
.fieldset { border: 0; padding: 0; margin: 0; display: grid; gap: var(--space-2); }
.fieldset legend { font-weight: 600; margin-bottom: var(--space-2); }
.form { display: grid; gap: var(--space-5); max-width: 34rem; }
.form--grid { max-width: none; align-items: start; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); gap: var(--space-4) var(--space-5); }
.form--grid .full { grid-column: 1 / -1; }
.form-summary { display: grid; grid-template-columns: auto 1fr; gap: var(--space-3); align-items: baseline; padding: var(--space-3) var(--space-4); border: 1px solid color-mix(in srgb, var(--c-danger) 40%, transparent); border-radius: var(--radius-2); background-color: var(--c-danger-wash); }
.form-summary > * { grid-column: 2; min-width: 0; }
.form-summary::before { content: ""; grid-column: 1; grid-row: 1; width: 0.6em; height: 0.6em; background-color: var(--c-danger); border-radius: 1px; forced-color-adjust: none; }

/* ---------- Notices and status ---------- */
.notice { display: grid; grid-template-columns: auto 1fr; gap: var(--space-1) var(--space-3); padding: var(--space-4); border: 1px solid var(--c-line); border-radius: var(--radius-2); background-color: var(--c-raised); }
.notice::before { content: ""; width: 0.6em; height: 0.6em; margin-top: 0.5em; border-radius: 50%; background-color: var(--c-text-2); forced-color-adjust: none; }
.notice--warn { background-color: var(--c-warn-wash); border-color: color-mix(in srgb, var(--c-warn) 40%, transparent); }
.notice--warn::before { background-color: var(--c-warn); border-radius: 0; width: 0.7em; clip-path: polygon(50% 4%, 100% 96%, 0 96%); }
.notice--danger { background-color: var(--c-danger-wash); border-color: color-mix(in srgb, var(--c-danger) 40%, transparent); }
.notice--danger::before { background-color: var(--c-danger); border-radius: 1px; }
.notice > * { grid-column: 2; }
/* Status: shape and word first, colour third. Never a pulsing dot. The
   shapes are drawn, not typed: none of the typefaces carries them. */
.status { display: inline-flex; align-items: center; gap: 0.45em; font-weight: 600; white-space: nowrap; }
.status::before, .glyph { content: ""; flex: none; width: 0.6em; height: 0.6em; background-color: currentColor; forced-color-adjust: none; }
.status--ok { color: var(--c-ok); } .status--ok::before, .glyph--ok { border-radius: 50%; }
.status--warn { color: var(--c-warn); } .status--warn::before, .glyph--warn { clip-path: polygon(50% 4%, 100% 96%, 0 96%); width: 0.7em; }
.status--down { color: var(--c-danger); } .status--down::before, .glyph--down { border-radius: 1px; }
.status--idle { color: var(--c-text-3); } .status--idle::before, .glyph--idle { background-color: transparent; border: 2px solid currentColor; border-radius: 50%; }

/* ---------- Facts: numbers that carry their source ---------- */
/* Not clickable, so no pointer and no link colour. Hovering or focusing the
   value shows where it comes from. The note can be hovered itself (a bridge
   covers the gap), stays until the pointer or focus leaves, and Escape
   closes it (elchi.js). WCAG 1.4.13. Markup:
   <span class="fact"><span class="fact__value" tabindex="0" aria-describedby="n1">8</span><span class="fact__src" role="tooltip" id="n1">...</span></span> */
.fact { position: relative; display: inline-block; }
.fact__value { text-decoration: underline dotted; text-decoration-color: var(--c-text-3); text-decoration-thickness: 1px; text-underline-offset: 0.2em; cursor: help; transition: text-decoration-color var(--dur-fast) var(--ease); }
.fact:hover .fact__value, .fact__value:focus-visible { text-decoration-color: var(--c-action); }
.fact__src { display: none; translate: var(--shift, 0px) 0; position: absolute; z-index: 30; inset-block-start: calc(100% + 6px); inset-inline-start: 0; width: max-content; max-width: min(20rem, 80vw); padding: var(--space-2) var(--space-3); border: 1px solid var(--c-line); border-radius: var(--radius-2); background-color: var(--c-raised); color: var(--c-text-2); font-size: 0.8125rem; font-weight: 400; line-height: 1.45; letter-spacing: 0; text-align: start; white-space: normal; box-shadow: 0 8px 24px -12px rgb(0 0 0 / 0.3); opacity: 0; transform: translateY(-2px); transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), display var(--dur-fast) allow-discrete; }
.fact__src::before { content: ""; position: absolute; inset-inline: 0; inset-block-start: -8px; height: 8px; } /* the bridge */
/* Hidden notes take no space at all, so they never widen the page. */
.fact:hover .fact__src, .fact:focus-within .fact__src { display: block; opacity: 1; transform: none; }
@starting-style { .fact:hover .fact__src, .fact:focus-within .fact__src { opacity: 0; transform: translateY(-2px); } }
.fact.is-dismissed .fact__src { display: none; }

/* Headings offer their own address. */
.anchored { position: relative; }
.anchor { margin-inline-start: 0.4em; font-size: 0.6em; font-weight: 400; color: var(--c-text-3); text-decoration: none; opacity: 0; transition: opacity var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); vertical-align: middle; }
.anchored:hover .anchor, .anchor:focus-visible { opacity: 1; }
.anchor:hover { color: var(--c-action); }
.anchor[data-copied]::after { content: " kopiert"; }
:lang(en) .anchor[data-copied]::after { content: " copied"; }
@media (hover: none) { .anchor { opacity: 1; } }

/* ---------- Readings: a value with unit, date and source ---------- */
.reading { display: grid; gap: var(--space-1); padding-block: var(--space-4); border-top: 1px solid var(--c-rule); }
.reading__value { font-size: clamp(2rem, 1.6rem + 1.6vw, 3rem); font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.reading__unit { font-size: 0.45em; font-weight: 400; color: var(--c-text-2); margin-inline-start: 0.15em; letter-spacing: 0; }
.reading__label { color: var(--c-text-2); }
.reading__source { font-family: var(--font-mono); font-size: 0.75rem; color: var(--c-text-3); }

/* ---------- Tables, dense and calm ---------- */
.table-wrap { overflow-x: auto; border: 1px solid var(--c-line); border-radius: var(--radius-2); background-color: var(--c-raised); }
.table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }
.table th, .table td { padding: 0.6rem 0.9rem; text-align: start; border-bottom: 1px solid var(--c-line); vertical-align: top; }
.table th { position: sticky; top: 0; background-color: var(--c-sunk); font-weight: 600; font-size: 0.8125rem; color: var(--c-text-2); white-space: nowrap; }
.table tbody tr { transition: background-color var(--dur-fast) var(--ease); }
.table tbody tr:hover { background-color: color-mix(in srgb, var(--c-sunk) 70%, transparent); }
.table tbody tr:last-child td { border-bottom: 0; }
.table .mono, .table .nowrap { white-space: nowrap; }
.table .num { text-align: end; font-variant-numeric: tabular-nums; }
.table tr[aria-selected="true"] { background-color: var(--c-action-wash); }
.table a.row-link { color: var(--c-text); font-weight: 600; text-decoration: none; }
.table a.row-link::after { content: ""; position: absolute; inset: 0; } /* the whole row navigates */
.table tr:has(.row-link) { position: relative; }
.table tr:has(.row-link):hover .row-link { color: var(--c-action); text-decoration: underline; }
.table-empty { padding: var(--space-7) var(--space-4); text-align: center; color: var(--c-text-2); }
.sort { all: unset; cursor: pointer; display: inline-flex; gap: 0.4em; align-items: center; min-height: 1.5rem; }
.sort::after { content: ""; width: 0.5em; height: 0.65em; background-color: var(--c-text-3); clip-path: polygon(50% 0, 100% 40%, 0 40%, 0 60%, 100% 60%, 50% 100%); forced-color-adjust: none; }
th[aria-sort="ascending"] .sort::after { background-color: var(--c-text); clip-path: polygon(50% 0, 100% 60%, 0 60%); }
th[aria-sort="descending"] .sort::after { background-color: var(--c-text); clip-path: polygon(0 40%, 100% 40%, 50% 100%); }
.sort:hover { color: var(--c-text); }
.sort:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }

/* ---------- Code, keys and secrets ---------- */
.code { position: relative; border: 1px solid var(--c-line); border-radius: var(--radius-2); background-color: var(--c-sunk); }
.code pre { overflow-x: auto; padding: var(--space-4); padding-inline-end: 7rem; font-size: 0.875rem; line-height: 1.6; }
@media (max-width: 47.99rem) { .code pre { white-space: pre-wrap; overflow-wrap: anywhere; } }
.code__copy { position: absolute; top: var(--space-2); right: var(--space-2); }
.secret { display: grid; gap: var(--space-2); padding: var(--space-4); border: 1px solid var(--c-line-strong); border-radius: var(--radius-2); background-color: var(--c-raised); }
.secret__value { display: flex; gap: var(--space-2); align-items: center; padding: var(--space-2) var(--space-3); background-color: var(--c-sunk); border-radius: var(--radius-1); font-family: var(--font-mono); font-size: 0.9375rem; overflow-wrap: anywhere; }
.no-js .copy, .no-js .code__copy { display: none; }
.copy[data-copied] .copy__label { display: none; }
.copy[data-copied]::after { content: "Kopiert"; }
:lang(en) .copy[data-copied]::after { content: "Copied"; }

/* ---------- Tabs ---------- */
.tabs { display: flex; gap: var(--space-1); border-bottom: 1px solid var(--c-line); overflow-x: auto; }
.tabs a, .tabs button { padding: var(--space-2) var(--space-3); border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px; background: none; color: var(--c-text-2); text-decoration: none; white-space: nowrap; transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease); }
.tabs a:hover, .tabs button:hover { color: var(--c-text); border-bottom-color: var(--c-line); }
.tabs [aria-current="page"], .tabs [aria-selected="true"] { color: var(--c-text); border-bottom-color: var(--c-action); font-weight: 600; }

/* ---------- Lists that hold the one under the pointer ---------- */
.index { list-style: none; padding: 0; border-top: 1px solid var(--c-line); }
.index > li { border-bottom: 1px solid var(--c-line); }
.index a { display: grid; gap: var(--space-1); padding: var(--space-4) 0; color: var(--c-text); text-decoration: none; transition: color var(--dur-fast) var(--ease); }
.index__title { font-weight: 700; font-size: 1.125rem; line-height: 1.3; transition: color var(--dur-fast) var(--ease); }
.index .meta { color: var(--c-text-2); font-size: 0.9375rem; }
.index a:hover .index__title { color: var(--c-action); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
@media (hover: hover) {
  .index:hover > li > a { color: var(--c-text-2); }
  .index:hover > li > a:hover { color: var(--c-text); }
}

/* ---------- Dialog, toast, popover menu ---------- */
.dialog { width: min(34rem, 100vw - 2rem); padding: 0; border: 1px solid var(--c-line); border-radius: var(--radius-2); background-color: var(--c-raised); color: var(--c-text); box-shadow: 0 24px 64px -24px rgb(0 0 0 / 0.45); opacity: 0; transform: translateY(8px); transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), overlay var(--dur-base) allow-discrete, display var(--dur-base) allow-discrete; }
.dialog[open] { opacity: 1; transform: none; }
@starting-style { .dialog[open] { opacity: 0; transform: translateY(8px); } }
.dialog::backdrop { background-color: rgb(5 8 14 / 0); transition: background-color var(--dur-base) var(--ease), overlay var(--dur-base) allow-discrete, display var(--dur-base) allow-discrete; }
.dialog[open]::backdrop { background-color: rgb(5 8 14 / 0.5); }
@starting-style { .dialog[open]::backdrop { background-color: rgb(5 8 14 / 0); } }
.dialog__body { padding: var(--space-5); display: grid; gap: var(--space-4); }
.dialog__actions { display: flex; gap: var(--space-3); justify-content: flex-end; padding: var(--space-4) var(--space-5); border-top: 1px solid var(--c-line); background-color: var(--c-sunk); }
.toast { position: fixed; inset-block-end: var(--space-5); inset-inline-end: var(--space-5); z-index: 50; display: flex; gap: var(--space-3); align-items: center; padding: var(--space-3) var(--space-4); border-radius: var(--radius-2); background-color: var(--c-text); color: var(--c-page); box-shadow: 0 12px 32px -12px rgb(0 0 0 / 0.4); transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease); }
.toast[hidden] { display: flex !important; opacity: 0; transform: translateY(8px); pointer-events: none; }

/* ---------- Loading and empty ---------- */
.loading { display: inline-flex; gap: var(--space-2); align-items: center; color: var(--c-text-2); }
.loading::before { content: ""; width: 0.9rem; height: 0.9rem; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: spin 700ms linear infinite; }
.skeleton { display: block; height: 1em; border-radius: var(--radius-1); background-color: var(--c-sunk); }
.empty { display: grid; justify-items: start; gap: var(--space-3); padding: var(--space-6); border: 1px dashed var(--c-control); border-radius: var(--radius-2); }
.empty svg { width: 4rem; height: auto; color: var(--c-text-3); }

/* ---------- Environment banner (sandbox and live) ---------- */
.env { display: flex; gap: var(--space-3); align-items: center; justify-content: center; padding: 0.35rem var(--space-4); font-size: 0.8125rem; font-weight: 600; background-color: var(--c-warn-wash); color: var(--c-warn); border-bottom: 1px solid color-mix(in srgb, var(--c-warn) 40%, transparent); }
.env::before { content: ""; width: 0.7em; height: 0.6em; background-color: currentColor; clip-path: polygon(50% 4%, 100% 96%, 0 96%); forced-color-adjust: none; }

/* ---------- Flow diagram ----------
   A drawn path through a system (design/flow): boxes, lanes and arrows,
   coloured from the tokens so both modes come from the page. Wide on a
   desk, tall on a phone. It draws itself once when it comes into view
   (elchi.js adds .is-drawing); without JavaScript, or with reduced
   motion, it is simply there. Pointing at a lane shows its path in the
   action colour; nothing in it is a control. */
.flow { margin: 0; }
.flow-svg { display: block; width: 100%; height: auto; font-family: var(--font-sans); }
.flow-close { display: none; }
@media (max-width: 39.99rem) { .flow-wide { display: none; } .flow-close { display: block; } }
.flow-node rect { fill: var(--c-raised); stroke: var(--c-line-strong); stroke-opacity: 0.55; stroke-width: 1.2; transition: stroke var(--dur-fast) var(--ease), stroke-opacity var(--dur-fast) var(--ease); }
.flow-group { fill: var(--c-sunk); fill-opacity: 0.5; stroke: var(--c-line-strong); stroke-opacity: 0.35; stroke-dasharray: 5 5; stroke-width: 1; }
.flow-t { fill: var(--c-text); font-size: 15px; font-weight: 700; }
.flow-s { fill: var(--c-text-2); font-size: 13px; }
.flow-k { fill: var(--c-text-3); font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; }
.flow-tag { fill: var(--c-action-wash); }
.flow-tagt { fill: var(--c-action-strong); font-size: 12px; font-weight: 600; }
.flow-icon { fill: none; stroke: var(--c-action); stroke-width: 1.4; stroke-linejoin: round; }
.flow-edge { fill: none; stroke: var(--c-text-3); stroke-width: 1.5; stroke-linejoin: round; transition: stroke var(--dur-fast) var(--ease); }
.flow-edge--copy { stroke-dasharray: 4 4; }
.flow-head { fill: var(--c-text-3); transition: fill var(--dur-fast) var(--ease); }
.flow-lane:hover .flow-edge { stroke: var(--c-action); }
.flow-lane:hover .flow-head { fill: var(--c-action); }
.flow-lane:hover .flow-node rect { stroke: var(--c-action); stroke-opacity: 1; }
.flow figcaption { margin-top: var(--space-3); color: var(--c-text-3); font-size: 0.875rem; }
@media (prefers-reduced-motion: no-preference) {
  .flow.is-drawing .flow-edge:not(.flow-edge--copy) { stroke-dasharray: 1; animation: flow-draw var(--dur-slow) var(--ease) both; }
  .flow.is-drawing .flow-node, .flow.is-drawing .flow-head, .flow.is-drawing .flow-k, .flow.is-drawing .flow-group, .flow.is-drawing .flow-edge--copy { animation: flow-in var(--dur-base) var(--ease) both; }
  .flow.is-drawing .flow-d2 * { animation-delay: 450ms; }
  .flow.is-drawing .flow-d3 * { animation-delay: 900ms; }
  .flow.is-drawing .flow-d4 * { animation-delay: 1350ms; }
}
@keyframes flow-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes flow-in { from { opacity: 0; } }

/* ---------- Star chart ---------- */
.starchart { width: 100%; height: auto; }
.chart-close { display: none; }
@media (max-width: 39.99rem) { .chart-wide { display: none; } .chart-close { display: block; } }
.chart-grid path { fill: none; stroke: var(--c-chart-grid); stroke-opacity: 0.13; stroke-width: 0.7; }
.chart-stars .s { fill: var(--c-chart-star); }
.chart-stars .s-b { fill: var(--c-chart-star-hot); }
.chart-stars .s-y { fill: var(--c-chart-star-cool); }
.chart-figure line { stroke: var(--c-chart-figure); stroke-width: 1.5; transition: stroke-width var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease); }
.chart-figure .f-star { fill: var(--c-chart-figure); transition: transform var(--dur-base) var(--ease); transform-box: fill-box; transform-origin: center; }
.chart-figure .f-ring { fill: none; stroke: var(--c-chart-figure); stroke-width: 1.2; }
.chart-figure .f-hit { fill: transparent; }
/* On a phone the chart is scaled down; the targets around the stars grow so a finger still finds them (24 pixels at least). */
@media (max-width: 39.99rem) { .chart-figure .f-hit { r: 22px; } }
@media (max-width: 23.99rem) { .chart-figure .f-hit { r: 30px; } }
.f-label, .m-label { font-family: var(--font-sans); font-size: 13px; font-weight: 700; }
.f-label { fill: var(--c-chart-figure); paint-order: stroke; stroke: var(--c-page); stroke-width: 4px; stroke-linejoin: round; }
.chart-close .f-label { font-size: 21px; }
.m-label { fill: var(--c-text-2); paint-order: stroke; stroke: var(--c-page); stroke-width: 4px; }
.m-galaxy, .m-ring { fill: none; stroke: var(--c-text-2); stroke-width: 1.2; }
/* Each star of the figure is a link to its servers: pointing at one
   raises it and the connections that start there. */
.chart-figure a { cursor: pointer; text-decoration: none; }
.chart-figure a:hover .f-star, .chart-figure a:focus-visible .f-star { transform: scale(1.6); }
.chart-figure a:focus-visible .f-hit { stroke: var(--c-focus); stroke-width: 2; }
.chart-figure:has(a:hover, a:focus-visible) line { opacity: 0.35; }
.chart-figure:has(a:hover, a:focus-visible) line.is-on { opacity: 1; stroke-width: 2.5; }

/* ---------- Footer ---------- */
.site-footer { position: relative; margin-top: var(--space-9); padding-block: var(--space-7) var(--space-8); font-size: 0.9375rem; color: var(--c-text-2); }
.site-footer a { color: var(--c-text-2); }
.site-footer li a, .site-footer p a { display: inline-block; padding-block: 0.125rem; } /* 24 pixels tall at least, a finger finds them */
.site-footer a:hover { color: var(--c-text); }
.site-footer__cols { display: grid; gap: var(--space-5); grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); }
.site-footer h2 { font-size: 0.875rem; color: var(--c-text); margin-bottom: var(--space-3); }
.site-footer ul { list-style: none; padding: 0; display: grid; gap: var(--space-2); }
.coords { font-family: var(--font-mono); font-size: 0.75rem; color: var(--c-text-3); font-variant-numeric: tabular-nums; }

/* ---------- Prose: documentation, journal, legal texts ---------- */
.prose { max-width: 44em; font-size: 1.0625rem; line-height: 1.65; }
.prose > * + * { margin-top: 1em; }
.prose > h1 { font-size: clamp(2rem, 1.5rem + 2vw, 2.875rem); line-height: 1.08; }
.prose > h1 + p { font-size: 1.1875rem; color: var(--c-text-2); }
.prose h2 { margin-top: 2.4em; font-size: 1.5rem; scroll-margin-top: 5rem; }
.prose h3 { margin-top: 1.8em; font-size: 1.1875rem; scroll-margin-top: 5rem; }
.prose h4 { margin-top: 1.5em; }
.prose :is(h2, h3, h4) + * { margin-top: 0.6em; }
.prose :is(ul, ol) { padding-inline-start: 1.35em; }
.prose li + li { margin-top: 0.35em; }
.prose li::marker { color: var(--c-text-3); }
.prose strong { font-weight: 700; }
.prose :not(pre) > code { padding: 0.05em 0.35em; border: 1px solid var(--c-line); border-radius: var(--radius-1); background-color: var(--c-sunk); font-size: 0.875em; overflow-wrap: anywhere; }
.prose pre { overflow-x: auto; padding: var(--space-4); border: 1px solid var(--c-line); border-radius: var(--radius-2); background-color: var(--c-sunk); font-size: 0.875rem; line-height: 1.6; tab-size: 2; }
.prose pre code { font-size: inherit; }
.prose table { display: block; width: 100%; overflow-x: auto; border-collapse: collapse; border: 1px solid var(--c-line); border-radius: var(--radius-2); font-size: 0.9375rem; }
.prose :is(th, td) { padding: 0.55rem 0.8rem; text-align: start; vertical-align: top; border-bottom: 1px solid var(--c-line); }
.prose th { background-color: var(--c-sunk); font-size: 0.875rem; font-weight: 600; color: var(--c-text-2); }
.prose tr:last-child td { border-bottom: 0; }
.prose blockquote { padding-inline-start: var(--space-4); border-inline-start: 3px solid var(--c-rule); color: var(--c-text-2); }
.prose hr { margin-block: 2.5em; }
.prose img { border-radius: var(--radius-2); }
.prose figure figcaption { margin-top: var(--space-2); font-size: 0.875rem; color: var(--c-text-2); }
.prose .note { padding: var(--space-3) var(--space-4); border: 1px solid var(--c-line); border-inline-start: 3px solid var(--c-action); border-radius: var(--radius-2); background-color: var(--c-raised); }
.prose dl dt { font-weight: 700; margin-top: 1em; }
.prose dl dd { margin-inline-start: 0; color: var(--c-text-2); }

/* ---------- Status: uptime per day, figures, incidents ---------- */
.status-hero { display: grid; gap: var(--space-3); padding-block: var(--space-8) var(--space-6); }
.status-hero .status { font-size: 1.0625rem; }
.monitor__head { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: baseline; justify-content: space-between; margin-bottom: var(--space-4); }
.monitor__head h2 { font-size: 1.375rem; }
/* Ninety days, one bar each. Pointing at a bar shows its day; the same is
   said in numbers under the bars, so nothing depends on the colour or the
   pointer. */
.uptime { display: grid; grid-template-columns: repeat(90, 1fr); gap: 2px; height: 2.5rem; }
.uptime__day { position: relative; border-radius: 1px; background-color: var(--c-sunk); transition: transform var(--dur-fast) var(--ease); transform-origin: bottom; }
.uptime__day--ok { background-color: var(--c-ok); }
.uptime__day--part { background-color: var(--c-warn); }
.uptime__day--bad { background-color: var(--c-danger); }
.uptime__day--none { background-color: var(--c-line); }
.uptime__day:hover { transform: scaleY(1.12); }
.uptime__day i { display: none; position: absolute; z-index: 30; inset-block-end: calc(100% + 8px); inset-inline-start: 50%; translate: -50% 0; width: max-content; padding: var(--space-1) var(--space-2); border-radius: var(--radius-1); background-color: var(--c-text); color: var(--c-page); font-family: var(--font-mono); font-size: 0.75rem; font-style: normal; white-space: nowrap; pointer-events: none; }
.uptime__day:hover i { display: block; }
.uptime__day:nth-child(-n+12) i { translate: -10% 0; }
.uptime__day:nth-last-child(-n+12) i { translate: -90% 0; }
.uptime__axis { display: flex; justify-content: space-between; margin-top: var(--space-2); }
@media (max-width: 39.99rem) {
  .uptime { grid-template-columns: repeat(45, 1fr); grid-auto-rows: 1.1rem; height: auto; row-gap: 4px; }
  .uptime__axis { display: none; }
}
.figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 9.5rem), 1fr)); gap: var(--space-4) var(--space-5); margin-top: var(--space-5); }
.figures > div { display: grid; align-content: start; gap: 0.1rem; padding-top: var(--space-3); border-top: 1px solid var(--c-line); }
.figures dt { font-size: 0.875rem; color: var(--c-text-2); }
.figures dd { margin: 0; font-size: 1.5rem; font-weight: 700; font-variant-numeric: tabular-nums lining-nums; letter-spacing: -0.01em; }
.figures dd + dd { font-size: 0.875rem; font-weight: 400; letter-spacing: 0; }
.incidents { list-style: none; padding: 0; margin-top: var(--space-5); display: grid; }
.incident { display: grid; gap: var(--space-2); padding-block: var(--space-4); border-top: 1px solid var(--c-line); }
.incident h3 { font-size: 1.125rem; }
.incident--open { border-top: 3px solid var(--c-danger); }
.incident__body { white-space: pre-wrap; }

/* ---------- Single task pages: sign-in, consent, a notice ---------- */
/* One card in the middle of the paper, the footer under it. The card is
   narrow for a sign-in and wide for an account page. */
.solo { display: grid; grid-template-rows: 1fr auto; min-height: 100dvh; }
.solo > main { display: grid; place-items: center; padding: var(--space-6) var(--gutter, 1rem); }
.solo__card { width: min(100%, 26rem); display: grid; gap: var(--space-4); padding: var(--space-6); border: 1px solid var(--c-line); border-radius: var(--radius-2); background-color: var(--c-raised); }
.solo__card--wide { width: min(100%, 42rem); }
@media (max-width: 29.99rem) { .solo__card { padding: var(--space-5) var(--space-4); } }
.solo__card h1 { font-size: 1.625rem; letter-spacing: -0.015em; }
.solo__card h2 { font-size: 1.125rem; padding-top: var(--space-5); margin-top: var(--space-3); border-top: 1px solid var(--c-line); }
.solo__card h3 { margin-top: var(--space-4); }
.solo__card form { display: grid; gap: var(--space-4); }
.solo__card .actions { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.solo__card .actions > .button { flex: 1 1 auto; }
.solo__card--wide .actions > .button { flex: 0 0 auto; }
.solo__logo { max-height: 2.25rem; max-width: 9rem; width: auto; }
.solo__foot { display: grid; justify-items: center; gap: var(--space-3); padding: var(--space-5) var(--gutter, 1rem) var(--space-6); font-size: 0.8125rem; color: var(--c-text-3); text-align: center; }
.solo__foot a { color: var(--c-text-2); }
.solo__foot a:hover { color: var(--c-text); }
.solo__foot .theme { margin: 0; }
.secured { display: inline-flex; align-items: center; gap: var(--space-2); }
.secured .brand__mark, .secured img { width: 1.25rem; height: 1.25rem; }
.secured:hover .brand__mark line { animation: draw var(--dur-slow) var(--ease); }
.inline-links { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); justify-content: center; list-style: none; padding: 0; }
/* A link on its own line grows its target to 24 px without moving the text. */
.inline-links--start, .site-footer .inline-links { display: flex; justify-content: flex-start; }
.inline-links a, .solo__card .text-link { display: inline-block; padding-block: 0.2rem; }

/* "or" between two ways of doing the same thing. */
.or { display: flex; align-items: center; gap: var(--space-3); color: var(--c-text-3); font-size: 0.875rem; }
.or::before, .or::after { content: ""; flex: 1; height: 1px; background-color: var(--c-line); }

/* An application or organisation: its initial in a square, its name beside. */
.who { display: flex; gap: var(--space-3); align-items: center; }
.initial { display: grid; place-items: center; flex: none; width: 2.25rem; height: 2.25rem; border-radius: var(--radius-2); background-color: var(--c-action-fill); color: var(--c-on-action); font-weight: 700; line-height: 1; }
/* A choice that is a whole row: the chooser of organisations. */
.choice { display: flex; gap: var(--space-3); align-items: center; width: 100%; padding: var(--space-3); border: 1px solid var(--c-line); border-radius: var(--radius-2); background-color: var(--c-raised); color: var(--c-text); text-align: start; transition: border-color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease), transform var(--dur-press) var(--ease); }
.choice:hover { border-color: var(--c-text-2); background-color: var(--c-sunk); }
.choice:active { transform: scale(0.99); }
.choice b { display: block; }

/* Scopes and other short lists of what something may do. */
.ticks { list-style: none; padding: 0; display: grid; gap: var(--space-2); }
.ticks li { display: grid; grid-template-columns: auto 1fr; gap: var(--space-3); align-items: baseline; color: var(--c-text-2); }
.ticks li::before { content: ""; width: 0.7em; height: 0.45em; border-left: 2px solid var(--c-ok); border-bottom: 2px solid var(--c-ok); transform: translateY(-0.2em) rotate(-45deg); forced-color-adjust: none; }

/* Rows of things with an action each: sessions, passkeys, applications. */
.rows { list-style: none; padding: 0; border-top: 1px solid var(--c-line); }
.rows > li { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; justify-content: space-between; padding-block: var(--space-3); border-bottom: 1px solid var(--c-line); }
.rows > li > :first-child { flex: 1 1 14rem; min-width: 0; }
.rows > li:last-child { border-bottom: 0; }
.rows .meta { font-size: 0.875rem; color: var(--c-text-3); }
.solo__card .rows form { display: block; }

/* A small label beside a name: on, off, this device. */
.tag { display: inline-block; margin-inline-start: var(--space-2); padding: 0 0.45em; border: 1px solid var(--c-line); border-radius: var(--radius-1); font-family: var(--font-mono); font-size: 0.75rem; font-weight: 400; color: var(--c-text-2); vertical-align: 0.1em; }
.tag--ok { color: var(--c-ok); border-color: color-mix(in srgb, var(--c-ok) 45%, transparent); }

/* One-time codes and recovery codes. */
.input--code { font-family: var(--font-mono); letter-spacing: 0.25em; text-align: center; font-size: 1.25rem; }
.codes { list-style: none; display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-2) var(--space-5); padding: var(--space-4); border: 1px solid var(--c-line); border-radius: var(--radius-2); background-color: var(--c-sunk); font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.qr { width: 13.75rem; height: 13.75rem; padding: var(--space-2); border-radius: var(--radius-2); background-color: #fff; }
.avatar { width: 4rem; height: 4rem; border-radius: 50%; object-fit: cover; }
.grow { flex: 1 1 auto; min-width: 0; }

/* ---------- Windows contrast themes ---------- */
@media (forced-colors: active) {
  .check input:checked, .switch input:checked { background-color: Highlight; border-color: Highlight; }
  .check input::before { background-color: HighlightText; }
  .switch input::before { background-color: CanvasText; }
  .switch input:checked::before { background-color: HighlightText; }
  .theme input:checked + label { background-color: Highlight; color: HighlightText; forced-color-adjust: none; }
  .button--primary { border: 2px solid ButtonText; }
  .fact__src, .switcher, .menu, .dialog { border: 1px solid CanvasText; }
}

/* ---------- Pages: the top of a page, sections, languages ---------- */
/* Shared by the hub, websites, legal and every other public surface. */
.page-hero { position: relative; display: grid; gap: var(--space-4); padding-block: var(--space-8) var(--space-7); }
/* The constellation at the right of a page head (elchi.js), quiet enough
   to sit behind nothing: it only appears where the heading leaves room. */
.page-hero > :not(.hero-sky), .dev-hero > :not(.hero-sky) { position: relative; z-index: 1; }
.hero-sky { position: absolute; z-index: 0; inset-inline-end: 0; bottom: var(--space-5); width: clamp(13rem, 20vw, 18rem); height: auto; pointer-events: none; overflow: visible; opacity: 0.45; }
.hero-sky line { stroke: var(--c-chart-figure); stroke-width: 1.4px; vector-effect: non-scaling-stroke; stroke-linecap: round; }
.hero-sky circle { fill: var(--c-chart-star); transform-box: fill-box; transform-origin: center; }
@media (max-width: 63.99rem) { .hero-sky { display: none; } }
.page-hero > * { min-width: 0; }
.page-hero h1 { max-width: 18em; overflow-wrap: anywhere; hyphens: auto; }
.page-hero--narrow h1 { max-width: 14em; }
/* The eyebrow carries a short stroke in the action colour, the one mark
   every page and section shares; it draws in with its section. */
.eyebrow { display: flex; align-items: center; gap: 0.6em; font-size: 0.9375rem; font-weight: 600; color: var(--c-text-2); }
.eyebrow::before { content: ""; flex: none; width: 1.25rem; height: 2px; border-radius: 1px; background-color: var(--c-action); transform-origin: left center; }
@media (prefers-reduced-motion: no-preference) { .js .page-hero .eyebrow::before, .js .is-in.eyebrow::before, .js .is-in .eyebrow::before { animation: rule-draw 700ms 150ms var(--ease) both; } }
.eyebrow a { display: inline-block; padding-block: 0.2rem; color: inherit; text-decoration: none; }
.eyebrow a:hover { color: var(--c-action); text-decoration: underline; }
.section-head { display: grid; gap: var(--space-3); margin-bottom: var(--space-6); max-width: 44em; }
.section-head p { color: var(--c-text-2); }
.section-title { margin-bottom: var(--space-5); }
.more { display: inline-flex; align-items: center; gap: var(--space-2); margin-top: var(--space-5); font-weight: 600; }
.more::after { content: ""; width: 0.45em; height: 0.45em; border-top: 2px solid currentColor; border-right: 2px solid currentColor; transform: rotate(45deg); transition: transform var(--dur-base) var(--ease); }
.more:hover::after { transform: translateX(3px) rotate(45deg); }
.langs { display: flex; gap: 0; margin: 0; font-size: 0.875rem; }
.langs a { position: relative; display: inline-grid; place-items: center; min-width: 2.25rem; min-height: 2.25rem; padding: 0 var(--space-2); border-radius: var(--radius-1); color: var(--c-text-2); text-decoration: none; font-weight: 600; transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease); }
.langs a:hover { color: var(--c-text); background-color: var(--c-sunk); }
.langs a[aria-current] { color: var(--c-text); box-shadow: inset 0 -2px 0 var(--c-action); }
.langs abbr { text-decoration: none; }
@media (max-width: 22.49rem) { .site-header__end > .langs { display: none; } }

/* A table that becomes one block per row on a phone, each value under its
   column's name (data-label). */
@media (max-width: 39.99rem) {
  .table--stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .table--stack tr { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-2); padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--c-line); }
  .table--stack tbody tr:last-child { border-bottom: 0; }
  .table--stack th, .table--stack td { display: block; min-width: 0; padding: 0; border: 0; }
  .table--stack tbody th { position: static; white-space: normal; background: none; color: var(--c-text); font-size: inherit; }
  .table--stack code { overflow-wrap: anywhere; }
  .table--stack td::before { content: attr(data-label); display: block; font-size: 0.8125rem; font-weight: 600; color: var(--c-text-3); }
}

/* ---------- Small motion everywhere ----------
   Samuel's rule of 9 October 2026: every icon answers the pointer and
   text moves a little. Transform only, under 300 ms, nothing for reduced
   motion. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .ticks li::before { transition: transform var(--dur-base) var(--ease); }
  .ticks li:hover::before { transform: translateY(-0.2em) rotate(-45deg) scale(1.3); }
  .ticks li { transition: color var(--dur-fast) var(--ease), transform var(--dur-base) var(--ease); }
  .ticks li:hover { color: var(--c-text); transform: translateX(2px); }
  .index a .index__title, .index a .meta { display: inline-block; transition: transform var(--dur-base) var(--ease), color var(--dur-fast) var(--ease); }
  .index a:hover .index__title { transform: translateX(4px); }
  .index a:hover .meta { transform: translateX(2px); }
  .site-footer li a, .site-footer p a { display: inline-block; transition: color var(--dur-fast) var(--ease), transform var(--dur-base) var(--ease); }
  .site-footer li a:hover, .site-footer p a:hover { transform: translateX(3px); }
  .flow-node { transition: transform var(--dur-base) var(--ease); }
  .flow-node:hover { transform: translateY(-2px); }
  .reading:hover .reading__value { transform: translateY(-2px); }
  .reading__value { display: inline-block; transition: transform var(--dur-base) var(--ease); }
  .eyebrow::before { transition: width var(--dur-base) var(--ease); }
  .section-head:hover .eyebrow::before, .page-hero:hover .eyebrow::before { width: 2rem; }
  .brand:hover .brand__name { transform: translateX(2px); }
  .brand__name { display: inline-block; transition: transform var(--dur-base) var(--ease); }
}

/* ---------- More arrivals and answers (9 October 2026, second pass) ---------- */
/* Long reading carries a thin bar under the header that fills as the page
   is read (elchi.js inserts it where the text is long). */
.read-progress { position: fixed; inset: 0 0 auto 0; z-index: 30; height: 2px; background-color: var(--c-action); transform: scaleX(0); transform-origin: left center; pointer-events: none; }
@media print { .read-progress { display: none; } }
@media (prefers-reduced-motion: no-preference) {
  /* The menu's links come in one after another as it opens. */
  .menu:popover-open nav a { animation: settle 420ms var(--ease) both; }
  .menu:popover-open nav a:nth-child(2) { animation-delay: 40ms; }
  .menu:popover-open nav a:nth-child(3) { animation-delay: 80ms; }
  .menu:popover-open nav a:nth-child(4) { animation-delay: 120ms; }
  .menu:popover-open nav a:nth-child(5) { animation-delay: 160ms; }
  .menu:popover-open nav a:nth-child(n+6) { animation-delay: 200ms; }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .menu nav a { transition: color var(--dur-fast) var(--ease), padding-inline-start var(--dur-base) var(--ease); }
  .menu nav a:hover { padding-inline-start: var(--space-2); }
  /* The other buttons answer too: the outline takes the action colour. */
  .button:not(.button--primary):not(.button--quiet):not(.button--danger):hover { --b-line: var(--c-action); }
  /* Links in running text: the underline grows under the pointer. */
  .prose a, .lede a { transition: color var(--dur-fast) var(--ease), text-decoration-thickness var(--dur-fast) var(--ease), text-underline-offset var(--dur-fast) var(--ease); }
  .prose a:hover, .lede a:hover { text-decoration-thickness: 2px; text-underline-offset: 0.24em; }
  /* Table rows nudge their first cell, so a row reads as one line. */
  .table tbody tr > :first-child { transition: transform var(--dur-base) var(--ease); }
  .table tbody tr:hover > :first-child { transform: translateX(3px); }
  /* Code blocks and wells lift their border under the pointer. */
  .code { transition: border-color var(--dur-fast) var(--ease); }
  .code:hover { border-color: var(--c-control); }
}
/* The ninety days of a monitor sweep in from the left when they arrive,
   wherever they first show. */
@media (prefers-reduced-motion: no-preference) {
  .js .uptime { animation: wipe 1100ms 150ms var(--ease) backwards; } /* no fill after: a clip would cut the days' notes */
}
@keyframes wipe { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
