/* ============================================================================
   WebDevCore — Premium-Layer (premium.css)
   Neue Premium-Komponenten & -Sektionen. Baut ausschliesslich auf theme.css-Tokens
   und harmoniert mit base.css. Von head.php NACH base.css, VOR effects.css geladen.

   INVARIANTEN (wie effects.css):
   - Additiv: setzt nur transform/opacity/clip-path/filter/eigene Layer — NIE
     semantische Tokens (--bg/--fg/--accent/Schrift) um. Inhalt ohne JS voll da.
   - prefers-reduced-motion: reduce -> keine Bewegung (base.css *-Regel kappt
     Transitions/Animationen; JS-Module (motion.js) attachen dann gar nicht erst).
   - Kein externer Request. Self-hosted, build-frei.
   Klassen werden von partials/sections/* + motion.js genutzt (siehe design-registry.json).
   ========================================================================== */

/* ============================================================================
   1. Split-Text (motion.js [data-motion~="split"]) — Wörter steigen gestaffelt auf.
   Ohne JS bleibt der Text schlicht sichtbar; motion.js setzt .is-split (Startzustand
   verstecken) erst NACH dem Wrappen und nur ohne reduced-motion.
   ========================================================================== */
.wsplit { display: inline-block; overflow: hidden; vertical-align: top; }
.wsplit__i { display: inline-block; will-change: transform; }
.is-split .wsplit__i {
  transform: translateY(115%); opacity: 0;
  transition: transform var(--dur-xslow) var(--ease-premium), opacity var(--dur-slow) var(--ease-out);
  transition-delay: calc(var(--wi, 0) * var(--stagger-sm));
}
.is-split.is-in .wsplit__i { transform: none; opacity: 1; }

/* ============================================================================
   2. Premium-Karten-Modifier — teurer, ruhiger Hover. Basis-.card bleibt gültig.
   ========================================================================== */
.card--edge { position: relative; box-shadow: var(--card-shadow), var(--shadow-inset); }
.card--edge::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px; border-radius: inherit;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: 0; transition: opacity var(--dur-base) var(--ease);
}
.card--edge:hover::before { opacity: 0.9; }

.card--glow { transition: transform var(--dur-base) var(--ease-soft), box-shadow var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease); }
.card--glow:hover { transform: translateY(-5px); box-shadow: var(--shadow-glow); border-color: var(--accent); }

/* 3D-Tilt (motion.js [data-motion~="tilt"]) — Karte kippt leicht zur Maus, mit
   wandernder Lichtreflexion. transform-style + Winkel per CSS-Var von JS gesetzt. */
[data-motion~="tilt"] {
  position: relative;
  transform-style: preserve-3d;
  transform: perspective(900px) rotateX(var(--tiltX, 0deg)) rotateY(var(--tiltY, 0deg));
  transition: transform var(--dur-base) var(--ease-soft), box-shadow var(--dur-base) var(--ease);
}
[data-motion~="tilt"].is-tilting { transition: none; }
[data-motion~="tilt"]:hover { box-shadow: var(--shadow-premium); }
[data-motion~="tilt"] > * { transform: translateZ(0); }
.tilt-glare {
  position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: radial-gradient(30rem 30rem at var(--gx, 50%) var(--gy, 0%), color-mix(in srgb, #fff 22%, transparent), transparent 45%);
  opacity: 0; transition: opacity var(--dur-base) var(--ease); mix-blend-mode: soft-light; z-index: 2;
}
[data-motion~="tilt"]:hover .tilt-glare { opacity: 1; }

/* Glas-Karten (HELL-first, HELL-Pflicht-konform): frostiges Glas auf HELLER wie
   dunkler Fläche via color-mix. Fallback ohne backdrop-filter = solide Fläche. */
.card--glass, [data-glass] .card, [data-glass] .kpi, [data-glass] .mockup__card {
  background: color-mix(in srgb, var(--surface) 60%, transparent);
  border: 1px solid color-mix(in srgb, var(--fg) 9%, transparent);
  box-shadow: var(--shadow-sm), var(--shadow-inset);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card--glass, [data-glass] .card, [data-glass] .kpi, [data-glass] .mockup__card {
    backdrop-filter: blur(var(--blur-md)) saturate(1.3);
    -webkit-backdrop-filter: blur(var(--blur-md)) saturate(1.3);
  }
}

/* ============================================================================
   3. Button-Microinteractions — magnetic (JS), light-sweep, icon-slide.
   ========================================================================== */
.btn--sweep { position: relative; overflow: hidden; isolation: isolate; }
.btn--sweep::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--gradient-sheen); transform: translateX(-120%);
  transition: transform var(--dur-slow) var(--ease-out);
}
.btn--sweep:hover::after { transform: translateX(120%); }
.btn [data-arrow], .btn .btn__arrow { display: inline-block; transition: transform var(--dur-base) var(--ease-soft); }
.btn:hover [data-arrow], .btn:hover .btn__arrow { transform: translateX(0.35em); }
.btn--magnetic [data-mag-inner] { display: inline-flex; align-items: center; gap: inherit; will-change: transform; }

/* Animierter Link-Unterstrich (feiner als Nav) */
.link-underline { position: relative; color: var(--accent-600); font-weight: var(--weight-semibold); }
.link-underline::after {
  content: ""; position: absolute; left: 0; bottom: -2px; height: 2px; width: 100%;
  background: currentColor; transform: scaleX(0); transform-origin: right; border-radius: 2px;
  transition: transform var(--dur-base) var(--ease-out);
}
.link-underline:hover::after { transform: scaleX(1); transform-origin: left; }

/* ============================================================================
   4. Sticky-Story (story.php + motion.js [data-scene]).
   Ohne JS: alle Panels stehen im Fluss (mobil & Fallback). Mit JS (.js-scene,
   Desktop, ohne reduced-motion): Aside sticky, Panels absolut gestapelt, nur das
   aktive sichtbar, Fortschritts-Balken per --p (0..1) von motion.js.
   ========================================================================== */
.story__grid { display: grid; grid-template-columns: 0.85fr 1.15fr; gap: clamp(var(--space-lg), 5vw, var(--space-2xl)); align-items: start; }
.story__aside { display: grid; gap: var(--space-md); }
.story__nav { display: grid; gap: var(--space-xs); }
.story__step {
  display: grid; grid-template-columns: auto 1fr; gap: 0.2rem var(--space-sm); align-items: baseline;
  padding: var(--space-sm) var(--space-md); border-radius: var(--radius-lg);
  border: 1px solid transparent; color: var(--fg-muted);
  transition: color var(--dur-base) var(--ease), background var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
}
.story__step-n { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--step-1); color: var(--accent-2-300); grid-row: span 2; }
.story__step b { font-size: var(--step-1); color: var(--fg); font-weight: var(--weight-semibold); }
.story__step span:last-child { grid-column: 2; font-size: var(--step--1); }
.story__step.is-active { color: var(--fg); background: var(--surface-soft); border-color: var(--border); }
.story__step.is-active .story__step-n { color: var(--accent-600); }
.story__progress { display: none; }
.story__stage { position: relative; min-height: 22rem; }
.story__panel {
  border: var(--card-border); border-radius: var(--radius-xl); background: var(--surface);
  box-shadow: var(--card-shadow); padding: clamp(var(--space-md), 3vw, var(--space-xl));
  display: grid; gap: var(--space-sm); align-content: center; min-height: 20rem;
}
.story__panel-metric { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--step-6); line-height: 1; color: var(--accent-600); letter-spacing: var(--tracking-tight); }
.story__panel-icon { display: grid; place-items: center; width: 3.5rem; height: 3.5rem; border-radius: var(--radius-md); background: var(--accent-soft); color: var(--accent-600); }
.story__panel-icon svg { width: 1.7rem; height: 1.7rem; }

/* Aktiver JS-Modus (Desktop, ohne reduced-motion): Aside bleibt sticky stehen,
   die Stage ist eine HOHE Spalte hintereinander stehender Panels -> die
   Scroll-Distanz treibt Fortschritt + aktiven Schritt. Inaktive Panels sind
   gedimmt, das zentrierte Panel „leuchtet" (kein Content-Verstecken -> robust). */
@media (min-width: 821px) {
  .story.js-scene .story__aside { position: sticky; top: 14vh; align-self: start; }
  .story.js-scene .story__progress {
    display: block; position: relative; height: 3px; border-radius: 2px;
    background: var(--border); overflow: hidden;
  }
  .story.js-scene .story__progress-bar { position: absolute; inset: 0 auto 0 0; width: calc(var(--p, 0) * 100%); background: var(--accent); border-radius: 2px; }
  .story.js-scene .story__stage { display: grid; gap: 9vh; }
  .story.js-scene .story__panel {
    min-height: 62vh; opacity: 0.4; transform: translateY(12px) scale(0.99);
    transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
  }
  .story.js-scene .story__panel.is-active { opacity: 1; transform: none; }
}
@media (max-width: 820px) {
  .story__grid { grid-template-columns: 1fr; gap: var(--space-lg); }
  .story__aside { order: -1; }
  .story__stage { display: grid; gap: var(--space-md); }
  .story__panel { min-height: 0; }
}

/* ============================================================================
   5. Dashboard-/App-Mockup (mockup.php). Schwebender „Frame" mit KPI-Karten,
   SVG-Chart (Draw), Status-Pills. Zahlen via [data-count].
   ========================================================================== */
.mockup__frame {
  position: relative; border: 1px solid var(--border-strong); border-radius: var(--radius-xl);
  background: var(--surface); box-shadow: var(--shadow-premium); overflow: hidden;
}
.mockup__bar { display: flex; align-items: center; gap: 0.45rem; padding: var(--space-sm) var(--space-md); border-bottom: 1px solid var(--border); background: var(--surface-2); }
.mockup__bar::before, .mockup__bar i {
  content: ""; width: 0.7rem; height: 0.7rem; border-radius: 50%; background: var(--border-strong); flex: none; display: block;
}
.mockup__bar i:nth-child(1) { background: color-mix(in srgb, var(--accent) 60%, var(--border-strong)); }
.mockup__bar-label { margin-left: auto; font-size: var(--step--1); color: var(--fg-subtle); font-family: var(--font-mono); }
.mockup__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-sm); padding: clamp(var(--space-sm), 2.5vw, var(--space-lg)); }
.mockup__card { border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface); padding: var(--space-md); display: grid; gap: 0.35rem; align-content: start; box-shadow: var(--shadow-xs); }
.mockup__card--wide { grid-column: span 2; }
.mockup__card--full { grid-column: 1 / -1; }
@media (max-width: 640px) { .mockup__grid { grid-template-columns: repeat(2, 1fr); } .mockup__card--wide { grid-column: 1 / -1; } }
.kpi__value { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--step-4); line-height: 1; color: var(--accent-600); letter-spacing: var(--tracking-tight); }
.kpi__label { font-size: var(--step--1); color: var(--fg-muted); }
.kpi__delta { font-size: var(--step--1); font-weight: var(--weight-semibold); display: inline-flex; align-items: center; gap: 0.25em; }
.kpi__delta svg { width: 0.9em; height: 0.9em; flex: none; }
.kpi__delta.ok { color: var(--success); }
.kpi__delta.warn { color: var(--warning); }
.status-pill { display: inline-flex; align-items: center; gap: 0.4em; padding: 0.25em 0.75em; border-radius: var(--radius-full); font-size: var(--step--1); font-weight: var(--weight-medium); background: var(--surface-2); border: 1px solid var(--border); color: var(--fg-muted); }
.status-pill::before { content: ""; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: currentColor; }
.status-pill.ok { color: var(--success); background: color-mix(in srgb, var(--success) 10%, transparent); border-color: color-mix(in srgb, var(--success) 30%, transparent); }
.status-pill.warn { color: var(--warning); background: color-mix(in srgb, var(--warning) 10%, transparent); border-color: color-mix(in srgb, var(--warning) 30%, transparent); }
.status-pill.accent { color: var(--accent-600); background: var(--accent-soft); border-color: var(--accent-ring); }
.mockup__pills { display: flex; flex-wrap: wrap; gap: var(--space-2xs); }
.chart { width: 100%; }
/* feste, dezente Chart-Hoehe; preserveAspectRatio="none" streckt die Daten auf die
   Breite -> Stroke via vector-effect konstant halten (sonst wird er mitskaliert). */
.chart svg { width: 100%; height: clamp(110px, 16vw, 180px); display: block; }
.chart__grid line { stroke: var(--border); stroke-width: 1; vector-effect: non-scaling-stroke; }
.chart__line { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.chart__area { fill: var(--accent-soft); }
.chart__bar { fill: var(--accent); }
.chart__bar--soft { fill: var(--accent-soft); }

/* Dezentes Schweben EINZELNER KPI-Karten (nicht des ganzen Frames — kollidiert nicht
   mit dem .reveal des Frames, da eigene Elemente + eigene, additive Transform-Achse). */
@media (prefers-reduced-motion: no-preference) {
  .mockup__grid .kpi { animation: kpi-float 7s var(--ease-soft) infinite; will-change: transform; }
  .mockup__grid .kpi:nth-child(2) { animation-delay: -1.6s; }
  .mockup__grid .kpi:nth-child(3) { animation-delay: -3.1s; }
}
@keyframes kpi-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }

/* ============================================================================
   6. Prozess-/Timeline (timeline.php) — selbstzeichnende Verbindungslinie.
   ========================================================================== */
.timeline { position: relative; display: grid; gap: var(--space-lg); }
.timeline__rail { position: absolute; inset-block: 0.5rem; inset-inline-start: 1.15rem; width: 2px; pointer-events: none; }
.timeline__rail svg { width: 2px; height: 100%; overflow: visible; }
.timeline__rail path, .timeline__rail line { stroke: var(--accent); stroke-width: 2; fill: none; stroke-linecap: round; }
.tstep { position: relative; display: grid; grid-template-columns: auto 1fr; gap: var(--space-md); align-items: start; padding-inline-start: 0; }
.tstep__dot { position: relative; z-index: 1; display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border-radius: var(--radius-full); background: var(--surface); border: 2px solid var(--accent); color: var(--accent-600); box-shadow: 0 0 0 5px var(--bg); flex: none; }
.tstep__dot svg { width: 1.15rem; height: 1.15rem; }
.tstep__body { display: grid; gap: var(--space-3xs); }
.tstep__body h4 { font-size: var(--step-1); }
.tstep__n { font-size: var(--step--1); font-weight: var(--weight-semibold); color: var(--accent-600); letter-spacing: 0.06em; text-transform: uppercase; }
/* horizontal */
.timeline--h { grid-auto-flow: column; grid-auto-columns: 1fr; gap: var(--space-md); }
.timeline--h .timeline__rail { inset: 1.15rem 0.5rem auto 0.5rem; width: auto; height: 2px; }
.timeline--h .timeline__rail svg { width: 100%; height: 2px; }
.timeline--h .tstep { grid-template-columns: 1fr; gap: var(--space-sm); text-align: center; justify-items: center; }
@media (max-width: 760px) { .timeline--h { grid-auto-flow: row; grid-auto-columns: auto; } .timeline--h .timeline__rail { inset-block: 0.5rem; inset-inline-start: 1.15rem; width: 2px; height: auto; } .timeline--h .tstep { grid-template-columns: auto 1fr; text-align: start; justify-items: start; } }

/* ============================================================================
   7. Marquee (marquee.php) — nahtloser horizontaler Lauf, CSS-only, Pause@hover.
   ========================================================================== */
.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; align-items: center; gap: clamp(var(--space-lg), 5vw, var(--space-2xl)); width: max-content; }
.marquee__item { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--fg-muted); font-weight: var(--weight-semibold); font-size: var(--step-1); white-space: nowrap; }
.marquee__item svg { width: 1.2rem; height: 1.2rem; color: var(--accent-600); }
.marquee__item--dot::after { content: "•"; margin-left: clamp(var(--space-lg), 5vw, var(--space-2xl)); color: var(--accent-300); }
@media (prefers-reduced-motion: no-preference) {
  .marquee__track { animation: marquee-scroll 32s linear infinite; }
  .marquee[data-speed="slow"] .marquee__track { animation-duration: 52s; }
  .marquee[data-speed="fast"] .marquee__track { animation-duration: 20s; }
  .marquee:hover .marquee__track { animation-play-state: paused; }
}
@keyframes marquee-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee { -webkit-mask-image: none; mask-image: none; } .marquee__track { flex-wrap: wrap; width: auto; justify-content: center; row-gap: var(--space-sm); } }

/* ============================================================================
   8. Showcase (showcase.php) — Bild-/Referenz-Reveal mit Maske + Parallax.
   ========================================================================== */
.showcase { display: grid; gap: clamp(var(--space-xl), 6vw, calc(var(--space-2xl) * 1.1)); }
.showcase__row { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(var(--space-lg), 5vw, var(--space-2xl)); align-items: center; }
.showcase__row:nth-child(even) .showcase__media { order: -1; }
.showcase__media { position: relative; aspect-ratio: 4 / 3; border-radius: var(--radius-image); overflow: hidden; background: var(--surface-2); border: 1px solid var(--border); box-shadow: var(--card-shadow); display: grid; place-items: center; color: var(--accent); }
.showcase__media img, .showcase__media picture { width: 100%; height: 100%; object-fit: cover; }
.showcase__media > svg { width: 30%; height: auto; opacity: 0.5; }
.showcase__tag { display: inline-flex; align-items: center; gap: 0.4em; align-self: start; padding: 0.3em 0.8em; border-radius: var(--radius-full); background: var(--accent-soft); color: var(--accent-700); font-size: var(--step--1); font-weight: var(--weight-semibold); }
.showcase__tag svg { width: 0.95em; height: 0.95em; flex: none; }
.showcase__body { display: grid; gap: var(--space-sm); align-content: center; }
.showcase__body h3 { font-size: var(--step-3); }
/* clip-mask-Reveal des Mediums (scroll-driven; ohne Support/reduced -> statisch sichtbar) */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .showcase__media img, .showcase__media picture, .showcase__media > svg {
      animation-name: fx-mask-up; animation-fill-mode: both; animation-timing-function: var(--ease-out);
      animation-timeline: view(); animation-range: entry 0% cover 38%;
    }
  }
}
@keyframes fx-mask-up { from { clip-path: inset(0 0 100% 0); transform: scale(1.05); } to { clip-path: inset(0 0 0 0); transform: none; } }
@media (max-width: 800px) {
  .showcase__row { grid-template-columns: 1fr; gap: var(--space-md); }
  .showcase__row:nth-child(even) .showcase__media { order: 0; }
}

/* ============================================================================
   9. Atmosphere (atmosphere.php) — Ambient-Canvas-Band. CSS-Verlauf ist der
   garantierte Grundzustand; das Canvas liegt dezent darüber (JS, motionLevel>=2).
   ========================================================================== */
.atmosphere { position: relative; overflow: hidden; isolation: isolate; text-align: center; background: radial-gradient(120% 90% at 50% 0%, var(--accent-soft), transparent 60%), var(--surface); }
.atmo__canvas { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; opacity: 0; pointer-events: none; transition: opacity 1s var(--ease-out); }
.atmo__canvas.is-live { opacity: 0.85; }
.atmosphere > .container { position: relative; z-index: 1; }
.atmosphere .section__head { margin-inline: auto; }
.hero__atmo { position: absolute; inset: 0; z-index: -1; opacity: 0; transition: opacity 1.2s var(--ease-out); }
.hero__atmo.is-live { opacity: 0.7; }

/* ============================================================================
   10. Section-Übergänge / Sheen.
   ========================================================================== */
.section--sheen { position: relative; }
.section--sheen::before { content: ""; position: absolute; inset-block-start: 0; inset-inline: 0; height: 1px; background: linear-gradient(90deg, transparent, var(--accent-ring) 30%, var(--accent-ring) 70%, transparent); }

/* ============================================================================
   11. FAQ plus/minus-Morph (optional, wenn .faq__plus statt Chevron genutzt wird).
   ========================================================================== */
.faq__plus { position: relative; flex: none; width: 1.15rem; height: 1.15rem; }
.faq__plus::before, .faq__plus::after { content: ""; position: absolute; inset-block-start: 50%; inset-inline: 0; height: 2px; background: var(--accent-2-600); border-radius: 2px; transition: transform var(--dur-base) var(--ease); }
.faq__plus::after { transform: rotate(90deg); }
.faq__item[open] .faq__plus::after { transform: rotate(0deg); }

/* ============================================================================
   12. Reveal-Varianten — sanfter Premium-Rise mit Skala (nur Startzustand, wenn
   .reveal--soft; nutzt dieselbe Sichtbarkeits-Logik wie .reveal aus base.css).
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .reveal--soft { animation-name: reveal-soft; animation-timing-function: var(--ease-premium); animation-range: entry 0% cover 34%; }
  }
}
@keyframes reveal-soft { from { opacity: 0; transform: translateY(26px) scale(0.985); } to { opacity: 1; transform: none; } }

/* Anti-CLS: das JS-gesteuerte Verstecken (motion.js) greift nur bei aktivem JS. */
html:not(.js) .is-split .wsplit__i { transform: none; opacity: 1; }
/* ============================================================================
   8b. Viewer3D (viewer3d.php) — frei schwebender Wohnungs-Viewer (KEIN Fenster/Rahmen):
   <model-viewer> (self-hosted GLB) steht direkt auf der Seite, geerdet durch Kontakt-
   schatten + Spotlight; 2D-Grundriss im SELBEN Feld (Radio-Umschalter), Bedienung als
   schwebende Pille darunter.
   ========================================================================== */
.viewer3d { position: relative; max-width: min(1040px, 100%); margin-inline: auto; }

/* Frei schwebende Bühne — transparent, kein Rahmen. Spotlight (::before) + der
   Kontaktschatten des Modells erden es auf der Seite. */
.viewer3d__stage {
  position: relative; aspect-ratio: 16 / 9; isolation: isolate;
  display: grid; place-items: center; overflow: visible;
}
@media (max-width: 640px) { .viewer3d__stage { aspect-ratio: 4 / 3; } }
.viewer3d__stage::before {
  content: ""; position: absolute; inset: -6% -4% -2%; z-index: 0; pointer-events: none;
  background: radial-gradient(58% 46% at 50% 60%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 72%);
}

/* Poster / Startzustand */
.viewer3d__poster {
  position: absolute; inset: 0; display: grid; place-items: center;
  text-decoration: none; color: var(--fg); cursor: pointer; isolation: isolate;
}
.viewer3d__poster--empty { cursor: default; }
.viewer3d__poster picture, .viewer3d__poster img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0;
}
.viewer3d__poster-fallback { position: absolute; inset: 0; display: grid; place-items: center; color: var(--accent); z-index: 0; }
.viewer3d__poster-fallback svg { width: 22%; height: auto; opacity: 0.5; }
.viewer3d__scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(120% 92% at 50% 40%, color-mix(in srgb, var(--bg) 8%, transparent), color-mix(in srgb, #000 60%, transparent));
}
.viewer3d__play {
  position: relative; z-index: 2; display: inline-flex; align-items: center; gap: var(--space-sm);
  padding: var(--space-xs) var(--space-md) var(--space-xs) var(--space-xs);
  background: color-mix(in srgb, var(--surface) 84%, transparent); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  border: 1px solid var(--border); border-radius: var(--radius-full); box-shadow: var(--shadow-md);
  transition: transform .25s var(--ease-out), box-shadow .25s var(--ease-out);
}
.viewer3d__poster:hover .viewer3d__play, .viewer3d__poster:focus-visible .viewer3d__play { transform: translateY(-2px); box-shadow: var(--shadow-lg); }
.viewer3d__play--soft { background: color-mix(in srgb, var(--surface) 90%, transparent); }
.viewer3d__play-dot {
  display: grid; place-items: center; width: 2.6rem; height: 2.6rem; flex: none;
  border-radius: var(--radius-full); background: var(--accent); color: var(--accent-ink);
}
.viewer3d__play-dot svg { width: 1.2rem; height: 1.2rem; }
.viewer3d__play-txt { display: grid; gap: 0.1rem; padding-right: var(--space-2xs); text-align: start; }
.viewer3d__play-txt strong { font-size: var(--step-0); font-weight: var(--weight-semibold); color: var(--fg); }
.viewer3d__play-txt small { font-size: var(--step--1); color: var(--fg-muted); }
@media (prefers-reduced-motion: no-preference) {
  .viewer3d__poster:not(.viewer3d__poster--empty) .viewer3d__play-dot { animation: v3d-pulse 2.6s var(--ease-soft) infinite; }
}
@keyframes v3d-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  50%      { box-shadow: 0 0 0 0.6rem color-mix(in srgb, var(--accent) 0%, transparent); }
}

/* Geladener iFrame / selbst-gehostetes 3D-Modell (<model-viewer>) */
.viewer3d__iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; background: var(--surface-2); z-index: 0; }
.viewer3d__mv { position: absolute; inset: 0; width: 100%; height: 100%; display: block; z-index: 1; background: transparent; --poster-color: transparent; }
/* Lazy-Poster (Div, kein Klick-Affordance) mit Lade-Spinner, bis das Modell gemountet ist. */
.viewer3d__poster--lazy { cursor: default; }
.viewer3d__spin {
  position: relative; z-index: 2; width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid color-mix(in srgb, var(--accent) 22%, transparent); border-top-color: var(--accent);
}
@media (prefers-reduced-motion: no-preference) { .viewer3d__spin { animation: v3d-spin 0.85s linear infinite; } }
@keyframes v3d-spin { to { transform: rotate(360deg); } }
/* Pause/Play der Auto-Rotation (per JS eingefuegt, sobald das Modell rotiert). */
.viewer3d__rotate {
  position: absolute; right: 0.7rem; bottom: 0.7rem; z-index: 4;
  font-size: var(--step--1); font-weight: var(--weight-semibold); color: var(--accent-ink);
  background: color-mix(in srgb, var(--accent) 88%, transparent);
  border: 1px solid color-mix(in srgb, #fff 28%, transparent);
  padding: 0.4em 0.85em; border-radius: var(--radius-full);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); box-shadow: var(--shadow-sm);
}
.viewer3d__rotate:hover { background: var(--accent); }
.viewer3d__radio--2d:checked ~ .viewer3d__stage .viewer3d__rotate { display: none; }

/* 2D/3D-Umschalter im SELBEN Feld: zwei versteckte Radios (3D = Default) steuern per
   CSS, was in der Bühne sichtbar ist. Sichtbare Bedienung = Segment-Control unten mittig.
   Reines CSS, per Tastatur bedienbar (Radio-Gruppe). */
.viewer3d__radio { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none; }

/* 2D-Grundriss füllt die Bühne. Fix: render_picture() umschliesst das Bild mit <picture>;
   picture{display:contents} nimmt es aus dem Sizing-Pfad, das <img> bekommt eine definite
   Höhe (Grid-Track minmax(0,1fr)) -> object-fit:contain letterboxt korrekt statt zu überlaufen. */
/* 2D-Grundriss als „Datenblatt": Plan (links) + Raumliste (rechts), frei schwebend.
   Plan-Sizing-Fix: render_picture() wrappt in <picture> -> display:contents + Grid
   minmax(0,1fr) + img height:100% -> object-fit contain (sonst läuft der Plan raus). */
.viewer3d__planlayer {
  position: absolute; inset: 0; z-index: 4; display: none;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); grid-template-rows: minmax(0, 1fr);
  gap: clamp(var(--space-sm), 2.4vw, var(--space-xl)); align-items: stretch;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg); padding: clamp(var(--space-md), 2.5vw, var(--space-lg));
}
.viewer3d__radio--2d:checked ~ .viewer3d__stage .viewer3d__planlayer { display: grid; }
.viewer3d__radio--2d:checked ~ .viewer3d__stage .viewer3d__mv { visibility: hidden; }
.viewer3d__plansheet {
  margin: 0; min-width: 0; min-height: 0; display: grid;
  grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr);
}
.viewer3d__plansheet picture { display: contents; }
.viewer3d__plansheet img { width: 100%; height: 100%; object-fit: contain; object-position: center; }

/* Raumliste (Legende) — Exposé-Datenblatt */
.viewer3d__legend { display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow: auto; }
.viewer3d__legend-title {
  margin: 0 0 var(--space-xs); display: inline-flex; align-items: center; gap: 0.4em;
  font-size: var(--step--1); font-weight: var(--weight-semibold); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--fg-subtle);
}
.viewer3d__legend-title svg { width: 1em; height: 1em; flex: none; color: var(--accent-600); }
.viewer3d__rooms { margin: 0; display: flex; flex-direction: column; }
.viewer3d__room {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.75em;
  padding: 0.5em 0; border-bottom: 1px solid var(--border);
}
.viewer3d__room dt { font-weight: var(--weight-medium); color: var(--fg); }
.viewer3d__room dd { margin: 0; font-family: var(--font-mono); font-size: var(--step--1); color: var(--fg-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.viewer3d__legend-total {
  margin-top: auto; display: flex; align-items: baseline; justify-content: space-between; gap: 0.5em;
  padding-top: var(--space-sm); border-top: 2px solid var(--accent);
}
.viewer3d__legend-total span { color: var(--fg-muted); font-size: var(--step--1); }
.viewer3d__legend-total strong { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--step-2); color: var(--accent-700); letter-spacing: var(--tracking-tight); }

@media (max-width: 720px) {
  .viewer3d__planlayer { grid-template-columns: minmax(0, 1fr); padding: clamp(var(--space-sm), 2.5vw, var(--space-md)); }
  .viewer3d__legend { display: none; }
}

/* Segment-Control als schwebende Pille — mittig UNTER dem Modell */
.viewer3d__seg {
  display: flex; width: max-content; max-width: 100%; margin: clamp(var(--space-sm), 3vw, var(--space-lg)) auto 0;
  padding: 3px; gap: 2px; border-radius: var(--radius-full);
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow-md);
}
.viewer3d__seg-i {
  display: inline-flex; align-items: center; gap: 0.4em; padding: 0.5em 1.1em; border-radius: var(--radius-full);
  font-size: var(--step--1); font-weight: var(--weight-semibold); color: var(--fg-muted); cursor: pointer;
  white-space: nowrap; user-select: none; transition: background .2s var(--ease-out), color .2s var(--ease-out);
}
.viewer3d__seg-i svg { width: 1em; height: 1em; flex: none; }
.viewer3d__radio--3d:checked ~ .viewer3d__seg .viewer3d__seg-i--3d,
.viewer3d__radio--2d:checked ~ .viewer3d__seg .viewer3d__seg-i--2d { background: var(--accent); color: var(--accent-ink); }
.viewer3d__radio:focus-visible ~ .viewer3d__seg { outline: 2px solid var(--accent); outline-offset: 3px; }

/* „Ziehen zum Drehen"-Hinweis (blendet sich nach kurzer Zeit aus) */
.viewer3d__hint {
  position: absolute; z-index: 5; left: clamp(var(--space-sm), 3vw, var(--space-md)); top: clamp(var(--space-sm), 3vw, var(--space-md));
  margin: 0; display: inline-flex; align-items: center; gap: 0.4em; padding: 0.35em 0.75em;
  border-radius: var(--radius-full); border: 1px solid var(--border); pointer-events: none;
  background: color-mix(in srgb, var(--surface) 82%, transparent); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  font-size: var(--step--1); color: var(--fg-subtle);
}
.viewer3d__hint svg { width: 1em; height: 1em; flex: none; color: var(--accent-600); transform: rotate(90deg); }
.viewer3d__radio--2d:checked ~ .viewer3d__stage .viewer3d__hint { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .viewer3d__hint { animation: v3d-hint 0.6s var(--ease-out) 6s forwards; }
}
@keyframes v3d-hint { to { opacity: 0; visibility: hidden; } }

/* Hinweiszeile */
.viewer3d__note {
  display: flex; align-items: center; gap: 0.5em; margin: 0; padding: var(--space-sm) var(--space-md);
  border-top: 1px solid var(--border); background: var(--surface-2);
  font-size: var(--step--1); color: var(--fg-subtle);
}
.viewer3d__note svg { width: 1em; height: 1em; flex: none; color: var(--accent-600); }

/* (Alte Eck-Vorschau/<dialog> entfernt — 2D liegt jetzt im selben Feld: .viewer3d__planlayer + Radio-Segment-Control.) */
