/* ════════════════════════════════════════════════════
   Dynamic Visual — Theme + Base on DV-Nova
   No site-* component classes. Styling is done with dv-nova
   components (dv-card, dv-section, dv-text, dv-grid, dv-stack, …)
   and dv: utilities. This file holds ONLY:
     1. @font-face (Inter, local)
     2. @layer dv-themes  → brand token overrides (palette/font/accent)
     3. base element styles (html/body)
     4. the few app behaviours dv-nova has no component for —
        the condensing sticky header, skip-link, and print rules
        (prefixed `app-`, never `site-`).
   ════════════════════════════════════════════════════ */

/* ── Inter (lokal) ───────────────────────────────── */
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('../fonts/inter-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('../fonts/inter-500.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('../fonts/inter-600.woff2') format('woff2');
}

/* ════════════════════════════════════════════════════
   THEME — DV-Nova token overrides (brand palette/font/accent)
   ════════════════════════════════════════════════════ */
@layer dv-themes {
  :root {
    --dv-font-family-sans: 'Inter', -apple-system, BlinkMacSystemFont,
      'Helvetica Neue', system-ui, sans-serif;

    /* Warme Neutralpalette */
    --dv-color-bg-default: #f8f7f5;
    --dv-color-bg-raised: #ffffff;
    --dv-color-bg-overlay: #ffffff;
    --dv-color-bg-muted: #f2f1ef;
    --dv-color-bg-subtle: #f2f1ef;
    --dv-color-bg-input: #ffffff;
    --dv-color-bg-inverse: #1a1a1a;
    --dv-color-bg-neutral: #f2f1ef;
    --dv-color-bg-neutral-hover: #eae8e5;
    --dv-color-bg-neutral-active: #e0deda;

    --dv-color-fg-default: #1a1a1a;
    --dv-color-fg-muted: #4a4a4a;
    --dv-color-fg-subtle: #5c5c5c;
    --dv-color-fg-disabled: #a8a5a1;
    --dv-color-fg-inverse: #ffffff;

    --dv-color-border-default: #dedede;
    --dv-color-border-muted: #efefef;
    --dv-color-border-emphasis: #c9c6c2;
    --dv-color-border-strong: #4a4a4a;

    /* Magenta-Pink-Akzent — die Markenfarbe (vgl. brand_visual.md, Logo-Gradient).
       Hot-Pink #e91e63 nie als Text auf Hell (nur 4.35:1) — daher Deep-Violet für
       fg/Links, ein leicht vertiefter Magenta für Solid-Flächen, AA-geprüft. */
    --dv-color-bg-accent: #8e1f9e;
    --dv-color-bg-accent-hover: #7a1a8a;
    --dv-color-bg-accent-active: #661572;
    --dv-color-bg-accent-subtle: #f0d4eb;
    --dv-color-fg-accent: #8b1a80;
    --dv-color-fg-accent-hover: #661572;
    --dv-color-fg-on-accent: #ffffff;
    --dv-color-fg-on-accent-subtle: #8b1a80;
    --dv-color-border-accent: #9c27b0;

    /* App-level (nicht-dv) Variablen */
    --app-header-h: 5rem;
    /* Marken-Gradient (Logo: #9c27b0 → #e91e63). Schräge echot die Monogramm-Slashes.
       Nur für die Signatur (H1-Keyword + Haarlinie), nie flächig — 10-%-Regel. */
    --app-grad: linear-gradient(115deg, #9c27b0 0%, #e91e63 100%);
  }

  /* Dark palette — the brand's warm-dark token set. Applied in TWO cases, mirroring
     dv-nova's own theming contract:
       1. manual override:  html[data-mode="dark"]   (set by the header toggle)
       2. OS preference:    @media dark + html:not([data-mode])  (no manual choice yet)
     The auto case is gated on `:not([data-mode])` so a manual light choice wins over the
     OS, and stays no-JS-safe (CSS-only auto dark still works with scripting disabled).
     dv-nova reads the same `[data-mode]` attribute, so its base tokens flip in lockstep.
     Keep the two blocks identical when editing. */
  html[data-mode="dark"] {
    --dv-color-bg-default: #121110;
    --dv-color-bg-raised: #1c1a18;
    --dv-color-bg-overlay: #1c1a18;
    --dv-color-bg-muted: #221f1d;
    --dv-color-bg-subtle: #221f1d;
    --dv-color-bg-input: #1c1a18;
    --dv-color-bg-inverse: #edecea;
    --dv-color-bg-neutral: #242220;
    --dv-color-bg-neutral-hover: #2e2c2a;
    --dv-color-bg-neutral-active: #383532;

    --dv-color-fg-default: #edecea;
    --dv-color-fg-muted: #b8b5b0;
    --dv-color-fg-subtle: #8a8784;
    --dv-color-fg-disabled: #5c5955;
    --dv-color-fg-inverse: #121110;

    --dv-color-border-default: #2e2c2a;
    --dv-color-border-muted: #242220;
    --dv-color-border-emphasis: #44413e;
    --dv-color-border-strong: #b8b5b0;

    --dv-color-bg-accent: #a82a9e;
    --dv-color-bg-accent-hover: #8e1f9e;
    --dv-color-bg-accent-active: #7a1a8a;
    --dv-color-bg-accent-subtle: #2a1828;
    --dv-color-fg-accent: #e673c4;
    --dv-color-fg-accent-hover: #ef93d4;
    --dv-color-fg-on-accent-subtle: #e673c4;
    --dv-color-border-accent: #c44fb8;
  }

  @media (prefers-color-scheme: dark) {
    html:not([data-mode]) {
      --dv-color-bg-default: #121110;
      --dv-color-bg-raised: #1c1a18;
      --dv-color-bg-overlay: #1c1a18;
      --dv-color-bg-muted: #221f1d;
      --dv-color-bg-subtle: #221f1d;
      --dv-color-bg-input: #1c1a18;
      --dv-color-bg-inverse: #edecea;
      --dv-color-bg-neutral: #242220;
      --dv-color-bg-neutral-hover: #2e2c2a;
      --dv-color-bg-neutral-active: #383532;

      --dv-color-fg-default: #edecea;
      --dv-color-fg-muted: #b8b5b0;
      --dv-color-fg-subtle: #8a8784;
      --dv-color-fg-disabled: #5c5955;
      --dv-color-fg-inverse: #121110;

      --dv-color-border-default: #2e2c2a;
      --dv-color-border-muted: #242220;
      --dv-color-border-emphasis: #44413e;
      --dv-color-border-strong: #b8b5b0;

      --dv-color-bg-accent: #a82a9e;
      --dv-color-bg-accent-hover: #8e1f9e;
      --dv-color-bg-accent-active: #7a1a8a;
      --dv-color-bg-accent-subtle: #2a1828;
      --dv-color-fg-accent: #e673c4;
      --dv-color-fg-accent-hover: #ef93d4;
      --dv-color-fg-on-accent-subtle: #e673c4;
      --dv-color-border-accent: #c44fb8;
    }
  }
}

/* ════════════════════════════════════════════════════
   BASE
   ════════════════════════════════════════════════════ */
html {
  scroll-padding-top: calc(var(--app-header-h) + var(--dv-space-4));
}

body {
  background: var(--dv-color-bg-default);
  color: var(--dv-color-fg-default);
  font-family: var(--dv-font-family-sans);
  line-height: var(--dv-line-height-normal);
  /* Platz für die FIXE Kopfleiste reservieren — konstant die EXPANDED-Höhe
     (nicht das schrumpfende --app-header-h), sonst springt der Inhalt beim
     Kondensieren. Nur relevant, wenn dv-ui.js den Header auf fixed umstellt und
     --app-header-h-expanded je Seite misst. Ohne JS bleibt der Header sticky
     (reserviert seinen Platz selbst im Fluss) → Fallback 0, kein doppeltes
     Padding, kein Inhalt unter der Leiste. */
  padding-top: var(--app-header-h-expanded, 0px);
}

/* ════════════════════════════════════════════════════
   DV-NOVA-FIX — lesbarer Text auf .dv-card--inverse
   In dv-nova 0.15.4 setzt .dv-text ein eigenes color:fg-default und
   überschreibt damit die geerbte helle Schrift der Inverse-Card →
   Dunkel-auf-Dunkel (Titel/Preis 1.0:1, subtle 3.27:1). Hier re-mappen,
   analog zu dv-nova's eigenem .dv-card__title/__description. Ungelayert,
   damit es die gelayerten dv-nova-Regeln schlägt.
   → Entfernen, sobald ein dv-nova-Bundle den Inverse-Text-Defekt behebt
     (nach jedem Bundle-Bump gegenprüfen, vgl. CLAUDE.md).
   ════════════════════════════════════════════════════ */
.dv-card--inverse :is(.dv-text, .dv-dl__definition) {
  color: var(--dv-color-fg-inverse);
}
.dv-card--inverse :is(.dv-text--muted, .dv-text--subtle, .dv-dl__term) {
  color: color-mix(in oklch, var(--dv-color-fg-inverse) 72%, transparent);
}
/* dv-dl--bordered malt ein helles bg-default (weiß) + helle Borders. Auf einer
   Inverse-Card ist das eine weiße Box mit unsichtbaren Trennlinien. Hier auf das
   Card-Schema umfärben — analog zu dv-nova's eigenen __header/__footer-Borders
   (translucentes fg-inverse). Mit der Inverse-Text-Regel oben entfernen, sobald
   ein dv-nova-Bundle Inverse-Cards thematisch korrekt scoped (vgl. CLAUDE.md). */
.dv-card--inverse .dv-dl--bordered {
  background: transparent;
  border-color: color-mix(in oklch, var(--dv-color-fg-inverse) 15%, transparent);
}
.dv-card--inverse .dv-dl__item {
  border-bottom-color: color-mix(in oklch, var(--dv-color-fg-inverse) 15%, transparent);
}

/* ════════════════════════════════════════════════════
   DV-NOVA-FIX — sichtbarere Ruhe-Border auf .dv-card
   dv-nova's .dv-card-Basis nutzt --dv-color-border-muted (oklch 96%) — auf
   unserem warmen bg-default praktisch unsichtbar, die Karte „schwebt" ohne
   Kante. Hier auf --dv-color-border-default (92%) anheben; der Hover-State
   bleibt unangetastet (dv-nova hebt ihn auf border-emphasis 87% an), daher
   :not(:hover) — so bleibt das Hover-Delta erhalten.
   Ausgeklammert sind alle Varianten, die ihre Border bewusst selbst setzen
   (transparent: elevated/inverse/warning/success/info; Status-Tint: *-subtle;
   linker Akzentstreifen: --border-*). Ungelayert, damit es die gelayerte
   dv-nova-Basis schlägt.
   → Entfernen, sobald ein dv-nova-Bundle die Card-Ruhe-Border sichtbarer
     macht (nach jedem Bundle-Bump gegenprüfen, vgl. CLAUDE.md).
   ════════════════════════════════════════════════════ */
.dv-card:not(
  :hover,
  .dv-card--inverse, .dv-card--elevated,
  .dv-card--warning, .dv-card--success, .dv-card--info,
  .dv-card--success-subtle, .dv-card--warning-subtle,
  .dv-card--info-subtle, .dv-card--error-subtle,
  .dv-card--border-success, .dv-card--border-warning,
  .dv-card--border-error, .dv-card--border-info
) {
  border-color: var(--dv-color-border-default);
}

/* ════════════════════════════════════════════════════
   APP BEHAVIOURS (no dv-nova component equivalent)
   ════════════════════════════════════════════════════ */

/* ── Reading-Progress-Balken über den klebenden Header heben ──
   Der Balken (.dv-reading-progress) liegt fix bei top:0 auf der --dv-z-sticky-
   Ebene — exakt wie .app-header. Bei gleichem z-index gewinnt der später im DOM
   stehende Header und verdeckt den 4px-Balken mit seinem Hintergrund. Eine Stufe
   höher (unter Mobile-Drawer 1045 / Modal 1050) macht ihn sichtbar. */
.dv-reading-progress {
  z-index: calc(var(--dv-z-sticky) + 1);
}

/* ── Condensing header (dv-ui.js toggles .app-header--compact) ──
   Basis = sticky: no-JS-safe, reserviert seinen Platz selbst im Fluss. Ohne JS
   kondensiert der Header nie (das macht JS), also ändert sich die Dokumenthöhe
   nicht und der Reading-Progress springt nicht.
   Mit JS hebt dv-ui.js den Header per .app-header--fixed aus dem Fluss (fixed)
   und reserviert den Platz stattdessen als konstantes body-padding-top
   (Expanded-Höhe) — so ändert das Kondensieren die Dokumenthöhe nicht mehr und
   der Inhalt scrollt unter die durchscheinende Leiste. Der Wechsel ist
   nahtlos, weil Padding == bisherige Flow-Höhe. */
.app-header {
  position: sticky;
  top: 0;
  z-index: var(--dv-z-sticky);
  background: var(--dv-color-bg-default);
  border-bottom: var(--dv-border-width-1) solid var(--dv-color-border-default);
  padding-top: var(--dv-space-6);
  transition: background 0.25s ease, padding 0.25s ease;
}

/* JS-Upgrade: aus dem Fluss nehmen (Platz übernimmt body-padding-top).
   inset-inline:0 gibt die volle Breite, die der Block früher aus dem Fluss hatte. */
.app-header--fixed {
  position: fixed;
  inset-inline: 0;
}

/* Logo-Link reset (kein Unterstrich/Accent) */
.app-header a.app-logo {
  text-decoration: none;
  color: inherit;
}
.app-header a.app-logo img {
  display: block;
  height: var(--dv-space-10);
  width: auto;
  object-fit: contain;
}

/* Footer-Emblem */
.app-footer-logo {
  display: block;
  height: var(--dv-space-8);
  width: auto;
  opacity: 0.35;
}
html[data-mode="dark"] .app-footer-logo { filter: invert(1); }
@media (prefers-color-scheme: dark) {
  html:not([data-mode]) .app-footer-logo { filter: invert(1); }
}

/* Kollabierende Logo-Zeile */
.app-header__inner {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--dv-space-10);
  padding-bottom: var(--dv-space-4);
  max-height: 12.5rem;
  opacity: 1;
  visibility: visible;
  overflow: hidden;
  transition: max-height 0.25s ease, padding 0.25s ease, opacity 0.2s ease, visibility 0.25s;
}

/* Nav-Zeilen: horizontal scrollbar ausblenden + Trennlinie oben */
.app-header__bar {
  border-top: var(--dv-border-width-1) solid var(--dv-color-border-default);
  padding-block: var(--dv-space-3);
  overflow-x: auto;
  scrollbar-width: none;
  transition: padding 0.25s ease;
}
.app-header__bar::-webkit-scrollbar { display: none; }

.app-header--compact {
  padding-top: 0;
  background: color-mix(in srgb, var(--dv-color-bg-default) 82%, transparent);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
}
.app-header--compact .app-header__inner {
  max-height: 0;
  padding-bottom: 0;
  opacity: 0;
  visibility: hidden;
}
.app-header--compact .app-header__bar {
  border-top: none;
  padding-block: var(--dv-space-2);
}
.app-header--init,
.app-header--init .app-header__inner,
.app-header--init .app-header__bar {
  transition: none !important;
}

/* ── Theme-Toggle: das Icon spiegelt die EFFEKTIVE Darstellung ──
   Rein per CSS gesteuert (kein JS nötig fürs Icon): Mond = „auf Hell", Sonne =
   „auf Dunkel" — gezeigt wird das Icon der jeweils aktiven Darstellung, damit
   schon vor dem (deferred) Toggle-JS und beim ersten Paint der Zustand stimmt.
   Gleiche Doppel-Gatung wie die Palette: [data-mode] manuell, Media-Query auto. */
.app-theme-toggle .app-icon-sun { display: none; }
.app-theme-toggle .app-icon-moon { display: block; }
html[data-mode="dark"] .app-theme-toggle .app-icon-sun { display: block; }
html[data-mode="dark"] .app-theme-toggle .app-icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
  html:not([data-mode]) .app-theme-toggle .app-icon-sun { display: block; }
  html:not([data-mode]) .app-theme-toggle .app-icon-moon { display: none; }
}

/* ── Mobile-Navigation: Burger + dv-nova Drawer ──
   < 768px: die Primär-Links weichen einem Burger, der den dv-sidebar-Drawer
   (rechts) öffnet — Overlay, Fokus-Falle, Escape und Scroll-Lock übernimmt das
   dv-nova-JS (data-dv-sidebar*). ≥ 768px ist der Drawer komplett aus und die
   normale Leiste sichtbar. (.app-*-Regeln sind unlayered und schlagen damit die
   @layer-Komponentenregeln von dv-nova ohne !important.) */
.app-header__links { display: contents; }   /* Desktop: layout-neutral */
.app-burger { display: none; }               /* Burger nur mobil */

/* Drawer + Overlay über den sticky Header heben (Header-z = 1020, dv-sidebar
   wäre sonst mit 990/980 darunter). */
.app-mobile-nav { z-index: 1045; }
.dv-sidebar__overlay { z-index: 1040; }

@media (max-width: 767.98px) {
  .app-header__links { display: none; }      /* Primär-Links wandern in den Drawer */
  .app-burger { display: inline-flex; }
  .app-header__bar { justify-content: flex-end; }  /* Toggle + Burger nach rechts */
}

/* Ab 768px würde dv-nova den Drawer zur fixen In-Flow-Spalte machen
   (@media min-width:768){.dv-sidebar{position:sticky}}) — hier ganz ausblenden. */
@media (min-width: 768px) {
  .app-mobile-nav,
  .dv-sidebar__overlay { display: none; }
}

/* ── Skip-Link ───────────────────────────────────── */
.app-skip-link {
  position: absolute;
  top: -100%;
  left: var(--dv-space-4);
  z-index: var(--dv-z-modal);
  padding: var(--dv-space-3) var(--dv-space-6);
  background: var(--dv-color-bg-inverse);
  color: var(--dv-color-fg-inverse);
  font-size: var(--dv-font-size-sm);
  font-weight: var(--dv-font-weight-semibold);
  text-decoration: none;
  border-radius: 0 0 var(--dv-radius-md) var(--dv-radius-md);
  transition: top 0.2s;
}
.app-skip-link:focus { top: 0; }

/* ── Marken-Gradient-Signatur (aus der Logo-Geometrie abgeleitet) ──
   Sparsam: ein Gradient-Wort in der H1 + eine diagonale Haarlinie. Sonst nichts. */
.app-grad-text {
  color: var(--dv-color-fg-accent);          /* Solid-Fallback (AA), falls clip fehlt */
  background: var(--app-grad);
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}
@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .app-grad-text { -webkit-text-fill-color: currentColor; }
}

/* Diagonale Gradient-Haarlinie — echot die Schräge des Monogramms */
.app-grad-rule {
  width: 3.5rem;
  height: 3px;
  border: 0;
  margin: 0;
  background: var(--app-grad);
  border-radius: var(--dv-radius-full);
}

/* „Eigene Technologie"-Band: der echte dv-*-Stack in der Mono-Stimme.
   Zeigt die Eigenentwicklung, statt sie zu behaupten. Statisch umbrechend. */
.app-techband {
  border-block: var(--dv-border-width-1) solid var(--dv-color-border-muted);
  padding-block: var(--dv-space-5);
}
.app-techband__track {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--dv-space-3) var(--dv-space-6);
}

/* ── Print ───────────────────────────────────────── */
@media print {
  .no-print { display: none !important; }
  body { background: #fff; }
  .app-header { position: static; backdrop-filter: none; }
  .dv-card--inverse { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ── Reduced motion ──────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
