/*
 * Kunden-Portal · Layout und Zustände.
 *
 * Diese Datei setzt KEINE Werte. Farbe, Schrift, Abstand und Zustand kommen aus dem
 * Marken-Fundament: brand/tokens.css (primitiv -> semantisch) und brand/components.css
 * (Komponenten-Ebene), beide unter /static/brand/ ausgeliefert (CD-S4).
 *
 * Wo eine Komponente gemeint ist, steht hier ihr Component-Token und nicht die semantische
 * Rolle darunter: --topbar-*, --btn-*, --field-*, --badge-*, --table-*, --kv-*, --meter-*,
 * --nav-*, --card-*, --icon-*, --focus-ring-* und die Dichte-Rollen (--gap-*, --pad-*).
 * Semantische Rollen (--surface, --ink, --ink-soft) tragen nur noch das Blatt-Layout.
 *
 * Regel und Begründung je Element: brand/components.md. Fehlt ein Wert, wird er dort
 * ergänzt, nicht hier gesetzt.
 *
 * Nackte Masse bleiben genau zwei Sorten, beide bewusst: Spaltenbreiten und der
 * Umbruchpunkt (Layout dieser Oberfläche, keine Marken-Werte) und die 1-px-Haarlinie, die
 * auch brand/belege/komponenten.html so schreibt. Farbe, Schrift und Abstand kommen
 * ausnahmslos aus Tokens; Gegenprobe:
 *   grep -rnE '#[0-9a-fA-F]{3,6}|rgba?\(' app/static/css app/templates   # erwartet leer
 */

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

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: var(--weight-body);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
}

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

/* Ein einziger Fokusring, überall gleich. Der Versatz legt ihn auf die umgebende Fläche,
   damit er gegen sie misst und nicht gegen die Komponente, die er umschliesst. */
:is(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

.skip {
  position: absolute;
  left: -9999px;
}
.skip:focus {
  left: var(--gap-stack);
  top: var(--gap-stack);
  z-index: 10;
  background: var(--card-bg);
  color: var(--ink);
  padding: var(--pad-compact);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
}

/* ---------- Kopfzeile ---------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  height: var(--topbar-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--topbar-gap);
  padding: 0 var(--topbar-pad-x);
  background: var(--topbar-bg);
  color: var(--topbar-ink);
}

/* Das Zeichen steht inline im HTML, nicht als <img>: die mono-Variante trägt currentColor
   und folgt damit --topbar-ink, das in Light und Dark verschieden ist. Ein Bild erbt keine
   Textfarbe. --topbar-gap ist der Schutzraum: innerhalb davon steht kein Text. */
.brand { display: flex; align-items: center; gap: var(--topbar-gap); }
.brand svg { display: block; width: auto; }
.brand-logo { display: flex; }
.brand-logo svg { height: var(--topbar-logo-height); }
.brand-icon { display: none; }
.brand-icon svg { height: var(--topbar-icon-height); }

.topbar-right { display: flex; align-items: center; gap: var(--gap-inline); }
.who { font-family: var(--font-data); font-size: var(--step--1); }

/* ---------- Knöpfe ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--btn-gap);
  min-height: var(--btn-min-height);
  padding: 0 var(--btn-pad-x);
  border: var(--btn-border-width) solid transparent;
  border-radius: var(--btn-radius);
  font: inherit;
  font-weight: var(--btn-weight);
  text-decoration: none;
  cursor: pointer;
}
/* Gedrückt: der Inhalt rückt eine Haarlinie nach, farblich bleibt es beim Hover-Zustand. */
.btn:active { transform: translateY(var(--btn-active-shift)); }

.btn.primary {
  background: var(--btn-primary-bg);
  color: var(--btn-primary-ink);
  border-color: var(--btn-primary-border);
}
.btn.primary:hover { background: var(--btn-primary-bg-hover); border-color: var(--btn-primary-bg-hover); }

.btn.secondary {
  background: var(--btn-secondary-bg);
  color: var(--btn-secondary-ink);
  border-color: var(--btn-secondary-border);
}
.btn.secondary:hover { background: var(--btn-secondary-bg-hover); }

.btn.quiet {
  background: var(--btn-quiet-bg);
  color: var(--btn-quiet-ink);
  border-color: var(--btn-quiet-border);
}
.btn.quiet:hover { background: var(--btn-quiet-bg-hover); }

/* Destruktiv ist ruhend konturiert und erst im Hover gefüllt: eine Aktion, die etwas
   löscht, wird nicht beworben. Sie ersetzt den primären Knopf ihrer Fläche. */
.btn.danger {
  background: var(--btn-danger-bg);
  color: var(--btn-danger-ink);
  border-color: var(--btn-danger-border);
}
.btn.danger:hover {
  background: var(--btn-danger-bg-hover);
  border-color: var(--btn-danger-bg-hover);
  color: var(--btn-danger-ink-hover);
}

/* Auf der Markenfläche trägt der übliche Fokusring nicht: er ist die Marke und stünde auf
   der Marke. Dort wechselt er auf die Gegenfarbe (nachgerechnet in CD-S3). */
.btn.on-accent {
  background: var(--btn-on-accent-bg);
  color: var(--btn-on-accent-ink);
  border-color: var(--btn-on-accent-border);
}
.btn.on-accent:hover { background: var(--btn-on-accent-bg-hover); }
.btn.on-accent:focus-visible { outline-color: var(--focus-ring-color-on-accent); }

.btn:disabled {
  background: var(--btn-disabled-bg);
  color: var(--btn-disabled-ink);
  border-color: var(--btn-disabled-border);
  cursor: not-allowed;
}

/* ---------- Eingabefeld ---------- */
/* Noch ohne Formular im Portal (Schreibpfade kommen mit PORTAL-S4), aber vollständig nach
   brand/components.md: Beschriftung immer sichtbar, Rand mit 3:1, Fehler mit Farbe UND
   doppelter Randstärke UND Text. */

.feld { display: flex; flex-direction: column; gap: var(--field-gap); }
.feld label { font-size: var(--step--1); color: var(--field-label-ink); }
.feld .pflicht { color: var(--field-required-ink); }
.feld input, .feld select, .feld textarea {
  font: inherit;
  color: var(--field-ink);
  background: var(--field-bg);
  border: var(--field-border-width) solid var(--field-border);
  border-radius: var(--field-radius);
  padding: var(--field-pad-y) var(--field-pad-x);
  min-height: var(--field-min-height);
}
.feld :is(input, select, textarea)::placeholder { color: var(--field-placeholder-ink); }
.feld :is(input, select, textarea):hover { border-color: var(--field-border-hover); }
.feld :is(input, select, textarea):focus-visible { border-color: var(--field-border-focus); }
.feld :is(input, select, textarea):disabled {
  background: var(--field-disabled-bg);
  color: var(--field-disabled-ink);
  border-color: var(--field-disabled-border);
}
.feld :is(input, select, textarea)[aria-invalid="true"] {
  border: var(--field-error-width) solid var(--field-error-border);
  background: var(--field-error-bg);
}
.feld .hinweis { font-size: var(--step--1); color: var(--field-hint-ink); }
.feld .fehler { font-size: var(--step--1); color: var(--field-error-ink); }

/* ---------- Anmeldung ---------- */

/* Vor der Anmeldung gibt es keine Kopfzeile: die Anmeldefläche trägt das Logo selbst und
   steht allein auf dem Seitengrund. */
.login {
  /* Die Fusszeile mit den Rechtstexten steht darunter und soll ohne Scrollen sichtbar sein. */
  min-height: calc(100dvh - var(--legal-block));
  display: grid;
  place-items: center;
  padding: var(--gap-block);
}
.login-card {
  width: min(var(--login-width), 100%);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
  padding: var(--login-pad);
  display: flex;
  flex-direction: column;
  gap: var(--login-gap);
}
/* Volles Logo als Absender. Die mono-Variante folgt currentColor, deshalb steht hier die
   Markenfarbe: auf einer Karte wäre die Textfarbe anthrazit, und der Absender trägt die
   Marke. --login-gap ist zugleich der Schutzraum darunter. */
.login-mark { align-self: center; color: var(--login-logo-ink); }
.login-mark svg { display: block; height: var(--login-logo-height); width: auto; }
.login-card h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: var(--weight-medium);
  line-height: var(--lh-tight);
}
.login-lede { margin: 0; color: var(--ink-soft); }
.login-foot { margin: 0; font-size: var(--step--1); color: var(--ink-faint); }

/* Eine abgewiesene Anmeldung ist ein Fehler und trägt die Fehler-Rollen des Eingabefelds:
   Farbe, doppelte Randstärke und Text zugleich. */
.notice {
  margin: 0;
  padding: var(--pad-compact);
  border-left: var(--field-error-width) solid var(--field-error-border);
  background: var(--field-error-bg);
  color: var(--field-error-ink);
  font-size: var(--step--1);
}

/* Hinweisseite bei abgewiesenem Schreibaufruf: dieselbe Karte wie die Anmeldefläche, aber
   unter der Kopfzeile, deshalb ohne die Bildschirmhöhe, die die Anmeldefläche allein auf dem
   Seitengrund stehen lässt. */
.notice-page {
  display: grid;
  place-items: center;
  padding: var(--gap-block);
}

/* ---------- Gerüst: Navigation + Inhalt ---------- */

.shell {
  display: grid;
  grid-template-columns: 12rem minmax(0, 1fr);
  align-items: start;
}

.nav {
  position: sticky;
  top: var(--topbar-height);
  max-height: calc(100dvh - var(--topbar-height));
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--pad-compact) var(--nav-item-pad-x);
  background: var(--nav-bg);
  border-right: 1px solid var(--nav-edge);
}
.nav a {
  display: flex;
  align-items: center;
  gap: var(--nav-item-gap);
  min-height: var(--nav-item-min-height);   /* Tippziel, auch auf dem Handy */
  padding: 0 var(--nav-item-pad-x);
  border-left: var(--nav-marker-width) solid transparent;
  border-radius: var(--nav-item-radius);
  color: var(--nav-ink);
  text-decoration: none;
  font-size: var(--nav-size);
}
.nav a:hover { background: var(--nav-hover-bg); }
/* Der aktive Eintrag trägt vier Merkmale, nicht eines: Fläche, Kante, Gewicht und
   aria-current. In Graustufen bleibt er damit erkennbar. */
.nav a[aria-current="true"] {
  background: var(--nav-current-bg);
  border-left-color: var(--nav-current-marker);
  color: var(--nav-current-ink);
  font-weight: var(--nav-current-weight);
}
.nav-group {
  font-family: var(--font-data);
  font-size: var(--nav-group-size);
  font-variant: small-caps;
  letter-spacing: var(--nav-group-tracking);
  color: var(--nav-group-ink);
  padding: var(--space-2) var(--nav-item-pad-x) var(--space-1);
}

.content {
  padding: 0 var(--gap-block) var(--gap-section);
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  .content { scroll-behavior: auto; }
}

/* ---------- Blöcke ---------- */

.block {
  padding-top: var(--gap-block);
  /* Sprungziel darf nicht unter den klebenden Leisten verschwinden. `--sticky-height` ist
     die Summe aller Leisten über dem Inhalt: auf dem Desktop nur die Kopfzeile, auf dem
     Handy zusätzlich die Navigationsleiste. app.js misst den Wert nach und überschreibt ihn,
     die Angaben hier sind der Stand ohne JavaScript. */
  scroll-margin-top: calc(var(--sticky-height) + var(--gap-stack));
}
.block + .block { border-top: 1px solid var(--divider-strong); margin-top: var(--gap-block); }
.block-head {
  display: flex;
  align-items: baseline;
  gap: var(--gap-stack);
  margin-bottom: var(--space-2);
}
.block-head h1, .block-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: var(--weight-medium);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
  display: flex;
  align-items: center;
  gap: var(--gap-inline);
}
.block-head h2 { font-size: var(--step-1); letter-spacing: normal; }
.block-lede { margin: 0 0 var(--gap-group); color: var(--ink-soft); }

/* ---------- Kacheln ---------- */

.tiles {
  display: grid;
  gap: var(--gap-group);
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}
.tile {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
  padding: var(--card-pad);
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
}
.tile-head { display: flex; align-items: center; justify-content: space-between; gap: var(--gap-inline); }
.tile-name { display: flex; align-items: center; gap: var(--gap-inline); font-weight: var(--weight-medium); }
.num {
  font-family: var(--font-data);
  font-size: var(--step--1);
  color: var(--meter-label-ink);
  font-variant-numeric: var(--meter-numeric);
}

/* Limit-Anzeige als <progress>: die CSP verbietet Inline-Styles, `value` und `max` sind
   Attribute. Beide Engines brauchen ihre eigenen Pseudo-Elemente. Ruhig bis 79 %, warnend
   ab 80 %, kritisch ab 100 %, dieselben Schwellen wie in app/models.py. */
progress.meter {
  appearance: none;
  -webkit-appearance: none;
  display: block;
  width: 100%;
  height: var(--meter-height);
  border: 0;
  border-radius: var(--meter-radius);
  background: var(--meter-track);   /* Firefox: Spur */
  overflow: hidden;
}
progress.meter::-webkit-progress-bar { background: var(--meter-track); }
progress.meter::-webkit-progress-value { background: var(--meter-fill); }
progress.meter::-moz-progress-bar { background: var(--meter-fill); }
progress.meter.warn::-webkit-progress-value { background: var(--meter-fill-warn); }
progress.meter.warn::-moz-progress-bar { background: var(--meter-fill-warn); }
progress.meter.critical::-webkit-progress-value { background: var(--meter-fill-critical); }
progress.meter.critical::-moz-progress-bar { background: var(--meter-fill-critical); }

.quota { margin: var(--gap-group) 0 0; color: var(--ink-soft); font-size: var(--step--1); }

/* ---------- Zustands-Badge ---------- */
/* Farbe allein trägt nie die Aussage: der Zustand steht immer auch im Text, und der Rand
   hält 3:1, damit die Form auch dann trägt, wenn die Farbe nicht ankommt. */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--badge-gap);
  min-height: var(--badge-min-height);
  padding: 0 var(--badge-pad-x);
  border: var(--badge-border-width) solid transparent;
  border-radius: var(--badge-radius);
  font-family: var(--badge-font);
  font-size: var(--badge-size);
  font-weight: var(--badge-weight);
  letter-spacing: var(--badge-tracking);
  white-space: nowrap;
}
.badge.ok { color: var(--badge-ok-ink); background: var(--badge-ok-bg); border-color: var(--badge-ok-border); }
.badge.warn { color: var(--badge-warn-ink); background: var(--badge-warn-bg); border-color: var(--badge-warn-border); }
.badge.critical { color: var(--badge-critical-ink); background: var(--badge-critical-bg); border-color: var(--badge-critical-border); }
.badge.neutral { color: var(--badge-neutral-ink); background: var(--badge-neutral-bg); border-color: var(--badge-neutral-border); }
.badge.accent { color: var(--badge-accent-ink); background: var(--badge-accent-bg); border-color: var(--badge-accent-border); }

/* Hinweis auf einen veralteten Stand (PORTAL-S4). Warnend, nicht alarmierend: die Anzeige ist
   alt, der Dienst ist es nicht. Farben aus derselben Warn-Familie wie die Limit-Anzeige, damit
   kein neuer Farbwert entsteht; die Aussage steht im Text und nicht nur in der Farbe. */
.notice-stale {
  margin: 0 0 var(--gap-group);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--badge-warn-border);
  border-radius: var(--radius);
  background: var(--badge-warn-bg);
  color: var(--badge-warn-ink);
  font-size: 0.9rem;
}
.notice-stale .stale-when { display: block; opacity: 0.85; }

/* ---------- Panels, Feld-Wert-Listen, Tabellen ---------- */

.panel {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
}
.kv {
  margin: 0;
  padding: var(--kv-pad);
  display: grid;
  grid-template-columns: minmax(8rem, max-content) minmax(0, 1fr);
  gap: var(--kv-row-gap) var(--kv-col-gap);
}
.kv dt {
  font-family: var(--font-data);
  font-size: var(--kv-label-size);
  font-variant: small-caps;
  letter-spacing: var(--kv-label-tracking);
  color: var(--kv-label-ink);
}
.kv dd { margin: 0; color: var(--kv-value-ink); font-variant-numeric: var(--kv-numeric); }

/* Auf schmalen Viewports scrollt die Tabelle waagrecht in ihrem eigenen Kasten, nicht die
   Seite. Die Kante zeigt, dass dort noch etwas ist. */
.table-scroll { overflow-x: auto; border-top: 1px solid var(--table-scroll-edge); }
.kv + .table-scroll { border-top: 1px solid var(--divider-strong); }
table { border-collapse: collapse; width: 100%; font-size: var(--table-size); }
th, td {
  text-align: left;
  padding: var(--table-pad-y) var(--table-pad-x);
  line-height: var(--table-line-height);
  white-space: nowrap;
}
th {
  background: var(--table-head-bg);
  color: var(--table-head-ink);
  font-family: var(--font-data);
  font-weight: var(--table-head-weight);
  font-size: var(--table-head-size);
  font-variant: small-caps;
  letter-spacing: var(--table-head-tracking);
  border-bottom: 1px solid var(--table-head-edge);
}
td { border-top: 1px solid var(--table-row-line); font-variant-numeric: var(--table-numeric); }
tbody tr:hover td { background: var(--table-row-hover-bg); }

.panel-empty, .panel-foot {
  margin: 0;
  padding: var(--pad-compact);
  color: var(--ink-faint);
  font-size: var(--step--1);
}
.panel-foot { border-top: 1px solid var(--divider-strong); }

/* Ein Symbol ist ein grafisches Objekt und hält 3:1. Es steht nie allein für eine Aussage,
   begleitet immer eine Beschriftung und trägt aria-hidden. */
.ico {
  width: var(--icon-size);
  height: var(--icon-size);
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: var(--icon-stroke);
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--icon-ink);
}

/* ---------- DNS-Record-Editor (PORTAL-S5) ---------- */
/* Erster Schreibpfad eines Kunden. Alles hier folgt derselben Regel wie der Rest: keine
   Inline-Styles (die CSP verwirft sie wortlos), keine neuen Farbwerte, jeder Zustand steht
   auch im Text. Die drei Meldungsflächen borgen sich die Familien der Badges, damit kein
   vierter Farbwert entsteht. */

.notice-ok, .notice-fehler, .notice-warn {
  margin: 0;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--divider-strong);
  font-size: var(--step--1);
}
.notice-ok { background: var(--badge-ok-bg); color: var(--badge-ok-ink); }
.notice-fehler { background: var(--badge-critical-bg); color: var(--badge-critical-ink); }
.notice-warn { background: var(--badge-warn-bg); color: var(--badge-warn-ink); }

/* Werte eines rrsets stehen untereinander, weil sie zusammengehören: sie werden gemeinsam
   gespeichert, und eine Zeile je Wert würde das Gegenteil suggerieren. */
.werte { margin: 0; padding: 0; list-style: none; white-space: normal; }
.werte li { overflow-wrap: anywhere; }
td .werte code { font-size: var(--step--1); }

.zeile-aktionen { display: flex; gap: var(--gap-inline); align-items: center; }
.zeile-aktionen form { margin: 0; }
.zeile-bearbeiten td { white-space: normal; background: var(--table-row-hover-bg); }

.dns-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--gap-group);
  padding: var(--pad-compact);
}
.dns-form h3 {
  grid-column: 1 / -1;
  margin: 0;
  font-size: var(--step-0);
}
.dns-form .feld-breit { grid-column: 1 / -1; }
.dns-form textarea { font-family: var(--font-data); resize: vertical; }
.dns-form output { font-family: var(--font-data); }
.formular-fuss { grid-column: 1 / -1; display: flex; gap: var(--gap-inline); align-items: center; }
.formular-neu { border-top: 1px solid var(--divider-strong); }

/* Die Zonen im DNS-Block des Dashboards: jede führt in ihren Editor. */
.zonen { margin: 0; padding: var(--pad-compact); list-style: none; }
.zonen li + li { margin-top: var(--space-2); }

.muted { color: var(--ink-faint); }

/* ---------- Handy: enge Kopfzeile, Navigation wird zur Leiste ---------- */

@media (max-width: 52rem) {
  /* Die enge Kopfzeile trägt das Logo-Icon statt des Logos: für das volle Zeichen reichen
     3 rem nicht (Minimalgrösse plus Schutzraum, brand/components.md). Alles andere folgt
     von selbst, weil Leiste, Sprungziel-Abstand und Anmeldefläche dieselbe Variable lesen. */
  :root {
    --topbar-height: var(--topbar-height-compact);
    /* Kopfzeile UND Navigationsleiste kleben übereinander, beide verdecken Sprungziele.
       Die Leistenhöhe ist das Tippziel plus die Polsterung unten; app.js ersetzt den Wert
       durch die gemessene, damit auch grössere Systemschrift passt. */
    --sticky-height: calc(var(--topbar-height) + var(--nav-item-min-height) + var(--space-2) * 2);
  }

  .brand-logo { display: none; }
  .brand-icon { display: flex; }

  .shell { grid-template-columns: minmax(0, 1fr); }
  .nav {
    position: sticky;
    top: var(--topbar-height);
    flex-direction: row;
    max-height: none;
    overflow-x: auto;
    border-right: 0;
    border-bottom: 1px solid var(--nav-edge);
    padding: var(--space-2);
  }
  .nav a { border-left: 0; border-bottom: var(--nav-marker-width) solid transparent; white-space: nowrap; }
  .nav a[aria-current="true"] { border-bottom-color: var(--nav-current-marker); }
  .nav-group { display: none; }   /* Gruppentitel ergeben in einer Leiste keinen Sinn */
  .content { padding: 0 var(--gap-group) var(--gap-section); }

  /* Die Kennung braucht auf dem Handy zwei Zeilen und drängt den Abmelden-Knopf aus dem
     Bild. Wer angemeldet ist, sieht das ohnehin am Inhalt, der Knopf muss erreichbar sein. */
  .who { display: none; }
}

/* ---------- Rechtstexte (Fusszeile jeder Seite) ---------- */

/* Wie auf der Apex-Seite: Absender links, drei Links rechts, kleine Schrift. Die Höhe steht
   als Variable, weil die Anmeldefläche sie von ihrer Mindesthöhe abzieht. */
:root { --legal-block: 3.5rem; }
.legal {
  min-height: var(--legal-block);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-inline);
  padding: var(--gap-stack) var(--gap-block);
  border-top: 1px solid var(--line-soft);
  font-size: var(--step--1);
  color: var(--ink-soft);
}
.legal ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--gap-block); }
.legal a { color: inherit; }
