/* ==========================================================================
   Grafik-Bibliothek (Run 8, 27.09.2026): eigene, animierte Inline-SVGs im Stil „Shopify-Messlabor“.
   Makros: templates/macros/gfx.html. Asynchron geladen (nicht kritisch); nur der Hero hat kritisches CSS.

   Regeln (CLAUDE.md, Regel 4 + Run 8):
   1. Endzustand ist der Normalzustand. Ohne JS, ohne CSS dieser Datei und bei reduced-motion ist jede Grafik
      vollständig sichtbar. SVG-Elemente tragen deshalb Präsentationsattribute (fill="none", stroke="currentColor").
   2. Startzustände gibt es nur unter .is-armed (setzt ev.js per IntersectionObserver NUR für Grafiken unterhalb
      des sichtbaren Bereichs); .is-in spielt die Einblendung einmal ab. Endlos-Animationen laufen nur mit .is-in
      und pausieren mit .is-off (außerhalb des Sichtbereichs).
   3. Nur transform, opacity und stroke-dashoffset. Keine Layout-Eigenschaften, kein CLS.
   4. Jede Zahl in einer Grafik ist echt und belegt (cases.json, pricing.json), sonst keine Zahl.
   ========================================================================== */

/* ---------- Rahmen ---------- */
.gfx { margin: 0; position: relative; color: var(--text-2); }
.gfx svg { display: block; width: 100%; height: auto; overflow: visible; }
.gfx__cap { margin-top: var(--space-3); font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-2); }
.gfx--panel { background: var(--surface); border: var(--border); border-radius: var(--r-3); padding: var(--space-5); }
.tone-surface .gfx--panel { background: var(--bg); }

/* ---------- SVG-Vokabular (Farben immer über Tokens → hell/dunkel automatisch) ---------- */
.gfx .g-frame { fill: var(--surface); stroke: var(--line); }
.tone-surface .gfx .g-frame { fill: var(--bg); }
.gfx .g-raised { fill: var(--raised); }
.gfx .g-line { stroke: var(--line-strong); }
.gfx .g-hair { stroke: var(--line); }
.gfx .g-grid { stroke: var(--grid-line); }
.gfx .g-sig { stroke: var(--signal); }
.gfx .g-sig-f { fill: var(--signal-fill); }
.gfx .g-sig-soft { fill: color-mix(in srgb, var(--signal) 14%, transparent); }
.gfx .g-data { stroke: var(--data); }
.gfx .g-data-f { fill: var(--data); }
.gfx .g-data-soft { fill: var(--data-soft); }
.gfx .g-pos { stroke: var(--positive); }
.gfx .g-pos-f { fill: var(--positive); }
.gfx .g-ink { fill: var(--text); }
.gfx .g-mute { fill: var(--text-3); }
.gfx .g-t { fill: var(--text-2); font-family: var(--font-mono); font-size: 11px; font-variant-numeric: tabular-nums; }
.gfx .g-t1 { fill: var(--text); font-family: var(--font-mono); font-size: 12px; font-weight: 500; font-variant-numeric: tabular-nums; }
.gfx .g-th { fill: var(--text); font-family: var(--font-display); font-weight: 700; font-size: 13px; letter-spacing: -.01em; }
.gfx .g-on-sig { fill: var(--on-signal); }

/* ---------- Bewegung ---------- */
@keyframes g-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes g-pop { from { transform: scale(.4); } to { transform: scale(1); } }
@keyframes g-rise { from { transform: translateY(14px); } to { transform: translateY(0); } }
@keyframes g-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes g-flow { to { stroke-dashoffset: -24; } }
@keyframes g-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
@keyframes g-pulse { 0%, 100% { transform: scale(1); opacity: .9; } 50% { transform: scale(1.6); opacity: 0; } }

.gfx .g-draw { stroke-dasharray: 1; stroke-dashoffset: 0; }
.gfx .g-pop, .gfx .g-rise, .gfx .g-float, .gfx .g-pulse { transform-box: fill-box; transform-origin: center; }

@media (prefers-reduced-motion: no-preference) {
  /* Einblendung: nur wenn ev.js die Grafik scharf gemacht hat (lag beim Laden unterhalb des Sichtbereichs) */
  .gfx.is-armed:not(.is-in) .g-draw { stroke-dashoffset: 1; }
  .gfx.is-armed:not(.is-in) .g-pop { transform: scale(.4); }
  .gfx.is-armed:not(.is-in) .g-rise { transform: translateY(14px); }
  .gfx.is-armed:not(.is-in) .g-fade { opacity: 0; }
  .gfx.is-armed.is-in .g-draw { animation: g-draw 1.1s var(--ease-out) var(--d, 0s) both; }
  .gfx.is-armed.is-in .g-pop { animation: g-pop .45s var(--ease-out) var(--d, 0s) both; }
  .gfx.is-armed.is-in .g-rise { animation: g-rise .6s var(--ease-out) var(--d, 0s) both; }
  .gfx.is-armed.is-in .g-fade { animation: g-fade .6s var(--ease-out) var(--d, 0s) both; }

  /* Endlos (dezent), nur im Sichtbereich */
  .gfx.is-in .g-flow { stroke-dasharray: 4 8; animation: g-flow 1.6s linear infinite; }
  .gfx.is-in .g-float { animation: g-float 5s ease-in-out var(--d, 0s) infinite; }
  .gfx.is-in .g-pulse { animation: g-pulse 2.4s ease-out var(--d, 0s) infinite; }
  .gfx.is-off .g-flow, .gfx.is-off .g-float, .gfx.is-off .g-pulse, .gfx.is-off .g-loop { animation-play-state: paused; }
}
/* Ohne Bewegung: gestrichelte Flusslinien trotzdem als Strichelung zeigen (Aussage: „fließt“) */
.gfx .g-flow { stroke-dasharray: 4 8; }

/* Run 10: reduzierte Bewegung = Stufe statt aus. Nur Einblenden per opacity (300 ms) und einmaliges Zeichnen von Linien
   (600 ms); pop/rise werden zum reinen Einblenden, Endlos-Animationen und Hochzählen entfallen (motion.css sperrt den Rest). */
@media (prefers-reduced-motion: reduce) {
  .gfx.is-armed:not(.is-in) .g-draw { stroke-dashoffset: 1; }
  .gfx.is-armed:not(.is-in) :is(.g-fade, .g-pop, .g-rise) { opacity: 0; }
  .gfx.is-armed.is-in .g-draw { animation: g-draw .6s var(--ease-out) calc(var(--d, 0s) * .4) both !important; }
  .gfx.is-armed.is-in :is(.g-fade, .g-pop, .g-rise) { animation: g-fade .3s var(--ease-out) calc(var(--d, 0s) * .4) both !important; }
  .gfx.is-armed:not(.is-in) .gb-at__k::after { transform: scaleY(0); }
  .gfx.is-armed:not(.is-in) .gb-at__dot::after { opacity: 0; }
  .gfx.is-armed.is-in .gb-at__k::after { animation: gb-fill-y .15s linear calc(var(--k) * .15s) both !important; }
  @container (min-width: 40rem) {
    .gfx.is-armed:not(.is-in) .gb-at__k::after { transform: scaleX(0); }
    .gfx.is-armed.is-in .gb-at__k::after { animation-name: gb-fill-x !important; }
  }
  .gfx.is-armed.is-in .gb-at__dot::after { animation: g-fade .15s linear calc(var(--k) * .15s) both !important; }
}
/* Grafik-Bibliothek Teil A (Run 8): spark, measure_line, icon, migration, seo, funnel.
   Makros: templates/macros/gfx_a.html. Hero: gfx-hero.css. Bewegungsmodell und Vokabular: gfx.css. */

/* ---------- gemeinsam ---------- */
.gfx .ga-ring { stroke: var(--surface); }
.tone-surface .gfx .ga-ring { stroke: var(--bg); }
.gfx .ga-bar { fill: color-mix(in srgb, var(--text-3) 38%, transparent); }
.gfx .ga-bar2 { fill: color-mix(in srgb, var(--text-2) 55%, transparent); }
.gfx .ga-minor { opacity: .55; }
.gfx .ga-hl { fill: var(--signal-ink); }
@media (max-width: 40rem) { .gfx--mig.gfx--panel, .gfx--seo.gfx--panel, .gfx--fun.gfx--panel { padding: var(--space-4) var(--space-3); } }

/* ---------- Sparkline / Messlinie: feste Größe, Zeile der Belegleiste ---------- */
.gfx--spark, .gfx--measure { display: inline-block; vertical-align: middle; line-height: 0; }
.gfx--spark svg { width: 124px; height: 34px; }
.gfx--measure svg { width: 124px; height: 14px; }

/* ---------- Leistungs-Icons ---------- */
.svc-icon { display: inline-block; width: 48px; height: 48px; flex: none; color: var(--text); line-height: 0; }
.svc-icon svg { width: 48px; height: 48px; }
@keyframes ga-redraw { 0% { stroke-dashoffset: 1; } 100% { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: no-preference) {
  .svc-card:is(:hover, :focus-within) .svc-icon.gfx .g-draw { stroke-dasharray: 1; animation: ga-redraw .7s var(--ease-out) var(--d, 0s) both; }
  .svc-card:is(:hover, :focus-within) .svc-icon.gfx.is-armed.is-in .g-draw { animation: g-draw 1.1s var(--ease-out) var(--d, 0s) both, ga-redraw .7s var(--ease-out) var(--d, 0s) both; }
}

/* ---------- Migration ---------- */
.gfx--mig .ga-dst { stroke: var(--line-strong); }
.gfx.gfx--mig.gfx--panel .g-flow { stroke-dasharray: 6 6; }
.gfx--seo .g-t1, .gfx--fun .g-t1 { font-size: 13px; }
.gfx--mig .g-t, .gfx--mig .g-t1 { font-size: 12px; }
.gfx--mig .g-th { font-size: 15px; }

/* ---------- SEO: „Dein Shop“ wandert in der KI-Antwort nach oben (einmal beim Einblenden) ---------- */
.gfx--seo .ga-ai { fill: var(--raised); stroke: var(--line); }
.tone-surface .gfx--seo .ga-ai { fill: var(--surface); }
.gfx--seo .g-t { font-size: 12px; }
.gfx--seo .g-sig-f[width] { fill: color-mix(in srgb, var(--signal) 55%, transparent); }
@keyframes ga-up { from { transform: translateY(44px); } }
@keyframes ga-dn { from { transform: translateY(-22px); } }
@media (prefers-reduced-motion: no-preference) {
  .gfx.is-armed.is-in .ga-up { animation: ga-up .9s var(--ease-out) .5s both; }
  .gfx.is-armed.is-in .ga-dn { animation: ga-dn .9s var(--ease-out) .5s both; }
}

/* ---------- Funnel: Signalpunkt fällt dezent vom Besuch bis zum Kauf (endlos, nur im Sichtbereich) ---------- */
.gfx--fun .g-frame { fill: var(--raised); stroke: color-mix(in srgb, var(--text-3) 70%, transparent); }
.tone-surface .gfx--fun .g-frame { fill: var(--surface); }
.gfx--fun .g-hair { stroke: color-mix(in srgb, var(--text-3) 60%, transparent); }
.gfx--fun .ga-drop { transform-box: fill-box; transform-origin: center; }
@keyframes ga-drop {
  0% { transform: translateY(0); opacity: 0; }
  8% { opacity: 1; }
  70% { transform: translateY(144px); opacity: 1; }
  84%, 100% { transform: translateY(144px) scale(.5); opacity: 0; }
}
@media (prefers-reduced-motion: no-preference) {
  .gfx.is-in .ga-drop { animation: ga-drop 3.6s cubic-bezier(.45, 0, .55, 1) 1s infinite both; }
  .gfx.is-off .ga-drop { animation-play-state: paused; }
}

/* Grafik-Bibliothek Teil B (Run 8): ki_flow, widerruf, ablauf_track, werdegang, nrw_map, post_title.
   Makros: templates/macros/gfx_b.html. Vokabular und Bewegungsmodell: gfx.css (Endzustand = Normalzustand). */

/* ---------- gemeinsam: Beschriftungen ≥ 12 Einheiten (bei 330 px ≥ 10 px) ---------- */
.gb .g-t { font-size: 12px; }
.gb .g-t1 { font-size: 12.5px; }
.gb .g-th { font-size: 14px; }
.gb .g-t, .gb .g-t1 { letter-spacing: -.01em; }

/* ---------- Waage (Vergleichsartikel): Balken pendelt dezent um den Drehpunkt ---------- */
.gfx .gb-rock { transform-box: view-box; transform-origin: 200px 40px; }
@keyframes gb-rock { 0%, 100% { transform: rotate(-1.6deg); } 50% { transform: rotate(1.6deg); } }
@media (prefers-reduced-motion: no-preference) {
  .gfx.is-in .gb-rock { animation: gb-rock 6s ease-in-out infinite; }
}

/* ---------- Kopf-Illustration im Artikel: höchstens 420 px breit, mobil volle Breite ---------- */
.gfx--post { max-width: 26.25rem; }

/* ---------- Ablauf-Spur (HTML): Knoten über den Spalten der Schrittliste ---------- */
.gfx--ablauf { container-type: inline-size; color: var(--text-2); }
.gb-at { display: grid; gap: var(--space-4); }
.gb-at__k { position: relative; display: grid; grid-template-columns: 14px minmax(0, 1fr); column-gap: var(--space-3); align-items: start; }
.gb-at__dot { grid-row: span 2; width: 14px; height: 14px; margin-top: 3px; border-radius: 50%; border: 2px solid var(--line-strong); background: var(--bg); position: relative; z-index: 1; }
.tone-surface .gb-at__dot { background: var(--surface); }
.gb-at__dot::after { content: ""; position: absolute; inset: 1px; border-radius: 50%; background: var(--signal); }
.gb-at__n { font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 500; color: var(--signal-ink); font-variant-numeric: tabular-nums; line-height: 1.6; }
.gb-at__t { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-2); line-height: 1.45; }
/* Verbindung zum nächsten Knoten: Grundlinie + Signalfüllung (Füllung = Endzustand) */
.gb-at__k:not(:last-child)::before, .gb-at__k:not(:last-child)::after { content: ""; position: absolute; left: 6px; top: 17px; bottom: calc(-1 * var(--space-4) - 3px); width: 2px; background: var(--line); }
.gb-at__k:not(:last-child)::after { background: var(--signal); transform-origin: top center; }

@container (min-width: 40rem) {
  .gb-at { grid-template-columns: repeat(var(--n, 4), minmax(0, 1fr)); column-gap: var(--space-5); }
  .gb-at__k { grid-template-columns: minmax(0, 1fr); row-gap: var(--space-2); }
  .gb-at__dot { grid-row: auto; margin-top: 0; }
  .gb-at__k:not(:last-child)::before, .gb-at__k:not(:last-child)::after { left: 14px; top: 6px; bottom: auto; width: calc(100% + var(--space-5) - 14px); height: 2px; }
  .gb-at__k:not(:last-child)::after { transform-origin: left center; }
}

/* Über der Schrittliste: nur Knoten + Linie (Liste trägt Nummer und Titel); unter 64rem ist die Liste vertikal → Spur aus */
.gfx--ablauf:has(+ .steps) { display: none; }
@media (min-width: 64rem) {
  .gfx--ablauf:has(+ .steps--row) { display: block; margin-bottom: var(--space-3); }
  .gfx--ablauf:has(+ .steps--row) :is(.gb-at__n, .gb-at__t) { display: none; }
}

/* Bewegung A: einmalig beim Einblenden (ohne Scroll-Timeline) */
@keyframes gb-fill-y { from { transform: scaleY(0); } }
@keyframes gb-fill-x { from { transform: scaleX(0); } }
@keyframes gb-core { from { transform: scale(0); } }
@media (prefers-reduced-motion: no-preference) {
  .gfx.is-armed:not(.is-in) .gb-at__k::after { transform: scaleY(0); }
  .gfx.is-armed:not(.is-in) .gb-at__dot::after { transform: scale(0); }
  .gfx.is-armed.is-in .gb-at__k::after { animation: gb-fill-y .4s linear calc(var(--k) * .4s + .15s) both; }
  .gfx.is-armed.is-in .gb-at__dot::after { animation: gb-core .25s var(--ease-out) calc(var(--k) * .4s) both; }
  @container (min-width: 40rem) {
    .gfx.is-armed:not(.is-in) .gb-at__k::after { transform: scaleX(0); }
    .gfx.is-armed.is-in .gb-at__k::after { animation-name: gb-fill-x; }
  }
}

/* Bewegung B: an den Scroll gekoppelt (füllt sich zwischen 10 % und 45 % des Durchlaufs durch den Sichtbereich) */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .gfx.gfx--ablauf .gb-at { view-timeline: --gb-at block; }
    .gfx.gfx--ablauf.gb .gb-at .gb-at__k::after {
      --s: calc(35% / max(1, var(--n) - 1));
      animation: gb-fill-y linear both; animation-timeline: --gb-at;
      animation-range: cover calc(10% + var(--k) * var(--s)) cover calc(10% + (var(--k) + 1) * var(--s));
    }
    .gfx.gfx--ablauf.gb .gb-at .gb-at__dot::after {
      --s: calc(35% / max(1, var(--n) - 1));
      animation: gb-core var(--ease-out) both; animation-timeline: --gb-at;
      animation-range: cover calc(8% + var(--k) * var(--s)) cover calc(12% + var(--k) * var(--s));
    }
    @container (min-width: 40rem) {
      .gfx.gfx--ablauf.gb .gb-at .gb-at__k::after { animation-name: gb-fill-x; }
    }
  }
}

/* Platzhalter-Balken (Text, Felder): sichtbar in beiden Themes, ohne Aussage */
.gfx .gb-bar { fill: color-mix(in srgb, var(--text-3) 40%, transparent); }

/* ---------- Run 10: Mobil-Fassungen (.gfx__m, 280 Einheiten breit, Umschalten in components.css .gfx--dual) ----------
   Beschriftung mindestens 14 Einheiten; die Fassung erscheint nur bei Rahmen < 24rem (Handy) und ist dort ≥ 280 px breit
   → effektiv ≥ 14 px (Konsistenz-Check Kategorie 11). */
.gfx .gfx__m .g-t { font-size: 14px; }
.gfx .gfx__m .g-t1 { font-size: 14.5px; }
.gfx .gfx__m .g-th { font-size: 15.5px; }
.gfx .gfx__m .ga-big { font-size: 18px; }
.gfx.gfx--post .gfx__m { max-width: 22rem; }
.colchart__svg--m { max-width: 22rem; }
.colchart__svg--m .colchart__tick, .colchart__svg--m .colchart__lbl { font-size: 14px; }
.colchart__svg--m .colchart__val { font-size: 16px; }
/* Run 10: Blog-Titelgrafiken breit (≈ 420 px für 400 Einheiten): Beschriftung 14 Einheiten → am Desktop ≥ 14 px */
.gfx.gfx--post .gfx__d .g-t, .gfx.gfx--post .gfx__d .g-t1 { font-size: 14px; }
.gfx.gfx--post .gfx__d .g-th { font-size: 15px; }
