/* ==========================================================================
   loginai.de  ·  design system (Port aus site/assets/css/main.css)
   --------------------------------------------------------------------------
   One stylesheet, no framework, no external requests. Mobile first.

   Radius lock:  every corner is 3px. Nothing is pill, nothing is 16px.
   Accent lock:  --accent is the only accent on the page. Status badges are
                 the one exception and they carry real semantic state.
   Theme lock:   light by default, full dark variant via prefers-color-scheme.
                 The closing call to action and the footer form one continuous
                 inverted block. That is the only theme block on a page.
   ========================================================================== */

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

/* --------------------------------------------------------------- tokens --- */
:root {
  --paper: #fcfcfd;
  --surface: #f3f5f8;
  --surface-2: #eceff4;
  --ink: #10151c;
  --ink-2: #4a5361;
  /* Dark enough to clear 4.5:1 on the tinted surface too, not just on paper. */
  --ink-3: #626a77;
  --rule: #e0e4ea;
  --rule-strong: #c9cfd8;
  /* An empty input has no label inside it, so its border is the only thing
     identifying the control. WCAG 1.4.11 wants 3:1 for that. */
  --field: #7c8593;
  /* Markenblau aus dem gelieferten Logo. Weiss darauf ergibt 5,1:1 und damit
     AA; der frueher genutzte dunklere Ton haette 8,2:1 gebracht, waere aber
     nicht die Marke gewesen. */
  --accent: #2563eb;
  --accent-press: #1b4ed0;
  --accent-tint: #eef3ff;
  --on-accent: #ffffff;

  --status-live: #0a6a4c;
  --status-live-bg: #e6f4ee;
  --status-customer: #1d4fd7;
  --status-customer-bg: #e9effc;
  --status-pilot: #7d5200;
  --status-pilot-bg: #fbf1de;
  --status-demo: #0d5b6b;
  --status-demo-bg: #e4f1f4;

  --err: #b3261e;

  --inv-bg: #0c1017;
  --inv-surface: #141a23;
  --inv-ink: #f2f4f7;
  --inv-ink-2: #a8b1bf;
  --inv-rule: #262d38;
  --inv-accent: #93b4ff;

  --hero-field: url("/assets/img/hero-field.webp");

  --radius: 3px;
  --maxw: 1280px;
  --gutter: clamp(1.25rem, 5vw, 4.5rem);
  --section-y: clamp(4rem, 9vw, 8rem);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  /* Für sich zeichnende Linien. --ease hat bei 30 % der Dauer schon 90 % des
     Weges hinter sich; eine damit gezeichnete Linie blitzt und kriecht nach. */
  --ease-draw: cubic-bezier(0.4, 0.05, 0.25, 1);

  --font: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, "Cascadia Mono", Menlo,
    Consolas, monospace;

  color-scheme: light;
}

/* The dark tokens exist twice on purpose.
   - The media query covers the visitor who never touched the switch, and it
     works with JavaScript switched off.
   - The attribute rule covers the visitor who chose dark explicitly.
   CSS cannot share one declaration block between a media query and a plain
   selector, so `node build/audit.mjs` compares the two blocks on every build
   and fails if they drift apart. Change both or neither.
   DARK-TOKENS-START-A */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #0b0e13;
    --surface: #12171f;
    --surface-2: #171d26;
    --ink: #edeff2;
    --ink-2: #a4adba;
    --ink-3: #7d8694;
    --rule: #212832;
    --rule-strong: #333c49;
    --field: #5b6575;
    --accent: #93b4ff;
    --accent-press: #b6ccff;
    --accent-tint: #16203a;
    --on-accent: #0b0e13;

    --status-live: #5fd6a8;
    --status-live-bg: #10241d;
    --status-customer: #9db9ff;
    --status-customer-bg: #131d33;
    --status-pilot: #e0b562;
    --status-pilot-bg: #241d10;
    --status-demo: #6fc6d8;
    --status-demo-bg: #102226;

    --err: #ff8a80;

    --inv-bg: #05070a;
    --inv-surface: #0e131a;
    --inv-ink: #f2f4f7;
    --inv-ink-2: #a8b1bf;
    --inv-rule: #1c222b;
    --inv-accent: #93b4ff;

    --hero-field: url("/assets/img/hero-field-dark.webp");

    color-scheme: dark;
  }
}
/* DARK-TOKENS-END-A */
/* DARK-TOKENS-START-B */
:root[data-theme="dark"] {
  --paper: #0b0e13;
  --surface: #12171f;
  --surface-2: #171d26;
  --ink: #edeff2;
  --ink-2: #a4adba;
  --ink-3: #7d8694;
  --rule: #212832;
  --rule-strong: #333c49;
  --field: #5b6575;
  --accent: #93b4ff;
  --accent-press: #b6ccff;
  --accent-tint: #16203a;
  --on-accent: #0b0e13;

  --status-live: #5fd6a8;
  --status-live-bg: #10241d;
  --status-customer: #9db9ff;
  --status-customer-bg: #131d33;
  --status-pilot: #e0b562;
  --status-pilot-bg: #241d10;
  --status-demo: #6fc6d8;
  --status-demo-bg: #102226;

  --err: #ff8a80;

  --inv-bg: #05070a;
  --inv-surface: #0e131a;
  --inv-ink: #f2f4f7;
  --inv-ink-2: #a8b1bf;
  --inv-rule: #1c222b;
  --inv-accent: #93b4ff;

  --hero-field: url("/assets/img/hero-field-dark.webp");

  color-scheme: dark;
}
/* DARK-TOKENS-END-B */

/* ---------------------------------------------------------------- reset --- */
*,
*::before,
*::after {
  box-sizing: border-box;
}
* {
  margin: 0;
}
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}
body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.62;
  letter-spacing: -0.006em;
  font-feature-settings: "cv11", "ss01";
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
@media (min-width: 48rem) {
  body {
    font-size: 1.125rem;
  }
}
img,
svg,
picture {
  display: block;
  max-width: 100%;
  height: auto;
}
button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}
a {
  color: inherit;
}
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 1px;
}
::selection {
  background: var(--accent);
  color: var(--on-accent);
}
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  background: var(--ink);
  color: var(--paper);
  padding: 0.75rem 1.25rem;
  border-radius: var(--radius);
}
.skip:focus {
  left: 1rem;
  top: 1rem;
}
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* -------------------------------------------------------------- headings --- */
h1,
h2,
h3,
h4 {
  font-weight: 560;
  line-height: 1.1;
  letter-spacing: -0.028em;
  text-wrap: balance;
}
.d1 {
  font-size: clamp(2.45rem, 6.6vw, 4.5rem);
  line-height: 1.02;
  letter-spacing: -0.038em;
}
.d2 {
  font-size: clamp(2.05rem, 4.9vw, 3.35rem);
  line-height: 1.05;
  letter-spacing: -0.034em;
}
.h2 {
  font-size: clamp(1.6rem, 3.3vw, 2.4rem);
  line-height: 1.1;
  letter-spacing: -0.03em;
}
.h3 {
  font-size: clamp(1.18rem, 1.7vw, 1.4rem);
  line-height: 1.24;
  letter-spacing: -0.022em;
  font-weight: 560;
}
.h4 {
  font-size: 1.0625rem;
  line-height: 1.35;
  letter-spacing: -0.016em;
  font-weight: 560;
}
.lead {
  font-size: clamp(1.16rem, 1.9vw, 1.4rem);
  line-height: 1.5;
  letter-spacing: -0.017em;
  color: var(--ink-2);
  max-width: 34ch;
}
.prose {
  color: var(--ink-2);
  max-width: 64ch;
}
.prose + .prose {
  margin-top: 1.1em;
}
.meta {
  font-size: 0.8125rem;
  line-height: 1.5;
  letter-spacing: 0.005em;
  color: var(--ink-3);
}
.num {
  font-variant-numeric: tabular-nums;
}
strong,
b {
  font-weight: 560;
  color: var(--ink);
}
code {
  font-family: var(--mono);
  font-size: 0.875em;
  background: var(--surface-2);
  border-radius: 2px;
  padding: 0.1em 0.35em;
  color: var(--ink);
}

/* ---------------------------------------------------------------- layout --- */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.sec {
  padding-block: var(--section-y);
  position: relative;
}
.sec--tint {
  background: var(--surface);
}
.sec--tight {
  padding-block: clamp(3rem, 6vw, 5rem);
}
.rule-top {
  border-top: 1px solid var(--rule);
}
.grid {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
.stack-sm > * + * {
  margin-top: 0.5rem;
}
.stack > * + * {
  margin-top: 1rem;
}
.stack-lg > * + * {
  margin-top: 2rem;
}

/* Section head: headline stacked over body. No split header, no eyebrow. */
.sec-head {
  max-width: 44ch;
  margin-bottom: clamp(2.25rem, 4.5vw, 3.75rem);
}
.sec-head .prose {
  margin-top: 1.15rem;
}

/* --------------------------------------------------------------- buttons --- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.82rem 1.4rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: -0.012em;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.18s var(--ease), border-color 0.18s var(--ease),
    color 0.18s var(--ease), transform 0.12s var(--ease);
}
.btn:active {
  transform: translateY(1px);
}
.btn--primary {
  background: var(--accent);
  color: var(--on-accent);
}
.btn--primary:hover {
  background: var(--accent-press);
}
.btn--ghost {
  border-color: var(--rule-strong);
  color: var(--ink);
  background: transparent;
}
.btn--ghost:hover {
  border-color: var(--ink);
  background: var(--surface-2);
}
.btn--inv {
  background: var(--inv-ink);
  color: var(--inv-bg);
}
.btn--inv:hover {
  background: #fff;
}
.btn--inv-ghost {
  border-color: var(--inv-rule);
  color: var(--inv-ink);
}
.btn--inv-ghost:hover {
  border-color: var(--inv-ink-2);
  background: var(--inv-surface);
}
.btn--sm {
  padding: 0.6rem 1rem;
  font-size: 0.9375rem;
}
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
}
/* On a phone two buttons of different label lengths read as a mistake.
   Stack them at equal width instead. */
@media (max-width: 29.99rem) {
  .btn-row {
    flex-direction: column;
    align-items: stretch;
  }
  .btn-row .btn {
    justify-content: center;
  }
}

/* Text link that carries a direction cue drawn from type, not an icon file. */
.tlink {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45rem;
  color: var(--accent);
  font-weight: 500;
  text-decoration: none;
  letter-spacing: -0.012em;
}
.tlink::after {
  content: "\2192";
  transition: transform 0.2s var(--ease);
}
.tlink:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.tlink:hover::after {
  transform: translateX(3px);
}
.tlink--ext::after {
  content: "\2197";
}

/* ---------------------------------------------------------------- badges --- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.28rem 0.6rem;
  border-radius: var(--radius);
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  white-space: nowrap;
}
.badge--live {
  color: var(--status-live);
  background: var(--status-live-bg);
}
.badge--customer {
  color: var(--status-customer);
  background: var(--status-customer-bg);
}
.badge--pilot {
  color: var(--status-pilot);
  background: var(--status-pilot-bg);
}
.badge--demo {
  color: var(--status-demo);
  background: var(--status-demo-bg);
}

/* ------------------------------------------------------------------- nav --- */
.hdr {
  position: sticky;
  top: 0;
  z-index: 100;
  background: color-mix(in srgb, var(--paper) 86%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--rule);
}
@supports not (backdrop-filter: blur(1px)) {
  .hdr {
    background: var(--paper);
  }
}
.hdr__in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  height: 4rem;
}
@media (min-width: 74rem) {
  .hdr__in {
    height: 4.5rem;
  }
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  text-decoration: none;
  flex: none;
}
/* Die Bildmarke ist breit (rund 2,1:1), deshalb Höhe vorgeben und Breite
   mitlaufen lassen. Die Wortmarke sitzt optisch auf derselben Linie. */
/* Die Bildmarke ist breit (226:108) und besteht aus fünf dünnen Strichen. Zu
   klein skaliert verschmelzen sie. Im gelieferten Logo ist die Marke etwa
   1,8 mal so hoch wie die Versalhöhe der Wortmarke, dieses Verhältnis gilt
   hier auch. */
.brand svg {
  height: 1.45rem;
  width: 3.03rem;
  flex: none;
  overflow: visible;
}
.brand__wm {
  font-size: 1.1875rem;
  font-weight: 560;
  letter-spacing: -0.038em;
}
@media (min-width: 74rem) {
  .brand svg {
    height: 1.65rem;
    width: 3.45rem;
  }
  .brand__wm {
    font-size: 1.3125rem;
  }
}
.brand__wm i {
  font-style: normal;
  color: var(--accent);
}

.nav,
.hdr__in .tsw {
  display: none;
}
@media (min-width: 74rem) {
  .hdr__in .tsw {
    display: inline-flex;
    margin-left: 0.35rem;
  }
  .nav {
    display: flex;
    align-items: center;
    gap: clamp(0.5rem, 1.6vw, 1.35rem);
    margin-left: auto;
  }
  .nav a {
    font-size: 0.9375rem;
    font-weight: 450;
    letter-spacing: -0.014em;
    text-decoration: none;
    color: var(--ink-2);
    white-space: nowrap;
    padding-block: 0.35rem;
    transition: color 0.16s var(--ease);
  }
  .nav a:hover {
    color: var(--ink);
  }
  .nav a[aria-current] {
    color: var(--ink);
    font-weight: 500;
    box-shadow: inset 0 -1px 0 var(--ink);
  }
  .hdr .btn {
    flex: none;
  }
}
.hdr__cta {
  display: none;
}
@media (min-width: 74rem) {
  .hdr__cta {
    display: inline-flex;
    margin-left: 0.5rem;
  }
}

/* ------------------------------------------------------- theme switch --- */
/* Built on real radio inputs, so a single tab stop, arrow keys and group
   semantics come from the browser instead of from JavaScript.

   The three glyphs are Phosphor Icons (Regular, MIT) drawn as CSS masks. That
   keeps the path data in this cached file instead of repeating it inside every
   page, and it lets the icon take its colour from the label. */
.tsw {
  display: inline-flex;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 2px;
  margin: 0;
  gap: 2px;
  flex: none;
}
.tsw label {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.85rem;
  height: 1.6rem;
  border-radius: 2px;
  cursor: pointer;
  color: var(--ink-3);
  transition: color 0.16s var(--ease), background-color 0.16s var(--ease);
}
.tsw label::before {
  content: "";
  flex: none;
  width: 0.95rem;
  height: 0.95rem;
  background-color: currentColor;
  -webkit-mask: var(--ic) center / contain no-repeat;
  mask: var(--ic) center / contain no-repeat;
}
.tsw label:hover {
  color: var(--ink);
}
.tsw input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
/* The active option is an accent fill, not a slightly lighter panel. Two dark
   surfaces sit about 1.04:1 apart, which is invisible, and a fill also survives
   colour vision deficiency where a hue shift alone would not.
   Accent against the track: 5.7:1 in light, 7.7:1 in dark. */
.tsw label:has(input:checked) {
  background: var(--accent);
  color: var(--on-accent);
}
.tsw label:has(input:checked):hover {
  background: var(--accent-press);
  color: var(--on-accent);
}
.tsw label:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.tsw label[data-i="sun"] {
  --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M120,40V16a8,8,0,0,1,16,0V40a8,8,0,0,1-16,0Zm72,88a64,64,0,1,1-64-64A64.07,64.07,0,0,1,192,128Zm-16,0a48,48,0,1,0-48,48A48.05,48.05,0,0,0,176,128ZM58.34,69.66A8,8,0,0,0,69.66,58.34l-16-16A8,8,0,0,0,42.34,53.66Zm0,116.68-16,16a8,8,0,0,0,11.32,11.32l16-16a8,8,0,0,0-11.32-11.32ZM192,72a8,8,0,0,0,5.66-2.34l16-16a8,8,0,0,0-11.32-11.32l-16,16A8,8,0,0,0,192,72Zm5.66,114.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32-11.32ZM48,128a8,8,0,0,0-8-8H16a8,8,0,0,0,0,16H40A8,8,0,0,0,48,128Zm80,80a8,8,0,0,0-8,8v24a8,8,0,0,0,16,0V216A8,8,0,0,0,128,208Zm112-88H216a8,8,0,0,0,0,16h24a8,8,0,0,0,0-16Z'/%3E%3C/svg%3E");
}
.tsw label[data-i="monitor"] {
  --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M208,40H48A24,24,0,0,0,24,64V176a24,24,0,0,0,24,24H208a24,24,0,0,0,24-24V64A24,24,0,0,0,208,40Zm8,136a8,8,0,0,1-8,8H48a8,8,0,0,1-8-8V64a8,8,0,0,1,8-8H208a8,8,0,0,1,8,8Zm-48,48a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,224Z'/%3E%3C/svg%3E");
}
.tsw label[data-i="moon"] {
  --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M233.54,142.23a8,8,0,0,0-8-2,88.08,88.08,0,0,1-109.8-109.8,8,8,0,0,0-10-10,104.84,104.84,0,0,0-52.91,37A104,104,0,0,0,136,224a103.09,103.09,0,0,0,62.52-20.88,104.84,104.84,0,0,0,37-52.91A8,8,0,0,0,233.54,142.23ZM188.9,190.34A88,88,0,0,1,65.66,67.11a89,89,0,0,1,31.4-26A106,106,0,0,0,96,56,104.11,104.11,0,0,0,200,160a106,106,0,0,0,14.92-1.06A89,89,0,0,1,188.9,190.34Z'/%3E%3C/svg%3E");
}

/* If :has() is missing there is no way to show which option is active, and if
   masks are missing there are no glyphs. In both cases fall back to the written
   labels, which are in the markup anyway. */
@supports not selector(:has(*)) {
  .tsw label {
    color: var(--ink-2);
  }
}
@supports not ((-webkit-mask-image: none) or (mask-image: none)) {
  .tsw label::before {
    display: none;
  }
  .tsw label {
    width: auto;
    padding-inline: 0.5rem;
    font-size: 0.8125rem;
  }
  .tsw label span {
    position: static;
    width: auto;
    height: auto;
    clip-path: none;
    overflow: visible;
    white-space: nowrap;
  }
}

/* In the mobile menu the switch gets its written labels, there is room. */
.mnav .tsw {
  width: 100%;
  margin-top: 1rem;
}
.mnav .tsw label {
  flex: 1;
  width: auto;
  height: 2.5rem;
  gap: 0.45rem;
  font-size: 0.9375rem;
  letter-spacing: -0.012em;
}
.mnav .tsw label span {
  position: static;
  width: auto;
  height: auto;
  clip-path: none;
  overflow: visible;
}

.burger {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-left: auto;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: transparent;
  font-size: 0.875rem;
  font-weight: 450;
  cursor: pointer;
}
.burger b {
  display: block;
  width: 1rem;
  height: 1px;
  background: var(--ink);
  box-shadow: 0 4px 0 var(--ink), 0 -4px 0 var(--ink);
}
@media (min-width: 74rem) {
  .burger {
    display: none;
  }
}
.mnav {
  display: none;
  border-top: 1px solid var(--rule);
  background: var(--paper);
  max-height: calc(100dvh - 4rem);
  overflow-y: auto;
}
.mnav[data-open] {
  display: block;
}
@media (min-width: 74rem) {
  .mnav {
    display: none !important;
  }
}
.mnav ul {
  list-style: none;
  padding: 0.5rem var(--gutter) 1.25rem;
  margin: 0;
}
.mnav li + li {
  border-top: 1px solid var(--rule);
}
/* Scoped to the list so it cannot repaint the button below it. */
.mnav ul a {
  display: block;
  padding: 0.95rem 0;
  text-decoration: none;
  font-size: 1.0625rem;
  font-weight: 450;
  letter-spacing: -0.018em;
}
.mnav ul a[aria-current] {
  color: var(--accent);
}
.mnav .btn {
  display: flex;
  width: 100%;
  justify-content: center;
  margin-top: 1rem;
}

/* ------------------------------------------------------------------ hero --- */
.hero {
  position: relative;
  padding-block: clamp(2.25rem, 4.4vw, 3.75rem) clamp(2.75rem, 6vw, 5rem);
  overflow: hidden;
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--hero-field);
  background-size: cover;
  background-position: 60% 40%;
  opacity: 0.32;
  pointer-events: none;
  z-index: -1;
}
@media (min-width: 62rem) {
  .hero::before {
    opacity: 0.5;
  }
}
.hero__in {
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
}
@media (min-width: 62rem) {
  .hero__in {
    grid-template-columns: minmax(0, 1.46fr) minmax(0, 1fr);
    align-items: stretch;
    gap: clamp(2.5rem, 5vw, 4.5rem);
  }
  .hero__in > div:first-child {
    align-self: center;
  }
}
/* The headline is two sentences of positioning copy. Sized so it lands on
   three lines at desktop instead of five. */
.hero .d1 {
  font-size: clamp(2.3rem, 5.1vw, 3.5rem);
  max-width: 27ch;
}
.hero .lead {
  margin-top: clamp(1.1rem, 2vw, 1.6rem);
  max-width: 41ch;
}
.hero .btn-row {
  margin-top: clamp(1.75rem, 3vw, 2.5rem);
}

/* The hero asset: the three rules the system runs under. Real content,
   not a fake product screenshot. */
.rules {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(8px);
  padding: clamp(1.5rem, 2.8vw, 2.25rem);
}
.rules__t {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--rule);
}
.rules ol {
  list-style: none;
  padding: 0;
  margin: 0;
  counter-reset: r;
}
.rules li {
  counter-increment: r;
  display: grid;
  grid-template-columns: 1.6rem 1fr;
  gap: 0.9rem;
  padding: 1.05rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: 0.9688rem;
  line-height: 1.45;
  letter-spacing: -0.013em;
}
.rules li:last-child {
  border-bottom: 0;
  padding-bottom: 0.25rem;
}
.rules li > * {
  grid-column: 2;
}
.rules li::before {
  grid-column: 1;
  grid-row: 1;
  content: counter(r, decimal-leading-zero);
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--accent);
  padding-top: 0.22rem;
  font-variant-numeric: tabular-nums;
}
.rules li b {
  display: block;
  font-weight: 560;
}
.rules li span {
  color: var(--ink-2);
}

/* Compact page header for subpages. */
.phead {
  padding-block: clamp(2.25rem, 5vw, 4rem) clamp(2rem, 4vw, 3.25rem);
  border-bottom: 1px solid var(--rule);
}
.phead__in {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
@media (min-width: 62rem) {
  .phead__in {
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
    align-items: end;
    gap: clamp(2.5rem, 5vw, 4.5rem);
  }
}
.phead .lead {
  max-width: 46ch;
}
.crumb {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  align-items: center;
  list-style: none;
  padding: 0;
  margin-bottom: 1.1rem;
  font-size: 0.8125rem;
  color: var(--ink-3);
}
.crumb a {
  text-decoration: none;
  color: var(--ink-3);
}
.crumb a:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.crumb li + li::before {
  content: "/";
  margin-right: 0.45rem;
  color: var(--rule-strong);
}

/* ------------------------------------------------- pattern: problem grid --- */
.pgrid {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--rule);
}
@media (min-width: 48rem) {
  .pgrid {
    grid-template-columns: 1fr 1fr;
  }
}
.pgrid > div {
  padding: clamp(1.5rem, 3vw, 2.25rem) 0;
  border-bottom: 1px solid var(--rule);
}
@media (min-width: 48rem) {
  .pgrid > div {
    padding-right: clamp(1.5rem, 4vw, 3.5rem);
  }
  .pgrid > div:nth-child(2n) {
    padding-right: 0;
    padding-left: clamp(1.5rem, 4vw, 3.5rem);
    border-left: 1px solid var(--rule);
  }
}
.pgrid h3 {
  margin-bottom: 0.6rem;
}
.pgrid p {
  color: var(--ink-2);
  font-size: 1rem;
  max-width: 42ch;
}

/* --------------------------------------------- pattern: asymmetric bento --- */
.bento {
  display: grid;
  gap: clamp(0.75rem, 1.4vw, 1rem);
}
@media (min-width: 56rem) {
  .bento {
    grid-template-columns: repeat(12, 1fr);
  }
  .bento > *:nth-child(1) {
    grid-column: span 7;
  }
  .bento > *:nth-child(2) {
    grid-column: span 5;
  }
  .bento > *:nth-child(3) {
    grid-column: span 5;
  }
  .bento > *:nth-child(4) {
    grid-column: span 7;
  }
}
.tile {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  overflow: hidden;
  text-decoration: none;
  transition: border-color 0.2s var(--ease), transform 0.25s var(--ease);
}
.tile:hover {
  border-color: var(--rule-strong);
}
.tile__fig {
  margin: 0;
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
}
.tile__fig img {
  width: 100%;
  aspect-ratio: 2 / 1;
  object-fit: cover;
}
/* Signaturgrafik als Inline-SVG. Die viewBox ist 2:1 und damit gleich der
   Kachelvorgabe, deshalb schneidet das voreingestellte preserveAspectRatio
   nichts ab und object-fit wäre wirkungslos. color setzt die Graustufen, die
   im SVG als currentColor stehen. */
.tile__fig .sig {
  width: 100%;
  aspect-ratio: 2 / 1;
  color: var(--ink-3);
}
.tile__b {
  padding: clamp(1.25rem, 2.4vw, 1.85rem);
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  flex: 1;
}
.tile__b p {
  color: var(--ink-2);
  font-size: 1rem;
  margin: 0;
}
.tile__b .tlink {
  margin-top: auto;
  padding-top: 0.4rem;
}
.tile--plain .tile__b {
  gap: 0.55rem;
}

/* --------------------------------------- pattern: sticky split with list --- */
.split {
  display: grid;
  gap: clamp(2rem, 4vw, 3rem);
}
@media (min-width: 62rem) {
  .split {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: clamp(3rem, 7vw, 6rem);
    align-items: start;
  }
  .split__aside {
    position: sticky;
    top: 7rem;
  }
}
/* On the contact page the form is the point of the page. On a phone it goes
   above the supporting column instead of below it. */
@media (max-width: 61.99rem) {
  .split--form > *:first-child {
    order: 2;
  }
}
.checks {
  list-style: none;
  padding: 0;
  margin: 0;
  border-top: 1px solid var(--rule);
}
.checks li {
  display: grid;
  grid-template-columns: 1.5rem 1fr;
  gap: 0.85rem;
  padding: 1.05rem 0;
  border-bottom: 1px solid var(--rule);
  color: var(--ink-2);
  font-size: 1rem;
}
.checks li::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  margin-top: 0.55rem;
  border-radius: 1px;
  background: var(--accent);
  transform: rotate(45deg);
}
.checks li b {
  color: var(--ink);
}
.checks--plain li::before {
  background: var(--rule-strong);
}

/* --------------------------------------------- pattern: numbered process --- */
.steps {
  list-style: none;
  padding: 0;
  margin: 0;
  counter-reset: s;
  display: grid;
  gap: 0;
}
.steps > li {
  counter-increment: s;
  position: relative;
  padding: clamp(1.5rem, 3vw, 2.25rem) 0 clamp(1.5rem, 3vw, 2.25rem)
    clamp(3rem, 6vw, 5.5rem);
  border-top: 1px solid var(--rule);
}
.steps > li:last-child {
  border-bottom: 1px solid var(--rule);
}
.steps > li::before {
  content: counter(s, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: clamp(1.5rem, 3vw, 2.25rem);
  font-family: var(--mono);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}
.steps > li::after {
  content: "";
  position: absolute;
  left: 0.55rem;
  top: 3.35rem;
  bottom: 0;
  width: 1px;
  background: var(--rule);
}
.steps > li:last-child::after {
  display: none;
}
.steps h3 {
  margin-bottom: 0.55rem;
}
.steps p {
  color: var(--ink-2);
  max-width: 62ch;
}
.steps ul {
  margin: 0.9rem 0 0;
  padding-left: 1.1rem;
  color: var(--ink-2);
}
.steps ul li {
  margin-top: 0.3rem;
}

/* Ordered flow used on showcase and solution pages. */
.flow {
  counter-reset: f;
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
}
@media (min-width: 48rem) {
  .flow {
    grid-template-columns: 1fr 1fr;
  }
}
.flow li {
  counter-increment: f;
  background: var(--paper);
  padding: 1.15rem clamp(1.1rem, 2vw, 1.5rem);
  display: grid;
  grid-template-columns: 1.7rem 1fr;
  gap: 0.85rem;
  font-size: 1rem;
  color: var(--ink-2);
}
.flow li::before {
  content: counter(f, decimal-leading-zero);
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--accent);
  padding-top: 0.2rem;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------- pattern: horizontal showcase rail --- */
.rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 84vw;
  gap: clamp(0.75rem, 1.4vw, 1rem);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  padding-bottom: 1rem;
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
  overscroll-behavior-x: contain;
}
.rail > * {
  scroll-snap-align: start;
}
@media (min-width: 40rem) {
  .rail {
    grid-auto-columns: 47%;
  }
}
@media (min-width: 62rem) {
  .rail {
    grid-auto-flow: row;
    grid-template-columns: repeat(3, 1fr);
    overflow: visible;
    margin-inline: 0;
    padding-inline: 0;
    padding-bottom: 0;
  }
}

/* -------------------------------------------------- pattern: tag cluster --- */
.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  list-style: none;
  padding: 0;
  margin: 0;
}
.tags li {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 0.42rem 0.75rem;
  font-size: 0.9375rem;
  color: var(--ink-2);
  background: var(--paper);
}

/* Two column key/value block for delivery items and system types. */
.defs {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--rule);
}
@media (min-width: 48rem) {
  .defs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(2rem, 5vw, 4rem);
  }
}
.defs > div {
  padding: 1.15rem 0;
  border-bottom: 1px solid var(--rule);
}
.defs dt,
.defs .k {
  font-weight: 560;
  letter-spacing: -0.016em;
}
.defs dd,
.defs .v {
  margin: 0.35rem 0 0;
  color: var(--ink-2);
  font-size: 1rem;
}

/* --------------------------------------- pattern: phone mockup (Nachweis) --- */
/* Rahmen für die Bildschirmaufnahmen des Live-Systems. Das Gerät entsteht aus
   zwei verschachtelten Radien plus Kante und Schatten, nicht aus einem
   Rahmenbild, damit kein weiterer Abruf nötig ist. */
.phones {
  display: grid;
  gap: clamp(1.75rem, 5vw, 3.5rem);
  justify-items: center;
  padding-top: 0.5rem;
}
@media (min-width: 40rem) {
  .phones {
    grid-template-columns: 1fr 1fr;
    align-items: start;
    gap: clamp(1.5rem, 4vw, 3rem);
  }
  /* leichter Versatz, damit die beiden Geräte nicht wie eine Tabelle wirken */
  .phones > :nth-child(2) {
    margin-top: clamp(1.5rem, 4vw, 3rem);
  }
}
.phone {
  margin: 0;
  max-width: 17rem;
  width: 100%;
}
.phone__d {
  position: relative;
  border-radius: 2.1rem;
  padding: 0.42rem;
  background: linear-gradient(160deg, #3b4350, #14181f 42%, #262c36);
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.3),
    inset 0 0 0 1px rgb(255 255 255 / 0.16),
    0 18px 40px -12px rgb(16 21 28 / 0.4);
}
.phone__d img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 1.72rem;
  background: #0b0b0d;
}
/* Kamerainsel. Sie sitzt in der Lücke der Statusleiste der Aufnahme. */
.phone__d::after {
  content: "";
  position: absolute;
  top: 1.05rem;
  left: 50%;
  transform: translateX(-50%);
  width: 4.1rem;
  height: 1.05rem;
  border-radius: 0.6rem;
  background: #07080a;
  pointer-events: none;
}
.phone figcaption {
  margin-top: 1rem;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--ink-3);
  text-align: center;
}
.phone figcaption b {
  display: block;
  color: var(--ink);
  font-weight: 560;
  font-size: 0.9375rem;
  letter-spacing: -0.014em;
}

/* ------------------------------------------------ pattern: Ansprechpartner --- */
.person {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.25rem);
  align-items: center;
}
@media (min-width: 34rem) {
  .person {
    grid-template-columns: minmax(0, 11rem) minmax(0, 1fr);
    gap: clamp(1.5rem, 4vw, 2.75rem);
  }
}
.person img {
  width: 100%;
  max-width: 11rem;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius);
  background: var(--surface-2);
}
.person__n {
  font-weight: 560;
  letter-spacing: -0.018em;
}
.person__r {
  color: var(--ink-3);
  font-size: 0.9375rem;
  margin-top: 0.15rem;
}
.person p.prose {
  margin-top: 0.9rem;
}
.person__c {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  margin-top: 1.1rem;
}

/* ------------------------------------------------- pattern: note / limit --- */
.note {
  border-left: 2px solid var(--accent);
  padding: 0.25rem 0 0.25rem 1.15rem;
  color: var(--ink-2);
  max-width: 62ch;
}
.note--quiet {
  border-left-color: var(--rule-strong);
}
.panel {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  padding: clamp(1.35rem, 3vw, 2rem);
}

/* ---------------------------------------------------------------- accord --- */
.acc {
  border-top: 1px solid var(--rule);
}
.acc details {
  border-bottom: 1px solid var(--rule);
}
.acc summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.3rem 0;
  cursor: pointer;
  list-style: none;
  font-size: clamp(1.05rem, 1.6vw, 1.2rem);
  font-weight: 500;
  letter-spacing: -0.02em;
}
.acc summary::-webkit-details-marker {
  display: none;
}
.acc summary::after {
  content: "+";
  font-family: var(--mono);
  font-size: 1.1rem;
  color: var(--accent);
  flex: none;
  transition: transform 0.2s var(--ease);
}
.acc details[open] summary::after {
  transform: rotate(45deg);
}
.acc summary:hover {
  color: var(--accent);
}
.acc__b {
  padding-bottom: 1.4rem;
  color: var(--ink-2);
  max-width: 68ch;
}

/* ------------------------------------------------------------------ form --- */
.form {
  display: grid;
  gap: 1.15rem;
}
.f {
  display: grid;
  gap: 0.4rem;
}
.f > label {
  font-size: 0.9375rem;
  font-weight: 500;
  letter-spacing: -0.012em;
}
.f > label .opt {
  color: var(--ink-3);
  font-weight: 400;
}
.f .hint {
  font-size: 0.8125rem;
  color: var(--ink-3);
}
.f input[type="text"],
.f input[type="email"],
.f input[type="tel"],
.f select,
.f textarea {
  width: 100%;
  padding: 0.72rem 0.85rem;
  background: var(--paper);
  border: 1px solid var(--field);
  border-radius: var(--radius);
  font-size: 1rem;
  color: var(--ink);
  transition: border-color 0.16s var(--ease), box-shadow 0.16s var(--ease);
}
.f textarea {
  min-height: 7.5rem;
  resize: vertical;
  line-height: 1.55;
}
.f input::placeholder,
.f textarea::placeholder {
  color: var(--ink-3);
  opacity: 1;
}
.f input:focus,
.f select:focus,
.f textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-tint);
}
.f select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-2) 50%),
    linear-gradient(135deg, var(--ink-2) 50%, transparent 50%);
  background-position: calc(100% - 1.15rem) 1.22rem,
    calc(100% - 0.8rem) 1.22rem;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 2.5rem;
}
/* Die Fehlerfarbe kommt aus dem Token-Block und folgt damit auch dem
   manuellen Farbschema-Schalter, nicht nur der Systemeinstellung. */
.f .err {
  font-size: 0.8125rem;
  color: var(--err);
  display: none;
}
.f[data-invalid] .err {
  display: block;
}
.f[data-invalid] input,
.f[data-invalid] select,
.f[data-invalid] textarea {
  border-color: var(--err);
}
.f2 {
  display: grid;
  gap: 1.15rem;
}
@media (min-width: 40rem) {
  .f2 {
    grid-template-columns: 1fr 1fr;
  }
}
.choice {
  display: grid;
  gap: 0.5rem;
}
@media (min-width: 30rem) {
  .choice {
    grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  }
}
.choice label {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.62rem 0.8rem;
  border: 1px solid var(--field);
  border-radius: var(--radius);
  font-size: 0.9375rem;
  cursor: pointer;
  background: var(--paper);
  transition: border-color 0.16s var(--ease), background-color 0.16s var(--ease);
}
.choice label:hover {
  border-color: var(--ink-3);
}
.choice input {
  accent-color: var(--accent);
  flex: none;
}
.choice input:checked + span {
  font-weight: 500;
}
.choice label:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-tint);
}
.consent {
  display: flex;
  gap: 0.7rem;
  align-items: flex-start;
  font-size: 0.9375rem;
  color: var(--ink-2);
  line-height: 1.5;
}
.consent input {
  margin-top: 0.28rem;
  accent-color: var(--accent);
  flex: none;
  width: 1rem;
  height: 1rem;
}
.consent a {
  color: var(--accent);
}
.fstate {
  border-radius: var(--radius);
  padding: 1rem 1.15rem;
  font-size: 1rem;
  display: none;
}
.fstate[data-show] {
  display: block;
  margin-bottom: 1.5rem;
}
.fstate--ok {
  background: var(--status-live-bg);
  color: var(--status-live);
  box-shadow: inset 0 0 0 1px currentColor;
}
.fstate--bad {
  background: var(--status-pilot-bg);
  color: var(--status-pilot);
  box-shadow: inset 0 0 0 1px currentColor;
}
.fstate b {
  color: inherit;
  display: block;
  margin-bottom: 0.2rem;
}
/* Honigtopf gegen Spam: fuer Menschen unsichtbar, fuer Formular-Bots ein
   normales Feld. Ein befuellter Honigtopf wird serverseitig verworfen. */
.hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.btn[aria-busy="true"] {
  opacity: 0.75;
  pointer-events: none;
}

/* ------------------------------------------------------- inverted footer --- */
.foot {
  background: var(--inv-bg);
  color: var(--inv-ink);
}
.cta {
  padding-block: clamp(3.5rem, 8vw, 7rem);
  border-bottom: 1px solid var(--inv-rule);
}
.cta__in {
  display: grid;
  gap: clamp(1.75rem, 4vw, 3rem);
}
@media (min-width: 62rem) {
  .cta__in {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    align-items: end;
    gap: clamp(3rem, 6vw, 5rem);
  }
}
.cta .d2 {
  max-width: 24ch;
}
.cta p {
  color: var(--inv-ink-2);
  max-width: 52ch;
  margin-top: 1.1rem;
}
.foot__main {
  padding-block: clamp(2.5rem, 5vw, 4rem);
  display: grid;
  gap: clamp(2rem, 4vw, 3rem);
}
@media (min-width: 48rem) {
  .foot__main {
    grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr));
    gap: clamp(1.5rem, 3vw, 2.5rem);
  }
}
/* Only the footer column labels are mono. The closing call to action inside
   .foot keeps display sizing, so this must not match its h2. */
.foot .fh {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--inv-ink-2);
  margin-bottom: 1rem;
}
/* Die Spaltentitel verlinken auf die Übersichtsseiten, behalten aber ihr
   Erscheinungsbild. Die allgemeine Linkregel weiter unten würde sonst
   Schriftgröße und Farbe der Listeneinträge erzwingen. */
.foot .fh a {
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
}
.foot .fh a:hover {
  color: var(--inv-ink);
}
.foot ul {
  list-style: none;
  padding: 0;
  margin: 0;
}
.foot li + li {
  margin-top: 0.6rem;
}
/* Scoped to the link lists so it cannot repaint the buttons in .cta. */
.foot__main a,
.foot__base a {
  color: var(--inv-ink-2);
  text-decoration: none;
  font-size: 0.9688rem;
  transition: color 0.16s var(--ease);
}
.foot__main a:hover,
.foot__base a:hover {
  color: var(--inv-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.foot .brand__wm {
  color: var(--inv-ink);
}
.foot .brand__wm i {
  color: var(--inv-accent);
}
.foot__about {
  color: var(--inv-ink-2);
  font-size: 0.9688rem;
  max-width: 34ch;
  margin-top: 1rem;
}
.foot__addr {
  font-style: normal;
  color: var(--inv-ink-2);
  font-size: 0.9375rem;
  line-height: 1.7;
  margin-top: 1.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--inv-rule);
  max-width: 34ch;
}
.foot__base {
  border-top: 1px solid var(--inv-rule);
  padding-block: 1.35rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.5rem;
  align-items: center;
  justify-content: space-between;
  font-size: 0.875rem;
  color: var(--inv-ink-2);
}
.foot__base ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.35rem;
}
.foot__base li + li {
  margin-top: 0;
}
.foot :focus-visible {
  outline-color: var(--inv-accent);
}

/* --------------------------------------------------- sticky mobile action --- */
.sticky-cta {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 90;
  padding: 0.7rem var(--gutter) calc(0.7rem + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--rule);
  transform: translateY(110%);
  transition: transform 0.28s var(--ease);
}
.sticky-cta[data-show] {
  transform: translateY(0);
}
.sticky-cta .btn {
  width: 100%;
  justify-content: center;
}
@media (min-width: 74rem) {
  .sticky-cta {
    display: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .sticky-cta {
    transition: none;
  }
}
body:has(.sticky-cta[data-show]) .foot__base {
  padding-bottom: 4.75rem;
}
@media (min-width: 74rem) {
  body:has(.sticky-cta[data-show]) .foot__base {
    padding-bottom: 1.35rem;
  }
}

/* --------------------------------------------------------------- reveal --- */
/* Motivated motion only: content enters in reading order so the eye lands on
   the headline before the supporting detail. Collapses to static when the
   visitor asked for less motion, and when JS never runs. */
@media (prefers-reduced-motion: no-preference) {
  [data-rv] {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
    transition-delay: var(--rv-d, 0ms);
  }
  [data-rv][data-in] {
    opacity: 1;
    transform: none;
  }
  html.no-js [data-rv] {
    opacity: 1;
    transform: none;
  }
}

/* ------------------------------------------------------- signaturgrafiken --- */
/* Die Signaturgrafiken zeigen ihren Ablauf einmal, wenn die Kachel in den Blick
   kommt: erst setzen sich die Stufen, dann zeichnet sich der Pfad, dann die
   Marker. Wie beim Reveal wird Bewegung HINZUGEFÜGT, nicht weggenommen — die
   Keyframes haben nur ein "from", der Zielzustand ist der, der im SVG steht.
   Ohne diese Media Query und ohne JavaScript ist die Grafik deshalb von sich
   aus fertig gezeichnet, im SVG selbst verbirgt nichts etwas.
   Eine Choreografie aus einem Dutzend Elementen mit gestaffelten Verzögerungen
   geht mit transition nur, indem JavaScript nacheinander Klassen setzt; das
   sind die einzigen @keyframes dieser Datei und sie ersparen genau das. */
@media (prefers-reduced-motion: no-preference) {
  .sig [data-draw],
  .sig [data-pop],
  .sig [data-fade],
  .sig [data-rise] {
    /* --sig-d/--sig-t setzt das Motiv je Gruppe, --rv-d ist die vorhandene
       Kachelstaffelung des Reveal (0 bis 350 ms). Ohne das Addieren liefe die
       Zeichnung an, während die Kachel noch unsichtbar ist. */
    animation-duration: var(--sig-t, 0.7s);
    animation-delay: calc(var(--rv-d, 0ms) + var(--sig-d, 0s));
    /* backwards, nicht both: vor dem Start gilt der Anfangszustand, nach dem
       Ende fällt das Element auf seinen eigenen Stil zurück. Dadurch trägt der
       Pfad das stroke-dasharray nur während der Zeichnung — beachtet eine
       Engine pathLength nicht, bleibt am Ende trotzdem eine durchgezogene
       Linie stehen statt einer gepunkteten. */
    animation-fill-mode: backwards;
    transform-box: fill-box;
    transform-origin: 50% 50%;
  }
  .sig [data-draw] {
    animation-name: sig-draw;
    animation-timing-function: var(--ease-draw);
  }
  .sig [data-pop] {
    animation-name: sig-pop;
    animation-timing-function: var(--ease);
  }
  .sig [data-fade] {
    animation-name: sig-fade;
    animation-timing-function: var(--ease);
  }
  /* Balken wachsen aus der Grundlinie, deshalb der Ursprung unten. */
  .sig [data-rise] {
    animation-name: sig-rise;
    animation-timing-function: var(--ease);
    transform-origin: 50% 100%;
  }

  /* Warten, bis die Kachel im Blick ist. */
  [data-rv]:not([data-in]) .sig [data-draw],
  [data-rv]:not([data-in]) .sig [data-pop],
  [data-rv]:not([data-in]) .sig [data-fade],
  [data-rv]:not([data-in]) .sig [data-rise] {
    animation-play-state: paused;
  }

  /* Ohne JavaScript kommt kein data-in, also gar keine Animation. */
  html.no-js .sig [data-draw],
  html.no-js .sig [data-pop],
  html.no-js .sig [data-fade],
  html.no-js .sig [data-rise] {
    animation: none;
  }

  /* Betonung beim Überfahren der Kachel. Bewusst kein Neuzeichnen: das müsste
     den fertigen Pfad erst löschen und liest sich als Fehler. */
  .sig [data-accent-end] {
    transition: transform 0.2s var(--ease);
  }
  .tile:hover .sig [data-accent-end] {
    transform: scale(1.18);
  }

  @keyframes sig-draw {
    from {
      stroke-dasharray: 1;
      stroke-dashoffset: 1;
    }
    to {
      stroke-dasharray: 1;
      stroke-dashoffset: 0;
    }
  }
  @keyframes sig-pop {
    from {
      opacity: 0;
      transform: scale(0.55);
    }
  }
  @keyframes sig-fade {
    from {
      opacity: 0;
    }
  }
  @keyframes sig-rise {
    from {
      opacity: 0;
      transform: scaleY(0.12);
    }
  }
}

/* ----------------------------------------------------------------- print --- */
@media print {
  .hdr,
  .mnav,
  .sticky-cta,
  .cta {
    display: none !important;
  }
  body {
    background: #fff;
    color: #000;
    font-size: 11pt;
  }
  .hero::before {
    display: none;
  }
}

/* ------------------------------------------------------------- article --- */
/* Beitragsbild über dem Fließtext. Die Breitenbegrenzung gehört an den
   Rahmen, nicht ans Bild: eine max-width am <img> selbst schlägt den Reset
   img{max-width:100%} und das Bild läuft auf schmalen Displays aus dem
   Viewport. Format 3:2 wie die erzeugten Bilder (1536x1024), damit beim
   Laden nichts springt und abweichende Uploads mittig beschnitten werden. */
.article__hero {
  max-width: 72ch;
  margin-bottom: 2.5rem;
}
.article__hero img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--radius);
}
/* Fließtext aus dem News-Editor (TipTap-HTML ohne Klassen). Der Reset oben
   nimmt allen Elementen die Ränder, hier bekommen sie sie zurück. */
.article {
  max-width: 72ch;
}
.article > * + * {
  margin-top: 1.1rem;
}
.article h2 {
  font-size: clamp(1.4rem, 2.6vw, 1.9rem);
  margin-top: 2.6rem;
}
.article h3 {
  font-size: clamp(1.15rem, 1.8vw, 1.35rem);
  margin-top: 2.1rem;
}
.article ul,
.article ol {
  padding-left: 1.35rem;
}
.article li + li {
  margin-top: 0.45rem;
}
.article a {
  color: var(--accent);
  text-underline-offset: 3px;
}
/* Muss nach .article > * + * stehen: gleiche Spezifität, die spätere Regel
   gewinnt, sonst greift dort margin-top statt der Abstände hier. */
.article img {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  margin-block: 1.8rem;
}
/* Tabellen aus dem Editor. display:block macht die Tabelle selbst zum
   Scrollrahmen — dieselbe Loesung wie bei .article pre, und sie braucht
   keinen Wrapper im HTML, den TipTap gar nicht liefert: getHTML gibt ein
   nacktes <table> aus, den .tableWrapper gibt es nur im Editor.
   border-collapse ist eine vererbte Eigenschaft und greift deshalb auch auf
   der anonymen Tabellenbox, die durch display:block entsteht. Die min-width
   an den Zellen erzwingt Scrollen statt Zerquetschen: ohne sie presst der
   Browser drei Spalten in 335 px und bricht mitten in den Woertern um. */
.article table {
  display: block;
  overflow-x: auto;
  scrollbar-width: thin;
  border-collapse: collapse;
  font-size: 0.9375rem;
  margin-block: 1.8rem;
}
.article th,
.article td {
  min-width: 14ch;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--rule);
  text-align: left;
  vertical-align: top;
}
.article th {
  background: var(--surface);
  font-weight: 600;
}
.article blockquote {
  border-left: 3px solid var(--rule-strong);
  padding-left: 1rem;
  color: var(--ink-2);
}
.article pre {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 1rem 1.15rem;
  overflow-x: auto;
  font-family: var(--mono);
  font-size: 0.875rem;
  line-height: 1.6;
}
.article code {
  font-family: var(--mono);
  font-size: 0.9em;
}
.article__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  color: var(--ink-3);
  font-size: 0.875rem;
}

/* Rechtstexte aus dem CMS (/impressum/, /datenschutz/): kompaktere
   Abschnitts-Überschriften als in Blog-Artikeln */
.article.legal h2 {
  font-size: clamp(1.3rem, 2.2vw, 1.7rem);
  margin-top: 3rem;
}

/* Kopierknopf an Code-Blöcken im Artikel (nachgerüstet von
   components/code-block-enhancer, rein optional). */
.code-block-container {
  position: relative;
}
.code-block-copy-btn {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink-2);
  cursor: pointer;
}
.code-block-copy-btn:hover {
  color: var(--ink);
  border-color: var(--rule-strong);
}

/* ------------------------------------------------- bento ab der 5. Kachel --- */
/* Das Grundmuster weiter oben ist auf genau vier Kacheln ausgelegt
   (nth-child(1) bis (4) mit 7/5/5/7 von zwölf Spalten). Die News-Übersicht
   zeigt bis zu neun; ab der fünften fehlte die Spaltenangabe, sie landeten ab
   56rem in je einer von zwölf Spalten. Dieselben Spannen, jetzt zyklisch. Für
   die ersten vier Kacheln sind die Werte identisch, bestehende
   Vier-Kachel-Abschnitte ändern sich also nicht. */
@media (min-width: 56rem) {
  .bento > *:nth-child(4n + 1) {
    grid-column: span 7;
  }
  .bento > *:nth-child(4n + 2) {
    grid-column: span 5;
  }
  .bento > *:nth-child(4n + 3) {
    grid-column: span 5;
  }
  .bento > *:nth-child(4n + 4) {
    grid-column: span 7;
  }
}
