/* ============================================================================
   Customsfeed — one stylesheet for every surface.

   WHY ONE FILE

   Until this file existed the CSS lived in three <style> blocks (base.html,
   hub.html, landing.html) plus a shared partial, plus a Jinja macro file for
   the dark palettes, plus a hundred-odd inline style attributes. The three
   blocks had drifted the way copies do: 49 distinct font sizes, 11 corner
   radii, and two names for the same red — base.html called it --critical, the
   hub called it --crit, and the shared shell partial had to define a third
   name of its own because it could not rely on either. Nothing looked broken
   in isolation; it looked like five products.

   So: one file, two layers. The token layer below states the decisions — the
   type scale, the spacing scale, the corner radii, the control heights, the
   ramps the colours come out of. The component layer states nothing but which
   tokens a thing uses. A change to the product's look is a change to the first
   layer, which is the property that was missing.

   NO BUILD STEP, NO CDN — the same constraint as the rest of the UI. This is
   plain CSS, served by the application itself (see api/assets.py), so it works
   from a laptop with no network and inside the serverless bundle alike. Custom
   properties do the job a preprocessor would, and are the reason this can be
   one file without becoming a pile of hard-coded hex.

   The URL carries a digest of this file's contents, so a browser holding
   yesterday's copy cannot answer a request for today's — a stale stylesheet
   does not look slightly old, it looks like the layout is destroyed.

   CONTROL HEIGHTS ARE A TOKEN, AND THAT IS THE POINT

   --control-h and friends exist because "the input is taller than the button
   beside it" is not a bug you fix once. It comes back every time someone pads
   a control by eye. A shared height that both of them set is the only version
   of the fix that stays fixed.
   ============================================================================ */


/* ── 1. Tokens: the primitives ──────────────────────────────────────────────
   The ramps. Nothing in the component layer may state a colour that is not
   resolved from here, and nothing here is used directly by a component — the
   semantic names in §2 are the interface. */
:root {
  color-scheme: light;

  /* Brand blue. #3b82f6 and #1e3a8a are the two stops of the gradient in
     static/favicon.svg, so the palette is derived from the mark rather than
     invented next to it. The rest of the ramp is the same family. */
  --brand-50:  #eff5ff;
  --brand-100: #dbe7fe;
  --brand-200: #bfd3ff;
  --brand-300: #93b4fd;
  --brand-400: #6091f9;
  --brand-500: #3b82f6;
  --brand-600: #2563eb;
  --brand-700: #1d4ed8;
  --brand-800: #1e40af;
  --brand-900: #1e3a8a;

  /* A cool neutral, because a warm grey beside this blue reads as two
     unrelated decisions. Everything structural — page, surfaces, rules,
     text — comes out of this ramp. */
  --slate-25:  #fafbfd;
  --slate-50:  #f5f7fa;
  --slate-100: #eef1f5;
  --slate-200: #e3e7ed;
  --slate-300: #cbd2dc;
  --slate-400: #8b95a5;
  --slate-500: #5b6675;
  --slate-600: #46505f;
  --slate-700: #343f4e;
  --slate-800: #232b38;
  --slate-900: #151b24;
  --slate-950: #0b0f15;

  /* Type. Eight steps, and a component picks one of them. The old CSS had 49
     sizes between .62rem and 1.75rem, which is not a scale, it is a history of
     individual decisions. */
  --text-2xs:  0.6875rem;  /* 11px — uppercase labels, keycaps, provenance    */
  --text-xs:   0.75rem;    /* 12px — captions, footnotes, counts              */
  --text-sm:   0.8125rem;  /* 13px — dense UI: tables, control bars, chips    */
  --text-base: 0.875rem;   /* 14px — body                                     */
  --text-md:   1rem;       /* 16px — card and drawer titles, prominent input  */
  --text-lg:   1.125rem;   /* 18px — page title                               */
  --text-xl:   1.375rem;   /* 22px — screen heading                           */
  --text-2xl:  1.75rem;    /* 28px — the one number a card is about           */

  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  --weight-medium: 550;
  --weight-semi:   620;
  --weight-bold:   660;

  /* Space. One scale, used for padding and for gaps alike. */
  --space-1: 0.25rem;
  --space-2: 0.375rem;
  --space-3: 0.5rem;
  --space-4: 0.75rem;
  --space-5: 1rem;
  --space-6: 1.5rem;
  --space-7: 2rem;
  --space-8: 3rem;

  /* Corners. Four, plus the pill. There were eleven. */
  --radius-sm:   4px;
  --radius:      7px;
  --radius-md:  10px;
  --radius-lg:  14px;
  --radius-pill: 999px;

  /* Control heights. Every interactive box on a row sets one of these, which
     is what makes a row of them line up. */
  --control-h:    32px;  /* control bars, filter forms, table row actions  */
  --control-h-sm: 24px;  /* actions inside a table cell                    */
  --control-h-lg: 46px;  /* the search that carries a whole screen         */

  --sidebar-w: 232px;
  --content-max: 1560px;

  --ease: cubic-bezier(.4, 0, .2, 1);
}


/* ── 2. Tokens: the semantics ───────────────────────────────────────────────
   What a component is allowed to name. Light first; §3 restates the same list
   for dark. */
:root {
  --bg:        var(--slate-50);
  --surface:   #ffffff;
  --surface-2: var(--slate-25);
  --surface-3: var(--slate-100);
  --fg:        var(--slate-900);
  --muted:     var(--slate-500);
  --faint:     var(--slate-400);
  --line:      var(--slate-200);
  --line-strong: var(--slate-300);

  --accent:       var(--brand-600);
  --accent-hover: var(--brand-700);
  --accent-soft:  var(--brand-50);
  --accent-line:  var(--brand-200);
  --accent-fg:    #ffffff;

  /* The five significance levels the domain already has names for. The hub
     used to call these --crit/--warn/--ok and base.html used the long names
     for the same three colours; the long names win because they are the words
     the API and the change feed use. */
  --critical: #b42318;      --critical-bg: #fdecea;
  --relevant: #8a5a00;      --relevant-bg: #fdf3e0;
  --informational: #175f7f; --informational-bg: #e6f2f8;
  --technical: #55606f;     --technical-bg: #eef1f5;
  --ok: #17724a;            --ok-bg: #e6f5ee;

  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .05);
  --shadow:    0 1px 2px rgba(16, 24, 40, .05), 0 1px 3px rgba(16, 24, 40, .06);
  --shadow-lg: 0 12px 32px rgba(16, 24, 40, .14), 0 2px 8px rgba(16, 24, 40, .06);

  --scrim: rgba(10, 12, 16, .34);

  /* The navigation stays dark in both themes. It is product chrome rather
     than page, and a dark rail beside a light document is what tells the two
     apart at a glance. */
  --sidebar:            var(--slate-900);
  --sidebar-fg:         #b9c1cd;
  --sidebar-fg-dim:     #838d9c;
  --sidebar-fg-strong:  #ffffff;
  --sidebar-active:     var(--slate-800);
  --sidebar-label:      #6b7686;
  --sidebar-rule:       #2a333f;

  /* Flags carry white and near-black fields, so they need an edge of their
     own or they bleed into the surface behind them. */
  --flag-edge: rgba(16, 24, 40, .16);
}


/* ── 3. Dark ────────────────────────────────────────────────────────────────
   Stated twice, on purpose, and the two copies must stay identical — there is
   a test that reads this file and compares them (tests/test_design_system.py).

   They cannot be one selector. Outside the media query
   `:root[data-theme="dark"]` has to win on a light system; inside it the
   system default has to lose to an explicit `data-theme="light"`. Plain CSS
   has no way to say "either of these" without repeating the declarations, and
   this used to be a Jinja macro emitted twice for exactly that reason. The
   macro is gone because a stylesheet that needs a template engine to be read
   is a stylesheet nobody can open. The test replaces it. */

/* dark, take 1 — the system setting, unless the switch has overruled it */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg:        var(--slate-950);
    --surface:   #12171f;
    --surface-2: #171d26;
    --surface-3: #1e2531;
    --fg:        #e6eaf0;
    --muted:     #98a3b3;
    --faint:     #6d798a;
    --line:      #232b36;
    --line-strong: #343f4e;
    --accent:       #7aa2ff;
    --accent-hover: #93b4fd;
    --accent-soft:  #16233c;
    --accent-line:  #2d4a86;
    --accent-fg:    #0b0f15;
    --critical: #ff8b80;      --critical-bg: #3a1b18;
    --relevant: #ffc46b;      --relevant-bg: #3a2d12;
    --informational: #8ecbe8; --informational-bg: #142c3a;
    --technical: #b3bac4;     --technical-bg: #262d38;
    --ok: #6fd6a0;            --ok-bg: #122b20;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .35);
    --shadow:    0 1px 2px rgba(0, 0, 0, .35), 0 1px 3px rgba(0, 0, 0, .3);
    --shadow-lg: 0 16px 40px rgba(0, 0, 0, .55), 0 2px 8px rgba(0, 0, 0, .4);
    --scrim: rgba(0, 0, 0, .58);
    --sidebar:           #080b0f;
    --sidebar-fg:        #99a3b1;
    --sidebar-fg-dim:    #6d7887;
    --sidebar-fg-strong: #ffffff;
    --sidebar-active:    #1c232e;
    --sidebar-label:     #6b7686;
    --sidebar-rule:      #212832;
    --flag-edge: rgba(255, 255, 255, .18);
  }
}

/* dark, take 2 — the switch, on a light system */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg:        var(--slate-950);
  --surface:   #12171f;
  --surface-2: #171d26;
  --surface-3: #1e2531;
  --fg:        #e6eaf0;
  --muted:     #98a3b3;
  --faint:     #6d798a;
  --line:      #232b36;
  --line-strong: #343f4e;
  --accent:       #7aa2ff;
  --accent-hover: #93b4fd;
  --accent-soft:  #16233c;
  --accent-line:  #2d4a86;
  --accent-fg:    #0b0f15;
  --critical: #ff8b80;      --critical-bg: #3a1b18;
  --relevant: #ffc46b;      --relevant-bg: #3a2d12;
  --informational: #8ecbe8; --informational-bg: #142c3a;
  --technical: #b3bac4;     --technical-bg: #262d38;
  --ok: #6fd6a0;            --ok-bg: #122b20;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .35);
  --shadow:    0 1px 2px rgba(0, 0, 0, .35), 0 1px 3px rgba(0, 0, 0, .3);
  --shadow-lg: 0 16px 40px rgba(0, 0, 0, .55), 0 2px 8px rgba(0, 0, 0, .4);
  --scrim: rgba(0, 0, 0, .58);
  --sidebar:           #080b0f;
  --sidebar-fg:        #99a3b1;
  --sidebar-fg-dim:    #6d7887;
  --sidebar-fg-strong: #ffffff;
  --sidebar-active:    #1c232e;
  --sidebar-label:     #6b7686;
  --sidebar-rule:      #212832;
  --flag-edge: rgba(255, 255, 255, .18);
}


/* ── 4. Base ────────────────────────────────────────────────────────────── */
* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: var(--text-base)/1.55 var(--font-sans);
  -webkit-font-smoothing: antialiased;
  /* break-word, not anywhere: a token that cannot fit — a raw-file URI, a
     checksum, CUSTOMSFEED_DEBUG_UI_ENABLED — breaks, and ordinary prose is
     left alone. Without it one such token in a release note makes the whole
     page scroll sideways on a phone. */
  overflow-wrap: break-word;
}

/* The workspace does not scroll as a document: its table scrolls inside a
   fixed frame, so the page may not grow with its content. */
body.workspace { overflow: hidden; font-size: var(--text-base); line-height: 1.5; }

a { color: var(--accent); }
a:hover { color: var(--accent-hover); }

/* A bare <button> has to look like one, so the element default is the same
   shape as .btn (§7). It belongs here, at the base, rather than beside .btn:
   a component that restyles its buttons writes `.something button:hover`,
   which has the same specificity as `button:hover` — so whichever is written
   later wins, and that has to be the component. Element specificity on
   purpose too: the tariff tiles, the switcher menu, the chips' remove
   crosses, the theme switch and the actions inside a table row all carry a
   class, and a class must be able to win without saying !important. */
button {
  cursor: pointer;
  height: var(--control-h); padding: 0 var(--space-4);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--surface); color: var(--fg); font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}
button:hover { background: var(--surface-3); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: var(--radius-sm);
}

h1, h2, h3, h4 { letter-spacing: -0.01em; }

code, .mono { font-family: var(--font-mono); font-size: 0.9em; }

.muted { color: var(--muted); }
.nowrap { white-space: nowrap; }
.scroll { overflow-x: auto; }
.num, th.num, td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* A one-line qualifier under or beside a heading. Was three near-identical
   rules scoped to the topbar, the drawer header and the landing header. */
.sub { color: var(--muted); font-size: var(--text-sm); }

/* The paragraph that introduces a screen. */
.lede { color: var(--muted); margin: 0; max-width: 60ch; }

.note {
  border-left: 3px solid var(--line-strong);
  padding-left: var(--space-4);
  color: var(--muted);
  font-size: var(--text-sm);
}

.empty { padding: var(--space-7) var(--space-5); text-align: center; color: var(--muted); }

.old  { color: var(--critical); text-decoration: line-through; }
.new  { color: var(--ok); font-weight: 600; }
.pass { color: var(--ok); font-weight: var(--weight-semi); }
.fail { color: var(--critical); font-weight: var(--weight-semi); }


/* ── 5. Shell: sidebar, content column, topbar ──────────────────────────── */
.shell { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100%; }
.shell.fixed { height: 100%; min-height: 0; overflow: hidden; }

.sidebar {
  background: var(--sidebar); color: var(--sidebar-fg);
  display: flex; flex-direction: column; gap: var(--space-6);
  padding: var(--space-5) var(--space-4); position: sticky; top: 0; height: 100vh;
}
.shell.fixed .sidebar { height: 100%; overflow-y: auto; }

.brand {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 0 var(--space-3); text-decoration: none;
}
.brand .name {
  color: var(--sidebar-fg-strong); font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
}
/* The mark is static/favicon.svg, so it brings its own gradient and its own
   corner radius — a CSS radius on top of the artwork's would clip it. */
.mark { flex: none; display: block; }

.nav-group { display: flex; flex-direction: column; gap: 0.15rem; }
.nav-label {
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--sidebar-label); padding: 0 var(--space-3); margin-bottom: var(--space-1);
}
/* The operating surfaces, set apart rather than merely listed further down.
   A rule and a dimmer set of links say "different kind of thing" at a glance,
   which a fourth heading of equal weight did not. */
.nav-group.admin {
  border-top: 1px solid var(--sidebar-rule);
  padding-top: var(--space-5); margin-top: -0.4rem;
}
.nav-group.admin .nav-item { color: var(--sidebar-fg-dim); }
.nav-group.admin .nav-item:hover,
.nav-group.admin .nav-item.active { color: var(--sidebar-fg-strong); }

.sidebar .nav-item {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius);
  color: var(--sidebar-fg); text-decoration: none; font-size: var(--text-base);
}
.sidebar .nav-item:hover,
.sidebar .nav-item.active { background: var(--sidebar-active); color: var(--sidebar-fg-strong); }
.sidebar .nav-item.active { font-weight: var(--weight-medium); }
.sidebar .nav-item svg { width: 16px; height: 16px; flex: none; opacity: .85; }
/* How many commodity codes are on the Merkliste, written by the sidebar's own
   script once the browser has read it. */
.sidebar .nav-count {
  margin-left: auto; font-size: var(--text-xs); font-variant-numeric: tabular-nums;
  background: var(--sidebar-active); color: var(--sidebar-fg-strong);
  border-radius: var(--radius-pill); padding: 0.05rem var(--space-2); flex: none;
}
.sidebar .spacer { flex: 1; }

/* -- theme switch (see _theme_switch.html) -- */
.theme-switch { display: flex; gap: 0.15rem; }
/* Icon over caption, so this one is two lines tall rather than one control
   high — `height: auto` is load-bearing: the default button height squashed
   the icon to a third of its size instead of overflowing visibly. */
.theme-switch button {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
  height: auto; padding: var(--space-2) var(--space-1); border: 0;
  border-radius: var(--radius); cursor: pointer; background: none;
  color: var(--sidebar-fg); font: inherit; font-size: var(--text-2xs); line-height: 1.1;
}
.theme-switch button svg { width: 15px; height: 15px; flex: none; opacity: .85; }
.theme-switch button:hover { background: var(--sidebar-active); color: var(--sidebar-fg-strong); }
.theme-switch button[aria-pressed="true"] {
  background: var(--sidebar-active); color: var(--sidebar-fg-strong);
  font-weight: var(--weight-medium);
}
.theme-switch button[aria-pressed="true"] svg { opacity: 1; }

.content { min-width: 0; display: flex; flex-direction: column; }
.shell.fixed .content { min-height: 0; overflow: hidden; }

.topbar {
  display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap;
  padding: var(--space-4) var(--space-6); border-bottom: 1px solid var(--line);
  background: var(--surface); position: sticky; top: 0; z-index: 5; flex: none;
}
.topbar h1 {
  font-size: var(--text-lg); margin: 0; font-weight: var(--weight-semi);
}
.topbar .right { margin-left: auto; display: flex; align-items: center; gap: var(--space-4); }

main { padding: var(--space-6) var(--space-6) var(--space-8); max-width: var(--content-max); width: 100%; }

.health {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: var(--text-sm); color: var(--muted);
}
.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); flex: none; }
.dot.bad { background: var(--critical); }


/* ── 6. Data status (see _datastand.html) ───────────────────────────────── */
.datastand { position: relative; }
.datastand > summary {
  display: inline-flex; align-items: center; gap: var(--space-2); cursor: pointer;
  font-size: var(--text-sm); color: var(--muted); list-style: none;
  padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill);
  border: 1px solid transparent; white-space: nowrap;
}
.datastand > summary::-webkit-details-marker { display: none; }
.datastand > summary:hover { border-color: var(--line); background: var(--surface-2); color: var(--fg); }
.datastand > summary .caret { font-size: var(--text-2xs); opacity: .7; }
.datastand[open] > summary { border-color: var(--line); background: var(--surface-2); }
.datastand[open] > summary .caret { transform: rotate(180deg); }
.ds-panel {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  min-width: 26rem; max-width: min(34rem, 92vw);
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  padding: var(--space-4);
  /* Three columns of dates in a panel pinned to a phone's width: the table
     scrolls inside the panel rather than making the whole page scroll
     sideways, which is what it did. */
  overflow-x: auto;
}
.ds-head { font-size: var(--text-sm); font-weight: var(--weight-semi); margin-bottom: var(--space-3); }
.ds-panel table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.ds-panel th {
  text-align: left; font-weight: 600; font-size: var(--text-2xs); text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--muted); padding: var(--space-1) var(--space-2);
  border-bottom: 1px solid var(--line); background: none; position: static;
}
.ds-panel td { padding: var(--space-1) var(--space-2); border-bottom: 1px solid var(--line); vertical-align: top; }
.ds-panel tr:last-child td { border-bottom: 0; }
.ds-stale { color: var(--critical); font-weight: 600; }
.ds-foot { margin: var(--space-3) 0 0; font-size: var(--text-xs); color: var(--muted); line-height: 1.45; }


/* ── 7. Controls ────────────────────────────────────────────────────────────
   One height for everything that sits on a row, so a row of them lines up
   without anyone measuring. Font size follows the same rule: a control bar is
   one size, not five. */
/* font-family, not the `font` shorthand: the shorthand also resets font-size,
   which would quietly undo the size the base layer gave a bare <button>. Form
   controls are the one place a browser does not inherit the page's typeface,
   so this is the whole of what has to be said. */
input, select, button, textarea { font-family: inherit; color: inherit; }

input, select, textarea {
  padding: 0 var(--space-3); border: 1px solid var(--line-strong);
  border-radius: var(--radius); background: var(--surface); color: var(--fg);
  font-size: var(--text-sm);
}
input, select { height: var(--control-h); }
input[type="checkbox"], input[type="radio"] { height: auto; padding: 0; }
textarea { padding: var(--space-3); line-height: 1.5; }
input::placeholder { color: var(--faint); }
input:disabled, select:disabled, button:disabled { opacity: .55; cursor: not-allowed; }

/* The label above a control. Uppercase and small on purpose: it names the
   field, it is not part of the answer. */
label {
  display: block; font-size: var(--text-2xs); line-height: 1.4; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: var(--space-1);
}

.btn, button.btn, a.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--control-h); padding: 0 var(--space-4);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--surface); color: var(--fg);
  font-size: var(--text-sm); font-weight: var(--weight-medium);
  white-space: nowrap; text-decoration: none;
}
.btn:hover { background: var(--surface-3); color: var(--fg); }
.btn svg { width: 14px; height: 14px; flex: none; }
.btn.primary, button.primary {
  background: var(--accent); border-color: var(--accent); color: var(--accent-fg);
}
.btn.primary:hover, button.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--accent-fg); }
.btn.on { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); }
.btn.sm { height: var(--control-h-sm); padding: 0 var(--space-3); font-size: var(--text-xs); }

/* A label + control pair. The gap is a token so every bar breathes the same. */
.field, form.filters > div {
  display: flex; flex-direction: column; gap: var(--space-1); min-width: 0;
}
.field > label, form.filters > div > label { margin-bottom: 0; }
.field select, .field input { width: 100%; }
/* A checkbox is a switch with a word beside it, not a field with a name above
   it — so it keeps the row's height and reads left to right. */
label.check {
  display: inline-flex; align-items: center; gap: var(--space-2);
  height: var(--control-h); margin: 0; cursor: pointer;
  text-transform: none; letter-spacing: 0; font-size: var(--text-sm); color: var(--fg);
}
label.check input[type="checkbox"] { margin: 0; }

/* The filter form on the document pages. */
form.filters {
  display: flex; gap: var(--space-4); flex-wrap: wrap; align-items: flex-end;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-md); padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-5); box-shadow: var(--shadow);
}
/* A filter form nested inside a card is already on a surface; it must not
   draw a second one. Was six copies of the same inline style. */
form.filters.bare { margin: 0; padding: 0; border: 0; box-shadow: none; background: none; }

.review-form { display: flex; gap: var(--space-1); align-items: center; flex-wrap: wrap; }
.review-form select, .review-form input, .review-form button {
  height: var(--control-h-sm); font-size: var(--text-xs); padding: 0 var(--space-2);
}

.actions { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; }
.actions.stack { flex-direction: column; align-items: stretch; }
.actions.right { margin-left: auto; }


/* ── 8. Surfaces ────────────────────────────────────────────────────────── */
h2 {
  font-size: var(--text-md); margin: var(--space-6) 0 var(--space-4);
  font-weight: var(--weight-semi);
}
h2:first-child { margin-top: 0; }

.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-md); box-shadow: var(--shadow);
}
.card > .card-head {
  padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap;
}
.card > .card-head h3 { margin: 0; font-size: var(--text-base); font-weight: var(--weight-semi); }
/* A label inside a card head sits beside its control, not above it. */
.card > .card-head label { margin: 0; }
/* The qualifier on the right of a card's head: what window, how many, whose.
   Was the same three inline declarations in six templates. */
.card > .card-head .meta { margin-left: auto; font-size: var(--text-xs); color: var(--muted); }
.card > .card-head .meta a { font-size: inherit; }
.card > .card-body { padding: var(--space-5); }
.card > .card-body > p:first-child { margin-top: 0; }
.card > .card-body > p:last-child { margin-bottom: 0; }
.card > .card-body.flush { padding: 0; }
/* A body that opens out of a <summary> rather than following a head. */
.card > .card-body.ruled { border-top: 1px solid var(--line); }
.card.narrow { max-width: 27rem; margin: var(--space-8) auto; }
.card.prose-width { max-width: 46rem; }

.grid { display: grid; gap: var(--space-5); }
.grid.cols-2 { grid-template-columns: repeat(auto-fit, minmax(390px, 1fr)); }
/* A grid item will not shrink below its min-content width unless told to, and
   min-content here is however long the longest unbreakable token inside
   happens to be — one raw-file URI in a release note and the column, the card
   and then the whole page are wider than the phone holding them. */
.grid > *, .tiles > *, .home-grid > *, .link-grid > *, .tariff-grid > * { min-width: 0; }

.tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  gap: var(--space-4); margin-bottom: var(--space-6);
}
.tile {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-md); padding: var(--space-4) var(--space-5);
  box-shadow: var(--shadow);
}
.tile .l {
  color: var(--muted); font-size: var(--text-2xs);
  text-transform: uppercase; letter-spacing: 0.05em;
}
.tile .n {
  font-size: var(--text-2xl); font-weight: var(--weight-bold);
  letter-spacing: -0.025em; margin-top: 0.15rem; font-variant-numeric: tabular-nums;
}
.tile .foot { font-size: var(--text-xs); color: var(--muted); margin-top: 0.2rem; }
.tile.accent { border-color: var(--accent-line); }

/* The band above the fold: what is wrong, said in words. The health check ran
   on every page long before it had anywhere to print its findings. */
.band {
  border: 1px solid var(--line); border-left-width: 3px;
  border-radius: var(--radius-md); background: var(--surface);
  padding: var(--space-4) var(--space-5); margin-bottom: var(--space-5);
  box-shadow: var(--shadow);
}
.band.bad { border-left-color: var(--critical); background: var(--critical-bg); }
.band.ok  { border-left-color: var(--ok); }
.band.run { border-left-color: var(--relevant); }
.band-head { font-weight: var(--weight-semi); font-size: var(--text-base); }
.band-foot { color: var(--muted); font-size: var(--text-sm); margin-top: var(--space-1); }
.band ul { margin: var(--space-2) 0 0; padding-left: var(--space-5); font-size: var(--text-sm); }
.band li { margin: 0.2rem 0; }
.band.bad, .band.bad a { color: var(--critical); }
.band.bad .band-foot { color: color-mix(in srgb, var(--critical) 75%, var(--fg)); }


/* ── 9. Tables ──────────────────────────────────────────────────────────── */
table { border-collapse: collapse; width: 100%; font-size: var(--text-sm); }
th, td { text-align: left; padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--line); vertical-align: top; }
thead th {
  font-weight: 600; color: var(--muted); font-size: var(--text-2xs);
  text-transform: uppercase; letter-spacing: 0.05em;
  background: var(--surface-2); position: sticky; top: 0;
}
tbody tr:hover { background: var(--surface-2); }
tbody tr:last-child td { border-bottom: 0; }
/* Actions that live in a table cell: small, on one line, and the same height
   whether they are links or buttons. */
.row-actions { display: flex; gap: var(--space-1); white-space: nowrap; }
.row-actions a, .row-actions button {
  display: inline-flex; align-items: center; height: var(--control-h-sm);
  padding: 0 var(--space-3); font-size: var(--text-xs); font-weight: 400;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--fg); text-decoration: none;
}
.row-actions a:hover, .row-actions button:hover { background: var(--surface-2); }
/* The widest a cell of free text may get before it starts pushing the columns
   that carry the answer off the screen. */
td.detail-cell { max-width: 32rem; }
/* One button per adapter, side by side inside a table cell. */
.run-action { display: inline-block; margin: 0 var(--space-1) var(--space-1) 0; }


/* ── 10. Badges, tags, chips, keycaps ───────────────────────────────────── */
.badge {
  display: inline-block; padding: 0.12rem var(--space-3); border-radius: var(--radius-pill);
  font-size: var(--text-xs); font-weight: 600; white-space: nowrap;
}
.badge.critical      { color: var(--critical);      background: var(--critical-bg); }
.badge.relevant      { color: var(--relevant);      background: var(--relevant-bg); }
.badge.informational { color: var(--informational); background: var(--informational-bg); }
.badge.technical     { color: var(--technical);     background: var(--technical-bg); }
.badge.ok            { color: var(--ok);            background: var(--ok-bg); }
.badge.neutral       { color: var(--muted);         background: var(--technical-bg); }
/* A badge used as a message rather than a marker: full width, room to read. */
.badge.block {
  display: block; padding: var(--space-3) var(--space-4);
  border-radius: var(--radius); white-space: normal;
  margin: 0 0 var(--space-4);
}
a.badge { text-decoration: none; }

/* A cloud of commodity codes under a snapshot: each one a link back into the
   change list, each one the same shape. */
.top-codes { margin-bottom: var(--space-5); }
.top-codes h4 {
  margin: 0 0 var(--space-2); font-size: var(--text-2xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted);
}
.top-codes a.badge { margin: 0 var(--space-1) var(--space-1) 0; }

.tag {
  font-size: var(--text-xs); padding: 0.08rem var(--space-2);
  border-radius: var(--radius-pill); background: var(--surface-3); color: var(--muted);
  font-weight: 600;
}
.tag.ok       { background: var(--ok-bg); color: var(--ok); }
.tag.relevant { background: var(--relevant-bg); color: var(--relevant); }
.tag.critical { background: var(--critical-bg); color: var(--critical); }
.tag.accent   { background: var(--accent-soft); color: var(--accent); }

kbd {
  font-family: inherit; font-size: var(--text-2xs);
  border: 1px solid var(--line-strong); border-bottom-width: 2px;
  border-radius: var(--radius-sm); padding: 0 var(--space-1);
  margin-right: 0.15rem; color: var(--fg);
}


/* ── 11. Charts, feeds and prose (no JS, no dependency) ─────────────────── */
.bars { display: flex; flex-direction: column; gap: var(--space-3); }
.bar-row {
  display: grid; grid-template-columns: 106px 1fr 44px; align-items: center;
  gap: var(--space-3); font-size: var(--text-sm);
}
.bar-track { background: var(--technical-bg); border-radius: var(--radius-pill); height: 8px; overflow: hidden; }
/* display:block is load-bearing: these are spans, and the track's children are
   not grid/flex items in the single-bar variant, so an inline box would drop
   width and height silently. */
.bar-fill { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--accent); }
.bar-track.segmented { display: flex; gap: 2px; background: none; }
.bar-track.segmented .bar-fill { flex: none; }
.bar-fill.critical      { background: var(--critical); }
.bar-fill.relevant      { background: var(--relevant); }
.bar-fill.informational { background: var(--informational); }
.bar-fill.technical     { background: var(--technical); }
.bar-row .v { text-align: right; color: var(--muted); font-variant-numeric: tabular-nums; }

/* Days as columns, levels stacked inside one. Percentage heights resolve
   against .day, which is why it carries an explicit height rather than
   stretching — an auto-height column would collapse every segment to nothing. */
.days { display: flex; align-items: flex-end; gap: 3px; height: 118px; }
.days .day {
  flex: 1 1 0; min-width: 0; height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 1px;
}
.days .seg { display: block; min-height: 2px; border-radius: 2px; background: var(--accent); }
.days .seg.critical      { background: var(--critical); }
.days .seg.relevant      { background: var(--relevant); }
.days .seg.informational { background: var(--informational); }
.days .seg.technical     { background: var(--technical); }
/* A day with nothing keeps its column and shows a baseline: a missing import
   is exactly what this chart is for, and a gap that closes up silently is the
   one thing it must not do. */
.days .none { display: block; height: 2px; border-radius: 2px; background: var(--line-strong); }
.day-labels { display: flex; gap: 3px; margin-top: var(--space-1); }
.day-labels span {
  flex: 1 1 0; min-width: 0; text-align: center; overflow: hidden;
  font-size: var(--text-2xs); color: var(--muted); font-variant-numeric: tabular-nums;
}
.legend {
  display: flex; gap: var(--space-4); flex-wrap: wrap; align-items: center;
  margin-top: var(--space-4); font-size: var(--text-xs); color: var(--muted);
}
.legend span { display: inline-flex; align-items: center; gap: var(--space-1); }
.legend i { width: 9px; height: 9px; border-radius: 2px; background: var(--accent); }
.legend i.critical      { background: var(--critical); }
.legend i.relevant      { background: var(--relevant); }
.legend i.informational { background: var(--informational); }
.legend i.technical     { background: var(--technical); }

.feed { list-style: none; margin: 0; padding: 0; }
/* Grid, not flex-wrap: the level and the date are fixed-width answers to fixed
   questions, and only the middle should ever break across lines. A wrapping
   flex row instead pushed the date onto a line of its own as soon as an entity
   type got long, which is most of them. */
.feed li {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-5); border-bottom: 1px solid var(--line);
  font-size: var(--text-sm);
}
.feed li.empty { display: block; }
.feed li:last-child { border-bottom: 0; }
.feed .feed-main { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: baseline; min-width: 0; }
/* Date and verdict travel together on the right. Apart, the verdict badge is
   the one thing narrow enough to wrap onto a line of its own. */
.feed .feed-right {
  margin-left: auto; display: flex; align-items: center; gap: var(--space-3);
  white-space: nowrap; font-size: var(--text-xs);
}

/* -- timeline (changelog) -- */
.timeline { position: relative; padding-left: var(--space-6); }
.timeline::before {
  content: ""; position: absolute; left: 6px; top: 4px; bottom: 4px;
  width: 2px; background: var(--line);
}
.tl-item { position: relative; margin-bottom: var(--space-5); }
.tl-item::before {
  content: ""; position: absolute; left: calc(-1 * var(--space-6)); top: 1.15rem;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--line-strong);
}
.tl-item.has-critical::before { border-color: var(--critical); background: var(--critical); }
.tl-head { display: flex; align-items: baseline; gap: var(--space-4); flex-wrap: wrap; }
.tl-date { font-weight: var(--weight-semi); font-size: var(--text-md); }
details.tl > summary {
  cursor: pointer; list-style: none;
  padding: var(--space-4) var(--space-7) var(--space-4) var(--space-5); position: relative;
}
details.tl > summary::-webkit-details-marker { display: none; }
details.tl > summary::after {
  content: "▾"; position: absolute; right: var(--space-5); top: var(--space-4);
  color: var(--muted); font-size: var(--text-sm); transition: transform .15s;
}
details.tl[open] > summary::after { transform: rotate(180deg); }
details.tl > summary:hover { background: var(--surface-2); }

/* -- release notes -- */
.prose { max-width: 74ch; }
.prose h2 { border-bottom: 1px solid var(--line); padding-bottom: var(--space-2); }
.prose h3 { font-size: var(--text-base); margin: var(--space-5) 0 var(--space-2); font-weight: var(--weight-semi); }
.prose ul { padding-left: var(--space-5); margin: var(--space-2) 0; }
.prose li { margin: 0.28rem 0; }
.prose code { background: var(--technical-bg); padding: 0.08rem 0.32rem; border-radius: var(--radius-sm); }
.rel { display: flex; gap: var(--space-3); align-items: baseline; flex-wrap: wrap; }
.rel .ver { font-weight: var(--weight-bold); font-size: var(--text-md); }


/* ── 12. Flags ──────────────────────────────────────────────────────────────
   The visual anchor for a tariff, in the switcher and on the start screen.

   Drawn here as background images rather than emoji or markup, for two
   reasons. Emoji is out: Windows ships no flag glyphs and renders 🇩🇪 as the
   letters "DE", which beside real flags looks like a bug — that is why these
   used to be two-letter monograms. And markup is out because the same flag is
   needed in a server-rendered tile and in a menu built by JavaScript, and one
   definition in CSS beats two copies of the artwork that can disagree.

   A source with no flag here keeps a neutral tile. Adding a tariff must not
   require a CSS entry to look finished. */
.flag {
  display: inline-block; flex: none;
  width: 22px; height: 15px; border-radius: 3px;
  background: var(--surface-3) center/cover no-repeat;
  box-shadow: inset 0 0 0 1px var(--flag-edge);
}
.flag[data-source="TARIC"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 20'%3E%3Crect width='30' height='20' fill='%23039'/%3E%3Cg fill='%23FC0'%3E%3Ccircle cx='15' cy='4' r='1.05'/%3E%3Ccircle cx='18' cy='4.8' r='1.05'/%3E%3Ccircle cx='20.2' cy='7' r='1.05'/%3E%3Ccircle cx='21' cy='10' r='1.05'/%3E%3Ccircle cx='20.2' cy='13' r='1.05'/%3E%3Ccircle cx='18' cy='15.2' r='1.05'/%3E%3Ccircle cx='15' cy='16' r='1.05'/%3E%3Ccircle cx='12' cy='15.2' r='1.05'/%3E%3Ccircle cx='9.8' cy='13' r='1.05'/%3E%3Ccircle cx='9' cy='10' r='1.05'/%3E%3Ccircle cx='9.8' cy='7' r='1.05'/%3E%3Ccircle cx='12' cy='4.8' r='1.05'/%3E%3C/g%3E%3C/svg%3E");
}
.flag[data-source="DE"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 5 3'%3E%3Crect width='5' height='3' fill='%23000'/%3E%3Crect y='1' width='5' height='1' fill='%23DD0000'/%3E%3Crect y='2' width='5' height='1' fill='%23FFCE00'/%3E%3C/svg%3E");
}
.flag[data-source="UK"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 30'%3E%3Crect width='60' height='30' fill='%23012169'/%3E%3Cpath d='M0 0l60 30M60 0L0 30' stroke='%23fff' stroke-width='6'/%3E%3Cpath d='M0 0l60 30M60 0L0 30' stroke='%23C8102E' stroke-width='3'/%3E%3Cpath d='M30 0v30M0 15h60' stroke='%23fff' stroke-width='10'/%3E%3Cpath d='M30 0v30M0 15h60' stroke='%23C8102E' stroke-width='6'/%3E%3C/svg%3E");
}
.flag[data-source="CH"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 20'%3E%3Crect width='30' height='20' fill='%23D52B1E'/%3E%3Cpath d='M13.4 4.5h3.2v4.1h4.1v3.2h-4.1v4.1h-3.2v-4.1H9.3V8.6h4.1z' fill='%23fff'/%3E%3C/svg%3E");
}
.flag[data-source="US"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 13'%3E%3Crect width='26' height='13' fill='%23fff'/%3E%3Cg fill='%23B22234'%3E%3Crect width='26' height='1'/%3E%3Crect y='2' width='26' height='1'/%3E%3Crect y='4' width='26' height='1'/%3E%3Crect y='6' width='26' height='1'/%3E%3Crect y='8' width='26' height='1'/%3E%3Crect y='10' width='26' height='1'/%3E%3Crect y='12' width='26' height='1'/%3E%3C/g%3E%3Crect width='10.4' height='7' fill='%233C3B6E'/%3E%3Cg fill='%23fff'%3E%3Ccircle cx='1.7' cy='1.2' r='.4'/%3E%3Ccircle cx='4.2' cy='1.2' r='.4'/%3E%3Ccircle cx='6.7' cy='1.2' r='.4'/%3E%3Ccircle cx='9.2' cy='1.2' r='.4'/%3E%3Ccircle cx='2.95' cy='2.6' r='.4'/%3E%3Ccircle cx='5.45' cy='2.6' r='.4'/%3E%3Ccircle cx='7.95' cy='2.6' r='.4'/%3E%3Ccircle cx='1.7' cy='4' r='.4'/%3E%3Ccircle cx='4.2' cy='4' r='.4'/%3E%3Ccircle cx='6.7' cy='4' r='.4'/%3E%3Ccircle cx='9.2' cy='4' r='.4'/%3E%3Ccircle cx='2.95' cy='5.4' r='.4'/%3E%3Ccircle cx='5.45' cy='5.4' r='.4'/%3E%3Ccircle cx='7.95' cy='5.4' r='.4'/%3E%3C/g%3E%3C/svg%3E");
}


/* ── 13. Workspace: the hub's control bar ───────────────────────────────── */
.app { display: flex; flex-direction: column; flex: 1; min-height: 0; }

/* The table and its bars are children of #workspace but have to be flex items
   of .app, which is what display:contents does. `hidden` alone cannot express
   that — it means display:none, and the shown state is `contents`, not
   `block` — so both states are written here and the attribute stays the
   switch. The [hidden] rule wins on specificity, as it must. */
#workspace { display: contents; }
#workspace[hidden] { display: none; }

.controls {
  display: flex; align-items: flex-end; gap: var(--space-4); flex-wrap: wrap;
  padding: var(--space-4) var(--space-5); background: var(--surface);
  border-bottom: 1px solid var(--line); flex: none;
}
.controls .spacer { flex: 1; }
/* Buttons sit on the same baseline as the controls that carry a label above
   them, which is what the row of fields establishes. */
.controls > .btn { margin-bottom: 0; }

/* The tariff switcher. It was a bar of two-line tabs above the controls —
   52 px of chrome for a setting that belongs beside Datensatz and Stichtag. */
.src-btn {
  display: inline-flex; align-items: center; gap: var(--space-2);
  height: var(--control-h); padding: 0 var(--space-3);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--surface); font-size: var(--text-sm);
  font-weight: var(--weight-medium); max-width: 17rem;
}
.src-btn:hover { background: var(--surface-3); }
.src-btn[aria-expanded="true"] { border-color: var(--accent); }
.src-btn .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.src-btn .caret { color: var(--faint); font-size: var(--text-2xs); margin-left: auto; }
/* The entries of the menu: flag, name, and under it what lies behind it. */
.src-item {
  display: flex; align-items: center; gap: var(--space-3); width: 100%; text-align: left;
  padding: var(--space-2) var(--space-3); border: 0; border-radius: var(--radius);
  background: none; font: inherit; height: auto;
}
.src-item:hover { background: var(--surface-2); }
.src-item[aria-current="true"] { background: var(--accent-soft); }
.src-item .nm { font-weight: var(--weight-medium); font-size: var(--text-sm); }
.src-item .sub { display: block; font-size: var(--text-xs); }
.src-item .tick { margin-left: auto; color: var(--accent); }

/* One box for two questions: digits are a commodity number, words are a
   description. Which one it took is stated under the box. */
.field.search { position: relative; }
.field.search input { padding-left: 2rem; width: 280px; }
.field.search > svg {
  position: absolute; left: var(--space-3); bottom: 9px;
  width: 14px; height: 14px; color: var(--faint); pointer-events: none;
}
.qhint {
  position: absolute; left: 2rem; top: 100%; margin-top: 0.18rem;
  font-size: var(--text-2xs); color: var(--muted); white-space: nowrap;
}
.qhint:empty { display: none; }

/* The criteria a customs person reaches for first, out where they can be seen
   rather than two clicks into the filter panel.

   Symmetrisch um die Trennlinie der Zeile darüber. Vorher stand hier
   `padding-top: 0` — aus einer Zeit, in der die Picker als Fortsetzung der
   Steuerleiste an ihr kleben sollten. Zwischen beiden liegt aber eine Linie,
   und daran klebte dann die Beschriftung: über „ZUSATZCODE" 0 px, unter ihr
   4 px zu ihrem eigenen Feld. Damit gehörte die Beschriftung optisch zur
   Zeile darüber statt zu ihrem Feld. Der Abstand zwischen zwei Zeilen muss
   deutlich größer sein als der innerhalb eines Paares, sonst ist nicht zu
   sehen, was zusammengehört. */
.controls.pickers {
  border-bottom: 0;
  padding-top: var(--space-4);
  padding-bottom: var(--space-4);
}
.controls.pickers:empty { display: none; }
.controls.pickers .field { min-width: 170px; max-width: 260px; flex: 1 1 170px; }
.controls.pickers .field.gap { flex: 0 1 auto; min-width: 0; }
.controls.pickers .field.gap > label { color: var(--faint); }
.gap-note { margin: 0; padding: var(--space-1) 0; font-size: var(--text-sm); color: var(--faint); font-style: italic; }

/* -- filter chips -- */
.chips {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  padding: var(--space-3) var(--space-5); border-bottom: 1px solid var(--line);
  background: var(--surface-2); flex: none;
}
.chips:empty { display: none; }
.chip {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: 0.1rem var(--space-1) 0.1rem var(--space-3);
  background: var(--accent-soft); border: 1px solid var(--accent-line); color: var(--accent);
  border-radius: var(--radius-pill); font-size: var(--text-sm); white-space: nowrap;
}
.chip b { font-weight: 600; }
.chip button {
  background: none; border: 0; color: inherit; opacity: .65; font-size: var(--text-md);
  line-height: 1; height: auto; padding: 0 var(--space-1); border-radius: var(--radius-pill);
}
.chip button:hover { opacity: 1; background: none; }
.joiner {
  font-size: var(--text-xs); color: var(--muted); border: 1px solid var(--line-strong);
  background: var(--surface); border-radius: var(--radius-pill); padding: 0.1rem var(--space-3);
}

/* -- what the table is currently answering -- */
.hint:empty { display: none; }
.hint {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  margin: 0 var(--space-5) 0.1rem; padding: var(--space-2) var(--space-3);
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  border-radius: var(--radius); font-size: var(--text-sm); color: var(--fg);
}
/* The button inside a hint is an aside on one line of text, not a control on
   a bar of them. */
.hint .btn { height: var(--control-h-sm); padding: 0 var(--space-3); font-size: var(--text-xs); }

.statusline {
  display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap;
  padding: var(--space-2) var(--space-5); font-size: var(--text-xs); color: var(--muted);
  border-bottom: 1px solid var(--line); background: var(--surface); flex: none;
}
.statusline .count { color: var(--fg); font-weight: var(--weight-semi); }
.statusline .sep { color: var(--line-strong); }
.pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); flex: none; }
.pulse.busy { background: var(--relevant); animation: blink .9s ease-in-out infinite; }
@keyframes blink { 50% { opacity: .25; } }


/* ── 14. Workspace: the table ───────────────────────────────────────────── */
.tablewrap { flex: 1; overflow: auto; background: var(--surface); position: relative; }
.tablewrap table { border-collapse: separate; border-spacing: 0; font-size: var(--text-sm); }
.tablewrap thead th {
  position: sticky; top: 0; z-index: 2; background: var(--surface-3);
  padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--line-strong);
  white-space: nowrap; cursor: pointer; user-select: none;
}
.tablewrap thead th:hover { color: var(--fg); }
.tablewrap thead th.nosort { cursor: default; color: var(--faint); }
.tablewrap thead th.nosort:hover { color: var(--faint); }
.tablewrap thead th .arrow { color: var(--accent); font-size: var(--text-xs); margin-left: 0.2rem; }
.tablewrap thead th .info { color: var(--faint); margin-left: var(--space-1); cursor: help; }
.tablewrap tbody td {
  padding: var(--space-2) var(--space-4); border-bottom: 1px solid var(--line);
  vertical-align: top; max-width: 34rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tablewrap tbody tr { cursor: pointer; }
.tablewrap tbody tr:hover { background: none; }
.tablewrap tbody tr:hover td { background: var(--surface-2); }
.tablewrap tbody tr.open td { background: var(--accent-soft); }
td.code { font-family: var(--font-mono); font-size: var(--text-xs); white-space: nowrap; }
td.empty-cell::after { content: "—"; color: var(--faint); }

/* An outline rather than a background: the row under the pointer already uses
   the background, and two selections that look the same are one selection. */
.tablewrap tbody tr.sel td { box-shadow: inset 0 1px 0 var(--accent), inset 0 -1px 0 var(--accent); }
.tablewrap tbody tr.sel td:first-child { box-shadow: inset 1px 1px 0 var(--accent), inset 0 -1px 0 var(--accent); }
.tablewrap tbody tr.sel td:last-child { box-shadow: inset -1px 1px 0 var(--accent), inset 0 -1px 0 var(--accent); }

/* Skeleton rows, so a slow query looks like loading and not like nothing.
   The widths are a small set rather than Math.random(): ragged is the point,
   arbitrary is not, and a random number written into a style attribute was the
   last inline style left in this page. */
.skel {
  height: 10px; border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--surface-3), var(--line), var(--surface-3));
  background-size: 200% 100%; animation: shimmer 1.1s linear infinite;
}
.skel.w45 { width: 45%; }
.skel.w60 { width: 60%; }
.skel.w75 { width: 75%; }
.skel.w90 { width: 90%; }
/* Stacked in the drawer rather than one per table cell. */
.skel.line { margin: var(--space-3) 0; }
@keyframes shimmer { to { background-position: -200% 0; } }

.state { padding: var(--space-8) var(--space-6); text-align: center; color: var(--muted); }
.state h3 { margin: 0 0 var(--space-2); font-size: var(--text-md); color: var(--fg); font-weight: 600; }
.state p { margin: 0 auto; max-width: 34rem; font-size: var(--text-base); }
.state.error h3 { color: var(--critical); }
.sentinel { padding: var(--space-4); text-align: center; font-size: var(--text-xs); color: var(--muted); }


/* ── 15. Workspace: drawer, panels, palette ─────────────────────────────── */
.scrim {
  position: fixed; inset: 0; background: var(--scrim); opacity: 0; pointer-events: none;
  transition: opacity .16s ease; z-index: 20;
}
.scrim.on { opacity: 1; pointer-events: auto; }

aside.drawer {
  position: fixed; top: 0; right: 0; height: 100%; width: min(680px, 94vw); z-index: 21;
  background: var(--surface); border-left: 1px solid var(--line); box-shadow: var(--shadow-lg);
  transform: translateX(100%); transition: transform .2s var(--ease);
  display: flex; flex-direction: column;
}
aside.drawer.on { transform: none; }
.drawer header {
  display: flex; align-items: flex-start; gap: var(--space-4);
  padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--line); flex: none;
}
.drawer header h2 { margin: 0; font-size: var(--text-md); font-weight: var(--weight-semi); }
.drawer header .sub { margin-top: 0.15rem; }
.drawer header button {
  margin-left: auto; background: none; border: 0; font-size: var(--text-xl);
  color: var(--muted); line-height: 1; height: var(--control-h); padding: 0 var(--space-2);
  border-radius: var(--radius-sm);
}
.drawer header button:hover { background: var(--surface-3); color: var(--fg); }
.drawer .body { overflow: auto; padding: var(--space-5) var(--space-5) var(--space-8); }
/* The actions that carry this position to the other surfaces. In the header
   rather than at the foot of the body: the body scrolls, and an action that
   scrolls away is an action nobody finds. */
.drawer-actions {
  display: flex; gap: var(--space-2); flex-wrap: wrap;
  padding: var(--space-3) var(--space-5); border-bottom: 1px solid var(--line);
  background: var(--surface-2); flex: none;
}

.sec { margin-bottom: var(--space-6); }
.sec > h4 {
  margin: 0 0 var(--space-3); font-size: var(--text-2xs); text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--muted);
}
.kv { display: grid; grid-template-columns: 11rem 1fr; gap: var(--space-1) var(--space-4); font-size: var(--text-sm); }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; word-break: break-word; }
.kv dd.sm { font-size: var(--text-xs); }
.kv dd.mono-sm { font-family: var(--font-mono); font-size: var(--text-2xs); word-break: break-all; }

/* The caveat under a section of the drawer: why the number above it reads the
   way it does. Was four paragraphs with four different inline font sizes. */
.drawer-note { margin: var(--space-3) 0 0; font-size: var(--text-xs); color: var(--muted); line-height: 1.5; }
.drawer-note.lead { margin: 0 0 var(--space-3); }
.drawer-cta { margin: 0 0 var(--space-4); }
/* Duty rates, conditions, footnotes and exclusions under a measure's key/value
   list. One box per group — the gap separates the groups, not a heading from
   the table under it. */
.measure-extras { margin-top: var(--space-3); display: flex; flex-direction: column; gap: var(--space-3); }
.measure-extras b { display: inline-block; margin-bottom: var(--space-1); }

.chain { display: flex; flex-direction: column; gap: 0.2rem; font-size: var(--text-sm); }
.chain .step { display: flex; gap: var(--space-3); align-items: baseline; padding: var(--space-1) var(--space-3); border-radius: var(--radius-sm); }
.chain .step:hover { background: var(--surface-2); }
.chain .step code { color: var(--accent); font-size: var(--text-xs); }

/* Hinweise: a card each, because a notice is a sentence and sentences need
   room. Quiet by default — they qualify the position, they are not the
   headline; the badge carries the weight. */
.notice {
  border: 1px solid var(--line); border-left: 3px solid var(--accent-line);
  border-radius: var(--radius); padding: var(--space-3); margin-bottom: var(--space-2);
  background: var(--surface-2);
}
.notice-head { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; font-size: var(--text-xs); margin-bottom: var(--space-1); }
.notice-text { font-size: var(--text-sm); line-height: 1.45; }
.notice-fn { margin: var(--space-2) 0 0; font-size: var(--text-xs); color: var(--muted); }
.notice-fn > summary { cursor: pointer; color: var(--accent); list-style: revert; }
.notice-fn ul { margin: var(--space-1) 0 0; padding-left: var(--space-5); }
.notice-fn li { margin: 0.2rem 0; line-height: 1.45; }
/* The footnote's code and its wording run together without this. */
.notice-fn li code { margin-right: var(--space-1); }

.mrec { border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: var(--space-3); overflow: hidden; }
.mrec.picked { border-color: var(--accent-line); box-shadow: 0 0 0 2px var(--accent-soft); }
.mrec > .h {
  padding: var(--space-3) var(--space-4); background: var(--surface-2);
  display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; font-size: var(--text-sm);
}
.mrec > .b { padding: var(--space-3) var(--space-4); font-size: var(--text-sm); }
.mrec table { font-size: var(--text-xs); }
.mrec td, .mrec th { padding: var(--space-1) var(--space-2); border-bottom: 1px solid var(--line); white-space: normal; }

.panel {
  position: absolute; z-index: 30; background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg); padding: var(--space-4);
  width: 340px; max-height: 70vh; overflow: auto;
}
.panel h4 { margin: 0 0 var(--space-3); font-size: var(--text-base); font-weight: var(--weight-semi); }
.panel .grp {
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--faint); margin: var(--space-4) 0 var(--space-1);
}
.panel label.row {
  display: flex; align-items: flex-start; gap: var(--space-2); padding: 0.22rem 0.2rem;
  font-size: var(--text-sm); border-radius: var(--radius-sm); cursor: pointer;
  text-transform: none; letter-spacing: 0; color: var(--fg); margin: 0;
}
.panel label.row:hover { background: var(--surface-2); }
.panel label.row input { margin-top: 0.2rem; }
.panel label.row .nt { display: block; font-size: var(--text-xs); color: var(--muted); }
.panel label.row.center { align-items: center; }
.panel .actions { margin-top: var(--space-4); }
/* The row of actions a panel opens with, above its explanation rather than
   below it. */
.panel .actions.lead { margin: 0 0 var(--space-4); }
.panel select, .panel input[type="text"], .panel textarea { width: 100%; }
.panel .fld { margin-bottom: var(--space-3); }
.panel textarea.api-call {
  font-family: var(--font-mono); font-size: var(--text-2xs);
  min-height: 4.5rem; resize: vertical; background: var(--surface-2);
}
/* The sentence a panel ends on: what this does, what it costs, where it is
   stored. Quiet, and the same size in every panel — there were five. */
.panel-note {
  margin: var(--space-4) 0 0; font-size: var(--text-xs);
  color: var(--muted); line-height: 1.5;
}
.panel-note.lead { margin: 0 0 var(--space-4); }

.palette {
  position: fixed; inset: 0; z-index: 50; background: var(--scrim);
  display: flex; align-items: flex-start; justify-content: center; padding: 12vh var(--space-5) var(--space-5);
}
.palette[hidden] { display: none; }
.palette-box {
  width: min(620px, 100%); background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); overflow: hidden;
  display: flex; flex-direction: column; max-height: 70vh;
}
.palette-box.pad { padding: var(--space-5); }
.palette-box h4 { margin: 0 0 var(--space-4); font-size: var(--text-md); font-weight: var(--weight-semi); }
.palette-box .actions { margin-top: var(--space-5); }
.palette-box > input {
  border: 0; border-bottom: 1px solid var(--line); border-radius: 0;
  height: auto; padding: var(--space-4) var(--space-5);
  font-size: var(--text-md); background: none; outline: none;
}
.palette-box ul { list-style: none; margin: 0; padding: var(--space-1); overflow: auto; flex: 1; }
.palette-box li {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius);
  font-size: var(--text-base); cursor: pointer;
}
.palette-box li .kindtag {
  font-size: var(--text-2xs); color: var(--faint); border: 1px solid var(--line);
  border-radius: var(--radius-pill); padding: 0.02rem var(--space-2); flex: none;
}
.palette-box li .sub { margin-left: auto; font-size: var(--text-xs); }
.palette-box li[aria-selected="true"] { background: var(--accent-soft); }
.palette-box li.none { color: var(--muted); cursor: default; }
.palette-foot {
  display: flex; gap: var(--space-4); padding: var(--space-2) var(--space-4);
  border-top: 1px solid var(--line); font-size: var(--text-xs); color: var(--muted);
  background: var(--surface-2); flex-wrap: wrap;
}
.palette-foot .right { margin-left: auto; }

/* The one-line confirmation the workspace drops at the bottom of the screen —
   "8504000000 gemerkt". It used to be built with a style attribute in
   JavaScript, which is the same problem as a style attribute in the markup
   with one more place to look for it. */
.flash {
  position: fixed; left: 50%; bottom: var(--space-6); transform: translateX(-50%);
  background: var(--fg); color: var(--bg); padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill); font-size: var(--text-sm);
  z-index: 60; box-shadow: var(--shadow-lg);
}

.keys { display: grid; grid-template-columns: auto 1fr; gap: var(--space-1) var(--space-4); font-size: var(--text-sm); align-items: baseline; }
.keys dt { white-space: nowrap; }
.keys dd { margin: 0; color: var(--muted); }


/* ── 16. The start screen ───────────────────────────────────────────────────
   Since `/` sends a signed-in visitor here, this is the first thing anyone
   sees in the morning. It answers the three questions people actually arrive
   with, in the order they are asked: I am looking for a number (the search),
   what happened to my numbers (the Merkliste), where was I (saved views). */
.home { flex: 1; overflow: auto; padding: var(--space-7) var(--space-5) var(--space-8); }
.home .inner { max-width: 1000px; margin: 0 auto; }
.home-head { margin-bottom: var(--space-6); }
.home h1 { font-size: var(--text-xl); margin: 0 0 var(--space-2); letter-spacing: -0.025em; font-weight: var(--weight-bold); }

/* The search carries the screen, so it is a paragraph tall rather than a form
   field tall — and the button is exactly as tall as the box beside it, which
   is the whole reason --control-h-lg exists. */
.home-search { display: flex; align-items: stretch; gap: var(--space-3); }
/* Die Box um Lupe und Feld. Sie trägt das `position: relative`, das vorher am
   Formular hing — sonst säße das Symbol am linken Rand des Formulars, und dort
   steht jetzt der Tarifwähler. */
.home-search-box { position: relative; flex: 1; min-width: 0; display: flex; }
/* Der Tarif gehört zur Frage, also steht er im Feld und nicht darüber — aber
   ruhiger als das Suchfeld: er wird selten angefasst, und was selten angefasst
   wird, soll nicht um Aufmerksamkeit mit dem konkurrieren, was immer angefasst
   wird. */
.home-search select {
  flex: 0 0 auto; max-width: 15rem; height: var(--control-h-lg);
  padding: 0 var(--space-4); font: inherit; font-size: var(--text-base);
  color: var(--ink); border: 1px solid var(--line-strong);
  border-radius: var(--radius-md); background: var(--surface-2);
}
.home-search select:focus-visible {
  border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--accent-soft);
}
.home-search input {
  flex: 1; min-width: 0; height: var(--control-h-lg);
  padding: 0 var(--space-5) 0 2.9rem; font-size: var(--text-md);
  border: 1px solid var(--line-strong); border-radius: var(--radius-md);
  background: var(--surface); box-shadow: var(--shadow-sm);
}
.home-search input:focus-visible {
  border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--accent-soft);
}
.home-search-box > svg {
  position: absolute; left: var(--space-5); top: 50%; transform: translateY(-50%);
  width: 17px; height: 17px; color: var(--faint); pointer-events: none;
}
.home-search .btn {
  height: var(--control-h-lg); padding: 0 var(--space-6);
  border-radius: var(--radius-md); font-size: var(--text-base);
}
.home-hint { min-height: 1.2rem; margin: var(--space-2) 0 var(--space-6) 0.2rem; font-size: var(--text-xs); color: var(--muted); }

.home-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--space-4); margin-bottom: var(--space-7);
}
.home-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-md);
  box-shadow: var(--shadow); overflow: hidden;
}
.home-card-head { display: flex; align-items: baseline; gap: var(--space-3); padding: var(--space-4) var(--space-4) 0; }
.home-card-head h2 {
  margin: 0; font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted); font-weight: var(--weight-semi);
}
.home-card-head a { margin-left: auto; font-size: var(--text-xs); }
.home-card-body { padding: var(--space-3) var(--space-4) var(--space-4); }
.home-card-body .empty { padding: 0; text-align: left; font-size: var(--text-sm); line-height: 1.5; }
/* The number that carries the card's meaning, and beside it what it means. */
.home-figure { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.home-figure b { font-size: var(--text-2xl); font-weight: var(--weight-bold); letter-spacing: -0.025em; }
.home-figure span { color: var(--muted); font-size: var(--text-sm); }
.home-tags { display: flex; gap: var(--space-1); flex-wrap: wrap; margin-top: var(--space-3); }
/* Saved views as buttons, not as a list: they are jumps. */
.home-views { display: flex; flex-direction: column; gap: var(--space-1); }
.home-views button {
  display: flex; align-items: center; gap: var(--space-3); width: 100%; text-align: left;
  height: auto; padding: var(--space-2); border: 0; border-radius: var(--radius);
  background: none; font: inherit; font-size: var(--text-sm); font-weight: 400;
}
.home-views button:hover { background: var(--surface-2); }
.home-views .sub { margin-left: auto; font-size: var(--text-xs); white-space: nowrap; }

.home-h2 {
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted); font-weight: var(--weight-semi); margin: 0 0 var(--space-3) 0.1rem;
}

/* -- the tariff tiles --------------------------------------------------------
   Every tile is the same shape whatever the length of the tariff's name. The
   name occupies exactly two lines — clamped above, floored below — so the code
   under it and, more importantly, the figure under that sit at the same height
   in every tile. Before this the whole tile hung off the length of its title,
   and five of them side by side read as five different designs.

   The figures are not pushed to the bottom. Bottom-aligning them would line up
   the last line of small print at the cost of the big number, and the big
   number is what the eye scans across the row. */
.tariff-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(244px, 1fr));
  gap: var(--space-4); margin-bottom: var(--space-7);
}
.tariff {
  display: flex; flex-direction: column; height: auto;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-md);
  padding: var(--space-4); box-shadow: var(--shadow); text-align: left; width: 100%;
  font-weight: 400;
}
.tariff:hover { border-color: var(--accent-line); box-shadow: var(--shadow-lg); background: var(--surface); }
/* Kein eigener Abstand nach unten: der Name reserviert immer zwei Zeilen, und
   bei einem einzeiligen Namen ist die zweite genau der Abstand. Ein Rand
   obendrauf riss die Kachel auseinander, seit die Codezeile weg ist, die den
   Platz vorher füllte. */
.tariff-head {
  display: flex; align-items: flex-start; gap: var(--space-3);
  margin-bottom: var(--space-2);
}
/* Exactly two lines, whether the name needs one or three. Without the floor a
   one-line name pulls the figure below it up and the tile beside it does not
   match — which is what "die Kacheln stellen den Text unterschiedlich dar"
   was about. `min-width: 0` because the clamp only works on a flex item that
   is allowed to shrink. */
.tariff-name {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  font-weight: var(--weight-semi); font-size: var(--text-sm); line-height: 1.3;
  min-height: 2.6em; min-width: 0;
}
/* Flex statt eines Textflusses, damit „Maßnahmen" hinter der Zahl umbrechen
   darf, ohne eine Zeile in der Höhe der Zahl aufzureißen: in einem Textfluss
   erbt die umgebrochene Zeile die Zeilenhöhe der 22-px-Zahl und steht dann mit
   28 px Abstand darunter. `row-gap: 0` sagt, dass der Umbruch keiner ist. */
.tariff-n {
  display: flex; flex-wrap: wrap; align-items: baseline;
  column-gap: var(--space-2); row-gap: 0;
  font-size: var(--text-xl); font-weight: var(--weight-bold);
  letter-spacing: -0.025em; font-variant-numeric: tabular-nums; line-height: 1.25;
}
.tariff-n small { font-size: var(--text-xs); font-weight: 400; color: var(--muted); letter-spacing: 0; }
.tariff-meta { display: block; font-size: var(--text-xs); color: var(--muted); margin-top: 0.1rem; }
/* Wenn „Maßnahmen" hinter die Zahl umbricht, steht es sonst direkt auf der
   ersten Meta-Zeile und liest sich als deren Anfang statt als Einheit der
   Zahl darüber. Der Abstand sagt, wo die eine Gruppe endet. */
.tariff-n + .tariff-meta { margin-top: var(--space-2); }


/* ── 17. The signpost at `/` ────────────────────────────────────────────── */
body.signpost {
  min-height: 100vh; height: auto; display: flex;
  align-items: flex-start; justify-content: center;
  padding: var(--space-8) var(--space-5) var(--space-8);
}
.signpost-wrap { width: 100%; max-width: 820px; }
.signpost-head { display: flex; align-items: center; gap: var(--space-4); margin-bottom: var(--space-2); }
.signpost-head h1 { font-size: var(--text-xl); margin: 0; letter-spacing: -0.02em; }
.signpost-wrap > .lede { margin: var(--space-4) 0 var(--space-7); font-size: var(--text-md); }

.cta {
  display: flex; align-items: center; gap: var(--space-5); text-decoration: none; color: inherit;
  background: var(--surface); border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--radius-md); padding: var(--space-5); margin-bottom: var(--space-4);
  box-shadow: var(--shadow);
}
.cta:hover { border-color: var(--accent); background: var(--accent-soft); color: inherit; }
.cta .t { display: block; font-weight: var(--weight-bold); }
.cta .d { display: block; color: var(--muted); font-size: var(--text-base); margin-top: 0.2rem; }
.cta .arrow { margin-left: auto; color: var(--accent); font-size: var(--text-xl); flex: none; }

/* Two columns at this page's width, not three: a card is a sentence about what
   a surface is for, and at 240 px the sentence was six lines tall and the last
   card of four sat alone on a row of its own. */
.link-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--space-4); }
.link-grid + .link-grid { margin-top: var(--space-4); }
.link-card {
  display: block; text-decoration: none; color: inherit; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius-md);
  padding: var(--space-5); box-shadow: var(--shadow);
}
.link-card:hover { border-color: var(--accent); background: var(--accent-soft); color: inherit; }
.link-card .t { font-weight: var(--weight-semi); display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.link-card .d { color: var(--muted); font-size: var(--text-base); margin-top: var(--space-1); }
.link-card .p { color: var(--faint); font-size: var(--text-xs); margin-top: var(--space-3); font-family: var(--font-mono); }

.svc {
  margin-top: var(--space-7); padding: var(--space-4) var(--space-5); background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius-md);
  font-size: var(--text-base); box-shadow: var(--shadow);
  display: flex; gap: var(--space-3); align-items: center;
}
.signpost-wrap > .note { margin-top: var(--space-6); }


/* ── 18. Login ──────────────────────────────────────────────────────────── */
.login-head { display: flex; align-items: center; gap: var(--space-4); margin-bottom: var(--space-4); }
.login-head .t { font-weight: var(--weight-bold); }
.login-head .sub { font-size: var(--text-xs); }
.login-intro { margin: 0 0 var(--space-5); color: var(--muted); }
.login-form { display: flex; flex-direction: column; gap: var(--space-1); }
.login-form input { height: var(--control-h-lg); font-size: var(--text-md); }
.login-form .btn { height: var(--control-h-lg); margin-top: var(--space-4); font-size: var(--text-base); }
.login-form + .note { margin-top: var(--space-5); }


/* ── 19. Merkliste ──────────────────────────────────────────────────────── */
.wl-empty { text-align: center; padding: var(--space-7) var(--space-5); }
.wl-empty h3 { margin: 0 0 var(--space-3); font-size: var(--text-lg); }
.wl-empty p { color: var(--muted); max-width: 42rem; margin: 0 auto var(--space-5); }
.wl-add { display: grid; gap: var(--space-4); grid-template-columns: 1fr 12rem; align-items: start; }
.wl-add textarea {
  width: 100%; min-height: 5.5rem; resize: vertical;
  font-family: var(--font-mono); font-size: var(--text-sm);
}
.wl-side { display: flex; flex-direction: column; gap: var(--space-3); }
.wl-side select { width: 100%; }
.wl-code { font-family: var(--font-mono); white-space: nowrap; }
.wl-missing { color: var(--critical); }
/* The file input is a button that says what it does, not "Datei auswählen". */
.wl-file { position: relative; overflow: hidden; display: inline-flex; }
.wl-file input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; height: 100%; }


/* ── 20. Der Beleg ──────────────────────────────────────────────────────── */
/* The actions above the sheet, none of which is printed. */
.beleg-bar { margin-bottom: var(--space-6); gap: var(--space-3); }
.beleg-bar .filters { align-items: flex-end; }
.beleg { max-width: 62rem; }
.beleg-head {
  display: flex; align-items: flex-start; gap: var(--space-5);
  border-bottom: 2px solid var(--fg); padding-bottom: var(--space-4); margin-bottom: var(--space-5);
}
.beleg-head .who { font-weight: var(--weight-bold); font-size: var(--text-lg); letter-spacing: -0.01em; }
.beleg-head .what { color: var(--muted); font-size: var(--text-sm); }
.beleg-head .when { margin-left: auto; text-align: right; font-size: var(--text-xs); color: var(--muted); }
.beleg h2 {
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--muted); margin: var(--space-6) 0 var(--space-3);
  border-bottom: 1px solid var(--line); padding-bottom: var(--space-1);
}
.beleg .kv { grid-template-columns: 13rem 1fr; gap: var(--space-1) var(--space-4); font-size: var(--text-base); }
.beleg .prov {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius-md); padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-3);
}
.beleg .measure { border: 1px solid var(--line); border-radius: var(--radius-md); margin-bottom: var(--space-3); break-inside: avoid; }
.beleg .measure > .h {
  padding: var(--space-2) var(--space-4); background: var(--surface-2);
  border-bottom: 1px solid var(--line); display: flex; gap: var(--space-3);
  flex-wrap: wrap; align-items: baseline; font-size: var(--text-sm);
}
.beleg .measure > .b { padding: var(--space-3) var(--space-4); font-size: var(--text-sm); }
.beleg .measure table { font-size: var(--text-xs); }
.beleg .chain { font-size: var(--text-sm); }
.beleg .chain span + span::before { content: " › "; color: var(--muted); }
.beleg-notice { margin: 0 0 var(--space-3); }
.beleg .sig {
  margin-top: var(--space-7); border-top: 1px solid var(--line); padding-top: var(--space-4);
  font-size: var(--text-xs); color: var(--muted); line-height: 1.5;
}
.beleg .sig p { margin: 0 0 var(--space-2); }
.beleg .sig p:last-child { margin: 0; }
.mono-sm { font-family: var(--font-mono); font-size: var(--text-2xs); word-break: break-all; }


/* ── 21. Spacing utilities ──────────────────────────────────────────────────
   A deliberately short list. These exist so a one-off margin does not become
   an inline style — not so that layout can be written in the markup. */
.flush { margin: 0; }
.flush-top { margin-top: 0; }
.flush-bottom { margin-bottom: 0; }
.gap-top { margin-top: var(--space-4); margin-bottom: 0; }
.gap-below { margin-bottom: var(--space-5); }
.sm { font-size: var(--text-xs); }
.push-right { margin-left: auto; }
.grow { flex: 1; min-width: 0; }
.pre-wrap { white-space: pre-wrap; }
.dim { opacity: .7; }
.full { width: 100%; }


/* ── 22. Narrow screens ─────────────────────────────────────────────────────
   The workspace had exactly one media query — the dark palette. Everything
   else was laid out for a desk: a 290 px search box, four picker columns, a
   680 px drawer and a control bar that assumed there was room to the right of
   it. On a tablet in a warehouse that is not a degraded page, it is an
   unusable one, and looking a number up on the way somewhere is a real use. */
@media (max-width: 980px) {
  .field.search input { width: 200px; }
  .controls { gap: var(--space-3); padding: var(--space-3) var(--space-4); }
  .controls .spacer { flex-basis: 100%; height: 0; }
}

@media (max-width: 860px) {
  .shell { grid-template-columns: 1fr; }
  .shell.fixed { grid-template-rows: auto minmax(0, 1fr); }
  .sidebar, .shell.fixed .sidebar {
    position: static; height: auto; flex-direction: row; align-items: center;
    gap: var(--space-3); overflow-x: auto; overflow-y: visible;
    padding: var(--space-3) var(--space-4);
  }
  .sidebar .nav-label { display: none; }
  .nav-group { flex-direction: row; }
  /* In a row the entries scroll sideways, so they may not wrap: "Trade Data
     Hub" broke onto three lines and made the bar three times as tall. */
  .sidebar .nav-item { white-space: nowrap; }
  /* The rule turns with the list: stacked it separates top from bottom, in a
     row it has to separate left from right or it underlines nothing. */
  .nav-group.admin {
    border-top: 0; border-left: 1px solid var(--sidebar-rule);
    padding-top: 0; margin-top: 0; padding-left: var(--space-3); margin-left: 0.2rem;
  }
  .sidebar .spacer { display: none; }
  .sidebar .nav-count { margin-left: 0.1rem; }
  .topbar { padding: var(--space-3) var(--space-5); }
  main { padding: var(--space-5); }
}

@media (max-width: 760px) {
  .controls { padding: var(--space-3) var(--space-4); }
  .field { flex: 1 1 auto; }
  .field.search { flex: 1 1 100%; }
  .field.search input { width: 100%; }
  .src-btn { max-width: none; width: 100%; }
  .controls.pickers .field { max-width: none; flex: 1 1 45%; }
  .chips, .statusline { padding-left: var(--space-4); padding-right: var(--space-4); }
  .hint { margin-left: var(--space-4); margin-right: var(--space-4); }
  .home { padding: var(--space-5) var(--space-4) var(--space-7); }
  .home h1 { font-size: var(--text-lg); }
  .home-search { flex-wrap: wrap; }
  .home-search input, .home-search .btn, .home-search select {
    height: 42px; font-size: var(--text-base);
  }
  /* Auf dem Telefon bricht der Wähler in eine eigene Zeile und nimmt sie
     ganz — halb so breit neben einem Suchfeld ist keins von beidem benutzbar. */
  .home-search select { flex: 1 0 100%; max-width: none; }
  .tariff-grid { grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: var(--space-3); }
  /* Full width, and off the bottom rather than off the side: on a phone a side
     panel that leaves 6 % of the table visible is a modal pretending not to
     be one. */
  aside.drawer {
    width: 100%; max-width: none; top: auto; bottom: 0; height: 88vh;
    border-left: 0; border-top: 1px solid var(--line);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0; transform: translateY(100%);
  }
  aside.drawer.on { transform: none; }
  .drawer-actions { padding: var(--space-3) var(--space-4); }
  .drawer .body { padding: var(--space-4) var(--space-4) var(--space-7); }
  .kv { grid-template-columns: 1fr; gap: 0.1rem var(--space-4); }
  .kv dt { margin-top: var(--space-1); font-size: var(--text-xs); }
  .panel { width: min(340px, calc(100vw - 1.6rem)); }
  /* Cells stop being one line: a description truncated to a phone's width is
     an ellipsis with a word in front of it. */
  .tablewrap tbody td { white-space: normal; max-width: 16rem; }
  .palette { padding: 6vh var(--space-3) var(--space-5); }
}

@media (max-width: 720px) {
  .wl-add { grid-template-columns: 1fr; }
}

@media (max-width: 620px) {
  /* Anchored to the topbar rather than to the summary: at this width the
     button sits near the right edge and a panel hung off it would run off. */
  .ds-panel { position: fixed; left: var(--space-3); right: var(--space-3); min-width: 0; max-width: none; }
}


/* ── 23. Print ──────────────────────────────────────────────────────────────
   A customs reader prints. What they print is the content, and the navigation,
   the topbar and the theme switch are furniture that costs a page and says
   nothing. `exact` keeps the significance colours, which carry meaning rather
   than decoration. */
@media print {
  :root { --bg: #fff; --surface: #fff; --surface-2: #fff; --surface-3: #fff; }
  .sidebar, .topbar, .filters, .no-print { display: none !important; }
  .shell { display: block; }
  body { background: #fff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  main { padding: 0; max-width: none; }
  .card { box-shadow: none; break-inside: avoid; }
  a { text-decoration: none; color: inherit; }
  thead { display: table-header-group; }
  tr { break-inside: avoid; }
  .beleg { max-width: none; }
  .beleg-head { border-bottom-color: #000; }
}

/* ── EZT-Auskunft: Warennummer → Maßnahmen als Karten (hub.html) ── */
#auskunft { display: grid; gap: 14px; padding: 12px 16px 24px; }
.ak-group { border: 1px solid var(--border); border-radius: var(--radius-md);
            background: var(--panel); }
.ak-head { display: flex; gap: 14px; align-items: baseline; flex-wrap: wrap;
           padding: 12px 16px; border-bottom: 1px solid var(--border); }
.ak-code { font-family: var(--font-mono); font-weight: 700; font-size: var(--text-md); }
.ak-desc { opacity: .85; flex: 1 1 320px; }
.ak-eust { margin-left: auto; text-align: center; border: 1px solid var(--border);
           border-radius: var(--radius); padding: 4px 12px; }
.ak-eust b { display: block; font-size: var(--text-lg); }
.ak-eust small { opacity: .7; letter-spacing: .06em; font-size: var(--text-2xs); }
.ak-measures { display: grid; gap: 10px; padding: 12px 16px; }
.ak-measure { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; }
.ak-mhead { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.ak-mkey { font-family: var(--font-mono); font-weight: 600; }
.ak-mtags { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }
.ak-tag { border: 1px solid var(--border); border-radius: var(--radius-pill);
          padding: 1px 9px; font-size: var(--text-xs); opacity: .85; }
.ak-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
           gap: 4px 18px; margin-top: 6px; font-size: var(--text-base); }
.ak-grid dt { opacity: .6; font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: .05em; }
.ak-grid dd { margin: 0; }
.ak-measure details { margin-top: 8px; border-top: 1px dashed var(--border); padding-top: 6px; }
.ak-measure summary { cursor: pointer; font-size: var(--text-sm); opacity: .9; }
.ak-measure details table { width: 100%; font-size: var(--text-sm); margin-top: 6px; }
.ak-measure details td { padding: 3px 8px 3px 0; vertical-align: top; }
.ak-inherit { font-size: var(--text-xs); opacity: .65; }
.ak-more { justify-self: center; }
.ak-notices { padding: 0 16px 12px; font-size: var(--text-sm); }
