/* Regensbot app stylesheet: the regensbot.de look for app.regensbot.de.
   GENERATED by design-kit/tools/build.mjs from tokens.css + fonts.css + components.css.
   Do not edit by hand. Built for the CSP "default-src 'self'; frame-ancestors 'none';
   form-action 'self' https:": no inline styles, no external hosts, no data: URIs.
   Fonts are loaded from ../fonts/ relative to this file (see README.md, "Install"). */

/* ═══ tokens.css ═══ */

/* ──────────────────────────────────────────────────────────────────────────────
   Regensbot design tokens ("The Instrument"), for app.regensbot.de.
   Source of truth: regensbot-website/src/app/globals.css. Same names, same values.

   Theme
   - Dark is the house theme and the default (:root).
   - The app follows the visitor's system setting: prefers-color-scheme: light switches
     to "paper", unless the page pins dark with <html data-theme="dark">.
   - data-theme="light" on <html> (or any element) forces paper; data-theme="dark" forces dark.

   Contrast (WCAG 2.2, measured on --bg and on a card):
     dark   fg 18:1 · fg-2 10:1 · fg-3 5.8:1 · fail-ink 7.6:1 · lime 17:1
     paper  fg 18:1 · fg-2 12:1 · fg-3 5.4:1 · fail-ink 5.6:1 · accent-ink 6.6:1 (6.2:1 on --card, 5.4:1 on the notice tint)
   Signal lime is the only brand accent. On paper it is a fill only (ink text on it);
   small accent text on paper uses --accent-ink.
   Verdict colours are data colours: dots, bars and fills, never small text on paper.
   No url(), no data: URIs here: the app's CSP is default-src 'self'.
   ────────────────────────────────────────────────────────────────────────────── */

:root,
[data-theme="dark"] {
  /* Surfaces and text */
  --bg: #050607;
  --bg-2: #0b0d10;
  --bg-3: #14171c;
  --fg: #eef0f3;
  --fg-2: #b6bdc9;
  --fg-3: #858d9c;
  --line: rgb(238 240 243 / 0.1);
  --line-strong: rgb(238 240 243 / 0.24);
  --glass: rgb(238 240 243 / 0.035);
  --glass-strong: rgb(238 240 243 / 0.06);
  --card: #0d0e0f; /* glass over bg, opaque (cards can scroll) */
  --scroll-shade: rgb(238 240 243 / 0.22);

  /* Accent */
  --accent: #d4ff3f;
  --accent-ink: #d4ff3f;
  --on-accent: #050607;
  --accent-soft: rgb(212 255 63 / 0.12);

  /* Form fields: the boundary is fg-3 (5.8:1, above the 3:1 for UI components) */
  --field-bg: rgb(238 240 243 / 0.03);
  --field-border: #858d9c;
  --field-border-hover: #b6bdc9;

  /* Text-safe status inks (small text on bg and cards) */
  --fail-ink: #ff7a6b;
  --warn-ink: #ffb224;
  --pass-ink: #d4ff3f;
  --manual-ink: #8fa2ff;
  --error-ink: #ff5fd2;

  /* Verdict dots: a soft glow on ink, a thin ring on paper */
  --dot-ring: transparent;
  --dot-glow: 10px;

  /* Focus */
  --focus: #d4ff3f;

  /* Elevation */
  --shadow: 0 40px 120px -40px rgb(0 0 0 / 0.9);
  --shadow-card: 0 1px 0 0 rgb(238 240 243 / 0.04) inset, 0 24px 60px -32px rgb(0 0 0 / 0.8);
  --glow-accent: 0 0 0 1px rgb(212 255 63 / 0.55), 0 0 40px -8px rgb(212 255 63 / 0.35);

  color-scheme: dark;
}

/* Paper, forced */
[data-theme="light"] {
  --bg: #f3f4ef;
  --bg-2: #e9ebe4;
  --bg-3: #dee1d6;
  --fg: #07080a;
  --fg-2: #2b2f35;
  --fg-3: #5a606a;
  --line: rgb(7 8 10 / 0.12);
  --line-strong: rgb(7 8 10 / 0.28);
  --glass: rgb(7 8 10 / 0.03);
  --glass-strong: rgb(7 8 10 / 0.055);
  --card: #ecede8;
  --scroll-shade: rgb(7 8 10 / 0.22);
  --accent: #d4ff3f;
  --accent-ink: #445f00;
  --on-accent: #07080a;
  --accent-soft: rgb(77 107 0 / 0.1);
  --field-bg: #fbfbf8;
  --field-border: #5a606a;
  --field-border-hover: #2b2f35;
  --fail-ink: #b42318;
  --warn-ink: #8a5300;
  --pass-ink: #445f00;
  --manual-ink: #3346c4;
  --error-ink: #a3127f;
  --dot-ring: rgb(7 8 10 / 0.45);
  --dot-glow: 0px;
  --focus: #07080a;
  --shadow: 0 40px 100px -40px rgb(20 30 0 / 0.35);
  --shadow-card: 0 1px 0 0 rgb(255 255 255 / 0.6) inset, 0 24px 60px -36px rgb(20 30 0 / 0.25);
  --glow-accent: 0 0 0 1px #445f00, 0 0 40px -10px rgb(68 95 0 / 0.35);
  color-scheme: light;
}

/* Paper, from the system setting (same values as above; CSS cannot share a block
   between a media query and a selector). */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg: #f3f4ef;
    --bg-2: #e9ebe4;
    --bg-3: #dee1d6;
    --fg: #07080a;
    --fg-2: #2b2f35;
    --fg-3: #5a606a;
    --line: rgb(7 8 10 / 0.12);
    --line-strong: rgb(7 8 10 / 0.28);
    --glass: rgb(7 8 10 / 0.03);
    --glass-strong: rgb(7 8 10 / 0.055);
    --card: #ecede8;
    --scroll-shade: rgb(7 8 10 / 0.22);
    --accent: #d4ff3f;
    --accent-ink: #445f00;
    --on-accent: #07080a;
    --accent-soft: rgb(77 107 0 / 0.1);
    --field-bg: #fbfbf8;
    --field-border: #5a606a;
    --field-border-hover: #2b2f35;
    --fail-ink: #b42318;
    --warn-ink: #8a5300;
    --pass-ink: #445f00;
    --manual-ink: #3346c4;
    --error-ink: #a3127f;
    --dot-ring: rgb(7 8 10 / 0.45);
    --dot-glow: 0px;
    --focus: #07080a;
    --shadow: 0 40px 100px -40px rgb(20 30 0 / 0.35);
    --shadow-card: 0 1px 0 0 rgb(255 255 255 / 0.6) inset, 0 24px 60px -36px rgb(20 30 0 / 0.25);
    --glow-accent: 0 0 0 1px #445f00, 0 0 40px -10px rgb(68 95 0 / 0.35);
    color-scheme: light;
  }
}

/* Theme-independent tokens */
:root {
  /* Fixed brand colours */
  --ink: #050607;
  --ink-2: #0b0d10;
  --paper: #f3f4ef;
  --signal: #d4ff3f;

  /* Verdicts: the same in both themes (fills, dots, bars, large type) */
  --color-fail: #ff5a47;
  --color-warn: #ffb224;
  --color-pass: #d4ff3f;
  --color-manual: #8fa2ff;
  --color-skip: #6b7383;
  --color-error: #ff5fd2;
  /* The app's two extra statuses, drawn as hollow rings in a sibling colour */
  --color-pending: #ffb224; /* pending_confirmation: a suspected problem a person confirms */
  --color-na: #6b7383; /* not_applicable */

  /* Fonts (self-hosted, see fonts.css) */
  --font-display: "Geist", "Geist Fallback", "Helvetica Neue", Arial, sans-serif;
  --font-sans: "Geist", "Geist Fallback", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
  --font-serif: "Instrument Serif", "Instrument Serif Fallback", "Times New Roman", Georgia, serif;

  /* Type scale (fluid where the site is fluid) */
  --text-2xs: 0.625rem; /* nav numbers */
  --text-xs: 0.6875rem; /* verdict chips, table heads */
  --text-kicker: 0.75rem; /* [RB: 01] */
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-md: 1.0625rem;
  --text-lg: clamp(1.125rem, 1.4vw, 1.4rem); /* .lead */
  --text-xl: clamp(1.3rem, 1.8vw, 1.875rem); /* .t-4, h2 */
  --text-2xl: clamp(1.6rem, 2.8vw, 3rem); /* .t-3 */
  --text-3xl: clamp(2.1rem, 4.5vw, 5rem); /* .t-2, h1 */
  --text-4xl: clamp(2.6rem, 6.4vw, 7.25rem); /* .t-1 */

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;

  --leading-display: 0.98;
  --leading-heading: 1.08;
  --leading-body: 1.55;
  --leading-tight: 1.3;

  --tracking-display: -0.045em;
  --tracking-heading: -0.03em;
  --tracking-body: -0.006em;
  --tracking-serif: -0.02em;
  --tracking-kicker: 0.06em;

  /* Spacing (4px base) */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;

  /* Layout */
  --wrap-max: 104rem;
  --gutter: clamp(1rem, 3.6vw, 3.5rem);
  --main-max: 76rem;
  --main-narrow: 34rem;
  --main-prose: 48rem;
  --card-pad: clamp(1.25rem, 2.6vw, 2.25rem);
  --header-h: 4.25rem;
  --control-h: 2.75rem;
  --control-h-sm: 2.25rem;

  /* Radii */
  --radius-xs: 0.3rem;
  --radius-sm: 0.5rem;
  --radius-md: 0.875rem;
  --radius-lg: 1.25rem;
  --radius-pill: 999px;

  /* Lines */
  --hairline: 1px;
  --rule: 1px solid var(--line);
  --rule-strong: 1px solid var(--line-strong);

  /* Focus ring */
  --focus-width: 2px;
  --focus-offset: 3px;
  --focus-ring: var(--focus-width) solid var(--focus);

  /* Motion */
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-in-out-quart: cubic-bezier(0.76, 0, 0.24, 1);
  --ease-in-out-expo: cubic-bezier(0.87, 0, 0.13, 1);
  --dur-fast: 200ms;
  --dur: 400ms;
  --dur-slow: 600ms;
}

/* ═══ fonts.css ═══ */

/* ──────────────────────────────────────────────────────────────────────────────
   Self-hosted fonts (SIL OFL 1.1, see ../fonts/LICENSE-fonts.md). Latin subset:
   covers ä ö ü ß é and €. No third-party host: the app's CSP is default-src 'self',
   and a German site must not load fonts from someone else's server without consent.

   The URLs are relative to this stylesheet: the woff2 files live in ../fonts/.
   In the app that means app.css at /static/app.css and the fonts at /fonts/*.woff2
   (or app.css at /static/css/app.css and the fonts at /static/fonts/). See README.

   The "… Fallback" faces resize a local system font to the web font's metrics
   (the values next/font computes for regensbot.de), so the swap does not shift layout.
   ────────────────────────────────────────────────────────────────────────────── */

@font-face {
  font-family: "Geist";
  src: url("../fonts/geist-wght.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Geist Mono";
  src: url("../fonts/geist-mono-wght.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Instrument Serif";
  src: url("../fonts/instrument-serif-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
  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;
}

/* Metric-matched fallbacks (local fonts only, no download) */
@font-face {
  font-family: "Geist Fallback";
  src: local("Arial");
  ascent-override: 94.56%;
  descent-override: 27.76%;
  line-gap-override: 0%;
  size-adjust: 106.28%;
}

@font-face {
  font-family: "Instrument Serif Fallback";
  src: local("Times New Roman");
  font-style: italic;
  ascent-override: 111.52%;
  descent-override: 34.92%;
  line-gap-override: 0%;
  size-adjust: 88.77%;
}

/* ═══ components.css ═══ */

/* ──────────────────────────────────────────────────────────────────────────────
   Regensbot app components: the regensbot.de look for app.regensbot.de.
   Styles the markup the app's Jinja templates already emit (base.html, _macros.html,
   web/templates/*.html, oauth/templates/*.html). No class or wrapper is required that
   the templates do not have; optional hooks (.verdict, .danger, .skip-link, em in
   headings, .pagination) are listed in TEMPLATE-CHANGES.md.

   CSP: default-src 'self'. Nothing here loads from another host or uses data: URIs;
   every ornament is drawn with borders, gradients and generated content.
   No JavaScript is needed or assumed.
   ────────────────────────────────────────────────────────────────────────────── */

/* ── 1. Base ─────────────────────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--bg);
  color: var(--fg);
  scrollbar-gutter: stable;
  interpolate-size: allow-keywords;
}

body {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  letter-spacing: var(--tracking-body);
  background: var(--bg);
  color: var(--fg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-kerning: normal;
  overflow-x: clip;
}

/* The measurement grid behind the top of every page (hairlines every 4rem, fading out). */
body::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  z-index: -1;
  height: min(46rem, 90vh);
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: 4rem 4rem;
  background-position: center top;
  opacity: 0.55;
  -webkit-mask-image: radial-gradient(120% 100% at 50% 0%, #000 0%, transparent 72%);
  mask-image: radial-gradient(120% 100% at 50% 0%, #000 0%, transparent 72%);
}

/* A part of the page pinned to the other theme (data-theme on a section) paints its own ground. */
[data-theme]:not(html) {
  color: var(--fg);
}
/* A pinned card keeps its own --card ground, so its scroll-shadow covers match the base colour. */
[data-theme]:not(html, .card) {
  background-color: var(--bg);
}

::selection {
  background: var(--accent);
  color: var(--on-accent);
}

:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
  border-radius: 2px;
}
:focus:not(:focus-visible) {
  outline: none;
}

img,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

h1,
h2,
h3,
h4 {
  text-wrap: balance;
  color: var(--fg);
}
p,
li,
dd {
  text-wrap: pretty;
}

p {
  margin: 0 0 1rem;
  color: var(--fg-2);
}

strong,
b {
  font-weight: var(--weight-semibold);
  color: var(--fg);
}

small {
  font-size: var(--text-sm);
}

hr {
  height: 1px;
  margin: var(--space-8) 0;
  border: 0;
  background: var(--line);
}

[hidden] {
  display: none !important;
}

/* Links: real underlines in running text (WCAG 1.4.1), hairline-thin like the site. */
a {
  color: var(--fg);
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  text-decoration-color: color-mix(in oklab, currentColor 38%, transparent);
  transition:
    color var(--dur) var(--ease-out-expo),
    text-decoration-color var(--dur) var(--ease-out-expo);
}
a:hover {
  text-decoration-color: currentColor;
}
a:visited {
  color: var(--fg);
}

ul,
ol {
  margin: 0 0 1rem;
  padding-left: 1.25rem;
  color: var(--fg-2);
}
li {
  margin: 0.3rem 0;
  padding-left: 0.25rem;
}
li::marker {
  color: var(--fg-3);
}
ol > li::marker {
  font-family: var(--font-mono);
  font-size: 0.8125em;
}
li > ul,
li > ol {
  margin: 0.35rem 0 0;
}

/* ── 2. Site primitives (same names as regensbot.de, for new markup) ───────── */

.display {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  line-height: 0.92;
  letter-spacing: var(--tracking-display);
}
.serif,
:is(h1, h2, h3) em {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-serif);
}
.lead {
  font-size: var(--text-lg);
  line-height: 1.5;
  letter-spacing: -0.012em;
}
.kicker {
  font-family: var(--font-mono);
  font-size: var(--text-kicker);
  line-height: var(--leading-tight);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
}
.mono {
  font-family: var(--font-mono);
  font-feature-settings: "zero" on;
}
.tabular {
  font-variant-numeric: tabular-nums;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Skip link (optional, see TEMPLATE-CHANGES.md): <a class="skip-link" href="#main"> */
.skip-link {
  position: absolute;
  left: var(--gutter);
  top: 0.75rem;
  z-index: 100;
  padding: 0.6rem 1rem;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--on-accent);
  font-weight: var(--weight-medium);
  text-decoration: none;
  transform: translateY(-200%);
}
.skip-link:focus-visible,
.skip-link:focus {
  transform: none;
  color: var(--on-accent);
}

/* ── 3. Shell: header ────────────────────────────────────────────────────── */

/* The header is keyed to its content, not to one width: brand left and nav right while the nav
   fits beside the brand; when it does not (German labels, laptops, phones), the whole nav drops
   to a second row and starts under the brand (space-between puts a lone item at the start).
   Nothing is ever forced onto one line, so nothing can run off the screen. */
header.top {
  position: relative;
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  column-gap: var(--space-6);
  row-gap: var(--space-2);
  min-height: var(--header-h);
  padding-block: var(--space-3);
  padding-inline: max(var(--gutter), calc((100% - var(--wrap-max)) / 2 + var(--gutter)));
  border-bottom: var(--rule);
  background: color-mix(in oklab, var(--bg) 82%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(1.2);
  backdrop-filter: blur(18px) saturate(1.2);
}

/* Wordmark: lowercase Geist, tight, with the 16-segment ring and the lime dot drawn in CSS. */
header.top .brand {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  min-height: 2.75rem;
  padding: 0.25rem 0;
  color: var(--fg);
  font-size: 1.3rem;
  font-weight: var(--weight-semibold);
  line-height: 1;
  letter-spacing: -0.05em;
  text-transform: lowercase;
  text-decoration: none;
  white-space: nowrap;
}
header.top .brand::before {
  content: "";
  flex: none;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background:
    radial-gradient(circle, var(--accent) 0 0.16rem, transparent 0.17rem),
    conic-gradient(
      transparent 0deg 2.5deg,
      color-mix(in srgb, currentColor 18%, transparent) 2.5deg 20deg,
      transparent 20deg 25deg,
      color-mix(in srgb, currentColor 22%, transparent) 25deg 42.5deg,
      transparent 42.5deg 47.5deg,
      color-mix(in srgb, currentColor 26%, transparent) 47.5deg 65deg,
      transparent 65deg 70deg,
      color-mix(in srgb, currentColor 30%, transparent) 70deg 87.5deg,
      transparent 87.5deg 92.5deg,
      color-mix(in srgb, currentColor 35%, transparent) 92.5deg 110deg,
      transparent 110deg 115deg,
      color-mix(in srgb, currentColor 39%, transparent) 115deg 132.5deg,
      transparent 132.5deg 137.5deg,
      color-mix(in srgb, currentColor 43%, transparent) 137.5deg 155deg,
      transparent 155deg 160deg,
      color-mix(in srgb, currentColor 47%, transparent) 160deg 177.5deg,
      transparent 177.5deg 182.5deg,
      color-mix(in srgb, currentColor 51%, transparent) 182.5deg 200deg,
      transparent 200deg 205deg,
      color-mix(in srgb, currentColor 55%, transparent) 205deg 222.5deg,
      transparent 222.5deg 227.5deg,
      color-mix(in srgb, currentColor 59%, transparent) 227.5deg 245deg,
      transparent 245deg 250deg,
      color-mix(in srgb, currentColor 63%, transparent) 250deg 267.5deg,
      transparent 267.5deg 272.5deg,
      color-mix(in srgb, currentColor 68%, transparent) 272.5deg 290deg,
      transparent 290deg 295deg,
      color-mix(in srgb, currentColor 72%, transparent) 295deg 312.5deg,
      transparent 312.5deg 317.5deg,
      color-mix(in srgb, currentColor 76%, transparent) 317.5deg 335deg,
      transparent 335deg 340deg,
      var(--accent) 340deg 357.5deg,
      transparent 357.5deg
    );
  -webkit-mask-image: radial-gradient(circle, #000 0 0.17rem, transparent 0.18rem 0.56rem, #000 0.57rem 0.77rem, transparent 0.78rem);
  mask-image: radial-gradient(circle, #000 0 0.17rem, transparent 0.18rem 0.56rem, #000 0.57rem 0.77rem, transparent 0.78rem);
}
header.top .brand:hover {
  color: var(--fg);
}

header.top nav {
  /* --nav-pad: side padding of a nav link; the nav's negative margin pulls the first label onto the
     brand's left edge when the nav sits on its own row. --lang-w: width of the DE/EN chip. */
  --nav-pad: 0.6rem;
  --nav-gap: 0.125rem;
  --lang-w: 5.75rem;
  display: flex;
  flex: 0 1 auto;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: var(--nav-gap);
  min-width: 0;
  margin-left: calc(-1 * var(--nav-pad));
  counter-reset: rb-nav;
}

/* Nav links: fg-2, numbered "01 … 11" in mono like the site's header. */
header.top nav > a,
header.top nav .link {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35rem;
  min-height: 2.5rem;
  padding: 0.6rem var(--nav-pad);
  border-radius: var(--radius-pill);
  color: var(--fg-2);
  font-size: 0.9375rem;
  line-height: 1.2;
  white-space: nowrap;
  text-decoration-line: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.5em;
}
header.top nav > a:not([hreflang], [href="/login"], [href="/signup"])::before {
  counter-increment: rb-nav;
  content: counter(rb-nav, decimal-leading-zero);
  content: counter(rb-nav, decimal-leading-zero) / "";
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  color: var(--fg-3);
  text-decoration: none;
  transition: color var(--dur) var(--ease-out-expo);
}
header.top nav > a:hover,
header.top nav .link:hover {
  color: var(--fg);
  text-decoration-color: currentColor;
}
header.top nav > a:hover::before {
  color: var(--accent-ink);
}
header.top nav > a[aria-current="page"] {
  color: var(--fg);
  text-decoration-color: currentColor;
}
header.top nav > a[aria-current="page"]::before {
  color: var(--accent-ink);
}

/* Sign out sits apart from the sections, like the site's utility group. When the nav has a row of
   its own and wraps, the auto margin moves sign out and the language chip to the right end of
   their row; beside the brand the nav is only as wide as its content, so nothing moves. */
header.top nav form.inline {
  display: inline-flex;
  margin: 0 0 0 auto;
  padding-left: 0.5rem;
  border-left: var(--rule);
}
header.top nav > a:has(+ form.inline) {
  margin-right: 0.5rem;
}
/* Sign out and the language chip never part: the form reserves the chip's room in its own margin,
   and the chip pulls itself back into that room with a negative margin of the same size. So the
   chip takes no space of its own when a row breaks, and the two always land on the same row. */
header.top nav form.inline:has(+ a[hreflang]) {
  margin-right: calc(var(--lang-w) + 0.5rem + var(--nav-gap));
}
header.top nav form.inline + a[hreflang] {
  margin-left: calc(-1 * (var(--lang-w) + var(--nav-gap)));
}

/* Language switch: a mono chip, like the site's DE / EN. "DEUTSCH" and "ENGLISH" are both seven
   monospaced letters, so the chip has one fixed width. */
header.top nav > a[hreflang] {
  box-sizing: border-box;
  width: var(--lang-w);
  margin-left: 0.5rem;
  padding: 0.5rem 0;
  min-height: 2.25rem;
  align-items: center;
  justify-content: center;
  border: var(--rule-strong);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  text-decoration: none;
  transition:
    border-color var(--dur) var(--ease-out-expo),
    color var(--dur) var(--ease-out-expo);
}
header.top nav > a[hreflang]:hover {
  border-color: var(--fg);
}

/* Signed out: "Create account" is the lime call to action, like "Start free" on the site. */
header.top nav > a[href="/signup"] {
  margin-left: 0.25rem;
  padding-inline: 1.15rem;
  align-items: center;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: var(--weight-medium);
  text-decoration: none;
  transition:
    background-color var(--dur) var(--ease-out-expo),
    color var(--dur) var(--ease-out-expo);
}
header.top nav > a[href="/signup"]:hover {
  background: var(--fg);
  color: var(--bg);
}

/* ── 4. Shell: main and footer ───────────────────────────────────────────── */

main {
  flex: 1 0 auto;
  width: 100%;
  max-width: calc(var(--main-max) + 2 * var(--gutter));
  margin: 0 auto;
  padding: clamp(2rem, 5vw, 4.5rem) var(--gutter) clamp(3rem, 6vw, 6rem);
  counter-reset: rb;
}

/* Pages that are one card without a table (sign in, sign up, reset, verify, sudo,
   sign out, messages, consent, invitations, new team): a narrow, centred column. */
main:has(> .card:only-child):not(:has(table)) {
  max-width: calc(var(--main-narrow) + 2 * var(--gutter));
  padding-top: clamp(2.5rem, 8vw, 7rem);
}
/* One prose card (legal pages, documentation): a reading column. */
main:has(> .card.prose:only-child) {
  max-width: calc(var(--main-prose) + 2 * var(--gutter));
}

footer {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 0;
  margin-top: auto;
  padding: var(--space-8) max(var(--gutter), calc((100% - var(--wrap-max)) / 2 + var(--gutter))) 0;
  border-top: var(--rule);
  overflow: hidden;
  font-size: var(--text-sm);
  color: var(--fg-3);
}
footer a {
  display: inline-block;
  margin-right: 1.75rem;
  padding-block: 0.6rem;
  color: var(--fg-2);
  text-decoration-color: transparent;
}
footer a:hover {
  color: var(--fg);
  text-decoration-color: currentColor;
}
/* The giant wordmark, as on regensbot.de: decorative, skipped by screen readers.
   "regensbot" is ::before, the lime full stop ::after. The pair is wider than what is left
   of the links' last line, so it always starts a line of its own, centred. */
footer::before,
footer::after {
  order: 100;
  margin-top: clamp(1.5rem, 4vw, 3.5rem);
  padding-bottom: 0.06em;
  font-family: var(--font-display);
  font-size: clamp(3.25rem, 16.8vw, 21rem);
  font-weight: var(--weight-semibold);
  line-height: 0.9;
  letter-spacing: -0.07em;
  white-space: nowrap;
  user-select: none;
  color: var(--fg);
}
footer::before {
  content: "regensbot";
  content: "regensbot" / "";
  margin-left: auto;
}
footer::after {
  content: ".";
  content: "." / "";
  margin-right: auto;
  color: var(--accent);
}

/* ── 5. Headings and the mono kickers ────────────────────────────────────── */

h1 {
  margin: 0 0 1.25rem;
  font-family: var(--font-display);
  font-size: clamp(2.1rem, 3.8vw, 3.75rem);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
}
h2 {
  margin: 2.25rem 0 0.9rem;
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 1.9vw, 1.875rem);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-heading);
}
h3 {
  margin: 1.75rem 0 0.6rem;
  font-size: 1.125rem;
  font-weight: var(--weight-semibold);
  line-height: 1.25;
  letter-spacing: -0.02em;
}
h4 {
  margin: 1.5rem 0 0.6rem;
  font-family: var(--font-mono);
  font-size: var(--text-kicker);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
}

/* "[RB: 01]" section codes: numbered per card, painted (not read aloud, not copied). */
.card:has(> h1, > h2) {
  counter-increment: rb;
}
.card > h1:not(:has(> code:first-child))::before,
.card > h2:first-of-type:not(h1 ~ h2)::before {
  content: "[RB: " counter(rb, decimal-leading-zero) "]";
  content: "[RB: " counter(rb, decimal-leading-zero) "]" / "";
  display: block;
  margin-bottom: 1.1rem;
  font-family: var(--font-mono);
  font-size: var(--text-kicker);
  font-weight: var(--weight-medium);
  line-height: 1.3;
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
  background: linear-gradient(var(--line), var(--line)) no-repeat right center / calc(100% - 5.25rem) 1px;
}
.card > h1:not(:has(> code:first-child))::before {
  margin-bottom: 1.5rem;
}

/* Requirement IDs in headings (checklist item: <h1><code>DEV-SRV-01</code> Title</h1>). */
h1 > code:first-child,
h3 > code:first-child {
  display: block;
  width: fit-content;
  margin-bottom: 0.9rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  font-size: var(--text-kicker);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  line-height: 1.2;
  color: var(--accent-ink);
}
h3 > code:first-child {
  display: inline-block;
  margin: 0 0.35rem 0 0;
  vertical-align: 0.15em;
}

/* ── 6. Cards ────────────────────────────────────────────────────────────── */

.card {
  position: relative;
  margin: 0 0 var(--space-5);
  padding: var(--card-pad);
  border: var(--rule);
  border-radius: var(--radius-lg);
  /* Opaque card with CSS-only scroll shadows: when a wide table makes the card scroll
     sideways (phones), a soft edge shows on the side that has more. */
  background:
    linear-gradient(to right, var(--card) 40%, transparent) left center / 2.5rem 100% no-repeat local,
    linear-gradient(to left, var(--card) 40%, transparent) right center / 2.5rem 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, var(--scroll-shade), transparent) left center / 0.85rem 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, var(--scroll-shade), transparent) right center / 0.85rem 100% no-repeat scroll,
    var(--card);
  overflow-x: auto;
  overflow-wrap: break-word;
}
.card > :first-child {
  margin-top: 0;
}
.card > :last-child {
  margin-bottom: 0;
}
.card > h2:first-child,
.card > h2:first-of-type:not(h1 ~ h2) {
  margin-top: 0;
}
/* A back link above the title (site page: "All sites of …"). */
.card > p:first-child:has(+ h1) {
  margin-bottom: 1.25rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
}
.card > p:first-child:has(+ h1) a {
  color: var(--fg-3);
  text-decoration-color: transparent;
}
.card > p:first-child:has(+ h1) a:hover {
  color: var(--fg);
  text-decoration-color: currentColor;
}

/* Prose cards (legal, documentation, the crawler page) */
.prose p,
.prose li {
  max-width: 68ch;
}
.prose h2 {
  margin-top: 2.5rem;
}

/* A navigation card (site page "Work on this site"): numbered rows. */
nav.card ul {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: rb-row;
}
nav.card li {
  display: grid;
  grid-template-columns: 2.25rem minmax(0, 1fr);
  margin: 0;
  padding: 0.85rem 0;
  border-top: var(--rule);
  counter-increment: rb-row;
}
nav.card li:last-child {
  border-bottom: var(--rule);
}
nav.card li::before {
  content: counter(rb-row, decimal-leading-zero);
  content: counter(rb-row, decimal-leading-zero) / "";
  grid-row: span 2;
  padding-top: 0.3rem;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-kicker);
  color: var(--fg-3);
}
nav.card li > a {
  font-weight: var(--weight-medium);
  text-decoration-color: transparent;
}
nav.card li > a:hover {
  color: var(--accent-ink);
}

/* A release (releases page) */
article.release {
  margin-top: var(--space-6);
  padding-top: var(--space-6);
  border-top: var(--rule-strong);
}
article.release > h3:first-child {
  margin-top: 0;
}

/* Screenshots */
figure {
  margin: var(--space-4) 0 var(--space-6);
}
figure img {
  border: var(--rule);
  border-radius: var(--radius-md);
  background: var(--bg-2);
}
figcaption {
  margin-top: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
}

/* ── 7. Text helpers the templates use ───────────────────────────────────── */

.aside,
.hint {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--fg-3);
}
p.aside {
  margin-top: var(--space-4);
}
.aside a,
.hint a {
  color: var(--fg-2);
}
.aside a:hover,
.hint a:hover {
  color: var(--fg);
}

.error {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45rem;
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--fail-ink);
}
.error::before {
  content: "";
  flex: none;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--color-fail);
  box-shadow: 0 0 0 1px var(--dot-ring);
  transform: translateY(-0.05rem);
}

/* ── 8. Notices and alerts (flash messages) ──────────────────────────────── */

.notice,
.alert {
  position: relative;
  margin: var(--space-4) 0;
  padding: 0.85rem 1.1rem 0.85rem 2.35rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  background: var(--glass-strong);
  color: var(--fg);
  font-size: 0.9375rem;
  line-height: 1.5;
}
.notice::before,
.alert::before {
  content: "";
  position: absolute;
  left: 1.05rem;
  top: 1.38rem;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--accent-ink);
  box-shadow:
    0 0 0 1px var(--dot-ring),
    0 0 var(--dot-glow) var(--accent);
}
.notice p,
.alert p {
  color: var(--fg);
}
.notice > :last-child,
.alert > :last-child {
  margin-bottom: 0;
}
div.notice > p {
  margin-bottom: 0.5rem;
}
div.notice form {
  margin-top: 0.85rem;
}
/* "Known app" and similar lead-ins become a mono tag. */
.notice > strong:first-child {
  display: inline-block;
  margin-right: 0.4rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--accent-ink);
}

.alert {
  border-color: color-mix(in oklab, var(--color-fail) 55%, transparent);
  border-left: 3px solid var(--color-fail);
  background: color-mix(in oklab, var(--color-fail) 8%, transparent);
}
.alert::before {
  background: var(--color-fail);
  box-shadow:
    0 0 0 1px var(--dot-ring),
    0 0 var(--dot-glow) var(--color-fail);
}

/* ── 9. Buttons ─────────────────────────────────────────────────────────── */

button,
a.button,
input[type="submit"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: var(--control-h);
  margin: 0;
  padding: 0.55rem 1.35rem;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--on-accent);
  font: inherit;
  font-size: 0.9375rem;
  font-weight: var(--weight-medium);
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition:
    background-color var(--dur) var(--ease-out-expo),
    color var(--dur) var(--ease-out-expo),
    border-color var(--dur) var(--ease-out-expo),
    transform var(--dur-fast) var(--ease-out-expo);
}
button:hover,
a.button:hover,
input[type="submit"]:hover {
  background: var(--fg);
  color: var(--bg);
}
button:active,
a.button:active {
  transform: translateY(1px);
}
a.button:visited {
  color: var(--on-accent);
}
a.button:visited:hover {
  color: var(--bg);
}

/* Secondary: hairline outline, fills with ink on hover (site "outline"). */
button.secondary,
a.button.secondary {
  border-color: var(--line-strong);
  background: transparent;
  color: var(--fg);
}
button.secondary:hover,
a.button.secondary:hover {
  border-color: var(--fg);
  background: var(--fg);
  color: var(--bg);
}
a.button.secondary:visited {
  color: var(--fg);
}

/* Ghost: text only, accent on hover. */
button.ghost,
a.button.ghost {
  padding-inline: 0.35rem;
  border-color: transparent;
  background: transparent;
  color: var(--fg);
}
button.ghost:hover,
a.button.ghost:hover {
  background: transparent;
  color: var(--accent-ink);
}

/* Danger: for deleting an account or a site. Without the class, the delete forms the app
   has today get it by their action (see TEMPLATE-CHANGES.md for the explicit class). */
button.danger,
a.button.danger,
form[action="/account/delete"] button[type="submit"],
form[action^="/sites/"][action$="/delete"] button[type="submit"] {
  border-color: color-mix(in oklab, var(--fail-ink) 70%, transparent);
  background: transparent;
  color: var(--fail-ink);
}
button.danger:hover,
a.button.danger:hover,
form[action="/account/delete"] button[type="submit"]:hover,
form[action^="/sites/"][action$="/delete"] button[type="submit"]:hover {
  border-color: var(--color-fail);
  background: var(--color-fail);
  color: var(--ink);
}

/* A button that reads as a link (header "Sign out"). */
button.link {
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--fg);
  font-weight: var(--weight-regular);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
}
button.link:hover {
  background: none;
  color: var(--fg);
}

button:disabled,
button[disabled],
input[type="submit"]:disabled {
  opacity: 0.42;
  cursor: not-allowed;
  transform: none;
}
button:disabled:hover {
  background: var(--accent);
  color: var(--on-accent);
}
button.secondary:disabled:hover {
  border-color: var(--line-strong);
  background: transparent;
  color: var(--fg);
}

/* Rows of buttons: <p><button>…</button> <button class="secondary">…</button></p> */
p:has(> button, > a.button) {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
}

/* Compact buttons inside tables and inline forms */
td button,
td a.button,
form.inline button:not(.link) {
  min-height: var(--control-h-sm);
  padding: 0.35rem 0.95rem;
  font-size: var(--text-sm);
}

form {
  margin: 0;
}
form.inline {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0.15rem 0.35rem 0.15rem 0;
  vertical-align: middle;
}

/* The account forms: one full-width call to action. */
form:is([action="/login"], [action="/signup"], [action="/reset"], [action="/reset/confirm"], [action="/sudo"])
  > p:last-child
  > button[type="submit"] {
  flex: 1 1 auto;
  min-height: 3.25rem;
  font-size: 1rem;
}

/* ── 10. Forms ──────────────────────────────────────────────────────────── */

.field {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  margin: 0 0 1.25rem;
  color: var(--fg);
}

label {
  font-size: 0.9375rem;
  font-weight: var(--weight-medium);
  line-height: 1.35;
  color: var(--fg);
}

input:is([type="text"], [type="email"], [type="password"], [type="number"], [type="url"], [type="search"], [type="tel"], [type="date"], :not([type])),
textarea,
select {
  width: 100%;
  min-height: 3rem;
  margin: 0;
  padding: 0.7rem 1rem;
  border: 1px solid var(--field-border);
  border-radius: 0.75rem;
  background: var(--field-bg);
  color: var(--fg);
  font: inherit;
  font-size: 1rem;
  line-height: 1.4;
  letter-spacing: -0.01em;
  transition:
    border-color var(--dur) var(--ease-out-expo),
    box-shadow var(--dur) var(--ease-out-expo),
    background-color var(--dur) var(--ease-out-expo);
}
input:is([type="text"], [type="email"], [type="password"], [type="number"], [type="url"], [type="search"], [type="tel"], [type="date"], :not([type])):hover,
textarea:hover,
select:hover {
  border-color: var(--field-border-hover);
}
input:is([type="text"], [type="email"], [type="password"], [type="number"], [type="url"], [type="search"], [type="tel"], [type="date"], :not([type])):focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
  border-color: var(--fg);
  border-radius: 0.75rem;
}
input::placeholder,
textarea::placeholder {
  color: var(--fg-3);
  opacity: 1;
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--fg);
  caret-color: var(--fg);
  transition: background-color 9999s 0s;
}
textarea {
  min-height: 6rem;
  resize: vertical;
  line-height: 1.5;
}
/* Monospace where people paste machine text (hosts, paths, templates, JSON) */
textarea:is([name="hosts"], [name="templates"], [name="cart_paths"], [name="private_prefixes"], [name="explicit_hosts"], [name="explicit_paths"], [name="columns"]),
input:is([name="log_format"], [name="prefix"], [name="bucket"], [name="project"], [name="dataset"]) {
  font-family: var(--font-mono);
  font-size: 0.875rem;
}
/* Native select: keeps the system arrow (no image allowed by the CSP), themed by color-scheme. */
select {
  padding-right: 0.75rem;
  cursor: pointer;
}
select option {
  background: var(--bg-2);
  color: var(--fg);
}

/* Small controls inside table rows and inline forms */
td select,
form.inline select {
  width: auto;
  min-height: var(--control-h-sm);
  padding: 0.3rem 0.6rem;
  font-size: var(--text-sm);
  border-radius: var(--radius-sm);
}
form.inline label {
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
}

/* Filter rows: <p><label/><select/>…<button/></p> inside a GET form */
form[method="get"] > p {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 0.75rem;
}
form[method="get"] > p > select {
  width: auto;
  min-width: 8rem;
  min-height: 2.5rem;
  padding-block: 0.4rem;
}
form[method="get"] > p > label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
}
form[method="get"] > p > label:not(:first-child) {
  margin-left: 0.5rem;
}

/* File input: the selector button looks like a secondary button. */
input[type="file"] {
  max-width: 100%;
  padding: 0.5rem;
  border: 1px dashed var(--field-border);
  border-radius: var(--radius-md);
  background: var(--field-bg);
  color: var(--fg-2);
  font: inherit;
  font-size: var(--text-sm);
}
input[type="file"]::file-selector-button {
  margin-right: 0.85rem;
  padding: 0.5rem 1rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--fg);
  font: inherit;
  font-weight: var(--weight-medium);
  cursor: pointer;
  transition:
    background-color var(--dur) var(--ease-out-expo),
    color var(--dur) var(--ease-out-expo);
}
input[type="file"]::file-selector-button:hover {
  background: var(--fg);
  color: var(--bg);
}

/* Invalid fields (the macro adds .invalid to the <p class="field">) */
.invalid input,
.invalid textarea,
.invalid select,
[aria-invalid="true"] {
  border-color: var(--fail-ink);
}
.invalid input:hover,
.invalid textarea:hover {
  border-color: var(--color-fail);
}

/* Checkboxes and radios, drawn without images */
input[type="checkbox"],
input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  display: inline-grid;
  place-content: center;
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  margin: 0.12rem 0 0;
  border: 1px solid var(--field-border);
  border-radius: 0.3rem;
  background: var(--field-bg);
  color: var(--bg);
  cursor: pointer;
  vertical-align: -0.2em;
  transition:
    border-color var(--dur) var(--ease-out-expo),
    background-color var(--dur) var(--ease-out-expo);
}
input[type="radio"] {
  border-radius: 50%;
}
input[type="checkbox"]::after {
  content: "";
  width: 0.34rem;
  height: 0.66rem;
  margin-top: -0.14rem;
  border: solid currentColor;
  border-width: 0 1.75px 1.75px 0;
  transform: rotate(45deg) scale(0);
  transition: transform 0.35s var(--ease-out-expo);
}
input[type="radio"]::after {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: currentColor;
  transform: scale(0);
  transition: transform 0.35s var(--ease-out-expo);
}
input:is([type="checkbox"], [type="radio"]):hover {
  border-color: var(--field-border-hover);
}
input:is([type="checkbox"], [type="radio"]):checked {
  border-color: var(--fg);
  background: var(--fg);
}
input:is([type="checkbox"], [type="radio"]):checked::after {
  transform: rotate(45deg) scale(1);
}
input[type="radio"]:checked::after {
  transform: scale(1);
}
input:is([type="checkbox"], [type="radio"]):focus-visible {
  outline: var(--focus-ring);
  outline-offset: 3px;
}
.invalid input:is([type="checkbox"], [type="radio"]) {
  border-color: var(--fail-ink);
}

/* <p class="field check">: box first, then its label; notes on their own line. */
.field.check {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.5rem 0.65rem;
}
.field.check label {
  flex: 0 1 auto;
  min-width: 0;
  font-weight: var(--weight-regular);
  line-height: 1.45;
  color: var(--fg-2);
  cursor: pointer;
}
/* Radio groups (several inputs in one <p class="field check">): one option per row. */
.field.check:has(> input[type="radio"] ~ input[type="radio"]) {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: 0.6rem 0.65rem;
}
.field.check:has(> input[type="radio"] ~ input[type="radio"]) label + input {
  margin-left: 0;
}
.field.check:has(> input[type="radio"] ~ input[type="radio"]) :is(.hint, .error) {
  grid-column: 1 / -1;
}

/* A single box with a long label (terms, a crawler): the label wraps beside the box. */
.field.check > label:only-of-type {
  flex: 1 1 0;
}
.field.check label + input {
  margin-left: 0.85rem;
}
.field.check :is(.hint, .error) {
  flex-basis: 100%;
  padding-left: 1.9rem;
}

input:disabled,
textarea:disabled,
select:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

fieldset.field,
fieldset {
  min-width: 0;
  margin: 0 0 1.25rem;
  padding: 1rem 1.25rem 0.25rem;
  border: var(--rule-strong);
  border-radius: var(--radius-md);
}
legend {
  padding: 0 0.45rem;
  margin-left: -0.45rem;
  font-size: 0.9375rem;
  font-weight: var(--weight-medium);
  color: var(--fg);
}
fieldset > .field.check {
  margin-bottom: 0.85rem;
}

/* ── 11. Tables ─────────────────────────────────────────────────────────── */

table {
  width: 100%;
  margin: 0.5rem 0 1.25rem;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
}
caption {
  padding-bottom: 0.75rem;
  text-align: left;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
}
th,
td {
  padding: 0.85rem 1.25rem 0.85rem 0;
  border-bottom: var(--rule);
  text-align: left;
  vertical-align: top;
}
th:last-child,
td:last-child {
  padding-right: 0;
}
thead th {
  padding-block: 0.6rem 0.75rem;
  border-bottom: var(--rule-strong);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: 1.3;
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  vertical-align: bottom;
  color: var(--fg-3);
}
td {
  color: var(--fg-2);
}
td:first-child {
  color: var(--fg);
}
tbody tr:last-child > * {
  border-bottom: 0;
}
tbody tr {
  transition: background-color var(--dur-fast) linear;
}
tbody tr:hover > td {
  background: linear-gradient(var(--glass), var(--glass));
}

/* Key-value tables (audit, checklist item): <th scope="row"> */
th[scope="row"] {
  width: 32%;
  min-width: 8rem;
  padding-top: 1.05rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
}
th[scope="row"] + td {
  color: var(--fg);
}

td > ul,
td > ol {
  margin: 0.5rem 0 0;
  padding-left: 1.1rem;
  font-size: var(--text-sm);
}
td > ul:first-child {
  margin-top: 0;
}
td li {
  margin: 0.2rem 0;
}
td .hint,
td .aside {
  font-size: 0.8125rem;
}
td > p:last-child {
  margin-bottom: 0;
}

/* Empty state rows: <tr><td colspan="…">No audits yet.</td></tr> */
tbody tr:only-child > td[colspan] {
  padding: 2.5rem 1rem;
  text-align: center;
  color: var(--fg-3);
  background: repeating-linear-gradient(-45deg, transparent 0 10px, var(--glass) 10px 11px);
  border-radius: var(--radius-md);
}

/* ── 12. Description lists (crawl, render, logs, releases, account) ───────── */

dl {
  display: grid;
  grid-template-columns: minmax(8rem, 15rem) minmax(0, 1fr);
  margin: 0.5rem 0 1.25rem;
  border-top: var(--rule);
}
dt,
dd {
  margin: 0;
  padding: 0.8rem 0;
  border-bottom: var(--rule);
}
dt {
  grid-column: 1;
  padding-top: 0.95rem;
  padding-right: 1rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
}
dd {
  grid-column: 2;
  color: var(--fg);
}

/* ── 13. Code, keys and URLs ─────────────────────────────────────────────── */

code,
kbd,
samp,
pre {
  font-family: var(--font-mono);
  font-feature-settings: "zero" on;
}
code {
  padding: 0.12em 0.4em;
  border-radius: var(--radius-xs);
  background: var(--glass-strong);
  font-size: 0.86em;
  color: var(--fg);
  overflow-wrap: anywhere;
}
a code {
  color: inherit;
}
kbd {
  padding: 0.1em 0.4em;
  border: 1px solid var(--line-strong);
  border-bottom-width: 2px;
  border-radius: var(--radius-xs);
  font-size: 0.82em;
}

/* The MCP URL, a new API key, a push token: a framed, select-all field. */
code.url {
  display: inline-block;
  max-width: 100%;
  padding: 0.75rem 1rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  background: var(--bg-2);
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--fg);
  word-break: break-all;
  user-select: all;
  -webkit-user-select: all;
}
td code.url,
li code.url {
  display: inline;
  padding: 0.12em 0.4em;
  border: 0;
  border-radius: var(--radius-xs);
  background: var(--glass-strong);
  font-size: 0.8125rem;
  user-select: text;
  -webkit-user-select: text;
}
/* A key shown once (keys page, push tokens): lime frame. */
section[aria-labelledby="new-key"] code.url,
section[aria-labelledby="secret-new"] code.url,
.key-once code.url {
  border-color: var(--accent-ink);
  box-shadow: var(--glow-accent);
}

pre {
  margin: 0 0 1rem;
  padding: 1rem 1.25rem;
  border: var(--rule);
  border-radius: var(--radius-md);
  background: var(--bg-2);
  font-size: 0.8125rem;
  line-height: 1.65;
  color: var(--fg);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
pre code {
  padding: 0;
  background: none;
  font-size: inherit;
}

/* ── 14. Verdict chips (see TEMPLATE-CHANGES.md: <span class="verdict" data-v="fail">) ─ */

.verdict {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.3em 0.7em;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: 1.25;
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  white-space: nowrap;
  vertical-align: 0.1em;
  color: var(--fg-2);
}
.verdict::before {
  content: "";
  flex: none;
  width: 0.55em;
  height: 0.55em;
  border-radius: 50%;
  background: var(--v, var(--color-skip));
  box-shadow:
    0 0 0 1px var(--dot-ring),
    0 0 var(--dot-glow) var(--v, transparent);
}
.verdict b,
.verdict strong {
  font-weight: var(--weight-semibold);
  color: var(--fg);
}
.verdict[data-v="fail"] {
  --v: var(--color-fail);
}
.verdict[data-v="warn"] {
  --v: var(--color-warn);
}
.verdict[data-v="pass"] {
  --v: var(--color-pass);
}
.verdict[data-v="manual"] {
  --v: var(--color-manual);
}
.verdict[data-v="error"] {
  --v: var(--color-error);
}
.verdict:is([data-v="skipped"], [data-v="skip"]) {
  --v: var(--color-skip);
  box-shadow: none;
}
/* Hollow rings: a person still has to decide (pending), or nothing to decide (n/a). */
.verdict[data-v="pending_confirmation"]::before {
  background: transparent;
  box-shadow:
    inset 0 0 0 1.5px var(--color-pending),
    0 0 0 1px var(--dot-ring);
}
.verdict[data-v="not_applicable"]::before {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--color-na);
}
.verdict:is([data-v="skipped"], [data-v="not_applicable"]) {
  color: var(--fg-3);
}
/* Checklist states (checklist/engine.py SHOWN): data-v="{{ row.shown_as }}" */
.verdict[data-v="needs_confirmation"]::before {
  background: transparent;
  box-shadow:
    inset 0 0 0 1.5px var(--color-pending),
    0 0 0 1px var(--dot-ring);
}
.verdict[data-v="confirmed"] {
  --v: var(--color-fail);
}
.verdict[data-v="attested"] {
  --v: var(--color-manual);
}
.verdict[data-v="rejected"] {
  --v: var(--color-skip);
}
.verdict[data-v="evidence_requested"]::before {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--color-manual);
}
.verdict[data-v="expired"]::before {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--color-warn);
}
.verdict[data-v="open"]::before {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--fg-3);
}
/* Strong verdicts (fail, error) carry a tinted border so they read first in a list. */
.verdict:is([data-v="fail"], [data-v="error"]) {
  border-color: color-mix(in oklab, var(--v) 55%, transparent);
}
/* A row of counts: <span class="verdicts"><span class="verdict" data-v="fail">Fail <b>3</b></span> …</span> */
.verdicts {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

/* ── 15. Optional components (no template uses them yet) ─────────────────── */

/* Pagination: <nav class="pagination" aria-label="Pages"><a rel="prev">…</a><a aria-current="page">2</a>…</nav> */
.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin: 1.25rem 0 0;
}
.pagination a,
.pagination span {
  display: inline-grid;
  place-items: center;
  min-width: 2.5rem;
  min-height: 2.5rem;
  padding: 0 0.85rem;
  border: var(--rule-strong);
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: var(--text-kicker);
  letter-spacing: var(--tracking-kicker);
  color: var(--fg-2);
  text-decoration: none;
}
.pagination a:hover {
  border-color: var(--fg);
  color: var(--fg);
}
.pagination [aria-current="page"] {
  border-color: var(--fg);
  background: var(--fg);
  color: var(--bg);
}
.pagination span:not([aria-current]) {
  border-color: transparent;
  color: var(--fg-3);
}

/* Scrollable wrapper for a wide table with no links or buttons in it (coverage, logs):
   <div class="table-scroll" tabindex="0" role="region" aria-labelledby="…"><table>…</table></div>
   Keyboard users can then scroll it too (axe: scrollable-region-focusable). */
.table-scroll {
  margin: 0.5rem 0 1.25rem;
  overflow-x: auto;
  border-radius: var(--radius-sm);
  background:
    linear-gradient(to right, var(--card) 40%, transparent) left center / 2.5rem 100% no-repeat local,
    linear-gradient(to left, var(--card) 40%, transparent) right center / 2.5rem 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, var(--scroll-shade), transparent) left center / 0.85rem 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, var(--scroll-shade), transparent) right center / 0.85rem 100% no-repeat scroll,
    var(--card);
}
.table-scroll > table {
  margin: 0;
}

/* Empty state outside a table */
.empty {
  padding: 2.5rem 1.25rem;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-md);
  text-align: center;
  color: var(--fg-3);
}
.empty > :last-child {
  margin-bottom: 0;
}

/* Usage meter (for "used of limit"): <meter value="7" max="10"> */
meter {
  width: 100%;
  max-width: 16rem;
  height: 0.5rem;
  vertical-align: middle;
}

/* ── 16. Page-specific touches, keyed on markup the app already emits ─────── */

/* Narrow pages: a calmer title size. */
main:has(> .card:only-child):not(:has(table)) h1 {
  font-size: clamp(2rem, 3.2vw, 2.75rem);
}
main:has(> .card:only-child):not(:has(table)) .card {
  padding: clamp(1.5rem, 4vw, 2.5rem);
  background: color-mix(in oklab, var(--bg-2) 88%, transparent);
  border-color: var(--line-strong);
  box-shadow: var(--shadow);
}

/* OAuth consent: the app and return addresses read as two data rows. */
.card:has(form[action="/oauth/consent"]) > h2 {
  margin: 0;
  padding: 0.8rem 0;
  border-top: var(--rule);
  font-family: var(--font-mono);
  font-size: 0.875rem;
  font-weight: var(--weight-medium);
  letter-spacing: 0;
  line-height: 1.4;
  overflow-wrap: anywhere;
}
.card:has(form[action="/oauth/consent"]) > h2 + :not(h2) {
  margin-top: 0;
  border-top: var(--rule);
  padding-top: 1rem;
}
.card:has(form[action="/oauth/consent"]) > ul {
  padding: 0;
  list-style: none;
}
.card:has(form[action="/oauth/consent"]) > ul > li {
  position: relative;
  padding: 0.7rem 0 0.7rem 1.75rem;
  border: var(--rule);
  border-radius: var(--radius-md);
  background: var(--glass);
  color: var(--fg);
}
.card:has(form[action="/oauth/consent"]) > ul > li::before {
  content: "";
  position: absolute;
  left: 0.85rem;
  top: 1.15rem;
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background: var(--accent-ink);
}
.card:has(form[action="/oauth/consent"]) > ul > li {
  padding-left: 1.85rem;
}
form[action="/oauth/consent"] > p:last-child > button {
  flex: 1 1 10rem;
  min-height: 3.25rem;
}

/* ── 17. Responsive ─────────────────────────────────────────────────────── */

/* Very wide screens (104rem, the page's max width): the numbered nav fits beside the brand in both
   languages (German, the longest, needs about 95rem), so the header is one row and sticks. */
@media (min-width: 104rem) {
  header.top {
    position: sticky;
    top: 0;
  }
}
/* Below that the section numbers go: without them the nav fits beside the brand from about
   79rem (English) and 89rem (German), and on its own row from about 61rem. */
@media (max-width: 103.99rem) {
  header.top nav > a::before {
    display: none;
  }
}
@media (max-width: 90rem) {
  header.top nav {
    --nav-pad: 0.5rem;
  }
}
@media (max-width: 64rem) {
  header.top nav > a,
  header.top nav .link {
    padding-block: 0.55rem;
    font-size: 0.875rem;
  }
}

@media (max-width: 40rem) {
  header.top {
    column-gap: 1rem;
  }
  header.top nav form.inline {
    padding-left: 0.25rem;
  }
  header.top nav > a[hreflang] {
    margin-left: 0.35rem;
  }
  header.top nav form.inline:has(+ a[hreflang]) {
    margin-right: calc(var(--lang-w) + 0.35rem + var(--nav-gap));
  }

  main {
    padding-top: 1.5rem;
  }
  .card {
    border-radius: var(--radius-md);
  }

  table {
    font-size: 0.875rem;
  }
  th,
  td {
    padding-right: 0.75rem;
  }
  td {
    overflow-wrap: anywhere;
  }
  /* Wide tables with links or buttons keep readable columns and scroll inside their card
     (with the scroll shadows above); keyboard users reach the scroller through those controls.
     Wide tables without anything focusable reflow instead (below), because a scroller nobody
     can focus fails WCAG 2.1.1; wrap one in .table-scroll (TEMPLATE-CHANGES 5) to let it scroll. */
  table:has(th:nth-child(4)):has(a, button, input, select, textarea) td,
  .table-scroll td {
    min-width: 6.5rem;
  }
  /* …and get room to breathe, so a prose column (checklist "Requirement") is not cut to the
     6.5rem minimum: the table auto layout hands the extra width to the longest content. */
  table:has(th:nth-child(4)):has(a, button, input, select, textarea),
  .table-scroll > table {
    min-width: 34rem;
  }
  table:has(th:nth-child(5)):has(a, button, input, select, textarea),
  .table-scroll > table:has(th:nth-child(5)) {
    min-width: 40rem;
  }

  /* Tables with three or more columns and nothing focusable (audit findings, history, thresholds,
     coverage, log summaries) cannot scroll for keyboard users, so on phones they reflow instead.
     Each row becomes a small grid: the last column (the prose: "What we found", "Notes", "Meaning",
     "Needs") drops under the others at full width, and from five columns on the first column (the
     row's name: requirement, check) takes a full line on top too. The head row reflows the same
     way, so every value keeps its label, and subgrid keeps the columns aligned from row to row.
     Wrap a table in .table-scroll (TEMPLATE-CHANGES 5) to keep it a plain table that scrolls. */
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) {
    --rb-cols: 2;
    display: grid;
    grid-template-columns: repeat(var(--rb-cols), auto);
    column-gap: 1rem;
  }
  table:has(> thead > tr > th:nth-child(4):last-child):not(:has(a, button, input, select, textarea)):not(.table-scroll > *) {
    --rb-cols: 3;
  }
  table:has(> thead > tr > th:nth-child(5):last-child):not(:has(a, button, input, select, textarea)):not(.table-scroll > *) {
    --rb-cols: 3;
  }
  table:has(> thead > tr > th:nth-child(6):last-child):not(:has(a, button, input, select, textarea)):not(.table-scroll > *) {
    --rb-cols: 4;
  }
  table:has(> thead > tr > th:nth-child(7)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *) {
    --rb-cols: 5;
  }
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) > :is(thead, tbody, tfoot),
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) > * > tr {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
  }
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) > * > tr {
    border-bottom: var(--rule);
  }
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) > thead > tr {
    border-bottom: var(--rule-strong);
  }
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) > tbody > tr:last-child {
    border-bottom: 0;
  }
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) :is(th, td) {
    min-width: 0;
    padding: 0.85rem 0 0.3rem;
    border-bottom: 0;
    background: none;
  }
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) thead th {
    padding: 0.6rem 0 0.2rem;
    align-self: end;
  }
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) :is(th, td):last-child {
    grid-column: 1 / -1;
    padding: 0 0 0.85rem;
    overflow-wrap: break-word;
  }
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) thead th:last-child {
    padding: 0 0 0.6rem;
  }
  table:has(> thead > tr > th:nth-child(5)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *) :is(th, td):first-child {
    grid-column: 1 / -1;
    padding-bottom: 0.15rem;
  }
  table:has(> thead > tr > th:nth-child(5)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *) :is(th, td):not(:first-child, :last-child) {
    padding-top: 0.15rem;
  }
  table:has(> thead > tr > th:nth-child(5)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *) thead th:first-child {
    padding-bottom: 0.1rem;
  }
  table:has(> thead > tr > th:nth-child(5)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *) thead th:not(:first-child, :last-child) {
    padding: 0.1rem 0 0.2rem;
  }
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) td[colspan] {
    grid-column: 1 / -1;
    padding: 2rem 0;
  }
  /* Evidence lines (URLs) use the full width and break only where a line is full. */
  table:has(> thead > tr > th:nth-child(3)):not(:has(a, button, input, select, textarea)):not(.table-scroll > *):not(:has(> tbody > tr:only-child > td[colspan])) td li {
    overflow-wrap: anywhere;
  }
  table:not(:has(a, button, input, select, textarea)) th {
    overflow-wrap: anywhere;
  }
  .table-scroll th {
    overflow-wrap: normal;
  }
  td:has(> input[type="checkbox"]:only-child),
  td:empty {
    min-width: 0 !important;
  }
  thead th {
    letter-spacing: 0.02em;
    hyphens: auto;
  }
  /* Requirement IDs and similar short codes keep their width; the prose column gives way. */
  td > code:only-child,
  td > a:only-child > code {
    white-space: nowrap;
  }
  td .verdict {
    white-space: normal;
    overflow-wrap: normal;
    border-radius: 0.75rem;
  }
  th[scope="row"] {
    width: 40%;
    min-width: 0;
  }

  dl {
    grid-template-columns: minmax(0, 1fr);
  }
  dt,
  dd {
    grid-column: 1;
  }
  dt {
    padding-bottom: 0.15rem;
    border-bottom: 0;
  }
  dd {
    padding-top: 0.15rem;
  }

  /* Filter row: each label sits beside its own select, one pair per line; the button gets a row. */
  form[method="get"] > p {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: 0.6rem 1rem;
  }
  form[method="get"] > p > select {
    width: 100%;
    min-width: 0;
  }
  form[method="get"] > p > label:not(:first-child) {
    margin-left: 0;
  }
  form[method="get"] > p > :is(button, input:not([type="hidden"])) {
    grid-column: 1 / -1;
    justify-self: start;
  }

  footer a {
    margin-right: 1.25rem;
  }
}

/* ── 18. Motion, contrast and print ─────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  button:active,
  a.button:active {
    transform: none;
  }
}

@media (forced-colors: active) {
  .verdict::before,
  .notice::before,
  .alert::before,
  .error::before {
    forced-color-adjust: none;
    background: CanvasText;
    border: 1px solid CanvasText;
  }
  button,
  a.button {
    border-color: ButtonText;
  }
  header.top .brand::before {
    display: none;
  }
}

@media print {
  body::before,
  header.top nav,
  footer::before,
  footer::after {
    display: none;
  }
  .card {
    break-inside: avoid;
    border-color: #999;
    background: none;
  }
  a {
    text-decoration: underline;
  }
}

/* ── App additions (not from the design kit) ── */
/* Everything below is the app's own. The kit's sections above stay as built, so a newer kit can be
   pasted over them and this block re-appended unchanged. Only the kit's tokens are used here, so both
   themes (dark default, paper) follow automatically. */

/* A1. Focus: the kit's generic `:focus-visible { border-radius: 2px }` (0,1,0) outranks the bare
   `button` rule (0,0,1) that makes buttons pills, so a focused button turned square. Buttons keep their
   own shape; a button drawn as a link keeps the small radius. */
:is(button, input[type="submit"]):focus-visible {
  border-radius: var(--radius-pill);
}
button.link:focus-visible {
  border-radius: 2px;
}

/* A2. Header and footer: a section's sub-pages (/audits/<id>, /sites/<id>/…) mark their section with
   aria-current="true" (the section's own page keeps "page"); both look the same. */
header.top nav > a[aria-current="true"] {
  color: var(--fg);
  text-decoration-color: currentColor;
}
header.top nav > a[aria-current="true"]::before {
  color: var(--accent-ink);
}
footer a[aria-current="page"] {
  color: var(--fg);
  text-decoration-color: currentColor;
}

/* A3. Form fields: the input types the kit's text-field rule leaves out (workflow drill window). */
input:is([type="datetime-local"], [type="time"], [type="month"], [type="week"]) {
  width: 100%;
  min-height: 3rem;
  margin: 0;
  padding: 0.7rem 1rem;
  border: 1px solid var(--field-border);
  border-radius: 0.75rem;
  background: var(--field-bg);
  color: var(--fg);
  font: inherit;
  font-size: 1rem;
  line-height: 1.4;
  letter-spacing: -0.01em;
  transition:
    border-color var(--dur) var(--ease-out-expo),
    box-shadow var(--dur) var(--ease-out-expo),
    background-color var(--dur) var(--ease-out-expo);
}
input:is([type="datetime-local"], [type="time"], [type="month"], [type="week"]):hover {
  border-color: var(--field-border-hover);
}
input:is([type="datetime-local"], [type="time"], [type="month"], [type="week"]):focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
  border-color: var(--fg);
  border-radius: 0.75rem;
}
input:is([type="datetime-local"], [type="time"], [type="month"], [type="week"])::-webkit-datetime-edit {
  line-height: 1.4;
}
.invalid input:is([type="datetime-local"], [type="time"], [type="month"], [type="week"]) {
  border-color: var(--fail-ink);
}
/* Monospace for the workflow fields where people paste machine text. */
textarea[name="urls"],
input:is([name="old_hosts"], [name="requirement_id"]) {
  font-family: var(--font-mono);
  font-size: 0.875rem;
}
/* The other one-action cards get the account forms' full-width call to action. */
form:is([action="/verify"], [action="/invite/accept"], [action="/orgs/new"]) > p:last-child > button[type="submit"] {
  flex: 1 1 auto;
  min-height: 3.25rem;
  font-size: 1rem;
}

/* A4. Values that must not break, and values that may.
   .id / .nowrap  an identifier or date stays on one line: <code class="id">DEV-IMG-04</code>,
                  <span class="nowrap">2026-10-28</span>. Short values only (ids, key prefixes, dates,
                  UUIDs); the |when_html filter emits a <time> made of .nowrap parts.
   .break         a long URL or e-mail address may break anywhere once a line is full; with the |wbr
                  filter it breaks after slashes and before ? # & @ first:
                  <span class="break">{{ url|wbr }}</span>.
   A table cell that holds nothing but one code (requirement id, key prefix, commit) keeps it on one
   line at every width, so its column is as wide as the id (the kit did this on phones only). A framed
   value to copy (<code class="url">, a DNS token) or one marked .break is long by nature and wraps. */
.id,
.nowrap,
td > code:only-child:not(.url, .break),
td > a:only-child > code:not(.url, .break) {
  white-space: nowrap;
  overflow-wrap: normal;
  word-break: normal;
}
.break {
  overflow-wrap: anywhere;
  word-break: normal;
}
/* …also against the kit's phone rule that keeps a lone code in a cell on one line. */
td > code:only-child:is(.url, .break),
td > a:only-child > code:is(.url, .break) {
  white-space: normal;
}

/* A5. Organisation switcher (_macros.html org_switcher): names as separate chips, the current one
   filled. <nav class="org-switch" aria-label="…"><span class="org-switch-label">Organisation:</span>
   <ul><li><a href="/keys?org=1" aria-current="page">…</a></li>…</ul></nav> */
.org-switch {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 0.75rem;
  margin: 0 0 1rem;
}
.org-switch-label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
}
.org-switch ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  min-width: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}
.org-switch li {
  max-width: 100%;
  margin: 0;
  padding: 0;
}
.org-switch a {
  display: inline-block;
  max-width: 100%;
  padding: 0.4rem 0.85rem;
  border: var(--rule-strong);
  border-radius: var(--radius-md);
  color: var(--fg-2);
  font-size: var(--text-sm);
  line-height: 1.35;
  text-decoration: none;
  overflow-wrap: break-word;
  transition:
    border-color var(--dur) var(--ease-out-expo),
    color var(--dur) var(--ease-out-expo);
}
.org-switch a:hover {
  border-color: var(--fg);
  color: var(--fg);
}
.org-switch a[aria-current="page"],
.org-switch a[aria-current="page"]:hover {
  border-color: var(--fg);
  background: var(--fg);
  color: var(--bg);
  font-weight: var(--weight-medium);
}

/* A6. Stacked tables on phones: <table class="stack">. The one pattern for tables with four or more
   columns, or with links and buttons. On phones each row becomes a small card: the title cell on a
   line of its own, the other cells as label/value pairs two to a line, wide cells and the actions
   full width. Nothing scrolls sideways and every control stays in the tab order. Markup:
     <table class="stack">
       <thead><tr><th scope="col">Name</th><th scope="col">Created</th>…</tr></thead>
       <tbody><tr>
         <td class="cell-title">Demo audit</td>                  (or <th scope="row">)
         <td data-label="{{ _("Created") }}">{{ k.created_at|when_html }}</td>
         <td class="cell-wide" data-label="{{ _("Address") }}"><span class="break">{{ url|wbr }}</span></td>
         <td class="cell-actions"><form …><button …>…</button></form></td>
       </tr></tbody>
     </table>
   data-label repeats the column head (the same catalogue string) above the value on phones. On wider
   screens a .stack table is an ordinary table. ":not(#_)" lifts these rules above the kit's long
   :has() selectors for tables (section 17) without a single !important. */
@media (max-width: 40rem) {
  table.stack:not(#_) {
    display: block;
    width: 100%;
    min-width: 0;
  }
  table.stack:not(#_) > caption {
    display: block;
  }
  table.stack:not(#_) > thead {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  table.stack:not(#_) > :is(tbody, tfoot) {
    display: block;
  }
  table.stack:not(#_) > :is(tbody, tfoot) > tr {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem 1rem;
    padding: 1rem 0;
    border-bottom: var(--rule);
  }
  table.stack:not(#_) > tbody > tr:first-child {
    padding-top: 0.25rem;
  }
  table.stack:not(#_) > tbody > tr:last-child {
    border-bottom: 0;
  }
  table.stack:not(#_) > :is(tbody, tfoot) > tr > :is(th, td) {
    display: block;
    grid-column: auto;
    width: auto;
    min-width: 0;
    padding: 0;
    border: 0;
    background: none;
    overflow-wrap: break-word;
  }
  table.stack:not(#_) > :is(tbody, tfoot) > tr > [data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 0.2rem;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    line-height: 1.3;
    letter-spacing: var(--tracking-kicker);
    text-transform: uppercase;
    color: var(--fg-3);
  }
  table.stack:not(#_) > :is(tbody, tfoot) > tr > :is(.cell-title, th[scope="row"]) {
    grid-column: 1 / -1;
    font-family: var(--font-sans);
    font-size: var(--text-base);
    font-weight: var(--weight-medium);
    letter-spacing: var(--tracking-body);
    text-transform: none;
    color: var(--fg);
  }
  table.stack:not(#_) > :is(tbody, tfoot) > tr > :is(.cell-wide, [colspan]) {
    grid-column: 1 / -1;
  }
  table.stack:not(#_) > :is(tbody, tfoot) > tr > .cell-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    grid-column: 1 / -1;
  }
  table.stack:not(#_) > :is(tbody, tfoot) > tr > .cell-actions > form.inline {
    margin: 0;
  }
  table.stack:not(#_) > :is(tbody, tfoot) > tr > :is(th, td):empty {
    display: none;
  }
  table.stack:not(#_) > tbody > tr:only-child > td[colspan] {
    padding: 2rem 1rem;
    text-align: center;
  }
  table.stack:not(#_) > tbody > tr:hover > td {
    background: none;
  }
  /* A cell marked .break (e-mail, URL, project) keeps A4's "break anywhere" against the cell rule above. */
  table.stack:not(#_) > :is(tbody, tfoot) > tr > .break {
    overflow-wrap: anywhere;
  }
}

/* A7. Verdict chips for states that are not audit results reuse the kit's values, so no new colours:
     pass            verified, done, active, on, connected, accepted
     warn            waiting on time or a person, incomplete, capped, expiring soon
     fail            a failed check, a refused verification, hard failures
     error           a technical failure (job, crawl or render error)
     manual          attested, needs a person to look
     open            queued, running, not started (hollow neutral ring)
     skipped         off, revoked, expired, cancelled, never
     not_applicable  does not apply
   <span class="verdict" data-v="pass">{{ _("Verified") }}</span> */

/* A8. Empty states outside a table use the kit's .empty (section 15):
   <div class="empty"><p>{{ _("No releases yet.") }}</p></div> */

/* A9. Requirement ids after an h2's text (workflows: <h2>Wartungsübung <code class="id">DEV-SRV-03</code></h2>)
   get the kit's id pill from "h1/h3 > code:first-child", inline and set beside the words. */
h2 > code {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  font-size: var(--text-kicker);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  line-height: 1.2;
  color: var(--accent-ink);
  vertical-align: 0.35em;
}
h2 > code:first-child {
  margin: 0 0.35rem 0 0;
}

/* A10. Several forms in one card (checklist item "Ihre Entscheidung", Google intent and prefill): a rule
   between them shows which textarea belongs to which button. Inline button forms are left alone. */
.card > form:not(.inline) + form:not(.inline) {
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: var(--rule);
}

/* A11. Render screenshots side by side: <div class="shots"><figure>…</figure>…</div>. One column on
   phones; the kit's figure margin would double the grid gap. */
.shots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
  gap: var(--space-5);
  align-items: start;
  margin: var(--space-4) 0 var(--space-6);
}
.shots > figure {
  margin: 0;
}

/* A12. On phones a long word in a title (an organisation name in "Team von …", "Join …") is hyphenated
   by the page language instead of breaking without a hyphen. Short words are never split. */
@media (max-width: 40rem) {
  h1 {
    -webkit-hyphens: auto;
    hyphens: auto;
    hyphenate-limit-chars: 10 4 4;
  }
}

/* A13. Header on phones: the sections scroll sideways in one row under the brand instead of wrapping
   into four rows; sign out and the language chip leave the scroller and sit on the brand's row, so
   they are never scrolled away. A soft edge on the right shows that the row goes on (the kit's
   scroll-shadow technique, as on cards). Signed out the header is short already and stays as it is. */
@media (max-width: 40rem) {
  header.top:has(nav form.inline) {
    padding-bottom: var(--space-1);
  }
  header.top:has(nav form.inline) nav {
    flex: 1 0 100%;
    flex-wrap: nowrap;
    min-width: 0;
    margin: 0 calc(-1 * var(--gutter));
    padding: 0.25rem 2.5rem 0.25rem calc(var(--gutter) - var(--nav-pad));
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-padding-inline: var(--gutter) 2.5rem;
    scrollbar-width: none;
    background:
      linear-gradient(to left, var(--bg) 35%, transparent) right center / 2.5rem 100% no-repeat local,
      radial-gradient(farthest-side at 100% 50%, var(--scroll-shade), transparent) right center / 0.75rem 100% no-repeat scroll;
  }
  header.top:has(nav form.inline) nav::-webkit-scrollbar {
    display: none;
  }
  header.top nav form.inline:has(+ a[hreflang]) {
    position: absolute;
    top: calc(var(--space-3) + 0.125rem);
    right: calc(var(--gutter) + var(--lang-w) + 0.35rem);
    margin: 0;
    padding: 0;
    border-left: 0;
  }
  header.top nav form.inline + a[hreflang] {
    position: absolute;
    top: calc(var(--space-3) + 0.25rem);
    right: var(--gutter);
    margin: 0;
  }
}

/* On laptops (64 to 90rem) the links sit a little closer, so the German nav fits beside the brand on one
   row as the English one does, and the page starts at the same height in both languages. */
@media (min-width: 64.0625rem) and (max-width: 90rem) {
  header.top nav {
    --nav-pad: 0.375rem;
  }
}

/* A14. Light theme: the lime of a positive chip vanishes on paper; the chip's dot takes the theme's
   pass ink (lime on dark, olive on paper), as the notices' dot already does. */
.verdict[data-v="pass"] {
  --v: var(--pass-ink);
}

/* A15. A caution (an app on the user's computer, a site not verified yet): amber instead of the
   notice's positive dot. <p class="notice warn" role="alert">…</p> */
.notice.warn {
  border-color: color-mix(in oklab, var(--warn-ink) 55%, transparent);
  border-left: 3px solid var(--warn-ink);
  background: color-mix(in oklab, var(--warn-ink) 8%, transparent);
}
.notice.warn::before {
  background: var(--warn-ink);
  box-shadow: 0 0 0 1px var(--dot-ring);
}

/* A16. Titles that carry data. A long name or URL never sets the display size:
     <h1>Audits<span class="h1-sub">Org name</span></h1>                  the name as a smaller second line
     <h1>Audit</h1><p class="audit-url"><code>{{ url|wbr }}</code></p>   the URL in mono under it
     <h1>Allow access?</h1><p class="app-name"><strong>App</strong> wants …</p>   consent */
.h1-sub {
  display: block;
  margin-top: 0.4rem;
  font-size: var(--text-lg);
  font-weight: var(--weight-medium);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-body);
  color: var(--fg-2);
  -webkit-hyphens: manual;
  hyphens: manual;
  text-wrap: balance;
}
.audit-url {
  margin: -0.5rem 0 1.25rem;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
}
.audit-url code {
  padding: 0;
  background: none;
  font-size: inherit;
  color: var(--fg-2);
}
.app-name {
  font-size: var(--text-md);
  overflow-wrap: anywhere;
}
.app-name strong {
  display: block;
  margin-bottom: 0.15rem;
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
}

/* A17. Organisation chips stay one line each; a long name is cut with an ellipsis (its title shows
   it whole, and the page names the organisation elsewhere). */
.org-switch a {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: top;
}

/* A18. An e-mail address ({{ email|email_wbr }}) wraps only after its @ and before a dot. After a
   person's name it goes muted and smaller on a line of its own:
   <td class="cell-title">Name<span class="email email-sub">{{ email|email_wbr }}</span></td> */
.email {
  overflow-wrap: normal;
  word-break: normal;
}
.email-sub {
  display: block;
  font-size: var(--text-sm);
  color: var(--fg-2);
}

/* A19. Tables on wider screens: an actions cell is as narrow as its widest button, so the name column gets
   the room; buttons and links drawn as buttons never wrap inside their pill; a date with its time
   (|when_html) stays on one line. */
td button,
td a.button {
  white-space: nowrap;
}
@media (min-width: 40.0625rem) {
  td.cell-actions {
    width: 1%;
  }
  td > time,
  td > a > time {
    white-space: nowrap;
  }
}

/* A20. Key/value tables (<th scope="row"> then the value) on phones: the label above its value, so a
   long value (a DNS token, a URL) gets the whole width instead of squeezing the label to a letter. */
@media (max-width: 40rem) {
  table:not(.stack):not(:has(> thead)):has(> tbody > tr > th[scope="row"]):not(#_) {
    display: block;
    width: 100%;
    min-width: 0;
  }
  table:not(.stack):not(:has(> thead)):has(> tbody > tr > th[scope="row"]):not(#_) > tbody {
    display: block;
  }
  table:not(.stack):not(:has(> thead)):has(> tbody > tr > th[scope="row"]):not(#_) > tbody > tr {
    display: block;
    padding: 0.7rem 0;
    border-bottom: var(--rule);
  }
  table:not(.stack):not(:has(> thead)):has(> tbody > tr > th[scope="row"]):not(#_) > tbody > tr > :is(th, td) {
    display: block;
    width: auto;
    min-width: 0;
    padding: 0;
    border: 0;
  }
  table:not(.stack):not(:has(> thead)):has(> tbody > tr > th[scope="row"]):not(#_) > tbody > tr > th[scope="row"] {
    padding-bottom: 0.25rem;
  }
}

/* A21. Buttons that end a card's form sit one under another on phones at the same full width. */
@media (max-width: 40rem) {
  .card form > p:last-child > :is(button, a.button),
  .card > p:last-child > a.button,
  .card p > a.button:only-child {
    flex: 1 1 100%;
    width: 100%;
  }
}

/* A22. A disabled call to action is grey, not a faded lime that reads as another colour. A form whose
   fields wait with it wraps them in <fieldset class="plain" disabled>. */
button:not(.secondary, .danger, .link):disabled,
button:not(.secondary, .danger, .link):disabled:hover {
  opacity: 1;
  border-color: var(--line);
  background: var(--bg-3);
  color: var(--fg-3);
}
fieldset.plain {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* A23. A value to copy by hand (payload URL, push URL) breaks at its slashes where it can, not in the
   middle of a word: <code class="url copy">{{ url|wbr }}</code>, on a line of its own. */
code.url.copy {
  word-break: normal;
  overflow-wrap: anywhere;
}
p.copy-line {
  margin-top: 0.4rem;
}
td .push-label {
  margin-right: 0.5rem;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--fg-3);
}
td.push-row > form.inline {
  margin: 0.5rem 0.75rem 0 0;
}

/* A24. Findings grouped by result on the audit page: the groups that need nobody start closed.
   <details class="group" id="status-pass"><summary><span class="verdict" data-v="pass">Pass <b>28</b></span></summary><table>…</table></details> */
details.group {
  border-top: var(--rule);
  scroll-margin-top: var(--space-4);
}
details.group:last-child {
  border-bottom: var(--rule);
}
details.group > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.75rem;
  min-height: var(--control-h);
  padding: var(--space-3) 0;
  cursor: pointer;
  list-style-position: inside;
}
details.group > summary::marker,
details.group > summary::-webkit-details-marker {
  color: var(--fg-3);
}
details.group > summary:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
  border-radius: 2px;
}
details.group > summary > .hint {
  font-size: var(--text-sm);
}
/* The group's own open/closed mark: a small chevron after the chip (the native marker is gone with flex). */
details.group > summary::after {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  margin-left: 0.15rem;
  border-right: 1.5px solid var(--fg-3);
  border-bottom: 1.5px solid var(--fg-3);
  transform: translateY(-0.15rem) rotate(45deg);
  transition: transform var(--dur) var(--ease-out-expo);
}
details.group[open] > summary::after {
  transform: translateY(0.1rem) rotate(-135deg);
}
details.group > summary:hover::after {
  border-color: var(--fg);
}
details.group[open] > summary {
  margin-bottom: var(--space-2);
}
a.verdict {
  text-decoration: none;
}
a.verdict:hover {
  border-color: var(--fg);
  color: var(--fg);
}

/* A25. Plans side by side on the billing page; the card of the current plan is outlined. */
.plans {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: var(--space-5);
  margin: 0 0 var(--space-5);
}
.plans > .card {
  display: flex;
  flex-direction: column;
  margin: 0;
}
.plans > .card > form:first-of-type {
  margin-top: auto;
}
/* The two intervals of a plan are one choice: no rule between their forms (A10 is for separate forms). */
.plans > .card > form + form {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.plans > .card > form > p {
  margin-bottom: 0.6rem;
}
.plans > .card.current {
  border-color: var(--accent-ink);
}
.plans > .card > h2 {
  margin-top: 0;
}

/* A26. A file field in the page language: the label is the button, the browser's own button and its
   "no file chosen" text are hidden, and the chosen file's name shows once there is one.
   <p class="field file-pick"><label class="button secondary" for="f-file">…</label><input type="file" required>
   <span class="file-none" aria-hidden="true">…</span><span class="hint">…</span></p> */
.file-pick {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: 0.5rem 0.85rem;
  text-align: start;
}
/* The label drawn as the kit's secondary button (the kit styles button and a.button only). */
.file-pick > label.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--control-h);
  margin: 0;
  padding: 0.55rem 1.35rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--fg);
  font-size: 0.9375rem;
  font-weight: var(--weight-medium);
  line-height: 1.2;
  cursor: pointer;
  transition:
    background-color var(--dur) var(--ease-out-expo),
    color var(--dur) var(--ease-out-expo),
    border-color var(--dur) var(--ease-out-expo);
}
.file-pick > label.button:hover {
  border-color: var(--fg);
  background: var(--fg);
  color: var(--bg);
}
.file-pick > input[type="file"] {
  width: auto;
  min-width: 0;
  max-width: 100%;
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--fg);
  font: inherit;
  font-size: var(--text-sm);
}
.file-pick > input[type="file"]::file-selector-button {
  display: none;
}
.file-pick > input[type="file"]:invalid {
  width: 1px;
  color: transparent;
}
.file-pick > input[type="file"]:valid + .file-none {
  display: none;
}
.file-pick > .file-none {
  font-size: var(--text-sm);
  color: var(--fg-3);
}
.file-pick > :is(.hint, .error) {
  flex: 1 0 100%;
  margin: 0;
}
.file-pick:has(> input:focus-visible) > label.button {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

/* A27. Render screenshots: same-shaped thumbnails (the top of the page), each a link to the full image. */
.shots img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: top;
  border: var(--rule);
  border-radius: var(--radius-md);
}

/* A28. The period tabs above a figure or an empty state keep their distance. */
.pagination {
  margin-bottom: var(--space-4);
}

/* A29. A detail page that can be a single card (a queued crawl, a render) keeps the wide layout of its
   siblings: {% block main_class %}wide{% endblock %}. The kit narrows every one-card page without a
   table, which is right for sign-in and messages only. */
main.wide:has(> .card:only-child):not(:has(table)) {
  max-width: calc(var(--main-max) + 2 * var(--gutter));
  padding-top: clamp(2rem, 5vw, 4.5rem);
}
main.wide:has(> .card:only-child):not(:has(table)) h1 {
  font-size: clamp(2.1rem, 3.8vw, 3.75rem);
}
main.wide:has(> .card:only-child):not(:has(table)) .card {
  padding: var(--card-pad);
  border-color: var(--line);
  background: var(--card);
  box-shadow: none;
}

/* A30. Short labels in a table column (a level, a source) stay on one line on wide screens. */
@media (min-width: 40.0625rem) {
  td.nowrap {
    white-space: nowrap;
  }
}

/* A31. Signed out, a page whose card has its own call to action (an invitation: sign in) does not get a
   second lime button in the header: "Create account" there becomes an outlined chip. */
body:has(main .card a.button:not(.secondary)) header.top nav > a[href="/signup"] {
  border: var(--rule-strong);
  background: none;
  color: var(--fg);
}
body:has(main .card a.button:not(.secondary)) header.top nav > a[href="/signup"]:hover {
  border-color: var(--fg);
  background: none;
  color: var(--fg);
}

/* A32. In a stacked table the title cell leads its card even when it is not the row's first cell. */
@media (max-width: 40rem) {
  table.stack:not(#_) > tbody > tr > .cell-title {
    order: -1;
  }
}

/* A33. Checked URLs of a workflow: the URL and the expectation get the room, the status code and the
   date only what they need. */
@media (min-width: 40.0625rem) {
  table.url-rows > thead > tr > th:nth-child(1) {
    width: 24%;
  }
  table.url-rows > thead > tr > th:nth-child(2) {
    width: 30%;
  }
  table.url-rows > thead > tr > th:nth-child(3) {
    width: 7%;
  }
  table.url-rows > thead > tr > th:nth-child(4) {
    width: 13%;
  }
}

@media print {
  .org-switch {
    display: none;
  }
}

/* Legal pages: postal addresses upright, like the rest of the text. */
.prose address {
  font-style: normal;
  margin-block: 0 1rem;
}
