/* ==========================================================================
   Werkbüro24 — Design & KI-Services
   Dark, indigo-accented "Nocturne" system: soft blurple glow, animated
   depth (mesh gradient, aurora, particles, blobs, beams) behind a calm
   content grid. Type: Inter throughout.
   ========================================================================== */

/* Inter lokal eingebunden (kein Abruf von Google) */
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/f-39529051.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/f-56724408.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../fonts/f-39529051.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../fonts/f-56724408.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../fonts/f-39529051.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../fonts/f-56724408.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/f-39529051.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/f-56724408.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --color-bg: #18181B;
  --color-surface: #232326;
  --color-text: #FAFAFA;
  --color-accent: #4C7FE0;
  --color-accent-2: #6C93D8;
  --color-divider: color-mix(in srgb, #FAFAFA 16%, transparent);

  --color-neutral-100: #f5f6fa;
  --color-neutral-800: #3d3d42;
  --color-neutral-900: #2a2a2d;

  --color-accent-100: #eef3ff;
  --color-accent-300: #c3d4f5;
  --color-accent-700: #33517e;
  --color-accent-800: #253a5c;
  --color-accent-900: #1a2740;

  --color-accent-2-100: #eef3ff;
  --color-accent-2-800: #2a3a56;

  --color-section: #1f2c4d;
  --color-section-glow: #2c3d6b;

  --font-heading: "Inter", system-ui, sans-serif;
  --font-heading-weight: 500;
  --font-body: "Inter", system-ui, sans-serif;

  --space-1: 2.8px;
  --space-2: 5.6px;
  --space-3: 8.4px;
  --space-4: 11.2px;
  --space-6: 16.8px;
  --space-8: 22.4px;

  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 14px;

  --shadow-sm: 0 0 0 1px #3f424d;
  --shadow-md: 0 0 0 1px #595d6c, 0 6px 18px rgba(0,0,0,0.55);
  --shadow-lg: 0 0 0 1px #9397ab, 0 16px 40px rgba(0,0,0,0.65);

  /* premium easing — stronger than the CSS built-ins */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
}

*, *::before, *::after { box-sizing: border-box; }
:root { color-scheme: dark; }
html {
  scroll-behavior: smooth;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--color-text) 25%, transparent) transparent;
}
body {
  margin: 0; overflow-x: hidden;
  background: var(--color-bg); color: var(--color-text);
  font-family: var(--font-body); font-size: 15px; line-height: 1.55; font-weight: 400;
}
body.nav-open { overflow: hidden; }
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  line-height: 1.12; letter-spacing: -0.015em; margin: 0 0 var(--space-2);
  text-wrap: balance;
}
h1 { font-size: 42px; line-height: 1.05; letter-spacing: -0.025em; }
h2 { font-size: 32px; line-height: 1.08; letter-spacing: -0.018em; }
h3 { font-size: 20px; line-height: 1.25; letter-spacing: -0.005em; }
h4 { line-height: 1.3; letter-spacing: 0; }
h6 { font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase; }
p { margin: 0 0 var(--space-3); text-wrap: pretty; }
a { color: var(--color-accent-300); text-decoration: none; text-underline-offset: 3px; }
a:hover { color: var(--color-accent); }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background-color: color-mix(in srgb, var(--color-text) 25%, transparent);
  border-radius: 8px; border: 2px solid var(--color-bg); background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background-color: var(--color-accent); }
@media (pointer: coarse), (max-width: 860px) {
  /* The grey translucent bar the user saw appear during scroll and fade
     out afterwards on their phone is this custom scrollbar thumb — on a
     touch device there's no cursor to hover a thin desktop-style
     scrollbar, so the browser instead renders it as a transient overlay,
     10px wide, right where a native (much subtler) scroll indicator would
     normally go. Hiding our custom one on coarse-pointer (touch) devices
     lets the platform's own minimal indicator show instead. Also gated on
     max-width as a fallback in case a given mobile browser doesn't report
     pointer:coarse reliably. */
  html { scrollbar-width: none; }
  ::-webkit-scrollbar { display: none; width: 0; height: 0; }
}

.skip-link {
  position: absolute; left: 12px; top: -48px; z-index: 10001;
  background: var(--color-accent); color: var(--color-bg);
  padding: 10px 16px; border-radius: var(--radius-md); font-weight: 600;
  transition: top .2s var(--ease-out);
}
.skip-link:focus { top: 12px; }

.container { max-width: 1400px; margin: 0 auto; padding: 0 clamp(20px, 4vw, 56px); position: relative; z-index: 1; }

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

/* ── loading sequence ───────────────────────────────────────────────────── */
.loader {
  position: fixed; inset: 0; z-index: 10000; background: var(--color-bg);
  display: flex; align-items: center; justify-content: center; overflow: hidden;
  opacity: 1; transition: opacity .5s var(--ease-in-out);
}
.loader.is-done { opacity: 0; pointer-events: none; }
.loader__inner { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.loader__mark { font-family: var(--font-heading); font-size: 22px; letter-spacing: -0.02em; color: var(--color-text); opacity: 0; animation: loaderFadeIn .5s var(--ease-out) .1s forwards; }
.loader__bar { width: 160px; height: 2px; border-radius: 2px; background: var(--color-divider); overflow: hidden; opacity: 0; animation: loaderFadeIn .5s var(--ease-out) .25s forwards; }
.loader__bar-fill { width: 100%; height: 100%; background: var(--color-accent); transform: scaleX(0); transform-origin: left; transition: transform 1s var(--ease-in-out); }
.loader__sweep {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: linear-gradient(100deg, transparent 40%, color-mix(in srgb, var(--color-accent) 22%, transparent) 50%, transparent 60%);
  transform: translateX(-100%);
}
.loader__sweep.is-sweeping { animation: loaderSweep .7s var(--ease-in-out) forwards; }
@media (prefers-reduced-motion: reduce) {
  .loader__mark, .loader__bar { opacity: 1; animation: none; }
  .loader__bar-fill { transition: none; }
}

/* ── buttons / tags / cards / inputs (shared component classes) ───────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 14px; line-height: 1.2; color: var(--color-text);
  background: transparent; border: 1px solid transparent;
  padding: var(--space-2) calc(var(--space-3) * 1.2);
  border-radius: var(--radius-md);
  transition: transform 160ms var(--ease-out), background 200ms var(--ease-out), border-color 200ms var(--ease-out), box-shadow 200ms var(--ease-out);
}
.btn:active { transform: scale(0.97); }
.btn__arrow { display: inline-block; transition: transform 220ms var(--ease-out); }
.btn:hover .btn__arrow { transform: translateX(3px); }
.btn-secondary:hover .btn__arrow { transform: translateY(2px); }
.btn-primary { color: var(--color-accent); border-color: var(--color-accent); }
.btn-primary:hover { background: color-mix(in srgb, var(--color-accent) 12%, transparent); color: var(--color-accent); box-shadow: 0 0 0 1px var(--color-accent), 0 0 24px -6px color-mix(in srgb, var(--color-accent) 70%, transparent); }
.btn-secondary { border-color: var(--color-divider); }
.btn-secondary:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); color: var(--color-text); border-color: color-mix(in srgb, var(--color-text) 40%, transparent); }

.input {
  width: 100%; min-height: 36px; max-height: 120px; padding: 8px 10px; font: inherit;
  font-size: 14px; line-height: 1.4; color: var(--color-text); caret-color: var(--color-accent);
  background: var(--color-surface);
  border: 1px solid var(--color-divider); border-radius: var(--radius-md);
  transition: border-color 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
  resize: none; overflow-y: auto;
}
.input:hover { border-color: color-mix(in srgb, var(--color-text) 45%, transparent); }
.input:focus-visible { border-color: var(--color-accent); outline-offset: 0; box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 20%, transparent); }

.card { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-surface); }
.card-title { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 17px; line-height: 1.2; margin: 0; }
.card-body { margin: 0; font-size: 13px; opacity: 0.8; flex: 1; }
.elev-sm { box-shadow: var(--shadow-sm); }
.elev-md { box-shadow: var(--shadow-md); }

.tag { display: inline-flex; align-items: center; width: fit-content; font-size: 11px; letter-spacing: 0.02em; padding: 3px 10px; border-radius: calc(var(--radius-md) * 0.75); white-space: nowrap; }
.tag-accent { background: var(--color-accent-800); color: var(--color-accent-100); }
.tag-accent-2 { background: var(--color-accent-2-800); color: var(--color-accent-2-100); }
.tag-neutral { background: var(--color-neutral-800); color: var(--color-neutral-100); }
.tag-outline { border: 1px solid var(--color-accent); color: var(--color-accent); }

.dot-pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--color-accent); display: inline-block; flex: none; animation: pulseDot 2s var(--ease-in-out) infinite; }
.eyebrow { color: var(--color-accent); }

/* ── background decor ──────────────────────────────────────────────────── */
.bg-decor { position: fixed; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
.parallax-layer { position: absolute; inset: 0; will-change: transform; }

.bg-mesh {
  position: absolute; inset: -10%;
  background:
    radial-gradient(38% 32% at 18% 22%, color-mix(in srgb, var(--color-accent) 30%, transparent), transparent 70%),
    radial-gradient(34% 30% at 82% 18%, color-mix(in srgb, var(--color-accent-2) 24%, transparent), transparent 72%),
    radial-gradient(40% 36% at 70% 78%, color-mix(in srgb, var(--color-section-glow) 55%, transparent), transparent 70%),
    radial-gradient(30% 30% at 20% 85%, color-mix(in srgb, var(--color-accent) 18%, transparent), transparent 72%);
  filter: blur(4px);
  animation: meshDrift 46s var(--ease-in-out) infinite;
  opacity: .85;
  will-change: transform;
}
.bg-aurora {
  position: absolute; inset: -20%;
  background: conic-gradient(from 0deg at 50% 30%,
    color-mix(in srgb, var(--color-accent) 16%, transparent),
    transparent 22%, transparent 55%,
    color-mix(in srgb, var(--color-accent-2) 14%, transparent) 68%,
    transparent 85%, color-mix(in srgb, var(--color-accent) 12%, transparent) 100%);
  filter: blur(22px);
  mix-blend-mode: screen;
  opacity: .4;
  animation: auroraSpin 90s linear infinite;
  will-change: transform;
}
.blob { position: absolute; filter: blur(10px); will-change: transform; }
.blob--a { width: 520px; height: 520px; left: -160px; top: -120px; background: radial-gradient(circle, var(--color-accent-700), transparent 70%); opacity: .5; border-radius: 42% 58% 63% 37% / 45% 52% 48% 55%; animation: blobDriftA 16s var(--ease-in-out) infinite; }
.blob--b { width: 460px; height: 460px; right: -140px; top: 420px; background: radial-gradient(circle, var(--color-accent-2-800), transparent 70%); opacity: .4; border-radius: 61% 39% 46% 54% / 55% 48% 52% 45%; animation: blobDriftB 19s var(--ease-in-out) infinite; }
.blob--c { width: 380px; height: 380px; left: 38%; top: 60px; background: radial-gradient(circle, var(--color-accent-700), transparent 72%); opacity: .28; filter: blur(16px); border-radius: 55% 45% 40% 60% / 48% 55% 45% 52%; animation: blobDriftB 23s var(--ease-in-out) infinite; }
.bg-grid-wrap {
  position: absolute; left: 0; right: 0; bottom: -10%; height: 60%; overflow: hidden;
  mask-image: linear-gradient(to top, black, transparent 85%);
  -webkit-mask-image: linear-gradient(to top, black, transparent 85%);
  opacity: .3;
}
.bg-grid {
  position: absolute; left: -56px; top: -56px; right: -56px; bottom: -56px;
  background-image: linear-gradient(color-mix(in srgb, var(--color-accent) 14%, transparent) 1px, transparent 1px),
                     linear-gradient(90deg, color-mix(in srgb, var(--color-accent) 14%, transparent) 1px, transparent 1px);
  background-size: 56px 56px;
  animation: gridDrift 18s linear infinite;
  will-change: transform;
}
.beam { position: absolute; width: 2px; filter: blur(2px); will-change: transform, opacity; }
.beam--a { top: 8%; left: 12%; height: 340px; background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--color-accent) 70%, transparent), transparent); --rot: 18deg; animation: beamMove 12s var(--ease-in-out) infinite; }
.beam--b { top: 2%; right: 18%; height: 260px; background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--color-accent-2) 60%, transparent), transparent); --rot: -14deg; animation: beamMove 15s var(--ease-in-out) infinite reverse; }
.bg-particles { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: .7; }
.bg-particles--ambient { opacity: .25; }
.bg-noise-wrap { position: absolute; inset: -10px; overflow: hidden; opacity: .035; mix-blend-mode: overlay; }
.bg-noise {
  position: absolute; inset: -120px;
  background-repeat: repeat; background-size: 120px 120px;
  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>');
  animation: noiseDrift 9s steps(6) infinite;
  will-change: transform;
}

/* ── reveal on scroll ───────────────────────────────────────────────────── */
[data-reveal-item] {
  opacity: 0; transform: translateY(26px) scale(.98); filter: blur(3px);
  transition: opacity .8s var(--ease-out), transform .8s var(--ease-out), filter .8s var(--ease-out);
}
/* Cards get `is-visible` from the same IntersectionObserver as their
   parent `[data-reveal]` section, but each is observed independently
   against its own (small) bounding box, while the section is observed
   against its own (much taller, heading + full grid) bounding box.
   A short card can cross its own 25% threshold — and so get
   `is-visible` — well before the tall section crosses its own 25%,
   since 25% of a small box is a lot less scroll distance than 25% of a
   large one. That let cards visually fade in before the heading above
   them, which hadn't started its own reveal yet. Requiring the ancestor
   section's `is-visible` too (not just the item's own) means the card's
   CSS transition only fires once the section — and so the heading,
   which reveals off that same class — has already become visible. */
[data-reveal].is-visible [data-reveal-item].is-visible { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
.projects__grid .project:nth-child(2) { transition-delay: .1s; }
.projects__grid .project:nth-child(3) { transition-delay: .2s; }

.reveal-child {
  opacity: 0; transform: translateY(18px); filter: blur(2px);
  transition: opacity .7s var(--ease-out), transform .7s var(--ease-out), filter .7s var(--ease-out);
  transition-delay: var(--stagger-delay, 0ms);
}
[data-reveal].is-visible .reveal-child { opacity: 1; transform: translateY(0); filter: blur(0); }

.reveal-scale {
  opacity: 0; transform: translateX(70px);
  transition: opacity .6s var(--ease-out), transform .6s var(--ease-out), box-shadow .3s var(--ease-out);
}
/* the big tile leads from the left, the other three follow in from the
   right — they converge into the resting grid instead of each tile just
   fading up in place. */
.stats__tile--big.reveal-scale { transform: translateX(-78px); }
[data-reveal].is-visible .reveal-scale { opacity: 1; transform: translateX(0); }
@media (max-width: 720px) {
  /* The ±70/78px horizontal pre-reveal offset has no room to work with once
     a tile already spans the full mobile grid width — it pushed tiles past
     the viewport edge before they were ever scrolled into view, inflating
     the whole page's horizontal scroll range for the entire session (real
     device bug: the page's right edge sat mid-screen everywhere, not just
     near this section). Vertical motion carries the same "settles into
     place" feel without any horizontal-overflow risk. */
  .reveal-scale, .stats__tile--big.reveal-scale { transform: translateY(20px); }
}
.stats__grid .reveal-scale:nth-child(1) { transition-delay: 320ms; }
.stats__grid .reveal-scale:nth-child(2) { transition-delay: 390ms; }
.stats__grid .reveal-scale:nth-child(3) { transition-delay: 460ms; }
.stats__grid .reveal-scale:nth-child(4) { transition-delay: 530ms; }

.demo-console[data-reveal-delay="1"] { opacity: 0; transform: translateY(24px) scale(.98); filter: blur(3px); transition: opacity .8s var(--ease-out) .1s, transform .8s var(--ease-out) .1s, filter .8s var(--ease-out) .1s; }
.demo-console[data-reveal-delay="1"].is-visible { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }

/* SVG draw-on-reveal */
.draw-path { fill: none; stroke: var(--color-accent); stroke-width: 1.4; opacity: .55; transition: stroke-dashoffset 1s var(--ease-out); }
circle.draw-path { fill: color-mix(in srgb, var(--color-accent) 12%, transparent); }
.services__draw { width: 120px; height: 80px; flex: none; opacity: .8; }

/* ── header / nav ───────────────────────────────────────────────────────── */
.site-header {
  position: sticky; top: 0; z-index: 10; backdrop-filter: blur(14px);
  background: transparent; border-bottom: 1px solid transparent;
  transition: background .3s var(--ease-out), border-color .3s var(--ease-out);
}
.site-header.is-scrolled { background: color-mix(in srgb, var(--color-bg) 78%, transparent); border-bottom-color: var(--color-divider); box-shadow: 0 1px 0 color-mix(in srgb, #fff 5%, transparent); }
.site-header__inner { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; padding-block: var(--space-3); }
.brand { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 18px; color: var(--color-text); }
.brand:hover { color: var(--color-text); }
.accent-dot { color: var(--color-accent); }
.nav-desktop { display: flex; gap: 22px; flex-wrap: wrap; margin-left: auto; align-items: center; flex-shrink: 0; }
.nav-desktop a:not(.btn) { position: relative; color: inherit; font-size: 14px; padding-bottom: 2px; }
.nav-desktop a:not(.btn) span { position: relative; }
.nav-desktop a:not(.btn)::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
  background: var(--color-accent); transform: scaleX(0); transform-origin: left;
  transition: transform 220ms var(--ease-out);
}
.nav-desktop a:not(.btn):hover { color: var(--color-accent); }
.nav-desktop a:not(.btn):hover::after { transform: scaleX(1); }

.nav-toggle {
  display: none; flex-direction: column; justify-content: center; gap: 5px;
  width: 40px; height: 40px; margin-left: auto; padding: 0; border: none; background: none; cursor: pointer;
}
.nav-toggle__bar {
  width: 20px; height: 2px; margin: 0 auto; border-radius: 2px; background: var(--color-text);
  transition: transform .3s var(--ease-drawer), opacity .2s var(--ease-out);
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.nav-drawer {
  position: fixed; inset: 0; z-index: 500;
  background: color-mix(in srgb, var(--color-bg) 97%, transparent);
  backdrop-filter: blur(20px);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; visibility: hidden; transform: translateY(-8px);
  transition: opacity .35s var(--ease-drawer), transform .35s var(--ease-drawer), visibility 0s linear .35s;
}
.nav-drawer.is-open {
  opacity: 1; visibility: visible; transform: translateY(0);
  transition: opacity .35s var(--ease-drawer), transform .35s var(--ease-drawer), visibility 0s linear;
}
.nav-drawer__nav { display: flex; flex-direction: column; align-items: center; gap: 28px; }
.nav-drawer__nav a:not(.btn) { color: var(--color-text); font-family: var(--font-heading); font-size: 26px; font-weight: 600; }
.nav-drawer__nav a:not(.btn):hover { color: var(--color-accent); }
.nav-drawer__cta { margin-top: 12px; }

/* ── hero ───────────────────────────────────────────────────────────────── */
.hero { position: relative; isolation: isolate; padding-block: clamp(30px, 6vw, 72px) clamp(40px, 6vw, 64px); }
.hero__grid { position: relative; z-index: 1; display: grid; grid-template-columns: .74fr 1.26fr; gap: clamp(24px, 5vw, 48px); align-items: start; }
.hero__content { min-width: 0; }
.hero__title {
  font-size: clamp(34px, 5.2vw, 58px); margin-top: 14px;
  background: linear-gradient(100deg, var(--color-text) 20%, var(--color-accent-300) 45%, var(--color-accent) 55%, var(--color-text) 80%);
  background-size: 200% auto; -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: gradientShift 10s var(--ease-in-out) infinite;
}
h2 {
  background: linear-gradient(100deg, var(--color-text) 30%, var(--color-accent-300) 60%, var(--color-text) 90%);
  background-size: 200% auto; -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: gradientShift 12s var(--ease-in-out) infinite;
}
.hero__lede { font-size: 16px; opacity: .8; max-width: 46ch; margin-top: 6px; }
.hero__actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 26px; }
.hero__badges { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 22px; }
.hero__badges .tag { display: inline-flex; align-items: center; gap: 6px; }
.float-tag { animation: floatTag 6.5s var(--ease-in-out) infinite; will-change: transform; }
.float-tag--d1 { animation-duration: 7.2s; animation-delay: .3s; }
.float-tag--d2 { animation-duration: 6.8s; animation-delay: .6s; }

.demo-console {
  padding: 14px; overflow: hidden; position: relative;
  background: color-mix(in srgb, var(--color-surface) 88%, transparent);
  backdrop-filter: blur(18px);
  border: 1px solid color-mix(in srgb, #fff 8%, transparent);
  box-shadow: var(--shadow-md), 0 0 60px -20px color-mix(in srgb, var(--color-accent) 45%, transparent), inset 0 1px 0 color-mix(in srgb, #fff 6%, transparent);
  will-change: transform;
  /* Starts as a compact widget (header still comfortable, not cramped) and
     grows to its full working width only once the AI actually starts —
     same beat as the 3-way split below, so the whole console reads as one
     continuous "opening up" motion instead of two unrelated animations. */
  max-width: 560px; justify-self: end;
  transition: max-width .8s var(--ease-in-out);
}
.demo-console.is-expanded { max-width: 100%; }
@media (max-width: 860px) { .demo-console { max-width: none; justify-self: stretch; } }
.chat-card__spot { position: absolute; inset: 0; pointer-events: none; }
.demo-console__top {
  display: grid; grid-template-columns: 1fr 0fr 0fr; gap: 0;
  transition: grid-template-columns .8s var(--ease-in-out), gap .8s var(--ease-in-out);
}
.demo-console__top.is-split { grid-template-columns: 1.25fr 1fr 0.95fr; gap: 10px; }
.demo-chat { display: flex; flex-direction: column; border-radius: var(--radius-md); background: color-mix(in srgb, var(--color-bg) 35%, transparent); overflow: hidden; position: relative; }
.chat-card__scan { position: absolute; top: 0; left: 0; width: 40%; height: 1px; background: linear-gradient(90deg, transparent, var(--color-accent), transparent); animation: scanline 3.5s linear infinite; }
.chat-card__header { position: relative; padding: 12px 14px; border-bottom: 1px solid var(--color-divider); display: flex; align-items: center; gap: 8px; font-size: 12px; opacity: .85; }
.chat-card__live { margin-left: auto; font-size: 10px; letter-spacing: .05em; text-transform: uppercase; color: var(--color-accent); border: 1px solid color-mix(in srgb, var(--color-accent) 55%, transparent); border-radius: 20px; padding: 2px 8px; }
.chat-card__messages { position: relative; padding: 12px 14px 4px; display: flex; flex-direction: column; gap: 10px; min-height: 150px; max-height: 260px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--color-text) 25%, transparent) transparent; }
.chat-msg { display: flex; gap: 8px; animation: msgIn .3s var(--ease-out) both; }
.chat-msg--bot { justify-content: flex-start; align-items: flex-start; }
.chat-msg--user { justify-content: flex-end; }
.chat-msg__bubble { max-width: 78%; padding: 8px 12px; border-radius: 12px; font-size: 13.5px; line-height: 1.4; overflow-wrap: break-word; word-break: break-word; }
.chat-msg--bot .chat-msg__bubble { background: var(--color-surface); box-shadow: var(--shadow-sm); }
.chat-msg--user .chat-msg__bubble { background: var(--color-accent-800); color: var(--color-accent-100); }
.chat-avatar {
  flex: none; width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center;
  font-size: 11px; color: var(--color-accent-100);
  background: linear-gradient(135deg, var(--color-accent), var(--color-accent-2));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 50%, transparent), 0 0 14px -2px color-mix(in srgb, var(--color-accent) 70%, transparent);
  animation: avatarPulse 2.4s var(--ease-in-out) infinite;
}
.chat-card__typing { position: relative; margin: 0 16px 10px; display: none; align-items: center; gap: 8px; }
.chat-card__typing:not([hidden]) { display: flex; animation: msgIn .25s var(--ease-out) both; }
.chat-card__typing-dots { display: inline-flex; gap: 4px; padding: 8px 12px; border-radius: 12px; background: var(--color-surface); box-shadow: var(--shadow-sm); }
.chat-card__typing-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--color-accent-300); font-style: normal; animation: typeDots 1.2s ease-in-out infinite; }
.chat-card__typing-dots i:nth-child(2) { animation-delay: .15s; }
.chat-card__typing-dots i:nth-child(3) { animation-delay: .3s; }
.chat-card__typing-label {
  font-size: 11.5px; line-height: 1.35; opacity: .6;
  transition: color .25s var(--ease-out), opacity .25s var(--ease-out);
  /* The actual cause of the hero shifting while the demo plays: status
     labels vary a lot in length ("Erledigt" vs. "CRM & E-Mail-System
     werden verknüpft …"), and on a narrow card the longer ones wrap to a
     second line while the short ones don't — that's the height change,
     not the typing indicator appearing/disappearing (which was already
     fixed earlier). Reserving two lines' worth of height up front means a
     short label just leaves the second line blank instead of the row
     shrinking and the card "bouncing" back down. */
  min-height: calc(1.35em * 2);
  display: flex; align-items: center;
}
.chat-card__typing.is-done .chat-card__typing-dots i { animation: none; opacity: 1; background: var(--color-accent-300); }
.chat-card__typing.is-done .chat-card__typing-label { color: var(--color-accent-300); opacity: 1; }
.chat-card__input-row { position: relative; display: flex; align-items: flex-end; gap: 8px; padding: 10px 14px; border-top: 1px solid var(--color-divider); }
.chat-card__input-row .input { flex: 1; }

/* ── demo canvas (ChatGPT-Canvas-style workspace panel) ─────────────────── */
.demo-canvas, .demo-overview {
  display: flex; flex-direction: column; border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--color-bg) 45%, transparent);
  border: 1px solid color-mix(in srgb, #fff 6%, transparent);
  opacity: 0; transform: translateX(14px); filter: blur(3px);
  transition: opacity .5s var(--ease-out), transform .5s var(--ease-out), filter .5s var(--ease-out), max-height .5s var(--ease-out);
  overflow: hidden; min-width: 0;
  /* At 0fr width these still lay out their real content (KPI grid, donut
     legend, canvas placeholder text) — squeezed that narrow, it wraps into
     a very tall column and, per CSS Grid's row-sizing rules, that height
     still inflates the shared row even though nothing is visibly showing.
     Capping it to 0 until the split happens keeps the compact starting
     card genuinely compact instead of pre-reserving space for content
     nobody can see yet. */
  max-height: 0;
}
.demo-canvas.is-active, .demo-overview.is-active { opacity: 1; transform: translateX(0); filter: blur(0); max-height: 640px; }
.demo-overview { transition-delay: .08s; }
.demo-canvas__header {
  display: flex; align-items: center; gap: 7px; padding: 12px 14px;
  border-bottom: 1px solid var(--color-divider); font-size: 12px; opacity: .85;
}
.demo-canvas__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--color-accent-2); animation: pulseDot 2.2s var(--ease-in-out) infinite; flex: none; }
.demo-canvas__body { padding: 12px 14px; font-size: 12.5px; max-height: 300px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--color-text) 25%, transparent) transparent; }
.demo-canvas__placeholder { opacity: .45; font-style: italic; }
.canvas-line {
  display: flex; align-items: center; gap: 6px; font-family: var(--font-heading);
  color: var(--color-accent-300); margin-bottom: 8px; min-height: 16px;
}
.canvas-line__cursor {
  display: inline-block; width: 6px; height: 13px; background: var(--color-accent);
  animation: cursorBlink 1s steps(1) infinite;
}
.canvas-heading {
  font-family: var(--font-heading); font-weight: 600; font-size: 13px; color: var(--color-text);
  margin: 14px 0 6px; opacity: 0; transform: translateY(6px);
  animation: canvasIn .4s var(--ease-out) forwards;
}
.canvas-heading:first-child { margin-top: 0; }
.canvas-check {
  display: flex; align-items: center; gap: 7px; font-size: 12.5px; opacity: 0;
  padding: 3px 0; transform: translateY(4px);
  animation: canvasIn .4s var(--ease-out) forwards;
}
.canvas-check__mark {
  flex: none; width: 15px; height: 15px; border-radius: 50%; display: grid; place-items: center;
  font-size: 9px; background: var(--color-accent-800); color: var(--color-accent-100);
  transform: scale(.5); opacity: 0; transition: transform .3s var(--ease-out), opacity .3s var(--ease-out);
}
.canvas-check.is-checked .canvas-check__mark { transform: scale(1); opacity: 1; }

/* ── collapsible reveal wrap: KPI strip + lower row start closed, open
   once the story begins (so the console reads as "chat only" at first) ─── */
.demo-reveal-wrap {
  display: grid; grid-template-rows: 0fr; margin-top: 0;
  transition: grid-template-rows .7s var(--ease-in-out), margin-top .7s var(--ease-in-out);
}
.demo-reveal-wrap.is-open { grid-template-rows: 1fr; margin-top: 10px; }
.demo-reveal-wrap__inner { overflow: hidden; opacity: 0; transition: opacity .5s var(--ease-out) .15s; }
.demo-reveal-wrap.is-open .demo-reveal-wrap__inner { opacity: 1; }

/* ── overview column: KPI grid + donut chart ───────────────────────────── */
.demo-overview__body { padding: 10px 12px; display: flex; flex-direction: column; gap: 12px; }
.demo-console__kpis { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.demo-kpi {
  background: var(--color-surface); border-radius: var(--radius-md); padding: 10px 10px 9px; min-width: 0;
  transition: box-shadow .3s var(--ease-out), transform .3s var(--ease-out);
}
.demo-kpi__top { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 2px 6px; }
.demo-kpi__label { font-size: 10px; opacity: .65; letter-spacing: .01em; line-height: 1.25; min-width: 0; overflow-wrap: anywhere; }
.demo-kpi__delta { font-size: 9.5px; font-weight: 600; color: var(--color-accent-300); flex: none; white-space: nowrap; margin-left: auto; opacity: 0; transition: opacity .3s var(--ease-out); }
.demo-kpi.is-revealed .demo-kpi__delta { opacity: 1; }
.demo-kpi__delta--down { color: var(--color-accent-2); }
.demo-kpi__value { display: block; font-family: var(--font-heading); font-weight: 600; font-size: 19px; font-variant-numeric: tabular-nums; margin-top: 2px; }
.demo-kpi__spark { display: block; width: 100%; height: 16px; margin-top: 4px; overflow: visible; }
.demo-kpi__spark polyline { fill: none; stroke: var(--color-accent-300); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; opacity: .8; transition: stroke-dashoffset 1s var(--ease-out); }
.demo-kpi.is-updated { animation: kpiPop .5s var(--ease-out); }

.demo-donut__row { display: flex; align-items: center; gap: 14px; }
.demo-donut__svg { width: 76px; height: 76px; flex: none; transform: rotate(-90deg); opacity: 0; transform-origin: center; transition: opacity .5s var(--ease-out), transform .5s var(--ease-out); }
.demo-donut.is-active .demo-donut__svg { opacity: 1; transform: rotate(-90deg) scale(1); }
.demo-donut__seg { fill: none; stroke-width: 11; }
.demo-donut__legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; font-size: 10.5px; opacity: .85; }
.demo-donut__legend b { font-weight: 600; margin-left: 4px; opacity: .7; }
.demo-donut__dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--c); margin-right: 6px; }

/* ── shared timeline card: activity feed + workflow, as horizontal
   node chains — one tile, two stacked rows ────────────────────────────── */
.demo-timeline-card { background: color-mix(in srgb, var(--color-bg) 35%, transparent); border-radius: var(--radius-md); }
.demo-timeline-row { padding: 12px 14px; }
.demo-timeline-divider { height: 1px; background: var(--color-divider); margin: 0 14px; }
.demo-feed__header { display: flex; align-items: center; gap: 8px; font-size: 11px; letter-spacing: .04em; text-transform: uppercase; opacity: .6; margin-bottom: 12px; }

/* overflow-x:auto forces overflow-y to a non-visible value too (per the
   CSS overflow spec, visible can't pair with a non-visible axis) — that
   was clipping the active-node glow at the row's top/bottom edge. The
   padding gives the glow's blur radius room so it isn't cut off. */
.demo-hline { display: flex; align-items: flex-start; overflow-x: auto; padding: 18px 6px 6px; margin: -6px -6px 0; }
.demo-hnode {
  display: flex; flex-direction: column; align-items: center; gap: 6px; flex: none; width: 84px;
  opacity: .4; transition: opacity .3s var(--ease-out);
}
.demo-hnode.is-active { opacity: 1; }
.demo-hnode__icon {
  width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center;
  background: var(--color-surface); color: var(--color-accent-300);
  transition: box-shadow .3s var(--ease-out), transform .3s var(--ease-out), background .3s var(--ease-out), color .3s var(--ease-out);
}
.demo-hnode__icon svg { width: 16px; height: 16px; flex: none; }
.demo-hnode.is-active .demo-hnode__icon {
  background: var(--color-accent-800); color: var(--color-accent-100);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 20%, transparent), 0 0 16px -2px color-mix(in srgb, var(--color-accent) 70%, transparent);
  transform: scale(1.08);
}
.demo-hnode--done .demo-hnode__icon { background: color-mix(in srgb, var(--color-accent) 25%, var(--color-surface)); color: var(--color-accent-100); }
.demo-hnode__time { font-size: 9px; opacity: .5; font-variant-numeric: tabular-nums; min-height: 11px; }
.demo-hnode__label { font-size: 10px; text-align: center; opacity: .8; line-height: 1.25; }
.demo-hconnector { flex: 1; min-width: 20px; height: 1px; margin: 17px 4px 0; border-top: 2px dotted var(--color-divider); position: relative; }
.demo-hconnector--flow::after {
  content: ""; position: absolute; top: -3px; left: 0; width: 6px; height: 6px; border-radius: 50%;
  background: var(--color-accent-300); box-shadow: 0 0 6px 1px color-mix(in srgb, var(--color-accent) 70%, transparent);
  animation: hpipeFlow 3s linear infinite;
}
.demo-hline--flow .demo-hconnector:nth-of-type(4)::after { animation-delay: -.6s; }
.demo-hline--flow .demo-hconnector:nth-of-type(6)::after { animation-delay: -1.2s; }
.demo-hline--flow .demo-hconnector:nth-of-type(8)::after { animation-delay: -1.8s; }
.demo-hline--flow .demo-hconnector:nth-of-type(10)::after { animation-delay: -2.4s; }

@media (max-width: 980px) {
  /* No scroll anchoring inside the hero while the demo grows, and no
     animated blur on the panels (expensive to repaint during a scroll). */
  .hero, .demo-console { overflow-anchor: none; }
  .demo-canvas, .demo-overview { filter: none; transition: opacity .5s var(--ease-out), transform .5s var(--ease-out), max-height .5s var(--ease-out); }
  .demo-console__top, .demo-console__top.is-split { grid-template-columns: 1fr; }
  .demo-canvas, .demo-overview { transform: translateY(10px); }
  .demo-canvas.is-active, .demo-overview.is-active { transform: translateY(0); }
}
@media (max-width: 600px) {
  /* Stacked full-width KPI/donut panel gets very tall with all 4 cards
     plus the donut — trims to the two headline metrics on phones. */
  .demo-kpi:nth-child(n+3) { display: none; }
  .demo-donut { display: none; }

  /* Wissensbasis panel dropped entirely on phones — it's the tallest of
     the three stacked panels and adds the least at this size; the chat
     and the overview KPIs already carry the story. */
  .demo-canvas { display: none; }

  /* Both horizontal node chains (Live-Aktivität + Workflow) need to read
     in one glance without a sideways swipe. Nodes, icons and connectors
     shrink together so a 5-node row fits the card width outright instead
     of spilling into `.demo-hline`'s overflow-x scroll. */
  .demo-hline { padding-left: 3px; padding-right: 3px; }
  .demo-hnode { width: 48px; min-width: 0; gap: 3px; }
  .demo-hnode__icon { width: 25px; height: 25px; }
  .demo-hnode__icon svg { width: 13px; height: 13px; }
  .demo-hnode__time { font-size: 7.5px; min-height: 9px; }
  .demo-hnode__label { font-size: 9px; overflow-wrap: anywhere; word-break: break-word; }
  .demo-hconnector { flex: 0 1 8px; min-width: 4px; margin: 12px 1.5px 0; }

  /* The workflow row's "Prüfung (optional)" step is, by its own label,
     the one skippable node — dropped first so the remaining 5 nodes get
     more of the freed-up width instead of everyone shrinking further. */
  .demo-hnode--opt, .demo-hconnector--opt { display: none; }

  /* Measured root cause of a real-device bug: the auto-playing hero demo
     accumulates chat bubbles and KPI cards over ~30s, and both containers
     grow in normal document flow while that plays out — confirmed via the
     Layout Instability API (PerformanceObserver({type:'layout-shift'})),
     which recorded dozens of shifts sourced from exactly these two elements
     across the whole story, not tied to any particular scroll position.
     Every growth step pushes `.hero`'s height, which shifts every section
     below it on the page — read by the user as the entire rest of the site
     "hooking and releasing" while scrolling, regardless of where they'd
     scrolled to. Reserving each container's own already-known final size
     up front means the demo still visibly fills in over time, but within
     space that was already there — nothing below it moves again. */
  .chat-card__messages { min-height: 260px; }
  .demo-overview.is-active { min-height: 172px; }

  /* Third source of the same bug, measured the same way: the "KI denkt
     nach…" typing indicator toggles the `hidden` attribute on and off
     several times per story step, and since its default is `display:none`
     it adds/removes its own ~31px of height from `#chatCard` on every
     toggle. Keeping it always in flow (visibility/opacity instead of
     display) reserves that space permanently, so appearing and
     disappearing no longer moves anything below it. */
  .chat-card__typing { display: flex; visibility: hidden; opacity: 0; }
  .chat-card__typing:not([hidden]) { visibility: visible; opacity: 1; }
}

/* ── marquee ────────────────────────────────────────────────────────────── */
.marquee {
  overflow: hidden; margin: clamp(28px,4vw,44px) 0 0; padding: 12px 0;
  border-top: 1px solid var(--color-divider); border-bottom: 1px solid var(--color-divider);
  white-space: nowrap; position: relative; z-index: 1;
  mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent);
}
.marquee__track { display: inline-flex; animation: marquee 22s linear infinite; }
.marquee__group { display: inline-block; font-size: 13px; letter-spacing: .06em; text-transform: uppercase; color: var(--color-accent-300); opacity: .8; }

/* ── process spine (scroll-scrubbed, reversible) ───────────────────────── */
.process { isolation: isolate; padding-block: clamp(48px,6vw,84px) clamp(24px,4vw,40px); }
.process__bg-sticky {
  position: sticky; top: 0; z-index: -1; pointer-events: none;
  height: 100vh; margin-bottom: -100vh;
}
.process__bg-photo {
  position: absolute; top: 0; bottom: 0; left: 50%; width: 100vw; margin-left: -50vw;
  background-image: url('../img/hero-ambient.jpg');
  background-size: cover; background-position: center 30%;
  opacity: calc(.48 * var(--bg-fade, 1)); mix-blend-mode: screen;
  filter: hue-rotate(-31deg) saturate(.9);
  mask-image: linear-gradient(to bottom, transparent, black 16%, black 82%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent, black 16%, black 82%, transparent 100%);
  transition: opacity .3s linear;
}
@media (max-width: 860px) {
  .process__bg-photo { opacity: calc(.34 * var(--bg-fade, 1)); }
  /* `position: sticky` pinning combined with `100vh` is notorious for a
     "catches, then releases" scroll feel on real mobile browsers: the
     address bar collapsing/expanding mid-scroll changes the actual visible
     height out from under the 100vh math, so the pin's release point never
     quite lines up with where the user's scroll gesture expects it to let
     go. Trading the pin for a plain absolutely-positioned layer over the
     section removes that whole class of jank — the backdrop now scrolls
     normally with the content instead of fighting the browser chrome.
     (`.process` already has `position: relative` from `.container`, so
     this absolute layer sizes against the section itself, not the page.) */
  .process__bg-sticky { position: absolute; inset: 0; height: auto; margin-bottom: 0; }
}
.process__intro { max-width: 56ch; opacity: .78; font-size: 15px; margin-top: 4px; }
.process__timeline { position: relative; margin-top: clamp(30px,5vw,52px); padding: 10px 0; }
.process__line {
  position: absolute; left: 50%; top: 0; bottom: 0; width: 5px; border-radius: 3px;
  background: color-mix(in srgb, var(--color-text) 22%, transparent); transform: translateX(-50%);
}
.process__line-fill {
  position: absolute; inset: 0; border-radius: 3px; transform-origin: top; transform: scaleY(0);
  background: linear-gradient(180deg, var(--color-accent-300), var(--color-accent) 55%, var(--color-accent-2));
  box-shadow: 0 0 16px 1px color-mix(in srgb, var(--color-accent) 65%, transparent);
  will-change: transform;
}
.process__step {
  position: relative; width: calc(50% - 34px); margin-bottom: clamp(32px,5vw,56px);
  opacity: 0; transform: translateY(24px); filter: blur(2px);
  transition: opacity .6s var(--ease-out), transform .6s var(--ease-out), filter .6s var(--ease-out);
}
.process__step.is-active { opacity: 1; transform: translateY(0); filter: blur(0); }
.process__step--left { margin-right: auto; text-align: right; }
.process__step--right { margin-left: auto; text-align: left; }
.process__dot {
  position: absolute; top: 20px; width: 15px; height: 15px; border-radius: 50%;
  background: var(--color-bg); border: 3px solid color-mix(in srgb, var(--color-text) 26%, transparent);
  transition: border-color .4s var(--ease-out), background .4s var(--ease-out), box-shadow .4s var(--ease-out);
}
.process__step--left .process__dot { right: -41.5px; }
.process__step--right .process__dot { left: -41.5px; }
.process__step.is-active .process__dot {
  border-color: var(--color-accent); background: var(--color-accent);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--color-accent) 18%, transparent);
}
.process__card { display: inline-block; max-width: 380px; }
.process__step--left .process__card { text-align: right; }
.process__step--right .process__card { text-align: left; }
.process__icon { width: 32px; height: 32px; margin-bottom: 6px; opacity: .9; }
.process__step--left .process__icon { margin-left: auto; }
.process__card .service__num { display: block; margin-bottom: 2px; }
.process__card h3 { font-size: 19px; margin-bottom: 6px; }
.process__card p { font-size: 14px; opacity: .78; margin: 0; }

@media (max-width: 720px) {
  .process__line { left: 14px; }
  .process__step, .process__step--left, .process__step--right {
    width: calc(100% - 40px); margin-left: 40px !important; margin-right: 0 !important;
    text-align: left !important;
  }
  .process__step--left .process__dot, .process__step--right .process__dot { left: -33.5px; right: auto; }
  .process__step--left .process__card, .process__step--right .process__card { text-align: left !important; }
  .process__step--left .process__icon { margin-left: 0; }
}

/* ── project mockup graphics (contextual, on-brand — no stock imagery) ──── */
.mockup { position: absolute; inset: 10px; border-radius: 6px; overflow: hidden; }
.mockup--browser { background: color-mix(in srgb, var(--color-bg) 55%, transparent); border: 1px solid color-mix(in srgb, #fff 8%, transparent); }
.mockup__bar { display: flex; gap: 4px; padding: 6px 8px; border-bottom: 1px solid color-mix(in srgb, #fff 8%, transparent); }
.mockup__bar i { width: 5px; height: 5px; border-radius: 50%; background: color-mix(in srgb, var(--color-text) 30%, transparent); }
.mockup__body { padding: 10px; }
.mockup__line { height: 5px; border-radius: 3px; background: color-mix(in srgb, var(--color-text) 16%, transparent); margin-bottom: 7px; }
.mockup__line--w60 { width: 60%; }
.mockup__line--w80 { width: 80%; }
.mockup__chatbubble {
  width: 42%; height: 16px; border-radius: 8px; margin-top: 10px;
  background: linear-gradient(135deg, var(--color-accent-800), var(--color-accent-700));
  animation: bubblePulse 3s var(--ease-in-out) infinite;
}
.mockup--flow { display: flex; align-items: center; justify-content: center; gap: 0; }
.mockup__node { width: 14px; height: 14px; border-radius: 50%; background: var(--color-accent-700); border: 1.5px solid var(--color-accent); flex: none; }
.mockup__node--accent { background: var(--color-accent); box-shadow: 0 0 16px 2px color-mix(in srgb, var(--color-accent) 60%, transparent); }
.mockup__flow-line { position: relative; width: 42px; height: 2px; background: var(--color-divider); overflow: hidden; flex: none; }
.mockup__flow-line::after {
  content: ""; position: absolute; top: -1px; left: 0; width: 40%; height: 4px; border-radius: 2px;
  background: var(--color-accent-300); transform: translateX(-100%);
  animation: flowShimmer 2.6s var(--ease-in-out) infinite;
}
.mockup__flow-line:nth-of-type(2)::after { animation-delay: .5s; }
.mockup--dashboard { display: flex; align-items: flex-end; justify-content: center; gap: 8px; padding-bottom: 14px; }
.mockup__bar-chart {
  width: 12%; height: var(--h); border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, var(--color-accent-300), var(--color-accent-700));
  transform: scaleY(.3); transform-origin: bottom;
  transition: transform .7s var(--ease-out);
}
[data-reveal-item].is-visible .mockup__bar-chart { transform: scaleY(1); }

/* ── stats bento ────────────────────────────────────────────────────────── */
.stats { margin-block: clamp(28px,4vw,44px); }
.stats__grid { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: auto auto; gap: 14px; }
.stats__tile { background: var(--color-surface); border-radius: var(--radius-lg); padding: 20px; transition: transform .3s var(--ease-out); }
.stats__tile--big { grid-column: span 2; grid-row: span 2; padding: 26px; position: relative; overflow: hidden; background: var(--color-section); }
.stats__tile--big::before { content: ""; position: absolute; inset: 0; background: radial-gradient(circle at 100% 0%, var(--color-section-glow), transparent 60%); opacity: .7; }
.stats__tile--wide { grid-column: span 2; display: flex; align-items: center; gap: 10px; padding: 18px 20px; }
@media (hover: hover) and (pointer: fine) {
  /* .reveal-scale's nth-child stagger sets a transition-delay for the
     scroll-in reveal — without resetting it here, that same delay would
     also apply to the hover lift, since transition-delay isn't scoped to
     what triggered the change. */
  .stats__tile:hover { transition-delay: 0s; transform: translateY(-3px); box-shadow: 0 0 0 1px var(--color-accent-2), 0 14px 30px -12px color-mix(in srgb, var(--color-accent-2) 55%, transparent); }
  .stats__tile--big:hover { box-shadow: 0 0 0 1px var(--color-accent), 0 18px 40px -12px color-mix(in srgb, var(--color-accent) 60%, transparent); }
  .stats__tile--wide:hover { box-shadow: 0 0 0 1px var(--color-accent), 0 14px 30px -12px color-mix(in srgb, var(--color-accent) 55%, transparent); }
}
.stats__value { position: relative; font-family: var(--font-heading); font-size: clamp(40px,5vw,58px); font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; }
.stats__tile:not(.stats__tile--big):not(.stats__tile--wide) .stats__value { font-size: 30px; }
.stats__value--sm { font-size: 20px; font-weight: 600; }
.stats__label { position: relative; font-size: 14px; opacity: .8; margin-top: 8px; max-width: 24ch; }
.stats__tile:not(.stats__tile--big) .stats__label { font-size: 12.5px; opacity: .75; margin-top: 4px; }

@media (max-width: 720px) {
  .stats__grid { grid-template-columns: repeat(2, 1fr); }
  .stats__tile--big, .stats__tile--wide { grid-column: span 2; }
}

/* ── market stats (Bitkom-Studie callout) — mobile-first: base rules below
   are the phone layout, @media (min-width:721px) progressively upgrades to
   the desktop 3-/4-column layout ────────────────────────────────────────── */
.market { padding-block: clamp(40px,6vw,72px); }
.market__eyebrow { gap: 6px; }
.market__eyebrow svg { width: 13px; height: 13px; flex: none; }
.market h2 { margin-top: 14px; }
.market h2 em { font-style: italic; color: var(--color-accent); }
.market__intro { max-width: 56ch; opacity: .78; font-size: 15.5px; margin-top: 10px; }

.market__grid { display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: 28px; }
.market__card { padding: var(--space-4); gap: 10px; }
.market__icon {
  width: 40px; height: 40px; border-radius: var(--radius-md); display: grid; place-items: center;
  background: var(--color-accent-800); color: var(--color-accent-300); flex: none;
}
.market__icon svg { width: 19px; height: 19px; }
.market__value { font-family: var(--font-heading); font-weight: 600; font-size: clamp(36px,9vw,46px); color: var(--color-accent); line-height: 1; margin-top: 2px; }
.market__label { font-size: 16px; margin: 4px 0 0; }
.market__text { font-size: 13.5px; opacity: .75; margin: 0; }
.market__bar { height: 4px; border-radius: 2px; background: var(--color-divider); overflow: hidden; margin-top: 4px; }
.market__bar-fill {
  height: 100%; border-radius: 2px; width: 0;
  background: linear-gradient(90deg, var(--color-accent-300), var(--color-accent));
  transition: width 1.1s var(--ease-out) .25s;
}
[data-reveal-item].is-visible .market__bar-fill { width: var(--pct); }
.market__source { font-size: 11px; opacity: .5; margin-top: 2px; }

.market__strip {
  display: grid; grid-template-columns: 1fr 1fr; gap: 18px 14px; margin-top: 28px;
  padding: 20px; border-radius: var(--radius-lg); background: var(--color-surface);
}
.market__mini { text-align: center; }
.market__mini-value { font-family: var(--font-heading); font-weight: 600; font-size: 26px; color: var(--color-accent); line-height: 1; }
.market__mini-label { font-size: 11.5px; opacity: .75; margin-top: 6px; line-height: 1.3; }
.market__mini-source { display: block; font-size: 10px; opacity: .45; margin-top: 6px; }

@media (min-width: 721px) {
  .market__grid { grid-template-columns: repeat(3, 1fr); gap: 20px; }
  .market__strip { grid-template-columns: repeat(4, 1fr); }
}

/* ── services accordion ────────────────────────────────────────────────── */
.services { padding-block: clamp(48px,6vw,80px) clamp(24px,4vw,40px); }
.services__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.services__list { margin-top: 10px; }
.service { border-bottom: 1px solid var(--color-divider); }
.service__head {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 20px 4px; cursor: pointer; background: none; border: 0; text-align: left; color: inherit; font: inherit;
  transition: background 200ms var(--ease-out);
}
.service__head:hover { background: color-mix(in srgb, var(--color-text) 4%, transparent); }
.service__head-left { display: flex; align-items: baseline; gap: 14px; min-width: 0; }
.service__num { font-family: var(--font-heading); font-size: 13px; color: var(--color-accent); transition: transform 220ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .service__head:hover .service__num { transform: translateX(2px); }
}
.service__title { font-size: clamp(19px,2.6vw,25px); margin: 0; }
.service__arrow { font-size: 20px; color: var(--color-accent); flex: none; transition: transform .35s var(--ease-out); }
.service.is-open .service__arrow { transform: rotate(180deg); }
.service__panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .4s var(--ease-in-out); }
.service.is-open .service__panel { grid-template-rows: 1fr; }
.service__panel-inner { overflow: hidden; }
.service__body { padding: 0 4px 22px; max-width: 64ch; opacity: .8; font-size: 14.5px; margin: 0; }

/* ── problems we solve ──────────────────────────────────────────────────── */
.problems { padding-block: clamp(40px,6vw,72px) clamp(20px,4vw,32px); }
.problems__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px; margin-top: 20px; }
.problem { padding: var(--space-4); gap: 10px; }
.problem__head { display: flex; align-items: center; gap: 10px; }
.problem__icon {
  width: 38px; height: 38px; border-radius: var(--radius-md); display: grid; place-items: center;
  background: var(--color-accent-800); color: var(--color-accent-300); flex: none;
}
.problem__icon svg { width: 18px; height: 18px; }
.problem__num { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--color-accent); font-weight: 600; }
.problem__title { font-size: 17px; margin: 0; }
.problem__text { font-size: 13px; opacity: .75; margin: 0; }

.problem__severity { display: flex; align-items: center; gap: 10px; }
.problem__severity-track { flex: 1; height: 4px; border-radius: 2px; background: var(--color-divider); overflow: hidden; }
.problem__severity-fill {
  height: 100%; border-radius: 2px; width: 0; background: var(--sev-color, var(--color-accent));
  transition: width 1s var(--ease-out) .2s;
}
[data-reveal-item].is-visible .problem__severity-fill { width: var(--sev-width, 40%); }
.problem__severity-label { font-size: 11px; font-weight: 600; color: var(--sev-color, var(--color-accent)); flex: none; }
.problem__severity--critical { --sev-color: #E2636B; --sev-width: 100%; }
.problem__severity--high { --sev-color: #E2A15A; --sev-width: 70%; }
.problem__severity--medium { --sev-color: #D6C065; --sev-width: 40%; }

.problem__tags { display: flex; flex-wrap: wrap; gap: 6px; }
.problem__tag {
  font-size: 10.5px; padding: 4px 10px; border-radius: 20px;
  background: color-mix(in srgb, var(--color-accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--color-accent) 32%, transparent);
  color: var(--color-accent-300);
}

/* ── before/after & generic-vs-custom comparisons ──────────────────────── */
.compare { padding-block: clamp(40px,6vw,72px); }
.compare__grid { display: grid; grid-template-columns: 1fr auto 1fr; gap: 18px; align-items: center; margin-top: 22px; }
.compare__col { padding: var(--space-4); gap: 10px; }
.compare__col--before { opacity: .85; }
.compare__col--after { box-shadow: 0 0 0 1px var(--color-accent), 0 0 30px -14px color-mix(in srgb, var(--color-accent) 60%, transparent); }
.compare__tag { display: inline-block; font-size: 11px; letter-spacing: .04em; text-transform: uppercase; opacity: .6; }
.compare__tag--accent { color: var(--color-accent); opacity: 1; }
.compare__list { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 9px; font-size: 14px; }
.compare__list li { padding-left: 20px; position: relative; opacity: .75; }
.compare__list li::before { content: "–"; position: absolute; left: 0; opacity: .5; }
.compare__list--after li { opacity: 1; }
.compare__list--after li::before { content: "✓"; color: var(--color-accent); opacity: 1; }
.compare__arrow { font-size: 22px; color: var(--color-accent); text-align: center; }
@media (max-width: 720px) {
  .compare__grid { grid-template-columns: 1fr; }
  .compare__arrow { transform: rotate(90deg); }

  /* Five full-width problem cards stacked vertically read as a wall of
     near-identical text on a phone. A swipeable, snap-aligned row turns
     the same content into one clear "moment" at a time, with the next
     card peeking in as an obvious invitation to keep going, instead of
     a long scroll through five stacked lookalikes. */
  .problems__grid {
    display: flex; grid-template-columns: none; gap: 14px;
    overflow-x: auto; scroll-snap-type: x mandatory;
    /* `html { scroll-behavior: smooth }` is global and inherited — without
       this override, every scrollLeft nudge from the drag handler below
       would ease toward its target over time instead of landing instantly,
       so the carousel would visibly lag behind the finger instead of
       tracking it 1:1. */
    scroll-behavior: auto;
    margin-inline: calc(clamp(20px, 4vw, 56px) * -1);
    padding-inline: clamp(20px, 4vw, 56px); padding-bottom: 6px;
    /* Tells the snap algorithm itself where the scrollport's logical edges
       are. Without this, `scroll-snap-align: start` on the first card
       snaps against the container's own margin box, which fought the
       container's padding-inline and auto-scrolled a few px on load —
       just enough to swallow the whole reserved edge gap. scroll-padding
       is the mechanism built for exactly this, and leaves the padding
       itself alone to still render normally at scrollLeft 0. */
    scroll-padding-inline: clamp(20px, 4vw, 56px);
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
    /* touch-action:pan-x (claiming horizontal, leaving vertical unclaimed
       for the page) turned out not to reliably let vertical drags bubble
       to page scroll on real devices — a known touch-action/scroll-snap
       inconsistency. pan-y instead claims VERTICAL natively (guaranteed:
       it's the browser's default gesture, nothing to go wrong), and a small
       JS handler below (main.js) drives horizontal dragging manually by
       reading the gesture's dominant axis on the first few pixels of
       movement — see the comment there for the full reasoning. */
    touch-action: pan-y;
  }
  .problems__grid::-webkit-scrollbar { display: none; }
  .problem {
    flex: 0 0 80%; scroll-snap-align: start;
    /* Without this, a fast flick can carry enough momentum to sail past
       several snap points and only settle several cards later — it still
       "snaps" in the end, but skips the one-card-per-gesture feel. `always`
       forces the browser to stop at every card regardless of fling speed. */
    scroll-snap-stop: always;
  }
  /* Cards sit off-screen to the right until swiped to, so the shared
     scroll-reveal system (which starts every [data-reveal-item] hidden
     until ITS OWN intersection ratio crosses a threshold) left card 2+
     invisible even once the section itself was on screen — nothing hinted
     that swiping right would reveal more content. All cards now render
     immediately; only the severity bar's fill-in (tied to the same
     .is-visible class via the reveal observer, untouched below) still
     plays once a card is actually swiped into view. */
  .problem[data-reveal-item] { opacity: 1; transform: none; filter: none; }
}

/* ── solutions showcase: four animated bento tiles ─────────────────────── */
.solutions { padding-block: clamp(40px,6vw,72px); }
.solutions__intro { max-width: 60ch; opacity: .78; font-size: 15px; margin-top: 4px; }
.solutions__grid { display: grid; grid-template-columns: 1fr; gap: 18px; margin-top: 28px; }
@media (min-width: 860px) {
  .solutions__grid { grid-template-columns: 1fr 1fr; gap: 22px; }
}

.solution-tile {
  padding: var(--space-6); gap: 12px; min-height: 300px;
  transition: transform .3s var(--ease-out);
}
.solution-tile h4 { font-size: 19px; margin: 0; }
.solution-tile p { font-size: 13.5px; opacity: .75; margin: 0; max-width: 46ch; }
.solution-tile__icon {
  width: 42px; height: 42px; border-radius: var(--radius-md); display: grid; place-items: center;
  background: var(--color-accent-800); color: var(--color-accent-300); flex: none;
}
.solution-tile__icon svg { width: 19px; height: 19px; }

/* KI-Strategie tile: four-phase horizontal loader, auto-cycling in an
   infinite loop (js/main.js). The runner itself is a plain CSS animation
   (transform-only, cheap even off-screen); js only toggles which node and
   label are "is-active" in sync with it, same visual language as the hero
   demo's `.demo-hnode` workflow chain but as a small self-contained loop
   instead of a one-shot scripted story. */
.strategy-loop { margin-top: auto; padding-top: 18px; }
/* Each node sits in its own flex:1 cell, centered within it — matching
   `.strategy-loop__labels span`'s identical flex:1/text-align:center setup
   below. Distributing the 34px circles themselves via justify-content:
   space-between (as this used to do) packs them at their natural width
   with equal gaps *between* them, which centers on different x-positions
   than four equal-width label cells do — the fixed-width-with-gaps vs.
   equal-width-cells mismatch was exactly why icons and labels didn't line
   up. Wrapping each icon in an equal-width cell makes both rows use the
   same distribution, so every node sits directly above its label. */
.strategy-loop__row { display: flex; }
.strategy-loop__node-wrap { flex: 1; min-width: 0; display: flex; justify-content: center; }
.strategy-loop__node {
  width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; flex: none;
  background: var(--color-surface); color: color-mix(in srgb, var(--color-text) 40%, transparent);
  transition: background .3s var(--ease-out), color .3s var(--ease-out), box-shadow .3s var(--ease-out), transform .3s var(--ease-out);
}
.strategy-loop__node svg { width: 16px; height: 16px; }
.strategy-loop__node.is-active {
  background: var(--color-accent-800); color: var(--color-accent-100); transform: scale(1.1);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 20%, transparent), 0 0 16px -2px color-mix(in srgb, var(--color-accent) 70%, transparent);
}
.strategy-loop__track { position: relative; height: 3px; border-radius: 2px; background: var(--color-divider); margin: 10px 1px 8px; overflow: hidden; }
.strategy-loop__runner {
  position: absolute; top: 0; left: 0; width: 26%; height: 100%; border-radius: 2px;
  background: linear-gradient(90deg, transparent, var(--color-accent-300), var(--color-accent));
  animation: strategyRunner 6.4s linear infinite;
}
.strategy-loop__labels { display: flex; justify-content: space-between; }
.strategy-loop__labels span {
  flex: 1; text-align: center; font-size: 9.5px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  opacity: .45; transition: opacity .3s var(--ease-out), color .3s var(--ease-out);
}
.strategy-loop__labels span.is-active { opacity: 1; color: var(--color-accent-300); }

/* Automatisierung tile: three stacked pipeline stages, auto-cycling
   top-to-bottom (js/main.js). Only the current stage is "is-active"; a
   stage the loop has already passed keeps a settled "is-done" checkmark
   until the loop reaches its last stage, at which point every earlier
   stage resets to idle in the same tick the last one lights up, so the
   whole thing restarts cleanly instead of visibly jumping backwards. */
.pipeline { margin-top: auto; padding-top: 14px; display: flex; flex-direction: column; }
.pipeline-row {
  display: flex; align-items: center; gap: 10px; padding: 9px 11px; border-radius: var(--radius-md);
  background: var(--color-surface); transition: background .3s var(--ease-out), box-shadow .3s var(--ease-out);
}
.pipeline-row__icon {
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; flex: none;
  background: var(--color-bg); color: color-mix(in srgb, var(--color-text) 45%, transparent);
  transition: background .3s var(--ease-out), color .3s var(--ease-out);
}
.pipeline-row__icon svg { width: 13px; height: 13px; }
.pipeline-row__label { font-size: 12.5px; font-weight: 500; opacity: .7; flex: 1; transition: opacity .3s var(--ease-out), color .3s var(--ease-out); }
.pipeline-row__status { font-size: 12px; opacity: 0; transition: opacity .3s var(--ease-out); flex: none; color: var(--color-accent-300); }
.pipeline-row__status--dots { letter-spacing: 1px; }
.pipeline-row__bar { width: 46px; height: 4px; border-radius: 2px; background: var(--color-divider); overflow: hidden; flex: none; }
.pipeline-row__bar-fill { display: block; height: 100%; width: 0; border-radius: 2px; background: var(--color-accent-300); transition: width 1.1s var(--ease-out); }

.pipeline-row.is-active { background: var(--color-accent-800); box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 35%, transparent); }
.pipeline-row.is-active .pipeline-row__icon { background: var(--color-accent-700); color: var(--color-accent-100); }
.pipeline-row.is-active .pipeline-row__label { opacity: 1; color: var(--color-accent-100); }
.pipeline-row.is-active .pipeline-row__bar-fill { width: 100%; }
.pipeline-row.is-done .pipeline-row__status { opacity: 1; }
.pipeline-row:not(.is-active):not(.is-done) .pipeline-row__status--dots { opacity: .4; }

.pipeline-connector { width: 2px; height: 12px; margin: 0 0 0 24px; border-radius: 1px; background: var(--color-divider); position: relative; overflow: hidden; }
.pipeline-connector::after {
  content: ""; position: absolute; left: -1px; top: 0; width: 4px; height: 6px; border-radius: 2px;
  background: var(--color-accent-300); box-shadow: 0 0 6px 1px color-mix(in srgb, var(--color-accent) 70%, transparent);
  animation: vpipeFlow 3s linear infinite;
}

/* Software-Entwicklung tile: pure-CSS code mockup, no JS needed — a
   blinking cursor plus a periodic "build successful" status line, both
   infinite keyframe loops. */
.code-mockup { margin-top: auto; border-radius: var(--radius-md); background: var(--color-bg); overflow: hidden; border: 1px solid color-mix(in srgb, #fff 8%, transparent); }
.code-mockup__bar { display: flex; gap: 4px; padding: 7px 9px; border-bottom: 1px solid color-mix(in srgb, #fff 8%, transparent); }
.code-mockup__bar i { width: 6px; height: 6px; border-radius: 50%; background: color-mix(in srgb, var(--color-text) 28%, transparent); }
.code-mockup__body {
  margin: 0; padding: 12px 13px; font-family: "SFMono-Regular", ui-monospace, Menlo, Consolas, monospace;
  font-size: 11.5px; line-height: 1.65; overflow-x: auto; color: var(--color-text);
}
.cm-com { color: color-mix(in srgb, var(--color-text) 40%, transparent); }
.cm-kw { color: var(--color-accent-2); }
.cm-var { color: var(--color-accent-100); }
.cm-prop { color: var(--color-accent-300); }
.cm-str { color: #9FD88A; }
.cm-fn { color: #E0C36C; }
.code-mockup__cursor {
  display: inline-block; width: 6px; height: 12px; margin-left: 1px; vertical-align: -2px;
  background: var(--color-accent-300); animation: cursorBlink 1s step-end infinite;
}
.code-mockup__status {
  display: flex; align-items: center; gap: 6px; padding: 8px 13px; font-size: 11px; opacity: 0;
  border-top: 1px solid color-mix(in srgb, #fff 8%, transparent); color: var(--color-accent-300);
  animation: cmStatusLoop 6s var(--ease-out) infinite;
}
.code-mockup__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--color-accent-300); flex: none; box-shadow: 0 0 6px 1px color-mix(in srgb, var(--color-accent) 70%, transparent); }

/* KI-Integration tile: reuses the existing `.mockup--flow` node/line
   components (project-card mockups further down this file) without their
   absolute-positioning wrapper, since this one sits inline at a tile's
   bottom edge instead of filling an absolutely-positioned card. */
.integration-flow { margin-top: auto; padding-top: 26px; display: flex; align-items: center; justify-content: center; gap: 0; }

@media (max-width: 720px) {
  .solution-tile { min-height: 0; }
}

/* ── integrations / tech stack badge grids ─────────────────────────────── */
.integrations { padding-block: clamp(40px,6vw,72px); }
.integrations__intro { max-width: 60ch; opacity: .78; margin-top: 4px; }

/* Two-row auto-scrolling logo marquee for "Bestehende Systeme bleiben im
   Einsatz" — deliberately kept separate from `.badge-grid` below (the
   "Womit wir bauen" tech stack further down the page): this row is about
   the client's *existing* business tools staying in place, that one is
   about Werkbüro24's *own* build stack. Same chip-grid shape, different
   subject, different treatment — this section gets the animated marquee
   since it's the one making a "look how many systems this covers" claim,
   the tech stack stays a static grid so the page doesn't repeat the same
   showy effect twice for two different messages. */
.integration-marquee { margin-top: 28px; display: flex; flex-direction: column; gap: 12px; }
.integration-row {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent);
}
.integration-track { display: inline-flex; width: max-content; animation: integrationScroll 34s linear infinite; }
.integration-row--right .integration-track { animation-direction: reverse; }
.integration-group { display: inline-flex; flex: none; gap: 12px; padding-right: 12px; }
@media (hover: hover) and (pointer: fine) {
  .integration-marquee:hover .integration-track { animation-play-state: paused; }
}
.integration-chip {
  display: inline-flex; align-items: center; gap: 10px; padding: 10px 16px;
  border-radius: var(--radius-md); background: var(--color-surface);
  border: 1px solid color-mix(in srgb, #fff 7%, transparent); white-space: nowrap;
}
/* Real brand SVGs (dropped in by the user under /img) mix gradients, CSS
   classes and black-default fills with no reliable common background
   assumption — some (Stripe, SAP) are self-contained colored badges with
   white lettering, others (Notion, Airtable) are dark marks meant for a
   light backdrop. A single light neutral tile behind every logo (the
   existing but previously-unused `--color-neutral-100` token) is the one
   background that renders all of them correctly at once, matching how
   most real "integrates with" logo walls handle a mixed icon set. */
.integration-chip__icon {
  width: 32px; height: 32px; border-radius: 8px; display: grid; place-items: center; flex: none;
  background: var(--color-neutral-100); padding: 5px;
}
.integration-chip__icon img { width: 100%; height: 100%; object-fit: contain; display: block; }
.integration-chip__text { display: flex; flex-direction: column; line-height: 1.25; }
.integration-chip__name { font-size: 13px; font-weight: 600; }
.integration-chip__sub { font-size: 10.5px; opacity: .55; }

.techstack { padding-block: clamp(40px,6vw,72px); }
.badge-grid { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
.badge-chip {
  --dot: var(--color-accent);
  display: inline-flex; align-items: center; gap: 8px; font-size: 13px;
  padding: 8px 14px; border-radius: 20px; background: var(--color-surface);
  border: 1px solid var(--color-divider);
  transition: border-color .25s var(--ease-out), transform .25s var(--ease-out);
}
.badge-chip::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--dot); box-shadow: 0 0 8px 0 var(--dot); flex: none; }
@media (hover: hover) and (pointer: fine) {
  .badge-chip:hover { border-color: color-mix(in srgb, var(--dot) 60%, transparent); transform: translateY(-2px); }
}
.integrations__trust { margin-top: 20px; font-size: 12.5px; opacity: .55; }

/* ── expanded case study meta ──────────────────────────────────────────── */
.project__meta { margin: 4px 0 0; font-size: 12px; display: flex; flex-direction: column; gap: 5px; }
.project__meta dt { display: inline; font-weight: 600; opacity: .6; }
.project__meta dt::after { content: ": "; }
.project__meta dd { display: inline; margin: 0; opacity: .8; }
.project__results { display: flex; flex-wrap: wrap; gap: 8px 14px; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--color-divider); }
.project__stat { font-family: var(--font-heading); font-weight: 600; font-size: 14px; color: var(--color-accent-300); display: flex; flex-direction: column; gap: 1px; }
.project__stat small { font-family: var(--font-body); font-weight: 400; font-size: 10.5px; opacity: .6; color: var(--color-text); }

/* ── FAQ (reuses .service accordion styles, own single-open group) ──────── */
.faq { padding-block: clamp(40px,6vw,72px); }
.faq__list { margin-top: 12px; }

/* ── projects ───────────────────────────────────────────────────────────── */
.projects { padding-block: clamp(40px,6vw,72px); }
.projects__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 22px; margin-top: 22px; }
.project { transition: opacity .8s var(--ease-out), transform .8s var(--ease-out), filter .8s var(--ease-out), box-shadow .3s var(--ease-out); }
.project:hover { box-shadow: var(--shadow-lg); }
.project__inner { display: flex; flex-direction: column; gap: var(--space-2); will-change: transform; }
.project__image { border-radius: var(--radius-md); width: 100%; height: 160px; position: relative; overflow: hidden; }
.project__image::after { content: ""; position: absolute; inset: 0; background-image: radial-gradient(color-mix(in srgb, #fff 10%, transparent) 1px, transparent 1px); background-size: 14px 14px; opacity: .5; }
.project__image--1 { background: radial-gradient(circle at 25% 20%, var(--color-accent-700), var(--color-bg) 70%); }
.project__image--2 { background: radial-gradient(circle at 75% 25%, var(--color-accent-2-800), var(--color-bg) 70%); }
.project__image--3 { background: radial-gradient(circle at 50% 80%, var(--color-section-glow), var(--color-bg) 75%); }
.project__peek {
  position: absolute; right: 10px; bottom: 10px; z-index: 1;
  font-size: 11px; letter-spacing: .02em; color: var(--color-bg);
  background: var(--color-accent-300); border-radius: 20px; padding: 4px 10px;
  opacity: 0; transform: translateY(6px) scale(.95);
  transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out);
}
.project:hover .project__peek { opacity: 1; transform: translateY(0) scale(1); }
.project__tags { display: flex; gap: 6px; flex-wrap: wrap; }

/* ── compliance (DSGVO / EU AI Act / Hosting) ──────────────────────────── */
.compliance { padding-block: clamp(40px,6vw,72px); }
.compliance__eyebrow { gap: 6px; }
.compliance__eyebrow svg { width: 13px; height: 13px; flex: none; }
.compliance h2 { margin-top: 14px; }
.compliance h2 em { font-style: italic; color: var(--color-accent); }
.compliance__intro { max-width: 60ch; opacity: .78; font-size: 15.5px; margin-top: 10px; }

.compliance__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 28px; }
.compliance__card { padding: var(--space-4); gap: 12px; align-items: center; text-align: center; }
.compliance__icon {
  width: 52px; height: 52px; border-radius: var(--radius-md); display: grid; place-items: center;
  background: var(--color-accent-800); color: var(--color-accent-300); flex: none;
}
.compliance__icon svg { width: 24px; height: 24px; }
.compliance__card h4 { font-size: 17px; margin: 0; }
.compliance__card p { font-size: 13px; opacity: .75; margin: 0; }
.compliance__tag {
  font-size: 11.5px; font-weight: 600; padding: 6px 14px; border-radius: 20px; margin-top: 4px;
  background: color-mix(in srgb, var(--color-accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--color-accent) 32%, transparent);
  color: var(--color-accent-300);
}

@media (max-width: 720px) {
  .compliance__grid { grid-template-columns: 1fr; }
}

/* ── gradient, color-framed cards: problems / solutions / compliance ────
   These three card families used flat `--color-surface` backgrounds and
   `.elev-sm`'s single flat-gray 1px ring (`--shadow-sm`), which read as
   one-dimensional next to the rest of the page's blue-accented gradients
   and glows. A diagonal accent-tinted gradient background plus a genuine
   gradient border (double-background trick: one gradient painted into
   the padding-box for the fill, another into the border-box for the
   ring, with `border-color: transparent` so the border-box gradient
   shows through) replaces that flat look. Scoped to just these three
   selectors, not `.elev-sm` itself, so its plain ring stays untouched
   everywhere else it's used (chat bubbles, project/market cards, compare
   columns) — only these three card types asked for the treatment.
   `--card-angle` varies per nth-child so a grid of these doesn't read as
   the exact same tile repeated — a small "dynamic" touch alongside the
   gradient/border itself. */
.problem, .solution-tile, .compliance__card {
  --card-angle: 155deg;
  background:
    linear-gradient(var(--card-angle), var(--color-surface), color-mix(in srgb, var(--color-accent) 9%, var(--color-surface)) 65%, color-mix(in srgb, var(--color-accent-2) 7%, var(--color-surface))) padding-box,
    linear-gradient(var(--card-angle), color-mix(in srgb, var(--color-accent) 55%, transparent), color-mix(in srgb, var(--color-accent-2) 12%, transparent) 55%, color-mix(in srgb, var(--color-accent) 32%, transparent)) border-box;
  border: 1px solid transparent;
  box-shadow: 0 10px 26px -18px rgba(0,0,0,.6);
  transition: box-shadow .3s var(--ease-out), transform .3s var(--ease-out), background .3s var(--ease-out);
}
.problem:nth-child(3n+2), .solution-tile:nth-child(2n) { --card-angle: 200deg; }
.problem:nth-child(3n+3), .solution-tile:nth-child(3n) { --card-angle: 115deg; }
.compliance__card:nth-child(2) { --card-angle: 200deg; }
.compliance__card:nth-child(3) { --card-angle: 115deg; }

@media (hover: hover) and (pointer: fine) {
  .problem:hover, .solution-tile:hover, .compliance__card:hover {
    transform: translateY(-3px);
    background:
      linear-gradient(var(--card-angle), var(--color-surface), color-mix(in srgb, var(--color-accent) 13%, var(--color-surface)) 65%, color-mix(in srgb, var(--color-accent-2) 11%, var(--color-surface))) padding-box,
      linear-gradient(var(--card-angle), var(--color-accent), var(--color-accent-2) 55%, var(--color-accent)) border-box;
    box-shadow: 0 16px 34px -16px rgba(0,0,0,.65), 0 0 32px -14px color-mix(in srgb, var(--color-accent) 50%, transparent);
  }
}

/* ── contact ────────────────────────────────────────────────────────────── */
/* `.contact` used to carry `.container` directly on the same element as its
   own *visible* card border/background (`.card.elev-md`) — every other
   `.container` section is invisible chrome around inset content, so nobody
   notices that `.container`'s padding only insets *content*, never a border
   drawn around the box itself. Once this element's own edge WAS the
   border, that border sat flush with the viewport edge below the
   `.container` max-width breakpoint (where its margin is just `auto` = 0),
   while every other section's content still sat padding-inset — the card
   visibly stuck out past the margin everything else respects, worst on
   mobile where the whole viewport is narrow. Fix: `.container` now lives on
   a separate, invisible `.contact-wrap` outer section (identical to every
   other section on the page), and `.contact` itself is just a plain block
   filling that wrapper's padding box — pixel-identical inset to every other
   section's content, at every viewport width, with no formula to keep in
   sync with `.container`'s own values. */
.contact-wrap { padding-block: clamp(20px,4vw,40px) 60px; }
.contact { text-align: center; position: relative; overflow: hidden; padding: clamp(36px,6vw,56px) 24px; }
.contact__glow { position: absolute; inset: 0; background: radial-gradient(circle at 50% 0%, color-mix(in srgb, var(--color-accent) 14%, transparent), transparent 60%); pointer-events: none; }
.contact h2, .contact p, .contact .btn { position: relative; }
.contact p { opacity: .75; max-width: 50ch; margin: 8px auto 0; }
.cta-pulse { margin-top: 20px; border-radius: 8px; animation: ctaPulse 2.4s var(--ease-in-out) infinite; }
.contact__reassure {
  list-style: none; margin: 22px 0 0; padding: 0; display: flex; flex-wrap: wrap;
  justify-content: center; gap: 8px 20px; font-size: 12.5px; opacity: .65;
}
.contact__reassure li { position: relative; padding-left: 14px; }
.contact__reassure li::before { content: "✓"; position: absolute; left: 0; color: var(--color-accent); }

/* ── footer ─────────────────────────────────────────────────────────────── */
.site-footer { border-top: 1px solid var(--color-divider); padding-block: 28px 40px; display: flex; flex-wrap: wrap; gap: 16px; justify-content: space-between; font-size: 13px; opacity: .65; }
.site-footer__links { display: flex; gap: 18px; flex-wrap: wrap; }
.site-footer__links a { color: inherit; }

/* ── responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 860px) {
  .hero__grid { grid-template-columns: 1fr; }
  .services__draw { display: none; }
  .nav-desktop { display: none; }
  .nav-toggle { display: flex; }
}
@media (hover: none) {
  .project__peek { display: none; }
}

/* ── keyframes ──────────────────────────────────────────────────────────── */
@keyframes loaderFadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
@keyframes loaderSweep { from { transform: translateX(-100%); opacity: 0; } 40% { opacity: 1; } to { transform: translateX(100%); opacity: 0; } }
@keyframes avatarPulse { 0%,100% { box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 50%, transparent), 0 0 10px -2px color-mix(in srgb, var(--color-accent) 60%, transparent); } 50% { box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 60%, transparent), 0 0 18px -1px color-mix(in srgb, var(--color-accent) 80%, transparent); } }
@keyframes pulseDot { 0%,100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-accent) 55%, transparent); } 50% { box-shadow: 0 0 0 6px transparent; } }
@keyframes msgIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes typeDots { 0%,60%,100% { opacity: .25; transform: scale(.85); } 30% { opacity: 1; transform: scale(1); } }
@keyframes scanline { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes integrationScroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes ctaPulse { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-accent) 45%, transparent); } 70% { box-shadow: 0 0 0 14px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }
/* background loops: transform/opacity only — border-radius and background-position
   are paint-triggering, not compositor-only, and were the actual source of jank */
@keyframes meshDrift { 0%,100% { transform: translate(0,0) scale(1) rotate(0deg); } 33% { transform: translate(-2.5%,2%) scale(1.035) rotate(1.2deg); } 66% { transform: translate(2%,-2.5%) scale(1.02) rotate(-1deg); } }
@keyframes auroraSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes blobDriftA { 0%,100% { transform: translate(0,0) scale(1) rotate(0deg); } 50% { transform: translate(-24px,30px) scale(1.06) rotate(4deg); } }
@keyframes blobDriftB { 0%,100% { transform: translate(0,0) scale(1) rotate(0deg); } 50% { transform: translate(20px,-26px) scale(1.05) rotate(-4deg); } }
@keyframes gridDrift { from { transform: translate(0,0); } to { transform: translate(-56px,-56px); } }
@keyframes beamMove { 0%,100% { opacity: .35; transform: translateY(0) rotate(var(--rot, 0deg)); } 50% { opacity: .7; transform: translateY(-14px) rotate(var(--rot, 0deg)); } }
@keyframes noiseDrift { from { transform: translate(0,0); } to { transform: translate(-120px,-60px); } }
@keyframes floatTag { 0%,100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-6px) rotate(1deg); } }
@keyframes gradientShift { 0%,100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }
@keyframes bubblePulse { 0%,100% { opacity: .75; } 50% { opacity: 1; } }
@keyframes flowShimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(350%); } }
@keyframes cursorBlink { 0%,49% { opacity: 1; } 50%,100% { opacity: 0; } }
@keyframes canvasIn { to { opacity: 1; transform: translateY(0); } }
@keyframes kpiPop { 0% { transform: scale(1); } 40% { transform: scale(1.06); box-shadow: 0 0 0 1px var(--color-accent), 0 0 16px -4px color-mix(in srgb, var(--color-accent) 70%, transparent); } 100% { transform: scale(1); } }
@keyframes hpipeFlow { 0% { transform: translateX(0); opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { transform: translateX(28px); opacity: 0; } }
@keyframes strategyRunner { 0% { transform: translateX(-120%); } 100% { transform: translateX(480%); } }
@keyframes vpipeFlow { 0% { transform: translateY(-100%); opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { transform: translateY(300%); opacity: 0; } }
@keyframes cmStatusLoop { 0%, 55% { opacity: 0; transform: translateY(4px); } 70%, 95% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(4px); } }

/* ── contact form (additiv, nutzt .input/.btn der Seite) ─────────────────── */
.cform { --cform-error: #ef6b6b; position: relative; width: 100%; max-width: 680px; margin: 28px auto 0; text-align: left; display: flex; flex-direction: column; gap: 14px; }
.cform__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.cform__field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.cform__field--full { grid-column: 1 / -1; }
.cform__label { font-size: 12px; letter-spacing: 0.02em; color: color-mix(in srgb, var(--color-text) 72%, transparent); }
.cform__label em { font-style: normal; opacity: .7; }
.cform .input { min-height: 44px; padding: 10px 12px; font-size: 15px; background: color-mix(in srgb, var(--color-bg) 55%, var(--color-surface)); }
.cform .input::placeholder { color: color-mix(in srgb, var(--color-text) 38%, transparent); }
.cform__textarea { min-height: 104px; resize: vertical; max-height: 240px; }
.cform__select { appearance: none; -webkit-appearance: none; padding-right: 36px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23FAFAFA' stroke-opacity='.6' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 8 5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; background-size: 16px; }
.cform .input[aria-invalid="true"] { border-color: var(--cform-error); box-shadow: 0 0 0 3px color-mix(in srgb, var(--cform-error) 18%, transparent); }
.cform__hint { font-size: 12.5px; color: color-mix(in srgb, var(--color-text) 60%, transparent); }
.cform__consent { display: flex; gap: 10px; align-items: flex-start; font-size: 13px; line-height: 1.5; color: color-mix(in srgb, var(--color-text) 72%, transparent); cursor: pointer; }
.cform__consent input { flex: none; width: 18px; height: 18px; margin-top: 1px; accent-color: var(--color-accent); cursor: pointer; }
.cform__consent a { color: var(--color-accent-2); text-decoration: underline; text-underline-offset: 2px; }
.cform__consent.is-invalid span { color: var(--cform-error); }
.cform__trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.cform__status { min-height: 0; font-size: 13.5px; line-height: 1.5; }
.cform__status:not(:empty) { padding: 10px 12px; border-radius: var(--radius-md); border: 1px solid var(--color-divider); }
.cform__status.is-error { color: var(--cform-error); border-color: color-mix(in srgb, var(--cform-error) 55%, transparent); background: color-mix(in srgb, var(--cform-error) 8%, transparent); }
.cform__status.is-ok { color: var(--color-accent-2); border-color: color-mix(in srgb, var(--color-accent) 55%, transparent); background: color-mix(in srgb, var(--color-accent) 9%, transparent); }
.cform > .btn { align-self: stretch; justify-content: center; }
.cform > .btn[disabled] { opacity: .6; pointer-events: none; animation: none; }
.cform__alt { font-size: 13px; text-align: center; color: color-mix(in srgb, var(--color-text) 60%, transparent); }
.cform__alt a { color: var(--color-accent-2); }
.cform.is-done .cform__grid, .cform.is-done .cform__hint, .cform.is-done .cform__consent, .cform.is-done > .btn { display: none; }
@media (max-width: 640px) {
  .cform__grid { grid-template-columns: 1fr; }
}

/* ── Handy: ruhigeres Einblenden und Risiko-Balken im Karussell ─────────────
   Unschaerfe-Animationen (filter: blur) werden bei jedem Frame neu gerastert
   und erzeugen auf dem Handy Ruckler und halbtransparente Raender an
   Bloecken, die gerade einblenden. Auf Touch/schmalen Geraeten blenden
   Elemente deshalb nur ueber Transparenz und eine kurze Verschiebung ein,
   etwas schneller als am Desktop. */
@media (pointer: coarse), (max-width: 860px) {
  [data-reveal-item] {
    transform: translateY(16px); filter: none;
    transition: opacity .5s var(--ease-out), transform .5s var(--ease-out);
  }
  [data-reveal].is-visible [data-reveal-item].is-visible { transform: translateY(0); filter: none; }
  .reveal-child {
    transform: translateY(12px); filter: none;
    transition: opacity .5s var(--ease-out), transform .5s var(--ease-out);
    transition-delay: var(--stagger-delay, 0ms);
  }
  [data-reveal].is-visible .reveal-child { transform: translateY(0); filter: none; }
  .bg-noise-wrap { display: none; }
}
/* Karussell: Balken bleiben leer, bis die Karte zur Ruhe gekommen ist (`sev-on`). */
@media (max-width: 720px) {
  .problems__grid.sev-gated .problem[data-reveal-item] .problem__severity-fill { width: 0; transition: width .8s var(--ease-out); }
  .problems__grid.sev-gated .problem.sev-on[data-reveal-item] .problem__severity-fill { width: var(--sev-width, 40%); }
}

/* ── Demo-Vorschau in den Projekt-Kacheln + Demo-Fenster ───────────────── */
.project__image[data-demo] { cursor: pointer; }
.project__image[data-demo]:focus-visible { outline: 2px solid var(--color-accent-300); outline-offset: 2px; }
.project__preview {
  position: absolute; top: 0; left: 0; z-index: 0; border: 0; background: #fff;
  transform-origin: 0 0; pointer-events: none; opacity: 0; transition: opacity 400ms var(--ease-out);
}
.project__image.has-preview .project__preview { opacity: 1; }
.project__image.has-preview::after, .project__image.has-preview .mockup { display: none; }

.demo-modal {
  width: min(1280px, calc(100vw - 32px)); height: min(860px, calc(100vh - 32px));
  max-width: none; max-height: none; margin: auto; padding: 0; overflow: hidden;
  border: 1px solid var(--color-divider); border-radius: var(--radius-md);
  background: var(--color-surface); color: var(--color-text); box-shadow: var(--shadow-lg);
}
.demo-modal[open] { display: flex; flex-direction: column; }
.demo-modal::backdrop { background: color-mix(in srgb, var(--color-bg) 80%, transparent); backdrop-filter: blur(6px); }
.demo-modal__bar { display: flex; align-items: center; gap: 14px; padding: 10px 14px; border-bottom: 1px solid var(--color-divider); flex: none; }
.demo-modal__title { font-family: var(--font-heading); font-weight: 600; font-size: 14px; margin-right: auto; }
.demo-modal__ext { font-size: 12px; color: var(--color-accent-300); text-decoration: none; }
.demo-modal__ext:hover { text-decoration: underline; }
.demo-modal__close {
  width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--color-divider);
  background: transparent; color: var(--color-text); cursor: pointer; font-size: 13px; line-height: 1;
  transition: background 200ms var(--ease-out);
}
.demo-modal__close:hover { background: color-mix(in srgb, var(--color-text) 10%, transparent); }
.demo-modal__close:focus-visible { outline: 2px solid var(--color-accent-300); outline-offset: 2px; }
.demo-modal__stage { position: relative; flex: 1; min-height: 0; }
.demo-modal__frame { width: 100%; height: 100%; border: 0; background: #fff; display: block; }
.demo-modal__off { position: absolute; inset: 0; margin: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px; padding: 24px; text-align: center; background: var(--color-surface); font-size: 14px; }
.demo-modal__off[hidden] { display: none; }
.demo-modal__spin { width: 28px; height: 28px; border-radius: 50%; border: 2px solid var(--color-divider); border-top-color: var(--color-accent); animation: demo-spin .9s linear infinite; }
.demo-modal__off.is-error .demo-modal__spin { display: none; }
@keyframes demo-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .demo-modal__spin { animation-duration: 3s; } }
.project__poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center top; z-index: 0; opacity: 0; transition: opacity 400ms var(--ease-out); }
.project__image.has-preview .project__poster { opacity: 1; }

/* ── Scroll-Performance auf Handy/Tablet ────────────────────────────────────
   Hinter der Seite liegt ein vollflächig fixierter, dauerhaft animierter
   Hintergrund (Verläufe, weichgezeichnete Blobs, Aurora mit Blend-Modus,
   Rauschen, zwei Canvas). Liegt darüber ein backdrop-filter (Header, Demo-
   Konsole), muss der Browser den Bereich dahinter bei JEDEM Scroll-Frame neu
   verwischen — auf Handys ist das die Hauptursache fürs Ruckeln. Hier fällt
   deshalb nur das weg, was teuer und kaum sichtbar ist; das Aussehen bleibt
   (Konsole und Header sind etwas deckender statt unscharf-durchsichtig). */
@media (max-width: 980px), (pointer: coarse) {
  .site-header { backdrop-filter: none; -webkit-backdrop-filter: none; }
  .site-header.is-scrolled { background: color-mix(in srgb, var(--color-bg) 94%, transparent); }
  .demo-console { backdrop-filter: none; -webkit-backdrop-filter: none; background: color-mix(in srgb, var(--color-surface) 96%, transparent); }

  .bg-aurora, .bg-noise-wrap, #bgParticlesAmbient { display: none; }
  .bg-mesh, .blob, .beam { filter: none; }

  /* Die Chat-Spalte läuft automatisch nach unten. Als eigener Scroll-Bereich
     fängt sie Wisch-Gesten ab und das Scrollen der Seite hakt, sobald der
     Finger darauf landet. Programmatisches Scrollen funktioniert weiter. */
  .chat-card__messages, .demo-canvas__body { overflow-y: hidden; }
}
