/* ============================================================
   TURMZWEI LABS — Design System v2 · "Tinte & Papier"
   Light-first, minimal, editorial. Ink on paper, one blue accent.
   ============================================================ */

/* ---------- Fonts (self-hosted, OFL, GDPR-safe) ---------- */
@font-face {
  font-family: "Aspekta";
  src: url("../fonts/aspekta-vf.woff2") format("woff2-variations");
  font-weight: 100 950;
  font-display: swap;
}
@font-face {
  font-family: "Instrument Serif";
  src: url("../fonts/instrument-serif-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

/* ---------- Tokens ---------- */
:root {
  color-scheme: light;
  --paper: #f7f8fa;
  --paper-2: #ffffff;
  --paper-sunk: #eef0f4;
  --ink: #0f1218;
  --ink-2: #2c313b;
  --muted: #59606c;
  --faint: #676d79;
  --line: #e5e8ee;
  --line-2: #d7dbe4;
  --accent: #2440c0;
  --accent-ink: #1c33a0;
  --accent-wash: rgba(36, 64, 192, 0.06);
  --accent-line: rgba(36, 64, 192, 0.22);
  /* Status "startet bald" — bewusst NICHT der Akzent, sonst liest es sich wie "live". */
  --warn: #9a5b06;

  --font: "Aspekta", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --serif: "Instrument Serif", Georgia, "Times New Roman", serif;

  --fs-display: clamp(2.5rem, 5.6vw, 4.9rem);
  --fs-h1: clamp(2.2rem, 4.4vw, 3.4rem);
  --fs-h2: clamp(1.7rem, 3.2vw, 2.5rem);
  --fs-h3: 1.24rem;
  --fs-body: 1.0625rem;
  --fs-sm: 0.9375rem;
  --fs-xs: 0.8rem;

  --lh-tight: 1.05;
  --lh-body: 1.62;

  --radius: 12px;
  --radius-sm: 8px;
  --radius-pill: 999px;

  --container: 1140px;
  --measure: 70ch;
  --pad-x: clamp(1.25rem, 4vw, 2.75rem);
  /* Vorher 4,5-7 rem: zwischen den Abschnitten stand mehr Leerraum als
     Inhalt. Enger gesetzt sieht man pro Bildschirm deutlich mehr. */
  --space: clamp(3rem, 5vw, 4.5rem);

  --ease: cubic-bezier(0.22, 0.75, 0.28, 1);
  --shadow: 0 1px 2px rgba(15, 18, 24, 0.04), 0 12px 32px -18px rgba(15, 18, 24, 0.18);
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --paper: #0c0e13;
    --paper-2: #12151c;
    --paper-sunk: #090b0f;
    --ink: #f2f4f8;
    --ink-2: #d3d8e1;
    --muted: #9aa2b0;
    --faint: #7e8795;
    --line: #1e232d;
    --line-2: #2a303c;
    --accent: #6e86ff;
    --accent-ink: #899cff;
    --accent-wash: rgba(110, 134, 255, 0.1);
    --accent-line: rgba(110, 134, 255, 0.3);
    --warn: #fbbf24;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 18px 40px -20px rgba(0, 0, 0, 0.7);
  }
}

:root[data-theme="light"] {
  color-scheme: light;
  --paper: #f7f8fa; --paper-2: #ffffff; --paper-sunk: #eef0f4;
  --ink: #0f1218; --ink-2: #2c313b; --muted: #59606c; --faint: #676d79;
  --line: #e5e8ee; --line-2: #d7dbe4;
  --accent: #2440c0; --accent-ink: #1c33a0; --accent-wash: rgba(36, 64, 192, 0.06); --accent-line: rgba(36, 64, 192, 0.22);
  --warn: #9a5b06;
  --shadow: 0 1px 2px rgba(15, 18, 24, 0.04), 0 12px 32px -18px rgba(15, 18, 24, 0.18);
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --paper: #0c0e13; --paper-2: #12151c; --paper-sunk: #090b0f;
  --ink: #f2f4f8; --ink-2: #d3d8e1; --muted: #9aa2b0; --faint: #7e8795;
  --line: #1e232d; --line-2: #2a303c;
  --accent: #6e86ff; --accent-ink: #899cff; --accent-wash: rgba(110, 134, 255, 0.1); --accent-line: rgba(110, 134, 255, 0.3);
  --warn: #fbbf24;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 18px 40px -20px rgba(0, 0, 0, 0.7);
}

/* Registered so it can be transitioned — a plain custom property can't animate,
   which is why the hover pool used to snap instead of fade. */
@property --spot {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

/* ---------- Base ---------- */
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
::selection { background: var(--accent); color: #fff; }
img, svg { max-width: 100%; display: block; }
/* <picture> ist nur ein Format-Schalter, kein Layout-Kasten. Ohne diese Zeile
   haengt jedes "height: 100%" am <picture> (Hoehe auto) statt am Container —
   der Scroll-Hero und die Sticky-Buehne fielen damit in sich zusammen. */
picture { display: contents; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }
strong { font-weight: 640; color: var(--ink); }

.container { max-width: var(--container); margin: 0 auto; padding: 0 var(--pad-x); }
.container-wide { max-width: 1320px; margin: 0 auto; padding: 0 var(--pad-x); }

/* ---------- Typography ---------- */
h1, h2, h3, h4 { font-weight: 640; letter-spacing: -0.021em; line-height: var(--lh-tight); text-wrap: balance; }
.display {
  font-size: var(--fs-display);
  font-weight: 660;
  letter-spacing: -0.035em;
  line-height: 0.98;
}
.h1 { font-size: var(--fs-h1); letter-spacing: -0.028em; }
.h2 { font-size: var(--fs-h2); letter-spacing: -0.026em; }
h3, .h3 { font-size: var(--fs-h3); font-weight: 600; letter-spacing: -0.012em; line-height: 1.25; }
.serif { font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: -0.01em; }
.accent-text { color: var(--accent); }

.lede { font-size: clamp(1.12rem, 1.7vw, 1.35rem); line-height: 1.55; color: var(--ink-2); max-width: var(--measure); letter-spacing: -0.012em; }
.body { color: var(--muted); max-width: var(--measure); }
.body + .body { margin-top: 1rem; }
.muted { color: var(--muted); }
.faint { color: var(--faint); }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: var(--fs-xs);
  font-weight: 560;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.eyebrow::before {
  content: "";
  width: 22px; height: 1px;
  background: var(--accent);
}

/* Section label (no numbers — labels encode meaning, not decoration) */
.label {
  font-size: var(--fs-xs);
  font-weight: 560;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.78rem 1.45rem;
  border-radius: var(--radius-pill);
  font-size: var(--fs-sm);
  font-weight: 560;
  letter-spacing: -0.006em;
  border: 1px solid transparent;
  transition: transform 0.4s var(--ease), background 0.3s var(--ease), border-color 0.3s var(--ease), color 0.3s var(--ease);
  white-space: nowrap;
}
.btn .arr { transition: transform 0.4s var(--ease); }
.btn:hover .arr { transform: translateX(3px); }
.btn-primary { background: var(--ink); color: var(--paper); }
.btn-primary:hover { transform: translateY(-2px); }
.btn-outline { border-color: var(--line-2); color: var(--ink); }
.btn-outline:hover { border-color: var(--ink); transform: translateY(-2px); }
.btn-lg { padding: 0.95rem 1.7rem; font-size: 1rem; }

.link {
  color: var(--accent);
  font-weight: 540;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  transition: gap 0.3s var(--ease);
}
.link:hover { gap: 0.65rem; }
.link .arr { transition: transform 0.3s var(--ease); }
.link:hover .arr { transform: translateX(2px); }

/* ---------- Skip link (keyboard / screen reader) ---------- */
.skip { position: fixed; left: 12px; top: -60px; z-index: 200; background: var(--ink);
  color: var(--paper); padding: .6rem 1rem; border-radius: 8px; transition: top .2s; }
.skip:focus { top: 12px; }

/* ---------- Nav ---------- */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  transition: background 0.4s var(--ease), border-color 0.4s var(--ease), backdrop-filter 0.4s;
  border-bottom: 1px solid transparent;
}
.nav.scrolled {
  /* 82 % war zu wenig: grosse Ueberschriften und das Laufband liefen lesbar
     durch die Leiste und kollidierten mit Logo und Links. 94 % + staerkerer
     Blur laesst noch Bewegung durchscheinen, aber keinen lesbaren Text. */
  background: color-mix(in srgb, var(--paper) 98%, transparent);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
  border-bottom-color: var(--line);
}
.nav-inner {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--pad-x);
  height: 72px;
  /* 1fr auto 1fr — the link row is centred on the bar, not on whatever
     is left over between two clusters of different width. */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1.5rem;
}
.nav-left { justify-self: start; }

/* scroll progress — quiet feedback that the page is moving */
.nav-progress { height: 1.5px; background: transparent; }
.nav-progress i {
  display: block;
  height: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 0.1s linear;
}

/* Wordmark: das echte Logo (Turm-Piktogramm mit der 2 + Schriftzug).
   Die Datei ist schwarz auf Transparenz — im Dark Mode wird sie invertiert,
   sonst verschwindet sie auf dem dunklen Papier. Beide Schaltwege sind
   abgedeckt: die Systemeinstellung und der Kopf-Schalter (data-theme). */
.wordmark { display: inline-flex; align-items: center; }
.wordmark img {
  /* Das Logo traegt drei Textzeilen (TURM/zwei/LABS) — unter ~40px
     verschwimmen sie. 44px in der Nav, im Footer traegt es die Marke allein. */
  height: 44px;
  width: auto;
  display: block;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .wordmark img { filter: invert(1); }
}
:root[data-theme="dark"] .wordmark img { filter: invert(1); }
:root[data-theme="light"] .wordmark img { filter: none; }
/* Im Footer steht das Logo etwas größer, es trägt dort die Marke allein. */
.footer-brand .wordmark img { height: 52px; }

.nav-links { display: flex; align-items: center; justify-content: center; gap: 2.25rem; }
.nav-links a { font-size: var(--fs-sm); font-weight: 480; color: var(--muted); transition: color 0.25s; position: relative; }
.nav-links a:hover { color: var(--ink); }
.nav-links a.active { color: var(--ink); font-weight: 540; }

.nav-right { display: flex; align-items: center; justify-self: end; gap: 0.9rem; }
.icon-btn {
  width: 44px; height: 44px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  display: grid;
  place-items: center;
  color: var(--muted);
  transition: color 0.25s, border-color 0.25s, background 0.25s;
}
.icon-btn:hover { color: var(--ink); border-color: var(--line-2); }
.icon-btn svg { width: 17px; height: 17px; }
.lang { font-size: var(--fs-xs); font-weight: 560; letter-spacing: 0.08em; color: var(--muted); padding: 0 0.35rem; }
.lang:hover { color: var(--ink); }
.theme-sun { display: none; }
:root[data-theme="dark"] .theme-sun, .theme-moon { display: block; }
:root[data-theme="dark"] .theme-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-sun { display: block; }
  :root:not([data-theme="light"]) .theme-moon { display: none; }
}
.nav-cta { padding: 0.5rem 1.05rem; font-size: var(--fs-sm); }

.burger { display: none; width: 44px; height: 44px; position: relative; z-index: 130; }
.burger span { position: absolute; left: 9px; right: 9px; height: 1.5px; background: var(--ink); transition: transform 0.35s var(--ease), opacity 0.3s; }
.burger span:nth-child(1) { top: 17px; }
.burger span:nth-child(2) { top: 22px; }
.burger span:nth-child(3) { top: 27px; }
body.menu-open .burger span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
body.menu-open .burger span:nth-child(2) { opacity: 0; }
body.menu-open .burger span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: var(--paper);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 var(--pad-x);
  gap: 0.25rem;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s var(--ease), visibility 0.4s;
}
body.menu-open .mobile-menu { opacity: 1; visibility: visible; }
/* Ohne diese Sperre scrollt die Seite HINTER dem offenen Menue weiter — man
   wischt, das Menue steht still und der Inhalt dahinter wandert (Joe, 21.09.).
   `overscroll-behavior` faengt zusaetzlich das Gummiband am Rand ab. */
body.menu-open { overflow: hidden; }
.mobile-menu { overscroll-behavior: contain; }
/* Der Burger traegt z-index 130 und sollte damit ueber dem Menue (120) liegen —
   er sitzt aber in `.nav` mit z-index 100, und das ist ein eigener
   Stacking-Context: sein 130 wirkt nur INNERHALB des Headers. Effektiv lag er
   also auf 100, unter dem Menue, und war nicht mehr antippbar — das Menue liess
   sich nur noch ueber einen seiner Links schliessen. Der Header muss im
   geoeffneten Zustand selbst nach oben. */
body.menu-open .nav { z-index: 130; }
/* Dadurch wird der Header im offenen Menue sichtbar — und der Sprachwechsel
   stuende zweimal da, oben und unten im .mm-foot. Der untere bleibt (er liegt
   neben dem Knopf, in Daumenreichweite), der obere tritt zurueck. */
body.menu-open .nav .lang { display: none; }
/* NUR die Navigationslinks (direkte Kinder). Vorher traf die Regel auch den
   Schreibfit-Knopf und den Sprachwechsel im .mm-foot: Der Knopf erbte 32 px
   Schrift, `padding: … 0` (Text ragte links und rechts aus der Pille) und
   `color: var(--ink-2)` — hellgrau auf hellem Knopf, Kontrast ~1,2:1,
   praktisch unlesbar. Gefunden von Joe am Handy, 21.09. */
.mobile-menu > a { font-size: clamp(2rem, 8vw, 3rem); font-weight: 620; letter-spacing: -0.03em; padding: 0.5rem 0; color: var(--ink-2); transition: color 0.25s; }
.mobile-menu > a:hover { color: var(--accent); }
.mobile-menu .mm-foot { margin-top: 2.5rem; display: flex; gap: 1rem; align-items: center; }
.mobile-menu .mm-foot .lang { font-size: var(--fs-sm); font-weight: 600; letter-spacing: .02em; color: var(--ink-2); padding: .78rem .4rem; }
.mobile-menu .mm-foot .lang:hover { color: var(--accent); }

/* ---------- Section rhythm ---------- */
.section { padding: var(--space) 0; }
/* Abschnittswechsel ohne Kante: die harten 1-px-Linien oben und unten haben
   die Seite in gestapelte Bloecke zerlegt. Jetzt laeuft der dunklere Grund an
   beiden Enden weich in den hellen aus — der Wechsel bleibt spuerbar, die
   Trennung verschwindet. */
.section.sunk { background: var(--paper-sunk); position: relative; }
.section.sunk::before,
.section.sunk::after {
  content: "";
  position: absolute; left: 0; right: 0;
  height: clamp(60px, 9vw, 130px);
  pointer-events: none;
}
.section.sunk::before { top: 0;    background: linear-gradient(var(--paper), transparent); }
.section.sunk::after  { bottom: 0; background: linear-gradient(transparent, var(--paper)); }
/* Grenzen zwei dunkle Abschnitte aneinander, darf dazwischen nichts aufhellen. */
.section.sunk + .section.sunk::before { display: none; }
.section.sunk:has(+ .section.sunk)::after { display: none; }
.section-head { max-width: 62ch; margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.section-head .label { display: block; margin-bottom: 1.1rem; }
.section-head .h2 { margin-bottom: 0; }

/* ============================================================
   CHIP LAYER — under the paper lies silicon.
   The canvas holds a generated circuit; a cursor-tracked mask
   is the only thing that lets it show through.
   ============================================================ */
/* Two layers: 0 = the circuit + tower field (masked), 2 = the words above it. */
[data-chip-host] { position: relative; isolation: isolate; }
[data-chip-host] > *:not(.chip-layer) { position: relative; z-index: 2; }

/* No CSS mask here: the board is revealed by SEVERAL travelling points at once
   (cursor + the tower's orbiting point + roaming data points), and a CSS mask
   composites its layers by intersection where we need their union. That union is
   built per frame in the canvas instead — see main.js. */
.chip-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

/* ---------- Hero — owns the whole first screen ---------- */
.hero {
  position: relative;
  padding-top: 72px;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}
/* the stage takes whatever the band and strip leave over, and centres the copy in it */
.hero-stage {
  position: relative;
  overflow: hidden;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  min-height: 0;
}
.hero-stage > .container { width: 100%; }
/* vh-based, not vw: this padding competes with the band and strip for the
   viewport's height, so it has to scale with height. */
.hero-copy { padding: clamp(1.25rem, 4vh, 3rem) 0; }
.hero-copy .eyebrow { margin-bottom: 1.7rem; }
.hero-copy .display { max-width: 21ch; margin-bottom: 1.9rem; }
.hero-copy .lede { max-width: 50ch; margin-bottom: 2.2rem; }
.hero-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }

/* full-bleed band, straight after the hero: the drawn tower becomes the real one */
.photo-band {
  position: relative;
  /* Vorher 220–360 px: davon blieb nur ein Backsteinstreifen uebrig.
     Jetzt hoch genug, dass der Turm als Gebaeude lesbar bleibt. */
  height: clamp(340px, 52svh, 560px);
  border-bottom: 1px solid var(--line);
  overflow: hidden;
}
/* Etwas oberhalb der Mitte anschneiden: bei Gebaeudefotos steht das
   Interessante oben, nicht auf der Strasse. */
.photo-band img { width: 100%; height: 100%; object-fit: cover; object-position: center 42%; }

/* Honest photo placeholder: brand monogram watermark, no faked illustration */
.photo-slot {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background:
    radial-gradient(90% 120% at 50% 100%, var(--accent-wash), transparent 62%),
    var(--paper-2);
}
.photo-slot::before {
  content: "2";
  font-weight: 700;
  font-size: clamp(9rem, 26vh, 20rem);
  line-height: 0.8;
  letter-spacing: -0.06em;
  color: var(--ink);
  opacity: 0.028;
}
.figure-cap {
  position: absolute;
  left: 1.5rem; bottom: 1.5rem;
  z-index: 2;
  font-size: var(--fs-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
  background: color-mix(in srgb, var(--paper) 90%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border: 1px solid var(--line);
  padding: 0.4rem 0.75rem;
  border-radius: var(--radius-pill);
}

/* strip of studio facts under hero */
.hero-strip { flex: 0 0 auto; border-top: 1px solid var(--line); }
.hero-strip .container { display: flex; flex-wrap: wrap; gap: clamp(1.5rem, 5vw, 4rem); padding-top: 1.05rem; padding-bottom: 1.05rem; }
.hero-strip .fact { font-size: var(--fs-sm); color: var(--faint); }
.hero-strip .fact b { display: block; color: var(--ink-2); font-weight: 560; }

/* ---------- Page header (subpages) ---------- */
.page-head { padding: calc(72px + clamp(3.5rem, 8vw, 6rem)) 0 clamp(2.5rem, 5vw, 3.5rem); }
.page-head .eyebrow { margin-bottom: 1.4rem; }
.page-head .display { max-width: 15ch; margin-bottom: 1.4rem; }
.page-head .lede { margin-top: 0.5rem; }

/* ---------- Split ---------- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2.5rem, 6vw, 5rem); align-items: center; }
.split.lean { grid-template-columns: 1.1fr 0.9fr; }
.split .h2 { margin-bottom: 1.4rem; }
.split .media { order: 1; }

/* Feature list — no ticks-in-boxes cliché; hairline rows.
   .bare drops the marker column where the items are attributes, not a sequence. */
.rows { list-style: none; display: grid; }
.rows li { display: grid; grid-template-columns: auto 1fr; gap: 1rem; padding: 1.15rem 0; border-top: 1px solid var(--line); }
.rows.bare li { grid-template-columns: 1fr; }
.rows li:last-child { border-bottom: 1px solid var(--line); }
.rows .k { color: var(--accent); font-weight: 600; font-size: var(--fs-sm); font-variant-numeric: tabular-nums; padding-top: 0.05rem; }
.rows .v { color: var(--muted); }
.rows .v b { display: block; color: var(--ink); font-weight: 560; margin-bottom: 0.15rem; }

/* Plain fact card */
.factcard {
  --spot: 0;
  background-color: var(--paper-2);
  background-image: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in srgb, var(--accent) calc(var(--spot) * 9%), transparent), transparent 70%);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(1.6rem, 3vw, 2.2rem);
  transition: border-color 0.35s var(--ease), --spot 0.4s var(--ease);
}
.factcard:hover { border-color: var(--line-2); --spot: 1; }
.factcard h3 { margin-bottom: 1.3rem; }

/* ---------- Editorial figure (tower) ---------- */
.figure {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--paper-2);
}
.figure img { width: 100%; height: 100%; object-fit: cover; }
.figure .figure-cap { left: 1.1rem; bottom: 1.1rem; }

/* ---------- Values (type-driven, no emoji) ---------- */
.value-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line-2); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.value {
  --spot: 0;
  min-height: 190px;
  background-color: var(--paper);
  /* the cursor lifts a pool of accent out of the surface; --spot fades it */
  background-image: radial-gradient(200px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in srgb, var(--accent) calc(var(--spot) * 9%), transparent), transparent 70%);
  padding: clamp(1.6rem, 3vw, 2.3rem);
  transition: background-color 0.35s var(--ease), --spot 0.4s var(--ease);
}
.value:hover { background-color: var(--paper-2); --spot: 1; }
.value .vk { font-size: var(--fs-xs); font-weight: 560; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); display: block; margin-bottom: 1.4rem; }
.value h3 { margin-bottom: 0.55rem; }
.value p { color: var(--muted); font-size: var(--fs-sm); }

/* ---------- Product block ---------- */
.product {
  display: grid;
  grid-template-columns: 1.08fr 0.92fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(2rem, 4.5vw, 3.4rem);
}
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--fs-xs);
  font-weight: 560;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-wash);
  border: 1px solid var(--accent-line);
  padding: 0.35rem 0.8rem;
  border-radius: var(--radius-pill);
  margin-bottom: 1.5rem;
}
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.product .p-name { font-size: clamp(1.9rem, 3.6vw, 2.7rem); letter-spacing: -0.03em; margin-bottom: 0.9rem; }
.product .p-desc { color: var(--muted); margin-bottom: 1.6rem; max-width: 46ch; }
.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 2rem; }
.chip { font-size: var(--fs-sm); color: var(--ink-2); border: 1px solid var(--line-2); border-radius: var(--radius-pill); padding: 0.35rem 0.85rem; }

/* device mock — minimal ink lines */
.device-wrap { display: flex; justify-content: center; }
.device {
  width: min(272px, 74vw);
  aspect-ratio: 9 / 17;
  border: 1px solid var(--line-2);
  border-radius: 34px;
  background: var(--paper);
  padding: 14px;
  box-shadow: var(--shadow);
}
.device .screen {
  height: 100%;
  border-radius: 22px;
  background: var(--paper-2);
  border: 1px solid var(--line);
  padding: 1.5rem 1.05rem 1.05rem;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}
.device .s-next {
  align-self: stretch;
  text-align: center;
  font-size: 0.82rem;
  font-weight: 560;
  color: var(--paper);
  background: var(--ink);
  border-radius: var(--radius-pill);
  padding: 0.55rem 0;
  margin-top: 0.15rem;
}
.device .s-label { font-size: var(--fs-xs); letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); }
.device .s-l { height: 8px; border-radius: 4px; background: var(--paper-sunk); }
.device .s-l.w70 { width: 70%; }
.device .s-l.w50 { width: 50%; }
.device .s-word {
  align-self: flex-start;
  font-size: 0.9rem;
  font-weight: 500;
  padding: 0.4rem 0.65rem;
  border-radius: 7px;
  color: var(--accent);
  background: var(--accent-wash);
  text-decoration: underline wavy var(--accent-line) 1.5px;
  text-underline-offset: 4px;
}
.device .s-hint { font-size: 0.8rem; line-height: 1.5; color: var(--muted); border-left: 2px solid var(--accent-line); padding: 0.15rem 0 0.15rem 0.7rem; }
.device .s-bar { margin-top: auto; }
.device .s-bar .track { height: 6px; border-radius: 4px; background: var(--paper-sunk); overflow: hidden; }
.device .s-bar .track i { display: block; height: 100%; width: 72%; background: var(--accent); border-radius: 4px; }
.device .s-bar span { font-size: var(--fs-xs); color: var(--faint); display: block; margin-top: 0.4rem; }

/* ---------- Steps (real sequence → numbers allowed) ---------- */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.5rem, 3vw, 2.5rem); }
.step {
  --spot: 0;
  padding: 1.4rem 1.2rem 1.4rem 0;
  border-top: 1.5px solid var(--ink);
  background-image: radial-gradient(200px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in srgb, var(--accent) calc(var(--spot) * 9%), transparent), transparent 70%);
  transition: --spot 0.4s var(--ease);
}
.step:hover { --spot: 1; }
.step .sn { font-size: var(--fs-sm); font-weight: 600; font-variant-numeric: tabular-nums; color: var(--accent); display: block; margin-bottom: 1rem; }
.step h3 { margin-bottom: 0.5rem; }
.step p { color: var(--muted); font-size: var(--fs-sm); }

/* ---------- Timeline ---------- */
.timeline { border-top: 1px solid var(--line); }
.tl {
  --spot: 0;
  display: grid;
  grid-template-columns: 150px 1fr auto;
  gap: 1.5rem;
  align-items: center;
  padding: 1.6rem 0.75rem;
  border-bottom: 1px solid var(--line);
  background-image: radial-gradient(280px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in srgb, var(--accent) calc(var(--spot) * 9%), transparent), transparent 70%);
  transition: --spot 0.4s var(--ease);
}
.tl:hover { --spot: 1; }
.tl .st { font-size: var(--fs-xs); letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); display: inline-flex; align-items: center; gap: 0.5rem; }
.tl.live .st { color: var(--accent); }
.tl.live .st::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
/* "Startet bald" ist kein "Live" — eigene, waermere Signalfarbe statt des
   Akzents, damit der Status nicht wie ein erledigter Launch aussieht. */
.tl.bald .st { color: var(--warn); }
.tl.bald .st::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--warn); }
.tl h3 { font-size: 1.15rem; margin-bottom: 0.15rem; }
.tl p { color: var(--muted); font-size: var(--fs-sm); }

/* ---------- Team ---------- */
.team { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem; }
/* --spot is registered with inherits:false, so it must be set on the very element
   that draws the gradient — not on the parent. */
.member .ph {
  --spot: 0;
  aspect-ratio: 3 / 4;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background-color: var(--paper-2);
  background-image: radial-gradient(220px circle at var(--mx, 50%) var(--my, 40%),
    color-mix(in srgb, var(--accent) calc(var(--spot) * 10%), transparent), transparent 70%);
  display: grid;
  place-items: center;
  margin-bottom: 1rem;
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.9rem;
  color: var(--faint);
  transition: border-color 0.35s var(--ease), transform 0.45s var(--ease), --spot 0.4s var(--ease);
}
.member:hover .ph { border-color: var(--line-2); transform: translateY(-3px); --spot: 1; }
.member h3 { font-size: 1.05rem; margin-bottom: 0.15rem; }
.member .role { color: var(--muted); font-size: var(--fs-sm); }

/* ---------- Quote ---------- */
.pullquote { max-width: 30ch; }
.pullquote .q { font-family: var(--serif); font-style: italic; font-size: clamp(2.4rem, 5.4vw, 4rem); line-height: 1.08; letter-spacing: -0.02em; color: var(--ink); }
.pullquote .cite { margin-top: 1.4rem; font-size: var(--fs-sm); color: var(--muted); }

/* ---------- CTA band ---------- */
.cta { text-align: center; padding: var(--space) 0; }
.cta .h2 { max-width: 20ch; margin: 0 auto 1.2rem; }
.cta p { color: var(--muted); max-width: 46ch; margin: 0 auto 2rem; }

/* ---------- Contact ---------- */
.contact { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: clamp(2rem, 5vw, 4rem); align-items: start; }
.formcard { background: var(--paper-2); border: 1px solid var(--line); border-radius: var(--radius); padding: clamp(1.75rem, 4vw, 2.75rem); }
.frow { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
.field { margin-bottom: 1.15rem; display: flex; flex-direction: column; gap: 0.45rem; }
.field label { font-size: var(--fs-sm); font-weight: 540; color: var(--ink-2); }
.field input, .field select, .field textarea {
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--ink);
  background: color-mix(in srgb, var(--ink) 5%, var(--paper-2));
  border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
  border-radius: var(--radius-sm);
  padding: 0.8rem 0.9rem;
  transition: border-color 0.25s, box-shadow 0.25s;
  width: 100%;
}
.field select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2359606c' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 0.95rem center; padding-right: 2.4rem; }
.field textarea { min-height: 140px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-wash); }
.check { display: flex; gap: 0.7rem; align-items: flex-start; font-size: var(--fs-sm); color: var(--muted); margin: 0.3rem 0 1.5rem; }
.check input { width: 17px; height: 17px; margin-top: 0.15rem; accent-color: var(--accent); flex: none; }
.form-note { font-size: var(--fs-xs); color: var(--faint); margin-top: 1rem; }
.form-ok { display: none; text-align: center; padding: 2.5rem 1rem; }
.form-ok .ok-mark { width: 46px; height: 46px; border-radius: 50%; border: 1.5px solid var(--accent); color: var(--accent); display: grid; place-items: center; margin: 0 auto 1.1rem; }
.formcard.sent form { display: none; }
.formcard.sent .form-ok { display: block; }
/* Fehlermeldung des Formulars. Sie steht ueber dem Knopf, nicht als Alert-Box
   oben — dort, wo der Blick nach dem Klick ohnehin schon ist. */
.form-fehler { display: none; margin: 0 0 1rem; padding: .85rem 1rem; border-radius: var(--radius-sm);
  border: 1px solid color-mix(in srgb, #e11d48 40%, var(--line)); background: color-mix(in srgb, #e11d48 8%, transparent);
  color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.5; }
.form-fehler.an { display: block; }
.form-fehler a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
/* Der Koeder fuer Bots: fuer Menschen und Screenreader nicht vorhanden. */
.koeder { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
button[disabled] { opacity: .6; cursor: progress; }

.infocard { border: 1px solid var(--line); border-radius: var(--radius); padding: clamp(1.6rem, 3.5vw, 2.4rem); background: var(--paper-2); }
.info-item { padding: 1.1rem 0; border-bottom: 1px solid var(--line); }
.info-item:first-child { padding-top: 0; }
.info-item:last-child { border-bottom: 0; padding-bottom: 0; }
.info-item .il { font-size: var(--fs-xs); letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); margin-bottom: 0.4rem; }
.info-item .iv { color: var(--ink); font-weight: 500; }
.info-item .iv a:hover { color: var(--accent); }

/* ---------- FAQ (native <details> — interactive without a line of JS) ---------- */
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  list-style: none;
  cursor: pointer;
  padding: 1.35rem 0.75rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  font-weight: 560;
  font-size: 1.05rem;
  letter-spacing: -0.012em;
  transition: color 0.25s;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--accent); }
.faq summary .sign { position: relative; width: 13px; height: 13px; flex: none; color: var(--accent); }
.faq summary .sign::before,
.faq summary .sign::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 1.5px;
  background: currentColor;
  transition: transform 0.35s var(--ease);
}
.faq summary .sign::after { transform: rotate(90deg); }
.faq details[open] summary .sign::after { transform: rotate(0deg); }
.faq .answer { padding: 0 0.75rem 1.5rem; color: var(--muted); font-size: var(--fs-sm); max-width: 68ch; }

/* ---------- Map (two-click: nothing reaches Google until asked) ---------- */
.map-card {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  height: clamp(300px, 42vh, 440px);
  background-color: var(--paper-2);
  background-image:
    radial-gradient(90% 120% at 50% 100%, var(--accent-wash), transparent 60%),
    /* faint street-grid hint, so the unloaded state still reads as a map */
    repeating-linear-gradient(0deg, var(--line) 0 1px, transparent 1px 44px),
    repeating-linear-gradient(90deg, var(--line) 0 1px, transparent 1px 44px);
  display: grid;
  place-items: center;
}
.map-ph { text-align: center; padding: 1.5rem; max-width: 42ch; }
.map-ph .pin {
  width: 42px; height: 42px;
  margin: 0 auto 1.1rem;
  border-radius: 50%;
  display: grid; place-items: center;
  color: var(--accent);
  border: 1px solid var(--accent-line);
  background: var(--paper);
}
.map-ph h3 { margin-bottom: 0.4rem; }
.map-ph p { color: var(--muted); font-size: var(--fs-sm); margin-bottom: 1.2rem; }
.map-card iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.map-card.loaded .map-ph { display: none; }
.map-meta { display: flex; flex-wrap: wrap; gap: 1.25rem 2rem; align-items: center; justify-content: space-between; margin-top: 1.25rem; }

/* ---------- Legal ---------- */
.legal { max-width: 720px; }
.legal h2 { font-size: 1.35rem; margin: 2.4rem 0 0.85rem; }
.legal h2:first-child { margin-top: 0; }
.legal p, .legal li { color: var(--muted); font-size: var(--fs-sm); line-height: 1.7; }
.legal ul { padding-left: 1.2rem; margin: 0.6rem 0; }
.legal p { margin-bottom: 0.6rem; }
.notice { border: 1px solid var(--accent-line); background: var(--accent-wash); border-radius: var(--radius); padding: 1.15rem 1.4rem; color: var(--ink-2); font-size: var(--fs-sm); margin-bottom: 2.5rem; }
.notice strong { color: var(--accent); }

/* ---------- Footer ---------- */
/* No margin-top: the preceding section already carries var(--space) bottom padding, and
   on the chip-host CTA that padding is INSIDE the canvas (interactive). A footer margin
   here added a second, dead (canvas-less) dark strip below the CTA — the reveal appeared
   to stop short of the footer. */
.footer { background: var(--paper-sunk); border-top: 1px solid var(--line); }
.footer-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 2.5rem; padding: clamp(3rem, 6vw, 4.5rem) 0 3rem; }
.footer h4 { font-size: var(--fs-xs); letter-spacing: 0.14em; text-transform: uppercase; color: var(--faint); margin-bottom: 1.1rem; font-weight: 560; }
.footer ul { list-style: none; display: grid; gap: 0.65rem; }
.footer a { color: var(--muted); font-size: var(--fs-sm); transition: color 0.25s; }
.footer a:hover { color: var(--ink); }
.footer-brand p { color: var(--muted); font-size: var(--fs-sm); margin-top: 1rem; max-width: 32ch; }
.footer-bottom { border-top: 1px solid var(--line); padding: 1.4rem 0 1.6rem; display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1rem; font-size: var(--fs-xs); color: var(--faint); }

/* ---------- Reveal ---------- */
[data-reveal] { opacity: 0; transform: translateY(20px); transition: opacity 0.8s var(--ease), transform 0.8s var(--ease); transition-delay: var(--d, 0s); }
[data-reveal].in { opacity: 1; transform: none; }

/* ---------- Responsive ---------- */

@media (max-width: 940px) {
  .hero { min-height: 0; }
  .hero-stage { min-height: 82svh; }
  /* The tower isn't built below 940px (initChip skips it) — the real photo band
     right below carries the visual on small screens. */
  .hero-copy { padding: clamp(3rem, 9vw, 5rem) 0 clamp(2.5rem, 6vw, 3.5rem); }
  .hero-copy .display { max-width: 16ch; }
  .photo-band { height: clamp(240px, 40svh, 360px); }
  /* .split.lean (0,2,0) outranks a bare .split rule, so it must be named here or
     the "lean" sections stay a cramped two columns on phones. */
  .split, .split.lean, .product, .contact { grid-template-columns: 1fr; }
  .split .media { order: -1; }
  /* a pullquote reads better after the text it punctuates; image figures stay above */
  .split .media:has(.pullquote) { order: 1; }
  .value-grid { grid-template-columns: repeat(2, 1fr); }
  .steps { grid-template-columns: 1fr; }
  .team { grid-template-columns: repeat(2, 1fr); }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .tl { grid-template-columns: 120px 1fr; }
  .tl .tl-cta { grid-column: 2; justify-self: start; }
}
@media (max-width: 720px) {
  .nav-links, .nav-cta { display: none; }
  .burger { display: block; }
  .frow { grid-template-columns: 1fr; }
  /* the 1fr auto 1fr grid squeezes the wordmark once the links are gone */
  .nav-inner { display: flex; justify-content: space-between; }
}
@media (max-width: 560px) {
  .value-grid { grid-template-columns: 1fr; }
}
@media (max-width: 480px) {
  .team { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr; gap: 2rem; }
  .hero-strip .container { flex-direction: column; gap: 1rem; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
  [data-reveal] { opacity: 1; transform: none; }
  /* the chip reveal stays (it is user-driven), but nothing moves on its own */
}

/* ── Fotos ────────────────────────────────────────────────────────────────────
   Nachgetragen 2026-08-31. Die Seite behauptete an drei Stellen einen realen Ort
   („ein echtes Gebäude, eine echte Adresse") und zeigte ihn nie. Haltung wie beim
   Rest: Haarlinie statt Schatten, moderater Radius, keine Effekte. Das Bild soll
   belegen, nicht dekorieren. */
.shot { margin: 0; }
.shot picture { display: block; }
.shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--paper-sunk);
}
.shot figcaption {
  margin-top: 0.7rem;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--faint);
}
/* Zwei Bilder nebeneinander — bricht früh um, damit nichts gequetscht wird. */
.shots {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
/* Hochformat (der Turm im Sommer) sonst zu dominant im Fluss. */
.shot.tall img { max-height: 30rem; object-fit: cover; object-position: center 35%; }

/* Echter App-Screenshot statt nachgebautem Geraet. Rahmen wie bei .shot, aber
   mit Hoehenbegrenzung — ein 818x1900-Bild wuerde die Zeile sonst sprengen. */
.appshot { margin: 0; max-width: 300px; }
.appshot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 20px;
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
}

/* Foto-Platzhalter: bewusst SICHTBAR und beschriftet, damit niemand ihn
   uebersieht — anders als die stillen [Platzhalter]-Klammern im Text. Er sagt,
   welches Bild fehlt und wie es aussehen soll. Vor dem Go-Live muss er weg;
   FOTOS-BENOETIGT.md fuehrt alle offenen Motive. */
.shot-todo .todo-frame {
  aspect-ratio: 4 / 3;
  border: 1.5px dashed var(--line-2);
  border-radius: 10px;
  background: var(--paper-2);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.7rem;
  padding: clamp(1.2rem, 3vw, 1.8rem);
}
.shot-todo .todo-kicker {
  font-size: var(--fs-xs);
  font-weight: 560;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--accent);
}
.shot-todo .todo-text { font-size: 0.9rem; line-height: 1.55; color: var(--muted); }
.shot-todo .todo-text b { color: var(--ink); font-weight: 600; }


/* Video-Platzhalter: gestrichelter Rahmen, im 4:3-Rahmen des
   spaeteren Loops. Bewusst sichtbar — er verschwindet, sobald die Datei da ist. */
.vid-todo {
  aspect-ratio: 4 / 3;
  border: 1.5px dashed var(--line-2);
  border-radius: 10px;
  background: var(--paper-2);
  display: flex; flex-direction: column; justify-content: center; gap: .8rem;
  padding: clamp(1.3rem, 3vw, 2rem);
}
.vid-todo .todo-kicker {
  font-size: var(--fs-xs); font-weight: 560; letter-spacing: .15em;
  text-transform: uppercase; color: var(--accent);
}
.vid-todo .todo-text { font-size: .88rem; line-height: 1.55; color: var(--muted); }
.vid-todo .todo-text b { color: var(--ink); font-weight: 600; }
/* Team im Zweispalter: zwei Karten nebeneinander, nicht vier in einer Reihe. */
.split .team { grid-template-columns: repeat(2, 1fr); }

/* ── Bildreihe unter dem Hero ────────────────────────────────────────────────
   Drei Ausschnitte statt eines Breitbands. Randlos aneinander, damit sie als
   ein Streifen lesen und nicht als drei Kacheln — das haelt den Uebergang vom
   Hero in den Text ruhig. */
.band3 {
  display: grid;
  grid-template-columns: 1.25fr 1fr 1fr;
  background: var(--line);
  gap: 1px;
}
.band3 .b3 { position: relative; margin: 0; overflow: hidden; background: var(--paper-2); }
.band3 img {
  width: 100%;
  height: clamp(240px, 32svh, 380px);
  object-fit: cover;
  object-position: center 45%;
  transition: transform .7s var(--ease);
}
.band3 .b3:hover img { transform: scale(1.03); }
.band3 figcaption {
  position: absolute; left: 14px; bottom: 14px;
  font-size: var(--fs-xs); font-weight: 560; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink); background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--radius-pill); padding: .3rem .8rem;
}
@media (max-width: 720px) {
  .band3 { grid-template-columns: 1fr 1fr; }
  .band3 .b3:last-child { display: none; }
  .band3 img { height: 200px; }
}

/* ── Der Turm als Hintergrund ────────────────────────────────────────────────
   „Warum es uns gibt" stand mit Text links und einer Karte rechts auf viel
   Weiss. Der Turm liegt jetzt als sehr blasse Marke dahinter — gross genug,
   dass der Raum gefuellt ist, blass genug, dass der Text ungestoert bleibt. */
.mit-turm { position: relative; overflow: hidden; }
.mit-turm::before {
  content: "";
  position: absolute;
  right: -4%;
  top: 50%;
  transform: translateY(-50%);
  width: clamp(260px, 34vw, 520px);
  aspect-ratio: 256/525;
  background: var(--ink);
  -webkit-mask: url("../img/turm-mark.png") center/contain no-repeat;
  mask: url("../img/turm-mark.png") center/contain no-repeat;
  opacity: .035;
  pointer-events: none;
}
.mit-turm > * { position: relative; z-index: 1; }
@media (max-width: 860px) { .mit-turm::before { display: none; } }

/* ══ Der Turm als Markenzeichen — A, B, E ═════════════════════════════════════
   Ein Bild (turm-mark.png, aus dem Logo geloest) als Maske ueber einer
   Farbflaeche. Dadurch erbt der Turm die Textfarbe und braucht im Dark Mode
   keine zweite Datei. --hoch steuert, wie viel von unten sichtbar ist. */
@property --hoch { syntax: "<percentage>"; inherits: true; initial-value: 0%; }

.tw-mark { position: relative; display: block; aspect-ratio: 256/525; }
.tw-mark i {
  position: absolute; inset: 0; background: currentColor;
  -webkit-mask: url("../img/turm-mark.png") center/contain no-repeat;
  mask: url("../img/turm-mark.png") center/contain no-repeat;
}
.tw-mark .blass { opacity: .13; }
.tw-mark .voll { clip-path: inset(calc(100% - var(--hoch, 0%)) 0 0 0); }

/* ── A · Ladeaufbau ─────────────────────────────────────────────────────────
   Liegt ueber der Seite, bis das erste Bild steht. Kein Spinner: der Turm
   waechst einmal durch und blendet weg. */
.tw-load {
  position: fixed; inset: 0; z-index: 400;
  display: grid; place-items: center;
  background: var(--paper);
  transition: opacity .45s var(--ease), visibility .45s;
}
.tw-load .tw-mark { width: 62px; color: var(--ink); }
.tw-load .voll { animation: tw-wachsen 1s cubic-bezier(.16,.85,.3,1) forwards; }
@keyframes tw-wachsen { from { --hoch: 0%; } to { --hoch: 100%; } }
body.geladen .tw-load { opacity: 0; visibility: hidden; }

/* ── B · Scroll-Fortschritt am rechten Rand ────────────────────────────────
   Ersetzt die Linie unter der Nav. Auf schmalen Schirmen ist rechts kein
   Platz — dort bleibt die Linie. */
.tw-rail {
  position: fixed; right: 22px; top: 50%; transform: translateY(-50%);
  width: 34px; z-index: 90; color: var(--ink);
  opacity: 0; transition: opacity .4s var(--ease);
  pointer-events: none;
}
body.gescrollt .tw-rail { opacity: 1; }
.tw-rail .voll { transition: clip-path .1s linear; }
@media (max-width: 1100px) { .tw-rail { display: none; } }
@media (min-width: 1101px) { .nav-progress { display: none; } }

/* ── E · Trennzeichen zwischen Abschnitten ─────────────────────────────────── */
.tw-rule { display: flex; align-items: center; gap: 1.3rem; color: var(--line-2);
           max-width: var(--container); margin: 0 auto; padding: 0 var(--pad-x); }
.tw-rule::before, .tw-rule::after { content: ""; height: 1px; flex: 1; background: currentColor; }
.tw-rule .tw-mark { width: 16px; color: var(--faint); flex: 0 0 auto; }

@media (prefers-reduced-motion: reduce) {
  .tw-load .voll { animation: none; --hoch: 100%; }
}

/* ══ Mehr Bild, mehr Bewegung ════════════════════════════════════════════════
   Die Seite war zu ruhig und zu leer. Drei Hebel, alle scrollgetrieben und
   ohne Bibliothek: groessere Bilder, Parallaxe darin, und Abschnitte, die
   sich beim Hereinscrollen aufbauen statt einfach dazustehen. */

/* Bilder duerfen deutlich groesser werden. */
.band3 img { height: clamp(300px, 42svh, 500px); }
.shot img  { max-height: none; }

/* Parallaxe: das Bild laeuft langsamer als die Seite. --p kommt aus main.js
   und liegt zwischen -1 und 1, gemessen an der Position im Fenster. */
.parallax { overflow: hidden; }
.parallax img {
  will-change: transform;
  transform: translate3d(0, calc(var(--p, 0) * 42px), 0) scale(1.12);
}

/* Vollbreites Bild zwischen zwei Abschnitten — traegt den Uebergang und
   fuellt den Raum, den vorher Weiss eingenommen hat. */
.breit {
  position: relative;
  margin: 0;
  height: clamp(360px, 62svh, 640px);
  overflow: hidden;
  background: var(--paper-sunk);
}
.breit img { width: 100%; height: 100%; object-fit: cover; }
.breit figcaption {
  position: absolute; left: 50%; bottom: clamp(1.5rem, 4vw, 3rem);
  transform: translateX(-50%);
  font-size: var(--fs-xs); font-weight: 560; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink); background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--radius-pill); padding: .45rem 1.1rem;
}
/* Text auf dem Bild — fuer den Moment, in dem ein Satz das Bild traegt. */
.breit .aufbild {
  position: absolute; inset: 0;
  display: grid; place-items: center; text-align: center;
  padding: var(--pad-x);
  background: linear-gradient(rgba(8,10,14,.42), rgba(8,10,14,.52));
}
.breit .aufbild p {
  color: #fff; font-size: clamp(1.5rem, 3.4vw, 2.6rem); font-weight: 640;
  letter-spacing: -.025em; line-height: 1.15; max-width: 20ch; text-wrap: balance;
}

/* Reveals mit mehr Weg: 14 px waren kaum zu bemerken. */
[data-reveal] { opacity: 0; transform: translateY(26px); }
[data-reveal].in { opacity: 1; transform: none; }

/* Zahlen und Karten staffeln sich beim Hereinscrollen. */
[data-stagger] > * { opacity: 0; transform: translateY(22px);
  transition: opacity .7s var(--ease), transform .7s var(--ease); }
[data-stagger].in > * { opacity: 1; transform: none; }
[data-stagger].in > *:nth-child(2) { transition-delay: .08s }
[data-stagger].in > *:nth-child(3) { transition-delay: .16s }
[data-stagger].in > *:nth-child(4) { transition-delay: .24s }

@media (prefers-reduced-motion: reduce) {
  .parallax img { transform: none; }
  [data-reveal], [data-stagger] > * { opacity: 1; transform: none; }
}

/* ══ Scroll-Expansion-Hero ═══════════════════════════════════════════════════
   Nachbau der React-Komponente scroll-expansion-hero in der Technik, die diese
   Seite hat: kein React, kein Tailwind, kein framer-motion.

   Ein wichtiger Unterschied zum Original: Das Original faengt das Scrollrad ab
   (wheel + preventDefault) und haelt die Seite fest, bis die Animation durch
   ist. Das bricht auf iOS, kollidiert mit Tastatur- und Trackpad-Scrollen und
   macht die Seite fuer Screenreader unbedienbar. Hier uebernimmt position:
   sticky in einem hohen Container dieselbe Wirkung — das Scrollen bleibt echt,
   der Fortschritt ergibt sich aus der Position im Container. */

.sx { position: relative; height: 260vh; }          /* Scrollweg der Animation */
.sx-buehne {
  position: sticky; top: 0; height: 100svh;
  display: grid; place-items: center;
  overflow: hidden;
}
/* Hintergrundbild, blendet aus, waehrend das Medium waechst. */
.sx-bg { position: absolute; inset: 0; z-index: 0; opacity: calc(1 - var(--x, 0) * .9); }
.sx-bg img { width: 100%; height: 100%; object-fit: cover; }
/* Der Schleier ist seit 18.09. leichter: vorher .55/.78 — da war vom Turm
   kaum mehr als eine graue Flaeche zu sehen. Der Titel traegt ueber seinen
   text-shadow. */
.sx-bg::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(rgba(6,8,12,.34), rgba(6,8,12,.62)); }

/* Das Medium in der Mitte: waechst von 300 px auf nahezu Vollbild. */
.sx-medium {
  position: relative; z-index: 2;
  width: calc(300px + var(--x, 0) * (min(92vw, 1250px) - 300px));
  height: calc(min(380px, 52svh) + var(--x, 0) * (min(84svh, 780px) - min(380px, 52svh)));
  border-radius: clamp(10px, calc(20px - var(--x, 0) * 8px), 20px);
  overflow: hidden;
  box-shadow: 0 40px 90px -30px rgba(0,0,0,.75);
}
.sx-medium img, .sx-medium video { width: 100%; height: 100%; object-fit: cover; display: block; }
.sx-medium::after {
  content: ""; position: absolute; inset: 0;
  background: rgba(6,8,12,.42); opacity: calc(.6 - var(--x, 0) * .6);
}

/* Der Titel faehrt auseinander — erstes Wort nach links, Rest nach rechts. */
.sx-titel {
  position: absolute; inset: 0; z-index: 3;
  display: grid; place-content: center; gap: .1em;
  text-align: center; pointer-events: none;
}
.sx-titel span {
  display: block; color: #fff;
  font-size: clamp(2.2rem, 6.5vw, 5rem); font-weight: 680;
  letter-spacing: -.04em; line-height: 1;
  text-shadow: 0 2px 30px rgba(0,0,0,.55), 0 1px 3px rgba(0,0,0,.4);
}
.sx-titel .a { transform: translateX(calc(var(--x, 0) * -46vw)); }
.sx-titel .b { transform: translateX(calc(var(--x, 0) * 46vw)); }

/* Hinweis und Datum, laufen mit dem Titel mit. */
.sx-meta {
  position: absolute; left: 0; right: 0; bottom: clamp(2rem, 7vh, 4.5rem);
  z-index: 3; text-align: center; pointer-events: none;
  opacity: calc(1 - var(--x, 0) * 2.2);
}
.sx-meta p { color: #cfd6ff; font-size: .92rem; letter-spacing: .04em; }
.sx-meta .pfeil { display: block; margin: .6rem auto 0; width: 18px; height: 18px;
  border-right: 2px solid #cfd6ff; border-bottom: 2px solid #cfd6ff;
  transform: rotate(45deg); animation: sx-tippen 1.6s ease-in-out infinite; }
@keyframes sx-tippen { 0%,100% { transform: rotate(45deg) translate(0,0) } 50% { transform: rotate(45deg) translate(4px,4px) } }

/* Der Text darunter erscheint erst, wenn das Medium offen ist. */
.sx-danach {
  opacity: calc((var(--x, 0) - .72) * 3.6);
  transform: translateY(calc((1 - var(--x, 0)) * 26px));
}

/* Erzwungene Umbrueche im FLIESSTEXT (nicht in Adressen) gelten nur auf breiten
   Schirmen. Am Handy liessen sie einzelne Woerter allein am Zeilenende stehen —
   "Regel:" bei 390 px, "Abitur." und "Jaekel," bei 360 px. Dort fliesst der Text. */
@media (max-width: 700px) { br.w-br { display: none; } }

@media (prefers-reduced-motion: reduce) {
  .sx { height: auto; }
  .sx-buehne { position: static; height: auto; padding: 3rem 0; }
  .sx-medium { width: min(92vw, 1100px); height: min(70svh, 620px); }
  .sx-titel .a, .sx-titel .b { transform: none; }
  .sx-danach { opacity: 1; transform: none; }
}

/* ── Link-Hover mit schwebendem Bild (Nachbau social-links.tsx) ───────────── */
[data-hoverbild] { display: flex; align-items: center; justify-content: center;
                   flex-wrap: wrap; gap: 0; }
[data-hoverbild] [data-bild] {
  position: relative; padding: .55rem 1.3rem; font-size: 1.05rem; font-weight: 560;
  transition: opacity .25s var(--ease); cursor: pointer;
}
[data-hoverbild].hb-aktiv [data-bild] { opacity: .45; }
[data-hoverbild].hb-aktiv [data-bild].hb-an { opacity: 1; }
.hb-bild {
  position: absolute; left: 50%; bottom: 100%; width: 66px; height: 66px;
  object-fit: cover; border-radius: 12px; pointer-events: none;
  opacity: 0; filter: blur(2px);
  transform: translate(-50%, 10px) rotate(var(--kipp, 0deg));
  transition: opacity .22s var(--ease), transform .22s var(--ease), filter .22s var(--ease);
}
[data-bild].hb-an .hb-bild {
  opacity: 1; filter: blur(0);
  transform: translate(-50%, -10px) rotate(var(--kipp, 0deg));
}

/* Für Screenreader sichtbar, visuell nicht — die H1 des Scroll-Heros. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ══ Dunkler Auftritt (vorher inline in index.html) ═══════════════════════
   Geteilt, damit ALLE Seiten die Karten, Glows und Pills nutzen koennen. */
  /* ── Grundton ──────────────────────────────────────────────────────────────
     Dunkler und kontrastreicher als Entwurf A. Die Tokens der Seite bleiben,
     nur tiefer gesetzt — dadurch bleibt alles kompatibel. */
  :root[data-theme="dark"] {
    --paper: #08090c; --paper-2: #0e1014; --paper-sunk: #050608;
    --line: #1c1f27; --line-2: #2a2f3a;
    --accent: #6e86ff; --accent-2: #a78bfa;
  }
  body { background: var(--paper); }
  .mono { font-variant-numeric: tabular-nums;
          font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

  /* ── Hero ──────────────────────────────────────────────────────────────── */
  .b-hero { position: relative; padding: clamp(7rem, 15vh, 11rem) 0 clamp(3rem, 6vw, 5rem); overflow: hidden; }
  /* Der Verlauf hinter der Headline — bei Linear das prägende Element.
     Zwei weiche Farbkreise, stark unscharf, sehr niedrig deckend. */
  .b-glow { position: absolute; inset: 0; pointer-events: none; z-index: 0; }
  .b-glow::before, .b-glow::after {
    content: ""; position: absolute; border-radius: 50%; filter: blur(90px);
  }
  .b-glow::before { width: 46vw; height: 46vw; left: 8%; top: -14%;
    background: radial-gradient(circle, rgba(110,134,255,.16), transparent 68%); }
  /* Der zweite, violette Nebel ist gestrichen (12.09.): kein Markenbezug — Logo
     schwarz/weiss, Turm Backstein — und das auffaelligste "KI-Landingpage"-Muster.
     Ein Akzent, halb so laut, reicht. */
  .b-glow::after  { display: none; }
  .b-hero > .container { position: relative; z-index: 1; }

  .b-pill {
    display: inline-flex; align-items: center; gap: .55rem;
    font-size: .78rem; font-weight: 500; letter-spacing: .02em;
    color: var(--ink-2); background: color-mix(in srgb, var(--ink) 4%, transparent);
    border: 1px solid var(--line-2); border-radius: 999px; padding: .38rem .9rem;
  }
  .b-pill .dot { width: 6px; height: 6px; border-radius: 50%; background: #34d399;
                 box-shadow: 0 0 0 3px rgba(52,211,153,.18); }
  /* Gruen heisst "laeuft". Solange die App nicht draussen ist, darf der Punkt
     nicht gruen sein — sonst behauptet die Farbe etwas, das der Text zuruecknimmt. */
  .b-pill.bald .dot { background: var(--warn);
                      box-shadow: 0 0 0 3px color-mix(in srgb, var(--warn) 18%, transparent); }
  .b-title {
    font-size: clamp(2.9rem, 7.2vw, 6rem);
    line-height: .96; letter-spacing: -.045em; font-weight: 680;
    margin: 1.6rem 0 0; max-width: 15ch; text-wrap: balance;
  }
  .b-title em { font-style: normal;
    background: linear-gradient(100deg, var(--accent), var(--accent-2) 60%, #f0abfc);
    -webkit-background-clip: text; background-clip: text; color: transparent; }
  .b-lede { font-size: clamp(1.05rem, 1.5vw, 1.25rem); color: var(--muted);
            max-width: 52ch; margin-top: 1.5rem; line-height: 1.6; }
  .b-cta { display: flex; gap: .75rem; flex-wrap: wrap; margin-top: 2.2rem; }

  /* ── Kennzahlen direkt unter dem Hero ──────────────────────────────────── */
  .b-stats {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
    background: var(--line); gap: 1px; margin-top: clamp(3rem, 7vw, 5rem);
  }
  .b-stat { background: var(--paper); padding: 1.5rem clamp(1rem, 2vw, 1.6rem); }
  .b-stat b { display: block; font-size: 1.9rem; font-weight: 660; letter-spacing: -.03em; }
  .b-stat span { font-size: .78rem; color: var(--faint); letter-spacing: .1em; text-transform: uppercase; }

  /* ── Karten-Raster ─────────────────────────────────────────────────────── */
  .b-sec { padding: clamp(3.5rem, 7vw, 6rem) 0; }
  .b-kopf { max-width: 60ch; margin-bottom: clamp(2rem, 4vw, 3rem); }
  .b-label { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
             font-size: max(.74rem, 12px); letter-spacing: .12em; text-transform: uppercase; color: var(--accent); }
  .b-h2 { font-size: clamp(1.8rem, 3.4vw, 2.9rem); letter-spacing: -.03em;
          line-height: 1.08; font-weight: 660; margin-top: .9rem; text-wrap: balance; }
  .b-sub { color: var(--muted); margin-top: 1rem; line-height: 1.65; }

  .b-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1px;
            background: var(--line); border: 1px solid var(--line); border-radius: 14px; overflow: hidden; }
  .b-card { background: var(--paper-2); padding: clamp(1.4rem, 2.6vw, 2rem);
            position: relative; transition: background .35s var(--ease); }
  .b-card:hover { background: color-mix(in srgb, var(--paper-2) 90%, var(--ink)); }
  /* Der Glow folgt dem Zeiger — dieselbe Idee wie bei Linears Karten. */
  .b-card::before {
    content: ""; position: absolute; inset: 0; opacity: 0; transition: opacity .35s var(--ease);
    background: radial-gradient(320px circle at var(--mx, 50%) var(--my, 50%),
                rgba(110,134,255,.10), transparent 65%);
  }
  .b-card:hover::before { opacity: 1; }
  .b-card > * { position: relative; }
  .b-card .n { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
               font-size: max(.74rem, 12px); color: var(--faint); }
  .b-card h3 { font-size: 1.12rem; font-weight: 620; margin: .8rem 0 .5rem; letter-spacing: -.015em; }
  .b-card p { color: var(--muted); font-size: .94rem; line-height: 1.6; }

  /* ── Produkt: grosses Bild, dunkle Buehne ──────────────────────────────── */
  /* Der Verlauf war fest verdrahtet dunkel (#0e1119 -> #0a0c11). Im hellen
     Modus drehte der Text mit den Tokens auf dunkel, der Grund aber nicht:
     gemessener Kontrast 1.0-3.0, die Chips praktisch unsichtbar. Jetzt ueber
     Tokens — im Dunkelmodus praktisch derselbe Ton wie vorher. */
  .b-produkt { border: 1px solid var(--line); border-radius: 18px; overflow: hidden;
               background: linear-gradient(180deg, var(--paper-2), var(--paper-sunk)); }
  .b-produkt .oben { display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(1.5rem, 4vw, 3.5rem);
                     padding: clamp(1.8rem, 4vw, 3.2rem); align-items: center; }
  .b-produkt .schuss { position: relative; }
  .b-produkt .schuss::after {
    content: ""; position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
    width: 130%; aspect-ratio: 1; border-radius: 50%; z-index: 0;
    background: radial-gradient(circle, rgba(110,134,255,.18), transparent 62%); filter: blur(50px);
  }
  .b-produkt .schuss img {
    /* height:auto ist Pflicht — das Bild traegt height="1787" im Attribut, und
       ohne die Regel bleibt es 1787 px hoch, waehrend die Breite auf 310 faellt.
       Die Karte wurde dadurch fast 1900 px hoch und das Bild lag ausserhalb. */
    position: relative; z-index: 1; display: block;
    width: 100%; height: auto; margin-inline: auto;
  }
  .b-chips { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: 1.5rem; }
  .b-chip { font-size: .78rem; color: var(--ink-2); border: 1px solid var(--line-2);
            border-radius: 999px; padding: .3rem .75rem;
            background: color-mix(in srgb, var(--ink) 3%, transparent); }

  /* ── Bildstreifen ──────────────────────────────────────────────────────── */
  .b-bilder { display: grid; grid-template-columns: 1.3fr 1fr 1fr; gap: 1px; background: var(--line);
              border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
  .b-bild { position: relative; overflow: hidden; margin: 0; background: var(--paper-2); }
  .b-bild img { width: 100%; height: clamp(220px, 34svh, 380px); object-fit: cover;
                filter: saturate(.85) contrast(1.05); transition: transform .8s var(--ease), filter .5s; }
  .b-bild:hover img { transform: scale(1.05); filter: saturate(1) contrast(1.05); }
  .b-bild figcaption { position: absolute; left: 14px; bottom: 14px; font-size: .72rem;
    letter-spacing: .11em; text-transform: uppercase; color: #fff;
    background: rgba(8,9,12,.62); backdrop-filter: blur(8px);
    border: 1px solid rgba(255,255,255,.14); border-radius: 999px; padding: .3rem .8rem; }
  @media (max-width: 760px) { .b-bilder { grid-template-columns: 1fr 1fr } .b-bild:last-child { display: none } }
  @media (max-width: 860px) { .b-produkt .oben { grid-template-columns: 1fr } }

  /* ── Abschluss ─────────────────────────────────────────────────────────── */
  .b-ende { text-align: center; padding: clamp(4rem, 9vw, 7rem) 0; position: relative; overflow: hidden; }
  .b-ende .b-glow::before { left: 50%; transform: translateX(-50%); top: 10%; width: 60vw; height: 40vw; }
  /* Video als Hintergrund des Abschlusses. Hochkant gedreht, deshalb zeigt object-fit
     nur einen Streifen. Bis 17.09. war das "center 42%" — die leere Wand mit dem
     Schriftzug, gearbeitet hat darin niemand. Jetzt liegt der Ausschnitt auf dem
     unteren rechten Drittel, wo der Schreibtisch und die Person am Laptop stehen.
     Der Schleier ist in Papierfarbe: dunkel dimmt er, hell waescht er aus; die
     Schrift bleibt in beiden Faellen lesbar. */
  .b-ende.mit-video .b-ende-video { position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; object-position: 70% 84%; z-index: 0; filter: saturate(.62); }
  .b-ende.mit-video .b-ende-schleier { position: absolute; inset: 0; z-index: 0;
    background:
      linear-gradient(180deg, var(--paper) 0%, transparent 28%, transparent 72%, var(--paper) 100%),
      color-mix(in srgb, var(--paper) 62%, transparent); }
  .b-ende.mit-video .b-glow { display: none; }
  /* Seit 18.09. mit den echten Markenzeichen — vorher drei Textlinks, das
     TikTok-Logo lag ungenutzt als Hover-Bild im Footer. Pillen statt Unterstrich,
     weil ein Unterstrich unter Icon und Wort schief liegt. */
  .b-ende-social { display: flex; justify-content: center; flex-wrap: wrap; gap: .7rem; margin-top: 2.6rem; }
  .b-ende-social a { display: inline-flex; align-items: center; gap: .55rem;
    font-size: var(--fs-sm); font-weight: 540; color: var(--ink-2); letter-spacing: .01em;
    padding: .55rem 1.1rem; border: 1px solid var(--line); border-radius: 999px;
    background: color-mix(in srgb, var(--paper-2) 82%, transparent);
    backdrop-filter: blur(6px);
    transition: color .25s var(--ease), border-color .25s var(--ease), background .25s var(--ease), transform .25s var(--ease); }
  .b-ende-social a:hover { color: var(--ink); transform: translateY(-2px);
    border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
    background: color-mix(in srgb, var(--accent) 8%, var(--paper-2)); }
  .b-ende-social svg { flex: 0 0 auto; }
  .b-ende.mit-video > .container { z-index: 1; }
  .b-ende.mit-video .b-h2, .b-ende.mit-video .b-sub { text-shadow: 0 1px 18px color-mix(in srgb, var(--paper) 80%, transparent); }
  @media (prefers-reduced-motion: reduce) { .b-ende.mit-video .b-ende-video { filter: saturate(.55) blur(2px); } }

/* Seitenkoepfe der Unterseiten bekommen denselben Glow wie der Hero. */
.page-head { position: relative; overflow: hidden; }
.page-head .b-glow { z-index: 0; }
.page-head .container { position: relative; z-index: 1; }
.page-head .eyebrow {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: max(.74rem, 12px); letter-spacing: .12em; color: var(--accent);
}

/* Zeiger-Glow auch auf den Bestandskarten der Unterseiten — main.js setzt
   --mx/--my dort schon laenger, es fehlte nur die sichtbare Reaktion. */
.value, .step, .member, .factcard { position: relative; overflow: hidden; }
.value::before, .step::before, .member::before, .factcard::before {
  content: ""; position: absolute; inset: 0; opacity: 0; pointer-events: none;
  transition: opacity .35s var(--ease);
  background: radial-gradient(320px circle at var(--mx, 50%) var(--my, 50%),
              rgba(110,134,255,.10), transparent 65%);
}
.value:hover::before, .step:hover::before, .member:hover::before, .factcard:hover::before { opacity: 1; }
.value > *, .step > *, .member > *, .factcard > * { position: relative; }

/* Kompakter Scroll-Expansion-Block fuer Unterseiten. */
.sx-kurz { height: 200vh; }

/* ══ Startseiten-Sprache fuer ALLE Seiten ════════════════════════════════════
   Abschnittskoepfe sitewide wie auf der Startseite: Monospace-Label in
   Akzentfarbe, groessere und enger gesetzte Ueberschriften. */
.section-head .label, .split .label {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: max(.74rem, 12px); letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent);
}
.section-head .h2, .split .h2 {
  font-size: clamp(1.8rem, 3.4vw, 2.9rem);
  letter-spacing: -.03em; line-height: 1.08; font-weight: 660;
}

/* Footer-Socials: linksbuendig und kompakt, das Hover-Bild bleibt. */
.footer [data-hoverbild] { justify-content: flex-start; margin-top: .3rem; }
.footer [data-hoverbild] [data-bild] { padding: .3rem 1.1rem .3rem 0; font-size: var(--fs-sm); }
.footer .hb-bild { width: 44px; height: 44px; border-radius: 10px; }

/* Kipp-Effekt: weiche Rueckkehr, Bewegung selbst folgt dem Zeiger direkt. */
.tilt { transition: transform .35s var(--ease); will-change: transform; }

/* ══════════════════════════════════════════════════════════════════════════
   ELEMENTE IM STIL DER VORBILDER (Linear · Vercel · v0)
   Alles in derselben Technik wie der Rest: CSS + Vanilla-JS, kein Build.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Filmkorn über der ganzen Seite ────────────────────────────────────────
   Linear legt ein sehr feines Rauschen über den dunklen Grund. Es nimmt
   Farbverläufen das Bandingen und lässt Flächen weniger digital wirken.
   Als data-URI, damit keine Datei geladen werden muss. */
body::after {
  content: "";
  position: fixed; inset: 0; z-index: 999; pointer-events: none;
  opacity: .035; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}
:root[data-theme="light"] body::after { opacity: .02; }

/* ── Raster-Linien im Hintergrund ─────────────────────────────────────────
   Vercels Markenzeichen: ein feines Gitter, das nach außen ausblendet.
   Liegt hinter dem Inhalt, nie darüber. */
.raster { position: relative; }
.raster::before {
  content: "";
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 64px 64px;
  opacity: .5;
  -webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 40%, #000 30%, transparent 78%);
  mask-image: radial-gradient(ellipse 80% 60% at 50% 40%, #000 30%, transparent 78%);
}
.raster > * { position: relative; z-index: 1; }

/* ── Bento-Raster ─────────────────────────────────────────────────────────
   Ungleich große Kacheln statt vier identischer Karten. Die erste Kachel
   nimmt zwei Spalten und zwei Reihen — dadurch entsteht die Hierarchie, die
   ein gleichförmiges Raster nicht hat. */
.bento {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: minmax(180px, auto);
  gap: 14px;
}
.bento .b-card {
  border: 1px solid var(--line); border-radius: 16px;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: 190px;
}
/* space-between hat den Inhalt der grossen Kachel ueber die ganze Hoehe
   auseinandergezogen — Titel oben, Text unten, dazwischen ein Loch. Alles
   unten sammeln haelt sie ruhig; die Zahl bleibt oben in der Ecke. */
.bento .gross { grid-column: span 2; grid-row: span 2; justify-content: flex-end; }
.bento .gross .n { position: absolute; top: clamp(1.4rem, 2.6vw, 2rem); left: clamp(1.4rem, 2.6vw, 2rem); }
.bento .gross h3 { margin-bottom: .7rem; }
.bento .breit { grid-column: span 2; }
.bento .gross h3 { font-size: clamp(1.3rem, 2.2vw, 1.75rem); letter-spacing: -.025em; }
.bento .gross p { font-size: 1rem; }
@media (max-width: 900px) {
  .bento { grid-template-columns: repeat(2, 1fr); }
  .bento .gross { grid-column: span 2; grid-row: span 1; }
}
@media (max-width: 560px) {
  .bento { grid-template-columns: 1fr; }
  .bento .gross, .bento .breit { grid-column: span 1; }
}

/* Leuchtender Rand beim Überfahren — bei Linear an jeder Karte. Zwei Ebenen:
   der Verlauf liegt als Maske nur auf dem Rand, nicht auf der Fläche. */
.bento .b-card::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  padding: 1px; pointer-events: none; opacity: 0;
  transition: opacity .4s var(--ease);
  background: linear-gradient(135deg, var(--accent), transparent 40%, transparent 60%, var(--accent-2, #a78bfa));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
}
.bento .b-card:hover::after { opacity: .55; }

/* ── Laufband ─────────────────────────────────────────────────────────────
   Endlose Zeile aus Schlagworten. Die Liste steht zweimal im Markup und
   läuft um genau ihre halbe Breite — dadurch ist der Übergang nahtlos. */
.band {
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: 1.1rem 0; overflow: hidden; position: relative;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.band-spur { display: flex; width: max-content; animation: band-lauf 38s linear infinite; }
.band:hover .band-spur { animation-play-state: paused; }
@keyframes band-lauf { to { transform: translateX(-50%); } }
.band-spur span {
  display: inline-flex; align-items: center; gap: .9rem;
  padding: 0 1.6rem; white-space: nowrap;
  font-size: .92rem; color: var(--muted); letter-spacing: .01em;
}
.band-spur span::after {
  content: ""; width: 4px; height: 4px; border-radius: 50%;
  background: var(--accent); opacity: .55;
}

/* ── Sticky-Scroll: Text bleibt, Bilder wechseln ──────────────────────────
   Der Kern-Effekt bei Linear und Vercel. Links steht die Erklärung fest,
   rechts tauscht das Bild beim Weiterscrollen. Umgesetzt mit position:sticky
   plus Opazität je Schritt — kein Scroll-Hijacking. */
.klebe { display: grid; grid-template-columns: 1fr 1.1fr; gap: clamp(2rem, 5vw, 4rem); }
.klebe-text { }
.klebe-schritt {
  /* Jeder Schritt braucht eigene Hoehe, sonst liegen alle drei gleichzeitig
     nahe der Fenstermitte und der Wechsel loest nie aus. 68svh heisst: waehrend
     man einen Schritt liest, ist genau er der naechste zur Mitte. */
  min-height: 68svh;
  display: flex; flex-direction: column; justify-content: center;
  padding: 1.5rem 0;
  opacity: .3; transition: opacity .45s var(--ease);
}
.klebe-text > .klebe-schritt:first-child { padding-top: 0; }
.klebe-schritt.an { opacity: 1; }
.klebe-schritt h3 {
  font-size: clamp(1.35rem, 2.4vw, 1.9rem); letter-spacing: -.025em;
  margin-bottom: .7rem; display: flex; align-items: baseline; gap: .8rem;
}
.klebe-schritt h3 i {
  font-style: normal; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .72rem; color: var(--accent); letter-spacing: .1em;
}
.klebe-schritt p { color: var(--muted); line-height: 1.65; }
.klebe-buehne { position: sticky; top: 96px; height: min(70svh, 560px); }
.klebe-bild {
  position: absolute; inset: 0; border-radius: 16px; overflow: hidden;
  border: 1px solid var(--line); background: var(--paper-2);
  opacity: 0; transform: scale(1.02); transition: opacity .55s var(--ease), transform .55s var(--ease);
}
.klebe-bild.an { opacity: 1; transform: none; }
.klebe-bild img { width: 100%; height: 100%; object-fit: cover; }
/* Telefon-Screenshot in der Buehne: ganz zeigen statt anschneiden. */
.klebe-bild.geraet img { object-fit: contain; padding: clamp(1rem, 3vw, 2rem); }
@media (max-width: 860px) {
  .klebe { grid-template-columns: 1fr; }
  .klebe-buehne { position: relative; top: 0; height: 46svh; order: -1; margin-bottom: 1.5rem; }
  .klebe-schritt { opacity: 1; padding: 1.5rem 0; min-height: 0; display: block; }
}

/* ── Wortweises Aufdecken ────────────────────────────────────────────────
   Die Überschrift erscheint Wort für Wort, wenn sie ins Bild kommt. */
.worte span {
  display: inline-block;
  opacity: 0; transform: translateY(14px);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
  transition-delay: calc(var(--i, 0) * 55ms);
}
.worte.in span { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .band-spur { animation: none; }
  .worte span { opacity: 1; transform: none; }
  .klebe-schritt { opacity: 1; }
}

/* ── Bento-Kachel mit Bild ────────────────────────────────────────────────
   Die Ort-Kachel wirkte leer, als fehle ein Bild. Jetzt traegt sie eins: das
   Foto liegt hinter dem Text, ein Verlauf haelt die Schrift lesbar. Das Bild
   ist dekorativ (alt="" + aria-hidden), der Text steht im Markup. */
.b-card.mit-bild { position: relative; overflow: hidden; min-height: 300px; }
.b-card.mit-bild picture { position: absolute; inset: 0; z-index: 0; }
.b-card.mit-bild img {
  width: 100%; height: 100%; object-fit: cover;
  /* Der Turm steht rechts im Bild, links dominiert der Baum — der Ausschnitt
     wandert deshalb nach rechts. */
  object-position: 72% 45%;
  transition: transform .8s var(--ease);
}
.b-card.mit-bild:hover img { transform: scale(1.04); }
.b-card.mit-bild::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  /* Kraeftiger als zuvor: der Himmel im Bild ist hell, darauf war die weisse
     Schrift kaum zu lesen. Unten fast deckend, damit der Absatz sitzt. */
  background: linear-gradient(180deg,
    rgba(8,9,12,.20) 0%, rgba(8,9,12,.55) 40%, rgba(8,9,12,.90) 72%, rgba(8,9,12,.97) 100%);
}
.b-card.mit-bild > .n,
.b-card.mit-bild > h3,
.b-card.mit-bild > p { position: relative; z-index: 2; }
.b-card.mit-bild > .n { color: rgba(255,255,255,.65); }
/* Ein knapper Schattenrand haelt die Schrift auch ueber hellen Bildstellen lesbar. */
.b-card.mit-bild > h3,
.b-card.mit-bild > p { text-shadow: 0 1px 12px rgba(0,0,0,.75); }
.b-card.mit-bild > h3 { color: #fff; }
.b-card.mit-bild > p { color: rgba(255,255,255,.82); }
/* Der Glow-Rand der uebrigen Kacheln wuerde hier mit dem Bild kollidieren. */
.b-card.mit-bild::after { display: none; }

/* Anker unter der festen Nav: ohne das verdeckt die Leiste die Ueberschrift,
   wenn man ueber #schreibfit hierher springt. */
[id] { scroll-margin-top: 96px; }

/* Video im Sticky-Scroll: fuellt die Buehne wie ein Bild. */
.klebe-video { width: 100%; height: 100%; object-fit: cover; display: block; }


/* Hochformat im Fliesstext deckeln. .shot img hebt max-height global auf
   (fuer die breiten Aufnahmen), .tall holt die Begrenzung gezielt zurueck. */
.shot.tall img { max-height: 30rem; object-fit: cover; object-position: center 42%; }
/* Helle Innenaufnahmen springen neben den dunklen Flaechen heraus. */
.shot.gedaempft img { filter: brightness(.86) contrast(1.02); }

/* ── Team: aufklappbare Steckbriefe ───────────────────────────────────────
   Kopf ist ein <button> (Tastatur, Screenreader), der Steckbrief haengt an
   aria-controls und wird ueber [hidden] geschaltet. */

/* ══ App-Screenshots in den drei Schritt-Karten (produkte.html) ══════════════ */
/* Karten als Flex-Spalte, Bild mit margin-top:auto — so stehen die drei Telefone
   auf einer Linie, auch wenn der Text darueber unterschiedlich lang ist. */
.b-grid .b-card { display: flex; flex-direction: column; }
.b-card .schritt-shot { display: block; width: min(100%, 190px); margin: auto auto 0; padding-top: 1.4rem; }
.b-card .schritt-shot img { width: 100%; height: auto; }

/* Video im Scroll-Hero (Ueber uns): nutzt .sx-medium wie das Turmfoto der Startseite.
   Ohne Motion-Wunsch kein Autoplay — das Poster steht (main.js). */

/* ══ Kapitelauftakt "Der Ort" (Ueber uns): Parallax-Collage ═══════════════════
   Drei Hochkant-Fotos, jede Spalte mit eigener Tiefe (--tiefe, px). main.js setzt
   --p von -1 (Element oben aus dem Fenster) bis 1 (unten); die Verschiebung ist
   --p * --tiefe. Die mittlere Spalte laeuft gegenlaeufig — das gibt die Raeumlichkeit.
   Reduced motion: keine Verschiebung. */
/* Die Collage .ort-* ist am 18.09. dem Raster .turm-gal gewichen — kein
   Markup nutzt sie mehr; die alten Regeln stehen in der Git-Historie. */

/* ══ Gruender-Karten (Ueber uns) ═══════════════════════════════════════════════
   Nach Joes Vorbild (TeamSection): zentrierte Karte mit leichtem Farbton, grosses
   RUNDES Portraet (nicht 144 px — hier ~min(70 %, 300 px)), das beim Hover einen
   Akzentrand bekommt und leicht waechst; von unten steigt ein weicher Verlauf
   ("Welle") auf; die Links blenden auf dem Desktop erst beim Hover ein, auf
   Touch-Geraeten stehen sie immer. Portraet-Platzhalter = Initialen im Serif. */
.gruender { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(1.2rem, 2.5vw, 2rem); }
.gruender-karte { --tint: color-mix(in srgb, var(--accent) 7%, var(--paper-2));
  position: relative; overflow: hidden; text-align: center;
  padding: clamp(2rem, 3.5vw, 3rem) clamp(1.4rem, 2.5vw, 2.2rem) clamp(1.8rem, 3vw, 2.4rem);
  border: 1px solid var(--line); border-radius: 22px; background: var(--tint);
  display: flex; flex-direction: column; align-items: center;
  transition: transform .5s var(--ease), box-shadow .5s var(--ease), border-color .5s var(--ease); }
.gruender-karte:nth-child(2) { --tint: color-mix(in srgb, var(--warn) 6%, var(--paper-2)); }
.gruender-karte:hover { transform: translateY(-6px) scale(1.01); box-shadow: 0 34px 70px -40px rgba(0,0,0,.65);
  border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); }
/* Welle: steigt beim Hover von unten auf */
.gruender-karte::before { content: ""; position: absolute; left: -10%; right: -10%; bottom: 0; height: 55%;
  border-radius: 50% 50% 0 0 / 100% 100% 0 0; transform: scaleY(0); transform-origin: bottom;
  background: linear-gradient(to top, color-mix(in srgb, var(--accent) 16%, transparent), transparent);
  transition: transform .6s var(--ease); pointer-events: none; }
.gruender-karte:hover::before { transform: scaleY(1); }
.gruender-karte > * { position: relative; }
.gruender-bild { width: min(70%, 300px); aspect-ratio: 1; border-radius: 50%; overflow: hidden; display: grid; place-items: center;
  border: 4px solid transparent; background: linear-gradient(160deg, color-mix(in srgb, var(--accent) 10%, var(--paper-sunk)), var(--paper-2));
  box-shadow: 0 10px 28px -20px rgba(0,0,0,.35);
  transition: border-color .5s var(--ease), transform .5s var(--ease); }
.gruender-karte:hover .gruender-bild { border-color: var(--accent); transform: scale(1.04); }
.gruender-bild picture, .gruender-bild img { width: 100%; height: 100%; }
.gruender-bild img { object-fit: cover; object-position: center 35%; display: block; transition: transform .7s var(--ease); }
.gruender-karte:hover .gruender-bild img { transform: scale(1.08); }
.gruender-bild .ini { font-family: var(--serif); font-style: italic; font-size: clamp(3.4rem, 6vw, 5.5rem); line-height: 1;
  color: var(--ink); opacity: .85; letter-spacing: -.04em; }
.gruender-text { margin-top: 1.5rem; }
.gruender-text h3 { font-size: clamp(1.25rem, 1.8vw, 1.5rem); letter-spacing: -.02em; margin: 0 0 .25rem; }
.gruender-text .rolle { color: var(--muted); font-size: var(--fs-sm); margin: 0 0 .7rem; }
.gruender-text .bio { color: var(--muted); font-size: var(--fs-sm); line-height: 1.6; margin: 0 0 1rem; }
.gruender-links { margin: 0; opacity: 0; transform: translateY(4px); transition: opacity .35s var(--ease), transform .35s var(--ease); }
.gruender-karte:hover .gruender-links, .gruender-karte:focus-within .gruender-links { opacity: 1; transform: none; }
@media (hover: none), (max-width: 720px) { .gruender-links { opacity: 1; transform: none; } }
.gruender-links a { display: inline-flex; align-items: center; gap: .5rem; font-size: var(--fs-sm); font-weight: 540;
  color: var(--ink-2); padding: .45rem .9rem; border-radius: 999px; border: 1px solid var(--line-2);
  transition: color .25s, border-color .25s, background .25s; }
.gruender-links a:hover { color: var(--ink); border-color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.gruender-links svg { flex: 0 0 auto; }
/* Bis 17.09. auf 26 rem beschnitten — von einem Hochformat blieb ein Streifen.
   Joe: "dass man das Bild wirklich sieht". Jetzt vollstaendig, dafuer schmaler. */
.gruender-band img { max-height: none; width: 100%; height: auto; object-fit: contain; }
@media (max-width: 720px) { .gruender { grid-template-columns: 1fr; } }


/* ══════════════════════════════════════════════════════════════════════════════
   NACHTRAEGE 17.09.2026 — Durchsicht Joe
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── Geraeterahmen fuer die App-Screenshots ───────────────────────────────────
   Die Renderings bringen runde Ecken mit (Radius ~7 % der Breite), aber keinen
   Geraeterand — sie wirkten dadurch wie ein beschnittenes Bild, nicht wie ein
   Telefon. Der Rahmen kommt aus CSS: dunkle Kante, iPhone-Radius (~12,5 % der
   Breite), Glanzlinie innen. Zwei Groessen, weil der Radius mit der Breite
   skalieren muss — 46 px an einem 190-px-Bild waeren eine Kapsel. */
.geraet-rahmen {
  display: block; position: relative;
  width: 100%; max-width: 300px; margin-inline: auto;
  padding: 8px;
  border-radius: 46px;
  background: linear-gradient(150deg, #474d5e 0%, #15181f 34%, #0b0d11 64%, #2f3541 100%);
  box-shadow: 0 30px 44px -20px rgba(0, 0, 0, 0.62), inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}
.geraet-rahmen > picture { display: block; }
.geraet-rahmen img {
  display: block; width: 100%; height: auto;
  border-radius: 38px;
  background: var(--paper-2);
}
/* Kleine Fassung: die drei Schritt-Karten auf der Produktseite. */
.b-card .schritt-shot.geraet-rahmen { max-width: 190px; padding: 5px; border-radius: 30px; }
.b-card .schritt-shot.geraet-rahmen img { border-radius: 25px; }
@media (max-width: 480px) {
  .geraet-rahmen { max-width: 260px; padding: 7px; border-radius: 40px; }
  .geraet-rahmen img { border-radius: 33px; }
}

/* ── Die Gruender im Einstieg der Startseite ──────────────────────────────────
   Joe 17.09.: "Gruender muessen neben dem Turm mehr im Mittelpunkt stehen und
   frueh vorkommen." Deshalb eine Zeile direkt unter den Einstiegsknoepfen, die
   zum Team fuehrt — zwei Portraets, beide Namen, ein Satz. */
.b-gruender {
  display: inline-flex; align-items: center; gap: clamp(1rem, 2vw, 1.5rem); margin-top: 2.6rem;
  padding: 0.7rem clamp(1.4rem, 2.6vw, 2rem) 0.7rem 0.7rem;
  border: 1px solid var(--line); border-radius: 999px; background: var(--paper-2);
  text-decoration: none; color: inherit; max-width: 100%;
  transition: border-color 0.3s var(--ease), transform 0.3s var(--ease), background 0.3s var(--ease);
}
.b-gruender:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: color-mix(in srgb, var(--accent) 6%, var(--paper-2));
  transform: translateY(-2px);
}
.b-gruender-bilder { display: flex; flex: 0 0 auto; }
/* Groesse seit 18.09. (Joe: "beim Start uns groesser") — vorher 56 px, da
   verschwanden zwei Gesichter neben dem Turmfoto. */
.b-gruender-bild {
  width: clamp(64px, 6.4vw, 92px); height: clamp(64px, 6.4vw, 92px);
  border-radius: 50%; overflow: hidden; display: grid; place-items: center;
  border: 2px solid var(--paper); background: var(--paper-sunk); flex: 0 0 auto;
  box-shadow: 0 10px 26px -14px rgba(0,0,0,.6);
}
.b-gruender-bild + .b-gruender-bild { margin-left: clamp(-20px, -1.6vw, -14px); }
.b-gruender-bild picture, .b-gruender-bild img { width: 100%; height: 100%; }
.b-gruender-bild img { object-fit: cover; object-position: center 42%; display: block; }
/* Portraet-Platzhalter: sichtbar als solcher (gestrichelt), ohne die Zeile zu
   zerstoeren. Austausch = <span class="ini"> gegen <picture> tauschen. */
.b-gruender-bild.leer { border-style: dashed; border-color: var(--line-2); background: var(--paper-sunk); }
.b-gruender-bild.leer i {
  font-family: var(--serif); font-style: italic; font-size: 1.15rem; color: var(--ink-2); letter-spacing: -0.02em;
}
.b-gruender-text { display: block; min-width: 0; }
.b-gruender-text b { display: block; font-weight: 600; font-size: clamp(1rem, 1.5vw, 1.2rem); letter-spacing: -0.015em; }
.b-gruender-text span { display: block; font-size: var(--fs-sm); color: var(--muted); margin-top: 0.25rem; }
.b-gruender .arr { color: var(--muted); flex: 0 0 auto; transition: transform 0.3s var(--ease); }
.b-gruender:hover .arr { transform: translateX(3px); }
@media (max-width: 560px) {
  .b-gruender { border-radius: 20px; align-items: flex-start; padding: 0.8rem 1rem; }
  .b-gruender .arr { display: none; }
}

/* Auch die grosse Gruender-Karte zeigt, dass das Portraet noch fehlt. */
.gruender-bild[data-foto-fehlt] { border: 2px dashed var(--line-2); }

/* ── Ueber uns: Text und die zwei Aufnahmen von uns ──────────────────────────
   Beides seit 18.09. Der Fliesstext stand vorher ueber den Portraets; jetzt
   kommen die Gesichter zuerst und der Text darunter. */
.ueber-text { max-width: 64ch; margin-top: clamp(2rem, 4vw, 3rem); }
.ueber-text .body + .body { margin-top: 1.1rem; }
.ueber-text .link .arr, .weiter-zum-produkt .arr, .factcard .link .arr {
  display: inline-block; transition: transform .3s var(--ease); }
.ueber-text .link:hover .arr, .weiter-zum-produkt .link:hover .arr,
.factcard .link:hover .arr { transform: translate(3px, -1px); }

/* Der Abschluss der drei Produktschritte: von hier geht es zum Produkt selbst.
   Vorher endete der Abschnitt ohne Weg dorthin, obwohl genau hier die Frage
   aufkommt, wo man Schreibfit bekommt (Joe 19.09.). Bewusst ein Satz mit Link
   statt eines weiteren Knopfes — davon stehen schon drei auf der Seite. */
.weiter-zum-produkt {
  margin: clamp(2rem, 4vw, 3rem) auto 0; max-width: 62ch; text-align: center;
  color: var(--muted); line-height: 1.65;
}

.wir-band {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(.7rem, 1.6vw, 1.2rem); margin-top: clamp(2rem, 4vw, 3rem);
}
.wir-band figure { margin: 0; border-radius: clamp(12px, 1.4vw, 18px); overflow: hidden;
  background: var(--paper-sunk); aspect-ratio: 4 / 5; }
.wir-band picture, .wir-band img { display: block; width: 100%; height: 100%; }
.wir-band img { object-fit: cover; transition: transform .8s var(--ease); }
.wir-band figure:hover img { transform: scale(1.04); }
@media (max-width: 620px) { .wir-band figure { aspect-ratio: 1; } }

/* ── Die Turm-Galerie ────────────────────────────────────────────────────────
   Vorher eine gedrehte Collage mit ueberlappenden Bildern auf einer prozentualen
   Buehne — huebsch, aber unruhig, und man sah nicht, dass sie anklickbar ist.
   Jetzt ein Raster, das exakt aufgeht: das Aussenbild ueber 2x2 Zellen, die fuenf
   Innenaufnahmen daneben. Drei Spalten x drei Reihen, keine Luecke.
   Am Handy zwei Spalten; dort liegt das grosse Bild quer oben und das letzte Bild
   quer unten, damit auch dort keine halbe Zeile stehen bleibt.
   RECHENREGEL, wenn Bilder dazukommen: das grosse belegt 4 Zellen, jedes weitere
   eine — bei n Bildern also n+3 Zellen. Das Raster geht nur auf, wenn n durch 3
   teilbar ist (6, 9, 12 …). Am Handy muss die Zahl der kleinen Bilder ungerade
   sein, damit die :last-child-Regel die Zeile fuellt. Stand 20.09.: 12 Bilder. */
.turm-gal {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(.5rem, 1.1vw, .9rem); margin-top: clamp(2rem, 4vw, 3rem);
}
.turm-gal figure {
  margin: 0; position: relative; overflow: hidden; cursor: zoom-in;
  border-radius: clamp(10px, 1.2vw, 16px); background: var(--paper-sunk);
  aspect-ratio: 1; transition: transform .45s var(--ease), box-shadow .45s var(--ease);
}
.turm-gal figure.gross { grid-column: span 2; grid-row: span 2; }
/* Das letzte Bild liegt quer ueber zwei Spalten — damit geht die Rechnung bei
   einer UNGERADEN Zahl kleiner Bilder auf (siehe Rechenregel oben). */
.turm-gal figure:last-child { grid-column: span 2; aspect-ratio: 2 / 1; }
.turm-gal picture, .turm-gal img { display: block; width: 100%; height: 100%; }
.turm-gal img { object-fit: cover; transition: transform .9s var(--ease); }
.turm-gal figure:hover { transform: translateY(-3px); box-shadow: 0 24px 50px -30px rgba(0,0,0,.7); }
.turm-gal figure:hover img { transform: scale(1.05); }
.turm-gal figure:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* Das Lupen-Zeichen sagt, dass die Kachel etwas tut. */
.turm-gal figure::after {
  content: ""; position: absolute; right: .6rem; bottom: .6rem; width: 30px; height: 30px;
  border-radius: 50%; background: rgba(12,14,19,.62) no-repeat center /14px 14px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-4.3-4.3M11 8v6M8 11h6'/%3E%3C/svg%3E");
  opacity: 0; transform: translateY(4px); transition: opacity .3s var(--ease), transform .3s var(--ease);
  backdrop-filter: blur(4px);
}
.turm-gal figure:hover::after, .turm-gal figure:focus-visible::after { opacity: 1; transform: none; }
@media (hover: none) { .turm-gal figure::after { opacity: 1; transform: none; } }
@media (max-width: 720px) {
  .turm-gal { grid-template-columns: repeat(2, 1fr); }
  .turm-gal figure.gross { grid-column: span 2; grid-row: span 1; aspect-ratio: 4 / 3; }
  /* Am Handy sind es zwei Spalten und die kleinen Bilder gehen gerade auf —
     die Desktop-Ausnahme fuer das letzte Bild muss hier zurueck. */
  .turm-gal figure:last-child { grid-column: auto; aspect-ratio: 1; }
}
.turm-sec { padding-bottom: clamp(3rem, 6vw, 5rem); }

/* ── Galerie: Collage anklickbar, Bild gross ──────────────────────────────────
   Joe 17.09.: den Turm "gut angucken" koennen. Die Collage bleibt die Geste,
   der Klick liefert das ganze Bild. Markup: [data-galerie] am Container,
   main.js macht daraus Knoepfe und baut die Lightbox. */
.ort-text .label { display: block; margin-bottom: 0.9rem; }

.lb[hidden] { display: none; }
.lb {
  position: fixed; inset: 0; z-index: 120; display: grid; place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: color-mix(in srgb, #05070b 97%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  animation: lb-auf 0.25s var(--ease);
}
@keyframes lb-auf { from { opacity: 0; } to { opacity: 1; } }
.lb-bild { max-width: min(96vw, 1180px); max-height: 84svh; width: auto; height: auto;
  border-radius: 12px; box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.8); display: block; }
.lb > div { display: flex; flex-direction: column; align-items: center; }
.lb-zahl { margin: .5rem auto 0; text-align: center; font-family: var(--mono, inherit);
  font-size: .78rem; letter-spacing: .1em; color: #8b93a3; }
.lb-zahl[hidden] { display: none; }
.lb-schliessen, .lb-vor, .lb-zurueck {
  position: absolute; display: grid; place-items: center; width: 44px; height: 44px;
  border-radius: 50%; border: 1px solid rgba(255, 255, 255, 0.22); background: rgba(12, 14, 19, 0.7);
  color: #fff; cursor: pointer; transition: background 0.25s, border-color 0.25s;
}
.lb-schliessen:hover, .lb-vor:hover, .lb-zurueck:hover { background: rgba(30, 34, 44, 0.92); border-color: rgba(255, 255, 255, 0.5); }
.lb-schliessen { top: clamp(0.8rem, 3vw, 1.6rem); right: clamp(0.8rem, 3vw, 1.6rem); }
.lb-zurueck { left: clamp(0.5rem, 3vw, 2rem); top: 50%; transform: translateY(-50%); }
.lb-vor { right: clamp(0.5rem, 3vw, 2rem); top: 50%; transform: translateY(-50%); }
@media (max-width: 560px) { .lb-zurueck { left: 0.6rem; } .lb-vor { right: 0.6rem; } }
@media (prefers-reduced-motion: reduce) { .lb { animation: none; } }
body.lb-offen { overflow: hidden; }

/* Seit die vierte Kennzahl ("1912 Baujahr Turm") raus ist, sind es drei — im
   zweispaltigen Raster des Handys blieb dadurch unten rechts eine leere Zelle
   stehen (der Rasterhintergrund schien durch). Deshalb dort feste zwei Spalten
   und die letzte Kennzahl ueber die volle Breite. */
@media (max-width: 560px) {
  .b-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .b-stats .b-stat:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* ══ Feinschliff Handy (21.09.2026) ══════════════════════════════════════════
   Aus dem Mobil-Durchgang ueber 13 Seiten x 2 Farbschemata (390 px).
   Kontrast war ueberall in Ordnung — null Verstoesse, auch nach dem
   Menue-Fix. Was blieb: Tippflaechen, der iOS-Zoom und die Umbrueche.
   Alle Regeln aendern nur Flaechen und Umbruchstellen, keine Farben,
   keine Schriftgroessen im Fliesstext. */

/* 1. iOS zoomt die Seite hinein, sobald ein Formularfeld unter 16 px liegt —
      danach steht die Seite verschoben da. Nur am Handy anheben; am Desktop
      bleibt die feinere Groesse. */
/* An der EINGABEART festmachen, nicht an der Fensterbreite: Ein iPhone im
   Querformat ist 844 px breit, ein iPad 768 px — eine `max-width: 700px`-Regel
   greift dort nicht, der Auto-Zoom aber schon. `pointer: coarse` trifft jedes
   Touchgeraet, unabhaengig von der Breite; mit Maus bleiben die 15 px. */
@media (max-width: 700px), (pointer: coarse) {
  .field input, .field select, .field textarea { font-size: 16px; }
}

/* 2. Tippflaechen auf 44 px. Die Schrift bleibt unveraendert, nur die
      Trefferflaeche waechst — sichtbar aendert sich nichts. */
.lang { display: inline-flex; align-items: center; min-height: 44px; }
.check { align-items: center; }
.check input { width: 22px; height: 22px; margin-top: 0; }
@media (max-width: 700px) {
  .footer li a,
  .footer-bottom a,
  .tl .tl-cta,
  .weiter-zum-produkt .link,
  .map-meta .link { display: inline-flex; align-items: center; min-height: 44px; }
  .footer ul { gap: 0; }
}

/* 3. Die Kapitaelchen-Labels lagen bei 11,84 px, knapp unter der 12-px-Grenze,
      ab der Kleinschrift auf dem Handy zuverlaessig lesbar bleibt. */
.eyebrow, .label, .b-label { font-size: max(var(--fs-xs), 12px); }

/* 4. Umbrueche. `balance` verteilt Ueberschriften gleichmaessig auf ihre
      Zeilen, statt ein Wort allein stehen zu lassen; `pretty` haelt denselben
      Fall aus dem Fliesstext heraus. Beides aendert nur, WO umbrochen wird —
      kein Buchstabe am Text. Browser ohne Unterstuetzung ignorieren es still. */
h1, h2, h3, h4, .display, .h2, .b-h2, .q, summary { text-wrap: balance; }
p, .body, .lede, .answer, .b-lede, figcaption { text-wrap: pretty; }
