/*!
 * SWOD-Home - Stylesheet.
 *
 * Copyright (c) 2026 ot2i7ba <https://github.com/ot2i7ba>
 * All rights, source, and usage reserved.
 *
 * @author    ot2i7ba <https://github.com/ot2i7ba>
 * @copyright 2026 ot2i7ba
 * @license   Proprietary
 * @link      https://github.com/ot2i7ba
 */

/*
 * Styling for both the public site (one-page sections, lightbox) and
 * the admin backend.
 *
 * No webfonts, no third-party resources, no inline styles in HTML.
 */

:root {
  --bg:           #0b0c0e;
  --bg-soft:      #101216;
  --panel:        #15171b;
  --panel-2:      #1c1f24;
  --line:         #2a2e35;
  --line-soft:    #20232a;
  --ink:          #e9eaec;
  /* Text colour for the four surfaces that veil a photograph — the lightbox
     caption banner, its source line, the lightbox close chip, the blog hero
     credit. Their backdrop is not the page but an unknown image behind a
     0.55–0.88 scrim, so their legibility budget must not be tied to the
     page's --ink. Pure white is the maximum the scrim can be asked to carry
     and holds against a bright photograph showing through. */
  --ink-on-dark:  #ffffff;
  --dim:          #b9bdc4;
  --muted:        #868b95;
  /* Lowest neutral step. On the dark ground it reaches 3.18:1 — enough for
     non-text marks (WCAG 1.4.11), never enough for type. Body copy that used
     to sit here (site footer) is on --muted. */
  --faint:        #5c626b;
  --red:          #e0202e;
  --red-bright:   #ff3340;
  /* The logo red. Surface and edge tone only: 1.87:1 on --bg makes it
     unusable as type. Carries the lower stop of the primary button and the
     shadow end of the duotone image filter. */
  --red-deep:     #850200;
  --green:        #4ec07a;
  /* The three tones of the logo laser, in the fixed relation the beam was
     drawn with: the base, a brighter tip, and the near-white core of the
     impact point. Notated as bare `R G B` triples rather than colours so
     each use site can dial its own alpha via `rgb(var(--laser) / A)`.
     These defaults ARE the historic red — a site with no laser colour
     configured renders exactly as before. The backend "Darstellung" page
     can override them through `?action=theme`, which derives the two
     brighter tones from a single operator hex (AppearanceStore::
     laserPalette). Kept in :root, not on the header, so the override
     needs one selector. */
  --laser:        224 32 46;
  --laser-bright: 255 51 64;
  --laser-core:   255 90 110;
  /* Shadow end of the duotone image filter (§ 8.4) and the opaque base of the
     filtered media box. A warm near-black, broken slightly towards the red —
     the dark counterpart of the light scheme's paper tone. `lighten` pins
     every channel to at least the layer colour, so on a dark page this end
     has to be the neutral one; with --red as the floor no pixel could fall
     below rgb(224,32,46) and every filtered photograph would glare. */
  --imgtint-base: #1a1214;
  /* Highlight end of the same filter, and the single dial for its strength.
     The brand red thinned with white: `multiply` reads a colour as a
     per-channel gain (white = 1.0), so 30 % red keeps the red channel at
     0.96 and pulls green/blue to 0.74/0.75. That is a constant ~23 %
     saturation over the whole tonal range — a red undertone rather than a
     colour cast that only bites where the picture is bright. Raising the
     share deepens the tint, lowering it washes it out. */
  --imgtint-tint: color-mix(in srgb, var(--red) 30%, #fff);

  /* Unified hover glow for clickable cards, tiles and images. */
  --rt-glow: 0 10px 30px -8px color-mix(in srgb, var(--red) 60%, transparent),
             0 0 0 1px color-mix(in srgb, var(--red) 35%, transparent);

  /* Spacing scale. One geometric-ish ladder so structural rhythm
     (section padding, heading margins, grid gaps) reads from a single
     source instead of scattered magic numbers. */
  --space-1: 6px;
  --space-2: 10px;
  --space-3: 16px;
  --space-4: 22px;
  --space-5: 28px;
  --space-6: 40px;
  --space-7: 64px;
  --space-8: 88px;

  /* Fluid type scale. clamp(min, preferred, max) so headings and the
     lede grow smoothly with the viewport between ~360px and the
     ~1180px shell width, instead of stepping at fixed breakpoints. The
     max values match the previous desktop sizes; the min values match
     the previous narrowest-breakpoint sizes — no visual regression at
     the extremes, smooth in between. */
  --fs-hero: clamp(1.625rem, 1.10rem + 2.70vw, 3rem);      /* 26 → 48 px */
  --fs-h1:   clamp(1.625rem, 1.35rem + 1.40vw, 2.25rem);   /* 26 → 36 px */
  --fs-h2:   clamp(1.3125rem, 1.15rem + 0.80vw, 1.625rem); /* 21 → 26 px */
  --fs-h3:   clamp(1rem, 0.94rem + 0.30vw, 1.125rem);      /* 16 → 18 px */
  --fs-lede: clamp(1rem, 0.92rem + 0.40vw, 1.1875rem);     /* 16 → 19 px */
  --fs-sm:   0.90625rem;  /* 14.5 px — secondary body / card text */
  --fs-xs:   0.78125rem;  /* 12.5 px — captions, meta, fine print */

  --section-pad-y: var(--space-8);
  --section-pad-x: var(--space-5);
  --content-max:   960px;
}

/*
 * Canonical responsive breakpoints. Component media-queries should snap
 * to one of these rather than inventing a nearby value:
 *   960px  — shell / two-column → stacked
 *   720px  — tablet / large phone landscape
 *   480px  — phone portrait
 * (A few component blocks below still carry their own intrinsic
 * breakpoint where the content genuinely flips at a different width;
 * those are intentional and commented at the point of use.)
 */

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Smooth anchor scrolling — but only for visitors who haven't asked the
   OS to reduce motion (consistent with the rest of the stylesheet). */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--red) 65%, transparent);
  text-underline-offset: 3px;
  transition: color 0.15s ease;
}
a:hover { color: var(--red-bright); }

/* -- Backdrop --------------------------------------------------------------- */
/* Two off-axis red glows over a vertical gradient base, plus a faint
   radially-masked grid overlay that echoes the splash-card
   composition. The grid is intentionally subtle (1px lines at 2.2%
   white opacity) and softly fades out towards the edges via the radial
   mask. */
.backdrop {
  position: fixed; inset: 0; z-index: -1;
  background:
    radial-gradient(820px 520px at 50% -8%, color-mix(in srgb, var(--red) 16%, transparent), transparent 70%),
    radial-gradient(640px 640px at 92% 108%, color-mix(in srgb, var(--red)  7%, transparent), transparent 70%),
    linear-gradient(180deg, var(--bg-soft), var(--bg));
}
.backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.022) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.022) 1px, transparent 1px);
  background-size: 46px 46px;
  mask-image: radial-gradient(circle at 50% 38%, #000 0%, transparent 78%);
  -webkit-mask-image: radial-gradient(circle at 50% 38%, #000 0%, transparent 78%);
}

/* -- Layout shell ----------------------------------------------------------- */
.shell-page {
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
}

/* -- Brand header (top of the page) ---------------------------------------- */
.site-header {
  padding: 36px 24px 8px;
  text-align: center;
}
.brand-home {
  display: inline-block;
  text-decoration: none;
  color: inherit;
  border-bottom: 0;
}
/* Display width derived from the former text wordmark's measured advance
   width at this rule's old font-size/weight/letter-spacing (~290-298px for
   "S.W.O.D.-Shot", see task report) — 300px is the nearest multiple of the
   source's aspect ratio (600:260 = 30:13) that keeps both 1x and 2x at
   whole pixel heights. */
.brand-word img { width: 300px; height: auto; display: block; margin: 0 auto; }
.brand-red  { color: var(--red-bright); }
.brand-sub {
  margin: 8px 0 0; font-size: 12px; letter-spacing: 2.6px;
  text-transform: uppercase; color: var(--muted);
}
/* Click-to-call, only rendered when `business_phone` is configured
   (templates/layout.php). Plain color/no-underline instead of the
   `--muted`+underline nav-link look, so it visually reads as a small
   action rather than a navigation entry. */
.header-phone {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 10px 0 0;
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--ink);
  text-decoration: none;
}
.header-phone:hover { color: var(--red-bright); }
.header-phone-icon { width: 15px; height: 15px; color: var(--red); flex: none; }

/* -- Anchor navigation (CSS-only, sticky) ---------------------------------- */
/* The bar floats at the top of the viewport once the user scrolls past the
   site-header. Solid enough to stay readable over arbitrary content under
   it, with a soft drop-shadow that sells the "floating" effect. */
.nav {
  position: sticky;
  top: 0;
  z-index: 10;
  background: color-mix(in srgb, var(--bg) 96%, transparent);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 6px 18px -6px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  margin: 32px 0 0;
}
.nav-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 12px 24px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  justify-content: center;
}
.nav a {
  font-size: 12px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  padding: 4px 2px;
  border-bottom: 1px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.nav a:hover {
  color: var(--ink);
  border-bottom-color: var(--red);
}
/* Scrollspy: the section currently in view (set by site.js). */
.nav a.is-current {
  color: var(--ink);
  border-bottom-color: var(--red);
}

/* Reading-progress bar (long-form pages; width driven by site.js). */
.read-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 3px;
  z-index: 50; pointer-events: none; background: transparent;
}
.read-progress-bar {
  display: block; height: 100%; width: 100%;
  transform: scaleX(0); transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--red), var(--red-bright));
}

/* Table of contents (server-built for long-form pages). */
.toc {
  margin: 0 0 28px; padding: 14px 18px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--bg-soft);
}
.toc-title {
  margin: 0 0 8px; font-size: 12px; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--muted);
}
.toc-list { list-style: none; margin: 0; padding: 0; }
.toc-list li { margin: 3px 0; }
.toc-list a { color: var(--dim); text-decoration: none; }
.toc-list a:hover { color: var(--red-bright); text-decoration: underline; }
.toc-sub { padding-left: 16px; font-size: 0.94em; }

/* -- Section: logos / social-proof wall ------------------------------------ */
.section-logos .lede { text-align: center; }
.logo-wall {
  display: flex; flex-wrap: wrap; gap: 22px 34px;
  align-items: center; justify-content: center; margin-top: 26px;
}
.logo-cell {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 8px 12px; border-radius: 8px; text-decoration: none;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}
a.logo-cell:hover, a.logo-cell:focus-visible { box-shadow: var(--rt-glow); transform: translateY(-2px); }
.logo-img {
  display: block; max-width: 180px; max-height: 60px;
  width: auto; height: auto; object-fit: contain;
}
.logos-grayscale .logo-img {
  filter: grayscale(1) brightness(1.35) contrast(0.92); opacity: 0.7;
  transition: filter 0.2s ease, opacity 0.2s ease;
}
.logos-grayscale .logo-cell:hover .logo-img,
.logos-grayscale .logo-cell:focus-visible .logo-img { filter: none; opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  a.logo-cell:hover, a.logo-cell:focus-visible { transform: none; }
}

/* -- Section: tabs (CSS-only, JS-free) ------------------------------------- */
.tabs { margin-top: 22px; }
/* The radios drive everything; visually hidden but still focusable. */
.tab-radio { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.tab-strip {
  display: flex; flex-wrap: wrap; gap: 2px;
  border-bottom: 1px solid var(--line);
}
.tab-label {
  cursor: pointer; padding: 10px 16px; font-size: 14px; font-weight: 600;
  color: var(--muted); border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.tab-label:hover { color: var(--ink); }
.tab-panels { padding-top: 18px; }
.tab-panel { display: none; }
/* Active label (red underline) for each tab index. */
.tab-radio:nth-of-type(1):checked ~ .tab-strip > .tab-label:nth-of-type(1),
.tab-radio:nth-of-type(2):checked ~ .tab-strip > .tab-label:nth-of-type(2),
.tab-radio:nth-of-type(3):checked ~ .tab-strip > .tab-label:nth-of-type(3),
.tab-radio:nth-of-type(4):checked ~ .tab-strip > .tab-label:nth-of-type(4),
.tab-radio:nth-of-type(5):checked ~ .tab-strip > .tab-label:nth-of-type(5),
.tab-radio:nth-of-type(6):checked ~ .tab-strip > .tab-label:nth-of-type(6),
.tab-radio:nth-of-type(7):checked ~ .tab-strip > .tab-label:nth-of-type(7),
.tab-radio:nth-of-type(8):checked ~ .tab-strip > .tab-label:nth-of-type(8),
.tab-radio:nth-of-type(9):checked ~ .tab-strip > .tab-label:nth-of-type(9),
.tab-radio:nth-of-type(10):checked ~ .tab-strip > .tab-label:nth-of-type(10),
.tab-radio:nth-of-type(11):checked ~ .tab-strip > .tab-label:nth-of-type(11),
.tab-radio:nth-of-type(12):checked ~ .tab-strip > .tab-label:nth-of-type(12) {
  color: var(--ink); border-bottom-color: var(--red);
}
/* Show the panel matching the checked tab. */
.tab-radio:nth-of-type(1):checked ~ .tab-panels > .tab-panel:nth-of-type(1),
.tab-radio:nth-of-type(2):checked ~ .tab-panels > .tab-panel:nth-of-type(2),
.tab-radio:nth-of-type(3):checked ~ .tab-panels > .tab-panel:nth-of-type(3),
.tab-radio:nth-of-type(4):checked ~ .tab-panels > .tab-panel:nth-of-type(4),
.tab-radio:nth-of-type(5):checked ~ .tab-panels > .tab-panel:nth-of-type(5),
.tab-radio:nth-of-type(6):checked ~ .tab-panels > .tab-panel:nth-of-type(6),
.tab-radio:nth-of-type(7):checked ~ .tab-panels > .tab-panel:nth-of-type(7),
.tab-radio:nth-of-type(8):checked ~ .tab-panels > .tab-panel:nth-of-type(8),
.tab-radio:nth-of-type(9):checked ~ .tab-panels > .tab-panel:nth-of-type(9),
.tab-radio:nth-of-type(10):checked ~ .tab-panels > .tab-panel:nth-of-type(10),
.tab-radio:nth-of-type(11):checked ~ .tab-panels > .tab-panel:nth-of-type(11),
.tab-radio:nth-of-type(12):checked ~ .tab-panels > .tab-panel:nth-of-type(12) {
  display: block;
}
/* Keyboard focus ring on the matching label. */
.tab-radio:nth-of-type(1):focus-visible ~ .tab-strip > .tab-label:nth-of-type(1),
.tab-radio:nth-of-type(2):focus-visible ~ .tab-strip > .tab-label:nth-of-type(2),
.tab-radio:nth-of-type(3):focus-visible ~ .tab-strip > .tab-label:nth-of-type(3),
.tab-radio:nth-of-type(4):focus-visible ~ .tab-strip > .tab-label:nth-of-type(4),
.tab-radio:nth-of-type(5):focus-visible ~ .tab-strip > .tab-label:nth-of-type(5),
.tab-radio:nth-of-type(6):focus-visible ~ .tab-strip > .tab-label:nth-of-type(6),
.tab-radio:nth-of-type(7):focus-visible ~ .tab-strip > .tab-label:nth-of-type(7),
.tab-radio:nth-of-type(8):focus-visible ~ .tab-strip > .tab-label:nth-of-type(8),
.tab-radio:nth-of-type(9):focus-visible ~ .tab-strip > .tab-label:nth-of-type(9),
.tab-radio:nth-of-type(10):focus-visible ~ .tab-strip > .tab-label:nth-of-type(10),
.tab-radio:nth-of-type(11):focus-visible ~ .tab-strip > .tab-label:nth-of-type(11),
.tab-radio:nth-of-type(12):focus-visible ~ .tab-strip > .tab-label:nth-of-type(12) {
  outline: 2px solid var(--red); outline-offset: 2px; border-radius: 4px;
}

/* -- Blog tags / tag filter ------------------------------------------------ */
.blog-tag-active { color: var(--red-bright); }
.blog-tagbar {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin: 0 0 26px;
}
.blog-tagbar-bottom { margin: 34px 0 0; }
.blog-tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--bg-soft);
  color: var(--dim); text-decoration: none; font-size: 13px;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.blog-tag:hover { color: var(--ink); border-color: color-mix(in srgb, var(--red) 50%, var(--line)); }
.blog-tag.is-active {
  color: var(--ink); border-color: var(--red);
  background: color-mix(in srgb, var(--red) 14%, var(--bg-soft));
}
.blog-tag-count { font-size: 11px; color: var(--muted); }
.blog-tag-sm { padding: 2px 10px; font-size: 12px; }
.blog-card-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 14px 4px; }
.blog-post-tags { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 6px; }

/* -- Backend: section trash (Papierkorb) ----------------------------------- */
.trash-list { list-style: none; margin: 0; padding: 0; }
.trash-item {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  justify-content: space-between;
  padding: 14px 16px; margin-bottom: 10px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--bg-soft);
}
.trash-meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.trash-title { font-weight: 600; }
.trash-tags { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 12.5px; }
.trash-type {
  font-size: 11px; letter-spacing: 0.3px; text-transform: uppercase;
  padding: 1px 8px; border-radius: 999px; border: 1px solid var(--line); color: var(--dim);
}
.trash-when { font-size: 12px; }
.trash-note { color: var(--red-bright); font-size: 12px; }
.trash-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.trash-actions form { margin: 0; }
.trash-config { margin: 0 0 6px; }
.input-narrow { max-width: 140px; }
/* Image-trash rows: thumbnail preview left, meta middle, actions right. */
.trash-item-image .trash-meta { flex: 1 1 auto; }
.image-trash-thumb { flex: 0 0 auto; display: block; line-height: 0; }
.image-trash-thumb img {
  width: 96px; height: 72px; object-fit: cover; display: block;
  border: 1px solid var(--line); border-radius: 8px; background: var(--panel-2);
}

/* -- Skip link (keyboard users) -------------------------------------------- */
/* Visually hidden until focused: the first Tab on the page reveals it and
   lets keyboard/screen-reader users jump past the navigation to <main>. */
.skip-link {
  position: absolute;
  left: 16px;
  top: -64px;
  z-index: 60;
  padding: 10px 16px;
  background: var(--panel);
  border: 1px solid var(--red);
  border-radius: 8px;
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
  transition: top 0.15s ease;
}
.skip-link:focus-visible {
  top: 16px;
  outline: 2px solid var(--red);
  outline-offset: 3px;
}

/* -- Back-to-top button (CSS-only) ----------------------------------------- */
/* Fixed-position anchor in the bottom-right. Smooth scroll is handled by
   `html { scroll-behavior: smooth }`. The button is always visible; on
   short pages it does nothing harmful (already at top → no-op).
   Compact 36 px circle — generous enough to tap reliably (the surrounding
   safe-area inset gives effective ~44 px of comfortable touch area) but
   small enough not to dominate the corner of the page. */
.back-to-top {
  position: fixed;
  right: 18px;
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  z-index: 20;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: color-mix(in srgb, var(--panel) 92%, transparent);
  border: 1px solid var(--line);
  color: var(--dim);
  text-decoration: none;
  box-shadow: 0 4px 12px -3px rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: color 0.15s ease, border-color 0.15s ease, transform 0.15s ease, background 0.15s ease;
}
.back-to-top svg { width: 14px; height: 14px; display: block; }
.back-to-top:hover {
  color: var(--ink);
  border-color: var(--red);
  background: color-mix(in srgb, var(--panel-2) 96%, transparent);
  transform: translateY(-2px);
}
.back-to-top:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .back-to-top { transition: none; }
  .back-to-top:hover { transform: none; }
  /* Freeze decorative motion: show the final, static state instead. */
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
  .bg-anim { opacity: 0.5; }
  /* threads: one static drawn layout */
  .bg-anim-threads .set-a { opacity: 1; }
  .bg-anim-threads .set-b { display: none; }
  .bg-anim-threads .t { stroke-dashoffset: 0; opacity: 0.28; }
  .bg-anim-threads .n { opacity: 0.4; }
  /* radar/pacman would animate themselves off-screen/invisible at their
     end frame — pin a visible static state instead. */
  .bg-anim-radar .ring { opacity: 0.28; transform: scale(0.7); }
  .bg-anim-radar .ring:nth-child(2), .bg-anim-radar .ring:nth-child(3) { display: none; }
  .bg-anim-pacman .pac { left: 46% !important; }
  /* terminal: pin to the top, no scroll */
  .bg-anim-terminal .term-scroll { transform: none !important; }
  /* hexwall: no row/cell glitch displacement, even brightness */
  .bg-anim-hexwall .hexw-row { transform: none !important; opacity: 1 !important; }
  .bg-anim-hexwall .hx-g { opacity: 0.55 !important; transform: none !important; }
  /* globe: full meridians drawn, arcs complete, dots mid-brightness */
  .bg-anim-globe .globe-merid { transform: none !important; }
  .bg-anim-globe .globe-arc { stroke-dashoffset: 0 !important; opacity: 0.4 !important; }
  .bg-anim-globe .globe-dot { opacity: 0.5 !important; transform: none !important; }
}

/* -- Section base ---------------------------------------------------------- */
.section {
  scroll-margin-top: 64px; /* anchor offset for sticky nav */
  padding: var(--section-pad-y) var(--section-pad-x);
}
.section-inner {
  max-width: var(--content-max);
  margin: 0 auto;
}
.section h1, .section h2 {
  font-weight: 800;
  letter-spacing: 0.4px;
  margin: 0 0 22px;
}
.section h1 {
  font-size: var(--fs-h1);
  line-height: 1.2;
}
.section h2 {
  font-size: var(--fs-h2);
}
.section h3 {
  font-size: var(--fs-h3);
  margin: var(--space-5) 0 var(--space-2);
  font-weight: 700;
  letter-spacing: 0.3px;
}
.section p { margin: 0 0 var(--space-3); }
.section ul { padding-left: var(--space-4); margin: 0 0 var(--space-3); }
.section li { margin-bottom: var(--space-1); }
.section .muted { color: var(--muted); }
.section .lede { color: var(--dim); font-size: var(--fs-lede); margin-bottom: var(--space-5); }

/* Section divider between alternating tones. */
.section + .section { border-top: 1px solid var(--line-soft); }
/* Heading + lead-in of a composed page belong to the first part that
   follows, so no rule is drawn between them. The parts themselves keep
   their dividers. */
.section-page + .section { border-top: 0; padding-top: 0; }
.section-alt {
  background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--panel) 25%, transparent));
}

/* Alternating section tints (opt-in via the "Darstellung" backend page →
   body.ui-tint). Every second on-page section gets the softer panel tone
   so a long one-pager reads as distinct bands instead of one flat sheet.
   The hero keeps its own treatment; sections that already carry a strong
   background of their own (quote, cta, maintenance) are excluded so the
   tint never fights an existing fill. nth-of-type counts <section>
   elements only, so the trailing lightbox <div>s never shift the rhythm. */
.ui-tint main > .section:nth-of-type(even):not(.section-hero):not(.section-quote):not(.section-cta):not(.section-maintenance) {
  background: var(--bg-soft);
}

/* -- Section: hero --------------------------------------------------------- */
.section-hero {
  padding-top: var(--space-7);
  padding-bottom: 96px;
  text-align: center;
}
.section-hero h1 {
  font-size: var(--fs-hero);
  letter-spacing: 0.6px;
}
.section-hero .lede {
  max-width: 640px;
  margin: 0 auto 30px;
}
.section-hero .cta-row {
  display: flex; gap: 14px; justify-content: center; flex-wrap: wrap;
}

/* Hero with an optional media slot: the centred text-only layout gives
   way to a two-column grid (text + product visual). The text column
   left-aligns so the visual has a clean edge to sit against; on narrow
   viewports it collapses back to a single stacked, centred column. */
.section-hero-split {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: var(--space-6);
  align-items: center;
  text-align: left;
}
.section-hero-split.hero-media-left { grid-template-columns: 0.95fr 1.05fr; }
.section-hero-split.hero-media-left .section-hero-text { order: 2; }
.section-hero-split.hero-media-left .section-hero-media { order: 1; }
.section-hero-split .lede { margin-left: 0; margin-right: 0; }
.section-hero-split .cta-row { justify-content: flex-start; }
.section-hero-media { margin: 0; min-width: 0; }
.section-hero-media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 14px;
  border: 1px solid var(--line);
  box-shadow: 0 18px 50px -26px rgba(0, 0, 0, 0.85);
}
.section-hero-media figcaption {
  margin-top: var(--space-2);
  font-size: var(--fs-xs, 12.5px);
  color: var(--muted);
  text-align: center;
}
@media (max-width: 720px) {
  .section-hero-split,
  .section-hero-split.hero-media-left { grid-template-columns: 1fr; text-align: center; }
  .section-hero-split .cta-row { justify-content: center; }
  .section-hero-split.hero-media-left .section-hero-text { order: 2; }
  .section-hero-split.hero-media-left .section-hero-media { order: 1; }
  .section-hero-split .section-hero-text { order: 2; }
  .section-hero-split .section-hero-media { order: 1; }
}

/* --- Hero "red thread" background animation (opt-in, JS-free) -------------
   Decorative SVG of entity nodes linked by red threads. Confined to the
   hero's upper area via a fade mask, kept behind the content, and fully
   frozen under prefers-reduced-motion (see the block below). No external
   assets, no script — CSP-safe. */
/* Shared by the hero + github sections via templates/_bg_animation.php.
   Confined to the host's upper area via a fade mask, behind the content,
   frozen under prefers-reduced-motion. No external assets/script. */
.has-bg-anim { position: relative; overflow: hidden; }
.has-bg-anim > .section-inner { position: relative; z-index: 1; }
.bg-anim {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.55;
  -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 55%, transparent 100%);
}
.bg-anim svg { width: 100%; height: 100%; display: block; }

/* Horizontal placement (opt-in via bg_animation_align): push the motion to
   one side so centred content doesn't cover it. 'center' = full bleed
   (default, no class). The inner edge fades toward the content. */
.bg-anim-pos-left {
  right: 38%;
  -webkit-mask-image: linear-gradient(to right, #000 65%, transparent 100%);
  mask-image: linear-gradient(to right, #000 65%, transparent 100%);
}
.bg-anim-pos-right {
  left: 38%;
  -webkit-mask-image: linear-gradient(to left, #000 65%, transparent 100%);
  mask-image: linear-gradient(to left, #000 65%, transparent 100%);
}

/* --- Variant: threads (two layouts cross-fade + redraw) --- */
.bg-anim-threads .t { stroke: var(--red); stroke-width: 1.6; opacity: 0.3; stroke-dasharray: 1; stroke-dashoffset: 1; }
.bg-anim-threads .n { fill: var(--red); opacity: 0.4; }
.bg-anim-threads .set { opacity: 0; }
.bg-anim-threads .set-a { animation: bg-set-a 16s ease-in-out infinite; }
.bg-anim-threads .set-b { animation: bg-set-b 16s ease-in-out infinite; }
.bg-anim-threads .set-a .t { animation: bg-draw-a 16s ease-in-out infinite; }
.bg-anim-threads .set-b .t { animation: bg-draw-b 16s ease-in-out infinite; }
@keyframes bg-set-a { 0% { opacity: 0; } 4% { opacity: 1; } 46% { opacity: 1; } 50% { opacity: 0; } 100% { opacity: 0; } }
@keyframes bg-set-b { 0% { opacity: 0; } 50% { opacity: 0; } 54% { opacity: 1; } 96% { opacity: 1; } 100% { opacity: 0; } }
@keyframes bg-draw-a { 0% { stroke-dashoffset: 1; } 12% { stroke-dashoffset: 0; } 50% { stroke-dashoffset: 0; } 50.01% { stroke-dashoffset: 1; } 100% { stroke-dashoffset: 1; } }
@keyframes bg-draw-b { 0% { stroke-dashoffset: 1; } 50% { stroke-dashoffset: 1; } 62% { stroke-dashoffset: 0; } 100% { stroke-dashoffset: 0; } }
@keyframes bg-thread-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
.bg-anim-once.bg-anim-threads .set-a { opacity: 1; animation: none; }
.bg-anim-once.bg-anim-threads .set-a .t { stroke-dashoffset: 0; animation: bg-thread-draw 2.4s ease forwards; }
.bg-anim-once.bg-anim-threads .set-b { display: none; }

/* --- Variant: constellation (drifting stars + faint links) --- */
.bg-anim-constellation .cl { stroke: var(--red); stroke-width: 1.2; opacity: 0.16; }
.bg-anim-constellation .star { fill: var(--red); opacity: 0.35; transform-box: fill-box; transform-origin: center; animation: bg-twinkle 4s ease-in-out infinite; }
.bg-anim-constellation .star:nth-child(3n)   { animation-duration: 5.5s; animation-delay: 1s; }
.bg-anim-constellation .star:nth-child(3n+1) { animation-duration: 6.5s; animation-delay: 2.2s; }
@keyframes bg-twinkle { 0%, 100% { opacity: 0.18; transform: scale(0.85); } 50% { opacity: 0.7; transform: scale(1.15); } }

/* --- Variant: radar / sonar --- */
.bg-anim-radar .ring { fill: none; stroke: var(--red); stroke-width: 1.4; transform-box: fill-box; transform-origin: center; opacity: 0; animation: bg-radar-ring 4.5s ease-out infinite; }
.bg-anim-radar .ring:nth-child(2) { animation-delay: 1.5s; }
.bg-anim-radar .ring:nth-child(3) { animation-delay: 3s; }
.bg-anim-radar .sweep { stroke: var(--red); stroke-width: 2; opacity: 0.5; transform-box: fill-box; transform-origin: bottom; animation: bg-radar-sweep 6s linear infinite; }
.bg-anim-radar .rc { fill: var(--red); opacity: 0.6; }
@keyframes bg-radar-ring { 0% { transform: scale(0.08); opacity: 0.6; } 80% { opacity: 0; } 100% { transform: scale(1); opacity: 0; } }
@keyframes bg-radar-sweep { from { transform: rotate(0); } to { transform: rotate(360deg); } }

/* --- Variant: datastream (matrix-style red rain) --- */
.bg-anim-datastream .ds { display: flex; justify-content: space-around; height: 100%; }
.bg-anim-datastream .ds-col {
  width: 2px; height: 100%;
  background: repeating-linear-gradient(to bottom, var(--red) 0 7px, transparent 7px 20px);
  background-size: 100% 54px;
  opacity: 0.18;
  animation: bg-ds-fall 3s linear infinite;
}
.bg-anim-datastream .ds-col:nth-child(even) { animation-duration: 4.2s; opacity: 0.12; }
.bg-anim-datastream .ds-col:nth-child(3n)   { animation-duration: 2.4s; animation-delay: 0.6s; }
@keyframes bg-ds-fall { from { background-position-y: 0; } to { background-position-y: 54px; } }

/* --- Variant: pacman --- */
.bg-anim-pacman .pac-lane { position: absolute; top: 38%; left: 0; right: 0; height: 24px; }
.bg-anim-pacman .pac-dots { position: absolute; left: 0; right: 0; top: 50%; height: 4px; transform: translateY(-50%); background: repeating-linear-gradient(to right, var(--red) 0 4px, transparent 4px 46px); opacity: 0.2; }
.bg-anim-pacman .pac { position: absolute; top: 0; left: 0; width: 22px; height: 22px; opacity: 0.6; animation: bg-pac-move 9s linear infinite; }
.bg-anim-pacman .pac::before, .bg-anim-pacman .pac::after { content: ''; position: absolute; left: 0; width: 22px; height: 11px; background: var(--red); }
.bg-anim-pacman .pac::before { top: 0; border-radius: 22px 22px 0 0; transform-origin: bottom; animation: bg-pac-top 0.35s linear infinite; }
.bg-anim-pacman .pac::after { bottom: 0; border-radius: 0 0 22px 22px; transform-origin: top; animation: bg-pac-bot 0.35s linear infinite; }
@keyframes bg-pac-move { from { left: -3%; } to { left: 103%; } }
@keyframes bg-pac-top { 0%, 100% { transform: rotate(0); } 50% { transform: rotate(-32deg); } }
@keyframes bg-pac-bot { 0%, 100% { transform: rotate(0); } 50% { transform: rotate(32deg); } }

/* --- Variant: space invaders --- */
.bg-anim-invaders .inv { display: flex; justify-content: center; gap: 36px; padding-top: 64px; animation: bg-inv-march 5s ease-in-out infinite; }
.bg-anim-invaders .inv-sprite { width: 28px; height: auto; fill: var(--red); opacity: 0.4; animation: bg-inv-bob 1.1s steps(2) infinite; }
@keyframes bg-inv-march { 0%, 100% { transform: translateX(-32px); } 50% { transform: translateX(32px); } }
@keyframes bg-inv-bob { from { transform: translateY(0); } to { transform: translateY(-3px); } }

/* --- Variant: live-log terminal (forensic feed, fast scroll) --- */
.bg-anim-terminal .term { position: absolute; inset: 0; overflow: hidden; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.bg-anim-terminal .term-scroll { animation: bg-term-scroll 16s linear infinite; }
.bg-anim-terminal .term-line { display: block; white-space: nowrap; font-size: 12px; line-height: 1.55; padding-left: 18px; color: color-mix(in srgb, var(--ink) 50%, transparent); }
.bg-anim-terminal .term-ts { color: var(--red-bright); opacity: 0.75; }
@keyframes bg-term-scroll { from { transform: translateY(0); } to { transform: translateY(-50%); } }

/* --- Variant: hex glitch wall --- */
.bg-anim-hexwall .hexw { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: center; gap: 6px; padding: 0 18px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.bg-anim-hexwall .hexw-row { display: flex; justify-content: space-between; font-size: 14px; letter-spacing: 2px; color: color-mix(in srgb, var(--ink) 26%, transparent); }
.bg-anim-hexwall .hexw-glitch { animation: bg-hex-row 7s steps(1) infinite; }
.bg-anim-hexwall .hexw-row:nth-child(3n)   { animation-delay: 2.5s; }
.bg-anim-hexwall .hexw-row:nth-child(3n+2) { animation-delay: 4.5s; }
.bg-anim-hexwall .hx-g { color: var(--red-bright); animation: bg-hex-cell 3.5s steps(1) infinite; }
.bg-anim-hexwall .hx-g:nth-child(even) { animation-delay: 1.2s; }
.bg-anim-hexwall .hx-g:nth-child(3n)   { animation-delay: 2.1s; }
@keyframes bg-hex-row { 0%, 92%, 100% { transform: translateX(0) skewX(0); opacity: 1; } 93% { transform: translateX(-3px) skewX(8deg); opacity: 0.6; } 95% { transform: translateX(4px) skewX(-6deg); } 97% { transform: translateX(-2px); } }
@keyframes bg-hex-cell { 0%, 80%, 100% { opacity: 0.5; transform: translateY(0); } 82% { opacity: 1; transform: translateY(-1px); } 86% { opacity: 0.15; } 90% { opacity: 0.9; } }

/* --- Variant: cyber globe (data-line sphere + tracing dots) --- */
/* `--neon` is the requested neon-blue tracing accent; it sits OUTSIDE
   the core brand palette (red/ink) — change here to tone it down. */
.bg-anim-globe { --neon: #29c7ff; }
.bg-anim-globe .globe-outline { fill: none; stroke: var(--red); stroke-width: 1.4; opacity: 0.35; }
.bg-anim-globe .globe-lat ellipse,
.bg-anim-globe .globe-merid ellipse { fill: none; stroke: var(--red); stroke-width: 1; opacity: 0.18; }
.bg-anim-globe .globe-merid { transform-box: fill-box; transform-origin: center; animation: bg-globe-spin 9s ease-in-out infinite; }
.bg-anim-globe .globe-arc { stroke: var(--red); stroke-width: 1.4; opacity: 0.5; stroke-dasharray: 1; stroke-dashoffset: 1; animation: bg-globe-arc 5s ease-in-out infinite; }
.bg-anim-globe .globe-arc.blue { stroke: var(--neon); }
.bg-anim-globe .globe-arc:nth-child(2) { animation-delay: 1.6s; }
.bg-anim-globe .globe-arc:nth-child(3) { animation-delay: 3.1s; }
.bg-anim-globe .globe-dot { fill: var(--red); transform-box: fill-box; transform-origin: center; animation: bg-globe-blink 2.6s ease-in-out infinite; }
.bg-anim-globe .globe-dot.blue { fill: var(--neon); }
.bg-anim-globe .globe-dot:nth-child(2n) { animation-delay: 0.8s; }
.bg-anim-globe .globe-dot:nth-child(3n) { animation-delay: 1.5s; }
@keyframes bg-globe-spin { 0%, 100% { transform: scaleX(1); } 50% { transform: scaleX(0.08); } }
@keyframes bg-globe-arc { 0% { stroke-dashoffset: 1; opacity: 0; } 20% { opacity: 0.5; } 60% { stroke-dashoffset: 0; opacity: 0.5; } 100% { stroke-dashoffset: 0; opacity: 0; } }
@keyframes bg-globe-blink { 0%, 100% { opacity: 0.25; transform: scale(0.8); } 50% { opacity: 0.9; transform: scale(1.25); } }

/* Background-animation multi-select (editor) — toggle chips instead of a
   bare checkbox list. The native checkbox stays (no-JS + a11y) but is
   compact + brand-accented; the whole chip lights up when checked. */
.bg-anim-choices {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 10px;
  margin: 6px 0 2px;
}
.bg-anim-choice {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 13px;
  font-size: 14px; line-height: 1.25;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg-soft);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
.bg-anim-choice:hover { border-color: color-mix(in srgb, var(--red) 45%, var(--line)); }
.bg-anim-choice:has(input:checked) {
  border-color: var(--red);
  background: color-mix(in srgb, var(--red) 12%, var(--bg-soft));
  box-shadow: var(--rt-glow);
}
.bg-anim-choice input { flex: none; width: 16px; height: 16px; accent-color: var(--red); cursor: pointer; }
.bg-anim-choice:focus-within { border-color: var(--red); }

/* -- Optional presentational refinements (opt-in via config, see layout) -- */
/* Node-line section dividers: a thin line with a centred red node between
   consecutive sections — the brand's node-line-node motif. */
.ui-dividers .section + .section { position: relative; }
.ui-dividers .section + .section::before {
  content: ""; position: absolute; top: -1px; left: 50%; transform: translateX(-50%);
  width: 140px; height: 2px; pointer-events: none; opacity: 0.5;
  background: linear-gradient(to right, transparent, var(--red) 28%, var(--red) 72%, transparent);
}
.ui-dividers .section + .section::after {
  content: ""; position: absolute; top: -4px; left: 50%; transform: translateX(-50%);
  width: 8px; height: 8px; border-radius: 50%; background: var(--red);
  pointer-events: none; opacity: 0.6;
}
/* No node between a composed page's heading and its first part — see
   `.section-page + .section` above. */
.ui-dividers .section-page + .section::before,
.ui-dividers .section-page + .section::after { content: none; }
/* Soft "scroll up" fade at the bottom of the viewport. */
.scroll-fade {
  position: fixed; left: 0; right: 0; bottom: 0; height: 90px;
  pointer-events: none; z-index: 5;
  background: linear-gradient(to top, var(--bg) 0%, color-mix(in srgb, var(--bg) 40%, transparent) 55%, transparent 100%);
}
/* Accent hover for content cards. */
.ui-cardhover .feature-card,
.ui-cardhover .stat-card,
.ui-cardhover .step-item,
.ui-cardhover .timeline-item,
.ui-cardhover .blog-teaser {
  transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}
.ui-cardhover .feature-card:hover,
.ui-cardhover .stat-card:hover,
.ui-cardhover .step-item:hover,
.ui-cardhover .timeline-item:hover,
.ui-cardhover .blog-teaser:hover {
  transform: translateY(-3px);
  border-color: var(--red);
  box-shadow: 0 12px 30px -18px color-mix(in srgb, var(--red) 60%, transparent);
}
@media (prefers-reduced-motion: reduce) {
  .ui-cardhover .feature-card:hover,
  .ui-cardhover .stat-card:hover,
  .ui-cardhover .step-item:hover,
  .ui-cardhover .timeline-item:hover,
  .ui-cardhover .blog-teaser:hover { transform: none; }
}

/* Duotone tint for content images, switched on from the backend
   ("Darstellung"). Two blend layers over a desaturated image give a true
   two-tone rendering — deliberately restrained, so the motif stays
   readable and only carries a red undertone; hovering fades the layers out
   to the original colours.
   Implemented with mix-blend-mode rather than an SVG filter because a
   filter referenced via url() cannot be interpolated — the transition to
   "filter: none" would snap instead of fading.

   The whole effect sits inside (hover: hover) on purpose. A device with no
   pointer never triggers the restore, so tinting it there would leave the
   images permanently discoloured — devices without a pointer show their
   images unmodified from the start.

   `.media` is a wrapper class set deliberately in the templates (the
   <a>/<picture> that encloses ONLY the image, never a sibling figcaption)
   rather than derived from exclusion rules here — a later content-image
   type stays untinted by default until a template opts it in.

   `display: block` is added on top of the brief's original rule: `<picture>`
   has no UA default display (it behaves like an inline wrapper), and every
   site using this class already sets its <img> to `display: block` — an
   inline box around a block-level child does not reliably size to that
   child, so `inset: 0` on the pseudo-elements would no longer track the
   rendered image. `<a>` wrappers are already block via their own section
   rules; the declaration is a harmless no-op there.

   `height: 100%` is the counterpart that `display: block` makes necessary.
   `.blog-card-image` and `.blog-post-hero` give their crop box a definite
   height (16/9 aspect-ratio on a definite width) and their `<img>` fills it
   with `height: 100%`. While the `<picture>` is inline it is not a block
   container, so that percentage resolves against the crop box. Turning the
   `<picture>` into a block makes IT the containing block — with an auto
   height, which makes the percentage indefinite, so the image falls back to
   its intrinsic height: the 16:9 crop and the backend's `object-position`
   anchors quietly stop working while the filter is on. Passing the definite
   height through keeps both switch states identical. Where the parent has an
   auto height (hero slot, image grid, embeds) `height: 100%` computes to
   `auto`, so this is inert there. */
@media (hover: hover) {
  /* The opaque base background is what makes the two blend layers behave.
     They cover the whole box, not only the pixels the image paints, and the
     isolated group starts out transparent. Per Compositing and Blending 1,
     § 9.2, the blend result is Co = (1 - αb)·Cs + αb·B(Cb, Cs): with a
     transparent backdrop (αb = 0) the blend is skipped and the source colour
     survives untouched — measured as pure brand red in the transparent half
     of a PNG and in the rounded-off corners. Giving the group an opaque floor
     puts αb at 1 everywhere, so a transparent area now resolves to
     lighten(base, base) → darken(…, red) = the base tone, which is the page's
     own near-black and therefore invisible. */
  .ui-imgtint .media { position: relative; isolation: isolate; display: block; height: 100%; background: var(--imgtint-base); }

  /* The floor fixes the colour but not the shape: the layers are still a
     rectangle over an image with rounded corners. Where the enclosing box
     already clips (image grid, split, blog card/hero/teaser) nothing is
     needed; these three carry their radius on the <img> itself, so the
     wrapper has to repeat it. Values mirror `.section-hero-media img`,
     `.embed-image img` and `.embed-gallery-item img`. */
  .ui-imgtint .section-hero-media .media { border-radius: 14px; overflow: hidden; }
  .ui-imgtint .embed-image .media,
  .ui-imgtint .embed-gallery-item .media { border-radius: 10px; overflow: hidden; }

  .ui-imgtint .media img { filter: grayscale(1); transition: filter .35s ease; }

  .ui-imgtint .media::before,
  .ui-imgtint .media::after {
    content: ""; position: absolute; inset: 0;
    pointer-events: none; transition: opacity .35s ease;
  }
  /* Duotone: `lighten` sets the floor, `multiply` the ceiling. On the dark
     page the floor is the neutral near-black, so a filtered photograph runs
     from the page's own shadow tone up into the tint colour instead of from
     red up into a glaring light tone.

     The ceiling used to be `darken` against the full brand red. That is a
     hard clamp: every channel above rgb(224,32,46) was cut down to it, which
     left a bright photograph as a near-solid red surface (measured 63 %
     mean saturation) while a dark one came through untouched (0.9 %) —
     the operator's complaint, and the opposite of an even undertone.
     `multiply` against the thinned red scales instead of clamping, so the
     luminance ladder of the picture survives and the same ~23 % of tint
     lands on shadows, midtones and highlights alike. */
  .ui-imgtint .media::before { background: var(--imgtint-base); mix-blend-mode: lighten; }
  .ui-imgtint .media::after  { background: var(--imgtint-tint); mix-blend-mode: multiply; }

  .ui-imgtint .media:hover img,
  .ui-imgtint .media:focus-within img { filter: none; }
  .ui-imgtint .media:hover::before,  .ui-imgtint .media:hover::after,
  .ui-imgtint .media:focus-within::before,
  .ui-imgtint .media:focus-within::after { opacity: 0; }
}

@media (hover: hover) and (prefers-reduced-motion: reduce) {
  .ui-imgtint .media img,
  .ui-imgtint .media::before,
  .ui-imgtint .media::after { transition: none; }
}

/* Backend "Darstellung" page: per-toggle origin hint chips. */
.appearance-toggle { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.appearance-toggle-label { font-weight: 600; }
.appearance-origin {
  font-size: 11px; letter-spacing: 0.4px; text-transform: uppercase;
  padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line);
}
.appearance-origin-inherited { color: var(--muted); }
.appearance-origin-set { color: var(--red-bright); border-color: color-mix(in srgb, var(--red) 45%, var(--line)); }

/* Laser colour row on the same page. The colour well is sized to match the
   text field's height so the pair reads as one control; browsers style
   `input[type=color]` themselves, so we only set the box and let the swatch
   inside it alone. */
.appearance-laser { display: flex; flex-direction: column; gap: 8px; }
.appearance-laser-controls {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
}
.appearance-laser-controls input[type="color"] {
  width: 46px; height: 38px; padding: 2px; cursor: pointer;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
}
.appearance-laser-controls input[type="text"] {
  width: 10ch; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  text-transform: lowercase;
}
.appearance-laser-reset {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--fs-xs, 12.5px); color: var(--dim);
}

/* Backend edit form: schedule window sub-labels. */
.schedule-field { display: flex; flex-direction: column; gap: 4px; }
.form-sublabel { font-size: var(--fs-xs, 12.5px); color: var(--muted); letter-spacing: 0.3px; }

/* Operator-only "not publicly visible" notice — both call sites: the
   scheduled-section banner in the public shell (App::renderSection) and the
   draft-preview banner above a blog post. A second, darker definition used to
   sit further down and, being later, won for both: it was the only dark
   surface left after the light rescheme and hard-coded its colours plus an
   `--amber` token that is never defined. This one is kept because it is built
   from the palette tokens and reads as part of the light UI; the sticky
   behaviour of the removed rule is not reinstated — the notice sits directly
   above the content it describes. */
.preview-banner {
  max-width: var(--content-max);
  margin: 18px auto 0;
  padding: 10px 18px;
  border: 1px dashed color-mix(in srgb, var(--red) 55%, var(--line));
  border-radius: 8px;
  background: color-mix(in srgb, var(--red) 10%, var(--panel));
  color: var(--dim);
  font-size: var(--fs-sm, 14.5px);
}

/* Admin section-list schedule badge. */
.sli-schedule {
  display: inline-block; margin-left: 6px;
  font-size: 11px; letter-spacing: 0.3px; text-transform: uppercase;
  padding: 1px 7px; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--red) 40%, var(--line));
  color: var(--dim);
}

/* Backend edit-form action row + whole-section preview modal. */
.edit-actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.section-preview-modal {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.section-preview-modal[hidden] { display: none; }
.section-preview-backdrop {
  position: absolute; inset: 0;
  background: color-mix(in srgb, #000 72%, transparent);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.section-preview-box {
  position: relative; z-index: 1;
  width: min(1100px, 100%); max-height: 90vh; overflow: auto;
  background: var(--bg); border: 1px solid var(--line);
  border-radius: 14px; box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.85);
}
.section-preview-head {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 18px; border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.section-preview-title {
  font-size: 12px; letter-spacing: 1.8px; text-transform: uppercase; color: var(--muted);
}
.section-preview-close {
  background: none; border: 0; color: var(--ink); cursor: pointer;
  font-size: 22px; line-height: 1; padding: 2px 8px; border-radius: 8px;
}
.section-preview-close:hover { color: var(--red-bright); }
.section-preview-body { padding: 0; }
body.preview-open { overflow: hidden; }

/* Backend snippets editor: one card-ish block per snippet. */
.snippet-row {
  border: 1px solid var(--line); border-radius: 10px;
  padding: 14px 16px; margin: 0 0 14px;
  background: color-mix(in srgb, var(--bg-soft) 60%, transparent);
}
.snippet-field { display: flex; flex-direction: column; gap: 4px; }
.snippet-content-label { display: block; margin-top: 10px; }
.snippet-delete { display: inline-flex; align-items: center; gap: 8px; margin-top: 8px; color: var(--dim); font-size: var(--fs-sm, 14.5px); }
.snippet-usage { margin-top: 6px; }

/* -- Section: features (3-column grid) ------------------------------------ */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 22px;
  margin: 16px 0 0;
}
.feature-card {
  background: linear-gradient(180deg, var(--panel), var(--panel-2));
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 22px 22px 20px;
}
.feature-card::before {
  content: "";
  display: block;
  height: 3px;
  width: 36px;
  background: var(--red);
  border-radius: 2px;
  margin-bottom: 14px;
}
.feature-card h3 { margin: 0 0 8px; font-size: 16px; }
.feature-card p { margin: 0; color: var(--dim); font-size: 14.5px; }

/* -- Section: images (CSS-only lightbox) ----------------------------------- */
.image-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
}
.image-grid figure {
  display: block;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: var(--panel-2);
  margin: 0;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.image-grid figure a {
  display: block;
  text-decoration: none;
}
/* Lift + accent only on clickable (lightbox) thumbnails. */
.image-grid figure:has(a):hover {
  border-color: var(--red);
  transform: translateY(-2px);
  box-shadow: var(--rt-glow);
}
.image-grid img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: center;
}
.image-grid figcaption {
  padding: 8px 12px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--muted);
}
/* Caption alignment utilities — shared by image grid, split and the
   lightbox banner so the choice is consistent across the site. */
.cap-left   { text-align: left; }
.cap-center { text-align: center; }
.cap-right  { text-align: right; }
/* Image credit/source line in a grid figcaption (lightbox-off case),
   mirroring .lightbox-source inside the overlay banner. */
.cap-source {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--dim);
  opacity: 0.85;
}

/* Lightbox overlay: visible only when its :target id is in the URL fragment.
   No JavaScript required — pure CSS. The "close" link clears the fragment. */
.lightbox {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(8, 9, 11, 0.92);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.lightbox:target { display: flex; }
.lightbox-frame {
  position: relative;
  margin: 0;
  max-width: 96vw;
  max-height: 92vh;
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  background: var(--bg);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.7);
}
/* Caption banner over the lower part of the enlarged image. */
.lightbox-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0;
  padding: 28px 18px 12px;
  background: linear-gradient(to top, rgba(8, 9, 11, 0.88), rgba(8, 9, 11, 0));
  color: var(--ink-on-dark);
  font-size: 14px;
  line-height: 1.45;
  pointer-events: none;
}
.lightbox-caption-text { display: block; }
/* Source/credit line inside the lightbox banner, after the caption. */
.lightbox-source {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--ink-on-dark);
  opacity: 0.85;
}
.lightbox-frame img {
  display: block;
  max-width: 96vw;
  max-height: 92vh;
  width: auto;
  height: auto;
}
.lightbox-close {
  position: absolute;
  top: 10px;
  right: 14px;
  color: var(--ink-on-dark);
  font-size: 22px;
  font-weight: 700;
  text-decoration: none;
  background: rgba(0,0,0,0.55);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 2px 10px;
  line-height: 1.3;
}
/* Hover turns the chip's glyph to the signal red: 5.62:1 on the composited
   chip, well clear of the 3:1 the 22px/700 glyph needs. */
.lightbox-close:hover {
  color: var(--red-bright);
  border-color: var(--red);
}

/* -- Section: quote -------------------------------------------------------- */
.section-quote {
  text-align: center;
}
.section-quote blockquote {
  margin: 0 auto;
  max-width: 720px;
  font-size: 22px;
  line-height: 1.45;
  color: var(--dim);
  font-style: italic;
  position: relative;
  padding: 0 30px;
}
.section-quote blockquote::before,
.section-quote blockquote::after {
  content: "";
  position: absolute;
  width: 60px;
  height: 2px;
  background: var(--red);
  left: 50%;
  transform: translateX(-50%);
}
.section-quote blockquote::before { top: -22px; }
.section-quote blockquote::after  { bottom: -22px; }
.section-quote cite {
  display: block;
  margin-top: 36px;
  color: var(--muted);
  font-size: 13px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  font-style: normal;
}

/* -- Section: CTA ---------------------------------------------------------- */
.section-cta {
  text-align: center;
  padding: 72px var(--section-pad-x);
}
.section-cta h2 { margin-bottom: 12px; }
.section-cta .lede { margin-bottom: 26px; }

/* -- Section: code --------------------------------------------------------- */
.section-code pre {
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 16px 18px;
  overflow-x: auto;
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink);
}
.section code, .markdown code {
  background: var(--panel-2);
  padding: 2px 6px;
  border-radius: 4px;
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 0.92em;
}
.section pre code, .markdown pre code {
  background: transparent;
  padding: 0;
  border-radius: 0;
  font-size: inherit;
}

/* -- Section: FAQ ---------------------------------------------------------- */
.faq-list { display: flex; flex-direction: column; gap: 10px; }
.faq-item {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 9px;
  overflow: hidden;
}
.faq-item summary {
  list-style: none;
  cursor: pointer;
  padding: 14px 18px;
  font-weight: 600;
  font-size: 15px;
  color: var(--ink);
  position: relative;
  user-select: none;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+";
  position: absolute;
  right: 18px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 22px;
  font-weight: 400;
  color: var(--red-bright);
  line-height: 1;
  transition: transform 0.15s ease;
}
.faq-item[open] summary::after { content: "−"; }
.faq-item summary:hover { background: color-mix(in srgb, var(--panel) 60%, transparent); }
.faq-answer {
  padding: 0 18px 16px;
  color: var(--dim);
  font-size: 14.5px;
}
.faq-answer p { margin: 8px 0; }

/* -- Section: Split (Image+Text) ------------------------------------------- */
.section-split-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  align-items: center;
}
/* DOM order is image-first → default (image-left) needs no reordering.
   For image-right the image moves to the second column so the TEXT sits
   left of it. */
.section-split-image-right .section-split-image { order: 1; }
.section-split-image a {
  display: block;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: var(--panel-2);
  text-decoration: none;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.section-split-image a:hover {
  border-color: var(--red);
  transform: translateY(-2px);
  box-shadow: var(--rt-glow);
}
.section-split-image img {
  display: block;
  width: 100%;
  height: auto;
}
.section-split-figure { margin: 0; }
.section-split-figure figcaption {
  padding: 8px 2px 0;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--muted);
}
.section-split-text h2 { margin-bottom: 16px; }
.section-split-text .markdown p:first-child { margin-top: 0; }

@media (max-width: 760px) {
  .section-split-grid {
    grid-template-columns: 1fr;
    gap: 24px;
  }
  /* Single column on mobile: image always on top, text below. */
  .section-split-image-right .section-split-image { order: 0; }
}

/* -- Section: Steps -------------------------------------------------------- */
.step-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 22px;
  padding: 0;
  margin: 16px 0 0;
  list-style: none;
  counter-reset: step;
}
.step-item {
  background: linear-gradient(180deg, var(--panel), var(--panel-2));
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 22px 22px 20px;
  position: relative;
}
.step-number {
  display: inline-block;
  width: 36px;
  height: 36px;
  line-height: 36px;
  text-align: center;
  border-radius: 50%;
  background: var(--red);
  color: #fff;
  font-weight: 800;
  font-size: 16px;
  margin-bottom: 12px;
}
.step-title { margin: 0 0 8px; font-size: 16px; }
.step-body  { margin: 0; color: var(--dim); font-size: 14.5px; }

/* -- Section: Stats -------------------------------------------------------- */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 18px;
  margin: 16px 0 0;
}
.stat-card {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 22px 20px;
  text-align: center;
}
.stat-value {
  font-size: 38px;
  line-height: 1;
  font-weight: 800;
  color: var(--red-bright);
  letter-spacing: -0.5px;
}
.stat-label {
  margin-top: 8px;
  font-size: 12.5px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted);
}

/* -- Section: Timeline ----------------------------------------------------- */
.timeline-list {
  list-style: none;
  padding: 0;
  margin: 16px 0 0;
  position: relative;
}
.timeline-list::before {
  content: "";
  position: absolute;
  left: 8px;
  top: 4px;
  bottom: 4px;
  width: 2px;
  background: var(--line);
}
.timeline-item {
  position: relative;
  padding: 8px 0 18px 32px;
}
.timeline-dot {
  position: absolute;
  left: 0;
  top: 14px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--bg);
  border: 3px solid var(--red);
  box-sizing: border-box;
}
.timeline-when {
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 4px;
}
.timeline-title {
  margin: 0 0 4px;
  font-size: 16px;
}
.timeline-body {
  margin: 0;
  color: var(--dim);
  font-size: 14.5px;
}

/* Copy button on code sections (revealed by site.js when clipboard works). */
.code-block { position: relative; }
.code-copy {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  padding: 4px 10px;
  font: inherit;
  font-size: 12px;
  color: var(--dim);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
}
.code-copy:hover, .code-copy:focus-visible { color: var(--ink); border-color: var(--muted); }
.code-copy.is-copied { color: var(--ink); border-color: var(--red); }

/* -- Maintenance banner (Admin-Sicht bei aktiver Wartung) ----------------- */
.maintenance-banner {
  position: sticky;
  top: 0;
  z-index: 200;
  background: var(--red);
  color: #fff;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.3px;
  padding: 10px 18px;
  text-align: center;
  border-bottom: 2px solid var(--red-bright);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
}
.maintenance-banner code {
  background: rgba(0, 0, 0, 0.22);
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 12px;
}

.maintenance-banner-link {
  color: #fff;
  text-decoration: underline;
  text-underline-offset: 3px;
  margin-left: 6px;
}
.maintenance-banner-link:hover { color: #fff; opacity: 0.85; }
/* Subtle pulsing dot — pure-CSS, no JS. */
.maintenance-banner-pulse {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
  animation: maint-pulse 2s infinite;
}
@keyframes maint-pulse {
  0%   { box-shadow: 0 0 0 0    rgba(255, 255, 255, 0.7); }
  70%  { box-shadow: 0 0 0 10px rgba(255, 255, 255, 0); }
  100% { box-shadow: 0 0 0 0    rgba(255, 255, 255, 0); }
}

/* -- Section: maintenance (public 503 page) ------------------------------- */
.section-maintenance {
  min-height: 60vh;
  display: flex;
  align-items: center;
  padding-top: 32px;
  padding-bottom: 32px;
}
.section-maintenance .section-inner {
  max-width: 560px;
  text-align: center;
}
.maintenance-message {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 32px 30px 30px;
  position: relative;
  overflow: hidden;
  text-align: left;
}
.maintenance-message::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--red), transparent);
}
.maintenance-message h1, .maintenance-message h2 {
  margin: 0 0 14px;
}
.maintenance-message p { margin: 10px 0; color: var(--dim); }

/* -- Section: legal -------------------------------------------------------- */
.section-legal {
  padding-top: 44px;
}
.section-legal h2 { margin-top: 26px; font-size: 18px; }

/* -- Hazy tag (anti-crawler obfuscation) ----------------------------------- */
/*
 * Server reverses the visible characters and intersperses junk-spans
 * (.hazy-noise) that are hidden via CSS. The wrapper `.hazy` uses
 * bidi-override to flip the visual order back to readable while the
 * raw DOM text still contains the reversed, junk-laden sequence. A
 * naive crawler that reads textContent gets unusable garbage.
 *
 * Headless browsers that render CSS can still extract the value —
 * this is security-through-obscurity, not a hard protection.
 */
.hazy {
  unicode-bidi: bidi-override;
  direction: rtl;
  white-space: nowrap;
}
.hazy-noise {
  display: none !important;
  user-select: none;
}
.hazy::after {
  /* prevent accidental leak via copy: append a zero-width separator
     so the entire span has consistent surrounding whitespace. */
  content: "\200B";
}

/* -- Footer ---------------------------------------------------------------- */
.site-footer {
  padding: 36px var(--section-pad-x) 48px;
  text-align: center;
  border-top: 1px solid var(--line-soft);
  /* --muted, not the palette's --faint: at 12.5px the footer carries running
     text (imprint links, contact line, copyright) and needs 4.5:1. --faint
     reaches 3.18:1 on --bg, --muted 5.72:1. */
  color: var(--muted);
  font-size: 12.5px;
  letter-spacing: 0.3px;
}
.site-footer .footer-links {
  margin-bottom: 12px;
  display: flex;
  gap: 6px 22px;
  flex-wrap: wrap;
  justify-content: center;
}
.site-footer .footer-links a {
  color: var(--muted);
  text-decoration: none;
  font-size: 11.5px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
}
.site-footer .footer-links a:hover { color: var(--ink); }
.footer-phone { color: var(--muted); text-decoration: none; }
.footer-phone:hover { color: var(--ink); }

/* -- Buttons --------------------------------------------------------------- */
/* The gradient runs from the signal red down into the logo red rather than
   starting at --red-bright: white on #ff3340 is 3.62:1 and the label is
   14.5px, so the bright end would fail AA. --red gives 4.76:1 at the top
   edge, --red-deep 10.47:1 at the bottom. For the same reason the hover no
   longer brightens the surface (brightness(1.08) drops the top edge to
   4.16:1) — it lights the brand glow instead. */
.btn {
  display: inline-block;
  padding: 12px 22px;
  background: linear-gradient(180deg, var(--red), var(--red-deep));
  color: #fff;
  border: 0;
  border-radius: 9px;
  font-size: 14.5px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-decoration: none;
  cursor: pointer;
  transition: box-shadow 0.15s ease, transform 0.05s ease;
}
.btn:hover  { box-shadow: var(--rt-glow); color: #fff; }
.btn:active { transform: translateY(1px); }
.btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--red-bright) 40%, transparent);
}
.btn-secondary {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line);
}
.btn-secondary:hover {
  border-color: var(--red);
  box-shadow: none;
  color: var(--ink);
}

/* -- Alerts ---------------------------------------------------------------- */
.alert {
  margin: 0 0 18px; padding: 12px 14px; font-size: 14px;
  color: #ffd9dc;
  background: color-mix(in srgb, var(--red) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--red) 42%, transparent);
  border-radius: 9px;
}
.alert-ok {
  color: #cdeedb;
  background: color-mix(in srgb, var(--green) 12%, transparent);
  border-color: color-mix(in srgb, var(--green) 40%, transparent);
}

/* ===========================================================================
   ADMIN BACKEND
   =========================================================================== */

.admin-shell {
  max-width: 920px;
  margin: 0 auto;
  padding: 28px 24px 48px;
}
.admin-head {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 28px;
}
.admin-head .admin-title {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.3px;
  margin: 0;
}
.admin-head .admin-nav {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}

/* One shared button look for every top-level nav element: group
   summaries, the Frontend link and the logout button. */
.admin-nav-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 6px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--dim);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.admin-nav-btn:hover { color: var(--ink); border-color: var(--red); }
.admin-nav-btn:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}
.admin-nav-btn-logout:hover { border-color: var(--red); color: var(--red-bright); }

/* Dropdown groups (native <details>; site.js adds outside-click /
   Escape / one-open-at-a-time on top). */
.admin-nav-group { position: relative; }
.admin-nav-group > summary { list-style: none; }
.admin-nav-group > summary::-webkit-details-marker { display: none; }
.admin-nav-group > summary::after {
  content: "\25BE";
  font-size: 10px;
  color: var(--muted);
  transition: transform 0.15s ease;
}
.admin-nav-group[open] > summary,
.admin-nav-group.active > summary {
  color: var(--ink);
  border-color: var(--red);
}
.admin-nav-group[open] > summary::after { transform: rotate(180deg); }
.admin-nav-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 80;
  min-width: 180px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 16px 38px -12px rgba(0, 0, 0, 0.65);
}
.admin-nav-panel a {
  display: block;
  padding: 9px 12px;
  border-radius: 7px;
  border-left: 2px solid transparent;
  color: var(--dim);
  font-size: 13.5px;
  text-decoration: none;
  transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}
.admin-nav-panel a:hover {
  color: var(--ink);
  background: var(--bg-soft);
}
.admin-nav-panel a.active {
  color: var(--ink);
  background: var(--bg-soft);
  border-left-color: var(--red);
}
.admin-nav-panel a:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: -2px;
}

.admin-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 22px 24px;
  margin-bottom: 22px;
}
.admin-card + .admin-card { margin-top: 0; }
.admin-card h2 {
  margin: 0 0 12px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--dim);
}

/* Section list */
.section-list { margin: 0; padding: 0; list-style: none; }
.section-list-item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-2);
  margin-bottom: 10px;
}
.section-list-item .sli-type {
  flex: 0 0 100px;
  font-size: 11px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--muted);
}
.section-list-item .sli-title {
  flex: 1;
  font-size: 14.5px;
  color: var(--ink);
}
.section-list-item.disabled { opacity: 0.5; }
/* Child of another section: indented one step, with a short connector so
   the nesting reads at a glance instead of having to compare titles. */
.section-list-item.is-child {
  margin-left: 34px;
  position: relative;
}
.section-list-item.is-child::before {
  content: "";
  position: absolute;
  left: -22px;
  top: 50%;
  width: 14px;
  height: 1px;
  background: var(--line);
}
/* Marks a section that is served as part of a composed page. */
.sli-embedded {
  font-size: 11px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--red);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 1px 8px;
  white-space: nowrap;
}
/* Parts of a composed page, listed read-only in its editor. */
.page-members { margin: 0; padding: 0; list-style: none; }
.page-member {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-2);
  margin-bottom: 8px;
}
.page-member.disabled { opacity: 0.55; }
.section-list-item .sli-actions {
  display: flex; gap: 6px;
}
.section-list-item .sli-actions form { display: inline; }
.section-list-item .sli-actions button {
  background: var(--bg-soft);
  border: 1px solid var(--line);
  color: var(--dim);
  border-radius: 6px;
  padding: 5px 10px;
  font-size: 12px;
  cursor: pointer;
}
.section-list-item .sli-actions button:hover {
  color: var(--ink);
  border-color: var(--red);
}
.section-list-item .sli-actions .danger:hover {
  color: var(--red-bright);
}

/* Forms */
.form-row { margin-bottom: 16px; }
/* Grouped fields in an edit form (e.g. the video source variants). */
.form-fieldset {
  margin: 0 0 18px;
  padding: 14px 16px 2px;
  border: 1px solid var(--line);
  border-radius: 8px;
}
.form-fieldset > legend {
  padding: 0 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--dim);
}
.form-row label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}
/* `tel` (contact form) and `datetime-local` (schedule windows, banner
   validity) were missing from this list. On the light scheme a UA-default
   field passed unnoticed on a white page; on the dark ground it stands out
   as a bright, half-width box. */
.form-row input[type=text],
.form-row input[type=password],
.form-row input[type=email],
.form-row input[type=tel],
.form-row input[type=url],
.form-row input[type=number],
.form-row input[type=datetime-local],
.form-row select,
.form-row textarea {
  width: 100%;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 9px;
  color: var(--ink);
  font-size: 15px;
  padding: 11px 14px;
  outline: none;
  font-family: inherit;
}
.form-row textarea {
  min-height: 200px;
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 13.5px;
  line-height: 1.55;
  resize: vertical;
}
.form-row input:focus, .form-row select:focus, .form-row textarea:focus {
  border-color: var(--red);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 22%, transparent);
}
.form-help {
  font-size: 12.5px;
  color: var(--muted);
  margin-top: 6px;
}

/* Honeypot field (hidden from real users — CSP-compliant via class). */
.honeypot {
  position: absolute;
  left: -9999px;
  top: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

/* Footer-Editor target-hint colors. */
.footer-hint-ok   { color: var(--green) !important; }
.footer-hint-ext  { color: var(--dim)   !important; }
.footer-hint-warn { color: var(--red-bright) !important; font-weight: 600; }

/* Hazy snippet output (copy-paste box) */
.hazy-snippet {
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px;
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 12.5px;
  white-space: pre-wrap;
  word-break: break-all;
  user-select: all;
  margin-top: 8px;
}

/* -- Two-column form grid (Footer-Editor, Edit-Form item boxes) ----------- */
/* Replaces the previous inline `style="grid-template-columns:1fr 1fr"`
   pattern that did not collapse on mobile. Use `.form-grid-2` on the
   wrapping div; on phones it falls back to a single column. */
.form-grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 12px;
}

/* Reusable item-box wrapper for repeated edit-form slots (features,
   images, faq, steps, stats, timeline). */
.edit-item-box {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px 16px;
  margin-bottom: 14px;
}

/* Header row above each edit-item-box: label on the left,
   move/delete buttons on the right. The buttons submit the surrounding
   form with an `op` field; the App layer interprets the op and
   permutes / removes the item before persisting. */
.edit-item-box .item-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px dashed var(--line-soft);
}
.edit-item-box .item-label {
  font-size: 12px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--muted);
}
.edit-item-box .item-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: var(--panel);
  color: var(--dim);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.btn-icon:hover {
  color: var(--ink);
  border-color: color-mix(in srgb, var(--red) 60%, var(--line));
  background: var(--panel-2);
}
.btn-icon:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}
.btn-icon.btn-icon-danger {
  color: color-mix(in srgb, var(--red-bright) 80%, var(--dim));
}
.btn-icon.btn-icon-danger:hover {
  color: var(--ink);
  background: color-mix(in srgb, var(--red) 18%, var(--panel-2));
  border-color: var(--red);
}
.btn-icon.btn-icon-placeholder {
  background: transparent;
  border-color: transparent;
  cursor: default;
}

/* Touch-Target-Minimum: WCAG-konforme 44 px tall für alle
   interaktiven Elemente im Backend. Buttons in der Section-Liste
   waren zuvor 5 px padding → praktisch nicht treffbar mit dem Finger. */
.section-list-item .sli-actions button {
  min-height: 36px;
  min-width: 36px;
  padding: 6px 12px;
}
/* Auf Touch-Geräten (coarse pointer) volle 44 px nach WCAG 2.5.8. */
@media (pointer: coarse) {
  .section-list-item .sli-actions button,
  .btn-icon {
    min-height: 44px;
    min-width: 44px;
  }
}

/* Destruktive Aktionen: bewusst NICHT der rote Primär-Gradient
   (der ist Marken-Rot für positive Aktionen), sondern Outline-Rot —
   klar als gefährlich erkennbar, ohne wie "Speichern" auszusehen. */
.btn-danger {
  background: transparent;
  color: var(--red-bright);
  border: 1px solid color-mix(in srgb, var(--red) 55%, transparent);
}
.btn-danger:hover {
  background: color-mix(in srgb, var(--red) 14%, transparent);
  border-color: var(--red-bright);
  color: var(--red-bright);
  box-shadow: none;
}

/* Drag-Reorder-Feedback: Statuszeile unter der Liste + gedimmte
   Liste während der Speicher-Request läuft. */
.reorder-status {
  min-height: 18px;
  margin: 4px 2px 0;
  font-size: 12.5px;
  color: var(--muted);
}
[data-reorder-list].reorder-saving { opacity: 0.65; }

/* Zeichenzähler unter limitierten Feldern. */
.char-counter {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  color: var(--muted);
  text-align: right;
}
.char-counter-warn { color: var(--red-bright); }

/* Markdown-Live-Vorschau: Toggle-Button + Pane unterhalb der
   Textarea. Die Pane nutzt die normalen .markdown-Styles, damit die
   Vorschau dem Frontend-Rendering entspricht. */
.md-preview-toggle {
  display: inline-block;
  margin-top: 8px;
  padding: 7px 14px;
  border-radius: 7px;
  font-size: 12.5px;
  cursor: pointer;
}
.md-preview-pane {
  margin-top: 10px;
  padding: 16px 18px;
  border: 1px dashed var(--line);
  border-radius: 9px;
  background: var(--panel-2);
}
.md-preview-pane:empty::after {
  content: "(noch keine Vorschau)";
  color: var(--muted);
  font-size: 13px;
}

/* Markdown-Referenz: aufklappbare Syntax-Hilfe neben Markdown-Feldern. */
.md-help { margin-top: 8px; }
.md-help summary {
  cursor: pointer;
  font-size: 12.5px;
  color: var(--muted);
}
.md-help summary:hover { color: var(--ink); }
.md-help-body {
  margin: 8px 0 0;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-2);
  font-size: 13px;
  color: var(--dim);
}
.md-help-body code {
  background: var(--bg-soft);
  padding: 1px 5px;
  border-radius: 4px;
}

/* Bild-Picker: <details> mit Radio-Kachel-Grid. Funktioniert ohne
   JS vollständig (Radios sind die Form-Controls); JS spiegelt nur
   die Auswahl in die Summary. */
.image-picker { margin: 0; }
.image-picker > summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg-soft);
  cursor: pointer;
  font-size: 13.5px;
  color: var(--ink);
}
.image-picker > summary:hover { border-color: color-mix(in srgb, var(--red) 50%, var(--line)); }
.image-picker-summary-thumb {
  width: 36px;
  height: 36px;
  object-fit: cover;
  border-radius: 5px;
  border: 1px solid var(--line);
}
/* Type filter bar (library + pickers). Hidden tiles keep their form
   state — filtering never unchecks a radio. */
.image-filter-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0 4px;
}
.image-filter-label {
  font-size: 11px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--muted);
  margin-right: 2px;
}
.image-filter-btn {
  min-height: 32px;
  padding: 4px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--dim);
  font-size: 12px;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.image-filter-btn:hover { color: var(--ink); border-color: var(--red); }
.image-filter-btn:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}
.image-filter-btn[aria-pressed="true"] {
  color: var(--ink);
  border-color: var(--red);
  font-weight: 700;
}
/* `!important`: this utility must beat later same-specificity rules
   like `.image-picker-tile { display: flex }` (defined further down),
   otherwise a filtered-out picker tile would stay visible. */
.image-filter-hidden { display: none !important; }
.image-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(108px, 1fr));
  gap: 8px;
  margin-top: 8px;
  padding: 10px;
  max-height: 320px;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-2);
}
.image-picker-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 4px;
  cursor: pointer;
}
.image-picker-tile input[type="radio"] {
  position: absolute;
  opacity: 0;
  inset: 0;
  margin: 0;
  cursor: pointer;
}
.image-picker-tile img,
.image-picker-tile .image-picker-none {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: 2px solid var(--line);
  border-radius: 7px;
  background: var(--bg-soft);
  color: var(--muted);
  font-size: 12px;
}
.image-picker-tile input:checked ~ img,
.image-picker-tile input:checked ~ .image-picker-none {
  border-color: var(--red-bright);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--red-bright) 35%, transparent);
}
.image-picker-tile input:focus-visible ~ img,
.image-picker-tile input:focus-visible ~ .image-picker-none {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}
.image-picker-name {
  font-size: 11px;
  color: var(--muted);
  word-break: break-all;
  text-align: center;
}

/* Suchfeld in der Admin-Nav. */
.admin-nav-search-form { display: inline-flex; }
.admin-nav-search {
  width: 150px;
  padding: 5px 10px;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 7px;
  color: var(--ink);
  font-size: 12.5px;
}
.admin-nav-search:focus {
  outline: none;
  border-color: var(--red);
}

/* Footer-Editor: Zeilen-Wrapper mit Move-Buttons rechts. */
.footer-row {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.footer-row .form-grid-2 { flex: 1; }
.footer-row .row-actions {
  display: inline-flex;
  gap: 6px;
  padding-top: 26px;
}

/* Versions-Liste: Inhalts-Auszug pro Snapshot. */
.version-excerpt {
  display: block;
  margin-top: 3px;
  font-size: 12.5px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 56ch;
}

/* -- Responsive ----------------------------------------------------------- */
/* Konsistente Breakpoints quer durch alle drei Apps:
     480 px  → Smartphone (klein)
     720 px  → Smartphone (groß) / Tablet (hochkant)
     960 px  → Tablet (querformat) / kleines Laptop
*/

@media (max-width: 960px) {
  :root {
    --section-pad-y: 72px;
  }
  /* Heading sizes are fluid (clamp) — no per-breakpoint font-size
     overrides needed below this point. */
}

@media (max-width: 720px) {
  :root {
    --section-pad-y: 56px;
    --section-pad-x: 18px;
  }
  .brand-word img { width: 250px; }
  .section-list-item { flex-wrap: wrap; }
  .section-list-item .sli-type { flex-basis: 100%; }
  .section-list-item .sli-title { flex-basis: 100%; padding: 4px 0; }
  .section-list-item .sli-actions { flex-wrap: wrap; gap: 8px; }

  /* Footer-Editor + Edit-Form 2-col Grids fallen auf 1-col zurück. */
  .form-grid-2 { grid-template-columns: 1fr; }

  /* Admin-Nav kompakter, falls die Seite auf mobile gescrollt wird. */
  .admin-head {
    flex-direction: column;
    align-items: flex-start;
  }
  .admin-head .admin-nav { width: 100%; row-gap: 6px; }
  .admin-head .admin-nav form { margin-left: auto; }
  /* Dropdown panels flow inline on narrow screens — an absolutely
     positioned popover would overlap the wrapped button rows. */
  .admin-nav-group { width: 100%; }
  .admin-nav-group > summary { width: 100%; justify-content: space-between; }
  .admin-nav-panel {
    position: static;
    width: 100%;
    min-width: 0;
    box-shadow: none;
    margin-top: 4px;
  }

  /* Sticky-Nav verzichtet auf sticky bei sehr engen Viewports — die
     Navigation würde auf < 720 px in mehrere Zeilen wrappen und einen
     erheblichen Teil der sichtbaren Höhe verschlucken. */
  .nav { position: static; }
  .nav-inner { gap: 4px 14px; }
}

@media (max-width: 480px) {
  .brand-word img { width: 220px; }
  .brand-sub { font-size: 10.5px; letter-spacing: 1.8px; }

  /* Lightbox-Schließbutton größer für Fingertouch. */
  .lightbox-close { padding: 6px 14px; font-size: 24px; }

  /* Form-Inputs full-bleed innerhalb der card. */
  .admin-card { padding: 18px 16px; }

  /* Bilder-Galerie noch kompakter (1-2 Karten pro Reihe). */
  .image-grid { grid-template-columns: 1fr 1fr; gap: 10px; }

  /* Stats brauchen mindestens 1-spaltig auf sehr engen Screens. */
  .stat-grid { grid-template-columns: 1fr; }

  /* Back-to-top auf schmalen Screens etwas näher an die Ecke setzen. */
  .back-to-top {
    right: 12px;
    bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  }
}

/* -- Touch-target safety: ensure all interactive elements have a
   minimum tappable area regardless of viewport. Applies to all
   media queries below this point. */
.btn, .btn-secondary {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.admin-head .admin-nav a {
  min-height: 28px;
  display: inline-flex;
  align-items: center;
}

/* -- Blog ------------------------------------------------------------------ */
/* Three views share these styles:
   - `.section-blog-list`   → public list at ?action=blog
   - `.section-blog-post`   → public single-post at ?action=blog&post=…
   - `.section-blog-teaser` → "latest N posts" section on the homepage */
.section-blog-list h1,
.section-blog-post .blog-post-title {
  margin-top: 0;
}
.blog-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 22px;
  margin-top: 28px;
}
.blog-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.blog-card:hover {
  border-color: color-mix(in srgb, var(--red) 60%, var(--line));
  transform: translateY(-2px);
}
.blog-card-link {
  display: block;
  color: inherit;
  text-decoration: none;
}
.blog-card-image {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--bg-soft);
  border-bottom: 1px solid var(--line-soft);
}
.blog-card-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}
/* Crop anchor overrides — applied via the admin-chosen
   `image_position` field on the blog post. Nine cells of a 3×3 grid
   mapping to a CSS `object-position` value. `pos-center` is the
   default and needs no rule. */
.blog-card-image.pos-top          img { object-position: center top; }
.blog-card-image.pos-bottom       img { object-position: center bottom; }
.blog-card-image.pos-left         img { object-position: left center; }
.blog-card-image.pos-right        img { object-position: right center; }
.blog-card-image.pos-top-left     img { object-position: left top; }
.blog-card-image.pos-top-right    img { object-position: right top; }
.blog-card-image.pos-bottom-left  img { object-position: left bottom; }
.blog-card-image.pos-bottom-right img { object-position: right bottom; }
.blog-card-body {
  padding: 18px 18px 22px;
}
.blog-card-date {
  font-size: 11px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}
.blog-card-title {
  font-size: 18px;
  line-height: 1.35;
  margin: 0 0 8px;
  color: var(--ink);
}
.blog-card-lede {
  font-size: 14px;
  color: var(--dim);
  margin: 0 0 12px;
  line-height: 1.55;
}
.blog-card-more {
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--red-bright);
}
.blog-card:hover .blog-card-more {
  color: var(--ink);
}

/* Blog list pagination — plain links, 44px touch targets. */
.pagination {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 8px;
  margin-top: 36px;
}
.pagination-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--panel);
  color: var(--dim);
  font-size: 14px;
  text-decoration: none;
  transition: color 0.15s ease, border-color 0.15s ease;
}
a.pagination-link:hover {
  color: var(--ink);
  border-color: var(--red);
}
a.pagination-link:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}
.pagination-current {
  color: var(--ink);
  border-color: var(--red);
  font-weight: 700;
}

/* Public single-post layout. */
.blog-post-back {
  font-size: 13px;
  margin: 0 0 18px;
}
.blog-post-back a {
  color: var(--muted);
  text-decoration: none;
}
.blog-post-back a:hover { color: var(--ink); }
.blog-post-date {
  font-size: 12px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 12px;
}
.blog-post-updated { color: var(--dim); }

/* "Stand: <Datum>" on legal / long-form standalone pages. */
.page-stand {
  margin: -4px 0 20px;
  font-size: 12px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--muted);
}

/* Related-posts block at the end of a blog post. */
.blog-related { margin: 44px 0 8px; }
.blog-related-title {
  font-size: 15px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 16px;
}
.blog-related-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}
.blog-related-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  text-decoration: none;
  color: var(--ink);
  transition: border-color 0.15s ease;
}
.blog-related-card:hover { border-color: var(--red); }
.blog-related-thumb { overflow: hidden; border-radius: 6px; }
.blog-related-thumb img { width: 100%; height: auto; display: block; }
.blog-related-heading { font-weight: 600; line-height: 1.3; }
.blog-related-lede {
  font-size: 13px;
  color: var(--muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Hover-revealed heading permalink on long-form pages + blog posts. */
.heading-anchor {
  margin-left: 8px;
  color: var(--muted);
  text-decoration: none;
  opacity: 0;
  transition: opacity 0.12s ease, color 0.12s ease;
}
h2:hover > .heading-anchor,
h3:hover > .heading-anchor,
h4:hover > .heading-anchor,
h5:hover > .heading-anchor,
h6:hover > .heading-anchor,
.heading-anchor:focus-visible { opacity: 1; }
.heading-anchor:hover { color: var(--red-bright); }
.heading-anchor.is-copied { opacity: 1; color: var(--red-bright); }
.blog-post-title {
  font-size: 32px;
  line-height: 1.2;
  margin: 0 0 12px;
}
.blog-post-lede {
  font-size: 17px;
  color: var(--dim);
  margin: 0 0 28px;
  line-height: 1.55;
}
/* Blog-Detail hero: spans the full text column width so it visually
   anchors to the body type below. Aspect-ratio gives a cinematic
   16:9 ratio with `max-height` as a safety brake to avoid a
   500 px tall banner on wide desktops. `object-fit: cover` keeps the
   focal centre regardless of the source's native aspect. The figure
   element resets the browser default margin so it lines up flush
   with the lede above it. */
.blog-post-hero {
  position: relative;
  margin: 0 0 32px;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: 420px;
  border: 1px solid var(--line-soft);
  border-radius: 6px;
  overflow: hidden;
  background: var(--bg-soft);
}
/* Discreet source/credit in the lower-right corner of the hero image. */
.blog-post-hero-source {
  position: absolute;
  right: 0;
  bottom: 0;
  margin: 0;
  max-width: 85%;
  padding: 4px 9px;
  font-size: 11.5px;
  line-height: 1.3;
  text-align: right;
  color: var(--ink-on-dark);
  background: linear-gradient(to top left, rgba(8, 9, 11, 0.8), rgba(8, 9, 11, 0.3));
  border-top-left-radius: 6px;
  pointer-events: none;
}
.blog-post-hero img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}
/* Crop anchor overrides — same 9-cell scheme as the card thumbnails. */
.blog-post-hero.pos-top          img { object-position: center top; }
.blog-post-hero.pos-bottom       img { object-position: center bottom; }
.blog-post-hero.pos-left         img { object-position: left center; }
.blog-post-hero.pos-right        img { object-position: right center; }
.blog-post-hero.pos-top-left     img { object-position: left top; }
.blog-post-hero.pos-top-right    img { object-position: right top; }
.blog-post-hero.pos-bottom-left  img { object-position: left bottom; }
.blog-post-hero.pos-bottom-right img { object-position: right bottom; }
.blog-post-body { font-size: 16px; }

/* Embedded [image] / [gallery] in any Markdown body (MediaRenderer) —
   blog posts, text, legal and page sections alike.
   Width, alignment and float are CSP-safe class PRESETS (no inline styles):
   width is a percentage of the text column (klein 25 / mittel 50 / groß 75 /
   voll 100), capped at the column width; the responsive srcset still delivers
   the right file per device. */
.embed-image            { margin: 24px 0; width: 100%; }
.embed-image .embed-zoom,
.embed-gallery-item .embed-zoom { display: block; cursor: zoom-in; }
.embed-image picture,
.embed-image img        { display: block; width: 100%; height: auto; border-radius: 10px; border: 1px solid var(--line); }
.embed-caption          { margin-top: 8px; font-size: 13px; color: var(--dim); text-align: center; }
/* Width presets (% of the content column). 100% = default (no class). */
.embed-image.embed-w-25 { width: 25%; }
.embed-image.embed-w-33 { width: 33.333%; }
.embed-image.embed-w-50 { width: 50%; }
.embed-image.embed-w-66 { width: 66.666%; }
.embed-image.embed-w-75 { width: 75%; }
/* Alignment within the column (block, no text-wrap). Default = left. */
.embed-image.embed-left   { margin-left: 0; margin-right: auto; }
.embed-image.embed-center { margin-left: auto; margin-right: auto; }
.embed-image.embed-right  { margin-left: auto; margin-right: 0; }
/* Text wrap (float=left|right). Unlike the alignment presets above, the
   text continues BESIDE the figure, so it needs an outer gap towards the
   text and a slightly raised top edge to sit on the first line. */
.embed-image.embed-float-left  { float: left;  margin: 6px 24px 16px 0; }
.embed-image.embed-float-right { float: right; margin: 6px 0 16px 24px; }
/* A float must never escape its own text body: a tall image at the end of a
   section would otherwise overlap whatever follows. Scoped with :has() so
   only bodies that actually wrap text get the clearfix — applying it to
   every .markdown would stop the last child's bottom margin from collapsing
   and shift spacing across the whole site. */
.markdown:has(.embed-float-left, .embed-float-right)::after {
  content: ""; display: table; clear: both;
}
.markdown hr { clear: both; }
/* Lead image: full column, cinematic crop — the standalone-page counterpart
   to a blog post's hero. */
.embed-image.embed-hero     { width: 100%; margin: 0 0 28px; }
.embed-image.embed-hero img { aspect-ratio: 16 / 9; object-fit: cover; }
.embed-gallery          { margin: 24px 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }
.embed-gallery.embed-gallery-cols-2 { grid-template-columns: repeat(2, 1fr); }
.embed-gallery.embed-gallery-cols-3 { grid-template-columns: repeat(3, 1fr); }
.embed-gallery.embed-gallery-cols-4 { grid-template-columns: repeat(4, 1fr); }
.embed-gallery-item     { margin: 0; }
.embed-gallery-item img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 10px; border: 1px solid var(--line); }
.embed-image .embed-zoom:hover img,
.embed-gallery-item .embed-zoom:hover img { box-shadow: var(--rt-glow); border-color: var(--red); }
/* A wrapped image gives up earlier than a merely aligned one: at 33% width
   a 700px viewport leaves under 400px of running text, which is too narrow
   to read comfortably. Below that the figure goes back into the flow. */
@media (max-width: 700px) {
  .embed-image.embed-float-left,
  .embed-image.embed-float-right { float: none; width: 100%; margin: 24px 0; }
}
/* On small screens a 25–75% image is too small to read → go full width. */
@media (max-width: 600px) {
  .embed-image[class*="embed-w-"]        { width: 100%; }
  .embed-gallery[class*="embed-gallery-cols-"] { grid-template-columns: repeat(2, 1fr); }
}

/* Prev/next navigation between published posts. */
.post-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 42px;
}
.post-nav-link {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--panel);
  text-decoration: none;
  transition: border-color 0.15s ease;
}
.post-nav-link:hover { border-color: var(--red); }
.post-nav-link:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}
.post-nav-older { text-align: right; grid-column: 2; }
.post-nav-newer { grid-column: 1; }
.post-nav-dir {
  font-size: 11px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted);
}
.post-nav-title { color: var(--ink); font-weight: 600; font-size: 14px; }
@media (max-width: 560px) {
  .post-nav { grid-template-columns: 1fr; }
  .post-nav-older { grid-column: 1; text-align: left; }
}

/* Teaser footer on the homepage section. The `.section p` reset above
   sets a default `margin: 0 0 16px` on every paragraph inside a section
   with higher specificity than a single class — qualify with `.section`
   here so the top margin actually takes effect. */
.section .blog-teaser-more {
  margin: 56px 0 0;
  text-align: center;
}

@media (max-width: 480px) {
  .blog-card-grid { gap: 14px; }
  .blog-post-title { font-size: 24px; }
  .blog-post-lede { font-size: 15px; }
  /* On narrow phones the 420 px cap would still produce a tall block
     because aspect-ratio falls back to 16:9 of the (small) width.
     Tighten the cap so the hero stays proportionate. */
  .blog-post-hero { max-height: 260px; }
}

/* -- Hierarchical nav + burger menu + reveal + drag-reorder -------------- */
/* The new <ul class="nav-list"> markup is styled to look identical to the
   pre-Phase-5 flat sticky bar on desktop. On narrow viewports the whole
   <nav> turns into a slide-in panel triggered by the burger checkbox. */

/* (Removed: .no-js .burger-button { display: none } — the checkbox/label
    pattern works fine without JS. Hiding the burger in no-js mode made
    the nav unreachable on narrow viewports.) */

/* Visually-hidden but still interactive. The legacy
   `left: -9999px` trick has been observed to break label-for-checkbox
   on some iOS Safari versions; the clip-path variant is the modern
   accessible-hide that iOS handles reliably. */
.burger-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.burger-button {
  display: none;
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 30;
  width: 46px;
  height: 46px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--panel) 92%, transparent);
  border: 1px solid var(--line);
  cursor: pointer;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 5px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.burger-button:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 3px;
}
.burger-bar {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--ink);
  border-radius: 2px;
  transition: transform 0.2s ease, opacity 0.15s ease;
}
.burger-toggle:checked ~ .burger-button .burger-bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.burger-toggle:checked ~ .burger-button .burger-bar:nth-child(2) {
  opacity: 0;
}
.burger-toggle:checked ~ .burger-button .burger-bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.nav-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  justify-content: center;
}
.nav-list .nav-item {
  position: relative;
}
.nav-list .nav-link,
.nav-list .nav-sub a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  padding: 4px 2px;
  border-bottom: 1px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.nav-list .nav-link:hover,
.nav-list .nav-sub a:hover {
  color: var(--ink);
  border-bottom-color: var(--red);
}
.nav-icon { display: inline-flex; width: 14px; height: 14px; }
.nav-icon-svg { width: 100%; height: 100%; }

/* Section-heading icon (public page): scales with the heading font and
   carries the brand-red accent. Mirrors the nav icon for the same key. */
.heading-icon {
  display: inline-flex;
  vertical-align: -0.12em;
  margin-right: 0.4em;
  color: var(--red);
}
.heading-icon-svg { width: 1em; height: 1em; }
.nav-chevron { font-size: 9px; margin-left: 2px; opacity: 0.7; }

/* Desktop submenu — appears below the parent on hover/focus. */
.nav-sub {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 180px;
  list-style: none;
  margin: 0;
  padding: 8px 0;
  background: color-mix(in srgb, var(--bg) 98%, transparent);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 12px 28px -10px rgba(0, 0, 0, 0.6);
  display: none;
  z-index: 11;
}
.nav-parent:hover .nav-sub,
.nav-parent:focus-within .nav-sub {
  display: block;
}
.nav-sub-item a {
  display: block;
  padding: 6px 16px;
  border-bottom: none;
}
.nav-sub-item a:hover {
  background: color-mix(in srgb, var(--red) 10%, transparent);
  border-bottom-color: transparent;
}

/* Mobile: burger button visible, nav becomes slide-in panel. */
@media (max-width: 760px) {
  .burger-button { display: inline-flex; }
  .nav-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(320px, 86vw);
    transform: translateX(105%);
    transition: transform 0.22s ease-out;
    z-index: 25;
    background: var(--bg);
    border-left: 1px solid var(--line);
    box-shadow: -8px 0 28px -8px rgba(0, 0, 0, 0.6);
    overflow-y: auto;
    margin: 0;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .nav-panel .nav-inner {
    padding: 72px 20px 24px;
  }
  .nav-panel .nav-list {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
  }
  .nav-panel .nav-link,
  .nav-panel .nav-sub a {
    padding: 12px 4px;
    font-size: 14px;
  }
  /* On mobile submenus expand inline, not as floating dropdown. */
  .nav-panel .nav-sub {
    position: static;
    display: block;
    border: none;
    box-shadow: none;
    background: transparent;
    padding: 0 0 8px 16px;
    min-width: 0;
  }
  .nav-panel .nav-sub a { padding: 8px 4px; }

  .burger-toggle:checked ~ .nav-panel {
    transform: translateX(0);
  }
  /* Body scroll-lock when the panel is open (JS adds this class). */
  body.nav-panel-open {
    overflow: hidden;
  }
  /* Backdrop dimming behind the open panel. */
  .burger-toggle:checked ~ .nav-panel::before {
    content: "";
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    z-index: -1;
    pointer-events: none;
  }
}

/* -- Reveal-on-Scroll ------------------------------------------------------ */
/* JS adds .to-reveal at boot, IntersectionObserver flips to
   .is-revealed when the section scrolls into view. Without JS the class
   is never added, so sections render at full opacity (the default). */
.to-reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.45s ease, transform 0.45s ease;
}
.is-revealed {
  opacity: 1;
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  .to-reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* -- View transitions (Chrome/Edge ≥ 111) --------------------------------- */
@view-transition { navigation: auto; }
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.2s;
}

/* -- Admin: drag-and-drop reorder ----------------------------------------- */
.section-list .sli-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  font-size: 16px;
  color: var(--dim);
  cursor: grab;
  user-select: none;
  margin-right: 4px;
  /* Prevent the browser from taking over the touch gesture (pan,
     zoom) when the user grabs the handle. Without this, iOS Safari
     scrolls the page instead of letting our touchmove handler
     reorder rows. */
  touch-action: none;
}
.section-list .sli-handle:active { cursor: grabbing; }
.no-js .section-list .sli-handle { display: none; }

.section-list-item.is-dragging {
  opacity: 0.4;
  outline: 2px dashed var(--red);
  outline-offset: -2px;
}

/* -- Cookie banner + analytics chart ------------------------------------- */

.cookie-banner {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: 16px;
  z-index: 22;
  padding: 12px 16px;
  background: color-mix(in srgb, var(--panel) 96%, transparent);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 10px 24px -10px rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.cookie-banner[hidden] { display: none; }
.cookie-banner-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}
.cookie-banner-text {
  margin: 0;
  font-size: 13px;
  color: var(--dim);
  flex: 1;
  min-width: 240px;
  line-height: 1.5;
}
.cookie-banner-dismiss { flex-shrink: 0; }

/* The cookie notice blocks the page until confirmed: a dimming overlay
   intercepts clicks (banner sits above it at z-index 22) and body scroll
   is locked. JS un-hides both; without JS neither appears. */
.cookie-overlay {
  position: fixed;
  inset: 0;
  z-index: 21;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.cookie-overlay[hidden] { display: none; }
body.cookie-locked { overflow: hidden; }

/* Markdown rendered inside the cookie notice — tame outer block spacing
   so it sits neatly in the banner. */
.cookie-banner-text.markdown > :first-child { margin-top: 0; }
.cookie-banner-text.markdown > :last-child { margin-bottom: 0; }
.cookie-banner-text.markdown p { margin: 6px 0; }
.cookie-banner-text.markdown ul,
.cookie-banner-text.markdown ol { margin: 6px 0; padding-left: 20px; }

/* Schedulable promo strip — top-of-page announcement, site-branded. */
.promo-banner {
  position: relative;
  z-index: 18;
  padding: 10px 16px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--red) 16%, var(--panel)) 0%,
    var(--panel) 70%);
  border-bottom: 1px solid color-mix(in srgb, var(--red) 40%, var(--line));
}
.promo-banner[hidden] { display: none; }
.promo-banner-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.promo-banner-dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--red) 70%, transparent);
  animation: promo-pulse 2.4s ease-out infinite;
}
.promo-banner-text {
  margin: 0;
  flex: 1;
  min-width: 220px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
}
.promo-banner-link {
  margin-left: 8px;
  white-space: nowrap;
  font-weight: 600;
  color: var(--red-bright);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.promo-banner-link:hover,
.promo-banner-link:focus-visible { border-bottom-color: currentColor; }
.promo-banner-dismiss {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  padding: 0;
  font-size: 20px;
  line-height: 1;
  color: var(--dim);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
}
.promo-banner-dismiss:hover,
.promo-banner-dismiss:focus-visible {
  color: var(--ink);
  border-color: var(--red);
}
@keyframes promo-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--red) 70%, transparent); }
  70%  { box-shadow: 0 0 0 7px color-mix(in srgb, var(--red) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--red) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .promo-banner-dot { animation: none; }
}
/* Markdown in the single-line promo strip: keep it on one line and
   degrade block elements (incl. headings) to inline emphasis so the
   thin strip never grows or breaks. */
.promo-banner-text.markdown p,
.promo-banner-text.markdown h1,
.promo-banner-text.markdown h2,
.promo-banner-text.markdown h3,
.promo-banner-text.markdown h4,
.promo-banner-text.markdown h5,
.promo-banner-text.markdown h6,
.promo-banner-text.markdown ul,
.promo-banner-text.markdown ol,
.promo-banner-text.markdown blockquote {
  display: inline;
  margin: 0;
  padding: 0;
  font-size: inherit;
  line-height: inherit;
}
.promo-banner-text.markdown strong,
.promo-banner-text.markdown h1,
.promo-banner-text.markdown h2,
.promo-banner-text.markdown h3,
.promo-banner-text.markdown h4,
.promo-banner-text.markdown h5,
.promo-banner-text.markdown h6 { font-weight: 700; }

/* Analytics histogram — CSS-only stacked bars. */
.analytics-chart {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(24px, 1fr);
  gap: 4px;
  align-items: end;
  padding: 12px 0 6px;
  height: 180px;
  border-bottom: 1px solid var(--line);
}
.analytics-bar {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  height: 100%;
  font-size: 10px;
  letter-spacing: 0.3px;
  color: var(--muted);
}
.analytics-bar-fill {
  display: block;
  width: 100%;
  max-width: 36px;
  background: var(--red);
  border-radius: 3px 3px 0 0;
  min-height: 2px;
}
.analytics-bar-count {
  position: absolute;
  bottom: 100%;
  margin-bottom: 2px;
  font-size: 10px;
  color: var(--ink);
}
.analytics-bar-label {
  margin-top: 4px;
  white-space: nowrap;
}

/* -- Video section: self-hosted player ------------------------------------ */
.video-figure {
  margin: 18px 0 0;
}
.video-player {
  display: block;
  width: 100%;
  /* Reserve a 16:9 box up front so the player doesn't reflow when the
     video metadata loads (CLS). Non-16:9 clips letterbox inside. */
  aspect-ratio: 16 / 9;
  max-height: 70vh;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #000;
}
.video-figure figcaption {
  padding: 8px 2px 0;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--muted);
}
.video-caption {
  margin-top: 12px;
  text-align: center;
  font-size: 12.5px;
}
/* Backend preview is smaller than the public player. */
.video-preview {
  max-height: 320px;
  margin-top: 8px;
}

/* Video gallery (2+ videos): responsive grid, mixed sources. */
.video-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 18px;
  margin-top: 18px;
}
.video-gallery-item { min-width: 0; }
.video-gallery .video-figure { margin: 0; }
.video-gallery .video-player { max-height: 360px; }
.video-gallery .yt-gate { margin-top: 0; }
.video-gallery .yt-gate-card { max-width: none; padding: 22px 18px; }

/* -- External-link interstitial modal ------------------------------------- */
.leave-modal {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.leave-modal[hidden] { display: none; }
.leave-modal-backdrop {
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.leave-modal-box {
  position: relative;
  width: min(440px, 100%);
  padding: 30px 28px 24px;
  background: linear-gradient(180deg, var(--panel), var(--panel-2));
  border: 1px solid color-mix(in srgb, var(--red) 45%, var(--line));
  border-radius: 16px;
  box-shadow: var(--rt-glow), 0 24px 60px -20px rgba(0, 0, 0, 0.7);
  text-align: center;
  animation: leave-pop 0.18s ease-out;
}
@keyframes leave-pop { from { opacity: 0; transform: translateY(8px) scale(0.97); } to { opacity: 1; transform: none; } }
.leave-modal-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; margin-bottom: 12px;
  color: var(--red-bright); border-radius: 50%;
  background: color-mix(in srgb, var(--red) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--red) 40%, transparent);
}
.leave-modal-mark svg { width: 26px; height: 26px; }
.leave-modal-title { margin: 0 0 8px; font-size: 20px; }
.leave-modal-desc { margin: 0 0 12px; font-size: 14.5px; color: var(--dim); line-height: 1.5; }
.leave-modal-host {
  margin: 0 auto 18px; max-width: 100%;
  padding: 8px 12px; border-radius: 8px;
  background: var(--bg-soft); border: 1px solid var(--line);
  font-size: 13px; color: var(--ink); word-break: break-all;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.leave-modal-timer {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  margin-bottom: 20px;
}
.leave-ring { position: relative; width: 44px; height: 44px; flex: none; }
.leave-ring svg { width: 44px; height: 44px; display: block; }
.leave-ring-track { fill: none; stroke: var(--line); stroke-width: 3; }
.leave-ring-progress {
  fill: none; stroke: var(--red); stroke-width: 3; stroke-linecap: round;
  stroke-dasharray: 1; stroke-dashoffset: 0;
}
.leave-ring-progress.run { animation: leave-ring 10s linear forwards; }
@keyframes leave-ring { from { stroke-dashoffset: 0; } to { stroke-dashoffset: 1; } }
.leave-ring-num {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 700; color: var(--ink);
}
.leave-modal-timer-text { font-size: 13px; color: var(--muted); }
.leave-modal-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.leave-modal-actions .btn { flex: 1 1 auto; min-width: 150px; }
body.leave-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .leave-modal-box { animation: none; }
  /* The ring conveys the live auto-timer, so keep its real 10s duration
     even though the global reduced-motion rule would otherwise freeze it. */
  .leave-ring-progress.run { animation: leave-ring 10s linear forwards !important; }
}

/* -- YouTube two-click privacy gate -------------------------------------- */
.section-video .yt-gate {
  margin-top: 18px;
}
.yt-gate-card {
  max-width: 560px;
  margin: 0 auto;
  text-align: center;
  padding: 32px 24px;
  background: color-mix(in srgb, var(--panel) 90%, transparent);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.yt-gate-icon {
  width: 96px;
  height: 72px;
  display: block;
  margin: 0 auto 12px;
}
/* Plate colour lives here, not as a presentation attribute on the <rect>:
   the marque follows the palette token like every other inline SVG. */
.yt-gate-icon rect { fill: var(--red); }
.yt-gate-title {
  margin: 0 0 8px;
  font-size: 18px;
  letter-spacing: 1px;
}
.yt-gate-note {
  margin: 0 0 18px;
  color: var(--dim);
  font-size: 13px;
  line-height: 1.5;
}
.yt-gate-button { margin: 6px 0; }
.yt-gate-fallback { margin-top: 14px; font-size: 13px; }

/* =========================================================================
 * Admin & form utility classes
 *
 * The CSP enforces `style-src 'self'`; templates use these classes instead
 * of inline `style="..."` attributes. Scoped to admin templates plus
 * page_password_gate.php (which is rendered under public CSP).
 * ========================================================================= */

/* Spacing — vertical rhythm in admin pages */
.admin-intro            { margin: 0 0 18px; }
.admin-intro-tight      { margin: 0 0 14px; }
.admin-intro-tighter    { margin: 0 0 10px; }
.admin-help-flush       { margin: 0 0 8px; }
.admin-block-flush      { margin: 0; }
.admin-stack-xs         { margin-top: 6px; }
.admin-stack-sm         { margin-top: 8px; }
.admin-stack-md         { margin-top: 12px; }
.admin-stack-lg         { margin-top: 14px; }
.admin-stack-xl         { margin-top: 18px; }
.admin-stack-neg        { margin-top: -6px; }
.admin-h3-stack         { margin: 24px 0 6px; }
.admin-h3-stack-first   { margin: 18px 0 6px; }
.admin-h3-stack-hazy    { margin-top: 26px; }
.admin-h3-stack-simple  { margin-top: 24px; }
.admin-h3-stack-loose   { margin-top: 28px; }
.admin-rule             { border: 0; border-top: 1px solid var(--line); margin: 26px 0; }
.admin-card-narrow      { max-width: 480px; margin: 24px auto; }
.btn-spaced-left        { margin-left: 8px; }
.form-row-flush         { margin-bottom: 0; }
.form-search            { margin: 0 0 18px; }
.form-advanced-mt       { margin: 18px 0; }
.form-advanced-row-mt   { margin-top: 12px; }
.form-help-pwd          { margin-top: 0; margin-bottom: 8px; }
.field-label-inline     { font-weight: normal; text-transform: none; letter-spacing: 0; color: var(--ink); }
.field-label-inline-stack { font-weight: normal; text-transform: none; letter-spacing: 0; color: var(--ink); margin-top: 8px; }
.field-label-block      { display: block; margin-top: 10px; }
.field-label-hidden     { position: absolute; left: -9999px; }
.input-wide             { width: 100%; }
.input-wide-clip        { width: 100%; max-width: 480px; }
.detail-summary         { cursor: pointer; }
.detail-summary-padded  { cursor: pointer; padding: 8px 0; }

/* Inline meta annotations — small uppercase labels next to titles */
.meta-tag               { font-size: 11px; letter-spacing: 1.4px; margin-left: 8px; }
.meta-tag-loose         { font-size: 12px; letter-spacing: 1.5px; }
.meta-tag-bare          { font-size: 11px; letter-spacing: 1.2px; }
.meta-tag-h2            { font-size: 12px; letter-spacing: 1.4px; }
.meta-h3-inline         { font-size: 12px; }
.meta-stack             { font-size: 13px; margin-top: 4px; }

/* Empty / callout / preview boxes */
.admin-empty            { text-align: center; padding: 32px 12px; }
.callout-list           { background: var(--bg-soft); border: 1px solid var(--line); border-radius: 8px; padding: 14px 22px; font-size: 13px; margin-top: 14px; }
.callout-list-bullets   { padding-left: 18px; margin: 0 0 8px; }
.callout-preview        { background: var(--bg-soft); border: 1px solid var(--line); border-radius: 8px; padding: 14px; }

/* page_images.php — library header + tile grid */
.library-header         { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.library-header > h2    { margin: 0; }
.library-header > form  { margin: 0; }
.image-grid-tiles       { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.image-tile             { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; background: var(--panel-2); }
.image-tile-thumb       { display: block; width: 100%; aspect-ratio: 4/3; object-fit: cover; }
.image-tile-meta        { padding: 8px 10px; font-family: ui-monospace, Consolas, monospace; font-size: 11.5px; }
.image-tile-usage       { margin-top: 6px; color: var(--dim); }
.image-tile-usage a     { color: var(--dim); }
.image-tile-delete-form { margin-top: 6px; }
.image-tile-delete-btn  { background: transparent; border: 0; cursor: pointer; padding: 0; font-size: 11.5px; color: var(--muted); }
.image-tile-delete-btn.in-use { color: var(--red-bright); }

/* page_images.php — library sort bar (JS-free GET links) */
.image-sort-bar   { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }
.image-sort-label { font-size: 11px; letter-spacing: 1.2px; text-transform: uppercase; color: var(--muted); margin-right: 2px; }
.image-sort-link  { min-height: 32px; display: inline-flex; align-items: center; padding: 4px 12px;
                    border: 1px solid var(--line); border-radius: 999px; background: var(--panel); color: var(--dim);
                    font-size: 12px; text-decoration: none; transition: color 0.15s ease, border-color 0.15s ease; }
.image-sort-link:hover         { color: var(--ink); border-color: var(--red); }
.image-sort-link:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
.image-sort-link.active        { color: var(--ink); border-color: var(--red); font-weight: 700; }
.cleanup-actions               { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.cleanup-actions > form        { margin: 0; }

/* Contact inquiries backend (page_contact_admin / page_contact_view) */
.contact-filter                { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 14px; }
.contact-filter-link           { min-height: 32px; display: inline-flex; align-items: center; padding: 4px 12px;
                                 border: 1px solid var(--line); border-radius: 999px; background: var(--panel);
                                 color: var(--dim); font-size: 12px; text-decoration: none;
                                 transition: color 0.15s ease, border-color 0.15s ease; }
.contact-filter-link:hover     { color: var(--ink); border-color: var(--red); }
.contact-filter-link.active    { color: var(--ink); border-color: var(--red); font-weight: 700; }
.contact-list                  { list-style: none; margin: 0; padding: 0; }
.contact-item                  { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
                                 padding: 10px 0; border-bottom: 1px solid var(--line); }
.contact-prio                  { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto; background: var(--muted); }
.contact-prio-green            { background: #39b54a; }
.contact-prio-yellow           { background: #e6b800; }
.contact-prio-red              { background: var(--red-bright); }
.contact-item-id               { font-family: ui-monospace, Consolas, monospace; font-weight: 700; text-decoration: none; }
.contact-item-when             { font-size: 12px; }
.contact-item-tags             { margin-left: auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.contact-detail-row            { margin-bottom: 12px; }
.contact-detail dt             { font-weight: 700; color: var(--dim); margin-bottom: 2px; }
.contact-detail dd             { margin: 0; }
.contact-message               { white-space: pre-wrap; word-break: break-word; }

/* Public contact form section */
.section-contact .contact-inner { max-width: 720px; }
.contact-intro, .contact-outro { margin-bottom: 16px; }
.contact-card                  { border: 1px solid var(--line); border-radius: 10px; background: var(--panel);
                                 padding: 20px; margin: 18px 0; }
.contact-step-note             { color: var(--dim); margin: 0 0 14px; }
.contact-phone-cta             { color: var(--dim); margin: 0 0 18px; font-size: 14px; }
.contact-phone-link            { color: var(--red-bright); font-weight: 700; text-decoration: none; }
.contact-phone-link:hover      { text-decoration: underline; }
.contact-error                 { color: var(--red-bright); border: 1px solid var(--red); border-radius: 8px;
                                 padding: 10px 12px; margin: 0 0 14px;
                                 background: color-mix(in srgb, var(--red) 10%, transparent); }
.contact-ref                   { margin-top: 12px; }

/* _media_insert.php — insert [image]/[gallery] tokens into a body */
.media-insert > .image-picker  { margin-top: 8px; }
.media-insert-tile             { appearance: none; border: 0; background: transparent; padding: 0; font: inherit; color: inherit; cursor: pointer; }
.media-insert-tile img         { transition: border-color 0.15s ease, box-shadow 0.15s ease; }
.media-insert-tile:hover img   { border-color: var(--red-bright); }
.media-insert-tile:focus-visible { outline: none; }
.media-insert-tile:focus-visible img { outline: 2px solid var(--red); outline-offset: 2px; }
/* The gallery picker uses checkboxes; the base tile styles only radios. */
.image-picker-tile input[type="checkbox"] { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.media-gallery-insert          { margin-top: 10px; }
.media-opts                    { display: flex; flex-wrap: wrap; gap: 12px; margin: 8px 0 4px; }
.media-opt                     { display: flex; flex-direction: column; gap: 3px; font-size: 12px; color: var(--dim); }
.media-opt select              { min-width: 150px; }

/* _edit_head.php — icon picker cluster */
.icon-picker            { display: flex; align-items: center; gap: 12px; }
.icon-picker > select   { flex: 1; }
.icon-swatch            { display: inline-flex; width: 28px; height: 28px; color: var(--red, #e0202e); }

/* page_password_gate.php — public password gate (public CSP) */
.gate-frame             { max-width: 520px; text-align: center; }
.gate-icon-svg          { width: 56px; height: 56px; margin: 8px auto 20px; color: var(--red, #e0202e); }
.gate-alert             { margin: 14px auto; max-width: 380px; }
.gate-form              { margin: 8px auto 0; max-width: 380px; }
.gate-form-input        { margin-bottom: 12px; }
.gate-footnote          { margin-top: 24px; font-size: 13px; }

/* Analytics bar chart — bucketed heights in 5% steps. */
.analytics-bar-fill              { height: 2%; }
.analytics-bar-fill.bar-h-5      { height: 5%; }
.analytics-bar-fill.bar-h-10     { height: 10%; }
.analytics-bar-fill.bar-h-15     { height: 15%; }
.analytics-bar-fill.bar-h-20     { height: 20%; }
.analytics-bar-fill.bar-h-25     { height: 25%; }
.analytics-bar-fill.bar-h-30     { height: 30%; }
.analytics-bar-fill.bar-h-35     { height: 35%; }
.analytics-bar-fill.bar-h-40     { height: 40%; }
.analytics-bar-fill.bar-h-45     { height: 45%; }
.analytics-bar-fill.bar-h-50     { height: 50%; }
.analytics-bar-fill.bar-h-55     { height: 55%; }
.analytics-bar-fill.bar-h-60     { height: 60%; }
.analytics-bar-fill.bar-h-65     { height: 65%; }
.analytics-bar-fill.bar-h-70     { height: 70%; }
.analytics-bar-fill.bar-h-75     { height: 75%; }
.analytics-bar-fill.bar-h-80     { height: 80%; }
.analytics-bar-fill.bar-h-85     { height: 85%; }
.analytics-bar-fill.bar-h-90     { height: 90%; }
.analytics-bar-fill.bar-h-95     { height: 95%; }
.analytics-bar-fill.bar-h-100    { height: 100%; }

/* -- Protected content (Impressum, Datenschutz, …) ----------------------- */
.section-protected .protected-intro { margin-bottom: 28px; }
.section-protected .protected-outro { margin-top: 28px; }

.protected-list {
  margin: 24px 0 0;
  padding: 0;
  border-top: 1px solid var(--line);
}
.protected-row {
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: 16px 28px;
  padding: 18px 0;
  border-bottom: 1px solid var(--line);
  /* Label sits at the TOP of its cell — it's the heading for the
     (possibly multi-line) content on the right. */
  align-items: start;
}
.protected-label {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 0.82rem;
  line-height: 1.4;
}
.protected-label-icon { display: inline-flex; flex: none; color: var(--red); }
.protected-label-svg { width: 1.4rem; height: 1.4rem; }
.protected-value { margin: 0; color: var(--ink); }
.protected-text > :first-child { margin-top: 0; }
.protected-text > :last-child { margin-bottom: 0; }

@media (max-width: 640px) {
  .protected-row { grid-template-columns: 1fr; gap: 6px; padding: 14px 0; }
}

/* Locked decoy: blurred, not selectable, not draggable. The real content
   is never in the DOM in this state — this is purely a placeholder. */
.protected-locked {
  -webkit-user-select: none;
  user-select: none;
  pointer-events: none;
}
.protected-decoy {
  display: inline-block;
  color: var(--muted);
  filter: blur(5px);
  letter-spacing: 0.12em;
  line-height: 1.7;
  opacity: 0.65;
}

/* Image-rendered block: a same-origin raster image (not text). */
.protected-img {
  display: block;
  max-width: 100%;
  height: auto;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}

.protected-empty { margin: 0; }

.protected-gate {
  margin: 24px 0;
  padding: 22px 24px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--red);
  border-radius: 10px;
}
.protected-gate-lede { margin-top: 0; color: var(--muted); }
.protected-qform { margin-top: 8px; }
.protected-qform .form-row { margin-bottom: 14px; }
.protected-error {
  margin: 0 0 14px;
  padding: 10px 14px;
  background: color-mix(in srgb, var(--red) 10%, transparent);
  border: 1px solid var(--red);
  border-radius: 8px;
  color: var(--ink);
}

/* -- Print ----------------------------------------------------------------
   Clean, ink-saving output — primarily for the legal pages (Impressum,
   Datenschutz). Hides chrome + decoration, prints link targets. */
@media print {
  /* The question gate + blurred decoy are never useful on paper. */
  .protected-gate, .protected-locked { display: none !important; }
  body { background: #fff; color: #000; }
  .nav, .burger-toggle, .burger-button, .back-to-top, .cookie-banner,
  .cookie-overlay, .promo-banner, .scroll-fade,
  .skip-link, .bg-anim, .yt-gate, .video-player, .heading-icon,
  .lightbox { display: none !important; }
  .section { padding: 10px 0; border: 0 !important; }
  .section + .section { border-top: 0 !important; }
  .section-inner { max-width: none; }
  h1, h2, h3, h4, p, li, .lede, .markdown { color: #000 !important; }
  a { color: #000; text-decoration: underline; }
  /* Reveal external link targets inline so a printout stays usable. */
  .markdown a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.85em;
    color: #444;
    word-break: break-all;
  }
  img, figure, .image-grid figure { break-inside: avoid; max-width: 100% !important; }
  /* A wrapped image cannot survive pagination — a float that crosses a page
     boundary tears the paragraph apart. In print it rejoins the flow. */
  .embed-image.embed-float-left,
  .embed-image.embed-float-right { float: none !important; width: 100% !important; margin: 12px 0 !important; }
}

/* Split-backup download row: several one-button forms side by side.
   Inline styles are impossible under the strict CSP, so this is the
   utility class the backup page uses. */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
}

.inline-form {
  display: inline;
  margin: 0;
}

/* ===========================================================================
   Logo laser-beam
   A thin red beam streams in from the left edge of the viewport and lands
   on the logo's bullseye. Pure CSS, GPU-cheap, respects reduced-motion.

   Geometry — measured on THIS project's artwork, not inherited:
   The beam is anchored to the `.site-header` (relative), whose 50% is the
   logo's horizontal centre: the header pads 24px on both sides, so its
   padding box and its centred content share a centre line.

   `public/assets/swod-shot-logo@2x.png` is 600x260. The bullseye's red
   core runs x 251..271 and y 88..108; the two innermost black rings sit
   symmetrically around the same point (x 241..249 / 272..280 and
   y 78..87 / 109..118). Centre of the target ring: 260.5 / 98, i.e.
   43.42 % / 37.69 % of the logo box.

   From that, per rendered logo width W (`.brand-word img`), with the box
   height H = W * 130/300 and the header's 36px padding-top:

     horizontal offset left of centre = (50 % - 43.42 %) * W = 0.0658 * W
     vertical centre of the ring      = 36px + 0.3769 * H

     W = 300px (default)      ->  offset 19.8px -> 20px, top 36 + 49.0 = 85px
     W = 250px (max-width 720) ->  offset 16.5px -> 16px, top 36 + 40.8 = 77px
     W = 220px (max-width 480) ->  offset 14.5px -> 14px, top 36 + 35.9 = 72px

   The template this was taken from computes `top` as the logo's vertical
   MIDDLE (36 + 65 = 101px). That is ~16px below the target ring, because
   the ring sits at 37.7 % of the box height, not at 50 % — hence the
   re-derivation above. The horizontal offset differs for the same reason
   (12 % of the width there against the measured 6.6 % here).
   =========================================================================== */
.site-header {
  position: relative;
  isolation: isolate;
}

/* Beam: thin gradient line from the viewport edge to the bullseye.
   The start anchor has to sit outside the window at EVERY width, otherwise
   the beam would visibly begin somewhere in the page. `.shell-page` caps
   the header at 1180px, so on a wide window its left edge already lies
   (vw - 1180px)/2 inside the window; a -50vw anchor lands at
   (vw - 1180px)/2 - vw/2 = -590px — a constant overshoot, independent of
   the window width. Below 1180px the header spans the full width and the
   anchor is -vw/2. Off-screen in both regimes, and the gradient's fade-in
   zone still covers the visible left half. */
.site-header::before {
  content: "";
  position: absolute;
  top: 85px;
  left: -50vw;
  right: calc(50% - 20px);            /* end at the bullseye */
  height: 2px;
  background: linear-gradient(
    to right,
    rgb(var(--laser) / 0)    0%,
    rgb(var(--laser) / 0.04) 18%,
    rgb(var(--laser) / 0.22) 45%,
    rgb(var(--laser) / 0.55) 72%,
    rgb(var(--laser-bright) / 1)   100%
  );
  filter: drop-shadow(0 0 6px rgb(var(--laser-bright) / 0.65));
  z-index: 0;
  pointer-events: none;
  animation: laser-pulse 2.8s ease-in-out infinite;
  /* The beam sits BEHIND the logo on the z-axis; the brand-home is
     stacked above it via position:relative + z-index:1. */
}

/* Impact glow at the bullseye. Unlike the beam this one sits ABOVE the
   logo (z-index 2 against the brand's 1): the target ring is painted
   opaquely in the artwork — black rings, white gaps, red core, no alpha
   anywhere inside it — so a glow behind the logo is covered completely and
   the beam would simply vanish into the wordmark. Only the 14px point is
   lifted; the beam itself stays behind, otherwise it would read as cutting
   through the letters instead of landing on them. */
.site-header::after {
  content: "";
  position: absolute;
  top: 85px;
  left: calc(50% - 20px);
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgb(var(--laser-core) / 1)   0%,
    rgb(var(--laser-bright) / 0.9) 30%,
    rgb(var(--laser) / 0)   70%
  );
  transform: translate(-50%, -50%);
  z-index: 2;
  pointer-events: none;
  filter: drop-shadow(0 0 10px rgb(var(--laser-bright) / 0.7));
  animation: laser-impact 2.8s ease-in-out infinite;
}

/* Logo above the beam, below the impact point. The sticky `.nav` carries
   z-index 10 and is a later sibling, so it keeps winning over this whole
   stacking context. */
.brand-home { position: relative; z-index: 1; }

/* Pulse: wider opacity range (0.55 <-> 1.0) with a brief peak, plus a
   sympathetic intensity bump on the drop-shadow so the bloom actually
   reads on the page — still smooth, not strobe-y. */
@keyframes laser-pulse {
  0%, 100% {
    opacity: 0.55;
    filter: drop-shadow(0 0 4px rgb(var(--laser-bright) / 0.45));
  }
  40% {
    opacity: 1;
    filter: drop-shadow(0 0 9px rgb(var(--laser-bright) / 0.85));
  }
  60% {
    opacity: 1;
    filter: drop-shadow(0 0 9px rgb(var(--laser-bright) / 0.85));
  }
}
@keyframes laser-impact {
  0%, 100% {
    transform: translate(-50%, -50%) scale(0.75);
    filter: drop-shadow(0 0 6px rgb(var(--laser-bright) / 0.5));
    opacity: 0.85;
  }
  40%, 60% {
    transform: translate(-50%, -50%) scale(1.25);
    filter: drop-shadow(0 0 18px rgb(var(--laser-bright) / 1));
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .site-header::before, .site-header::after { animation: none; }
}

/* On narrower viewports the logo shrinks; adjust the bullseye offset. */
@media (max-width: 720px) {
  .site-header::before {
    top: 77px;
    right: calc(50% - 16px);
    height: 1.5px;
  }
  .site-header::after {
    top: 77px;
    left: calc(50% - 16px);
    width: 11px;
    height: 11px;
  }
}
@media (max-width: 480px) {
  .site-header::before {
    top: 72px;
    right: calc(50% - 14px);
  }
  .site-header::after {
    top: 72px;
    left: calc(50% - 14px);
    width: 10px;
    height: 10px;
  }
}

/* ===========================================================================
   Audio section
   A stack of compact player rows. The height is the whole point of the
   type: a section with two tracks plus surrounding text must read like a
   short text section, not like an embedded video. Everything below is
   sized from --audio-track-height so that budget stays visible in one
   place instead of being spread over a dozen paddings.

   The progress bar uses --red, deliberately NOT the --laser* properties:
   the operator-configurable laser colour applies to the logo beam only
   (see the "Logo laser-beam" block). Tying the player to it would let a
   colour chosen for the header silently repaint content further down.
   =========================================================================== */
.section-audio .audio-intro { margin-bottom: var(--space-4); }
.section-audio .audio-outro { margin-top: var(--space-4); }

.audio-list { display: flex; flex-direction: column; gap: var(--space-2); }

.audio-track {
  --audio-track-height: 64px;
  margin: 0;
  padding: var(--space-2) var(--space-3);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.audio-title {
  font-size: var(--fs-sm, 14.5px);
  font-weight: 600;
  color: var(--ink);
  /* One line: a long title must not push the row past its budget. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Native player: the no-JS fallback, shown below the caption. Plain, but
   fully usable — and with the caption above it the visitor can tell the
   rows apart, which is the whole reason the caption sits outside the
   shell. */
.audio-track > audio {
  display: block;
  width: 100%;
  margin-top: var(--space-2);
}
.audio-track > audio[hidden] { display: none; }

.audio-shell[hidden] { display: none; }

/* Once the player has been upgraded the row collapses into the compact
   two-line grid: button on the left spanning both lines, caption above the
   bar. `display: contents` dissolves the shell so its children join this
   grid — the shell exists only to be hidden as a unit beforehand.

   Keyed on `is-enhanced`, which initAudioPlayers() sets as its LAST step,
   and not on `has-js`. `has-js` only says that site.js began parsing; it
   is set before boot() runs and says nothing about whether this particular
   upgrade succeeded. Keying the layout on it meant the styled row appeared
   even when the upgrade never happened — a control surface that answers no
   clicks, with the native player pushed out of the way. The whole point of
   the arrangement is that a failure degrades to working controls. */
.audio-track.is-enhanced {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 2px var(--space-3);
  min-height: var(--audio-track-height);
}
.audio-track.is-enhanced .audio-shell { display: contents; }
.audio-track.is-enhanced .audio-title { grid-column: 2; grid-row: 1; align-self: end; }
.audio-track.is-enhanced .audio-toggle { grid-column: 1; grid-row: 1 / 3; }
.audio-track.is-enhanced .audio-controls { grid-column: 2; grid-row: 2; align-self: start; }
/* Belt and braces: `hidden` must beat every layout rule regardless of
   source order. Same specificity would let position alone decide. */
.audio-track.is-enhanced .audio-shell[hidden] { display: none; }

.audio-toggle {
  flex: 0 0 auto;
  width: 36px; height: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--ink);
  cursor: pointer;
}
.audio-toggle:hover { border-color: color-mix(in srgb, var(--red) 45%, var(--line)); }
.audio-toggle:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

/* Play/pause glyph drawn in CSS — no icon font, no inline SVG per row.
   The triangle is a border trick; the pause bars are a box plus its own
   left border, so a single element covers both states. */
.audio-icon {
  display: block;
  width: 0; height: 0;
  margin-left: 3px;                       /* optical centring of the triangle */
  border-style: solid;
  border-width: 7px 0 7px 11px;
  border-color: transparent transparent transparent currentColor;
}
.audio-toggle[aria-pressed="true"] .audio-icon {
  width: 4px; height: 14px;
  margin-left: 0;
  border-width: 0 0 0 4px;
  border-color: currentColor;
  box-shadow: 8px 0 0 0 currentColor;     /* the second bar */
  background: none;
}

.audio-controls { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }

.audio-seek {
  flex: 1 1 auto; min-width: 0;
  height: 4px;
  appearance: none; -webkit-appearance: none;
  background: var(--line);
  border-radius: 999px;
  cursor: pointer;
}
/* The two thumb pseudo-elements cannot be combined into one rule: a
   selector list is dropped entirely if any part of it is unknown to the
   browser, so Firefox and Chrome need separate blocks. */
.audio-seek::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none;
  width: 12px; height: 12px;
  background: var(--red-bright);
  border: none; border-radius: 50%;
  cursor: pointer;
}
.audio-seek::-moz-range-thumb {
  width: 12px; height: 12px;
  background: var(--red-bright);
  border: none; border-radius: 50%;
  cursor: pointer;
}
.audio-seek::-moz-range-progress { height: 4px; background: var(--red); border-radius: 999px; }
.audio-seek:focus-visible { outline: 2px solid var(--red); outline-offset: 4px; }

.audio-time {
  flex: 0 0 auto;
  font-size: var(--fs-xs, 12.5px);
  color: var(--muted);
  font-variant-numeric: tabular-nums;      /* the row must not twitch per second */
  white-space: nowrap;
}

/* Narrow viewports: the time drops below the bar rather than squeezing it
   to nothing. The row grows by one line, which is the lesser evil. */
@media (max-width: 480px) {
  .audio-track { --audio-track-height: 78px; }
  .audio-controls { flex-wrap: wrap; gap: 4px var(--space-2); }
  .audio-seek { flex-basis: 100%; }
}

/* Backend: preview of an already-stored track in the edit form. */
.audio-preview { display: block; width: 100%; max-width: 420px; margin-top: var(--space-2); }
