/* ============================================================================
   Das Dashboard auf dem Laptopschirm, und die Kachel-Mockups.

   Beides ist echtes Markup, kein Videoinhalt. KI-Video rendert keine lesbare
   Oberfläche (siehe CLAUDE.md): der Clip macht nur die Kamerafahrt, der
   Bildschirm bleibt darin leer, und die Oberfläche liegt gestochen scharf
   darüber. Position und Größe rechnet app.js aus der tatsächlichen
   Videodarstellung aus, damit sie auf jedem Seitenverhältnis sitzt.
   ========================================================================== */

.sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

.screen {
  position: absolute; inset: 0;
  opacity: 0;
  pointer-events: none;
  z-index: 6;
}

/* Innen wird auf eine feste Entwurfsbreite gestaltet, die Homographie in
   app.js legt die Fläche danach auf den schrägen Schirm. Höhe und transform
   kommen von dort, hier steht nur, was ohne Rechnung gilt. */
.dash {
  /* Eigene, lokale Palette. Das Dashboard ist eine helle Produktoberfläche
     und folgt dem Theme der Seite bewusst nicht — es sieht bei Nacht aus wie
     bei Tag, weil es ein Bildschirm ist. Deshalb stehen die Rollen hier und
     nicht in tokens.css: sie gelten nur innerhalb dieser Fläche. Ab hier
     steht auch darin kein Hexwert mehr in einem Bauteil. */
  --papier:    #FDFCFA;
  --chrome:    #F2F6F7;
  --ink:       #16202B;
  --ink-soft:  #56666E;
  --rule:      #E4EAEC;
  --erledigt:  #2FA36B;
  --warte:     #E0A02A;
  --karte:     #FFFFFF;   /* Blöcke, die auf dem Papier liegen */
  --ruhig:     #C7D0D3;   /* Punkt einer Bahn, in der nichts wartet */
  --saeule:    #D7E0E2;   /* leere Stunde im Tagesstreifen */
  --marke:     #F1F5F6;   /* Schrittkennzeichnung in der Zeile */
  --wartefeld: #FDF6E7;   /* Grund einer Bahn, die auf den Menschen wartet */
  --warteton:  #9A6B10;   /* Zahl darin, dunkel genug zum Lesen */
  --seite:     #FAFCFC;   /* rechte Spalte, minimal abgesetzt */

  /* Die Leinwand des Ablaufs. Dunkler Grund mit Raster wie im Editor — die
     Knoten selbst bleiben aber hell, denn es sind dieselben Karten, aus denen
     sie entstanden sind. Sie dunkel werden zu lassen hieße, mitten im Flug
     die Schrift unlesbar zu machen. */
  /* Der Grund des Editors. Er kann nicht über das Seiten-Token laufen, denn
     die Fläche folgt dem Theme nicht — im hellen Theme wäre sie sonst weiß. */
  --leinwand:  #14181A;
  --raster:    #343A3D;
  --linie:     #667277;   /* Kante, muss auf dem dunklen Grund tragen */
  --auf-dunkel: #9AA8AD;  /* Beschriftung neben dem Knoten */
  --font-mono: ui-monospace, "Cascadia Mono", "Segoe UI Mono", monospace;

  position: absolute; top: 0; left: 0;
  width: 760px; height: 470px;
  transform-origin: 0 0;
  /* Leicht gerundet, wie ein echter Schirm im Rahmen sitzt. Der Wert steht
     im Entwurfsmaß, die Homographie verzerrt ihn mit — die Rundung wird
     dadurch von selbst perspektivisch richtig. */
  border-radius: 14px;
  /* Sobald die Fläche vom Schirm abhebt, ist sie eine Karte im Raum und
     braucht einen Schatten. Auf dem Schirm liegend darf sie keinen haben —
     deshalb kommt die Deckkraft aus app.js und nicht aus einer festen Regel.

     Drei Schattenstufen und ein Lichtsaum. Der Saum ist auf dunklem Grund das
     eigentlich tragende Element: ein schwarzer Schatten auf #14181A ist fast
     unsichtbar, waehrend ein hauchfeiner heller Rand die Karte als
     beleuchtetes Objekt liest. Beides haengt an --sa, ist also null, solange
     die Flaeche noch auf dem Schirm liegt, und waechst mit dem Abheben. */
  box-shadow:
    0 2px 6px rgb(0 0 0 / calc(var(--sa, 0) * .55)),
    0 20px 44px -14px rgb(0 0 0 / calc(var(--sa, 0) * .95)),
    0 54px 120px -34px rgb(0 0 0 / var(--sa, 0)),
    0 0 0 1px rgb(236 240 241 / calc(var(--sa, 0) * .18));
  overflow: hidden;
  background: var(--papier);
  color: var(--ink);
  font-family: var(--font-sans);
  display: flex; flex-direction: column;
}

/* Das Licht im Raum. Gemessen, nicht geschätzt: der Schirm im Video liegt
   an neun Stellen bei rgb(246 236 226), also warmes Tageslicht und kein
   kaltes Weiß. Multiplizieren legt genau dieses Licht über die ganze
   Fläche — Weiß landet auf dem gemessenen Ton, dunkle Schrift bleibt
   dunkel, und der Kontrast bleibt, wie er war. */
.dash::after {
  content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  border-radius: inherit;
  background: rgb(248 239 231);
  mix-blend-mode: multiply;
  /* Läuft mit der Dämmerung aus: sobald der Raum dunkel ist, ist der Schirm
     selbst die Lichtquelle und warmes Tageslicht darüber schlicht falsch. */
  opacity: var(--room, 1);
}

/* Und das Glas darüber: ein flacher Lichtstreifen von links oben, wo im
   Bild das Fenster steht, und eine leichte Verdunkelung zum Rand hin, wie
   sie jeder Schirm hat. Das setzt die Fläche in den Rahmen, statt sie
   davor schweben zu lassen. */
.dash::before {
  content: ""; position: absolute; inset: 0; z-index: 4; pointer-events: none;
  border-radius: inherit;
  opacity: var(--room, 1);
  background:
    linear-gradient(104deg, rgb(255 255 255 / .22) 0%, rgb(255 255 255 / .06) 26%,
                    rgb(255 255 255 / 0) 46%),
    radial-gradient(126% 104% at 48% 46%, transparent 54%, rgb(38 30 22 / .16) 100%);
}

/* ── Innenleben ───────────────────────────────────────────────────────────
   Vier Zonen: links die Bahnen, in der Mitte Kopfzahl, Tagesstreifen und die
   Vorgänge, rechts was auf dem Tisch liegt, unten die Bilanz.

   Die Zahlen der Bahnen summieren sich auf die Kopfzahl. Markiert ist genau
   dort, wo etwas auf den Menschen wartet, in derselben Farbe wie die Chips
   und die rechte Spalte. Eine Markierung ohne Bedeutung verwirrt mehr als
   gar keine.

   Alle Maße stehen im Entwurfsmaß 760 breit. Die Höhe kommt aus app.js und
   folgt dem Seitenverhältnis des Schirms, deshalb ist alles darunter als
   Flex-Spalte gebaut: der Überschuss landet im Körper, nicht in der Leiste. */

.d__bar {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 20px;
  border-bottom: 1px solid var(--rule);
  background: var(--chrome);
  font-size: 13px;
  flex: none;
}
.d__mark { display: flex; align-items: center; gap: 9px; font-weight: 600; color: var(--ink); }
.d__glyph { width: 15px; height: 15px; border-radius: 5px; background: var(--accent); display: block; flex: none; }
.d__when { color: var(--ink-soft); }
.d__live { margin-left: auto; display: flex; align-items: center; gap: 7px; color: var(--accent); font-weight: 500; }
.d__live i { width: 7px; height: 7px; border-radius: 50%; background: currentColor; display: block; }

.d__body { flex: 1; display: grid; grid-template-columns: 152px minmax(0, 1fr) 210px; min-height: 0; }

.d__rail { border-right: 1px solid var(--rule); padding: 16px 0; }
.d__railK {
  display: block;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 9.5px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--ink-soft); padding: 0 18px 9px;
}
.d__lanes { display: flex; flex-direction: column; gap: 2px; }
.d__lane {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 18px; font-size: 12.5px; color: var(--ink-soft);
}
.d__lane b { margin-left: auto; font-variant-numeric: tabular-nums; font-weight: 500; color: var(--ink); font-size: 12px; }
.d__lane i { width: 6px; height: 6px; border-radius: 50%; background: var(--ruhig); display: block; flex: none; }
.d__lane[data-wait] { color: var(--ink); font-weight: 500; background: var(--wartefeld); }
.d__lane[data-wait] i { background: var(--warte); }
.d__lane[data-wait] b { color: var(--warteton); }

.d__main { padding: 16px 18px; display: flex; flex-direction: column; min-width: 0; }

.d__headline { display: flex; align-items: flex-end; gap: 14px; }
.d__n {
  font-size: 42px; line-height: .92; font-weight: 600;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums; color: var(--ink);
}
.d__nk { font-size: 12.5px; color: var(--ink-soft); padding-bottom: 4px; line-height: 1.35; }
.d__nk b { display: block; color: var(--ink); font-weight: 600; font-size: 13px; }

/* Eine Säule je Stunde seit sechs */
.d__strip { display: flex; align-items: flex-end; gap: 3px; height: 26px; margin: 13px 0 12px; }
.d__strip i { flex: 1; background: var(--saeule); border-radius: 1.5px; display: block; }
.d__strip i[data-on] { background: var(--accent); }

.d__k {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 9.5px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--ink-soft); margin-bottom: 8px;
}

.d__queue { display: flex; flex-direction: column; gap: 6px; min-height: 0; }

/* Ein Vorgang. Eigener Block mit Rand, weil er im Zerfall zum Knoten wird. */
.d__item {
  display: flex; align-items: center; gap: 11px;
  padding: 8px 11px;
  border: 1px solid var(--rule);
  border-radius: 9px;
  background: var(--karte);
  font-size: 12.5px;
  line-height: 1.3;
  opacity: 0; transform: translateY(8px);
  transition: opacity 260ms var(--ease-out), transform 260ms var(--ease-out);
}
.d__item[data-on] { opacity: 1; transform: none; }
.d__t { font-size: 11px; color: var(--ink-soft); flex: none; font-variant-numeric: tabular-nums; }
.d__what { flex: 1; min-width: 0; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.d__step {
  flex: none; font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 9.5px; color: var(--ink-soft); background: var(--marke);
  border-radius: var(--radius-sm); padding: 2px 6px;
}
.d__chip { flex: none; display: flex; align-items: center; gap: 5px; font-size: 10.5px; font-weight: 500; color: var(--erledigt); }
.d__chip i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; display: block; }
.d__item[data-k="a"] .d__chip { color: var(--warte); }

.d__side { border-left: 1px solid var(--rule); padding: 16px; display: flex; flex-direction: column; gap: 9px; background: var(--seite); }
.d__sideK { display: flex; align-items: baseline; gap: 7px; }
.d__sideK span {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 9.5px; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-soft);
}
.d__sideK b { font-size: 15px; font-weight: 600; color: var(--warte); }

.d__ask { border: 1px solid var(--rule); border-radius: 9px; background: var(--karte); padding: 10px 11px; display: flex; flex-direction: column; gap: 8px; }
.d__askT { font-size: 12px; line-height: 1.35; color: var(--ink); }
.d__askM { font-family: var(--font-mono, ui-monospace, monospace); font-size: 10px; color: var(--ink-soft); }
.d__btns { display: flex; gap: 6px; }
.d__btn {
  font-size: 11px; font-weight: 500; padding: 5px 11px;
  border-radius: var(--radius-pill); background: var(--accent); color: var(--karte);
}
.d__btn--ghost { background: transparent; color: var(--ink-soft); box-shadow: inset 0 0 0 1px var(--rule); }

.d__foot {
  display: flex; gap: 22px; flex-wrap: wrap;
  padding: 11px 20px; border-top: 1px solid var(--rule); background: var(--chrome);
  font-size: 11.5px; color: var(--ink-soft); flex: none;
}
.d__foot b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }

/* Auf dem Telefon ist der Laptopschirm im Bild schmaler als der Text, der
   darauf stehen soll: gerechnet käme er auf rund 340 Punkte Breite, die
   Schrift läge dann bei sechs Pixeln. Also sitzt das Dashboard hier nicht
   mehr im Bild, sondern als eigene Karte davor, und die drei Spalten werden
   eine. Die Kamerafahrt läuft dahinter weiter. */
@media (max-width: 700px) {
  .screen {
    top: 50%; right: 16px; bottom: auto; left: 16px;
    height: auto; translate: 0 -50%;
    border-radius: var(--radius-lg); overflow: hidden;
    box-shadow: var(--shadow-2);
  }
  .dash { position: static; width: 100%; height: auto; transform: none; border-radius: 0; }
  .dash::before, .dash::after { content: none; }
  .d__body { grid-template-columns: 1fr; }
  .d__rail, .d__side { display: none; }
  .d__bar, .d__foot { padding: 11px 16px; }
  .d__main { padding: 14px 16px; }
  .d__n { font-size: 34px; }
  .d__step { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .d__item { opacity: 1; transform: none; }

  /* Freie Karte im Fluss statt gerechnetes Rechteck auf dem Laptopschirm. */
  .screen {
    position: relative; inset: auto; translate: none; opacity: 1;
    max-width: 860px; margin-inline: auto;
    border-radius: var(--radius-lg); overflow: hidden;
    box-shadow: var(--shadow-2);
  }
  .dash { position: static; width: 100%; height: auto; transform: none; border-radius: 0; }
  .dash::before, .dash::after { content: none; }
}

/* ═══════════════════════════════════════════ KACHEL-MOCKUPS ══════════════
   Vier kleine Oberflächen für die Akkordeon-Kacheln. Ebenfalls echtes
   Markup: bei einer Bildschirmaufnahme müsste erst aufgenommen werden, und
   generiertes Video kann keine Schrift.                                      */

/* Fuellt die Rasterzelle des Panels. `height: 100%` statt `inset: 0`, weil
   das Panel jetzt im Fluss liegt — waere die Oberflaeche absolut, zaehlte
   ihre Hoehe nicht mehr fuer die Zeilenhoehe und der Kasten fiele auf das
   blosse Seitenverhaeltnis zurueck. */
.mock {
  position: relative; height: 100%;
  background: var(--surface-default);
  padding: 26px;
  display: flex; flex-direction: column; gap: 12px;
  font-size: var(--text-sm);
}
.mock::before {
  content: attr(data-title);
  font-size: var(--text-xs); letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-subdued);
}
.mock__row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; border-radius: var(--radius-lg);
  background: var(--surface-elevated); border: 1px solid var(--border-subdued);
}
.mock__row i {
  width: 9px; height: 9px; border-radius: 50%; flex: none; background: var(--accent);
}
.mock__row span { color: var(--text-default); }
/* nowrap, weil der Kennwert sonst in sich umbricht: "+8,4 %" landete auf dem
   Telefon als "+8,4" und "%" auf zwei Zeilen. Zahl und Einheit gehoeren
   zusammen. */
.mock__row em {
  margin-left: auto; white-space: nowrap;
  font-style: normal; color: var(--text-subdued); font-size: var(--text-xs);
}
.mock__bar { height: 8px; border-radius: 999px; background: var(--background-secondary); overflow: hidden; }
.mock__bar > i { display: block; height: 100%; background: var(--accent); border-radius: 999px; }

.panel[data-active] .mock__row {
  animation: mockIn 460ms var(--ease-out) backwards;
}
.panel[data-active] .mock__row:nth-child(2) { animation-delay: 80ms; }
.panel[data-active] .mock__row:nth-child(3) { animation-delay: 180ms; }
.panel[data-active] .mock__row:nth-child(4) { animation-delay: 280ms; }
.panel[data-active] .mock__row:nth-child(5) { animation-delay: 380ms; }
@keyframes mockIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .panel[data-active] .mock__row { animation: none; }
}

/* ═══════════════════════════════════════════════ DER ZERFALL ═════════════
   Das Dashboard hört auf, ein Dashboard zu sein: das Chrom tritt ab, das
   Papier wird zur Leinwand des Editors, und die sechs Vorgangszeilen fliegen
   an ihre Stelle im Ablauf. Dort sind sie Knoten. Es sind dieselben Elemente
   — nichts wird ein- und etwas anderes ausgeblendet.

   Alles bleibt dabei im Entwurfsraum der Fläche (760 breit, Höhe aus app.js).
   Das ist der eigentliche Grund, warum der Zerfall hier drin stattfindet und
   nicht in einer eigenen Sektion: so rechnet dieselbe Homographie Zeilen und
   Knoten um. Zwei getrennte Koordinatensysteme liefen unweigerlich
   auseinander, und man sähe genau an dieser Naht, dass es zwei sind.        */

/* Die Leinwand wischt von links herein, sie blendet nicht auf. Der
   Unterschied ist nicht kosmetisch: eine Überblendung von weißem Papier auf
   dunkle Leinwand läuft zwangsläufig durch ein mattes Grau, und das steht
   eine halbe Sekunde lang im Bild. Ein Wischen hat diesen Zwischenzustand
   nicht — an jeder Stelle ist entweder das eine da oder das andere.

   --wisch läuft von 0 auf 114: bei 0 endet die deckende Zone bei -14 %,
   also außerhalb, und nichts ist zu sehen. */
.flow {
  position: absolute; inset: 0; z-index: 2;
  pointer-events: none;
  background-color: var(--leinwand);
  --wisch: 0%;
  -webkit-mask-image: linear-gradient(to right,
      #000 calc(var(--wisch) - 14%), transparent var(--wisch));
  mask-image: linear-gradient(to right,
      #000 calc(var(--wisch) - 14%), transparent var(--wisch));
}
.flow__raster {
  position: absolute; inset: 0;
  background-image:
    radial-gradient(circle at 1px 1px, var(--raster) 1.1px, transparent 1.2px);
  background-size: 22px 22px;
}

/* Der Abendraum, unscharf — dasselbe Bild, aus dem die Dämmerung im Hero
   kommt. Damit steht der Ablauf an dem Ort, in den man hineingeflogen ist,
   und nicht im Nichts. Sehr langsam, damit es atmet statt sich zu bewegen. */
.flow__grund {
  position: absolute; inset: -8%;
  background: url("assets/ambient.webp") center / cover;
  opacity: .30;
  animation: flowDrift 52s ease-in-out infinite alternate;
}
/* Zum Rand hin bleibt genau die Leinwandfarbe stehen, kein eigenes Dunkel.
   Sonst hätte der Rand einen anderen Ton als der Seitengrund, und die Naht
   am Ende der Bühne wäre wieder da. Der Raum leuchtet also nur in der Mitte
   durch, statt außen abgedunkelt zu werden. */
.flow__vignette {
  position: absolute; inset: 0;
  background: radial-gradient(120% 98% at 50% 56%,
              rgb(20 24 26 / .34) 0%, rgb(20 24 26 / .72) 44%, var(--leinwand) 80%);
}
@keyframes flowDrift {
  from { transform: translate3d(-1.6%,  .8%, 0) scale(1.04); }
  to   { transform: translate3d( 1.6%, -.8%, 0) scale(1.10); }
}

/* Kanten. Sie wachsen mit ihrem Ziel mit — gezeichnet über stroke-dashoffset,
   damit eine Linie wirklich läuft, statt bloß aufzublenden. */
.flow__kanten { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.flow__kanten path { fill: none; stroke: var(--linie); stroke-width: 1.3; stroke-linecap: round; }

/* Ein Knoten, der keine Zeile war: die drei Eingänge und die sechs Aktionen.
   Gleiche Karte wie eine Zeile, damit man sie als dieselbe Art Ding liest. */
.flow__knoten {
  position: absolute;
  border: 1px solid var(--rule);
  border-radius: 9px;
  background: var(--karte);
  display: flex; align-items: center; justify-content: center; gap: 7px;
  opacity: var(--an, 0);
}
.flow__knoten i {
  width: 9px; height: 9px; border-radius: 3px; display: block; flex: none;
  background: var(--erledigt);
}
.flow__knoten[data-wait] i { background: var(--warte); }
.flow__knoten b {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 9.5px; font-weight: 500; color: var(--ink);
  /* Kein nowrap mehr: "geprueft und weitergereicht" misst 147 Entwurfspixel,
     der Eingangskasten ist 87 breit — der Text raegte links und rechts aus
     der weissen Karte auf den dunklen Grund. min-width: 0 ist noetig, weil
     ein Flex-Element sonst nicht unter seine Mindestbreite schrumpft und
     damit gar nicht erst umbricht. Die kurzen Namen bleiben unberuehrt:
     der laengste andere ist "Buchhaltung" mit 62 Pixeln in einem 110er
     Kasten, der bricht auch ohne nowrap nicht um. */
  min-width: 0;
  text-align: center;
  line-height: 1.15;
}
/* Die Zusatzzeile steht außerhalb der Karte, auf dem dunklen Grund. */
.flow__knoten em {
  position: absolute; left: -34px; right: -34px; top: calc(100% + 5px);
  font-style: normal; text-align: center;
  font-size: 8.5px; color: var(--auf-dunkel); white-space: nowrap;
}

/* ── Die Zeile auf dem Weg zum Knoten ───────────────────────────────────── */

.dash[data-zerfall] .d__item {
  position: absolute; z-index: 4;
  margin: 0;
  overflow: hidden;              /* der Text schrumpft im Flug aus dem Kasten */
  justify-content: center;
  padding: 0 8px;
  transition: none;              /* ab hier führt der Scroll, nicht die Zeit */
  opacity: 1; transform: none;
}
/* Zeit, Beschreibung und Status verlassen die Zeile. Was bleibt, ist die
   Schrittkennzeichnung — sie stand schon vorher drin und wird zum Namen des
   Knotens. Deshalb können Zeile und Knoten gar nicht auseinanderlaufen. */
.dash[data-zerfall] .d__t,
.dash[data-zerfall] .d__what { opacity: calc(1 - var(--zeile, 0) * 3); }
.d__item[data-flug] .d__t,
.d__item[data-flug] .d__what { display: none; }
.d__item[data-flug] { gap: 7px; }
/* Der Statuspunkt bleibt und wandert nach vorn: er ist dann genau das
   Symbol, das auch die anderen Knoten tragen, und trägt weiter dieselbe
   Aussage — grün heißt allein erledigt, gelb heißt, es wartet auf Sie. */
.d__item[data-flug] .d__chip { order: -1; font-size: 0; gap: 0; }
.d__item[data-flug] .d__chip i { width: 9px; height: 9px; border-radius: 3px; }
.d__item[data-flug] .d__step {
  background: none; padding: 0; font-size: 9.5px; font-weight: 500; color: var(--ink);
}

/* Was beim Zerfall abtritt. Einzeln aufgeführt statt über den Container,
   weil die Zeilen im selben Container liegen und bleiben müssen. */
.d__bar, .d__foot, .d__rail, .d__side,
.d__headline, .d__strip, .d__k { opacity: var(--chromeAn, 1); }

@media (prefers-reduced-motion: reduce) {
  .flow__grund { animation: none; }
}

@media (max-width: 700px) {
  /* Auf dem Telefon steht die Fläche im Fluss und der Zerfall entfällt —
     eine Homographie auf 360 Pixeln Breite ergibt Knoten von 47 Pixeln. */
  .flow { display: none; }
}
