/* =========================================================================
   Traxx — App-Styles

   Die Farben, Maße und Schriften kommen aus css/tokens.css (Design-System,
   in Claude Design gebaut). Diese Datei setzt sie in Komponenten um. Der
   :root-Block direkt darunter ist eine Brücke: Er lässt die gewachsenen
   Namen dieser Datei (--bg, --ink, --accent …) auf die Traxx-Tokens
   (--c-bg, --c-text, --c-accent …) zeigen, damit nicht jede der rund
   hundert var()-Stellen umgeschrieben werden musste.

   Dunkel ist der Grundzustand (Studio, eine Hand, verschwitzt), Hell ist
   vollwertig, und ohne data-theme folgt die App der Systemeinstellung.

   FARBE STEHT FÜR ANSTRENGUNG, nicht für den Einheitstyp:
     calm  (Cyan)   vorbereiten und erholen — Aufwärmen, Mobilität,
                    Prehab, Baseline-Messung, Runterkommen
     work  (Orange) arbeiten — Kraft, Skill
     peak  (Rot)    der harte Teil — Finisher
   Den Einheitstyp kennt man beim Start; die Anstrengung muss man mitten in
   der Einheit ablesen können. [data-tone] färbt deshalb nur noch den
   kleinen Typ-Punkt im Screen-Kopf (power/combat/short/flow).
   ========================================================================= */

:root {
  /* --------------------------------------------------------------------
     Brücke auf die Traxx-Tokens. Die alten Namen bleiben, damit keine der
     rund 100 var()-Stellen im Rest dieser Datei angefasst werden muss.
     Etappe 6 der Migration löst diese Schicht wieder auf.
     -------------------------------------------------------------------- */
  --bg:          var(--c-bg);
  --surface:     var(--c-surface);
  --surface-2:   var(--c-surface-2);
  --surface-3:   var(--c-surface-3);
  --ink:         var(--c-text);
  --ink-soft:    var(--c-text-2);
  --muted:       var(--c-text-3);
  --rule:        var(--c-border);
  --edge:        var(--c-border-inset);
  --glass:       var(--c-glass);
  --glass-edge:  var(--c-border-strong);

  --accent:      var(--c-accent);
  --accent-dim:  var(--c-accent-press);
  --accent-ink:  var(--c-on-accent);
  --accent-bg:   var(--c-accent-soft);

  /* Einheitstyp-Klima. Noch färbt es die ganze Ansicht; Task 5 schrumpft
     seine Reichweite auf den Typ-Punkt im Kopf. */
  --tone-power:  var(--c-accent);
  --tone-combat: var(--c-warn);
  --tone-short:  var(--c-calm);
  --tone-flow:   var(--c-ok);

  --goal:        var(--c-warn);
  --goal-bg:     var(--c-warn-soft);
  --ok:          var(--c-ok);
  --ok-bg:       var(--c-ok-soft);

  /* --f-display, --f-body und --f-data kommen aus tokens.css und sind dort
     eine Erweiterung derselben Systemstacks — hier bewusst nicht gesetzt. */

  /* --nav-h kommt jetzt aus tokens.css (66px). Die frühere Überschreibung auf
     64px ist mit Traxx Bold entfallen — das Redesign will mehr Luft, und die
     Nav-Pille verträgt die zwei Pixel. */
  --nav-gap:  14px;
  --pad:      var(--gutter);
  --radius:   var(--r-l);
  --radius-s: var(--r-s);

  /* --------------------------------------------------------------------
     Bewegungssprache — genau zwei Federcharaktere (Leitbild §5).

       Arbeit  kritisch gedämpft, KEIN Nachschwingen. Alles Alltägliche:
               Tippen, Öffnen, Wechseln. Gewichte wackeln nicht.
       Erfolg  genau EIN Überschwinger. Nur wenn etwas geschafft ist:
               Durchstrich-Stempel, Einheit fertig.

     Eine dritte Feder gibt es nicht. Der gewachsene Name --spring zeigt
     deshalb auf „Arbeit" — damit werden die rund 15 Altstellen in dieser
     Datei mit einer Zeile ruhiggestellt, statt sie einzeln zu ändern.
     Dauern kommen ausschließlich aus --d-fast / --d-base / --d-slow.
     -------------------------------------------------------------------- */
  --e-arbeit: cubic-bezier(.22, .72, .3, 1);   /* @kind other */
  --e-erfolg: cubic-bezier(.2, 1.5, .4, 1);    /* @kind other */
  --spring:   var(--e-arbeit);
  --ease-out: var(--e-out);

  /* Der Durchstrich hat eine eigene Dauer, weil er zweimal vorkommt:
     einmal für die Satzzeile, einmal schwerer für die ganze Übung. */
  --d-strich:        200ms; /* @kind other */
  --d-strich-schwer: 240ms; /* @kind other */

  /* --------------------------------------------------------------------
     Tonfarbe. --tone ist die eine Variable, die Durchstrich und
     Vorgangsleiste einfärbt; --on-tone ist der garantiert kontrastreiche
     Text darauf. Grundwert ist die Marke; [data-tone] setzt den
     Einheitstyp, die Anstrengungsklassen (.is-calm/.is-work/.is-peak)
     setzen ihn innerhalb eines Blocks noch einmal um.
     -------------------------------------------------------------------- */
  --tone:    var(--c-accent);
  --on-tone: var(--c-on-accent);

  /* Zwei fehlende Kontrastpartner. tokens.css liefert --c-on-accent und
     --c-on-calm, aber nichts für Warn und Ok — die tragen als combat und
     flow ebenfalls Tonflächen. */
  --c-on-warn: #1C1200;
  --c-on-ok:   #05210F;

  /* Höhe der Vorgangsleiste. Steht hier, weil #view seinen unteren
     Freiraum daraus rechnet. */
  --vorgang-h: 64px;

  /* Ruhewerte der drei Größen, die js/ui.js zur Laufzeit setzt: Restanteil
     der Countdown-Füllung, Mittelpunkt der Halten-Füllung, Haltedauer. */
  --anteil: 1;         /* @kind other */
  --hx: 50%;
  --halte-dauer: 400ms; /* @kind other */
}

/* --------------------------------------------------------------------
   Kontrastkorrektur an der dritten Textstufe.

   --c-text-3 aus dem Design-System misst auf Graphit 4,36:1 und auf
   --c-surface 3,99:1 — beides unter der Pflichtgrenze von 4,5:1. Die
   Stufe trägt in dieser App aber echte Information (Dosierungen,
   Datumszeilen, ausgeschaltete Übungen), keine Dekoration. Zwei
   Helligkeitsstufen mehr, und sie hält überall 4,5:1.
   Gehört bei nächster Gelegenheit ins Design-System zurückgespielt.
   -------------------------------------------------------------------- */
:root,
[data-theme="dark"] { --c-text-3: #7C8492; }

[data-theme="light"] {
  --c-text-3:   #5F6672;
  --c-on-warn:  #FFFFFF;
  --c-on-ok:    #FFFFFF;
  /* Gold auf Weiß bleibt sonst bei 4,49:1 hängen */
  --tone-combat: #8A5D02;
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --c-text-3:   #5F6672;
    --c-on-warn:  #FFFFFF;
    --c-on-ok:    #FFFFFF;
    --tone-combat: #8A5D02;
  }
}

/* Sattere Akzente auf modernen Displays. Der Block spiegelt die Theme-Struktur
   von tokens.css: Im Light sind calm und peak bewusst dunkler gewählt, damit
   sie auf hellem Grund 4,5:1 halten — ein pauschales :root würde das brechen. */
@supports (color: color(display-p3 1 0 0)) {
  :root,
  [data-theme="dark"] {
    --c-accent: color(display-p3 1 0.36 0.10);    /* #FF5C1A */
    --c-calm:   color(display-p3 0.21 0.82 0.90); /* #35D2E6 */
    --c-peak:   color(display-p3 1 0.23 0.23);    /* #FF3B3B */
  }
  [data-theme="light"] {
    --c-accent: color(display-p3 1 0.36 0.10);    /* #FF5C1A, unverändert */
    --c-calm:   color(display-p3 0.05 0.48 0.58); /* #0E7A93 */
    --c-peak:   color(display-p3 0.84 0.16 0.16); /* #D62828 */
  }
  /* Light über die Systemeinstellung — ohne diesen Zweig bekäme ausgerechnet
     der Standardfall die zu hellen Dark-Werte. */
  @media (prefers-color-scheme: light) {
    :root:not([data-theme]) {
      --c-accent: color(display-p3 1 0.36 0.10);
      --c-calm:   color(display-p3 0.05 0.48 0.58);
      --c-peak:   color(display-p3 0.84 0.16 0.16);
    }
  }
}

/* Das Light-Theme kommt vollständig aus tokens.css. Die Brücke oben zeigt auf
   --c-*, und die wechseln dort je Theme — es muss hier nichts wiederholt werden. */

/* --------------------------------------------------------------------
   Einheitstyp — nur noch der Punkt im Kopf.

   Bis hierher übersteuerte [data-tone] die Variable --accent und färbte
   damit jede Ansicht komplett um. Diese Rolle hat jetzt die Anstrengung
   (siehe unten): Den Typ kennt man beim Start, die Anstrengung muss man
   mitten in der Einheit ablesen können.

   Was [data-tone] weiterhin setzt, ist --tone: die Farbe, in der die
   Signatur der App schreibt — der Durchstrich und die Vorgangsleiste.
   -------------------------------------------------------------------- */
[data-tone="power"]  { --tone: var(--tone-power);  --on-tone: var(--c-on-accent); }
[data-tone="combat"] { --tone: var(--tone-combat); --on-tone: var(--c-on-warn); }
[data-tone="short"]  { --tone: var(--tone-short);  --on-tone: var(--c-on-calm); }
[data-tone="flow"]   { --tone: var(--tone-flow);   --on-tone: var(--c-on-ok); }

/* Der Punkt vor dem Eyebrow ist ganz weg — nicht nur entfärbt.
   Ein Kritiker hatte pixelweise nachgemessen: „Es ist dieselbe Komponente,
   einmal Amber, einmal Cyan, 400 px auseinander, ohne Legende. Das ist keine
   Kodierung, das ist Zufall, der wie Kodierung aussieht." Behoben war das nur
   halb: Der Typ-Punkt verlor seine Farbe, blieb aber stehen — und damit
   standen in Heute ein grauer und ein cyanfarbener 8-px-Punkt an derselben
   linken Kante, der eine bedeutete Anstrengung, der andere nichts.
   Leitbild §4 beantwortet das selbst: „Lautet die Antwort ‚keinen', ist sie
   Text." Der farbige 8-px-Punkt (.ak-punkt / .tr-punkt) bedeutet in der
   ganzen App genau eine Sache — Anstrengung. Den Einheitstyp tragen das
   Motiv und die Vorgangsleiste; er braucht keinen zweiten Marker. */

/* --------------------------------------------------------------------
   Anstrengung. Die Zuordnung folgt den block.key aus planner.js:
     calm  warmup, mobility, cooldown, prehab, baseline (Messung)
     work  strength, skill
     peak  finisher
   -------------------------------------------------------------------- */
.is-calm {
  --effort: var(--c-calm);
  --effort-row: var(--g-row-calm);
  --effort-dot: var(--g-dot-calm);
  --tone: var(--c-calm);
  --on-tone: var(--c-on-calm);
}
.is-work {
  --effort: var(--c-accent);
  --effort-row: var(--g-row-accent);
  --effort-dot: var(--g-dot-accent);
  --tone: var(--c-accent);
  --on-tone: var(--c-on-accent);
}
.is-peak {
  --effort: var(--c-peak);
  --effort-row: var(--g-row-peak);
  --effort-dot: var(--g-dot-peak);
  --tone: var(--c-peak);
  --on-tone: var(--c-on-peak);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body { height: 100%; }

body {
  margin: 0;
  /* Traxx Bold: Tiefe entsteht über Verläufe statt über Schatten. */
  background: var(--g-page);
  background-attachment: fixed;
  color: var(--ink);
  font-family: var(--f-body);
  font-size: var(--t-body-size);
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: contain;
}

::selection { background: var(--accent); color: var(--accent-ink); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }

/* =============================================================== Struktur */

#view {
  padding: 0 var(--pad)
           calc(env(safe-area-inset-bottom) + var(--nav-h) + var(--nav-gap) + 46px);
  max-width: 640px;
  margin: 0 auto;
  /* Die überstehende Plan-Ziffer darf hinausragen, aber die Seite nicht
     seitlich verschiebbar machen — am Telefon waren das 70 px Wackeln.
     clip statt hidden: hidden erzeugte einen Scroll-Container und damit
     bliebe die sticky Topbar beim Scrollen nicht mehr stehen. */
  overflow-x: clip;
}

/* Ist eine Vorgangsleiste eingehängt, braucht der Inhalt darunter Platz:
   Nav + Leiste + Luft. Die Klasse setzt zeigeVorgang() in js/ui.js. */
body.hat-vorgang #view {
  padding-bottom: calc(env(safe-area-inset-bottom) + var(--nav-h)
                       + var(--nav-gap) + var(--vorgang-h) + 34px);
}

/* Ein Verlauf unter Leiste und Nav, damit scrollender Inhalt ausblendet
   statt hart abgeschnitten zu wirken.

   Zwei Kritiker haben unabhängig dasselbe gesehen: „Der gelbe CTA liegt
   undurchsichtig über der Listenzeile ‚Hampelmänner' und schneidet das Wort
   horizontal in zwei Hälften — ohne Verlaufsabdeckung, ohne Abstand, das
   liest sich wie ein Bug, nicht wie ein Sticky-Element."

   Das Padding unten löst es nur am Seitenende; mitten im Scrollen bleibt die
   Kante. Der Verlauf nimmt ihr die Härte, ohne etwas zu verdecken, was man
   nicht ohnehin gleich wegscrollt. */
body::after {
  content: "";
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: calc(env(safe-area-inset-bottom) + var(--nav-h) + var(--nav-gap) + 24px);
  z-index: 38;
  pointer-events: none;
  background: linear-gradient(to top, var(--c-bg) 34%, transparent);
}
body.hat-vorgang::after {
  height: calc(env(safe-area-inset-bottom) + var(--nav-h) + var(--nav-gap)
               + var(--vorgang-h) + 34px);
}

/* Ansichtswechsel: 180 ms Crossfade, 8 px Versatz nach oben. Seiten werden
   gesetzt, nicht geschoben — geschoben wird in dieser App genau eine Sache,
   und das ist der Eintritt in einen Vorgang (siehe @keyframes von-unten).
   Keine Staffelung mehr: sie hat den Wechsel auf 740 ms gedehnt. */
@keyframes rise-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
#view > * { animation: rise-in var(--d-base) var(--e-arbeit) backwards; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  -webkit-backdrop-filter: blur(22px) saturate(1.5);
  backdrop-filter: blur(22px) saturate(1.5);
  padding: calc(env(safe-area-inset-top) + 16px) var(--pad) 12px;
  margin: 0 calc(var(--pad) * -1) 22px;
  -webkit-mask-image: linear-gradient(to bottom, #000 82%, transparent);
  mask-image: linear-gradient(to bottom, #000 82%, transparent);
}
.topbar-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  max-width: 640px;
  margin: 0 auto;
}
/* Was rechts in der Topbar sitzt, bestimmt ihre Höhe NICHT mit.
   Der Abschluss-Knopf der Trainingsansicht ist 42 px hoch und trägt nur ein
   Icon — er hat keine Textgrundlinie in seiner Mitte. An der Grundlinie
   ausgerichtet schob er die ganze Zeile 20 px nach unten: Die Topbar war im
   Training 107,5 px hoch, in Heute und Abschluss 87,5 px, und beim Eintritt
   in die Einheit sprang der komplette Screen. Gemessen, nicht geschätzt. */
.topbar-row > * + * { align-self: center; }
.topbar h1 {
  font-family: var(--f-display);
  font-size: var(--t-title-size);
  font-weight: 800;
  letter-spacing: -0.025em;
  margin: 0;
}
/* Die Unterzeile der Topbar ist Kontext (Datum, Einheitstitel), nicht Marke.
   In Orange war sie die vierte Akzentfarbe auf dem Screen und stritt mit der
   Tonfarbe der Einheit — ein Kritiker las das als Fehler, nicht als
   Unterscheidung. Nur die Tonfarbe darf hier führen (Leitbild §4).

   Schrift, Größe, Sperrung und Versalien kommen aus der gemeinsamen
   Eyebrow-Regel weiter unten: Die Unterzeile IST ein Eyebrow, und sie lief
   mit 0.14em, während jeder andere 0.20em trug — zwei Sperrungen für eine
   Rolle, in Heute sogar 100 px übereinander im selben Bild. */
.topbar .sub {
  color: var(--c-text-2);
  margin: 0 0 4px;
}

/* ============================================== Nav — schwebende Glas-Pille */

.nav {
  position: fixed;
  bottom: calc(env(safe-area-inset-bottom) + var(--nav-gap));
  left: 50%;
  transform: translateX(-50%);
  z-index: 40;
  width: min(calc(100% - 28px), 400px);
  height: var(--nav-h);
  border-radius: 999px;
  background: var(--glass);
  -webkit-backdrop-filter: blur(28px) saturate(1.7);
  backdrop-filter: blur(28px) saturate(1.7);
  border: 1px solid var(--glass-edge);
  display: flex;
  padding: 5px;
}
.nav a {
  flex: 1;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  text-decoration: none;
  color: var(--muted);
  font-family: var(--f-body);
  font-size: var(--t-eyebrow-size);
  font-weight: 600;
  letter-spacing: 0.01em;
  border-radius: 999px;
  transition: color 0.2s;
}
/* Sharp-Solid statt Linienzeichnung: dieselbe Familie wie js/icons.js.
   Massive Flächen sind bei Blendung und Bewegung besser zu treffen als
   1,8-px-Konturen — und der Satz ist damit in der ganzen App derselbe. */
.nav a svg {
  width: 21px; height: 21px;
  fill: currentColor; stroke: none;
  transition: transform var(--d-base) var(--e-arbeit);
}
.nav a.on { color: var(--ink); }
.nav a.on svg { fill: var(--accent); transform: translateY(-1px); }
.nav a::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: transparent;
  transition: background 0.25s var(--ease-out);
}
.nav a.on::before { background: rgba(255, 255, 255, 0.09); }
:root[data-theme="light"] .nav a.on::before { background: rgba(20, 18, 26, 0.07); }
.nav a > * { position: relative; }

/* Fokus-Modus (setzt der Router auf #/session und #/finish): Während des
   Vorgangs verschwindet die Tab-Pille — im Training zählt, was als Nächstes
   kommt, nicht, wohin man sonst noch könnte. Die Leiste rückt dorthin, wo
   sonst die Nav sitzt, Padding und Ausblend-Verlauf rechnen ohne Nav-Höhe —
   dasselbe Muster wie im Onboarding (body[data-wizard]). */
body[data-fokus] .nav { display: none; }
body[data-fokus] .vorgang { bottom: calc(env(safe-area-inset-bottom) + var(--nav-gap)); }
body[data-fokus].hat-vorgang #view {
  padding-bottom: calc(env(safe-area-inset-bottom) + var(--nav-gap) + var(--vorgang-h) + 30px);
}
body[data-fokus].hat-vorgang::after {
  height: calc(env(safe-area-inset-bottom) + var(--nav-gap) + var(--vorgang-h) + 24px);
}
/* Im Training gibt es jetzt Zustände ganz ohne Bodenelement: keine Nav
   (Fokus-Modus) und keine Leiste (kein Vorgang — die Liste führt). Ohne
   diese Regel rechnen Padding und Ausblend-Verlauf weiter mit einer
   Nav-Höhe, die niemand einnimmt: rund 100 px Luft unter der letzten Zeile
   und ein Verlauf, der Zeilen ausblendet, hinter denen nichts liegt. */
body[data-fokus]:not(.hat-vorgang) #view {
  padding-bottom: calc(env(safe-area-inset-bottom) + var(--nav-gap) + 40px);
}
body[data-fokus]:not(.hat-vorgang)::after {
  height: calc(env(safe-area-inset-bottom) + var(--nav-gap) + 20px);
}

/* ============================================================== Bausteine */

/* Nach Traxx (.tx-card): flach, größerer Radius, kein Innenglanz. Die
   getönten Varianten laufen dort über einen radialen Verlauf aus der
   oberen rechten Ecke statt über eine durchgefärbte Fläche. */
.card {
  background: var(--g-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-xl);
  padding: var(--s-7);
  margin-bottom: 14px;
}
/* .card.flush und .card.accent sind mit der Rückschau und dem Katalog weggefallen —
   kein Vorkommen mehr in js/ oder index.html. .card.goal lebt im Abschluss weiter. */
.card.goal {
  background:
    radial-gradient(120% 140% at 100% 0%, var(--c-warn-soft) 0%, transparent 62%),
    var(--c-surface);
  border-color: var(--c-warn);
}

h2.section {
  font-family: var(--f-display);
  font-size: var(--t-heading-size);
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 32px 0 12px;
}
h2.section:first-child { margin-top: 0; }

/* Erste Zeile der Dreiergruppe (Leitbild §3): 11 px, 0,20em gesperrt,
   zurückgenommen. Der Eyebrow nennt den Kontext — laut ist darunter die
   Heldenzahl. Wer ihn doch farbig braucht, nimmt einen der Modifier.

   EINE Sperrung für die ganze Rolle. Vorher liefen neun Stellen mit
   sieben verschiedenen Werten (eine davon, .stat .k, ist mit den
   Bento-Kacheln der Rückschau weggefallen) (0.12 / 0.13 / 0.14 / 0.16 / 0.20em) — alle
   11 px, Mono, Versalien, alle dieselbe Sache. Wer eine neue Beschriftung
   setzt, hängt sie hier an, statt die vier Zeilen zu kopieren.
   Rand und Farbe bleiben bei den Einzelregeln: Die Farbe trennt Kontext
   (--c-text-2) von Formularbeschriftung (--c-text-3). */
.eyebrow,
.topbar .sub,
.feedback-label,
.tm-label,
.tr-gruppe,
.form-row label,
.sheet-section,
.howto-label {
  font-family: var(--f-data);
  font-size: var(--t-eyebrow-size);
  letter-spacing: var(--t-eyebrow-ls);
  text-transform: uppercase;
}
.eyebrow {
  line-height: var(--t-eyebrow-lh);
  color: var(--c-text-2);
  margin: 0 0 7px;
}
.eyebrow.goal { color: var(--goal); }
.eyebrow.muted { color: var(--muted); }
.eyebrow.ton { color: var(--tone); }
.eyebrow.akzent { color: var(--accent); }

p.lede { color: var(--ink-soft); font-size: var(--t-body-size); margin: 0 0 14px; }
p.hint { color: var(--muted); font-size: var(--t-bodys-size); margin: 8px 0 0; }
.empty { color: var(--muted); font-size: var(--t-body-size); padding: 36px 0; text-align: center; }

.data { font-family: var(--f-data); font-variant-numeric: tabular-nums; }

/* ================================================================ Buttons */

/* Nach Traxx (.tx-btn). Bewusst --f-body statt --f-display: Ein Button ist
   Bedienelement, keine Überschrift. Und bewusst Traxx' knappes Timing statt
   --spring — das federnde Easing bleibt den Flächen und Sheets vorbehalten,
   beim Tippen auf einen Knopf will man Quittung, kein Nachwippen. */
.btn {
  font-family: var(--f-body);
  font-size: var(--t-body-size);
  font-weight: 650;
  letter-spacing: -0.008em;
  padding: 0 var(--s-7);
  min-height: 52px;
  border: 1px solid transparent;
  background: var(--g-accent);
  color: var(--accent-ink);
  border-radius: var(--r-m);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-4);
  white-space: nowrap;
  text-decoration: none;
  transition: background var(--d-fast) var(--e-out),
              border-color var(--d-fast) var(--e-out),
              transform var(--d-fast) var(--e-out),
              opacity var(--d-fast) var(--e-out);
  box-shadow: var(--sh-cta);
}
.btn:hover { background: var(--c-accent-hover); }
.btn:active { transform: translateY(1px) scale(0.994); }
.btn svg { width: 20px; height: 20px; flex: none; }
/* Die 32 px darunter kamen bis zuletzt aus `.block { margin-bottom: 32px }` —
   einer Regel für den Session-Block der Fassung vor Traxx. Den Block gibt es
   nicht mehr, den Rand schon: Er stand unter jedem Vollbreiten-Knopf der App.
   Jetzt steht er dort, wo er wirkt. */
.btn.block { display: flex; width: 100%; margin-bottom: 32px; }

/* Die getönte Akzentfläche ist ein Zug dieser App, den Traxx so nicht führt.
   Statt sie aufzugeben, liegt sie jetzt auf den dafür gedachten Tokens. */
.btn.ghost {
  background: var(--c-accent-soft);
  border-color: var(--c-accent-soft-b);
  color: var(--c-accent-text);
  box-shadow: none;
}
.btn.ghost:hover { background: var(--c-accent-soft); border-color: var(--c-accent); }

/* entspricht tx-btn--secondary */
.btn.quiet {
  background: var(--c-surface-2);
  border-color: var(--c-border);
  color: var(--c-text);
  font-size: var(--t-body-size);
  font-weight: 600;
  min-height: 48px;
  padding: 0 var(--s-6);
  box-shadow: none;
}
.btn.quiet:hover { background: var(--c-surface-3); }

.btn.small { font-size: var(--t-bodys-size); padding: 0 var(--s-5); min-height: 42px; border-radius: var(--r-s); }
.btn:disabled { opacity: 0.42; cursor: not-allowed; transform: none; }
.btn:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }
.btn-row { display: flex; gap: 10px; flex-wrap: wrap; }
.btn-row .btn { flex: 1; }

/* ============================================================ Heute-Screen */

/* Ohne oberen Rand: Der Abstand zur Topbar kommt aus deren margin-bottom und
   ist damit in allen vier Ansichten gleich. Die 6 px, die hier standen,
   ließen den Kopf der Heute-Ansicht als einzigen 28 statt 22 px tief
   beginnen — bei sonst identischem Aufbau. */
.plan-head {
  position: relative;
  padding: 0 0 22px;
  margin-bottom: 22px;
  overflow: visible;
}
/* Aurora: das Farbklima der Einheit strahlt weich in die Fläche */
.plan-head::before {
  content: "";
  position: absolute;
  top: -50px;
  right: -90px;
  width: 300px;
  height: 300px;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 26%, transparent) 0%, transparent 62%);
  pointer-events: none;
}

/* Das Motiv des Einheitstyps — der visuelle Anker (Leitbild §3).
   Es liegt hinter Titel und Nummer, rechtsbündig: Die Illustrationen halten
   ihre linke Hälfte frei, dort steht die Schlagzeile. Der weiche Verlauf nach
   links blendet die Bildkante aus, damit kein Rahmen entsteht — das Band soll
   aus dem Hintergrund auftauchen, nicht wie ein eingeklebtes Foto wirken. */
/* „Die Kickbox-Silhouette ist ein dunkelgrauer Fleck auf Schwarz" — der
   Kritiker hatte recht: Bei 82 % Deckkraft auf 78 % Breite verschwand das
   Motiv hinter der Ziffer, statt der Anker zu sein, für den es gedacht war.
   Jetzt größer, voll deckend und weiter oben, damit es die Schlagzeile
   hinterfängt statt mit ihr um dieselbe Zeile zu streiten. */
/* Das Motiv gibt es zweimal — für Dunkel und für Hell.
   Im Hellmodus stand das dunkle Band als schwarzer Kasten über dem Titel:
   Die Maske blendet nur nach links aus, der Rest blieb ein harter Block.
   Ein CSS-Filter half nicht, weil die Figur selbst dunkelgrau ist — jede
   Aufhellung, die den Grund verschwinden lässt, frisst sie mit.

   Als Hintergrundbild statt <img>, damit die Kaskade entscheidet: Der Browser
   lädt nur die Datei, die er wirklich zeigt, und ein fehlendes Bild macht
   keinen Lärm (bei <img> hätte es ein kaputtes Symbol gegeben). Die beiden
   URLs kommen als Variablen aus typMotiv() in js/ui.js. */
/* Standardwert, damit die Regel auch ohne typMotiv() hält: Ohne die beiden
   Variablen wäre background-image ungültig, und der Check „keine offene
   Referenz" schlüge zu Recht an — die Werte kommen sonst nur aus dem
   style-Attribut, das js/ui.js setzt. */
:root { --motiv: none; --motiv-hell: none; }

.typ-motiv {
  position: absolute;
  top: -34px;
  right: calc(var(--gutter) * -1);
  width: 92%;
  max-width: 400px;
  aspect-ratio: 16 / 9;
  background-image: var(--motiv);
  background-size: contain;
  background-position: right center;
  background-repeat: no-repeat;
  pointer-events: none;
  user-select: none;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 38%, #000 100%);
  mask-image: linear-gradient(to right, transparent 0%, #000 38%, #000 100%);
}
:root[data-theme="light"] .typ-motiv { background-image: var(--motiv-hell); }
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) .typ-motiv { background-image: var(--motiv-hell); }
}
/* Wo das Motiv liegt, wäre die Aurora doppelt gemoppelt */
.plan-head:has(.typ-motiv)::before { opacity: .35; }

/* Und die dekorative Ziffer erst recht: Sie war der Ersatz für einen
   visuellen Anker, den es jetzt gibt. Beide übereinander kreuzen sich nur —
   „Einheit 2" steht ohnehin im Eyebrow darüber. Eine Sache pro Screen. */
.plan-head:has(.typ-motiv) .plate-num { display: none; }
/* Der Abstand zwischen Eyebrow und Held ist in allen drei Köpfen derselbe.
   Er stand vorher dreimal verschieden da: 12 px in Heute, 12 px im Abschluss,
   7 px (der Grundwert) im Training — dieselbe Dreiergruppe, drei Abstände. */
.plan-head .eyebrow,
.tr-kopf .eyebrow,
.ab-kopf .eyebrow { margin-bottom: 12px; }
.plan-head .eyebrow { position: relative; }
.plan-head h2 {
  font-family: var(--f-display);
  font-size: clamp(36px, 10.5vw, 50px);
  line-height: 1.02;
  font-weight: 800;
  letter-spacing: -0.035em;
  margin: 0 0 12px;
  max-width: 82%;
  text-wrap: balance;
  position: relative;
}
.plan-head .lede { max-width: 90%; position: relative; }

/* Die Einheitsnummer als Ghost-Ziffer — nur Kontur, wie graviert */
/* Die Plan-Nummer.
   Ein Kritiker fand sie zweimal: Sie „schneidet in die Unterlängen von
   Kondition", und ihr freistehender unterer Balken „wirkt wie ein
   Rendering-Rest". Beides kam davon, dass sie so groß war, dass ihre Teile
   einzeln neben dem Titel auftauchten. Jetzt sitzt sie höher, ist kleiner
   als der Titel und läuft deutlich schwächer — sie ist Hintergrund, nicht
   zweite Schlagzeile. */
.plate-num {
  position: absolute;
  top: -30px;
  right: -6px;
  font-family: var(--f-display);
  font-size: clamp(84px, 25vw, 124px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.04em;
  color: transparent;
  -webkit-text-stroke: 1.5px color-mix(in srgb, var(--tone, var(--accent)) 32%, transparent);
  user-select: none;
  -webkit-user-select: none;
  pointer-events: none;
}
@supports not (-webkit-text-stroke: 1px black) {
  .plate-num { color: var(--accent); opacity: 0.14; }
}

/* Hier standen bis zur Glättung von Welle 2/3 die Badge-Zeile .plan-facts
   (samt .goal-fact) und die Blockvorschau .block-preview (.mins/.bt/.bx).
   Beide gehörten dem alten Onboarding; seit dem Umbau der Randansichten
   zeigt der Assistent den Kopf und den Ablauf der Heute-Ansicht selbst
   (.plan-head, .ob-blockkopf, .ob-blockliste). Kein Vorkommen mehr in js/,
   index.html oder den Werkzeugen — gelöscht.

   Der Ablauf der Heute-Ansicht lag hier zweimal: einmal als .plan-edit /
   .plan-block / .plan-row / .pr-* aus der Fassung vor dem Redesign und einmal
   als .ablauf-* weiter unten. Die alte Fassung stand nur noch im Weg — .pr-name
   war dabei doppelt belegt (hier und bei den Bestleistungen im Fortschritt),
   wer die eine anfasste, änderte die andere mit. Gelöscht. */

/* --------------------------------------------- Änderungs-Sheet einer Übung */

.sheet-section {
  color: var(--muted);
  font-weight: 500;
  margin: 20px 0 8px;
}

/* Begründung des Generators — offengelegte Regeln, keine Werbetexte */
.why-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.why-list li {
  position: relative;
  padding-left: 16px;
  font-size: var(--t-bodys-size);
  line-height: 1.45;
  color: var(--ink-soft);
}
/* Der Aufzählungspunkt ist ein Aufzählungspunkt, kein Zustand. In Akzent
   war er der dritte runde farbige Punkt der App neben dem 8-px-Punkt, der
   die Anstrengung kodiert — „zwei gleiche Punkte dürfen nicht zwei Dinge
   bedeuten" (Leitbild „Farbe und Zustand"). Dieselbe Korrektur wie beim
   .type-dot in Welle 1: Wer keinen Zustand kodiert, ist Text. */
.why-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--c-text-3);
}

/* Die Alternativen des Tausch-Sheets. Sie standen in zwei Regelsätzen: hier
   die Grundform und weiter unten .alt-list .alt mit dem Raster. Der Umweg
   über .alt-list war nötig, solange .alt DOPPELT belegt war — im Onboarding
   trug sie der Textlink „Ich habe schon ein Konto", und ein Alleingang auf
   .alt verpasste ihm 60 px Mindesthöhe. Der Assistent heißt inzwischen
   .ob-alt; .alt gehört wieder allein dem Sheet, also steht sie wieder an
   einer Stelle. */
.alt-list { display: flex; flex-direction: column; gap: 6px; }
.alt {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0 var(--s-5);
  width: 100%;
  min-height: 60px;
  padding: 10px 14px;
  background: var(--surface-2);
  border: 1px solid var(--edge);
  border-radius: var(--r-m);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: transform 0.18s var(--spring), border-color 0.18s var(--ease-out);
}
.alt:hover { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.alt:active { transform: scale(0.97); }
.alt:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.alt-name { display: block; grid-column: 1; font-size: var(--t-body-size); font-weight: 500; }
/* Eine Stufe heller als der Grundwert: --c-text-3 misst auf --c-surface-2
   gerendert 4,33:1 und reißt damit die Pflichtgrenze. Auf derselben Fläche
   hält --c-text-2 7,0:1. */
.alt-meta {
  display: block;
  grid-column: 1;
  font-size: var(--t-caption-size);
  color: var(--c-text-2);
  margin-top: 2px;
}
.alt-zeichen {
  grid-column: 2;
  grid-row: 1 / span 2;
  display: inline-flex;
  font-size: 15px;
  color: var(--c-text-2);
}
.alt:hover .alt-zeichen { color: var(--c-accent-text); }

/* ================================== Reste der Session-Fassung vor Traxx

   Was die Trainingsansicht heute baut, steht unter „Training" weiter unten
   (.tr-*, .dotzeile, .durchstrich). Aus der alten Fassung sind nur noch die
   Teile übrig, die der KORREKTURMODUS im Verlauf weiterbenutzt: die
   Übungskarte (.ex-head/.ex-dose/.ex-body), die Satzliste (.sets/.set-row)
   und ihre beiden Knöpfe. Alles andere — .progress-*, section.block,
   .block-title, .block-note, .group-label, .ex, .check — ist gelöscht.

   .block { margin-bottom: 32px } stand ebenfalls hier und traf zuletzt nur
   noch .btn.block: Jeder Vollbreiten-Knopf der App trug einen Rand aus einer
   Regel für ein ganz anderes Bauteil. Die Regel steht jetzt bei den Buttons,
   gerendert ändert sich nichts.
   ==================================================================== */

.ex {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: inset 0 1px 0 var(--edge);
  margin-bottom: 10px;
  overflow: hidden;
  transition: border-color 0.25s, background-color 0.25s;
}
.ex.done { border-color: color-mix(in srgb, var(--ok) 40%, transparent); background: var(--ok-bg); }
.ex.open-detail { border-color: color-mix(in srgb, var(--accent) 50%, transparent); }

.ex-head {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 15px 16px;
  cursor: pointer;
}
.ex-name {
  font-family: var(--f-display);
  font-size: var(--t-heading-size);
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.18;
}
.ex.done .ex-name { color: var(--ink-soft); }
.ex-dose {
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  color: var(--accent);
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
.ex.done .ex-dose { color: var(--ok); }

/* Quittung des Satz-Häkchens im Korrekturmodus */
@keyframes pop {
  0% { transform: scale(0.8); }
  55% { transform: scale(1.16); }
  100% { transform: scale(1); }
}

.ex-body {
  padding: 0 16px 16px;
  border-top: 1px solid var(--rule);
  padding-top: 14px;
}

.sets { display: flex; flex-direction: column; gap: 8px; }
.set-row {
  display: grid;
  grid-template-columns: 28px 1fr 1fr 40px;
  gap: 8px;
  align-items: center;
}
.set-row .n {
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  color: var(--muted);
}
.field {
  display: flex;
  align-items: center;
  gap: 5px;
  background: var(--surface-2);
  border: 1px solid transparent;
  border-radius: 12px;
  padding: 0 11px;
  height: 48px;
  transition: border-color 0.2s, background-color 0.2s;
}
.field input {
  width: 100%;
  min-width: 0;
  border: none;
  background: transparent;
  color: var(--ink);
  font-family: var(--f-data);
  font-size: var(--t-body-size);
  font-variant-numeric: tabular-nums;
  padding: 0;
  -webkit-appearance: none;
}
.field input:focus { outline: none; }
.field:focus-within { border-color: var(--accent); background: var(--surface); }
/* Die Einheit im Feld („kg", „Wdh", „Min", „Sek") ist Information, keine
   Dekoration — ohne sie steht dort eine nackte Zahl. Sie lief in --c-text-3
   und hält auf der Feldfläche --c-surface-2 an den gerenderten Pixeln nur
   4,33:1 (dunkel), im Fokuszustand auf --c-surface 4,77:1. Das ist unter der
   Pflichtgrenze, und es betrifft jedes Zahlenfeld der App: Profil, Training,
   Abschluss, Korrekturmodus, Heute. Eine Stufe heller sind es 6,19:1 dunkel
   und 6,15:1 hell. */
.field .u { font-family: var(--f-data); font-size: var(--t-eyebrow-size); color: var(--c-text-2); white-space: nowrap; }

.set-done {
  width: 40px; height: 40px;
  border: 1.5px solid var(--surface-3);
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  display: grid;
  place-items: center;
  font-size: var(--t-body-size);
  transition: border-color 0.2s, background-color 0.2s, transform 0.25s var(--spring);
}
.set-done:active { transform: scale(0.9); }
.set-done.on { background: var(--ok); border-color: var(--ok); color: #072012; animation: pop 0.35s var(--spring); }

/* Korrekturmodus im Verlauf: dieselbe Satzzeile, aber mit Löschknopf und
   variabler Feldzahl — je nach Übung nur Wiederholungen oder Gewicht + Zeit. */
.set-row.editable { display: flex; }
.set-row.editable .field { flex: 1; min-width: 0; }
.set-del {
  flex-shrink: 0;
  width: 34px; height: 40px;
  border: none;
  background: none;
  color: var(--muted);
  font-size: var(--t-heading-size);
  line-height: 1;
  border-radius: 10px;
  cursor: pointer;
  transition: color 0.18s, transform 0.18s var(--spring);
}
.set-del:hover { color: var(--ink); }
.set-del:active { transform: scale(0.9); }

.feedback { margin-top: 14px; }
.feedback-label {
  color: var(--muted);
  margin-bottom: 7px;
}
.chips { display: flex; gap: 7px; flex-wrap: wrap; }
/* Nach Traxx (.tx-chip). Ausgewählt heißt jetzt weiche Akzentfläche mit
   Rand statt Vollfläche — dazu ein Punkt, der den Zustand auch ohne
   Farbwahrnehmung erkennbar macht. */
.chip {
  font-family: var(--f-body);
  font-size: var(--t-bodys-size);
  font-weight: 600;
  letter-spacing: -0.005em;
  padding: 0 var(--s-6);
  border: 1px solid var(--c-border);
  border-radius: var(--r-pill);
  background: var(--c-surface-2);
  color: var(--c-text-2);
  cursor: pointer;
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  transition: all var(--d-fast) var(--e-out);
}
.chip:hover { color: var(--c-text); border-color: var(--c-border-strong); }
.chip:active { transform: scale(0.97); }
.chip:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }
.chip.on {
  background: var(--c-accent-soft);
  border-color: var(--c-accent-soft-b);
  color: var(--c-accent-text);
}
.chip.on::before {
  content: "";
  width: 14px;
  height: 14px;
  flex: none;
  border-radius: 50%;
  background: var(--c-accent);
  box-shadow: inset 0 0 0 2px var(--c-bg);
}

/* ================================================================= Timer

   Der Vollbild-Timer steht unter „===== Timer =====" weiter unten (.uhr).
   Hier lag bis zuletzt seine Vorgängerfassung: .timer-overlay mit .work /
   .rest, .timer-phase, .timer-round, .timer-clock, .timer-next, .timer-ring,
   .timer-actions — dazu .timer-launch, der abgelöste Starter des
   Zirkel-Timers (heute .tr-zirkel). Keine Zeile davon stand noch im Markup;
   gelöscht.
   ==================================================================== */

/* =============================================================== Historie */

.session-row {
  display: grid;
  grid-template-columns: 56px 1fr auto;
  gap: 13px;
  align-items: center;
  padding: 8px 0;
  margin-bottom: 8px;
  text-decoration: none;
  color: inherit;
}
.session-row .date {
  font-family: var(--f-data);
  font-size: var(--t-eyebrow-size);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  text-align: center;
  line-height: 1.2;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius-s);
  padding: 8px 2px 7px;
}
.session-row .date b {
  display: block;
  font-family: var(--f-display);
  font-size: var(--t-heading-size);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.session-row .t {
  font-family: var(--f-display);
  font-size: var(--t-heading-size);
  font-weight: 700;
  letter-spacing: -0.015em;
}
.session-row .m { font-family: var(--f-data); font-size: var(--t-caption-size); color: var(--muted); }
.session-row .pct { font-family: var(--f-data); font-size: var(--t-label-size); color: var(--ok); }

/* Die Bento-Kacheln (.stat-grid / .stat mit .k/.v/.d) sind mit dem Umbau der
   Rückschau weggefallen: Der Verlauf führt jetzt eine Heldenzahl und drei
   Dot-Leader-Zeilen, „vier gleich laute Dinge erzählen keine Reihenfolge"
   (Leitbild „Layout-Grammatik"). Kein Vorkommen mehr in js/ — gelöscht,
   samt dem .stat .k aus der gemeinsamen Eyebrow-Regel weiter oben. */

.spark { display: block; width: 100%; height: 44px; margin-top: 10px; overflow: visible; }

/* Wochenziel als Segmente — gefüllt heißt trainiert */
.goal-segs { display: flex; gap: 5px; margin-top: 10px; }
.goal-segs i {
  height: 8px;
  flex: 1;
  max-width: 36px;
  border-radius: 4px;
  background: var(--surface-3);
  transition: background-color 0.3s;
}
.goal-segs i.on {
  background: var(--ok);
  box-shadow: 0 0 12px color-mix(in srgb, var(--ok) 45%, transparent);
}

/* =============================================================== Übungen */

.filter-row { display: flex; gap: 7px; overflow-x: auto; padding-bottom: 4px; margin-bottom: 14px; }
.filter-row::-webkit-scrollbar { display: none; }
.filter-row .chip { flex-shrink: 0; }

/* Die alte Katalogzeile (.ex-list-item mit .n und .joy) und der Pillen-
   Schalter (.switch) sind mit dem Umbau des Katalogs weggefallen: Die Liste
   ist eine Dot-Leader-Zeile (.kat-zeile), der Schalter zeigt seinen Zustand
   als eye / eye-slash (.kat-schalter).

   Achtung beim Nachprüfen: Nach `switch` zu greppen liefert Treffer, die
   keine sind — role="switch" in js/views/exercises.js, die id #switchType in
   js/views/home.js und switch-Anweisungen im Code. Als KLASSE steht `switch`
   in keiner Datei mehr, auch nicht im Profil: Das Akkordeon schaltet über
   .chip.on (geprüft in js/, index.html, tools/ und über die Historie —
   .switch lebte zuletzt im Katalog, nicht im Profil). */

/* ================================================================ Formular */

.form-row { margin-bottom: 14px; }
.form-row label {
  display: block;
  color: var(--muted);
  margin-bottom: 7px;
}
.form-row input, .form-row textarea, .form-row select {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid transparent;
  border-radius: var(--radius-s);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: var(--t-body-size);
  padding: 13px 14px;
  -webkit-appearance: none;
  transition: border-color 0.2s, background-color 0.2s;
}
.form-row input:focus, .form-row textarea:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--surface);
}
.form-row textarea { min-height: 78px; resize: vertical; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* ============================================================== Onboarding */

/* Während des Wizards gibt es keine Navigation — der Weg ist der Wizard */
body[data-wizard] .nav { display: none; }

.wizard {
  min-height: calc(100vh - 120px);
  min-height: calc(100dvh - 120px);
  display: flex;
  flex-direction: column;
}
/* Die Punktleiste .wizard-dots ist weg: Der Assistent zeigt seinen Stand als
   Stufenleiste (.ob-stufen/.stufe), erledigte Schritte werden durchgestrichen
   statt abgehakt — dieselbe Leiste wie der Klimmzug-Aufbau im Fortschritt. */

.wizard-step { flex: 1; animation: rise-in 0.45s var(--spring) backwards; }

.wizard-brand {
  font-family: var(--f-display);
  font-size: clamp(56px, 17vw, 84px);
  font-weight: 800;
  letter-spacing: -0.045em;
  line-height: 0.95;
  margin: 10vh 0 10px;
}
.wizard-claim {
  font-size: var(--t-heading-size);
  color: var(--ink-soft);
  max-width: 26ch;
  margin: 0 0 28px;
  text-wrap: balance;
}
.wizard-points { list-style: none; margin: 0 0 24px; padding: 0; }
.wizard-points li {
  display: flex;
  gap: 12px;
  align-items: baseline;
  padding: 9px 0;
  color: var(--ink-soft);
  font-size: var(--t-body-size);
}
/* Wie im Tausch-Sheet: Der Aufzählungspunkt kodiert keinen Zustand, also
   trägt er keine Farbe (Leitbild „Farbe und Zustand"). Er stand hier mit
   7 px im Akzent direkt neben der Stufenleiste, deren Rahmen dieselbe Farbe
   trägt und dort etwas heißt — „auf diesem Schritt stehst du". */
.wizard-points li::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--c-text-3);
  flex-shrink: 0;
  transform: translateY(-1px);
}

.wizard h2 {
  font-family: var(--f-display);
  font-size: clamp(28px, 8vw, 36px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin: 0 0 8px;
  text-wrap: balance;
}
.wizard .lede { margin-bottom: 22px; }

/* .wizard-foot (samt .wizard-foot .alt) ist weg: „Weiter" ist die
   Vorgangsleiste, die Nebenziele stehen in .ob-neben. Die Fußzeile war
   zugleich die zweite Stelle, an der .alt belegt war — einmal für die
   Alternativen des Tausch-Sheets, einmal für die Textziele des Assistenten.
   Der Assistent heißt heute .ob-alt, .alt gehört wieder allein dem Sheet. */
.gear-preset {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: inset 0 1px 0 var(--edge);
  padding: 14px 16px;
  margin-bottom: 10px;
  cursor: pointer;
  color: var(--ink);
  font-family: var(--f-body);
  transition: border-color 0.2s, background-color 0.2s, transform 0.25s var(--spring);
}
.gear-preset:active { transform: scale(0.985); }
.gear-preset .t1 {
  display: block;
  font-family: var(--f-display);
  font-size: var(--t-body-size);
  font-weight: 700;
  letter-spacing: -0.015em;
}
.gear-preset .t2 { font-size: var(--t-label-size); color: var(--muted); }
.gear-preset.on {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  background: var(--accent-bg);
}

/* ============================================================ Bottom-Sheet */

@keyframes fade-in { from { opacity: 0; } }
@keyframes sheet-up { from { transform: translateY(60px); opacity: 0.4; } }

.sheet-wrap {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.sheet-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  animation: fade-in 0.25s;
}
:root[data-theme="light"] .sheet-backdrop { background: rgba(30, 25, 45, 0.35); }
.sheet {
  position: relative;
  width: 100%;
  max-width: 640px;
  background: var(--surface);
  border: 1px solid var(--glass-edge);
  border-bottom: none;
  border-radius: 26px 26px 0 0;
  padding: 10px 20px calc(env(safe-area-inset-bottom) + 16px);
  max-height: 82vh;
  max-height: 82dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  animation: sheet-up var(--d-slow) var(--e-out);
}
.sheet-grip {
  width: 40px;
  height: 4px;
  background: var(--surface-3);
  border-radius: 2px;
  margin: 6px auto 16px;
}
.sheet h3 {
  font-family: var(--f-display);
  font-size: var(--t-title-size);
  font-weight: 800;
  letter-spacing: -0.025em;
  margin: 0 0 10px;
}
.sheet .eyebrow { margin-bottom: 4px; }

.howto-label {
  color: var(--muted);
  margin: 18px 0 8px;
}
.howto-steps {
  list-style: none;
  counter-reset: howto;
  margin: 0;
  padding: 0;
}
.howto-steps li {
  counter-increment: howto;
  position: relative;
  padding: 0 0 12px 40px;
  font-size: var(--t-bodys-size);
  color: var(--ink-soft);
}
.howto-steps li::before {
  content: counter(howto);
  position: absolute;
  left: 0;
  top: -1px;
  width: 26px;
  height: 26px;
  border-radius: 9px;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent);
  font-family: var(--f-display);
  font-size: var(--t-bodys-size);
  font-weight: 700;
  display: grid;
  place-items: center;
}
.howto-mistakes {
  list-style: none;
  margin: 0;
  padding: 0;
}
.howto-mistakes li {
  position: relative;
  padding: 0 0 8px 24px;
  font-size: var(--t-bodys-size);
  color: var(--ink-soft);
}
.howto-mistakes li::before {
  content: "✕";
  position: absolute;
  left: 2px;
  top: 0;
  color: var(--goal);
  font-size: var(--t-caption-size);
  font-weight: 700;
}
/* .sheet-meta ist mit dem Umbau der Sheets weggefallen — was dort stand,
   steht heute in der Fakten-Zeile am Kopf (.ts-fakten / .howto-fakten). */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--nav-gap) + 14px);
  transform: translateX(-50%);
  background: var(--glass);
  -webkit-backdrop-filter: blur(20px) saturate(1.5);
  backdrop-filter: blur(20px) saturate(1.5);
  border: 1px solid var(--glass-edge);
  color: var(--ink);
  font-size: var(--t-bodys-size);
  font-weight: 500;
  padding: 12px 20px;
  border-radius: 999px;
  z-index: 200;
  max-width: 88vw;
  text-align: center;
  animation: toast-rise var(--d-base) var(--e-arbeit);
}
/* Randnotiz: steigt 8 px, 180 ms — mehr Auftritt hat eine Randnotiz nicht */
@keyframes toast-rise { from { opacity: 0; transform: translate(-50%, 8px); } }

/* --------------------------------------------------------------------
   prefers-reduced-motion (Leitbild §5)

   Nicht „alles aus": Transforms entfallen, Übergänge werden zu kurzen
   Opazitätswechseln, Füllungen und Striche springen auf ihren Endzustand.
   Töne und Vibration bleiben — sie ersetzen dann die Bewegung. Und kein
   Bedienschritt darf hier länger dauern als ohne.
   -------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-property: opacity !important;
    transition-duration: 120ms !important;
  }
  /* Ausnahme mit Grund: Die radiale Füllung beim Halten IST die Anzeige,
     wie lange noch zu halten ist. Spränge sie sofort auf voll, gäbe sie
     eine Aktion vor, die noch gar nicht ausgelöst hat. */
  .vorgang.haelt .vorgang-halt {
    transition-property: opacity, transform !important;
    transition-duration: var(--halte-dauer, 400ms) !important;
  }
}

/* ------------------------------------------------ Howto-Illustrationen */
/* Die Figure reserviert 3:2, damit das lazy geladene Bild nicht springt;
   fehlt die Datei, entfernt onerror in howto.js die Figure komplett. */
.howto-figure {
  margin: 2px 0 18px;
  aspect-ratio: 3 / 2;
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid var(--rule);
  background:
    radial-gradient(130% 100% at 85% -10%, var(--accent-bg), transparent 58%),
    var(--surface);
}
.howto-figure img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ------------------------------------------------ Fortschritt (#/stats) */

/* .stats-card ist mit dem Umbau des Fortschritts weggefallen: Aus vier
   gestapelten Karten gleicher Lautstärke sind Abschnitte mit h2.section
   geworden — dieselbe Gliederung wie in Heute, Training und Abschluss. */
.stats-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.stats-delta {
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  color: var(--ink-soft);
}
.stats-delta.down { color: var(--ok); background: var(--ok-bg); border-color: transparent; }
.stats-empty { color: var(--ink-soft); font-size: var(--t-bodys-size); margin: 4px 0; }

.wg-chart { display: block; width: 100%; height: auto; }
.wg-line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  animation: wg-draw 1.1s var(--ease-out) backwards;
}
@keyframes wg-draw { from { stroke-dashoffset: 1; } }
.wg-area { animation: rise-in 0.9s var(--ease-out) backwards; }
.wg-dot { fill: var(--accent); }
.wg-goal { stroke: var(--muted); stroke-width: 1; stroke-dasharray: 3 4; opacity: 0.7; }
.wg-goal-t, .wg-axis {
  font-family: var(--f-data);
  font-size: var(--t-eyebrow-size);
  fill: var(--muted);
}
.wg-now {
  font-family: var(--f-data);
  font-size: var(--t-eyebrow-size);
  font-weight: 600;
  fill: var(--ink);
}

.bar-list { display: grid; gap: 9px; margin: 2px 0 12px; }
.bar-row {
  display: grid;
  grid-template-columns: 108px 1fr 26px;
  align-items: center;
  gap: 10px;
}
.bar-label {
  font-size: var(--t-label-size);
  color: var(--ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bar {
  height: 10px;
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
}
.bar i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--accent-dim), var(--accent));
  animation: bar-grow 0.7s var(--ease-out) backwards;
}
@keyframes bar-grow { from { width: 0 !important; } }
.bar-val {
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  color: var(--muted);
  text-align: right;
}

.pr-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--rule);
}
.pr-row:last-child { border-bottom: none; }
.pr-name { font-size: var(--t-bodys-size); font-weight: 500; min-width: 0; }
.pr-name small, .pr-best small {
  display: block;
  font-family: var(--f-data);
  font-size: var(--t-eyebrow-size);
  color: var(--muted);
  font-weight: 400;
  margin-top: 1px;
}
.pr-best {
  font-family: var(--f-data);
  font-size: var(--t-bodys-size);
  font-weight: 600;
  color: var(--accent);
  text-align: right;
  white-space: nowrap;
}

/* Die Zielzeilen (.goal-line / -head / -note) sind mit dem Umbau des
   Fortschritts weggefallen: Die zwei erklärten Ziele führen jetzt als
   Heldenzahl mit Stufenleiste (.fs-ziel), statt als vierte von vier gleich
   lauten Karten mitzulaufen. */

/* =====================================================================
   ==  BAUSTEINE DES LEITBILDS  ========================================
   =====================================================================
   Alles ab hier ist Grundausstattung, keine Ansicht. Jede View benutzt
   diese Klassen; keine baut sie nach. Reihenfolge:
     1  Der Durchstrich (die Signatur)
     2  Ausgeschaltet — die Gegenprobe, die kein Strich sein darf
     3  Die Vorgangsleiste
     4  Typo-Grammatik: Eyebrow · Held · Fakten · Dot-Leader · Datenzeile
     5  Das eine Slide-Muster + Icon-Grundmaß
   ===================================================================== */

/* ------------------------------------------------------- 1 Durchstrich
   „Bei Traxx wird nichts abgehakt — es wird durchgestrichen, wie auf
   einem Trainingszettel."

   Ein Tap, ein satter Balken in Tonfarbe fährt in 200 ms durch die
   Zeile, die Zeile sackt 2 px ab wie ein Stempel, es klackt (siehe
   durchstreichen() in js/ui.js).

   Der Zustand IST die Klasse .ist-durch — sie ist zugleich Animation und
   gespeicherter Zustand. Wer eine Ansicht neu aufbaut, setzt sie einfach
   wieder und bekommt den Endzustand ohne Sonderfall.

   Der Text darunter bleibt hell. Ein ausgegrauter durchgestrichener Text
   wäre bei Blendung und Schweiß das schlechteste Erledigt-Signal, das man
   bauen kann — der Strich sagt „geschafft", nie „gestrichen".
   -------------------------------------------------------------------- */
.durchstrich {
  position: relative;
  top: 0;
  transition: top var(--d-strich) var(--e-erfolg);
}
/* Der Balken liegt ÜBER dem Text, nicht darunter.
   Erste Fassung hatte ihn hinter die Zeile gelegt (die Kinder trugen
   position:relative und verdeckten ihn), und ein Kritiker las das prompt als
   das, was es dann war: „eine Fokus-Unterstreichung, kein Durchstrich — die
   Ziffern bleiben unberührt". Ein Durchstrich fährt durch die Zeichen, wie
   ein Filzstift über einen Trainingszettel.

   Das Easing ist bewusst nicht --e-out: Dessen Kurve ist nach 70 ms schon bei
   90 %, im Frame-Strip war vom Fahren nichts zu sehen. Diese Kurve läuft
   sichtbar durch und bremst erst zum Schluss. */
.durchstrich::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  z-index: 2;
  height: 3px;
  border-radius: 2px;
  background: var(--tone);
  transform: translateY(-50%) scaleX(0);
  transform-origin: left center;
  transition: transform var(--d-strich) cubic-bezier(.35, .12, .28, 1);
  pointer-events: none;
}
.durchstrich.ist-durch::after { transform: translateY(-50%) scaleX(1); }

/* Der Stempel: die Zeile sackt 2 px ab und bleibt unten.

   Bewusst top statt translateY: Ein transform schiebt das Element auf eine
   eigene Compositing-Ebene, und Chrome schaltet dort die Subpixel-
   Kantenglättung ab — die gestrichene Zeile wirkt dann blasser als die
   Zeilen darüber. Genau das darf sie nicht, der Text bleibt voll lesbar.
   Zwei Pixel relatives Versetzen kosten dagegen nichts. */
.durchstrich.ist-durch { top: 2px; }

/* Ganze Übung statt einzelner Satz: schwerer, langsamer, sichtbar mehr
   Gewicht. Dieselbe Mechanik, nur zwei Zahlen anders. */
.durchstrich--schwer::after { height: 5px; transition-duration: var(--d-strich-schwer); }

/* Der Text steht unter dem Balken — z-index 1 gegen die 2 des ::after. */
.durchstrich > * { position: relative; z-index: 1; }

/* Erledigt heißt auch: tritt zurück. Ein Kritiker vermisste genau das —
   „die Ziffern bleiben unberührt und voll hell, nichts wird abgedunkelt".
   Aber nur so weit, dass die Zeile lesbar bleibt: Ausgrauen wäre bei
   Blendung und Schweiß das schlechteste Erledigt-Signal, und der Strich
   soll „geschafft" sagen, nicht „gestrichen". 72 % ist der Kompromiss. */
.durchstrich.ist-durch > * { opacity: .72; }

/* ------------------------------------------------- 2 Ausgeschaltet
   „Nie wieder vorschlagen" ist KEIN Durchstrich. Ein Strich darf nicht
   zweierlei heißen: Erledigt ist Tonfarbe und heller Text, Aus ist
   gedämpfter Text hinter gestricheltem Rahmen (dazu in der Ansicht das
   Icon eye-slash). Wer beides gleich zeichnet, nimmt der Signatur ihre
   Bedeutung.
   -------------------------------------------------------------------- */
.ist-aus {
  color: var(--c-text-3);
  border: 1px dashed var(--c-border-strong);
  background: transparent;
}
.ist-aus .name,
.ist-aus .wert { color: var(--c-text-3); }
/* Sicherung: sollte eine Ansicht beide Klassen an ein Element hängen,
   gewinnt „aus" — gestrichen wird hier nichts. */
.ist-aus.durchstrich::after { content: none; }

/* --------------------------------------------------- 3 Vorgangsleiste
   Fest über der Navigation, außerhalb jedes Scroll-Containers, 64 px
   hoch, volle Breite, Tonfarbe der Einheit. Eine blind treffbare Fläche,
   immer am selben Ort.

   Was sie tragen darf: TRAINING STARTEN · WEITERMACHEN · PAUSE
   ÜBERSPRINGEN · EINHEIT ABSCHLIESSEN · FERTIG — Verben auf
   Vorgangsebene. Was sie NIE trägt: „Satz fertig", „Übung erledigt".
   Begründung steht am Helfer in js/ui.js.

   Zwei Modi, ein Element: normal trägt sie das Verb, in der Pause ist sie
   der Timer (Füllung läuft rückwärts leer, Restsekunden im Verb-Slot).
   -------------------------------------------------------------------- */
/* Die Leiste teilt die Formensprache der Nav-Pille darunter.

   Zwei Kritiker nannten unabhängig denselben Fehler: „Der hartkantige gelbe
   Balken widerspricht der sonst durchgehend runden Formensprache und drückt
   direkt auf die schwebende Tab-Pille" und „Zwei unten verankerte Balken,
   entgegengesetzte Ecken-Grammatik, direkt übereinander."

   Deshalb dieselbe Breite, derselbe Radius, dieselbe Mittelachse — die beiden
   lesen sich jetzt als ein Sockel. Randlos wäre einen Tick besser zu treffen,
   aber 400 × 64 px trifft man auch verschwitzt blind, und eine Formsprache,
   die sich selbst widerspricht, kostet mehr, als die 14 px Rand einbringen. */
.vorgang {
  position: fixed;
  /* Zentriert über margin-inline statt translateX: Die Einblend-Animation
     (von-unten) belegt transform, und zwei Transforms auf einem Element
     lassen die Leiste beim Einblenden nach links springen. */
  left: 0;
  right: 0;
  margin-inline: auto;
  bottom: calc(env(safe-area-inset-bottom) + var(--nav-gap) + var(--nav-h) + 10px);
  z-index: 45;
  width: min(calc(100% - 28px), 400px);
  border-radius: 999px;
  height: var(--vorgang-h);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 0 var(--pad);
  /* Nur die Block-Ränder zurücksetzen. Die Shorthand `margin: 0` stünde hier
     zwölf Zeilen nach `margin-inline: auto` und nähme die Zentrierung gleich
     wieder weg — die Leiste klebte dann links. */
  margin-block: 0;
  border: none;
  background: var(--tone);
  color: var(--on-tone);
  font-family: var(--f-display);
  text-align: center;
  cursor: pointer;
  overflow: hidden;
  isolation: isolate;
  -webkit-tap-highlight-color: transparent;
  /* Halten darf keinen Text markieren und keine Lupe aufrufen */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  touch-action: manipulation;
  animation: von-unten var(--d-slow) var(--e-arbeit) backwards;
}
.vorgang:active { filter: brightness(0.94); }
.vorgang:focus-visible { outline: 3px solid var(--c-focus); outline-offset: -5px; }

.vorgang-verb {
  position: relative;
  z-index: 2;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.1;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  /* Im Training steht hier der Name des Helden — „Kettlebell Goblet Squat"
     darf die 64-px-Leiste nicht zweizeilig sprengen. */
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.vorgang-danach {
  position: relative;
  z-index: 2;
  max-width: 100%;
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  font-weight: 500;
  letter-spacing: 0.01em;
  line-height: 1.2;
  opacity: 0.85;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Gesperrt: 600 ms nach jedem Verb-Wechsel ist die Leiste taub. Sichtbar
   gemacht, damit ein Fehltipp nicht wie ein toter Knopf wirkt. */
.vorgang.gesperrt { opacity: 0.72; }

/* Countdown. Fläche wird Fast-Schwarz, Schrift und Füllung tragen die
   Tonfarbe — so ist die Pause aus drei Metern von der Arbeit zu
   unterscheiden. Die Füllung bleibt bewusst schwach: der Text darüber
   muss auf beiden Hälften 4,5:1 halten. */
.vorgang.zaehlt {
  /* Fast-Schwarz mit einem Hauch Ton: rein --c-bg-sunken ist von der
     Seitenfläche nicht zu unterscheiden, und dann sähe man nicht die
     Füllung leerlaufen, sondern die Leiste schrumpfen. */
  background: color-mix(in srgb, var(--tone) 8%, var(--c-bg-sunken));
  color: var(--tone);
  border-top: 1px solid color-mix(in srgb, var(--tone) 45%, transparent);
}
.vorgang-fuell {
  position: absolute;
  inset: 0;
  z-index: 0;
  transform: scaleX(0);
  transform-origin: left center;
  background: color-mix(in srgb, var(--tone) 20%, transparent);
  pointer-events: none;
}
.vorgang.zaehlt .vorgang-fuell { transform: scaleX(var(--anteil, 1)); }

/* Halten als Gegenaktion: radiale Füllung unter dem Finger, 400 ms.
   Halten ist immer nur die Abkürzung — die Ansicht stellt zusätzlich ein
   sichtbares Textziel bereit. */
.vorgang-halt {
  position: absolute;
  top: 50%;
  left: var(--hx, 50%);
  width: 320px;
  height: 320px;
  margin: -160px 0 0 -160px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--on-tone) 20%, transparent);
  transform: scale(0);
  opacity: 0;
  z-index: 1;
  pointer-events: none;
}
.vorgang.zaehlt .vorgang-halt { background: color-mix(in srgb, var(--tone) 26%, transparent); }
.vorgang.haelt .vorgang-halt {
  transform: scale(1);
  opacity: 1;
  transition: transform var(--halte-dauer, 400ms) linear,
              opacity var(--d-fast) var(--e-arbeit);
}

/* ----------------------------------------------- 4 Typo-Grammatik
   Das Grundmuster jeder Ansicht (Leitbild §3 und §6):
     EYEBROW · HELD · FAKTEN · KÖRPER (Dot-Leader) · NEBEN (Datenzeile)
   -------------------------------------------------------------------- */

/* Die Heldenzahl. Größen sind gemessen, nicht geschätzt — vier Sora-
   Ziffern belegen bei 176 px rund 380 px von 390 px Bildschirmbreite.
   Deshalb genau diese vier Stufen:
     --gross   132 px  1–2 Ziffern   (87 Minuten, Stufe 2)
     --mittel  104 px  3 Ziffern     (140 Minuten)
     --uhr     112 px  Uhrzeit 0:24  (Timer)
     --lang     88 px  Uhrzeit 12:24 (langer Zirkel)
   Wer eine Heldenzahl setzt, prüft sie im Screenshot bei 390 px. */
.held {
  display: block;
  font-family: var(--f-display);
  font-size: 104px;
  font-weight: var(--t-numeral-w);
  line-height: var(--t-numeral-lh);
  letter-spacing: var(--t-numeral-ls);
  font-variant-numeric: tabular-nums;
  color: var(--c-text);
  margin: 0;
}
.held--gross  { font-size: 132px; }
.held--mittel { font-size: 104px; }
.held--lang   { font-size: 88px; }
/* --uhr (112 px) stand hier als vierte Stufe und ist nie benutzt worden:
   Der Vollbild-Timer setzt seine Ziffer selbst (.uhr, 248 px) — dort ist die
   Zahl der einzige Grund, warum der Screen existiert, und die Tabelle des
   Leitbilds gilt für Zahlen im Fließtext. Gelöscht statt mitgeschleppt. */
.held--ton    { color: var(--tone); }
/* Die Einheit hinter der Zahl läuft nie mit ihr mit */
.held small {
  font-family: var(--f-data);
  font-size: var(--t-body-size);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--c-text-2);
  margin-left: 8px;
}
/* Die dritte Zeile der Dreiergruppe: das Label unter der Heldenzahl
   (Leitbild §3, 11–13 px). Es gab diese Klasse schon, und trotzdem hat sie
   sich jede Ansicht neu gebaut — Training als .tz-wort, Abschluss als
   .ab-wort, beide 14,5 px, beide dasselbe. Jetzt eine Klasse, ein Maß.
   Ohne eigenen Rand: Das Label steht in beiden Fällen als Flex-Kind neben
   seiner Zahl, den Abstand macht dort der Gap. */
.held-label {
  font-family: var(--f-body);
  font-size: var(--t-label-size);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--c-text-2);
  margin: 0;
}

/* Fakten: EINE Zeile. Details wandern in ⓘ oder hinter eine Aufklappzeile,
   nie in einen eigenen Absatz. Läuft die Zeile über, scrollt sie seitlich,
   statt einen zweiten Absatz aufzumachen. */
.fakten {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 4px;
  padding-bottom: 2px;
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  color: var(--c-text-2);
  white-space: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
}
.fakten::-webkit-scrollbar { display: none; }
.fakten > * + *::before {
  content: "·";
  margin-right: 10px;
  color: var(--c-text-3);
}
.fakten b { color: var(--c-text); font-weight: 600; }
/* „gedrosselt" ist eine Angabe, keine Warnung. In der Tonfarbe war es bei
   einer Combat-Einheit gelb auf gelb und las sich als Fehler; jetzt steht es
   wie jede andere Angabe im Text, nur etwas heller hervorgehoben. */
.fakten .ton { color: var(--c-text); font-weight: 600; }

/* Datenzeile: was zurücktritt. Kein eigener Absatz, keine eigene Karte. */
.datenzeile {
  font-family: var(--f-data);
  font-size: var(--t-data-size);
  line-height: var(--t-data-lh);
  letter-spacing: var(--t-data-ls);
  font-variant-numeric: tabular-nums;
  color: var(--c-text-3);
  margin: 6px 0 0;
}

/* Dot-Leader-Zeile: Name links (kürzbar), Wert rechts, Punktlinie
   dazwischen. Der Leader ist das ::before des Flex-Containers und rutscht
   per order zwischen die beiden Kinder — so kommt die Zeile mit zwei
   schlichten <span> aus, ohne Füll-Element im Markup.

   Warum ::before und nicht ::after, wo ::after näher liegt: Genau diese
   Zeile ist der Regelfall für den Durchstrich („Satz 2 …… 12 × 40 kg"
   antippen), und dem gehört ::after. Beide auf demselben Pseudoelement
   hieß in der ersten Fassung: Zeile gestrichen, Punktlinie weg.

   Der Name bricht NIE um: „Rumänisches Kreuzheben einbeinig" ist bei
   390 px länger als die Zeile, und eine zweite Zeile zerlegt die Liste. */
.dotzeile {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  min-height: 48px;
  padding: 12px 0;
  margin: 0;
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
}
.dotzeile::before {
  content: "";
  order: 1;
  flex: 1 1 auto;
  min-width: 14px;
  align-self: baseline;
  margin-bottom: 3px;
  border-bottom: 2px dotted color-mix(in srgb, var(--c-text-3) 60%, transparent);
}
/* Eine Punktlinie, die zu nichts führt, verbindet nichts: Zeilen ohne Wert
   bekommen keine. Der Katalog hatte diese Regel für sich allein gebaut, sie
   gilt für jede Dot-Leader-Zeile. Zwei Schreibweisen, weil zwei Ansichten
   „kein Wert" verschieden bauen: Der Katalog lässt das Element weg, die
   Trainingsansicht setzt es leer (Übung ohne Dosierung). */
.dotzeile:not(:has(> .wert))::before,
.dotzeile:has(> .wert:empty)::before { display: none; }
.dotzeile > * { order: 0; min-width: 0; }
.dotzeile > :first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-body-size);
}
/* Der Wert rechts. Beide Selektoren, und das ist der Punkt: Sobald eine Zeile
   ein drittes Kind bekommt (Winkel, „Ändern"), greift :last-child nicht mehr —
   und dann hatte sich jede der vier Ansichten ihre eigene Kopie dieser sieben
   Zeilen gebaut (.ablauf-kopf, .plan-zeile, .tr-zeile, .ab-klapp, alle
   wortgleich). Einmal reicht. */
.dotzeile > :last-child,
.dotzeile > .wert {
  order: 2;
  flex: none;
  font-family: var(--f-data);
  font-size: var(--t-data-size);
  font-variant-numeric: tabular-nums;
  color: var(--c-text-2);
  white-space: nowrap;
}

/* --kopf: Die Zeile ist eine Abschnittszeile — der Kopf eines Blocks im
   Ablauf, ein Abschnitt des Profil- und Konto-Akkordeons, „Notizen" im
   Abschluss, „4 Gründe" im Tausch-Sheet, ein Block in der Vorschau des
   Assistenten. Sechs Stellen, dieselbe Rolle, und sie war dreimal wortgleich
   nachdeklariert (.ablauf-kopf .name, .pf-kopf > .name, .ob-blockkopf >
   .name) und zweimal anders beantwortet: .ab-klapp lief in der Fließschrift
   mit 600, .ts-warum im Grundwert 400. Vier Typografien für eine Rolle.
   Jetzt eine Regel: Anzeigeschrift, 700, dieselbe Sperrung wie jeder andere
   Abschnittstitel — und der Name bricht um, statt zu kürzen (Leitbild
   „Typografie": „Aktuelles Gewicht nachtrage…" verrät nichts mehr).

   Die Klasse hieß bis hierher --gross und setzte min-height: 64px. Diese
   Zeile ist nie angekommen: button.dotzeile (0-1-1) steht darüber und
   gewinnt gegen .dotzeile--gross (0-1-0) — alle sechs Köpfe sind 56 px hoch,
   und alle sechs Ansichten sind mit 56 px gebaut und geprüft worden. Statt
   die Ansichten nachträglich um 8 px zu strecken, ist die Regel weg und der
   Name sagt, was die Klasse wirklich tut. */
.dotzeile--kopf > .name {
  font-family: var(--f-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}
/* Und weil der Name umbrechen darf, muss die Punktlinie verschwinden können,
   statt als Vierpunkt-Stummel danebenzustehen — „wirkt wie ein
   Rendering-Rest". Das Profil hatte das für sich gelöst; es gilt für jede
   Abschnittszeile, deren Name lang werden kann („Schulter vorbereiten" im
   Ablauf bricht bei 390 px genauso um wie „Aktuelles Gewicht nachtragen"). */
.dotzeile--kopf::before { min-width: 0; }

/* --auskunft: Hier ist der Wert die Aussage der Zeile, nicht der Name —
   „Telefon …… +49 761 8878 6208", „Serie …… 0 Wochen". Zwei Ansichten hatten
   das unabhängig voneinander erfunden und verschieden gelöst: Das Impressum
   hob nur den Wert auf --c-text, der Verlauf hob den Wert UND setzte den
   Namen auf 13 px Datenschrift. Damit las sich dieselbe Zeile in Verlauf und
   Impressum wie zwei Bauteile. Jetzt eine Klasse: Der Name bleibt der Name
   (Fließschrift, wie in jeder anderen Dot-Leader-Zeile), der Wert bekommt
   den vollen Kontrast. */
.dotzeile--auskunft > .wert { color: var(--c-text); }

/* Der Aufklapp-Winkel am Ende einer Zeile. Er stand zweimal im CSS —
   in Heute 11 px in --c-text-3, im Abschluss 13 px in --c-text-2, mit 12
   bzw. 10 px Abstand: dasselbe Zeichen an derselben Stelle, zwei Maße.
   Jetzt eine Klasse; gedreht wird über das aria-expanded der Zeile, damit
   keine Ansicht dafür eine eigene Regel braucht. */
.dotzeile > .dz-chev {
  order: 3;
  flex: none;
  margin-left: 12px;
  font-size: 12px;
  line-height: 0;
  color: var(--c-text-3);
  transition: transform var(--d-base) var(--e-arbeit);
}
.dotzeile[aria-expanded="true"] > .dz-chev { transform: rotate(180deg); }
/* Als Knopf: die ganze Zeile ist das Ziel, 64 px hoch, volle Breite.
   Blind treffbar, kein Achsen-Lock, kein Wischen. */
button.dotzeile { min-height: 56px; cursor: pointer; -webkit-tap-highlight-color: transparent; }
button.dotzeile:active { background: var(--c-surface-2); }
button.dotzeile:focus-visible { outline: 2px solid var(--c-focus); outline-offset: -2px; }
.dotzeile + .dotzeile { border-top: 1px solid var(--c-border-inset); }

/* Die Übungszeile — im Ablauf der Heute-Ansicht (.plan-zeile), in der Liste
   der Trainingsansicht (.tr-zeile) und in der gelesenen Einheit des Verlaufs
   (.vd-zeile) dieselbe Zeile: Name über die volle Breite mit Umbruch,
   darunter rechts der Wert. Sie stand dreimal im Blatt, zuletzt mit drei
   Mindesthöhen (52 / 52 / 52 nach Welle 1, davor 46 / 52). Der Verlauf hat
   seine Kopie beim Bauen selbst als solche vermerkt: „Die drei gehören bei
   der nächsten Glättung in EINE Regel." Hier ist sie.

   Der Übungsname wird nie gekürzt (Leitbild „Typografie") — er ist die
   wichtigste Information der Zeile. „Battle Ropes — lock…" ist ein Fehler,
   kein Layout. Deshalb bricht er um statt abzuschneiden; die Zeile wird dann
   eben zweizeilig, Dosierung und „Ändern" rutschen unter den Namen.

   Was die drei trennt, steht bei ihnen: der Einzug (Heute), die Breite neben
   dem Haken (Training), das Feedback am Ende (Verlauf). */
.uebungszeile {
  min-height: 52px;
  padding: 10px 0;
  flex-wrap: wrap;
  row-gap: 2px;
}
.uebungszeile > .name {
  flex: 1 1 100%;
  min-width: 0;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

/* ------------------------------------- 5 Slide-Muster und Icon-Grundmaß
   Genau EIN Slide-Muster in der ganzen App: der Eintritt in einen
   Vorgang (Heute → Training, Verlauf → Detail, Vorgangsleiste). Alles
   andere fadet. Kein Nachrücken von rechts, kein diagonaler Riss.
   -------------------------------------------------------------------- */
@keyframes von-unten {
  from { transform: translateY(100%); opacity: 0; }
}
.tritt-ein { animation: von-unten var(--d-slow) var(--e-arbeit) backwards; }

/* Grundmaß für die Inline-Icons aus js/icons.js (icon(name, cls) gibt
   <svg class="ic …">). Ohne diese Regel hätte ein Inline-SVG ohne
   Attribute die Ersatzgröße 300×150. */
.ic {
  width: 1em;
  height: 1em;
  flex: none;
  fill: currentColor;
  vertical-align: -0.125em;
}

/* =====================================================================
   Heute — Ansicht #/ (Stück 3)

   Alles hier baut nur zusammen, was oben schon steht: .plan-head trägt
   den Helden (Eyebrow · Titel · Ghost-Ziffer), .fakten die eine Zeile,
   .dotzeile den Ablauf, .datenzeile den Stand, die Vorgangsleiste den
   Start. Neu sind nur die Kleinteile, die es dafür noch nicht gab:
   das ⓘ, die ruhigen Chips, der Blockkopf und der ±-Stepper.
   ===================================================================== */

/* Der Aurora-Schein von .plan-head ist ein absolut gesetztes ::before und
   läge sonst über den Kindern, die keine eigene Position haben. Titel und
   Lede sind oben schon versorgt; das hier sind die neuen Nachbarn. */
.plan-head .fakten,
.plan-head .info-inhalt,
.plan-head .hint,
.plan-head .form-row { position: relative; }

/* Eine Stufe kleiner und enger als der Grundwert: „78 Min realistisch ·
   22 Übungen · gedrosselt" plus ⓘ braucht bei 390 px die 11 px, sonst
   rutscht das Zeichen aus der Zeile — und mit ihm der Zugang zu den
   Details. Gemessen, nicht geschätzt. */
.plan-head .fakten {
  margin-top: 18px;
  gap: 8px;
  font-size: var(--t-eyebrow-size);
}
.plan-head .fakten > * + *::before { margin-right: 8px; }

/* Weniger Abstand, wenn direkt darunter die Chips stehen: die gehören
   noch zum Plan und nicht zum nächsten Abschnitt. */
.plan-head:has(+ .chip-reihe) { padding-bottom: 14px; margin-bottom: 14px; }

/* --------------------------------------------------------------- ⓘ
   Sitzt am Ende der Fakten-Zeile und klappt darunter auf, was sonst
   einen eigenen Absatz bekäme. Der Trennpunkt der Fakten-Zeile entfällt
   davor — ein Zeichen ist kein Fakt. */
.info-knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 36px;
  height: 36px;
  margin: -9px -8px -9px -2px;
  padding: 0;
  border: none;
  background: none;
  color: var(--c-text-3);
  font-size: 15px;
  cursor: pointer;
}
.info-knopf:hover { color: var(--c-text); }
.info-knopf[aria-expanded="true"] { color: var(--tone); }
.info-knopf:focus-visible { outline: 2px solid var(--c-focus); outline-offset: -6px; }
.fakten > .info-knopf::before { content: none; }

/* Was das ⓘ aufklappt. Hieß .plan-details und wohnte damit unter dem Namen
   der Heute-Ansicht in drei fremden: Der Katalog klappt darunter seine
   Fußnote auf, das Konto die Erklärung zur Sicherung. Jetzt heißt es wie
   sein Knopf — .info-knopf öffnet .info-inhalt. */
.info-inhalt { margin-top: 10px; max-width: 94%; }
.info-inhalt .datenzeile { line-height: 1.65; }
.info-inhalt .datenzeile + .datenzeile { margin-top: 4px; }

/* ----------------------------------------------------------- Chips
   „Andere Übungen", „Anderer Fokus", „Plan wiederherstellen": Zugriffe
   auf den Plan, nicht der Vorgang. Sie dürfen nie so laut sein wie die
   Leiste unten — deshalb der vorhandene .chip aus dem Profil, unverändert.
   Hier steht nur, wie sie stehen, und wie leise das Icon davor ist.

   Auch dieser Name kam aus Heute (.plan-chips) und stand am Ende in sieben
   Ansichten — Profil, Konto, Katalog, Verlauf, Abschluss. Eine Reihe Chips
   ist keine Eigenschaft des Plans. */
.chip-reihe {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
}
.chip-reihe .chip .ic { font-size: 12px; color: var(--c-text-3); }

/* ---------------------------------------------------------- Ablauf
   Ein Block ist eine Dot-Leader-Zeile: Minuten · Titel …… Übungszahl.
   Tippen klappt die Übungen darunter auf; die Liste steht schon im
   Markup, sie wird nur sichtbar. */
.ablauf { margin-top: 2px; }
.ablauf-block + .ablauf-block { border-top: 1px solid var(--c-border-inset); }

/* Blocktitel: Schrift, Sperrung und Umbruch kommen aus .dotzeile--kopf — es
   ist dieselbe Abschnittszeile wie im Profil, im Konto, im Abschluss, im
   Tausch-Sheet und in der Vorschau des Assistenten. Die Sperrung ist auch
   dieselbe wie beim Blocktitel der Trainingsansicht (.bk-titel); die GRÖSSE
   bleibt verschieden: hier ist der Block eine Zeile in einer Liste von acht,
   dort die Überschrift des Abschnitts, durch den man sich arbeitet. */

/* Der Anstrengungspunkt und die Minutenzahl davor gibt es zweimal — im
   Ablauf der Heute-Ansicht (.ak-*) und im Blockkopf der Trainingsansicht
   (.tr-punkt / .bk-min). Zweimal dieselbe Sache, deshalb hier zusammen
   deklariert; getrennt bleibt nur, was am Fluss hängt (Heute steht der
   Punkt inline im Namen, im Training ist er ein Flex-Kind).

   Die Minutenzahl ist Text, die Anstrengung sagt der Punkt daneben
   (Leitbild §4). In der Effort-Farbe war sie eine dritte Akzentfarbe im
   Ablauf und machte die Liste bunter, als sie Bedeutung trägt. */
.ak-punkt,
.tr-punkt {
  display: inline-block;
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--effort-dot, var(--c-border));
}
.ak-punkt { margin-right: 11px; vertical-align: 1px; }
.tr-punkt { align-self: center; }

.ak-min,
.bk-min {
  min-width: 32px;
  color: var(--c-text-2);
  font-size: var(--t-caption-size);
  font-weight: 500;
  letter-spacing: 0;
}
.ak-min { display: inline-block; margin-right: 11px; }
.bk-min { flex: none; }
.ablauf-liste { padding: 0 0 10px; }
.ablauf-liste[hidden] { display: none; }
.ablauf-hinweis { margin: -6px 0 4px; }

/* Maße und Umbruch der Übungszeile stehen bei .uebungszeile im Baustein-Teil
   — es ist dieselbe Zeile wie im Training und im Verlauf. Hier steht nur der
   Einzug: In Heute rückt die Zeile gegen die Blockminuten ein. */
.plan-zeile { padding-left: 19px; padding-right: 2px; }
/* „Ändern" steht als Wort in der Zeile, wie das Inventar es verlangt — jetzt
   ist Platz dafür, weil der Name eine eigene Zeile bekommt. Das Stift-Icon
   davor macht die Zeile auf einen Blick als änderbar erkennbar. */
.plan-zeile > .pz-mehr {
  order: 3;
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-left: auto;
  font-family: var(--f-body);
  font-size: var(--t-eyebrow-size);
  color: var(--c-text-3);
}
.plan-zeile > .pz-mehr .ic { width: 11px; height: 11px; }
.plan-zeile:hover > .pz-mehr,
.plan-zeile:active > .pz-mehr { color: var(--c-accent-text); }

/* ----------------------------------------------------------- Stand
   Aus drei gleich großen Kacheln wird eine Datenzeile: Gewicht, Ziel und
   Einheiten treten hinter den Plan zurück (Leitbild §6.1). Die Zahlen
   bleiben hell, damit man sie im Vorbeigehen findet. */
.stand-zeile {
  margin-top: 0;
  line-height: 1.65;
}
.stand-zeile b { color: var(--c-text); font-weight: 600; }
/* Zweite Zeile: die Einordnung zum Wert darüber. Getrennt, weil sechs Werte
   hintereinander keine Datenzeile mehr sind, sondern eine Textwurst. */
.stand-zeile--klein {
  font-size: var(--t-caption-size);
  color: var(--c-text-3);
}

/* --------------------------------------------------------- Stepper
   Minuten eintragen, ohne die Tastatur zu holen (Leitbild §6.4). Das
   Feld bleibt daneben: wer die Zahl antippt, tippt sie selbst ein. */
.stepper {
  display: flex;
  align-items: center;
  gap: 10px;
}
.stepper .field { flex: 1 1 auto; max-width: 148px; height: 52px; }
.stepper-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 52px;
  height: 52px;
  padding: 0;
  border: 1px solid var(--c-border);
  border-radius: var(--r-m);
  background: var(--c-surface-2);
  color: var(--c-text);
  font-size: 15px;
  cursor: pointer;
}
.stepper-btn:hover { background: var(--c-surface-3); }
.stepper-btn:active { background: var(--c-surface-3); }
.stepper-btn:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }

/* =====================================================================
   ===== Training =====   Ansicht #/session (Stück 4)

   Hier lebt die Signatur. 23 gleich große Karten mit runden Häkchen sind
   zu drei Lautstärken geworden:

     Fahne    was durch ist — Strich in Tonfarbe, Text voll lesbar
     Held     was jetzt dran ist — Name groß, Dosierung als größte Zahl
     Liste    was noch kommt — Dot-Leader-Zeilen, leise, aber antippbar

   Gebaut wird ausschließlich mit den Bausteinen von oben: .durchstrich auf
   der Satzzeile, .dotzeile für jede Liste, .held für die Zahl, .fakten für
   die eine Zeile, .datenzeile für alles, was zurücktritt, .field und .chip
   für die Eingaben. Neu ist nur, was es dafür noch nicht gab: der ruckende
   Zähler, der Blocktrenner, der ±-Stepper der Satzzeile und der schwere
   Strich auf einem Namen, der umbrechen darf.
   ===================================================================== */

/* ------------------------------------------------------------- Zähler
   „Fortschritt ist gezählte Arbeit" (Leitbild §5): Der Zähler ruckt
   ziffernweise weiter, er zählt nie weich hoch. 140 ms in drei Stufen,
   und nur die Ziffer bewegt sich, die sich wirklich geändert hat. */
.tr-kopf { margin: 14px 0 18px; }

.tr-zaehler {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 8px;
}
.tz-ziffern {
  display: inline-flex;
  overflow: hidden;
  padding: 3px 0 1px;
  font-family: var(--f-display);
  font-size: 40px;
  font-weight: var(--t-numeral-w);
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--c-text);
}
.tz-ziffern i {
  display: inline-block;
  min-width: 0.6em;
  font-style: normal;
  text-align: center;
}
.tz-ziffern i.tz-strich { min-width: 0.42em; color: var(--c-text-3); }

@keyframes tz-ruck { from { transform: translateY(-100%); } }
.tz-ziffern i.ruckt { animation: tz-ruck 140ms steps(3, end); }

/* Das Wort „Übungen" neben dem Zähler ist das Label der Dreiergruppe und
   steht als .held-label im Baustein-Teil. */

/* Die Schiene ist der Anteil, nicht die Botschaft: 3 px, flach, still.
   Bewusst NICHT in der Tonfarbe des Typs: Während der Einheit führt die
   Effort-Farbe (Leitbild §4), und die Schiene zählt über alle Blöcke — sie
   gehört keinem einzelnen Anstrengungsgrad. */
.tr-schiene { display: block; height: 3px; background: var(--c-track); overflow: hidden; }
.tr-schiene i {
  display: block;
  height: 100%;
  background: var(--c-text-2);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--d-base) var(--e-out);
}

/* --------------------------------------------------------- Blocktrenner
   Ein Block ist kein Kasten mehr, sondern eine Haarlinie mit Punkt,
   Minuten, Titel und Stand. Die Übungen darunter sind die Sache. */
.tr-block + .tr-block { margin-top: 12px; }

.tr-blockkopf {
  display: flex;
  align-items: baseline;
  gap: 0 10px;
  padding: 16px 0 8px;
  border-top: 1px solid var(--c-border);
}
/* .tr-punkt und .bk-min stehen beim Ablauf der Heute-Ansicht — dort, wo
   dieselben zwei Bauteile zum ersten Mal auftauchen. */

/* Auch der Blocktitel wird nie gekürzt (Leitbild §3) — er bricht um. */
.bk-titel {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--f-display);
  font-size: var(--t-heading-size);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.bk-zahl { flex: none; font-size: var(--t-data-size); color: var(--c-text-3); }

.tr-blocknotiz {
  margin: 0 0 12px;
  font-size: var(--t-bodys-size);
  line-height: 1.45;
  color: var(--c-text-2);
}

/* Die Übungen eines Blocks stehen an einer Kante — das macht die Fahne
   der durchgestrichenen Zeilen als Gruppe lesbar. */
.tr-liste { padding-left: 14px; border-left: 1px solid var(--c-border-inset); }

.tr-gruppe {
  margin: 16px 0 4px;
  color: var(--c-text-3);
}

/* ------------------------------------------------------- Zirkel-Timer */
.tr-zirkel {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 14px;
  padding: 11px 14px;
  background: var(--c-surface);
  border-left: 3px solid var(--c-border-strong);
}
.tr-zirkel .tz-txt { flex: 1; min-width: 0; }
.tr-zirkel .t1 {
  display: block;
  font-family: var(--f-display);
  font-size: var(--t-bodys-size);
  font-weight: 700;
  letter-spacing: -0.01em;
}
.tr-zirkel .t2 { display: block; margin-top: 3px; font-size: var(--t-caption-size); color: var(--c-text-2); }
.tr-zirkel .btn { flex: none; }

/* ------------------------------------------- Die Nebenaktionen im Training
   „Start", „Anleitung", „Tauschen", „90 Sek Pause" waren gefüllte Flächen
   mit Rahmen und standen damit lauter im Bild als das Abhaken selbst —
   Fläche für die Aktionen, die man am seltensten braucht. Sie bleiben
   Knöpfe (Rahmen, Zielgröße, Fokusring), geben aber ihre Füllung ab. Die
   Hierarchie entscheidet sich damit dort, wo sie hingehört: Eine Fläche im
   Bild ist gefüllt, und das ist die Zeile, die als Nächstes drankommt. */
.tr-zirkel .btn.quiet,
.tr-aktionen .btn.quiet {
  background: none;
  border-color: var(--c-border-inset);
  color: var(--c-text-2);
  font-weight: 550;
}
.tr-zirkel .btn.quiet:hover,
.tr-aktionen .btn.quiet:hover { background: var(--c-surface-2); color: var(--c-text); }

/* --------------------------------------------- Körperanalyse-Terminal
   Vier Zahlen, die vom Display des Geräts abgetippt werden. Bewusst ohne
   ±-Stepper: Eine abgelesene Zahl tippt man ab, man tastet sich nicht in
   Schritten an sie heran — acht weitere Knöpfe wären hier nur Lärm. */
.tr-terminal { margin: 0 0 16px; }
.tr-messgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.tr-mess { display: flex; flex-direction: column; gap: 5px; }
.tm-label { color: var(--c-text-2); }
.tr-mess .field { height: 46px; border-radius: var(--r-m); }

/* ------------------------------------------------------ Übungszeilen
   Die zurückgetretene Übung: Dot-Leader-Zeile wie im Ablauf der
   Heute-Ansicht, daneben der Knopf, der die ganze Übung durchstreicht. */
.tr-ex { position: relative; scroll-margin: 92px 0 150px; }
.tr-ex + .tr-ex { border-top: 1px solid var(--c-border-inset); }

.tr-kopfzeile { display: flex; align-items: center; gap: 6px; }

/* Maße und Umbruch stehen bei .uebungszeile im Baustein-Teil — es ist
   dieselbe Zeile wie in Heute und im Verlauf. Hier steht nur, dass sie sich
   neben dem Haken die Breite nimmt, die übrig ist. */
.tr-zeile { flex: 1 1 auto; min-width: 0; }

.tr-zuletzt { margin: -4px 0 8px; font-size: var(--t-caption-size); }

/* -------------------------------------- Der schwere Strich auf dem Namen
   Der Balken aus .durchstrich ist EIN ::after-Element: Auf einem Namen,
   der umbrechen darf, läge er zwischen den Zeilen statt durch die Wörter.
   Deshalb zeichnet der schwere Strich hier als Verlauf, der sich pro
   Zeilenkasten wiederholt — gleiche Tonfarbe, gleiche Dauer, gleiche
   Klasse .ist-durch, gleicher Stempel-Ton (durchstreichen() liest
   .durchstrich--schwer), nur eben einmal pro Zeile. Auf der Satzzeile,
   dem Regelfall des Leitbilds, bleibt .durchstrich unverändert im Einsatz.

   Der Baustein hieß .tr-name und trug damit das Kürzel der Trainingsansicht,
   obwohl der Korrekturmodus des Verlaufs ihn mitbenutzt (js/views/history.js).
   Er heißt jetzt nach dem, was er tut, nicht nach dem Ort, an dem er zuerst
   gebraucht wurde. */
.strich-name {
  display: inline;
  position: relative;
  top: 0;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  background-image: linear-gradient(to bottom,
    transparent calc(50% - 3px), var(--tone) calc(50% - 3px),
    var(--tone) calc(50% + 2px), transparent calc(50% + 2px));
  background-repeat: no-repeat;
  background-size: 0 100%;
  transition: background-size var(--d-strich-schwer) var(--e-out),
              top var(--d-strich-schwer) var(--e-erfolg);
}
.strich-name.ist-durch { background-size: 100% 100%; top: 2px; }
/* Erledigtes tritt zurück, bleibt aber lesbar — dieselben 72 % wie beim
   Durchstrich der Satzzeile. Gedämpft wird nur die Schrift (color), nicht
   das Element: Der Balken liegt hier im Hintergrund und soll seine volle
   Tonfarbe behalten. Durch die halbdurchsichtigen Zeichen scheint er hindurch
   und fährt damit sichtbar durch das Wort, nicht daran vorbei. */
.strich-name.ist-durch { color: color-mix(in srgb, var(--c-text) 72%, transparent); }

/* Der Knopf, der die ganze Übung durchstreicht. Immer am rechten Ende der
   Namenszeile — beim Helden wie bei jeder leisen Zeile. */
.tr-haken {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid var(--c-border-strong);
  background: none;
  color: var(--c-text-3);
  font-size: 15px;
  cursor: pointer;
  transition: background-color var(--d-base) var(--e-arbeit),
              color var(--d-base) var(--e-arbeit);
}
.tr-haken:hover { color: var(--c-text); border-color: var(--c-text-3); }
.tr-haken:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }
/* Erledigt bestätigt der Knopf leise: Die Aussage der Zeile ist der Strich
   durch den Namen. Eine Spalte voller satter Tonflächen wäre lauter als die
   Signatur und machte aus der Fahne wieder eine Häkchenliste.

   Die 14-%-Fläche war trotzdem zu viel, seit die aktive Satzzeile den vollen
   Akzent trägt: Im Kraftblock ist die Tonfarbe genau dieses Orange, und ein
   48-px-Quadrat in Orange stand als zweitgrößte satte Fläche neben dem
   Griff — nachgemessen im Screenshot, nicht vermutet. Jetzt bleibt der
   Knopf ganz ohne Füllung. Satte Fläche trägt genau ein Element im Bild.

   Auch der Rahmen fällt weg, sobald abgehakt ist: Am Ende der Einheit
   standen sonst vier gerahmte Kästchen in einer Spalte untereinander — die
   Häkchenliste, die das Leitbild an dieser Stelle ausdrücklich nicht will.
   Der Rahmen ist die Aufforderung („hier kann man abhaken") und gehört
   deshalb dem offenen Zustand. Erledigt sagt der Strich, bestätigt der Haken,
   und die Trefferfläche von 48 px bleibt unverändert. */
.tr-haken.ist-an {
  background: none;
  border-color: transparent;
  color: var(--tone);
}

/* -------------------------------------------------- Die offene Rückmeldung
   Eine fertige Übung, die noch keine Bewertung hat, lässt die Frage stehen.
   Sie ist bewusst klein und ohne Fläche: Sie steht in der Fahne der
   erledigten Zeilen und darf den Blick nicht von dem wegziehen, was gerade
   dran ist. Antwortet man, zeichnet der Handler die Zeile neu und die Frage
   ist weg — die Rechnung ist beglichen. */
.tr-nachfrage {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin: 2px 0 10px;
}
.tn-frage {
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  color: var(--c-text-3);
}
.tr-nachfrage .chips { gap: 6px; }
.tr-nachfrage .chip {
  min-height: 34px;
  padding: 0 12px;
  font-size: var(--t-caption-size);
}

/* ------------------------------------------------------------- Der Held
   Die Übung, die jetzt dran ist. Sie trägt die Fläche ihres
   Anstrengungsgrads und eine Kante in derselben Farbe — aus drei Metern
   sieht man, wo man ist. */
.tr-held {
  margin: 6px 0 14px;
  padding: 12px 12px 16px;
  background: var(--effort-row, var(--c-surface));
  border-left: 3px solid var(--c-accent);
}
.tr-held + .tr-ex,
.tr-ex + .tr-held { border-top: none; }

/* Die Effort-Farbe (Leitbild „Farbe und Zustand") trägt im Training nur noch
   der Blockpunkt und der getönte Kartengrund. Kante und Heldenzahl haben sie
   abgegeben, und zwar aus zwei verschiedenen Gründen:

     Die Kante ist jetzt der Aktiv-Marker — sie sagt „hier bist du", und das
     muss in jedem Block dieselbe Farbe sein, sonst ist es kein Marker.

     Die Heldenzahl ist die größte Fläche des Screens und trug die stärkste
     Farbe, obwohl man sie nicht drücken kann. Das war eine Prioritätsinversion
     im Farbbudget, genau die, die das Leitbild an anderer Stelle rügt. Sie ist
     jetzt Text: eine Ansage, kein Ziel.

   Punkt = Anstrengung, Fläche = Aktion. Zwei Rollen, zwei Formen — das ist
   die Antwort auf „zwei gleiche Punkte dürfen nicht zwei Dinge bedeuten". */
.tr-jetzt {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 8px;
  color: var(--c-text-2);
}
/* Wo man im Plan steht — vorher unten auf der Leiste, und damit weg, sobald
   die Leiste den Countdown trug. Am Helden ist es immer da. */
.tr-jetzt .tj-wo { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.tr-jetzt .tj-nr {
  flex: none;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  color: var(--c-text-3);
  text-transform: none;
}
.tr-held .tr-kopfzeile { align-items: flex-start; gap: 10px; }
.tr-heldname {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--f-display);
  font-size: 28px;
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.026em;
}
/* Unter Last zählt die Zahl. 104 px liegen unter der Grenze der
   Leitbild-Tabelle (132 px bei 1–2 Ziffern) — hier steht darüber noch ein
   Name und darunter muss die Liste sichtbar bleiben. */
.tr-held .held { margin: 4px 0 0; color: var(--c-text); }
.tr-held .fakten { margin: 2px 0 0; }
.tr-held .tr-zuletzt { margin: 6px 0 0; }
.tr-held .tr-body { padding: 0; }

/* ----------------------------------------------------------- Arbeitsteil */
.tr-body { padding: 2px 0 16px; }

.tr-cue { margin: 10px 0 0; font-size: var(--t-bodys-size); line-height: 1.45; color: var(--c-text-2); }
.tr-notiz {
  margin: 8px 0 0;
  padding-left: 11px;
  border-left: 2px solid var(--c-border-strong);
  font-size: var(--t-bodys-size);
  line-height: 1.45;
  color: var(--c-text-2);
}

/* ------------------------------------------------------------ Satzzeilen
   Die Zeile, die gerade dran ist, ist der Griff der ganzen Ansicht — und
   war bis hierher als Tabellenzeile getarnt. Sie hatte alles, was einen
   Knopf ausmacht, außer dem Aussehen: 56 px Trefferfläche, volle Breite,
   ein aria-label, ein aria-pressed. Nur sehen konnte man das nicht, und
   „blind treffbar" setzt voraus, dass man das Ziel einmal sehend gefunden
   hat. Der lauteste Knopf im Bild war stattdessen „Start" am Zirkel-Timer —
   also drückt man den.

   Drei Merkmale beheben das, ohne die Signatur anzutasten:

     1. Das Kästchen links. Es steht auf JEDER Satzzeile, auch den ruhigen:
        „Das hier ist abhakbar." Es ist die Affordanz, nicht die Priorität.
     2. Die Akzentfläche auf genau EINER Zeile: „Und diese ist jetzt dran."
        Farbe kodiert hier einen Zustand, keine Dekoration (Leitbild
        „Farbe muss etwas sagen") — und zwar den einzigen, nach dem man
        mitten im Satz fragt.
     3. Die „danach:"-Zeile. Ein fremder Kritiker hat als eigenständigste
        Idee der App benannt, dass jeder Primärbutton seine Folge nennt.
        Die aktive Satzzeile IST jetzt dieser Primärbutton — in dieser App
        trägt nichts anderes eine danach-Zeile, also liest sie sich als Knopf.

   Die Dot-Leader-Zeile mit Durchstrich bleibt darunter unverändert: Der
   Zettel-Charakter stirbt nicht, er wird endlich gefunden.

   Darunter die ±-Stepper (Leitbild „Layout-Grammatik"): Eine iOS-Tastatur
   ist mit feuchten Fingern der teuerste Bedienschritt der App. Das Zahlenfeld
   bleibt daneben — wer die Zahl antippt, tippt sie weiterhin selbst. */
.tr-saetze { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.tr-satz + .tr-satz { border-top: 1px solid var(--c-border-inset); padding-top: 8px; }

.tr-satzzeile {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  border-radius: var(--r-s);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--d-base) var(--e-arbeit);
}
.tr-satzzeile:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }
/* --c-focus ist selbst Orange — auf der Akzentfläche verschwände der Ring.
   Dort läuft er innen und in der Schriftfarbe der Fläche. */
.tr-satzzeile.ist-griff:focus-visible { outline-color: var(--c-on-accent); outline-offset: -3px; }
.tr-satzzeile:not(.ist-griff):active { background: var(--c-surface-2); }

/* 16 px oben wie unten: Der Balken von .durchstrich sitzt bei 50 % der
   Zeilenhöhe — nur wenn der Text mittig im Kasten steht, fährt er durch die
   Wörter statt darunter entlang. Die 56 px Trefferfläche bleiben. */
.tsz-kopf { min-height: 56px; padding: 16px 0; }
.tsz-kopf > .name {
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--c-text-2);
}
.tsz-kopf > .wert {
  font-family: var(--f-data);
  font-size: var(--t-body-size);
  color: var(--c-text);
}
/* Durchgestrichen heißt geschafft, nicht gestrichen: Der Wert behält seine
   helle Textfarbe. Zurück tritt er nur über die 72 % des Bausteins — grau
   wäre bei Blendung und Schweiß das schlechteste Erledigt-Signal. */
.tsz-kopf.ist-durch > .wert { color: var(--c-text); }

/* Das Kästchen. Es steht vor dem Namen (order −1 fügt sich in die
   Reihenfolge der Dot-Leader-Zeile ein, ohne sie umzuschreiben) und ist
   mittig statt auf der Grundlinie ausgerichtet — ein 22-px-Quadrat auf
   baseline hinge schief. */
.tsz-box {
  order: -1;
  align-self: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 22px;
  height: 22px;
  border: 1.5px solid var(--c-text-3);
  border-radius: 5px;
  color: transparent;
  transition: border-color var(--d-base) var(--e-arbeit),
              background-color var(--d-base) var(--e-arbeit),
              color var(--d-base) var(--e-arbeit);
}
.tsz-box svg { width: 12px; height: 12px; }
/* Erledigt bestätigt das Kästchen leise — dieselbe Zurückhaltung wie beim
   Haken der ganzen Übung. Eine satt gefüllte Tonfläche wäre im Kraftblock
   exakt das Orange des Griffs: Erledigtes sähe aus wie Dranseiendes, und
   die eine Regel, die dieser Umbau aufstellt, wäre am ersten Satz kaputt.
   Satte Fläche trägt genau ein Element im Bild. */
.ist-durch > .tsz-box {
  border-color: var(--tone);
  background: color-mix(in srgb, var(--tone) 16%, transparent);
  color: var(--tone);
}

/* Die Folge. Sie steht nur auf der Zeile, die dran ist — auf den ruhigen
   Sätzen wäre sie Lärm, und ihre Aussage („danach: 90 Sek Pause") gilt
   ohnehin nur für den nächsten Griff. */
.tsz-danach {
  display: none;
  padding: 0 0 12px 32px;
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  line-height: 1.3;
}
.ist-griff > .tsz-danach { display: block; }

/* --------------------------------------------------- Die Zeile, die dran ist
   Genau eine Fläche im Bild trägt den Akzent, und es ist immer die, die als
   Nächstes gedrückt wird. Daraus wird eine Regel, die man in einem Satz
   lernt und danach nie wieder nachschlägt: Wo Orange ist, drücke ich.

   Deshalb ist es hier auch --c-accent und NICHT --effort: Die Anstrengung
   sagt der Blockpunkt (Punkt = Anstrengung, Fläche = Aktion). Wäre die
   Fläche effort-gefärbt, hieße Orange im Aufwärmblock Cyan und im Finisher
   Rot — und die Regel wäre wieder eine Legende statt einer Gewohnheit. */
.tr-satzzeile.ist-griff { background: var(--c-accent); }
.tr-satzzeile.ist-griff:active { background: var(--c-accent-press); }
.ist-griff > .tsz-kopf { padding-left: 10px; padding-right: 10px; }
.ist-griff > .tsz-kopf > .name,
.ist-griff > .tsz-kopf > .wert { color: var(--c-on-accent); }
.ist-griff > .tsz-kopf::before {
  border-bottom-color: color-mix(in srgb, var(--c-on-accent) 42%, transparent);
}
/* 85 %, nicht 78 %: Nachgerechnet liegt die danach-Zeile bei 78 % nur bei
   4,66:1 auf der Akzentfläche — über der Grenze, aber ohne Reserve. Mit 85 %
   sind es 5,26:1. Kontrast ist Pflicht, nicht Ziel (Leitbild-Checkliste). */
.ist-griff > .tsz-danach { color: color-mix(in srgb, var(--c-on-accent) 85%, transparent); }
.ist-griff .tsz-box { border-color: color-mix(in srgb, var(--c-on-accent) 72%, transparent); }

/* Auf der Akzentfläche kann der Balken nicht in der Tonfarbe fahren — im
   Kraftblock ist die Tonfarbe genau dieses Orange, der Strich wäre
   unsichtbar. Er nimmt die Schriftfarbe der Fläche und bleibt damit in
   jedem Block gleich gut lesbar. */
.ist-griff > .tsz-kopf.durchstrich::after { background: var(--c-on-accent); }
.ist-griff > .tsz-kopf.ist-durch > .wert { color: var(--c-on-accent); }
.ist-griff > .tsz-kopf.ist-durch > .tsz-box {
  border-color: var(--c-on-accent);
  background: var(--c-on-accent);
  color: var(--c-accent);
}

.tr-stepperzeile { display: flex; flex-wrap: wrap; gap: 8px; }
/* Unter der Akzentfläche klebten die Stepper an der Kante — die Fläche
   bringt ihren eigenen Rand mit, die Dot-Leader-Zeile hatte 16 px Polster. */
.tr-satzzeile.ist-griff + .tr-stepperzeile { margin-top: 9px; }
.tr-stepper { display: flex; align-items: center; gap: 4px; flex: 1 1 148px; min-width: 0; max-width: 236px; }
.tr-stepper .field {
  flex: 1 1 auto;
  min-width: 0;
  height: 46px;
  padding: 0 8px;
  border-radius: var(--r-m);
  background: var(--c-surface-2);
}
/* Zahl und Einheit gehören zusammen — sonst steht die 12 links am Rand und
   das „Wdh" 140 px weiter rechts, und man liest zweimal. */
.tr-stepper .field input { font-size: var(--t-bodys-size); text-align: right; }
.tr-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 44px;
  height: 46px;
  padding: 0;
  border: 1px solid var(--c-border);
  background: var(--c-surface-2);
  color: var(--c-text);
  font-size: 13px;
  cursor: pointer;
}
.tr-step:hover { background: var(--c-surface-3); }
.tr-step:active { background: var(--c-surface-3); }
.tr-step:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }

/* --------------------------------------------------------- Rückmeldung
   und die vier Knöpfe. Sie wachsen nicht auf gleiche Breite: „Anleitung"
   braucht weniger Platz als „90 Sek Pause", und vier gleich große Flächen
   erzählen keine Reihenfolge (Leitbild §6.1). */
.tr-body .feedback { margin-top: 18px; }
.tr-aktionen { margin-top: 16px; gap: 8px; }
.tr-aktionen .btn { flex: 0 1 auto; }
.tr-aktionen .btn .ic { width: 13px; height: 13px; color: var(--c-text-3); }

/* Der neue Held zieht auf, statt zu erscheinen.

   Ein Kritiker am Frame-Strip: „Das Nachrücken des neuen Helden ist keine
   Bewegung, sondern ein Teleport ohne Lagekontinuität — man kann nicht sehen,
   dass etwas weitergerückt ist, nur dass etwas anderes dasteht." Die kurze
   Aufwärtsbewegung stellt genau diese Kontinuität her: Der neue Held kommt
   von dort, wo er in der Liste stand. */
.zieht-auf { animation: held-zieht-auf var(--d-slow) var(--e-arbeit); }

@keyframes held-zieht-auf {
  from { opacity: .4; transform: translateY(14px); }
  to   { opacity: 1;  transform: none; }
}

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

/* =========================================================================
   ===== Timer =====

   Das Vollbild-Overlay der Intervalle. Hier ist der Zustand nicht ein
   Abzeichen am Rand, sondern das Layout selbst (Leitbild §4) — das Telefon
   liegt am Boden, man steht drei Meter weiter mit einer Kettlebell in der
   Hand und muss aus dem Augenwinkel wissen, ob gearbeitet oder pausiert
   wird:

     work     die ganze Fläche flutet in der Effort-Farbe des Blocks,
              Text in der dunklen Gegenfarbe
     rest     Fast-Schwarz, die Ziffern tragen die Farbe
     done     eigener Zustand in --c-ok
     bereit   Graphit — der Wartezustand vor der ersten Phase

   Die Farbe kommt aus --tone/--on-tone. Das ist keine Abkürzung, sondern
   genau das Paar, das .is-calm/.is-work/.is-peak setzen — die Effort-Klasse
   des Blocks hängt am Overlay, und damit führt während der Einheit die
   Anstrengung. Fehlt sie, bleibt [data-tone] der Einheit stehen.

   BEWUSST FLACH GEFÜLLT, kein Verlauf: --g-accent-lg endet bei #D23F05, und
   die dunkle Tinte hält darauf nur 4,14:1. Kontrast ist Pflicht, nicht Ziel.

   DREI EBENEN, und die Reihenfolge ist der ganze Punkt (Leitbild §5):

     .uhr-grund   steht still und zeigt, was eben noch da war
     .uhr-blatt   fährt mit dem neuen Zustand ein — das ist die Bewegung
     .uhr-werk    liegt über beidem und bewegt sich NIE — die Uhr

   Ein Kritiker hat die Vorgängerfassung an genau diesen zwei Stellen
   zerlegt: „Die Ziffer reist rund 400 px nach oben […] Wer keucht und kurz
   hochschaut, muss die Zahl verfolgen statt sie zu lesen" und „Bei t = 0
   ist die Arbeitsfläche schon leer. Die Pausenfläche schiebt sich über
   nichts." Beides ist hier strukturell behoben, nicht kosmetisch.
   ========================================================================= */

.uhr {
  position: fixed;
  inset: 0;
  z-index: 100;
  overflow: hidden;
  /* Fängt nur den Sub-Pixel-Spalt an der Kante der einfahrenden Fläche ab;
     gesehen wird sonst überall der Grund. */
  background: var(--c-bg);

  --uhr-tinte:   var(--on-tone);   /* Text auf der gefluteten Arbeitsfläche */
  --uhr-schrift: var(--tone);      /* Effort-Farbe als Schrift in der Pause */
}
.uhr[data-vorher="work"]   { background: var(--tone); }
.uhr[data-vorher="rest"]   { background: var(--c-bg-sunken); }
.uhr[data-vorher="done"]   { background: var(--c-ok); }

/* Zwei Kontrastkorrekturen an den Token-Paaren, beide gemessen:
   1. Dunkel: Weiß auf --c-peak (#FF3B3B) misst 3,54:1. Als Fläche geht das
      nicht durch — die dunkle Gegenfarbe hält 5,1:1.
   2. Hell: Die Effort-Farbe als SCHRIFT auf hellem Fast-Schwarz (#E4E8EE)
      reicht nicht (Orange 2,5:1). Dafür hat das System die dunklen Stufen
      derselben Rampe: 4,8 / 6,3 / 5,0:1. */
.uhr.is-peak { --uhr-tinte: #240707; }

[data-theme="light"] .uhr.is-peak { --uhr-tinte: var(--c-on-peak); }
[data-theme="light"] .uhr.is-work { --uhr-schrift: var(--tx-orange-700); }
[data-theme="light"] .uhr.is-calm { --uhr-schrift: var(--tx-calm-700); }
[data-theme="light"] .uhr.is-peak { --uhr-schrift: var(--tx-peak-600); }
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) .uhr.is-peak { --uhr-tinte: var(--c-on-peak); }
  :root:not([data-theme]) .uhr.is-work { --uhr-schrift: var(--tx-orange-700); }
  :root:not([data-theme]) .uhr.is-calm { --uhr-schrift: var(--tx-calm-700); }
  :root:not([data-theme]) .uhr.is-peak { --uhr-schrift: var(--tx-peak-600); }
}

/* Ein Zustand, ein Wertesatz — und der hängt an [data-stand] statt am
   Overlay. Der Grund trägt beim Wechsel den ALTEN Stand, das Blatt den
   neuen, jede Ziffer ihren eigenen: Dieselbe Regel färbt damit beide
   Seiten des Übergangs, ohne dass es die Regeln zweimal gäbe. */
.uhr [data-stand="bereit"] {
  --flaeche: var(--c-bg);        --schrift: var(--c-text);
  --ziffer:  var(--c-text);      --knopf-bg: var(--c-surface-2); --knopf-tx: var(--c-text);
}
.uhr [data-stand="work"] {
  --flaeche: var(--tone);        --schrift: var(--uhr-tinte);
  --ziffer:  var(--uhr-tinte);   --knopf-bg: var(--uhr-tinte);   --knopf-tx: var(--tone);
}
.uhr [data-stand="rest"] {
  --flaeche: var(--c-bg-sunken); --schrift: var(--c-text);
  --ziffer:  var(--uhr-schrift); --knopf-bg: var(--tone);        --knopf-tx: var(--uhr-tinte);
}
.uhr [data-stand="done"] {
  --flaeche: var(--c-ok);        --schrift: var(--c-on-ok);
  --ziffer:  var(--c-on-ok);     --knopf-bg: var(--c-on-ok);     --knopf-tx: var(--c-ok);
}

/* Grund und Blatt sind dieselbe Fläche in zwei Rollen: Der Grund hält die
   alte Last fest, bis sie zugedeckt ist, das Blatt bringt die neue. */
.uhr-grund,
.uhr-blatt {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--flaeche);
  color: var(--schrift);
}
.uhr-grund {
  opacity: 0;
  pointer-events: none;
}

/* Linksbündig wie jede andere Ansicht: EYEBROW · HELD · FAKTEN stehen in
   dieser App an einer Kante, und die Uhr ist kein Sonderfall.

   Der Bauplan aus §6: EYEBROW (wo bin ich) · Phasenname · das Band stehen
   oben als eine typografische Einheit. Die Uhr steht in der Mitte der
   freien Fläche, aber in einer eigenen Schicht (.uhr-werk). Ganz unten
   NEBEN (was danach kommt) und LEISTE — beide zu einem Block verbunden. */
.uhr-inhalt {
  flex: 1;
  min-height: 0;
  padding: calc(env(safe-area-inset-top) + 22px) var(--pad) 0;
}

.uhr-runde {
  color: inherit;
  margin: 0 0 10px;
}
.uhr-runde:empty { display: none; }
.uhr [data-stand="rest"] .uhr-runde { color: var(--c-text-2); }

/* Der Name der Station. Er wird nie gekürzt (Leitbild §3) — er bricht um. */
.uhr-phase {
  font-family: var(--f-display);
  font-size: clamp(26px, 8vw, 34px);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.08;
  margin: 0;
  text-wrap: balance;
}
/* In der Pause tritt das Phasenlabel zurück: Der Star ist dort, was gleich
   kommt, nicht das Wort „Wechsel". */
.uhr [data-stand="rest"] .uhr-phase { font-size: 24px; font-weight: 700; }

/* --------------------------------------------------- Das Phasenband
   Ein Segment je Phase, so breit wie die Phase lang ist. Pausen liegen
   flacher als Arbeitsphasen — die Strecke ist damit als Rhythmus lesbar.
   Die abgelaufene Phase ist durchgezogen; derselbe Griff wie beim
   Durchstrich (scaleX von links).

   Ein Kritiker nannte die Vorgängerfassung „gedecktes Türkis auf Cyan, auf
   zwei Meter praktisch unsichtbar", obwohl das Band die zweitwichtigste
   Information des Screens trägt. Drei Korrekturen, alle am Kontrast:
   16 statt 12 px hoch, die Füllung in voller Schriftfarbe statt gedeckt
   (gemessen 4,65–9,79:1 gegen die Fläche, in jedem Ton und beiden Themes),
   und das LAUFENDE Segment bekommt einen 2 px starken Innenrahmen in
   derselben Farbe — damit ist auf einen Blick klar, welches gerade zählt.
   Die leere Spur bleibt bei 26 % und damit leise: Sie sagt „noch nicht",
   und je leiser sie ist, desto klarer hebt sich der Füllstand ab. */
.uhr-band {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 16px;
  margin: 18px 0 0;
}
.uhr [data-stand="rest"] .uhr-band { color: var(--uhr-schrift); }
.uhr-band i {
  flex: 1 1 0;
  min-width: 3px;
  height: 100%;
  overflow: hidden;
  background: color-mix(in srgb, currentColor 26%, transparent);
}
.uhr-band i.seg-pause { height: 8px; }
.uhr-band i.laeuft { box-shadow: inset 0 0 0 2px currentColor; }
.uhr-band b {
  display: block;
  height: 100%;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
}
.uhr-band i.ist-durch b { transform: scaleX(1); }

/* --------------------------------------------------- Die Uhr
   Eigene Schicht über beiden Flächen, ohne Maus- und Tastenfang. Sie ist
   der einzige Grund, warum dieser Screen existiert — deshalb steht sie in
   der Mitte der freien Fläche und ist so groß, wie die gemessene Breite
   zulässt.

   Die Ziffer steht ZWEIMAL an exakt derselben Stelle: die alte und die
   neue. Beim Wechsel wird die alte von der Kante der einfahrenden Fläche
   weggeschnitten und die neue von ihr freigelegt — gleiche Dauer, gleiche
   Kurve wie das Blatt. Bewegt wird also nur der Grund; die Zahl steht
   still und wechselt Wert und Farbe. Deshalb sind beide Ziffern so groß
   wie der ganze Bildschirm: clip-path rechnet in Prozent der eigenen Box,
   und die muss dem Weg der Fläche entsprechen. Die Zahl selbst sitzt über
   die Innenabstände an ihrem Platz. */
.uhr-werk {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.uhr-zahl {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding:
    calc(env(safe-area-inset-top) + 190px)
    var(--pad)
    calc(env(safe-area-inset-bottom) + 268px);
  color: var(--ziffer);
}
.uhr-zahl--alt { visibility: hidden; }

/* Gemessen bei 390 px (Range über den Text, wie in demo-bausteine.html);
   Inhaltsbreite 342 px, jede Stufe endet bei 313 px, Rand 29 px:
     ≤ 2 Ziffern  „39"     248 px
     3 Ziffern    „1:24"   148 px
     ≥ 4 Ziffern  „12:24"  114 px
   Das ist mehr, als die Heldenzahl-Tabelle in §3 erlaubt — und genau das
   verlangt §3 hier auch: „Auf einer Vollbild-Fläche, die sonst nichts
   trägt, ist mehr nicht nur erlaubt, sondern Pflicht." */
.uz-wert {
  display: block;
  font-family: var(--f-display);
  font-weight: var(--t-numeral-w);
  line-height: var(--t-numeral-lh);
  letter-spacing: var(--t-numeral-ls);
  font-variant-numeric: tabular-nums;
}
.uhr-zahl--z2 .uz-wert { font-size: 248px; }
.uhr-zahl--z3 .uz-wert { font-size: 148px; }
.uhr-zahl--z4 .uz-wert { font-size: 114px; }

/* Die Einheit unter der Zahl. „39" allein beantwortet nicht, was da zählt.
   Die feste Höhe hält die Zahl an ihrem Platz, auch wenn hier im
   Pausenzustand größere Buchstaben stehen. */
.uz-einheit {
  display: flex;
  align-items: center;
  min-height: 34px;
  margin-top: 8px;
  font-family: var(--f-data);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: var(--t-eyebrow-ls);
  text-transform: uppercase;
}
.uhr.ist-pausiert .uz-einheit { font-size: 23px; letter-spacing: 0.1em; }

/* --------------------------------------------------- Vorschau und Bedienung
   Ein Kritiker fand „danach: Wechsel" als „14-pt-Waise" über dem
   Knopfblock hängen. Vorschau und Knöpfe sind jetzt EIN Block mit einer
   Haarlinie darüber — genau die Grammatik der Vorgangsleiste aus §2: das
   Verb, und darüber die Ankündigung, was danach kommt.

   Und die Gewichtung ist umgedreht. Vorher trug „Überspringen" die
   92-px-Fläche: „Fläche für die Aktion, die man am seltensten braucht."
   Jetzt liegt dort PAUSE — die eine Aktion, die man schwitzend wirklich
   braucht. „Überspringen" tritt in die Nebenzeile zurück, „Schluss" bleibt
   daneben als sichtbares Textziel (Leitbild §8: jeder Weg in jedem
   Zustand). */
.uhr-taten {
  display: flex;
  flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom);
  border-top: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}

.uhr-danach {
  margin: 0;
  padding: 14px var(--pad) 13px;
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  line-height: 1.3;
  color: inherit;
}
.uhr-danach .ud-wort { margin-right: 6px; }
.uhr-danach.ohne-wort .ud-wort { display: none; }
/* Am Ende gibt es kein „danach" mehr — dann steht dort auch keine leere
   Zeile, sondern die Fläche schließt direkt an die Haarlinie an. */
.uhr [data-stand="done"] .uhr-danach { display: none; }
.uhr [data-stand="rest"] .uhr-danach .ud-wort {
  display: block;
  margin: 0 0 4px;
  font-size: var(--t-eyebrow-size);
  letter-spacing: var(--t-eyebrow-ls);
  text-transform: uppercase;
  color: var(--c-text-2);
}
.uhr [data-stand="rest"] .uhr-danach .ud-name {
  display: block;
  font-family: var(--f-display);
  font-size: clamp(22px, 6.6vw, 27px);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.12;
  color: var(--c-text);
}

/* Die Primärfläche: volle Breite, 104 px, immer am selben Ort, in
   umgekehrter Flächenfarbe — blind treffbar in der Daumenzone. */
.uhr-halt {
  width: 100%;
  min-height: 104px;
  border: none;
  cursor: pointer;
  font-family: var(--f-display);
  font-size: 23px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--knopf-bg);
  color: var(--knopf-tx);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: filter var(--d-fast) var(--e-out);
}
.uhr-halt:active { filter: brightness(1.15); }

/* Die Nebenzeile: zwei Textziele, getrennt durch eine Linie, gefasst durch
   eine zweite darüber. Eine getönte Fläche stand hier schon — sie ist
   wieder raus, weil sie am gerenderten Pixel gemessen den Text auf
   3,99:1 (calm hell) drückte. Kontrast ist Pflicht, nicht Ziel. */
.uhr-neben {
  display: flex;
  border-top: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
.uhr-ueber,
.uhr-schluss {
  min-height: 62px;
  border: none;
  background: transparent;
  cursor: pointer;
  color: inherit;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.uhr-ueber {
  flex: 1 1 58%;
  font-family: var(--f-display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.uhr-schluss {
  flex: 1 1 42%;
  border-left: 1px solid color-mix(in srgb, currentColor 22%, transparent);
  font-family: var(--f-body);
  font-size: var(--t-body-size);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 5px;
}
.uhr-ueber[hidden] + .uhr-schluss { border-left: none; }

/* Der globale Fokusring ist orange — auf einer orangenen Fläche wäre er
   unsichtbar. Hier liegt er in der Schriftfarbe des Knopfs. */
.uhr button:focus-visible {
  outline: 3px solid currentColor;
  outline-offset: -6px;
  border-radius: 0;
}

/* --------------------------------------------------- Bewegung (Leitbild §5)
   Arbeit → Pause: die Pausenfläche schiebt sich von unten über die Arbeit.
                   Last ablegen.
   Pause → Arbeit: die Arbeitsfläche fällt von oben und landet mit 2 px
                   Überschwinger. Das Gewicht kommt zurück in die Hand.
   Der Überschwinger steckt im Keyframe, nicht in einer dritten Feder —
   gefahren wird beides mit --e-arbeit.

   Der Grund hält die alte Last die ersten 62 % der Strecke voll sichtbar
   und blendet erst in den letzten 38 % aus: „Eine Fläche, die sich über
   etwas schiebt, muss dieses Etwas beim Start noch vorfinden."

   Unter prefers-reduced-motion greift die globale Regel weiter oben: alle
   Animationen dauern 1 ms, die Flächenwechsel werden harte Schnitte, die
   Ziffer springt auf ihren Endzustand. Die Tick-Sounds und die Vibration
   bleiben, sie ersetzen dann die Bewegung. */
@keyframes uhr-hoch {
  from { transform: translateY(100%); }
  to   { transform: none; }
}
@keyframes uhr-faellt {
  from { transform: translateY(-100%); }
  72%  { transform: translateY(2px); }
  to   { transform: none; }
}
@keyframes uhr-geschafft {
  from { transform: scale(0.94); }
  to   { transform: none; }
}
@keyframes uhr-grund-weicht {
  0%, 62% { opacity: 1; }
  100%    { opacity: 0; }
}
.uhr-blatt.kommt-hoch  { animation: uhr-hoch   var(--d-slow) var(--e-arbeit); }
.uhr-blatt.faellt-rein { animation: uhr-faellt var(--d-slow) var(--e-arbeit); }
/* Geschafft ist die eine Stelle im Timer, an der die Erfolgsfeder fährt. */
.uhr-blatt.geschafft   { animation: uhr-geschafft 350ms var(--e-erfolg); }
.uhr-grund.geht        { animation: uhr-grund-weicht var(--d-slow) var(--e-arbeit) forwards; }

/* Die Ziffer bewegt sich nicht — sie wird von derselben Kante freigelegt
   bzw. weggeschnitten, die die Fläche schiebt. Gleiche Dauer, gleiche
   Kurve, gegenläufige Richtung. */
@keyframes zahl-von-unten     { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0); } }
@keyframes zahl-weicht-hoch   { from { clip-path: inset(0); } to { clip-path: inset(0 0 100% 0); } }
@keyframes zahl-von-oben      { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0); } }
@keyframes zahl-weicht-runter { from { clip-path: inset(0); } to { clip-path: inset(100% 0 0 0); } }
@keyframes zahl-blende-auf    { from { opacity: 0; } to { opacity: 1; } }
@keyframes zahl-blende-ab     { from { opacity: 1; } to { opacity: 0; } }

.uhr-zahl.zeigt-hoch   { animation: zahl-von-unten var(--d-slow) var(--e-arbeit); }
.uhr-zahl.zeigt-runter { animation: zahl-von-oben  var(--d-slow) var(--e-arbeit); }
.uhr-zahl.zeigt-blende { animation: zahl-blende-auf 350ms var(--e-arbeit); }

.uhr-zahl--alt.weicht-hoch,
.uhr-zahl--alt.weicht-runter,
.uhr-zahl--alt.weicht-blende { visibility: visible; }
.uhr-zahl--alt.weicht-hoch   { animation: zahl-weicht-hoch   var(--d-slow) var(--e-arbeit) forwards; }
.uhr-zahl--alt.weicht-runter { animation: zahl-weicht-runter var(--d-slow) var(--e-arbeit) forwards; }
.uhr-zahl--alt.weicht-blende { animation: zahl-blende-ab     350ms var(--e-arbeit) forwards; }

@keyframes uhr-puls {
  0%   { transform: scale(1); }
  32%  { transform: scale(1.04); }
  100% { transform: scale(1); }
}
/* Ursprung links, weil die Zahl linksbündig steht: Sie wächst in den
   Screen hinein, statt an ihrer Kante zu wackeln. Gepulst wird der Wert,
   nicht die Schicht — die Schicht steht. */
.uz-wert.pulst {
  animation: uhr-puls 420ms var(--e-arbeit);
  transform-origin: left center;
}

/* =========================================================================
   ===== Abschluss =====

   Die Ansicht nach der Einheit. Sie baut fast nur zusammen, was oben schon
   steht: .held trägt die Minuten, .durchstrich die Bilanz, .dotzeile die
   Aufklappzeile, .chip die beiden Ein-Tap-Fragen, die Vorgangsleiste den
   Abschluss. Neu ist nur, was es dafür noch nicht gab — größere Chips,
   die Vorschau der Aufklappzeile und der Kasten für den Bericht.

   Zustand „Geschafft" (Leitbild §4): Graphit, Text in --c-text, und
   --c-ok an genau zwei Stellen — dem Balken des Durchstrichs und dem
   Eyebrow der Zusammenfassung.
   ========================================================================= */

.ab-kopf { margin: 12px 0 4px; }
.ab-kopf .held { margin: 0; }

/* Der Satz der Zusammenfassung („X Minuten, Titel. Die Werte sind
   gespeichert …") steht im Wortlaut weiter da, nur nicht mehr in einer
   eigenen Karte: Eine Karte um einen Satz ist eine Kachel, keine Ordnung. */
.ab-satz { margin: 20px 0 0; max-width: 94%; }

/* --------------------------------------------------------- Die Bilanz
   „19/23 Übungen erledigt" — Erledigt-Quote und Übungszahl in EINER Zeile
   am Helden statt in zwei eigenen Kacheln daneben. Leitbild §1 nennt genau
   diese Zeile als den Ort, an dem der Durchstrich im Abschluss auftaucht;
   der Balken trägt hier --c-ok, weil er den Zustand des ganzen Screens
   meint („geschafft") und nicht die Farbe der Einheit. Die Schreibweise
   „19/23" ist dieselbe wie im Zähler der Trainingsansicht.

   Gestrichen wird nur die Quote, und die ist deshalb 26 px groß. Zwei
   Anläufe davor, beide im Screenshot durchgefallen: Über den ganzen Satz
   gelegt las der Balken sich als „zählt nicht" statt als „geschafft", und
   in 16-px-Text deckt ein 3-px-Balken die Zeichen zu, statt durch sie
   hindurchzufahren — bei einer Satzzeile von 56 px stimmt das Maß, in
   einer Lesezeile nicht. Bei 26 px sitzt er wie ein Filzstiftstrich, und
   der Text bleibt voll lesbar. Das ist die Bedingung der Signatur. */
.ab-bilanz {
  display: flex;
  align-items: baseline;
  gap: 9px;
  margin: 14px 0 0;
}
.ab-quote {
  --tone: var(--c-ok);
  padding-right: 2px;
  font-family: var(--f-display);
  font-size: 26px;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--c-text);
}
/* Der 2-px-Stempel versetzt sonst eine ganze Zeile; neben einem Wort, das
   stehen bleibt, sähe er nach Satzfehler aus statt nach Stempel. */
.ab-quote.ist-durch { top: 0; }

/* „Übungen erledigt" hinter der Quote ist dasselbe Label wie „Übungen" neben
   dem Zähler der Trainingsansicht — beide sind .held-label. */

/* ------------------------------------------------ Die Ein-Tap-Fragen
   Formulare nach Aufwand sortieren (Leitbild §6.4): Anstrengung und
   Studio-Auslastung setzt man verschwitzt in vier Sekunden — also stehen
   sie vorn und sind groß genug für einen Daumen, der gerade noch eine
   Kettlebell gehalten hat. 56 px hoch, über die volle Zeilenbreite
   verteilt. */
.ab-frage + .ab-frage { margin-top: 22px; }
.ab-frage .eyebrow { margin-bottom: 10px; }

.ab-chips { gap: 8px; }
.ab-chips .chip {
  flex: 1 1 auto;
  justify-content: center;
  min-height: 56px;
  padding: 0 14px;
  font-size: var(--t-body-size);
  color: var(--c-text-2);
}
.ab-chips .chip.on { color: var(--c-accent-text); }

/* ------------------------------------------- Die Aufklappzeile „Notizen"
   Die drei Textfelder bleiben vollständig, sie stehen nur hinter einer
   Zeile mit Vorschau (Leitbild §6.2). Rechts steht, wie viele beantwortet
   sind; darunter, was drinsteht — sonst wäre es eine Schublade, von der
   niemand weiß, ob etwas drin ist. */
.ab-klapp {
  margin-top: 26px;
  border-top: 1px solid var(--c-border-inset);
}
/* Der Name kommt aus .dotzeile--kopf: „Notizen" ist derselbe Abschnittskopf
   wie „Ziele" im Profil oder „Aufwärmen" im Ablauf. Er lief hier als
   einziger in der Fließschrift mit 600. */

/* Die Vorschau kürzt sich ab — sie ist ein Blick in die Schublade, nicht
   ihr Inhalt. (Übungs- und Blocktitel werden nie gekürzt; eine freie Notiz
   ist beides nicht.) */
.ab-vorschau {
  margin: -6px 0 0;
  color: var(--c-text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ab-vorschau[hidden] { display: none; }

.ab-notizen { padding-top: 14px; }
.ab-notizen[hidden] { display: none; }
.ab-notizen .form-row:last-child { margin-bottom: 0; }

/* ----------------------------------------------------- Rückweg und Rest
   „Zurück zum Training" bleibt in jedem Zustand erreichbar (Leitbild §8):
   Die Leiste ist mit dem Abschluss belegt, also steht der Rückweg als
   sichtbares Textziel in der Ansicht — leiser als die Leiste, wie jeder
   Zugriff, der nicht der Vorgang ist. */
.ab-taten { margin-top: 24px; }

.ab-sicherung { margin-top: 18px; }

/* Der Eyebrow der Zusammenfassung — die zweite und letzte Stelle, an der
   --c-ok auftaucht. Er kodiert einen Zustand: gespeichert. */
.ab-ok {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--c-ok);
}
.ab-ok .ic { width: 13px; height: 13px; }

/* -------------------------------------------------------- Der Bericht
   Bleibt vollständig sichtbar — er ist der Zweck dieses Screens, nicht
   sein Detail. Nur der Knopf steht davor: Kopieren ist der eine Tap,
   Lesen ist die Ausnahme (Leitbild §6.4). */
.ab-bericht {
  margin: 14px 0 0;
  padding: 16px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-l);
  background: var(--c-surface-2);
  font-family: var(--f-data);
  font-size: 12px;
  line-height: 1.55;
  color: var(--c-text-2);
  white-space: pre-wrap;
  overflow-x: auto;
}

/* =========================================================================
   ===== Rückschau =====

   Verlauf (#/history), einzelne Einheit (#/history/:id) und Fortschritt
   (#/stats). Drei Ansichten, ein Bauplan — und fast nur Bausteine, die oben
   schon stehen: .held trägt die eine Zahl, .durchstrich die erledigten Tage
   und Stufen, .dotzeile die Listen, .datenzeile alles, was zurücktritt.

   Keine Vorgangsleiste. Rückschau ist Nachschlagen, kein Vorgang
   (Leitbild §2) — das ist die Regel, nicht das Vergessen.

   Neu ist nur, was es dafür noch nicht gab: die Wochenleiste, die
   Stufenleiste des Klimmzug-Aufbaus und die Kante der Datumsmarke.
   ========================================================================= */

/* Der Kopf beider Verlauf-Ansichten. Dieselben 12 px wie .ab-kopf: Sie
   fallen mit dem 22-px-Rand der Topbar zusammen, damit der Eyebrow auf
   derselben Höhe steht wie in Heute, Training und Abschluss. */
.rs-kopf { margin: 12px 0 22px; }
.rs-kopf .held { margin: 0; }
.rs-kopf .held-label { margin-top: 6px; }
.rs-kopf .fakten { margin-top: 14px; }

/* Die Bilanz der Einzelansicht ist dieselbe wie im Abschluss (.ab-bilanz /
   .ab-quote) — es ist dieselbe Einheit, nur später betrachtet. Einzige
   Abweichung: Der Balken trägt hier die Tonfarbe des Typs statt --c-ok.
   Der Abschluss ist der Zustand „Geschafft"; der Verlauf ist der Ort, an
   dem man vergleicht, was für eine Einheit das war (Leitbild §4). */
.rs-kopf .ab-quote { --tone: inherit; }

/* ------------------------------------------------------ Die Wochenleiste
   „Verlauf: trainierte Wochentage in der Wochenleiste" (Leitbild §1). Der
   Balken fährt durch das Tageskürzel, in der Tonfarbe der Einheit, die an
   dem Tag lief. Wer nicht trainiert hat, steht ungestrichen da — das ist
   der ganze Unterschied, und er ist aus zwei Metern lesbar. */
.wochenleiste {
  display: flex;
  gap: 4px;
  margin: 18px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--c-border-inset);
}
.wo-tag {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 34px;
  font-family: var(--f-data);
  font-size: var(--t-eyebrow-size);
  font-style: normal;
  text-transform: uppercase;
  color: var(--c-text-3);
}
/* Die Sperrung hängt am Wort, nicht an der Zelle: Sonst schiebt der
   Nachlauf des letzten Zeichens die zentrierte Beschriftung nach links. */
.wo-tag b {
  font-weight: 500;
  letter-spacing: var(--t-eyebrow-ls);
  margin-right: calc(var(--t-eyebrow-ls) * -1);
}
.wo-tag.ist-heute { color: var(--c-text-2); }
.wo-tag.ist-heute b { font-weight: 700; }
.wo-tag.ist-durch { color: var(--c-text); }
/* Wie bei der Quote im Abschluss bleibt der 2-px-Stempel aus: In einer
   Reihe von sieben Zellen läse er sich als schiefe Zeile, nicht als
   Stempel. Der Balken allein sagt hier „geschafft". */
.wo-tag.durchstrich.ist-durch { top: 0; }

/* --------------------------------------------------- Das Wochenziel
   Die Segment-Anzeige und ihre Textzeile stehen zusammen in EINER
   Faktenzeile (Leitbild §6): ein Bild und seine Bildunterschrift, kein
   eigener Absatz. Zwischen beiden entfällt der Mittelpunkt — er trennt
   Werte, nicht eine Grafik von ihrer Erklärung. */
.wochenziel .goal-segs { margin: 0; flex: none; }
.wochenziel .goal-segs + *::before { content: none; }
.wochenziel .goal-segs i { width: 20px; height: 6px; flex: none; max-width: none; }

/* Gefüllt heißt „trainiert", nicht „geschafft": --c-ok ist echter Status
   (Leitbild §4) und gehört dem erreichten Wochenziel — nicht jedem
   einzelnen Segment auf dem Weg dahin. */
.goal-segs i.on { background: var(--c-text-2); box-shadow: none; }
/* Den Zustand trägt die Grafik, nicht der Satz: --c-ok hält als Text auf
   hellem Grund nur 4,48:1 (gemessen), als Fläche ist es weit über der
   Grafik-Grenze. Der Satz steht deshalb in voller Textfarbe. */
.wochenziel.ist-erreicht { color: var(--c-text); }
.wochenziel.ist-erreicht .goal-segs i.on { background: var(--c-ok); }

/* ------------------------------------------------------ Die Einheitenliste
   Datumsmarke, Titel, Dauer und Quote. Die Marke bekommt links die Kante in
   der Tonfarbe des Typs — vor der Einheit führt der Typ (Leitbild §4), und
   in einer Liste ist er das, was die Zeilen voneinander unterscheidet. */
.session-row {
  grid-template-columns: 52px 1fr auto;
  gap: 14px;
  padding: 12px 0;
  margin: 0;
}
.session-row + .session-row { border-top: 1px solid var(--c-border-inset); }
.session-row:active { background: var(--c-surface-2); }
/* Das Monatskürzel steht auf --c-surface-2, und dort hält --c-text-3 nur
   4,33:1 (an den gerenderten Pixeln gemessen, nicht aus dem Token
   abgelesen). Eine Stufe heller, und es sind 6,19:1. */
.session-row .date {
  border: none;
  border-left: 3px solid var(--tone);
  background: var(--c-surface-2);
  padding: 7px 2px 6px;
  color: var(--c-text-2);
}
.session-row .date b { font-size: 19px; font-weight: 600; }
.session-row .sr-mitte { min-width: 0; }
/* Der Titel wird nie gekürzt (Leitbild §3) — er bricht um. */
.session-row .t {
  display: block;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 600;
}
.session-row .m { display: block; margin-top: 4px; color: var(--c-text-3); }
.session-row .pct {
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  color: var(--c-text-2);
}
.session-row .pct small { font-size: 11px; color: var(--c-text-3); }

/* ----------------------------------------------------------------- Stand
   Serie, Trainingszeit und Ausgegeben treten hinter die Liste zurück — aber
   als Dot-Leader-Zeilen (Leitbild §6.3), nicht als eine Datenzeile wie in
   Heute: Dort sind es kurze Werte, hier liefen dieselben drei samt ihrer
   Erklärzeilen über fünf umbrechende Zeilen.

   Der Wert steht im vollen Kontrast — er ist die Aussage der Zeile. Das
   macht .dotzeile--auskunft, dieselbe Klasse wie im Impressum; der Name
   stand hier bis zur Glättung zusätzlich in 13 px Datenschrift und war
   damit ein anderes Bauteil als dieselbe Zeile zwei Ansichten weiter. */
.rs-stand { min-height: 0; padding: 10px 0; flex-wrap: wrap; row-gap: 2px; }
.rs-stand > .rs-unter {
  order: 4;
  flex: 1 1 100%;
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  color: var(--c-text-3);
}

/* -------------------------------------------------------- Der Gewichtsteil
   Kein eigener Kasten mehr: Eyebrow, Wert, Kurve, Datenzeile — dieselbe
   Dreiergruppe wie überall, nur kleiner. Die ausführliche Kurve steht im
   Fortschritt; hier ist sie der Seitenblick. */
.rs-gewicht { margin-top: 20px; }
.rs-wert {
  margin: 0;
  font-family: var(--f-display);
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--c-text);
}
.rs-wert small {
  font-family: var(--f-data);
  font-size: 14px;
  font-weight: 500;
  color: var(--c-text-2);
}

/* -------------------------------------------- Die Einheit im Verlauf
   Maße und Umbruch stehen bei .uebungszeile im Baustein-Teil — es ist
   dieselbe Zeile wie in Heute und im Training. Der dritte Regelsatz, den
   diese Ansicht dafür mitbrachte, ist weg; hier steht nur noch, was diese
   Ansicht mehr hat als die anderen beiden: das Feedback am Zeilenende. */
/* Das Feedback ist die leiseste Angabe der Zeile: eine Erinnerung daran,
   wie es sich angefühlt hat, kein Messwert. */
.vd-zeile > .vd-fb {
  order: 3;
  flex: none;
  margin-left: 12px;
  font-family: var(--f-data);
  font-size: var(--t-eyebrow-size);
  color: var(--c-text-3);
  white-space: nowrap;
}
.vd-notiz b { color: var(--c-text); font-weight: 600; }
.vd-dauer { margin-top: 4px; }

/* Als Verweis: derselbe Chip wie in Heute, nur eben ein Link. */
a.chip { text-decoration: none; }

/* ------------------------------------------------- Der Korrekturmodus
   Die Log-Korrektur war der letzte Rest der Fassung vor Traxx: grün
   gefüllte Karten mit orangem Rand, dazu grüne Dosierungen. Gebaut wird
   hier nichts Neues — die Zeilen bekommen die Form, die die
   Trainingsansicht schon hat: Haarlinie statt Kasten, Durchstrich auf dem
   Namen statt grüner Fläche, und der Haken bestätigt leise in der
   Tonfarbe (wie .tr-haken.ist-an).

   Warum überhaupt ein Strich: In diesem Modus stehen ALLE Übungen da, auch
   die nie abgehakten. Erst dadurch unterscheidet der Strich etwas — in der
   Leseansicht wären alle Zeilen gestrichen und keine sagte mehr etwas.

   .ex, .ex-head, .ex-name, .ex-dose, .ex-body, .sets, .set-row, .set-done
   und .set-del gibt es in der ganzen App nur noch hier. */
.ex {
  background: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
  margin: 0;
  padding: 16px 0;
}
.ex.done,
.ex.open-detail { border: none; background: none; }
.ex + .ex { border-top: 1px solid var(--c-border-inset); }
.ex-head { padding: 0; cursor: default; }
/* Der Übungsname ist eine Zeile, keine Überschrift — 22 px fett standen hier
   aus einer Zeit, in der jede Übung eine eigene Karte war. */
.ex-name {
  font-family: var(--f-body);
  font-size: var(--t-body-size);
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.35;
}
.ex.done .ex-name { color: var(--c-text); }
/* Der Strich fährt durch die Zeichen, er deckt sie nicht zu. Die 5 px von
   .strich-name sind für den 22-px-Namen der Trainingsansicht gerechnet; auf
   16 px sind das 31 % Deckung und der Name ist nicht mehr zu lesen. Hier
   gilt deshalb das Maß der Satzzeile: 3 px. */
.ex-name .strich-name {
  background-image: linear-gradient(to bottom,
    transparent calc(50% - 2px), var(--tone) calc(50% - 2px),
    var(--tone) calc(50% + 1px), transparent calc(50% + 1px));
}
.ex-dose { color: var(--c-text-2); }
.ex.done .ex-dose { color: var(--c-text-2); }
.ex-body { padding: 12px 0 0; border-top: none; }
/* Erledigt bestätigt der Haken leise: Die Aussage der Übung ist der Strich
   durch ihren Namen. Eine Spalte voller satter Flächen wäre lauter als die
   Signatur — dieselbe Begründung wie bei .tr-haken im Training.

   Bewusst dasselbe Dreigespann wie .chip.on (--c-accent-soft /
   --c-accent-soft-b / --c-accent-text) statt der Tonfarbe: Erstens steht
   der Haken im selben Formular wie die Feedback-Chips, zweitens hält die
   Tonfarbe auf ihrer eigenen 14-%-Fläche im Hellmodus nur 2,52:1
   (gemessen) — das Häkchen wäre dort kaum zu sehen. --c-accent-text ist
   die Antwort des Design-Systems auf „Akzent als Zeichen": 5,99:1 dunkel,
   5,29:1 hell. */
.set-done.on {
  background: var(--c-accent-soft);
  border-color: var(--c-accent-soft-b);
  color: var(--c-accent-text);
}

/* =====================================================================
   Fortschritt — die zwei erklärten Ziele oben
   ===================================================================== */

.fs-ziel { margin: 0; }
.fs-ziel .held { margin: 0; }
.fs-ziel .held-label { margin-top: 6px; }
.fs-ziel .datenzeile { margin-top: 12px; }
/* Der zweite Wunsch tritt hinter den ersten zurück: 88 px statt 132. Zwei
   gleich große Heldenzahlen untereinander wären wieder zwei gleich laute
   Dinge ohne Reihenfolge (Leitbild §6.1). */
.fs-ziel--zweit { margin-top: 30px; padding-top: 24px; border-top: 1px solid var(--c-border-inset); }
.fs-ziel--zweit .held { font-size: 88px; }

/* ------------------------------------------------------ Die Stufenleiste
   „Fünf Stufennamen nebeneinander" sind bei 390 px verboten (Leitbild §3):
   deutsche Übungsnamen passen dort nicht. Also trägt die Leiste die
   Nummern, ausgeschrieben steht genau eine Stufe — die aktuelle, als Label
   unter der Zahl.

   Erreicht heißt durchgestrichen, nicht abgehakt (Leitbild §1): Der Balken
   fährt in der Tonfarbe durch die Nummer, die Zelle bleibt lesbar. Die
   Stufe, auf der man gerade steht, bekommt zusätzlich den Innenrahmen —
   derselbe Griff wie beim laufenden Segment des Phasenbands. */
.stufen { display: flex; gap: 4px; margin: 18px 0 0; }
.stufe {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 30px;
  background: var(--c-surface-2);
  font-family: var(--f-data);
  font-size: var(--t-data-size);
  font-style: normal;
  font-variant-numeric: tabular-nums;
  /* Nicht --c-text-3: auf --c-surface-2 sind das an den gerenderten Pixeln
     4,33:1 und damit unter der Pflichtgrenze. --c-text-2 hält 6,19:1 und
     bleibt trotzdem leiser als die erreichten Stufen in --c-text. */
  color: var(--c-text-2);
}
.stufe b { font-weight: 500; }
/* Die erreichte Stufe hebt sich neutral ab, nicht getönt: Eine
   orangestichige Fläche unter einem orangen Balken wird milchig, und die
   Farbe des Screens gehört dem Strich. Heller heißt hier „schon gewesen". */
.stufe.ist-durch {
  background: var(--c-surface-3);
  color: var(--c-text);
}
.stufe.ist-jetzt { box-shadow: inset 0 0 0 2px var(--tone); }
/* Wie in der Wochenleiste: In einer Reihe von fünf Zellen ist der
   2-px-Stempel ein Satzfehler, kein Stempel. */
.stufe.durchstrich.ist-durch { top: 0; }

/* ------------------------------------------------ Kurve, Muster, Bestwerte
   Aus vier gestapelten Karten gleicher Lautstärke werden Abschnitte mit
   Überschrift — dieselbe Gliederung wie in Heute, Training und Abschluss. */
.stats-head { margin: 32px 0 12px; }
.stats-head > h2.section { margin: 0; }

/* Die Balken kodieren eine Menge, keinen Zustand — also kein Orange
   (Leitbild §4). Zehn orange Balken wären Farbe an Dekoration ausgegeben;
   die Farbe des Screens gehört dem Durchstrich der erreichten Stufen. */
.bar { height: 8px; border-radius: var(--r-s); background: var(--c-track); }
.bar i { background: var(--c-text-2); }
.bar-label { color: var(--c-text-2); }
.bar-val { color: var(--c-text-2); }

/* Der Bestwert ist ein Wert, keine Warnung: Text statt Akzent. Datum und
   Trainingszahl bleiben die leisere Stufe darunter. */
.fs-prs { margin-top: 2px; }
.fs-prs .pr-row { padding: 11px 0; border-bottom-color: var(--c-border-inset); }
.fs-prs .pr-row:last-of-type { border-bottom: none; }
.fs-prs .pr-best { color: var(--c-text); }
.fs-prs .btn.ghost { margin-top: 12px; }

/* =====================================================================
   ===== Katalog und Sheets =====   #/exercises, Anleitung, Tausch
                                    (Welle 2, Stück 9+10)

   Drei Bauteile, die zusammengehören: Der Katalog listet 89 Übungen, das
   Tausch-Sheet öffnet das Anleitung-Sheet, und beide Sheets erscheinen aus
   Heute wie aus dem Training. Nichts hier ist neu erfunden — .dotzeile,
   .fakten, .datenzeile, .ist-aus und der ⓘ stehen alle oben.
   ===================================================================== */

/* ---------------------------------------------------------- Der Kopf
   Kein eigener Eyebrow: Die Unterzeile der Topbar („89 Übungen") ist die
   Kontextzeile dieser Ansicht, ein zweites „SUCHEN" darüber wäre dieselbe
   Rolle zweimal. Held ist das Suchfeld — bei 89 Einträgen ist Finden die
   eine Antwort des Screens, und Fläche wird nach Wichtigkeit vergeben. */
.kat-kopf { margin-bottom: 16px; }

.kat-suche { position: relative; display: flex; align-items: center; }
.kat-suche input {
  width: 100%;
  min-height: 60px;
  padding: 0 52px 0 var(--s-6);
  background: var(--g-surface-2);
  border: 1px solid var(--c-border);
  border-radius: var(--r-m);
  color: var(--c-text);
  font-family: var(--f-body);
  font-size: var(--t-heading-size);
  font-weight: 500;
  letter-spacing: var(--t-heading-ls);
  -webkit-appearance: none;
  appearance: none;
  transition: border-color var(--d-base) var(--e-out), background-color var(--d-base) var(--e-out);
}
.kat-suche input::placeholder { color: var(--c-text-3); font-weight: 400; }
.kat-suche input:focus {
  outline: none;
  border-color: var(--c-accent);
  background: var(--c-surface);
}
/* Der eigene Knopf steht schon da — der native wäre der zweite daneben */
.kat-suche input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

.kat-leeren {
  position: absolute;
  right: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: none;
  background: none;
  color: var(--c-text-3);
  font-size: 15px;
  cursor: pointer;
}
.kat-leeren:hover { color: var(--c-text); }
.kat-leeren:focus-visible { outline: 2px solid var(--c-focus); outline-offset: -6px; }
.kat-leeren[hidden] { display: none; }

.kat-fakten { margin-top: 14px; }

/* ------------------------------------------------------- Die Liste
   89 Zeilen: Name links, Stand rechts, Punktlinie dazwischen — die
   Dot-Leader-Zeile ist genau dafür gemacht (Leitbild §6.3). Der Name wird
   nie gekürzt (§3); passt er nicht, bricht er um, und der Stand bleibt an
   der ersten Grundlinie stehen. */
.kat-liste { margin-top: 2px; }

/* Das Geländer für den Daumen. Reine Sortierhilfe, deshalb aria-hidden
   und in der leisesten Textstufe — sie ordnet, sie sagt nichts. */
.kat-buchstabe {
  font-family: var(--f-data);
  font-size: var(--t-eyebrow-size);
  letter-spacing: var(--t-eyebrow-ls);
  text-transform: uppercase;
  color: var(--c-text-3);
  margin: 22px 0 2px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--c-border-inset);
}
.kat-buchstabe:first-child { margin-top: 6px; }

.kat-eintrag {
  display: flex;
  align-items: center;
  gap: var(--s-5);
}
.kat-eintrag + .kat-eintrag { border-top: 1px solid var(--c-border-inset); }

.kat-zeile {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 56px;
  padding: 11px 0;
  flex-wrap: wrap;
  row-gap: 2px;
}
/* Der Übungsname bricht um, statt zu kürzen (§3). Ohne eigenes Gewicht: Er
   lief hier als einziger Übungsname der App mit 500, in Heute, Training und
   Verlauf mit 400 — derselbe Name, vier Ansichten, zwei Schnitte. */
.kat-zeile > .name {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}
/* Muster und Geräte: die Einordnung unter dem Namen, volle Breite */
.kat-zeile > .kat-meta {
  order: 4;
  flex: 1 1 100%;
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  line-height: 1.35;
  letter-spacing: 0;
  color: var(--c-text-3);
  white-space: normal;
}
/* Passt der Stand nicht mehr neben den Namen, rutscht er in die nächste
   Zeile — dort gehört er an denselben rechten Rand wie sonst. */
.kat-zeile > .wert { align-self: baseline; margin-left: auto; }

/* Dass eine Zeile ohne Wert keine Punktlinie bekommt (Übungen ohne
   Trainingshistorie), steht jetzt beim Baustein — es gilt überall. */

/* „fehlt: Kettlebells" — eine Angabe, keine Warnung (§4). Sie steht in der
   nächsthelleren Textstufe, damit man sie in der Zeile findet, ohne dass
   die Liste zu blinken anfängt. */
.kat-fehlt { color: var(--c-text-2); }

/* Der Schalter. Er ist ein Schalter geblieben (role=switch, aria-checked),
   zeigt seinen Zustand aber als eye / eye-slash. Grund: 89 akzentfarbene
   Pillen kodieren den Normalfall — Farbe ist ein Budget (§4), und dieser
   Zustand hat keinen Anspruch darauf. Das Zeichen ist das, das Leitbild §1
   für „ausgeschaltet" nennt. */
.kat-schalter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 46px;
  height: 46px;
  padding: 0;
  border: 1px solid var(--c-border);
  border-radius: var(--r-m);
  background: var(--c-surface-2);
  color: var(--c-text-2);
  font-size: 16px;
  cursor: pointer;
  transition: color var(--d-fast) var(--e-out), border-color var(--d-fast) var(--e-out);
}
.kat-schalter:hover { color: var(--c-text); border-color: var(--c-border-strong); }
.kat-schalter:active { background: var(--c-surface-3); }
.kat-schalter:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }
/* Aus: derselbe gestrichelte Rahmen wie um die Zeile — ein Zeichen, eine Bedeutung */
.kat-schalter[aria-checked="false"] {
  border-style: dashed;
  border-color: var(--c-border-strong);
  background: transparent;
  color: var(--c-text-2);
}

/* Ausgeschaltet — die Gegenprobe zum Durchstrich (Leitbild §1).
   KEIN Strich: gedämpfter Text, gestrichelter Rahmen, eye-slash. Der Strich
   sagt in dieser App immer „geschafft"; wer ihn hier setzt, nimmt der
   Signatur ihre Bedeutung. .ist-aus bringt Rahmen und Textfarbe schon mit,
   hier steht nur, wie die Zeile darin sitzt. */
.kat-eintrag.ist-aus {
  padding: 0 var(--s-5);
  margin: 6px 0;
  border-radius: var(--r-m);
}
/* Sonst überschriebe die Trennlinie der Liste (später im Blatt, höhere
   Spezifität) die Oberkante des gestrichelten Rahmens mit einer durchgezogenen. */
.kat-eintrag.ist-aus { border-top-style: dashed; }
.kat-eintrag.ist-aus + .kat-eintrag { border-top: none; }
.kat-eintrag.ist-aus .kat-meta,
.kat-eintrag.ist-aus .kat-fehlt { color: var(--c-text-3); }
.kat-eintrag.ist-aus .dotzeile::before { border-bottom-color: transparent; }

/* Gerät fehlt — der zweite abgeschwächte Zustand, und er darf nie wie der
   erste aussehen: kein Rahmen, kein Zeichen, nur eine Stufe leiser. Den
   hat nicht der Nutzer entschieden, sondern das Profil. */
.kat-eintrag.ohne-geraet:not(.ist-aus) .name { color: var(--c-text-2); }

/* =====================================================================
   Das Anleitung-Sheet — hier leben die Übungsbilder
   ===================================================================== */

/* Die Bühne: randlos über die volle Sheet-Breite statt als gerahmte Kachel
   in der Spalte. Das Bild ist der Grund, warum dieses Sheet anders aussieht
   als jedes andere — es bekommt die Fläche dafür (§3). Traxx Bold heißt
   flache Kanten, also fällt der 16-px-Radius mit dem Rahmen weg.
   Fehlt die Datei, räumt onerror in js/howto.js die Figure weg; das Sheet
   sieht dann aus wie eines ohne Illustration. Das muss so bleiben. */
.sheet .howto-figure {
  margin: 4px calc(var(--s-7) * -1) 16px;
  /* Genau das Seitenverhältnis der erzeugten Bilder (1080 × 725): So
     schneidet object-fit:cover nichts ab, und wenn eine Figur am Rand
     steht, bleibt sie im Bild. */
  aspect-ratio: 3 / 2;
  border-radius: 0;
  border-left: none;
  border-right: none;
  border-color: var(--c-border-inset);
}
.howto-cue { margin-bottom: 10px; }
.howto-zuletzt { margin: 0 0 4px; }

/* Die Schritte sind eine Folge, keine vier Aufzählungspunkte: Die Ziffern
   hängen an einer durchgehenden Linie, wie die Stationen eines Ablaufs.
   Und sie sind Text, nicht Akzent — die Nummer kodiert keinen Zustand,
   sondern die Reihenfolge (§4). Die einzige Farbe im Sheet gehört den
   Fehlern; das ist das, was wehtun kann. */
.howto-steps { margin-top: 2px; }
.howto-steps li { padding: 0 0 16px 42px; color: var(--c-text); }
.howto-steps li:last-child { padding-bottom: 2px; }
.howto-steps li::before {
  width: 26px;
  height: 26px;
  border-radius: var(--r-m);
  background: var(--c-surface-3);
  color: var(--c-text);
  font-family: var(--f-data);
  font-size: var(--t-caption-size);
  font-weight: 700;
}
/* Die Linie zwischen den Ziffern — sie macht aus Punkten eine Folge */
.howto-steps li::after {
  content: "";
  position: absolute;
  left: 13px;
  top: 28px;
  bottom: 4px;
  width: 1px;
  background: var(--c-border-strong);
}
.howto-steps li:last-child::after { content: none; }

/* Die Warnliste: EIN Block mit einer Kante in --c-warn statt N farbiger
   Zeichen. Der Text steht im vollen Kontrast, die Farbe trägt allein die
   Kante — so bleibt die Warnung in beiden Themes über 4,5:1. */
.howto-fehler {
  margin-top: 20px;
  padding: 12px 14px 14px;
  border-left: 3px solid var(--c-warn);
  background: var(--c-warn-soft);
  border-radius: 0 var(--r-m) var(--r-m) 0;
}
.howto-fehler .howto-label { margin: 0 0 8px; color: var(--c-text-2); }
.howto-fehler .howto-mistakes li { color: var(--c-text); padding-left: 18px; }
.howto-fehler .howto-mistakes li:last-child { padding-bottom: 0; }
.howto-fehler .howto-mistakes li::before {
  content: "";
  top: 8px;
  left: 2px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--c-warn);
}

/* =====================================================================
   Das Tausch-Sheet — nach Häufigkeit sortiert
   ===================================================================== */

.ts-meta { margin: 0 0 14px; }
.ts-lesen { margin-bottom: 4px; }
.ts-lesen .btn { flex: none; }
.ts-lesen .btn .ic { color: var(--c-text-3); }

/* Die Alternativen sind der Grund, warum das Sheet offen ist: volle Zeile,
   Name ungekürzt, rechts das Tauschzeichen.

   Raster, Maße und Farben stehen jetzt bei .alt selbst — die Klasse ist
   nicht mehr doppelt belegt (siehe dort). */

/* Kein Platz frei — der Hinweis bekommt denselben gestrichelten Rahmen wie
   ein ausgeschalteter Eintrag: hier ist etwas nicht verfügbar. */
.ts-leer {
  margin: 0;
  padding: 14px;
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--r-m);
}

/* Eine echte Warnung (§4): Sätze gehen verloren. Gleiche Bauform wie die
   Fehlerliste im Anleitung-Sheet — ein Block, eine Kante, voller Kontrast. */
.warnblock {
  display: flex;
  align-items: flex-start;
  gap: var(--s-4);
  margin: 0 0 10px;
  padding: 12px 14px;
  border-left: 3px solid var(--c-warn);
  border-radius: 0 var(--r-m) var(--r-m) 0;
  background: var(--c-warn-soft);
  color: var(--c-text);
  font-size: var(--t-bodys-size);
  line-height: 1.45;
}
.warnblock-ic { flex: none; color: var(--c-warn); font-size: 15px; line-height: 1.4; }

/* „Warum das hier steht" — die Begründung des Generators hinter einer
   Aufklappzeile statt als dritter Absatz (§6.2). Wortlaut unverändert. */
.ts-warum { margin-top: 18px; border-top: 1px solid var(--c-border-inset); }
.why-list { margin-top: 2px; padding-bottom: 6px; }
.why-list li::before { background: var(--c-text-3); }
.why-list[hidden] { display: none; }

/* Die Eingriffe zuletzt: verschieben, streichen, nie wieder. Sie sind der
   seltenere Teil des Sheets und stehen deshalb unter den Alternativen. */
.ts-eingriffe { margin-top: 20px; padding-top: 4px; border-top: 1px solid var(--c-border-inset); }
.ts-reihenfolge { margin-bottom: 12px; }
.ts-reihenfolge .btn .ic { font-size: 11px; color: var(--c-text-3); }
.ts-hoch { display: inline-flex; transform: rotate(180deg); }

.sheet .btn.block { margin-bottom: 10px; }
.ts-streichen, .ts-nie { justify-content: flex-start; gap: var(--s-5); }
.ts-streichen .ic, .ts-nie .ic { font-size: 15px; color: var(--c-text-3); }
.ts-nie { margin-bottom: 4px; }

/* =====================================================================
   ===== Profil, Konto, Onboarding =====   #/profile · #/login ·
                                           #/reset/:token · #/start ·
                                           #/impressum   (Welle 3, Rand)
   =====================================================================
   Die vier Randansichten haben ein gemeinsames Problem, das keine der
   zwölf Ansichten sonst hat: Sie bestehen aus vielen gleichwertigen
   Abschnitten. Das Profil hat neun, die Kontoverwaltung acht — vorher
   waren das Stapel gleich lauter Karten, durch die man scrollen musste,
   um zu sehen, was überhaupt eingestellt ist.

   Die Antwort ist EIN Bauteil, in beiden Ansichten dasselbe: ein
   Akkordeon aus Dot-Leader-Zeilen, in dem jede Zeile ihren Ist-Zustand
   als Wert trägt („Ausrüstung …… 16 von 18 aktiv"). Die zugeklappte
   Liste beantwortet damit schon die halbe Ansicht.

   Neu erfunden wird hier nichts: .dotzeile, .dz-chev, .chip,
   .chip-reihe, .stufen/.stufe, .warnblock, .stepper, .fakten, das ⓘ und
   die Vorgangsleiste stehen alle weiter oben. Hier steht nur, was es
   dafür noch nicht gab.
   ===================================================================== */

/* ------------------------------------------------------ Gemeinsame Teile */

/* Die erklärende Nebenzeile eines Abschnitts.
   Weder .lede noch .hint passen: .lede ist mit 16 px so laut wie die
   Abschnittsnamen darüber, .hint steht in --c-text-3 und ist für drei
   Sätze Erklärung zu leise. Dazwischen liegt diese Stufe — 14,5 px in
   --c-text-2, gemessen 7,55:1 auf --c-bg. */
.notiz {
  font-family: var(--f-body);
  font-size: var(--t-bodys-size);
  line-height: 1.5;
  color: var(--c-text-2);
  margin: 12px 0 0;
}
.notiz b { color: var(--c-text); font-weight: 600; }
/* Steht die Notiz VOR dem Formular, gehört ihr Rand nach unten */
.notiz--oben { margin: 0 0 14px; }

/* Textlinks (Impressum, Fußzeilen, „Passwort vergessen?").
   Bis hierher liefen sie in der Browser-Voreinstellung — Blau und Violett,
   die einzigen zwei Farben der App, die nichts bedeuten und in keinem
   Token stehen. Jetzt in --c-accent-text: gemessen 6,44:1 (dunkel) und
   4,93:1 (hell). Als <button> gebaut sieht er genauso aus wie als <a> —
   „Zurück zur Anmeldung" wechselt nur den Zustand, nicht die Route. */
.textlink {
  display: inline;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: var(--c-accent-text);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  cursor: pointer;
}
.textlink:hover { color: var(--c-accent-hover); }
.textlink:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; border-radius: 3px; }

/* „Alles löschen" und „Konto endgültig löschen" sind echter Status
   (Leitbild „Farbe und Zustand"): hier geht etwas endgültig weg. Die
   Farbe trägt deshalb die Kante und das Zeichen, NICHT der Text — roter
   Text auf hellem Grund hält 4,20:1 und fiele unter die Pflichtgrenze.
   So bleibt die Beschriftung im vollen Kontrast und die Warnung sichtbar. */
.chip.gefahr,
.btn.gefahr { border-color: var(--c-peak-soft-b); }
.chip.gefahr:hover,
.btn.gefahr:hover { border-color: var(--c-peak); background: var(--c-peak-soft); }
.chip-reihe .chip.gefahr .ic,
.btn.gefahr .ic { color: var(--c-peak); }

/* ------------------------------------------- Das Akkordeon der Abschnitte
   Profil (#/profile) und Kontoverwaltung (#/login, angemeldet) teilen es
   sich vollständig — wer die eine Ansicht kennt, kennt die andere. */
.pf-liste {
  margin-top: 2px;
  border-top: 1px solid var(--c-border-inset);
}
.pf-abschnitt + .pf-abschnitt { border-top: 1px solid var(--c-border-inset); }

/* Schrift, Sperrung und Umbruch des Abschnittsnamens kommen aus
   .dotzeile--kopf — dieselbe Abschnittszeile wie der Blocktitel im Ablauf.
   Der Ist-Zustand darf dagegen kürzen: Eine lange E-Mail-Adresse ist ein
   Wert, kein Name. Sie steht ausgeschrieben im Abschnitt darunter. */
.pf-kopf > .wert {
  /* flex: none statt 0 1 auto: Sonst schrumpfen Name UND Wert gemeinsam,
     sobald die Zeile eng wird — und dann stand da „Aktuelles Gewicht
     nachtragen" zweizeilig NEBEN einem abgeschnittenen „90,2 …". Jetzt
     behält der Wert seine Breite, gekappt wird erst ab 56 % der Zeile
     (lange E-Mail-Adressen), und der Name nimmt sich den Rest. */
  flex: none;
  max-width: 56%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pf-inhalt { padding: 2px 0 24px; }
.pf-inhalt[hidden] { display: none; }
.pf-inhalt > :last-child { margin-bottom: 0; }
.pf-letzte { margin-bottom: 0; }
/* Icons in den Abschnitts-Aktionen: so leise wie in den Plan-Chips */
.pf-inhalt .btn .ic { width: 14px; height: 14px; color: var(--c-text-3); }
/* Zwei Knöpfe nebeneinander sollen ihre Beschriftung tragen, nicht die
   halbe Zeile füllen — .btn-row .btn { flex: 1 } presst sie sonst auf
   gleiche Breite und der längere überläuft (white-space: nowrap). */
.pf-paar .btn { flex: 0 0 auto; }
.pf-syncstand { margin-top: 12px; }
.pf-fuss { margin-top: 30px; }

/* ------------------------------------------------------------ Konto (d)
   Angemeldet führt die Adresse: sie ist die eine Auskunft, wegen der man
   die Ansicht öffnet. Die Erklärung zur automatischen Sicherung steht im
   Wortlaut hinter dem ⓘ, nicht als eigener Absatz. */
.kt-ich {
  margin: 0 0 10px;
  font-size: var(--t-body-size);
  line-height: 1.5;
  color: var(--c-text-2);
  overflow-wrap: anywhere;
}
.kt-ich b { color: var(--c-text); font-weight: 600; }
.kt-fakten { margin-bottom: 0; }
.kt-taten { margin-top: 18px; }
.kt-warn { margin-top: 20px; }
.kt-verify { margin: 10px 0 2px; }
.kt-liste-abschnitte { margin-top: 26px; }

/* Stände und Geräte: Zeitstempel links, Menge oder Zeichen rechts, die
   Aktion daneben. Bewusst KEINE .dotzeile — deren Wert-Regel greift auf
   :last-child und würde den Knopf zur Datenspalte umfärben. */
.kt-liste { margin-top: 6px; }
.kt-eintrag {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  padding: 10px 0;
}
.kt-eintrag + .kt-eintrag { border-top: 1px solid var(--c-border-inset); }
.kt-wann {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--f-data);
  font-size: var(--t-data-size);
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
  color: var(--c-text);
}
.kt-menge {
  flex: none;
  font-family: var(--f-data);
  font-size: var(--t-data-size);
  font-variant-numeric: tabular-nums;
  color: var(--c-text-2);
}
.kt-eintrag .btn { flex: none; }
/* Fehlermeldungen bleiben Text: --c-warn hält im Hell-Theme nur 3,96:1 */
.kt-fehler { color: var(--c-text); }

/* ------------------------------------------------------- Konto (a, b, c) */
.kt-tabs { margin-bottom: 20px; }
.kt-ohne {
  margin-top: 26px;
  padding-top: 22px;
  border-top: 1px solid var(--c-border-inset);
}
.kt-ohne .btn.block { margin-bottom: 0; }
.kt-rueck { margin-top: 26px; }

/* =====================================================================
   Onboarding — der erste Eindruck (#/start)

   Mehr Ruhe und mehr Haltung als der Rest, aber dieselbe Sprache: die
   Schrittleiste ist die Stufenleiste des Fortschritts (erledigt =
   durchgestrichen), „Weiter" ist die Vorgangsleiste, die Chips sind die
   Chips, und die Vorschau der ersten Einheit ist der Kopf und der Ablauf
   der Heute-Ansicht.
   ===================================================================== */

/* Ohne Navigation rückt die Leiste dorthin, wo sonst die Nav-Pille sitzt —
   sonst schwebte sie über 90 px Leerraum. */
body[data-wizard] .vorgang { bottom: calc(env(safe-area-inset-bottom) + var(--nav-gap)); }
body[data-wizard].hat-vorgang #view {
  padding-bottom: calc(env(safe-area-inset-bottom) + var(--nav-gap) + var(--vorgang-h) + 30px);
}
/* Die Höhe des Assistenten rechnet gegen genau diesen Freiraum: Mit dem
   Grundwert (100dvh - 120px) plus Bodenfreiheit wäre jeder Schritt um
   rund 100 px scrollbar, auch der leere Willkommens-Schritt. */
body[data-wizard] .wizard {
  min-height: calc(100vh - 118px);
  min-height: calc(100dvh - 118px);
}

/* Schlanker als im Fortschritt: Dort steht die Leiste unter einer
   Heldenzahl, hier ist sie das erste Element des Screens und darf die
   Schlagzeile darunter nicht überstimmen. */
.ob-stufen { margin: 6px 0 30px; gap: 3px; }
.ob-stufen .stufe { height: 22px; font-size: var(--t-caption-size); }

/* Was neben der Leiste steht: Zurück, „Ich habe schon ein Konto", der Weg
   ins Konto. Halten ist Abkürzung, die Leiste ist nie der einzige Weg —
   diese Ziele bleiben sichtbar und stehen am Fuß des Schritts. */
.ob-neben {
  margin-top: auto;
  padding-top: 22px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.ob-alt {
  align-self: center;
  background: none;
  border: none;
  padding: 12px 10px;
  font-family: var(--f-body);
  font-size: var(--t-bodys-size);
  font-weight: 500;
  color: var(--c-text-2);
  text-decoration: none;
  text-align: center;
  cursor: pointer;
}
.ob-alt:hover { color: var(--c-text); }
.ob-alt:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }
.ob-konto.btn.block { margin-bottom: 0; }

.ob-start .wizard-brand { margin-top: 7vh; }
.ob-grid { margin-bottom: 0; }
.ob-feld { margin-bottom: 24px; }
.ob-feld:last-child { margin-bottom: 0; }
.ob-chips { gap: 8px; }
.ob-fussnote { margin-top: 14px; }
.ob-warn { margin: 16px 0 20px; }
.ob-feintuning { margin-top: 22px; }

/* Die Vorschau der ersten Einheit ist der Kopf aus Heute — inklusive
   Typ-Motiv als visuellem Anker. Nur die Schlagzeile bleibt eine Spur
   kleiner: Unter ihr steht der ganze Ablauf, nicht nur eine Fakten-Zeile.
   (.wizard h2 wäre sonst stärker als .plan-head h2 und machte 36 px.) */
.ob-plan .plan-head { padding-bottom: 16px; margin-bottom: 14px; }
.ob-plan .plan-head h2 {
  font-size: clamp(34px, 9.5vw, 46px);
  line-height: 1.03;
  letter-spacing: -0.035em;
  max-width: 84%;
  margin: 0 0 12px;
}
.ob-ablauf { border-top: 1px solid var(--c-border-inset); }
.ob-block { padding-bottom: 12px; }
/* Schrift und Umbruch des Blocktitels kommen aus .dotzeile--kopf; hier steht
   nur, dass die Zeile in der Vorschau enger sitzt als im echten Ablauf. */
.ob-blockkopf { min-height: 44px; padding-bottom: 4px; }
/* Alle Übungsnamen des Blocks — das Inventar verlangt sie vollständig.
   Eingerückt wie die Übungszeile im Ablauf der Heute-Ansicht. */
.ob-blockliste {
  margin: -2px 0 0;
  padding-left: 19px;
  line-height: 1.55;
}

/* =====================================================================
   Impressum (#/impressum) — Text, kein Werkzeug

   Es braucht nur die Typo-Grammatik: Eyebrow, der Name des Anbieters als
   Held, Kontakt und Register als Dot-Leader-Zeilen. Keine Karte, keine
   Leiste — hier wird nichts bedient.
   ===================================================================== */
.im-name {
  font-family: var(--f-display);
  font-size: clamp(27px, 7.6vw, 34px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.1;
  margin: 0 0 12px;
  max-width: 94%;
  text-wrap: balance;
}
.im-adresse {
  margin: 0 0 14px;
  font-size: var(--t-body-size);
  line-height: 1.55;
  color: var(--c-text-2);
}
.im-vertreten { margin: 0; }
.im-liste { margin-top: 22px; border-top: 1px solid var(--c-border-inset); }
/* Die Angabe rechts steht im vollen Kontrast: Sie IST die Auskunft. Das
   macht .dotzeile--auskunft im Baustein-Teil — dieselbe Klasse trägt den
   „Stand" im Verlauf, wo derselbe Fall vorlag. */
.im-rueck { margin-top: 28px; }
