/* ============================================================================
   COREFRAME · Landingpage
   Grammatik: filmic one-shot. Aesthetische Familie: modern, hell, grafisch.
   Tokens aus CoreFrame/BRAND.md. Die Engine wird nicht angefasst.
   ========================================================================== */

:root {
  /* Warme Welt, ganze Seite. Signal-Gruen faellt: es ist die eine Farbe, die
     sich mit "warm technology statt cyberpunk" nicht vertraegt. Der Akzent
     ist jetzt Terrakotta, das Ink ein warmes Espresso statt Blauschwarz. */
  --sc-canvas:     #F4EFE6;   /* Ivory   */
  --sc-surface:    #EAE1D2;   /* Sand    */
  --sc-ink:        #241D16;   /* Espresso */
  --sc-ink-soft:   #6E5F4C;   /* Warmes Taupe */
  --sc-accent:     #A8482A;   /* Terrakotta */
  --sc-accent-ink: #FFF8F0;

  /* Violett und Sky sind in BRAND.md Produkt- und Datenebene, keine UI-Farben.
     Sie leben hier ausschliesslich in der Bahn und in den Bauteilen. */
  --cf-violet: #6357F5;       /* nur noch in Altlasten, nicht mehr sichtbar */
  --cf-sky:    #78DFFF;
  --cf-deep:   #2B2119;       /* warmes Espresso statt Blauschwarz */
  --cf-paper:  #F4EFE6;

  /* Die warme 3D-Welt. Studio-Produktfotografie statt Neon-Tech. */
  --cf-ivory:     #F7F3EC;
  --cf-cream:     #EFE7DA;
  --cf-sand:      #E2D5C2;
  --cf-taupe:     #B9A894;
  --cf-champagne: #D8C09A;
  --cf-terra:     #C97B5A;

  --sc-font-display: "Helvetica Neue", "Neue Haas Grotesk Text Pro", Arial, sans-serif;
  --sc-font-text:    "Helvetica Neue", "Neue Haas Grotesk Text Pro", Arial, sans-serif;
  --sc-font-mono:    "SFMono-Regular", Consolas, "Liberation Mono", monospace;

  --sc-track-tight: -0.055em;
  --sc-track-snug:  -0.03em;

  --sc-r-sm: 6px; --sc-r-md: 12px; --sc-r-lg: 22px; --sc-r-pill: 999px;
  --sc-shadow-color: 220 8% 6%;

  /* Lusions Bewegungssprache, aus deren Stylesheets gelesen: EINE Kurve fuer
     praktisch jedes transform, 0,4 bis 0,6 Sekunden, kein Ueberschwingen.
     Was dort fluessig wirkt, kommt nicht aus verschiedenen Kurven, sondern
     aus derselben Kurve mit verschiedenen VERZOEGERUNGEN je Element. */
  --cf-ease: cubic-bezier(0.4, 0, 0.1, 1);
  --cf-dur: 480ms;

  --cf-bar-h: 76px;
  --cf-gut: clamp(16px, 3.4vw, 44px);
  --cf-line: color-mix(in oklab, var(--sc-ink) 15%, transparent);
}

/* Die Engine setzt scroll-behavior: smooth. Zusammen mit unserem eigenen
   Nachlauf faellt das native Smooth-Scrollen jeden Frame in sich zusammen,
   und Tastatur sowie Anker kommen nicht mehr ans Ziel. Wir glaetten selbst. */
html { scroll-behavior: auto; }
body { font-weight: 400; letter-spacing: var(--sc-track-snug); }

.cf-mono, .cf-over {
  font-family: var(--sc-font-mono); font-size: 10px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--sc-ink-soft); margin: 0;
}
.cf-over--dark { color: #B3A392; }

.cf-skip {
  position: fixed; z-index: 200; top: 8px; left: 8px;
  padding: 8px 14px; background: var(--sc-accent); color: var(--sc-accent-ink);
  font-weight: 700; transform: translateY(-180%);
}
.cf-skip:focus { transform: none; }

/* Fokusring: Signal-Gruen misst auf Papier 1,1:1 und waere dort unsichtbar.
   Zwei Stops einer Familie, gekeyt auf den Grund. */
:focus-visible { outline-color: var(--sc-ink); }
.cf-stage--hero :focus-visible, .cf-stage--work :focus-visible,
.cf-window :focus-visible { outline-color: var(--sc-accent); }

/* ================================================================= BAR == */

.cf-bar {
  position: fixed; z-index: var(--sc-z-chrome); inset: 0 0 auto 0;
  height: var(--cf-bar-h);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--cf-gut);
  pointer-events: none;
}
.cf-bar > * { pointer-events: auto; }
.cf-bar.is-dark { color: var(--cf-paper); }
.cf-bar.is-dark .cf-pill { background: var(--cf-paper); color: var(--sc-ink); }
.cf-bar.is-dark .cf-pill::after { background: var(--sc-accent); }
.cf-bar, .cf-bar .cf-pill { transition: color 240ms var(--sc-ease-out),
  background-color 240ms var(--sc-ease-out); }
.cf-bar__right { display: flex; align-items: center; gap: 10px; }
.cf-bar__mark { display: flex; align-items: center; gap: 10px; text-decoration: none; }
.cf-bar__mark img { width: 26px; height: 26px; border-radius: var(--sc-r-sm); }
.cf-bar__mark span { font-size: 14px; font-weight: 700; letter-spacing: 0.15em; }

/* Ein Hof hinter der Wortmarke. Nur dort, und mit Absicht nicht breiter.

   Die Leiste schwebt, und auf dem Desktop stand deshalb bis zum 05.09.2026
   ueberhaupt kein Grund darunter -- mit der Begruendung, jede Buehne habe
   oben ihren Innenabstand. Das stimmt fuer Buehnen, die stehen. Die
   Claim-Zeile FAEHRT aber nach oben: gemessen bei 1440px laeuft "One system.
   Every layer." von Scrollstand 875 bis 1125 durch die Leiste, 250px lang,
   und die Wortmarke ist hinter dem O und dem n nicht mehr zu lesen.

   Der erste Versuch war, den Verlauf der schmalen Breiten einfach auf jede
   Breite zu ziehen. Das war falsch, und zwar sichtbar: ueber die volle Breite
   gelegt wuscht ein Papierschleier alles aus, was dunkel darunter liegt. Die
   Oberkante des dunklen Konfigurator-Panels in Akt 6 stand danach als heller
   Nebel da und "01 / UEBERSICHT" darin war verschmiert. Nachgemessen laeuft an
   21 von 96 Scrollstaenden dunkler Inhalt hinter der Leiste durch (Kugeln des
   Auftakts, Karten in Akt 5, das Panel in Akt 6) -- ein deckender oder
   halbdeckender Streifen ueber die ganze Breite trifft sie alle.

   Dunkel hinter der WORTMARKE liegt dagegen nur eines: die Claim-Zeile selbst
   (Spalten 2 bis 6 von 24, also die linken 25 %). Der Hof deckt genau das ab
   und hoert lange vor der Bildmitte auf. Auf Papiergrund ist er unsichtbar,
   weil er dieselbe Farbe hat -- er tritt genau dann hervor, wenn etwas
   darunter durchlaeuft.

   Ellipse statt Rechteck, damit keine Kante entsteht: die Seite ist ein
   filmic one-shot, Text soll weggeblendet werden, nicht abgeschnitten. */
.cf-bar__mark { position: relative; }
.cf-bar__mark::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  inset: -30px -190px -30px -26px;
  background: radial-gradient(64% 150% at 17% 50%,
    var(--cf-paper) 0%, var(--cf-paper) 26%,
    color-mix(in oklab, var(--cf-paper) 82%, transparent) 46%,
    color-mix(in oklab, var(--cf-paper) 46%, transparent) 66%,
    color-mix(in oklab, var(--cf-paper) 16%, transparent) 84%, transparent 100%);
}
/* Ueber dem Fuss ist der Grund dunkel, sonst steht ein heller Fleck darauf. */
.cf-bar.is-dark .cf-bar__mark::before {
  background: radial-gradient(64% 150% at 17% 50%,
    var(--sc-ink) 0%, var(--sc-ink) 26%,
    color-mix(in oklab, var(--sc-ink) 82%, transparent) 46%,
    color-mix(in oklab, var(--sc-ink) 46%, transparent) 66%,
    color-mix(in oklab, var(--sc-ink) 16%, transparent) 84%, transparent 100%);
}
/* Unter 860px traegt der vollflaechige Verlauf weiter unten die Arbeit: dort
   laeuft Text ueber die ganze Breite unter der Leiste durch, nicht nur links. */
@media (max-width: 860px) { .cf-bar__mark::before { content: none; } }

.cf-pill {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 11px 20px; border-radius: var(--sc-r-pill);
  background: var(--sc-ink); color: var(--cf-paper);
  font-size: 12.5px; font-weight: 550; letter-spacing: 0.01em;
  text-decoration: none;
  box-shadow: var(--sc-e1);
  transition: transform 150ms var(--sc-ease-out), box-shadow 150ms var(--sc-ease-out);
}
.cf-pill::after {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--sc-accent); flex: none;
}
@media (hover: hover) and (pointer: fine) { .cf-pill:hover { box-shadow: var(--sc-e2); } }
.cf-pill:active { transform: translateY(1px); }
.cf-pill--ink { background: var(--sc-accent); color: var(--sc-accent-ink); }
.cf-pill--ink::after { background: var(--sc-ink); }
.cf-pill--big { padding: 16px 28px; font-size: 15px; }

/* ============================================================== AKT 1 ==
   Nach dem Vorbild der Referenz: die Zeile steht OBEN, die Buehne darunter
   ueber die ganze Breite. Das gibt dem Haufen Raum und der Seite einen
   Auftakt statt einer Illustration neben Text. */

.cf-hero {
  min-height: 100vh; display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  align-content: center; gap: clamp(20px, 3.4vh, 40px);
  padding: calc(var(--cf-bar-h) + 18px) var(--cf-gut) var(--cf-gut);
  background: var(--cf-paper);
}
.cf-hero__head {
  display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  gap: clamp(20px, 5vw, 90px); align-items: end;
  width: 100%; max-width: 92rem; margin-inline: auto;
}
.cf-hero__title {
  margin: 0; font-family: var(--sc-font-display);
  font-size: clamp(2.1rem, 4.2vw, 3.9rem); font-weight: 500;
  letter-spacing: var(--sc-track-tight); line-height: 0.98;
}
.cf-hero__note {
  margin: 0 0 0.5em; max-width: 40ch; font-size: 14.5px; line-height: 1.58;
  color: var(--sc-ink-soft); text-wrap: pretty;
}

/* Die Buehne: volle Breite, warmer Studioverlauf, weiche Kante. */
.cf-stagebox {
  position: relative; width: 100%; max-width: 92rem; margin-inline: auto;
  min-height: 0; height: 100%;
  border-radius: var(--sc-r-lg);
  background:
    radial-gradient(120% 130% at 52% 34%, var(--cf-ivory) 0%, var(--cf-cream) 48%, var(--cf-sand) 100%);
  overflow: hidden;
  touch-action: pan-y;
}
.cf-stagebox canvas, .cf-core canvas, .cf-exp__viz canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
}
.cf-stagebox .cf-2d, .cf-core .cf-2d, .cf-exp__viz .cf-2d { z-index: 0; }
.cf-stagebox .cf-gl, .cf-core .cf-gl, .cf-exp__viz .cf-gl { z-index: 1; }

.cf-marks { display: flex; justify-content: space-between; padding: 0 2px;
            max-width: 92rem; margin-inline: auto; width: 100%; }
.cf-marks i { position: relative; width: 11px; height: 11px; opacity: 0.4; }
.cf-marks i::before, .cf-marks i::after { content: ""; position: absolute; background: var(--sc-ink); }
.cf-marks i::before { inset: 50% 0 auto 0; height: 1px; }
.cf-marks i::after  { inset: 0 50% 0 auto; width: 1px; }

/* Basisregel fuer jede gepinnte Buehne. Sie war bei einem frueheren
   Blockaustausch mit verlorengegangen, wodurch die Buehnen ohne Innenabstand
   und ohne Raster liefen. */
.cf-stage {
  display: grid;
  padding: calc(var(--cf-bar-h) + 10px) var(--cf-gut) var(--cf-gut);
  background: var(--cf-paper);
}

/* ======================================================= DIE HELLE STRECKE */

.cf-run { position: relative; background: var(--cf-paper); }
.cf-ribbon-wrap { position: absolute; inset: 0; overflow: hidden; z-index: 0; pointer-events: none; }
.cf-ribbon { position: absolute; inset: 0; width: 100%; height: 100%; }
.cf-run > section { position: relative; z-index: 1; }

.cf-wrap { width: 100%; max-width: 78rem; margin-inline: auto; padding-inline: var(--cf-gut); }

/* -------------------------------------------------------------- AKT 2 -- */

.cf-claim { padding-block: clamp(1rem, 2.5vh, 2.5rem) clamp(3.5rem, 9vh, 7rem); }
.cf-claim__t {
  margin: 0 0 clamp(28px, 5vh, 56px); max-width: 16ch;
  font-family: var(--sc-font-display);
  font-size: clamp(3rem, 9.4vw, 9rem); font-weight: 500;
  letter-spacing: var(--sc-track-tight); line-height: 0.9;
  text-wrap: balance;
}
.cf-claim__body {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(20px, 4vw, 64px); margin-left: auto; max-width: 62rem;
  padding: clamp(20px, 3vw, 34px);
  background: var(--cf-paper);
  border-radius: var(--sc-r-md);
}
.cf-lede {
  margin: 0; font-size: clamp(1.05rem, 1.5vw, 1.3rem); line-height: 1.46;
  letter-spacing: var(--sc-track-snug); text-wrap: pretty;
}
.cf-small { margin: 0; font-size: 14px; line-height: 1.6; color: var(--sc-ink-soft); text-wrap: pretty; }

/* -------------------------------------------------------------- AKT 3 -- */

/* Der seitliche Abstand sitzt auf der RAIL, nicht auf der Buehne.

   Die Engine rechnet den Fahrweg als `rail.scrollWidth - vw`, also gegen die
   Viewportbreite. Steht der Abstand auf der Buehne, faengt die Rail um genau
   diesen Betrag zu weit rechts an und endet um ihn zu weit links -- auf dem
   Desktop unauffaellig, auf 393px die Haelfte der letzten Karte. Auf der Rail
   zaehlt er in `scrollWidth` mit und die Rechnung geht auf. */
.cf-stage--rail { padding-block: var(--cf-gut); padding-inline: 0;
                  align-items: center; background: transparent; }
.cf-rail { gap: 16px; align-items: center; height: 100%;
           padding-inline: var(--cf-gut); }
/* Der Abstand am Ende als echtes Flex-Kind, nicht als padding-right.

   Ein Flex-Container zaehlt sein END-Padding nicht in `scrollWidth`, sobald
   der Inhalt ueberlaeuft (gemessen in Chromium: scrollWidth 2321 bei 16px
   Padding auf beiden Seiten, also nur das linke drin). Die Engine faehrt
   gegen genau diesen Wert, und die letzte Karte klebte dadurch am rechten
   Rand. Ein Kind zaehlt immer mit. Der `gap` traegt 16px davon schon. */
.cf-rail::after { content: ''; flex: 0 0 max(0px, calc(var(--cf-gut) - 16px)); }

.cf-card {
  flex: none; width: clamp(17rem, 22vw, 22rem);
  display: flex; flex-direction: column; gap: 10px;
  padding: 22px;
  border-radius: var(--sc-r-md);
  background: var(--cf-paper);
  border: 1px solid var(--cf-line);
  --i: 0;
}
.cf-card__link { text-decoration: none; }
.cf-card__link::after { content: ""; position: absolute; inset: 0; }
.cf-card { position: relative; }
.cf-card h3 {
  margin: 2px 0 0; font-family: var(--sc-font-display);
  font-size: 1.7rem; font-weight: 500; letter-spacing: var(--sc-track-tight); line-height: 1;
}
.cf-card__p { margin: 0; min-height: 4.5em; font-size: 13.5px; line-height: 1.5; color: var(--sc-ink-soft); }
.cf-spec {
  display: grid; grid-template-columns: auto 1fr; gap: 2px 12px;
  margin: 4px 0 0; padding-top: 14px; border-top: 1px solid var(--cf-line);
  font-size: 13px;
}
.cf-spec dt { font-family: var(--sc-font-mono); font-size: 9.5px; letter-spacing: 0.1em;
              text-transform: uppercase; color: var(--sc-ink-soft); align-self: center; }
.cf-spec dd { margin: 0; font-weight: 550; font-variant-numeric: tabular-nums; }

.cf-card--lead, .cf-card--end {
  width: clamp(19rem, 26vw, 27rem);
  border: 0; background: transparent; justify-content: center; padding: 0 4px;
}
.cf-card__lead {
  margin: 6px 0 0; font-family: var(--sc-font-display);
  font-size: clamp(1.9rem, 3vw, 2.9rem); font-weight: 500;
  letter-spacing: var(--sc-track-tight); line-height: 1.02;
}
.cf-card--end { gap: 16px; }
.cf-card--end .cf-pill { align-self: flex-start; }
.cf-card--lead .cf-small, .cf-card--end .cf-card__p { min-height: 0; }

/* ------------------------------------------------- AKT 4 · EXPLODED ---- */

.cf-stage--exploded { background: var(--cf-paper); }
.cf-exp {
  position: relative;
  display: grid; grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
  gap: clamp(20px, 4vw, 56px); align-items: center; height: 100%; min-height: 0;
}
.cf-exp__side { display: grid; gap: 16px; align-content: center; }
.cf-exp__t {
  margin: 0; font-family: var(--sc-font-display);
  font-size: clamp(1.9rem, 3.6vw, 3.4rem); font-weight: 500;
  letter-spacing: var(--sc-track-tight); line-height: 1;
}
.cf-exp__rail { position: relative; margin-top: 6px; padding-left: 16px; }
/* Dieselbe senkrechte Bahn wie in der Seitenspalte von Client und Admin:
   gleiche Farbe, gleiche runde Kappe, gleiche Bedeutung "hier entlang". */
.cf-exp__track {
  position: absolute; left: 4px; top: 4px; bottom: 4px; width: 3px;
  border-radius: 3px; background: color-mix(in oklab, var(--sc-ink) 11%, transparent);
}
/* Bewegt wird ueber transform, nicht ueber top: top und height sind Layout und
   ziehen bei jedem Schritt Layout, Paint und Composite nach sich. Die Hoehe
   bleibt eine echte Hoehe und wird NICHT animiert: alle Zeilen der Liste sind
   gleich hoch, sie aendert sich also ohnehin nicht. Ueber scaleY waere sie
   zwar auch GPU, aber die runde Kappe wuerde mitskalieren und aus dem Strich
   eine Spitze machen. */
.cf-exp__mark {
  position: absolute; left: 4px; top: 0; width: 3px;
  height: var(--cf-mark-h, 0px);
  border-radius: 3px; background: #C0603C;
  transform: translateY(var(--cf-mark-t, 0px));
  transition: transform 420ms var(--sc-ease-out);
}
.cf-exp__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }
.cf-exp__list li {
  display: grid; grid-template-columns: 30px minmax(0, 11rem) minmax(0, 1fr);
  gap: 10px; align-items: baseline; padding: 8px 10px;
  border-radius: var(--sc-r-sm);
  color: var(--sc-ink-soft);
  transition: color 320ms var(--sc-ease-out), background-color 320ms var(--sc-ease-out);
}
.cf-exp__list span { font-family: var(--sc-font-mono); font-size: 10px; letter-spacing: 0.08em; }
.cf-exp__list b { font-family: var(--sc-font-display); font-size: 1.05rem; font-weight: 500;
                  letter-spacing: var(--sc-track-snug); }
.cf-exp__list em { font-style: normal; font-size: 12.5px; }
.cf-exp__list li[aria-current="true"] {
  color: var(--sc-ink); background: color-mix(in oklab, var(--cf-sand) 62%, transparent);
}
.cf-exp__list li[aria-current="true"] span { color: var(--cf-terra); }
.cf-exp__p { margin: 6px 0 0; max-width: 42ch; font-size: 14px; line-height: 1.55; color: var(--sc-ink-soft); }

/* Die Tiefenanzeige. Die Liste links sagt WAS gerade vorn liegt, diese Zeile
   sagt WIE TIEF man schon ist. Sie steht bewusst NEBEN dem preserve-3d-Kasten:
   ein Kind darin liegt bei z=0 und wuerde von den ausfahrenden Blaettern
   (bis z=+360px) verdeckt. */
.cf-exp__depth {
  position: absolute; right: 0; top: clamp(8px, 3vh, 34px); z-index: 5; margin: 0;
  display: flex; align-items: baseline; gap: 10px;
  font-family: var(--sc-font-mono);
}
.cf-exp__depth b {
  font-family: var(--sc-font-display); font-weight: 500;
  font-size: clamp(1.9rem, 3.4vw, 3.1rem); line-height: 0.9;
  letter-spacing: var(--sc-track-tight); color: var(--sc-ink);
  font-variant-numeric: tabular-nums;
}
.cf-exp__depth span { font-size: 11px; letter-spacing: 0.1em; color: var(--sc-ink-soft); }
.cf-exp__depth em {
  font-style: normal; font-family: var(--sc-font-display); font-size: 13px;
  letter-spacing: var(--sc-track-snug); color: var(--sc-ink-soft);
  padding-left: 10px; border-left: 1px solid var(--cf-line);
}

/* Der Ebenenstapel: echte Aufnahmen und echtes Markup in CSS-3D. Als Textur
   auf einer WebGL-Flaeche waeren die Seiten an dieser Groesse nicht mehr
   lesbar gewesen, und lesbar war genau der Punkt. */
.cf-exp__viz {
  position: relative; height: 100%; min-height: 0;
  perspective: 1500px; perspective-origin: 44% 50%;
  transform-style: preserve-3d;
}
.cf-layer {
  position: absolute; left: 50%; top: 50%;
  width: min(100%, 54rem); aspect-ratio: 16 / 10;
  translate: -50% -50%;
  transform-origin: 50% 50%;
  border-radius: 10px; overflow: hidden;
  background: var(--cf-paper);
  box-shadow: 0 2px 6px rgba(43,33,25,.14), 0 34px 70px -30px rgba(43,33,25,.48);
  will-change: transform, opacity;
  /* KEINE Transition auf opacity. Der Wert wird in page.js jeden Frame gesetzt
     und ist dort ueber explodedP schon nachlaufend geglaettet. Eine Transition
     darueber wird jeden Frame neu angesetzt, kommt nie an und fuegt der
     Bewegung nur Verzoegerung hinzu. */
}
.cf-layer img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top left; }
/* Luftperspektive statt Deckkraft: ein wartendes Blatt bleibt deckend und
   wird nur Richtung Papierfarbe gewaschen. Sonst liest man durch den halben
   Stapel hindurch. */
.cf-layer::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: var(--cf-paper); opacity: var(--cf-haze, 0);
}

/* Die vier technischen Ebenen sind kein Bild, sondern Markup. Sie standen
   vorher als fast leere, fast weisse Blaetter da: winziger Inhalt, mittig,
   Creme auf #FFFCF7. Jetzt fuellen sie ihr Blatt und tragen echten Kontrast,
   sonst liest der Stapel sich ab Ebene 04 als vier leere Zettel. */
.cf-layer--tech { background: var(--cf-ivory); border: 1px solid var(--cf-line); }
.cf-layer--tech::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 34px;
  background: var(--cf-sand); border-bottom: 1px solid var(--cf-line);
}
.lay-in {
  height: 100%; display: grid; grid-template-rows: auto minmax(0, 1fr) auto;
  gap: clamp(10px, 1.8vh, 20px);
  padding: clamp(48px, 6vh, 62px) clamp(22px, 3.2vw, 46px) clamp(20px, 3vh, 34px);
}
.lay-head { display: grid; gap: 3px; }
.lay-t { margin: 0; font-family: var(--sc-font-display); font-weight: 500;
         font-size: clamp(1.15rem, 2vw, 1.7rem); line-height: 1;
         letter-spacing: var(--sc-track-tight); color: var(--sc-ink); }
.lay-h { margin: 0; font-family: var(--sc-font-mono); font-size: 9.5px; letter-spacing: 0.12em;
         text-transform: uppercase; color: var(--sc-ink-soft); }

/* 03 · Frontend, und die Antwortseite von 04. Echter Code, in denselben
   warmen Werten gesetzt: Klammern und Tags gedaempft, Namen in Ink, Werte in
   Terrakotta. Kein Buntsatz, die Seite hat drei Farben. */
.lay-code {
  margin: 0; overflow: hidden;
  font-family: var(--sc-font-mono);
  font-size: clamp(9px, 0.86vw, 12px);
  line-height: 1.62;
  color: var(--sc-ink);
  white-space: pre;
  tab-size: 2;
}
/* Vier Werte, alle gemessen gegen den Grund des Blattes (#F7F3EC). --cf-taupe
   waere fuer Tags naheliegend gewesen und traegt dort 2,1:1: als Zierde
   vielleicht vertretbar, als Code nicht. --cf-terra fuer Zahlen lag bei
   2,9:1. Beide raus. */
.lay-code .c-t { color: #7d6b55; }                      /* Tags und Klammern */
.lay-code .c-a { color: var(--sc-ink-soft); }           /* Attribut, Schluessel */
.lay-code .c-v { color: var(--sc-accent); }             /* Zeichenkette */
.lay-code .c-n { color: var(--sc-ink); }                /* Zahl */
.lay-code .c-c { color: #7d6b55; font-style: italic; }  /* Kommentar */

/* Anfrage links, Antwort rechts. Das ist die Aussage der Ebene: eine
   Vertragsschicht hat zwei Seiten. */
.lay-split {
  display: grid; grid-template-columns: minmax(0, 0.82fr) minmax(0, 1fr);
  gap: clamp(14px, 2.4vw, 34px); align-items: start; height: 100%;
}
.lay-code--json { font-size: clamp(9px, 0.8vw, 11.5px); }

/* 04 · API */
.lay-api { width: 100%; height: 100%; border-collapse: collapse; }
.lay-api td { padding: clamp(7px, 1.3vh, 13px) 0; border-bottom: 1px solid var(--cf-line);
              font-size: clamp(11px, 1.05vw, 14px); color: var(--sc-ink); vertical-align: baseline; }
.lay-api tr:last-child td { border-bottom: 0; }
.lay-api td:nth-child(1) { width: 4.6rem; }
.lay-api td:nth-child(3) { width: 3rem; text-align: right; font-family: var(--sc-font-mono);
                           font-size: 10px; color: var(--cf-terra); }
.lay-api td:nth-child(1) b {
  display: inline-block; font-family: var(--sc-font-mono); font-weight: 400;
  font-size: 9.5px; letter-spacing: 0.08em; padding: 3px 7px; border-radius: 4px;
  background: var(--cf-cream); border: 1px solid var(--cf-line); color: var(--sc-ink);
}
.lay-api td:nth-child(2) { font-family: var(--sc-font-mono); }

/* 05 · Backend */
.lay-grid { display: grid; height: 100%; grid-template-columns: repeat(2, minmax(0, 1fr));
            grid-auto-rows: minmax(0, 1fr); gap: clamp(7px, 1.3vh, 13px); }
.lay-grid span { display: grid; gap: 2px; padding: clamp(9px, 1.6vh, 15px) clamp(10px, 1.2vw, 16px);
                 border-radius: 8px; background: var(--cf-cream); border: 1px solid var(--cf-line); }
.lay-grid b { font-size: clamp(11px, 1vw, 13.5px); font-weight: 500; color: var(--sc-ink);
              letter-spacing: var(--sc-track-snug); }
.lay-grid em { font-style: normal; font-size: clamp(9.5px, 0.85vw, 11.5px); color: var(--sc-ink-soft); }

/* 06 · Database */
.lay-db { width: 100%; height: 100%; border-collapse: collapse; font-size: clamp(11px, 1.05vw, 14px); }
.lay-db td { padding: clamp(6px, 1.15vh, 12px) 0; border-bottom: 1px solid var(--cf-line);
             color: var(--sc-ink); }
.lay-db tr:last-child td { border-bottom: 0; }
.lay-db td:first-child { font-family: var(--sc-font-mono); width: 34%; }
.lay-db td:nth-child(2) { color: var(--sc-ink-soft); }
.lay-db td:last-child { text-align: right; font-family: var(--sc-font-mono);
                        font-variant-numeric: tabular-nums; }
.lay-note { margin: 0; font-size: 10.5px; color: var(--sc-ink-soft); }

/* 07 · Automation */
.lay-flow { list-style: none; margin: 0; padding: 0; height: 100%;
            display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
            gap: clamp(7px, 1vw, 14px); align-items: stretch; }
.lay-flow li { position: relative; display: grid; gap: 3px; align-content: start;
               padding: clamp(10px, 1.7vh, 17px) clamp(8px, 0.9vw, 13px);
               border-radius: 8px; background: var(--cf-cream); border: 1px solid var(--cf-line); }
.lay-flow b { font-size: clamp(10.5px, 0.95vw, 13px); font-weight: 500; color: var(--sc-ink);
              letter-spacing: var(--sc-track-snug); }
.lay-flow em { font-style: normal; font-size: clamp(9px, 0.8vw, 11px); color: var(--sc-ink-soft); }
/* Der Verbinder ist derselbe rundgekappte Terrakotta-Strich wie die Bahn. */
.lay-flow li + li::before {
  content: ""; position: absolute; top: 50%; left: calc(-1 * clamp(7px, 1vw, 14px) - 1px);
  width: clamp(7px, 1vw, 14px); height: 3px; border-radius: 3px; background: #C0603C;
}

/* ---------------------------------------------- AKT 5 · OBERFLAECHEN ---
   Hell wie die uebrige Seite. Der dunkle Block war der letzte Rest der
   alten, kuehlen Fassung und stand quer zur warmen Welt. */

.cf-stage--surfaces { background: var(--cf-paper); align-content: center;
                      gap: clamp(16px, 2.4vh, 30px); }
.cf-surf__head { display: grid; gap: 8px; grid-template-columns: minmax(0, 1fr) minmax(0, 30rem);
                 align-items: end; column-gap: clamp(24px, 5vw, 80px); }
.cf-surf__t { margin: 0; grid-column: 1; font-family: var(--sc-font-display);
  font-size: clamp(1.8rem, 3.2vw, 3rem); font-weight: 500;
  letter-spacing: var(--sc-track-tight); line-height: 1; }
.cf-surf__head .cf-over { grid-column: 1; }
.cf-surf__lede { grid-column: 2; grid-row: 1 / span 2; margin: 0; align-self: end;
  max-width: 42ch; font-size: 14px; line-height: 1.55; color: var(--sc-ink-soft); }

.cf-surf__grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(14px, 1.8vw, 30px);
  padding-inline: clamp(14px, 2vw, 34px);
  min-height: 0; align-content: center; align-items: start;
}

.cf-surf {
  display: grid; gap: 12px; text-decoration: none; color: inherit;
  /* Hover-Antwort. 520ms lagen weit ueber dem Band fuer Dropdowns und Selects
     (150 bis 250ms) und lasen sich als traege. */
  transition: transform 200ms var(--sc-ease-out), opacity 200ms var(--sc-ease-out);
}
/* Echte Aufnahmen der echten Unterseiten. Beide Masse werden ueberschrieben,
   sonst loest das nicht gesetzte auf den Attributwert auf. */
.cf-surf__media {
  position: relative; display: block; aspect-ratio: 16 / 10;
  border-radius: var(--sc-r-lg); overflow: hidden;
  background: #fff;
  box-shadow: 0 1px 2px rgba(43,33,25,.10), 0 18px 40px -18px rgba(43,33,25,.34);
}
.cf-surf__media img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: top left;
  transform: scale(1.02);
  transition: transform 260ms var(--sc-ease-out), filter 260ms var(--sc-ease-out);
  filter: saturate(0.82) contrast(0.96);
}
.cf-surf[aria-current="true"] .cf-surf__media img { transform: scale(1.07); filter: none; }
.cf-surf__open {
  position: absolute; right: 10px; top: 10px; z-index: 2;
  font-family: var(--sc-font-mono); font-size: 9px; letter-spacing: 0.12em;
  text-transform: uppercase; padding: 5px 9px; border-radius: var(--sc-r-pill);
  background: var(--sc-ink); color: var(--cf-paper);
  opacity: 0; transform: translateY(-5px);
  transition: opacity 300ms var(--sc-ease-out), transform 300ms var(--sc-ease-out);
}
.cf-surf[aria-current="true"] .cf-surf__open { opacity: 1; transform: none; }

.cf-surf__meta { display: grid; grid-template-columns: 28px 1fr; gap: 1px 8px; align-items: baseline; }
.cf-surf__n { grid-row: span 2; font-family: var(--sc-font-mono); font-size: 10px;
              letter-spacing: 0.1em; color: var(--sc-ink-soft); padding-top: 5px; }
.cf-surf__name { font-family: var(--sc-font-display); font-size: clamp(1.05rem, 1.5vw, 1.45rem);
                 font-weight: 500; letter-spacing: var(--sc-track-tight); line-height: 1;
                 color: var(--sc-ink-soft); transition: color 380ms var(--sc-ease-out); }
.cf-surf__tags { font-family: var(--sc-font-mono); font-size: 9.5px; letter-spacing: 0.1em;
                 text-transform: uppercase; color: var(--sc-ink-soft); }
.cf-surf[aria-current="true"] .cf-surf__name { color: var(--sc-ink); }
.cf-surf[aria-current="true"] .cf-surf__n { color: var(--sc-accent); }

@media (hover: hover) and (pointer: fine) {
  .cf-surf[aria-current="true"] { transform: scale(1.05); z-index: 2; }
  .cf-surf:not([aria-current="true"]) { opacity: 0.62; transform: scale(0.95); }
}
.cf-surf:focus-visible { outline-offset: 6px; }

/* ------------------------------------------------- AKT 5 · DER UNTERBAU --
   Der Anschluss an Akt 4. Ohne ihn stehen sieben Ebenen und vier Oberflaechen
   als zwei Bilder nebeneinander und niemand sagt, wie sie zusammenhaengen. */
.cf-base {
  position: relative; display: grid; gap: 0;
  padding-inline: clamp(14px, 2vw, 34px);
}
.cf-base__wire { display: block; width: 100%; height: clamp(46px, 7vh, 88px); overflow: visible; }
.cf-base__layers {
  list-style: none; margin: 0; padding: clamp(10px, 1.6vh, 16px) clamp(12px, 1.6vw, 22px);
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: clamp(6px, 1vw, 16px);
  border-radius: var(--sc-r-md);
  background: color-mix(in oklab, var(--cf-sand) 52%, transparent);
}
.cf-base__layers li { display: grid; gap: 2px; min-width: 0; }
.cf-base__layers span { font-family: var(--sc-font-mono); font-size: 9px; letter-spacing: 0.1em;
                        color: var(--cf-terra); }
.cf-base__layers b { font-size: clamp(11px, 0.92vw, 12.5px); font-weight: 500; color: var(--sc-ink);
                     letter-spacing: var(--sc-track-snug); white-space: nowrap;
                     overflow: hidden; text-overflow: ellipsis; }

/* ============================================================== AKT 6 ==
   Kein Rendering mehr, sondern eine Sequenz: das Bild startet klein links
   und waechst beim Scrollen auf. Die Groesse kommt aus --sc-p, das die
   Engine auf dem Akt veroeffentlicht. */

.cf-stage--close { background: var(--cf-paper); align-content: center; }
.cf-close {
  display: grid; grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: clamp(24px, 4vw, 70px); align-items: center; height: 100%; min-height: 0;
}
.cf-close__copy { display: grid; gap: 18px; justify-items: start; align-content: center; }
.cf-close__t {
  margin: 0; font-family: var(--sc-font-display);
  font-size: clamp(2.2rem, 4.6vw, 4.4rem); font-weight: 500;
  letter-spacing: var(--sc-track-tight); line-height: 0.96; text-wrap: balance;
}
.cf-close__p { margin: 0; max-width: 40ch; font-size: 15px; line-height: 1.56; color: var(--sc-ink-soft); }

/* Die vier echten Schritte des Konfigurators laufen mit dem Scroll nacheinander
   voll. Aus dem blossen Groesserwerden wird dadurch eine Sequenz: das Bild
   kommt naeher, WAEHREND daneben etwas passiert. Der Fuellstand kommt aus
   --sc-p, das die Engine auf dem Akt veroeffentlicht. */
.cf-close__steps {
  list-style: none; margin: 0; padding: 0; width: 100%; max-width: 30rem;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px;
}
.cf-close__steps li { position: relative; display: grid; gap: 3px; padding-top: 10px; }
.cf-close__steps li::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; border-radius: 3px;
  background: color-mix(in oklab, var(--sc-ink) 11%, transparent);
}
/* scaleX statt width. Der Fuellstand haengt an --sc-p und wurde damit bei
   JEDEM Scrollframe auf vier Elementen neu berechnet: width ist Layout, also
   Layout, Paint und Composite pro Frame. Als transform bleibt es auf der GPU.
   Die Kappe verzieht sich dabei leicht, aber bei 3 Pixel Hoehe sieht das
   niemand. */
.cf-close__steps i {
  position: absolute; left: 0; top: 0; width: 100%; height: 3px;
  border-radius: 3px; background: #C0603C;
  transform-origin: 0 50%;
  transform: scaleX(clamp(0, calc(var(--sc-p, 0) * 4 - var(--i)), 1));
}
.cf-close__steps span { font-family: var(--sc-font-mono); font-size: 9px; letter-spacing: 0.1em;
                        color: var(--sc-ink-soft); }
.cf-close__steps b { font-size: 12.5px; font-weight: 500; color: var(--sc-ink);
                     letter-spacing: var(--sc-track-snug); }

/* Die Zeile rollt wortweise aus einer Maske herauf. Das ist Lusions
   Handschrift auf ihrer Featured-Work-Liste, und sie kommt mit denselben
   Mitteln wie alles andere hier: eine Kurve, eine Dauer, gestaffelte
   Verzoegerung. Die Woerter werden in page.js eingepackt, damit im Markup ein
   lesbarer Satz steht und keine Span-Suppe. */
.cf-roll { overflow: visible; }
.cf-roll__m { display: inline-block; overflow: hidden; vertical-align: bottom; padding-bottom: 0.06em; }
.cf-roll__w {
  display: inline-block;
  transform: translateY(115%);
  transition: transform 700ms var(--cf-ease) calc(var(--i, 0) * 70ms);
}
.cf-roll.is-in .cf-roll__w { transform: none; }

.cf-close__shot {
  position: relative;
  display: block; justify-self: end; width: 100%;
  /* Waechst mit dem Scroll und richtet sich dabei auf: erst klein und schraeg
     im Raum, am Ende flach und gross. Nur transform, keine Layoutanimation. */
  /* --cf-g laeuft doppelt so schnell wie der Akt: die Aufnahme steht nach gut
     der halben Strecke fertig da, statt bis zum letzten Pixel zu wachsen. Der
     Rest des Akts gehoert dann der Zeile und dem Knopf. */
  --cf-g: clamp(0, calc(var(--sc-p, 0) * 2), 1);
  transform:
    perspective(1400px)
    translate3d(0, calc((1 - var(--cf-g)) * 3.5%), 0)
    rotateY(calc((1 - var(--cf-g)) * -13deg))
    rotateX(calc((1 - var(--cf-g)) * 4deg))
    scale(calc(0.58 + 0.42 * var(--cf-g)));
  transform-origin: 82% 50%;
}
/* Der Rahmen oeffnet sich waehrend des Wachsens aus einem Breitbild-Streifen
   auf sein volles Mass, und das Bild darin faehrt leicht gegen die Oeffnung.
   Dieses Gegenlaufen ist der Unterschied zwischen "ein Bild wird groesser"
   und "ein Bild geht auf": ohne es klebt der Inhalt am Rahmen und die Maske
   liest sich als Beschnitt. */
/* KEIN Vorhang mehr. Der Rahmen fuhr ueber scaleY senkrecht auf und das Bild
   skalierte dagegen. Rechnerisch stimmte das Bild, aber Rundung und Schatten
   wurden mitgestaucht, und man sah einen Letterbox-Ausschnitt statt der Seite:
   es sah gequetscht aus. Jetzt waechst die Aufnahme gleichmaessig und richtet
   sich dabei auf. Eine gleichmaessige Skalierung kann nicht quetschen. */
.cf-close__frame {
  display: block; position: relative; overflow: hidden;
  border-radius: var(--sc-r-lg); background: #fff;
  box-shadow: 0 2px 6px rgba(43,33,25,.12), 0 30px 64px -26px rgba(43,33,25,.42);
}
.cf-close__shot img {
  display: block; width: 100%; height: auto;
  transform: scale(var(--cf-zoom, 1));
  transition: transform var(--cf-dur) var(--cf-ease);
}
@media (hover: hover) and (pointer: fine) {
  .cf-close__shot:hover, .cf-close__shot:focus-visible { --cf-zoom: 1.04; }
}
/* Der Hinweis ist eine runde Marke in der Mitte, die auf Zeigergeraeten erst
   beim Ueberstreichen kommt. Eine Plakette unten links stand vorher genau auf
   dem "Weiter" der abgebildeten Seite, und eine dauerhafte Plakette auf einer
   Aufnahme ist ohnehin Beiwerk. Sie sitzt NEBEN dem Rahmen, nicht darin: im
   Rahmen braeuchte sie die Gegenskalierung des Vorhangs, und die Mitte ist
   ohnehin immer sichtbar, egal wie weit der Vorhang auf ist. */
.cf-close__hint {
  position: absolute; left: 50%; top: 50%; z-index: 2;
  /* Keine Gegenskalierung mehr noetig: es wird nichts mehr gestaucht. */
  display: grid; place-content: center; gap: 2px; text-align: center;
  width: 108px; height: 108px; border-radius: 50%;
  background: var(--sc-ink); color: var(--cf-paper);
  opacity: 0; transform: translate(-50%, -50%) scale(0.82);
  transition: opacity 420ms var(--cf-ease), transform 420ms var(--cf-ease),
              background-color 240ms var(--cf-ease);
}
.cf-close__hint b { font-family: var(--sc-font-display); font-size: 14px; font-weight: 500;
                    letter-spacing: var(--sc-track-snug); }
.cf-close__hint em { font-style: normal; font-family: var(--sc-font-mono); font-size: 8px;
                     letter-spacing: 0.12em; text-transform: uppercase; color: #C9BCAC; }

@media (hover: hover) and (pointer: fine) {
  .cf-close__shot:hover .cf-close__hint,
  .cf-close__shot:focus-visible .cf-close__hint {
    opacity: 1; transform: translate(-50%, -50%) scale(1);
  }
  .cf-close__shot:hover .cf-close__hint { background: var(--sc-accent); }
}
/* Ohne Zeiger gibt es kein Ueberstreichen. Dort steht sie einfach da, sobald
   das Bild weit genug offen ist. */
@media (hover: none) {
  .cf-close__hint { opacity: clamp(0, calc(var(--cf-g) * 2 - 0.9), 1);
                    transform: translate(-50%, -50%) scale(1); }
}

/* ================================================================ FOOT == */

.cf-foot {
  display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: 28px clamp(24px, 6vw, 80px);
  padding: clamp(2.5rem, 6vh, 4.5rem) var(--cf-gut);
  background: var(--cf-deep); color: var(--cf-paper);
}
.cf-foot__brand img { width: 190px; height: auto; }
.cf-foot__brand p { margin: 14px 0 0; max-width: 44ch; font-size: 13.5px; line-height: 1.6; color: #B3A392; }
.cf-foot__nav { display: flex; flex-wrap: wrap; gap: 10px 26px; align-content: start; font-size: 13.5px; }
.cf-foot__nav a { text-decoration: underline; text-underline-offset: 0.24em;
                  text-decoration-color: color-mix(in oklab, #F4EFE6 40%, transparent); }
.cf-foot__meta {
  grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 8px 24px;
  margin: 0; padding-top: 22px;
  border-top: 1px solid color-mix(in oklab, #F4EFE6 16%, transparent);
  font-family: var(--sc-font-mono); font-size: 10px; letter-spacing: 0.1em;
  text-transform: uppercase; color: #B3A392;
}

/* =============================================================== MOBIL == */

@media (max-width: 1000px) {
  .cf-hero__head { grid-template-columns: 1fr; gap: 12px; align-items: start; }
  .cf-hero__note { margin: 0; }
  .cf-claim__body { grid-template-columns: 1fr; }

  /* Ohne eigene Regeln stand die Textspalte ueber dem warmen Verlauf, und
     gedaempftes Grau auf Sand faellt unter 4,5:1. Beide Spalten trennen. */
  /* Drei Kinder, drei Zeilen: Text, Tiefenanzeige, Stapel. Mit nur zwei
     gesetzten Zeilen fiel der Stapel in eine implizite dritte, die Textspalte
     wurde geklemmt, und die Anzeige landete mitten auf den Blaettern. */
  .cf-exp { grid-template-columns: 1fr; grid-template-rows: auto auto minmax(0, 1fr); gap: 10px; }
  .cf-exp__side {
    background: var(--cf-paper); border-radius: var(--sc-r-md); padding: 12px 14px; gap: 8px;
  }
  .cf-exp__list li { grid-template-columns: 26px 1fr; gap: 2px 10px; padding: 5px 8px; }
  .cf-exp__list em { grid-column: 2; }
  .cf-exp__p { display: none; }

  .cf-exp__rail { padding-left: 13px; }
  .cf-exp__depth { position: static; margin: 0; gap: 8px; align-items: center; }
  .cf-exp__depth b { font-size: 1.1rem; }
  .cf-exp__depth em { font-size: 12px; padding-left: 8px; }

  .cf-surf__head { grid-template-columns: 1fr; gap: 8px; }
  .cf-surf__t, .cf-surf__head .cf-over, .cf-surf__lede { grid-column: 1; grid-row: auto; }
  .cf-surf__lede { max-width: none; font-size: 13px; }
  .cf-surf__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  /* 16/10 statt 5/4. Das ist das Format, in dem die Aufnahmen wirklich
     vorliegen (1440x900), es wird also nichts mehr beschnitten -- und es
     spart je Kartenreihe rund 30px Hoehe, die Akt 5 auf einem Telefon
     dringend braucht (siehe die Rechnung weiter unten). */
  .cf-surf__media { aspect-ratio: 16 / 10; }

  /* Zwei Reihen Karten: eine Steigleitung pro Spalte statt pro Karte waere
     falsch beschriftet. Die Leitungen treten hier ganz zurueck, die
     Ebenenbank traegt den Anschluss allein. */
  .cf-base__wire { display: none; }
  .cf-base__layers { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px 12px;
                     margin-top: clamp(12px, 2vh, 20px); }

  /* Nummer NEBEN den Namen, nicht darueber.

     Das ist die Zeile, an der Akt 5 auf dem Telefon gehangen hat. Die Buehne
     ist ein Grid mit `align-content: center`, das Raster darin traegt
     `min-height: 0` -- reicht die Hoehe nicht, wird das Raster stillschweigend
     unter seine Inhaltsgroesse gestaucht und die Karten ragen unten heraus,
     mitten in die Ebenenbank. Gemessen: bei 660px Bildschirm 55px zu wenig,
     bei 553px (iPhone SE in Safari) 110px.

     Genau das hat der Auftraggeber fotografiert: "03 Client Portal" stand im
     "01 Visual Design" der Bank, und der Absatz darueber verschwand unter den
     Karten (die Aufnahme-Harness mass dort 1,22:1).

     Uebereinander kostet jeder Eintrag 33px, nebeneinander 15px. Bei vier
     Zeilen sind das 85px -- zusammen mit dem flacheren Kartenformat deckt
     das beide Faelle. */
  .cf-base__layers li { grid-template-columns: auto minmax(0, 1fr);
                        align-items: baseline; gap: 0 7px; }

  .cf-close { grid-template-columns: 1fr; gap: 18px; align-content: center; }
  .cf-close__shot { transform: scale(calc(0.76 + 0.24 * var(--cf-g))); transform-origin: 50% 50%; }
  .cf-close__steps { max-width: none; }
}

@media (max-width: 860px) {
  :root { --cf-bar-h: 62px; }

  /* Ein weicher Grund unter der ganzen Leiste, nur auf schmalen Breiten.

     Hier laeuft Text ueber die volle Breite unter der Leiste durch, nicht nur
     links: der Pruefer hat fuenf solche Stellen gefunden (Ebenennamen aus
     Akt 4, "Admin" und "04" aus Akt 5), und die Pille nimmt hier fast die
     halbe Breite ein. Auf breiten Fenstern waere derselbe Streifen falsch --
     siehe den Hof an .cf-bar__mark weiter oben.

     Ein Verlauf statt eines Balkens, weil die Seite ein filmic one-shot ist:
     Text soll weggeblendet werden, nicht an einer Kante abgeschnitten. */
  .cf-bar::before {
    content: ''; position: absolute; inset: 0 0 auto 0; z-index: -1;
    height: calc(var(--cf-bar-h) + 14px); pointer-events: none;
    background: linear-gradient(to bottom,
      var(--cf-paper) 0%, var(--cf-paper) 46%,
      color-mix(in oklab, var(--cf-paper) 72%, transparent) 74%, transparent 100%);
  }
  /* Ueber dem Fuss ist der Grund dunkel, sonst blitzt ein heller Streifen
     ueber dunkler Flaeche auf. */
  .cf-bar.is-dark::before {
    background: linear-gradient(to bottom,
      var(--sc-ink) 0%, var(--sc-ink) 46%,
      color-mix(in oklab, var(--sc-ink) 72%, transparent) 74%, transparent 100%);
  }

  .cf-bar__mark span { display: none; }
  /* Trefferflaechen auf 44px, ohne dass sich am Bild etwas aendert.

     Die Marke ist ein 26px-Zeichen und die Pille 37px hoch -- beide unter
     der Vorgabe aus WCAG 2.5.5, und beide sitzen in einer 62px hohen Leiste,
     in der der Platz laengst da ist. Das Ziel waechst, das Sichtbare nicht. */
  .cf-bar__mark { min-height: 44px; align-items: center; }
  .cf-pill { padding: 9px 15px; font-size: 12px; min-height: 44px; }
  .cf-stage { padding: calc(var(--cf-bar-h) + 6px) var(--cf-gut) var(--cf-gut); }
  .cf-hero { padding-top: calc(var(--cf-bar-h) + 10px); }
  .cf-marks i:nth-child(2), .cf-marks i:nth-child(4) { display: none; }
  .cf-card { width: 78vw; }
  .cf-card--lead, .cf-card--end { width: 84vw; }
  /* Kein Klemmen mehr. Die Ueberschrift steht seit der Korrektur ueber den
     ganzen Akt, und ein max-height hat ihr die erste Zeile abgeschnitten,
     der Liste die letzten beiden. Stattdessen faellt die Beschreibung: der
     Name der Ebene traegt sie auf dieser Breite allein. */
  .cf-exp__side { max-height: none; overflow: visible; gap: 5px; }
  .cf-exp__t { font-size: clamp(1.4rem, 6.2vw, 1.9rem); }
  .cf-exp__list li { padding: 3px 8px; }
  .cf-exp__list em { display: none; }
  .cf-exp__list b { font-size: 0.94rem; }
  /* Flachere Perspektive: bei 1500px reicht ein Blatt auf dieser Hoehe ueber
     seinen Kasten hinaus und wird unten vom Bildschirmrand abgeschnitten. */
  .cf-exp__viz { perspective: 2400px; }

  /* Die vier technischen Blaetter sind fuer 780 Pixel Breite gesetzt und
     stehen hier auf 358. Sie tragen deshalb weniger, statt zu ueberlaufen. */
  .cf-layer--tech::before { height: 22px; }
  .lay-in { padding: 32px 14px 14px; gap: 7px; }
  .lay-t { font-size: 1rem; }
  .lay-h { font-size: 8px; }
  .lay-api td { padding: 4px 0; font-size: 10px; }
  .lay-api tr:nth-child(n+5) { display: none; }
  /* Auf 358 Pixel Blattbreite steht Code in zwei Spalten nicht mehr. Die
     Antwortseite faellt, die Anfrage traegt die Ebene allein. */
  .lay-split { grid-template-columns: 1fr; }
  .lay-code--json { display: none; }
  .lay-code { font-size: 8px; line-height: 1.5; }
  .lay-api td:nth-child(1) { width: 3.1rem; }
  .lay-api td:nth-child(1) b { font-size: 8px; padding: 2px 5px; }
  .lay-api td:nth-child(3) { width: 1.8rem; }
  .lay-grid { gap: 5px; }
  .lay-grid span { padding: 6px 8px; }
  .lay-grid b { font-size: 11px; }
  .lay-grid em { display: none; }
  .lay-db td { padding: 4px 0; font-size: 10px; }
  .lay-db td:nth-child(2) { display: none; }
  .lay-db tr:nth-child(n+5) { display: none; }
  /* Die Kaesten sind so hoch wie ihr Inhalt, nicht wie das Blatt.

     `.lay-flow` steht auf `height: 100%` und `align-items: stretch`, damit
     die fuenf Schritte auf dem Desktop eine geschlossene Reihe bilden. Dort
     tragen sie zwei Zeilen (Titel und Erlaeuterung); hier faellt die zweite
     weg, und aus der Reihe wurden fuenf hohe LEERE Rechtecke mit einem Wort
     am oberen Rand -- das liest sich als Ladezustand, nicht als Ablauf. Der
     Auftraggeber hat genau dieses Bild fotografiert.

     `align-items: center` schrumpft sie auf ihren Inhalt, `align-content`
     haelt die Reihe in der Mitte des Blattes, wo sie hingehoert. */
  .lay-flow { gap: 4px; align-items: center; align-content: center; }
  .lay-flow li { padding: 7px 4px; border-radius: 6px; }
  /* Ohne die zweite Zeile ist Platz fuer eine lesbare erste. */
  .lay-flow b { font-size: 11px; }
  .lay-flow em { display: none; }
  .lay-flow li + li::before { left: -5px; width: 5px; height: 2px; }
  .lay-note { font-size: 10px; }

  .cf-surf__tags { display: none; }
  .cf-surf__open { display: none; }
  .cf-base__layers { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cf-close__steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cf-foot { grid-template-columns: 1fr; }
  /* Acht Verweise mit 22px Hoehe sind auf einem Telefon kaum zu treffen.
     44px ist die Vorgabe aus WCAG 2.5.5 und zugleich Apples eigene. Die
     Zeile bleibt optisch so hoch wie vorher, das Ziel waechst nach oben und
     unten -- deshalb der negative Zeilenabstand im `gap`, sonst reisst die
     Fusszeile auf. */
  .cf-foot__nav { gap: 0 22px; }
  .cf-foot__nav a { display: inline-flex; align-items: center; min-height: 44px; }

  /* Die Bahn tritt auf dem Telefon zurueck -- dieselbe Entscheidung, die in
     shell.css fuer die Unterseiten schon steht, und aus demselben Grund.

     Der Strich ist 28px stark und `non-scaling-stroke`, also auf jeder
     Breite gleich dick: auf 1440 sind das 1,9 % der Breite und ein Bogen im
     Hintergrund, auf 393 sind es 7,1 % und ein Balken quer durchs Bild. Weil
     die Rail-Buehne bewusst durchsichtig ist (die Bahn soll ja hinter Akt 2
     bis 4 durchlaufen), stand er direkt hinter dem Fliesstext: Taupe auf
     Terrakotta traegt 1,44:1 und ist damit unlesbar.

     Duenner allein reicht nicht -- bei jeder Deckkraft, bei der die Bahn
     ueberhaupt noch zu sehen ist, bleibt der Text darauf unter 4,5:1.
     Nachgerechnet: 0,35 ergibt 3,9:1, und selbst 0,22 nur 4,5:1. Eine
     einspaltige Seite hat keine freie Bahn, auf der ein Bogen laufen kann. */
  .cf-ribbon-wrap { display: none; }
}

/* ================================================ NIEDRIGE BILDSCHIRME ==
   Safari auf dem Telefon gibt viel weniger Hoehe her, als die Geraetegroesse
   vermuten laesst: von den 852pt eines iPhone 15 bleiben mit Adress- und
   Werkzeugleiste rund 660 uebrig, auf einem iPhone SE von 667pt nur 553.
   Genau in dieser Luecke sind die Fehler entstanden, die der Auftraggeber
   fotografiert hat -- bei 844px Hoehe, mit der hier bis zum 31.08.2026
   gemessen wurde, ist die Seite tadellos.

   Ein pin act kann nicht scrollen, seine Buehne ist genau einen Bildschirm
   hoch. Passt der Inhalt nicht, staucht das Grid ihn stillschweigend. Also
   muss der Inhalt bei wenig Hoehe kleiner werden. */
@media (max-width: 860px) and (max-height: 620px) {
  /* Die Leiste nimmt sich zurueck. Sie traegt eine 26px-Marke und eine
     34px-Pille; 54px reichen dafuer, und jede der acht Buehnen bekommt die
     Differenz als Inhalt zurueck, weil ihr Innenabstand daran haengt. */
  :root { --cf-bar-h: 54px; }

  .cf-stage--surfaces { gap: 8px; }
  .cf-surf__t { font-size: 1.4rem; }
  .cf-surf__lede { font-size: 12px; line-height: 1.45; }
  .cf-surf__grid { gap: 8px; }
  .cf-surf { gap: 6px; }
  .cf-base__layers { margin-top: 8px; padding-block: 6px; gap: 5px 12px; }

  /* Der Abschluss steht unter demselben Druck: Ueberschrift, Absatz, vier
     Schritte, Knopf und das Konfiguratorbild in einer Bildschirmhoehe. */
  .cf-close { gap: 12px; }
  .cf-close__steps { gap: 8px; }
}

/* Gestaffeltes Setzen im Rail. Ohne das liest sich seitliche Fahrt als
   Diashow statt als Schublade. Die erste Karte ist ausgenommen, weil ein
   pan act seinen Einstieg schon zeigen muss. */
@media (prefers-reduced-motion: no-preference) {
  .cf-card:not(.cf-card--lead) {
    --t: clamp(0, (var(--sc-p, 0) - var(--i) * 0.05) * 7, 1);
    opacity: calc(0.55 + 0.45 * var(--t));
    transform: translate3d(0, calc((1 - var(--t)) * 24px), 0);
  }
}

/* ====================================================== REDUCED MOTION == */

@media (prefers-reduced-motion: reduce) {
  /* Der Hinweis lädt zu etwas ein, das hier abgeschaltet ist. */
  .cf-hint { display: none; }
  /* Das Schlussbild stand fertig da, drehte und wuchs aber weiter mit dem
     Scroll: genau die Bewegung, die hier abbestellt ist. Es steht jetzt
     einfach da, und die vier Schritte stehen voll. */
  .cf-close__shot { transform: none; }
  .cf-close__shot img { transform: none; }
  /* transform: none wuerde hier das Zentrieren mitnehmen: die Marke sitzt auf
     translate(-50%,-50%) und stuende sonst mit der linken oberen Ecke in der
     Mitte des Bildes. Nur die Skalierung faellt weg. */
  .cf-close__hint { transform: translate(-50%, -50%); opacity: 1; transition: none; }
  .cf-close__steps i { transform: scaleX(1); }
  .cf-roll__w { transform: none; transition: none; }
  .cf-window--work.is-lifted { transform: none; }
  .cf-projects button[aria-current="true"] .cf-proj__name { transform: none; }
}

.sc-grain { opacity: 0.03; }


/* ==================================================== DIE OBERFLAECHEN-KLAPPE ==
   Vier Oberflaechen hinter einem Knopf oben rechts, erreichbar von jeder
   Stelle der Seite. Ein volles Seitenmenue kam fuer diese Grammatik nicht in
   Frage: ein filmic one-shot hat einen Eingang und macht seine Reihenfolge
   nicht sichtbar. Vier Ziele hinter drei Punkten tun das nicht.
   Bewegung wie ueberall: Lusions Kurve, gestaffelte Verzoegerung je Zeile. */

.cf-menu { position: relative; }
.cf-menu__btn {
  display: grid; grid-auto-flow: column; align-items: center; gap: 4px;
  width: 44px; height: 44px; padding: 0; place-content: center;
  border-radius: 50%; border: 1px solid var(--cf-line);
  background: transparent; color: inherit; cursor: pointer;
  transition: background-color 240ms var(--cf-ease), border-color 240ms var(--cf-ease);
}
.cf-menu__btn i {
  display: block; width: 4px; height: 4px; border-radius: 50%;
  background: currentColor;
  transition: transform 400ms var(--cf-ease), background-color 240ms var(--cf-ease);
}
/* Aufgeklappt rueckt der mittlere Punkt heraus und wird Terrakotta: derselbe
   Punkt, den die Pille traegt, also dieselbe Sprache. */
.cf-menu__btn[aria-expanded="true"] i:nth-child(2) { background: var(--sc-accent); transform: scale(1.6); }
.cf-menu__btn[aria-expanded="true"] i:nth-child(1),
.cf-menu__btn[aria-expanded="true"] i:nth-child(3) { transform: scale(0.72); }
.cf-bar.is-dark .cf-menu__btn { border-color: rgba(244,239,230,.34); }
/* Ohne Gate bleibt der Hover-Zustand auf Beruehrgeraeten nach dem Tippen
   stehen, bis woanders hingetippt wird. */
@media (hover: hover) and (pointer: fine) {
  .cf-menu__btn:hover { background: color-mix(in oklab, var(--sc-ink) 7%, transparent); }
  .cf-bar.is-dark .cf-menu__btn:hover { background: rgba(244,239,230,.14); }
}

.cf-menu__panel {
  position: absolute; right: 0; top: calc(100% + 10px);
  width: min(86vw, 25rem);
  display: grid; gap: 4px;
  padding: 14px; border-radius: var(--sc-r-lg);
  background: var(--cf-ivory); border: 1px solid var(--cf-line);
  box-shadow: 0 2px 8px rgba(43,33,25,.14), 0 34px 70px -28px rgba(43,33,25,.52);
  color: var(--sc-ink);
}
.cf-menu__panel[hidden] { display: none; }
.cf-menu__panel .cf-over { padding: 2px 8px 6px; }

.cf-menu__row {
  --open-delay:  calc(50ms + var(--i, 0) * 40ms);
  --close-delay: 0ms;
  display: grid; grid-template-columns: 62px 26px minmax(0, 1fr);
  gap: 2px 10px; align-items: center;
  padding: 8px; border-radius: var(--sc-r-md);
  text-decoration: none; color: inherit;
  opacity: 0; transform: translateY(10px);
  transition: opacity 360ms var(--close-delay) var(--sc-ease-out),
              transform 360ms var(--close-delay) var(--sc-ease-out),
              background-color 200ms var(--sc-ease-out);
}
.cf-menu.is-open .cf-menu__row {
  opacity: 1; transform: none;
  transition: opacity 360ms var(--open-delay) var(--sc-ease-out),
              transform 360ms var(--open-delay) var(--sc-ease-out),
              background-color 200ms var(--sc-ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .cf-menu__row:hover { background: color-mix(in oklab, var(--cf-sand) 52%, transparent); }
  .cf-menu__row:hover .cf-menu__n { color: var(--sc-accent); }
}
/* Das Vorschaubild ist nicht Zierde: es ist das Rechteck, aus dem die Ansicht
   aufwaechst. Ohne ein Rechteck im Format 16:10 muesste der FLIP in x und y
   verschieden skalieren und das Bild quetscht auf dem Weg. */
.cf-menu__thumb {
  grid-row: span 2; position: relative; display: block;
  aspect-ratio: 16 / 10; border-radius: var(--sc-r-sm); overflow: hidden;
  background: #fff; border: 1px solid var(--cf-line);
}
.cf-menu__thumb img { position: absolute; inset: 0; width: 100%; height: 100%;
                      object-fit: cover; object-position: top left; }
.cf-menu__n { font-family: var(--sc-font-mono); font-size: 9.5px; letter-spacing: 0.1em;
              color: var(--sc-ink-soft); align-self: end; }
.cf-menu__nm { font-family: var(--sc-font-display); font-size: 1.05rem; font-weight: 500;
               letter-spacing: var(--sc-track-tight); align-self: end; }
.cf-menu__tg { grid-column: 2 / -1; font-family: var(--sc-font-mono); font-size: 9px;
               letter-spacing: 0.1em; text-transform: uppercase; color: var(--sc-ink-soft); }

.cf-menu__foot {
  --open-delay: 260ms; --close-delay: 0ms;
  margin-top: 6px; padding: 11px 14px; border-radius: var(--sc-r-md);
  background: var(--sc-ink); color: var(--cf-paper);
  font-size: 12.5px; font-weight: 550; text-align: center; text-decoration: none;
  opacity: 0; transform: translateY(10px);
  transition: opacity 360ms var(--close-delay) var(--sc-ease-out),
              transform 360ms var(--close-delay) var(--sc-ease-out);
}
.cf-menu.is-open .cf-menu__foot {
  opacity: 1; transform: none;
  transition: opacity 360ms var(--open-delay) var(--sc-ease-out),
              transform 360ms var(--open-delay) var(--sc-ease-out);
}

@media (max-width: 560px) {
  .cf-menu__panel { width: min(92vw, 22rem); }
  .cf-menu__row { grid-template-columns: 50px 24px minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  .cf-menu__row, .cf-menu.is-open .cf-menu__row,
  .cf-menu__foot, .cf-menu.is-open .cf-menu__foot { transition: none; transform: none; }
  .cf-menu__btn i { transition: none; }
}
