/* base.css — technisches Grundgerüst für alle /redesign-Vorschauen.
   Themes überschreiben NUR die :root-Variablen + eigene Sektions-Styles. */
:root {
  --bg: #ffffff;
  --bg-alt: #f4f4f5;
  --text: #18181b;
  --text-dim: #52525b;
  --accent: #2563eb;
  --accent-contrast: #ffffff;
  --display: system-ui, 'Segoe UI', Roboto, sans-serif;
  --body: system-ui, 'Segoe UI', Roboto, sans-serif;
  --radius: 1rem;
  --pad: clamp(1rem, 4vw, 2.5rem);
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  font-family: var(--body);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  overflow-x: hidden;
}
img { max-width: 100%; height: auto; display: block; }

/* ---------- A11y ---------- */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--accent); color: var(--accent-contrast);
  padding: .75rem 1.25rem; font-weight: 700;
}
.skip-link:focus { left: 0; }
a:focus-visible, button:focus-visible {
  outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 2px;
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---------- Layout ---------- */
.container { max-width: 72rem; margin-inline: auto; padding-inline: var(--pad); }
.section { padding-block: clamp(3.5rem, 8vw, 6.5rem); }
.section--alt { background: var(--bg-alt); }
.section-kicker {
  font-weight: 800; letter-spacing: .2em; text-transform: uppercase;
  font-size: .8rem; margin-bottom: .5rem; color: var(--accent);
}
.section-title { font-family: var(--display); font-size: clamp(2.2rem, 6vw, 4rem); line-height: 1.05; margin-bottom: 1rem; }

.grid { display: grid; gap: 1.5rem; }
@media (min-width: 700px) {
  .grid--2 { grid-template-columns: 1fr 1fr; }
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
}

/* ---------- Header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--bg) 85%, transparent);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
}
.header-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding-block: .6rem; flex-wrap: wrap;
}
.logo {
  font-family: var(--display); font-size: 1.5rem; color: var(--text);
  text-decoration: none; display: inline-flex; align-items: center;
  gap: .5rem; min-height: 44px; font-weight: 800;
}
.site-nav ul { display: flex; list-style: none; gap: .25rem; flex-wrap: wrap; }
.site-nav a {
  display: inline-flex; align-items: center; min-height: 44px;
  padding: .35rem .8rem; color: var(--text-dim); text-decoration: none;
  font-weight: 600; font-size: .95rem; border-radius: 999px;
  transition: color .2s, background .2s;
}
.site-nav a:hover { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); }
.site-nav a.nav-cta { background: var(--accent); color: var(--accent-contrast); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: .8rem 2rem; border-radius: 999px;
  font-weight: 800; font-size: 1.05rem; text-decoration: none;
  transition: transform .15s, box-shadow .15s, background .2s;
}
.btn--primary { background: var(--accent); color: var(--accent-contrast); }
.btn--primary:hover { transform: translateY(-2px); }
.btn--ghost { border: 2px solid color-mix(in srgb, var(--text) 40%, transparent); color: var(--text); }
.btn--ghost:hover { border-color: var(--text); }

/* ---------- Bild-Hilfen ---------- */
.img-cover { width: 100%; height: 100%; object-fit: cover; }
.img-card { border-radius: var(--radius); overflow: hidden; }

/* ---------- Footer ---------- */
.site-footer {
  background: var(--bg-alt);
  border-top: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
  padding-block: 3rem 5.5rem;
}
.footer-grid { display: grid; gap: 2rem; grid-template-columns: 1fr; }
@media (min-width: 700px) { .footer-grid { grid-template-columns: repeat(3, 1fr); } }
.site-footer h2 { font-size: 1.05rem; margin-bottom: .6rem; text-transform: uppercase; letter-spacing: .1em; }
.site-footer p, .site-footer li { color: var(--text-dim); font-size: .95rem; }
.site-footer ul { list-style: none; }
.site-footer a { color: var(--text); text-underline-offset: 3px; }
.footer-legal {
  margin-top: 2.5rem; padding-top: 1.5rem;
  border-top: 1px solid color-mix(in srgb, var(--text) 10%, transparent);
  font-size: .85rem; color: var(--text-dim);
  display: flex; gap: 1.5rem; flex-wrap: wrap;
}

/* ---------- Entwurfs-Badge (Pflicht) ---------- */
.draft-badge {
  position: fixed; right: .9rem; bottom: .9rem; z-index: 60;
  background: color-mix(in srgb, var(--text) 92%, transparent);
  color: var(--bg); border-radius: 999px; padding: .45rem 1rem;
  font-size: .78rem; font-weight: 600; pointer-events: none;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}

/* ---------- Scroll-Reveal ----------
   Sichtbar per Default (progressive enhancement): erst wenn base.js läuft,
   setzt es .js-reveal und blendet aus. Bleibt JS aus, verschwindet nichts. */
.reveal.js-reveal { opacity: 0; transform: translateY(24px); transition: opacity .6s ease, transform .6s ease; }
.reveal.js-reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .reveal.js-reveal { opacity: 1; transform: none; transition: none; } }

/* ---------- Scroll-gekoppeltes Text-Aufhellen ----------
   Für kurze Statement-Absätze (nicht für lange Fließtexte). Startet als
   normaler, voll sichtbarer Text (progressive enhancement) — erst base.js
   zerlegt ihn in Wörter und dimmt sie, danach hellen sie proportional zum
   Scrollfortschritt durch den Block auf. .sh-ready markiert "JS ist bereit",
   ohne das bleibt der Absatz einfach normaler Text. */
.scroll-highlight.sh-ready .sh-w {
  color: color-mix(in srgb, var(--text) 25%, transparent);
  transition: color .15s linear;
}
.scroll-highlight.sh-ready .sh-w.is-lit { color: var(--text); }
@media (prefers-reduced-motion: reduce) {
  .scroll-highlight.sh-ready .sh-w { color: var(--text); transition: none; }
}

/* ---------- Swipebare Abschnitte (mobil) ----------
   Handy: horizontales Scroll-Snap-Karussell, kein JS nötig für die Bedienung.
   Aktive Karte wird zentriert und ist dabei bündig mit dem normalen Seitenrand
   (--swipe-peek = derselbe Rand wie .container/--pad) statt an einem eigenen
   Prozent-Abstand zu kleben. Springt pro Wisch genau eine Karte weiter:
   scroll-snap-stop:always verhindert, dass ein schneller Wisch mehrere Karten
   überspringt und "weiterrotiert". ::before/::after sind so breit, dass die
   erste/letzte Karte trotzdem bündig zentriert einrasten kann.
   Ab 720px: normales Grid, keine Karten mehr abgeschnitten. Für Cards, Referenzen,
   Zitate, Logo-/Badge-Reihen – überall, wo auf dem Handy mehr "Bewegung" gut tut. */
.swipe {
  --swipe-peek: var(--pad);
  display: flex; gap: 1rem; overflow-x: auto; scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch; padding-block: .25rem;
  scrollbar-width: none; margin-inline: calc(var(--swipe-peek) * -1);
}
.swipe::-webkit-scrollbar { display: none; }
.swipe > * {
  scroll-snap-align: center;
  scroll-snap-stop: always;
  flex: 0 0 calc(100% - 2 * var(--swipe-peek));
  max-width: 22rem;
}
.swipe::before,
.swipe::after { content: ""; flex: 0 0 calc(var(--swipe-peek) - 1rem); }
.swipe::before { scroll-snap-align: start; }
@media (min-width: 720px) {
  .swipe {
    overflow-x: visible; display: grid;
    grid-template-columns: repeat(var(--swipe-cols, 3), 1fr);
    gap: 1.5rem; margin-inline: 0; padding-inline: 0;
  }
  .swipe > * { flex: initial; max-width: none; scroll-snap-align: none; scroll-snap-stop: normal; }
  .swipe::before, .swipe::after { content: none; }
}
.swipe-dots { display: flex; justify-content: center; gap: .4rem; margin-top: 1rem; }
.swipe-dots span {
  width: 6px; height: 6px; border-radius: 50%;
  background: color-mix(in srgb, var(--text) 25%, transparent);
  transition: background .2s, transform .2s;
}
.swipe-dots span.is-active { background: var(--accent); transform: scale(1.4); }
@media (min-width: 720px) { .swipe-dots { display: none; } }
@media (prefers-reduced-motion: reduce) { .swipe { scroll-behavior: auto; } }

/* ---------- Magnetische Buttons ----------
   Button folgt der Maus minimal (max. ~8px), federt beim Verlassen zurück.
   Ohne JS/bei reduced-motion: ganz normaler Button, keine Bewegung. */
.btn--magnetic { transition: transform .25s cubic-bezier(.2,.8,.2,1); }

/* ---------- Zahlen zählen hoch ----------
   <strong class="count-up" data-target="150" data-suffix="+">0</strong>
   Startwert im Markup ist "0" (oder Endwert für No-JS/Crawler) — base.js zählt
   erst hoch, wenn der Block ins Bild scrollt. font-variant-numeric hält die
   Ziffernbreite stabil, damit der Text beim Zählen nicht "zittert". */
.count-up { font-variant-numeric: tabular-nums; }

/* ---------- Sticky Schritt-Erklärung ----------
   Links ein sticky-fixiertes Bild/Icon, rechts mehrere Schritte, die beim
   Vorbeiscrollen einzeln hervorgehoben werden (nicht alle gleichzeitig grau).
   Nur für echte Abläufe mit Reihenfolge (z. B. "So arbeite ich"), keine
   künstliche Nummerierung für Aussagen ohne echte Sequenz. */
.steps-scroll { display: grid; gap: 3rem; }
@media (min-width: 900px) {
  .steps-scroll { grid-template-columns: 1fr 1fr; align-items: start; gap: 4rem; }
  .steps-scroll__visual { position: sticky; top: 6rem; }
}
.steps-scroll__step {
  padding-block: 2.5rem; border-top: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
  opacity: .4; transition: opacity .35s ease;
}
.steps-scroll__step:first-child { border-top: 0; }
.steps-scroll__step.is-active { opacity: 1; }
.steps-scroll__num {
  font-family: var(--display); font-weight: 700; font-size: .85rem;
  color: var(--accent); letter-spacing: .06em; margin-bottom: .5rem; display: block;
}
@media (prefers-reduced-motion: reduce) { .steps-scroll__step { opacity: 1; transition: none; } }

/* ---------- Marquee-Band (Endlos-Laufband) ----------
   Für Logo-/Partnerreihen oder eine wiederholte kurze Botschaft. Reiner CSS-Loop,
   kein JS nötig. Inhalt im Markup EINMAL schreiben, das zweite Mal identisch
   kopieren (siehe blocks.html) — die Animation verschiebt exakt um 50%, damit
   der Loop nahtlos wirkt. Pausiert bei Hover und bei reduzierter Bewegung. */
.marquee { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.marquee__track { display: flex; width: max-content; gap: 3.5rem; animation: marquee 26s linear infinite; }
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee__track { animation: none; } .marquee { overflow-x: auto; } }

/* ---------- Cursor-Glow (dunkle Sektionen) ----------
   Ein weiches Licht folgt dem Mauszeiger — nur auf .section--glow, nur Desktop
   (kein Touch), nur wenn Bewegung erlaubt ist. Rein dekorativ, per JS über
   --mx/--my gesteuerte CSS-Variablen, kein Layout-Einfluss. */
.section--glow { position: relative; overflow: hidden; }
.section--glow::before {
  content: ""; position: absolute; z-index: 0; pointer-events: none;
  left: var(--mx, 50%); top: var(--my, 50%); width: 42rem; height: 42rem;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 16%, transparent) 0%, transparent 70%);
  opacity: 0; transition: opacity .4s ease;
}
.section--glow.is-glowing::before { opacity: 1; }
.section--glow > * { position: relative; z-index: 1; }

/* ---------- Vorher/Nachher-Bildregler ----------
   Zwei Fotos exakt gleicher Größe übereinander, ein <input type="range">
   zieht die Trennlinie. Ohne JS/CSS-only: fixer 50/50-Split (Regler ist
   dann nur optisch inert, nicht kaputt) — JS synchronisiert clip-path und
   Griff live mit dem Wert. Für echte Vorher/Nachher-Fotos, nie erfunden. */
.compare-slider {
  position: relative; aspect-ratio: 16 / 10; overflow: hidden;
  border-radius: var(--radius); user-select: none; touch-action: pan-y;
}
.compare-slider__before, .compare-slider__after {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block;
}
.compare-slider__before { clip-path: inset(0 50% 0 0); }
.compare-slider__label {
  position: absolute; top: .75rem; z-index: 1;
  font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: #fff; background: rgba(0,0,0,.5); padding: .3rem .7rem; border-radius: 999px;
  pointer-events: none;
}
.compare-slider__label--before { left: .75rem; }
.compare-slider__label--after { right: .75rem; }
.compare-slider__handle {
  position: absolute; top: 0; bottom: 0; left: 50%; width: 3px; background: #fff;
  transform: translateX(-50%); box-shadow: 0 0 0 1px rgba(0,0,0,.15); pointer-events: none; z-index: 1;
}
.compare-slider__handle::after {
  content: "\21d4"; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 2.4rem; height: 2.4rem; border-radius: 50%; background: #fff; color: #18181b;
  display: flex; align-items: center; justify-content: center; font-size: 1.1rem;
  box-shadow: 0 4px 14px rgba(0,0,0,.25);
}
.compare-slider__range {
  position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: ew-resize;
  -webkit-appearance: none; appearance: none; z-index: 2;
}

/* ---------- 3D-Tilt-Karten ----------
   Karte kippt minimal Richtung Mauszeiger (Perspektive), federt beim
   Verlassen zurück. Nur Desktop/Maus. Sparsam einsetzen — für einzelne
   Bild-/Produktkarten, nicht für ganze Grids gleichzeitig. */
.tilt { transition: transform .2s ease-out; will-change: transform; }

/* ---------- Scroll-Fortschrittsleiste ----------
   Hauchdünner fixierter Balken oben, zeigt den Lesefortschritt der Seite.
   <div class="scroll-progress"></div> einmal direkt nach <body> einfügen. */
.scroll-progress {
  position: fixed; top: 0; left: 0; width: 100%; height: 3px;
  background: var(--accent); transform: scaleX(0); transform-origin: 0 0;
  z-index: 70; pointer-events: none;
}

/* ---------- Bottom-Dock-Navigation ----------
   Alternative zur klassischen Kopfzeile (.site-header): schwebende Pille
   unten, zentriert, statt oben fixiert. Passt zu One-Page-Portfolios/
   Agentur-Auftritten mit wenigen Ankern. Der Link zum aktuell sichtbaren
   Abschnitt wird per JS hervorgehoben (scroll-spy) — ohne JS bleiben alle
   Links normal klickbar, nur ohne aktive Markierung. Ersetzt .site-header,
   nicht zusätzlich zu ihr einsetzen. */
.dock-nav {
  position: fixed; left: 50%; bottom: 1.25rem; transform: translateX(-50%);
  z-index: 60; display: flex; gap: .2rem; max-width: calc(100% - 2rem);
  overflow-x: auto; scrollbar-width: none;
  background: var(--bg); border-radius: 999px; padding: .3rem;
  box-shadow: 0 10px 30px rgba(0,0,0,.14), 0 0 0 1px color-mix(in srgb, var(--text) 10%, transparent);
}
.dock-nav::-webkit-scrollbar { display: none; }
.dock-nav a {
  display: inline-flex; align-items: center; white-space: nowrap; min-height: 40px;
  padding: .5rem 1.1rem; border-radius: 999px; font-weight: 700; font-size: .85rem;
  color: var(--text-dim); text-decoration: none; transition: background .2s, color .2s;
}
.dock-nav a:hover { color: var(--text); }
.dock-nav a.is-active { background: var(--accent); color: var(--accent-contrast); }

/* ---------- Scroll-Schärfe-Reveal ----------
   Statement/Bild kommt beim Scrollen unscharf-zu-scharf in den Fokus statt
   nur zu faden — wirkt filmischer als reines .reveal. Für einzelne
   Aussagen/Bilder, NICHT für Fließtext (Lesbarkeit während der Bewegung).
   Progressive enhancement: ohne JS/bei reduzierter Bewegung immer
   scharf & voll sichtbar. */
.blur-reveal { will-change: filter, opacity; }
@media (prefers-reduced-motion: reduce) { .blur-reveal { filter: none !important; opacity: 1 !important; } }

/* ---------- Punktraster-Hintergrund ----------
   Dezente Textur hinter Hero-Content/Cards, reines CSS, kein JS. Farbe
   folgt automatisch --text, funktioniert also auf hell und dunkel. */
.bg-dots {
  background-image: radial-gradient(color-mix(in srgb, var(--text) 18%, transparent) 1.5px, transparent 1.5px);
  background-size: 22px 22px;
}
/* Variante: Fadenkreuz-Raster statt Punkte — nüchterner/technischer,
   passt zu Kanzleien/Ingenieurbüros/Präzisionshandwerk. */
.bg-crosshair {
  background-image:
    linear-gradient(color-mix(in srgb, var(--text) 12%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--text) 12%, transparent) 1px, transparent 1px);
  background-size: 44px 44px;
  background-position: center;
}

/* ---------- Theme-Umschalter (Hell/Dunkel) ----------
   Setzt data-theme="light"/"dark" auf <html> und überschreibt damit
   gezielt die System-Einstellung — merkt sich die Wahl (localStorage).
   Setzt voraus, dass das Theme nach demselben Muster wie bei Artifacts
   aufgebaut ist: Basis-Palette auf :root, System-Dark über
   "@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) }",
   explizites Dark nochmal über ":root[data-theme=\"dark\"]" (siehe
   Theme-Vorgabe in Phase 2/3). Ohne JS bleibt der Button funktionslos,
   die Seite folgt einfach der System-Einstellung — kein Bruch. */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 999px; flex: none;
  border: 1px solid color-mix(in srgb, var(--text) 18%, transparent);
  background: transparent; color: var(--text); cursor: pointer;
}
.theme-toggle svg { width: 18px; height: 18px; }
.theme-toggle__moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle__sun { display: none; }
  :root:not([data-theme="light"]) .theme-toggle__moon { display: block; }
}
:root[data-theme="dark"] .theme-toggle__sun { display: none; }
:root[data-theme="dark"] .theme-toggle__moon { display: block; }

/* ---------- Status-Punkt (verfügbar/online) ----------
   Kleiner pulsierender Punkt vor einer Verfügbarkeits-/Statusangabe
   ("2 Plätze frei im Juli", "Aktuell erreichbar"). Feste grüne Farbe
   (Semantik "verfügbar"), unabhängig von der Markenakzentfarbe — wie bei
   Ampelfarben üblich. **Nur bei echten, aktuellen Angaben**, nie als
   Deko-Attrappe (siehe Live-Mikro-Details-Regel in Phase 2). */
.status-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: #22c55e; position: relative; flex: none;
}
.status-dot::after {
  content: ""; position: absolute; inset: -4px; border-radius: 50%;
  background: inherit; opacity: .5; animation: status-pulse 2s ease-out infinite;
}
@keyframes status-pulse { 0% { transform: scale(.6); opacity: .5; } 100% { transform: scale(1.8); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .status-dot::after { animation: none; display: none; } }

/* ---------- Anlass-Auswahl (Kontaktformular) ----------
   Kachel-Auswahl statt langweiligem <select> für "Worum geht es?" im
   Kontaktformular. Radio-Buttons visuell versteckt, Kachel reagiert auf
   :checked — reines CSS, keine Zeile JS. Funktioniert identisch ohne
   CSS (dann normale native Radios), also niemals kaputt. */
.anlass-waehler { display: flex; flex-wrap: wrap; gap: .6rem; }
.anlass-option { position: relative; }
.anlass-option input {
  position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer;
}
.anlass-option span {
  display: inline-flex; align-items: center; gap: .5rem; min-height: 44px;
  padding: .6rem 1.1rem; border-radius: 999px; border: 1.5px solid color-mix(in srgb, var(--text) 20%, transparent);
  font-weight: 600; font-size: .92rem; color: var(--text-dim); background: var(--bg);
  transition: border-color .15s, color .15s, background .15s;
}
.anlass-option input:checked + span {
  border-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, var(--bg));
}
.anlass-option input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- Wunschzeit-Chips (Terminanfrage) ----------
   Mehrfachauswahl "wann passt es Ihnen" als Chips statt Freitext/Dropdown
   — für Betriebe, die echte Terminvorschläge statt Live-Kalender wollen
   (kein Cal.com/Buchungssystem, nur eine strukturierte Angabe fürs
   Kontaktformular). Checkbox-basiert, reines CSS. */
.zeit-chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.zeit-chip { position: relative; }
.zeit-chip input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.zeit-chip span {
  display: inline-flex; align-items: center; min-height: 40px; padding: .45rem .9rem;
  border-radius: var(--radius); border: 1.5px dashed color-mix(in srgb, var(--text) 25%, transparent);
  font-size: .88rem; color: var(--text-dim); transition: border-color .15s, color .15s, background .15s, border-style .15s;
}
.zeit-chip input:checked + span {
  border-style: solid; border-color: var(--accent); color: var(--accent-contrast); background: var(--accent);
}
.zeit-chip input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- Live-Ortszeit ----------
   Zeigt die aktuelle Uhrzeit am Firmenstandort, aktualisiert sich selbst.
   Ohne JS steht einfach der statische Fallback-Text im Markup (z. B. der
   Ortsname) da — kein "--:--", kein Bruch. Wirkt lebendig/lokal verankert,
   nur bei echtem Standort einsetzen (siehe Live-Mikro-Details-Regel). */
.local-time { font-variant-numeric: tabular-nums; }

/* ---------- Eckklammern (Viewfinder-Rahmen) ----------
   Vier kleine Eckklammern um ein Element, wie ein Kamera-Fokusrahmen —
   gibt Fotos/Hero-Flächen einen präzisen, "ausgewählten" Akzent. Reines
   CSS, kein JS. Sparsam einsetzen (1 Element pro Seite), gut für
   Fotografie/Architektur/Präzisionshandwerk. Markup: 4 leere <span
   aria-hidden="true"> vor dem eigentlichen Inhalt (siehe blocks.html). */
.frame-corners { position: relative; }
.frame-corners > span {
  position: absolute; width: 1.4rem; height: 1.4rem; pointer-events: none; z-index: 1;
  border: 2px solid var(--accent);
}
.frame-corners > span:nth-of-type(1) { top: -.5rem; left: -.5rem; border-right: 0; border-bottom: 0; }
.frame-corners > span:nth-of-type(2) { top: -.5rem; right: -.5rem; border-left: 0; border-bottom: 0; }
.frame-corners > span:nth-of-type(3) { bottom: -.5rem; left: -.5rem; border-right: 0; border-top: 0; }
.frame-corners > span:nth-of-type(4) { bottom: -.5rem; right: -.5rem; border-left: 0; border-top: 0; }

/* ---------- Film-Grain-Textur ----------
   Feines Rauschen über dunklen (oder hellen) Flächen statt flacher
   Farbfläche — wirkt hochwertiger/fotografischer. Reines SVG-Rauschen
   als Daten-URI, kein externer Request, kein Bild-Download. Sehr dezent
   dosiert (Opacity), overlay-Blend sorgt dafür, dass es auf hell wie
   dunkel funktioniert. Rein dekorativ, nimmt keinen Platz im Layout ein. */
.grain { position: relative; isolation: isolate; }
.grain::after {
  content: ""; position: absolute; inset: 0; z-index: 5; pointer-events: none;
  opacity: .05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}

/* ---------- Schwebende Foto-Badges (Trust-Pills auf Portrait/Hero-Foto) ----------
   Kleine, freigestellte Kennzahl-Pillen, die auf einem Portrait- oder
   Team-Foto "schweben" statt in einer separaten Kennzahlen-Sektion zu
   stehen — bindet echte Zahlen (Jahre Erfahrung, Kundenanzahl) direkt an
   das Gesicht dahinter. Reines CSS, kein JS. Nur echte, belegbare Angaben,
   nie erfinden. Sparsam: max. 2 Badges pro Foto, sonst wirkt es unruhig. */
.foto-badges { position: relative; display: inline-block; line-height: 0; }
.foto-badges img { display: block; width: 100%; border-radius: var(--radius); }
.foto-badges__badge {
  position: absolute; z-index: 2;
  display: inline-flex; align-items: center;
  background: var(--bg); color: var(--text);
  padding: .6rem 1.1rem; border-radius: 999px;
  font-size: .85rem; font-weight: 600; line-height: 1.2; white-space: nowrap;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .18);
}
.foto-badges__badge--tr { top: 1.25rem; right: -1rem; }
.foto-badges__badge--br { bottom: 1.25rem; right: -1rem; }
.foto-badges__badge--bl { bottom: 1.25rem; left: -1rem; }
.foto-badges__badge--tl { top: 1.25rem; left: -1rem; }
@media (max-width: 640px) {
  .foto-badges__badge--tr, .foto-badges__badge--tl { left: 1rem; right: auto; top: 1rem; }
  .foto-badges__badge--br, .foto-badges__badge--bl { left: 1rem; right: auto; bottom: 1rem; }
}

/* ---------- Video-Teaser mit Lightbox (ohne JS, reines :target) ----------
   Schwebende Abspielen-Pille über einem Vorschaubild statt eines
   eingebetteten <iframe> mit externem Anbieter (kein DSGVO-Cookie-Problem).
   Klick öffnet ein Vollbild-Modal per CSS-:target-Technik, komplett ohne
   JavaScript. Nur mit einem echten, selbst gehosteten Vorstellungsvideo
   einsetzen (z. B. kurzer Werkstatt-/Kanzlei-Rundgang), nie als Platzhalter. */
.video-teaser { position: relative; display: block; line-height: 0; }
.video-teaser__poster { display: block; width: 100%; border-radius: var(--radius); }
.video-teaser__play {
  position: absolute; right: 1.25rem; bottom: 1.25rem; z-index: 2;
  display: inline-flex; align-items: center; gap: .6rem;
  background: var(--bg); color: var(--text); text-decoration: none;
  padding: .5rem 1.1rem .5rem .5rem; border-radius: 999px;
  font-size: .85rem; font-weight: 600; line-height: 1.2;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .22);
  transition: transform .2s ease;
}
.video-teaser__play:hover { transform: scale(1.04); }
.video-teaser__play-icon { position: relative; width: 2.25rem; height: 2.25rem; border-radius: 50%; background: var(--accent); flex-shrink: 0; }
.video-teaser__play-icon::before {
  content: ""; position: absolute; top: 50%; left: 57%; transform: translate(-50%, -50%);
  border-style: solid; border-width: .5rem 0 .5rem .8rem;
  border-color: transparent transparent transparent var(--accent-contrast);
}
.video-teaser__modal {
  position: fixed; inset: 0; z-index: 100; padding: 2rem;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .25s ease;
}
.video-teaser__modal:target { opacity: 1; visibility: visible; pointer-events: auto; }
.video-teaser__backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, .75); }
.video-teaser__modal-box { position: relative; width: 100%; max-width: 900px; }
.video-teaser__modal-box video { display: block; width: 100%; border-radius: var(--radius); }
.video-teaser__close {
  position: absolute; top: -2.75rem; right: 0; z-index: 1;
  width: 2.25rem; height: 2.25rem; display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 1.75rem; line-height: 1; text-decoration: none;
}
@media (prefers-reduced-motion: reduce) { .video-teaser__modal { transition: none; } }
