/* ------------------------------------------------------------------ Tokens */
:root {
  /* Figma FriendlyPush, Frame "assets": brand and ui colors + illustration-colors. */
  --hue-teal:  #2f6f5e;
  --hue-brick: #833722;
  --hue-plum:  #7e446d;
  --hue-green: #478147;
  --hue-blue:  #226383;

  --bg: #fbf8f4;
  --surface: #ffffff;
  --ink: #241f1b;
  --ink-soft: #6c625a;
  --line: #e7ded3;
  /* Die Akzentfarbe steht in beiden Modi gleich: derselbe Teal trägt die
     Knöpfe und die Fläche der Übungskarte, eine aufgehellte Fassung im
     dunklen Modus hätte die beiden auseinanderlaufen lassen. */
  --accent: var(--hue-teal);
  --accent-ink: #ffffff;
  /* Derselbe Akzent, wo er nicht Fläche ist, sondern Schrift, Icon, Umriss
     oder eine kleine Marke: auf dunklem Grund trägt das Teal als Fläche,
     aber nicht als Zeichen (3:1 gegen den Hintergrund). Hell sind beide
     gleich, dunkel hebt diese Fassung ab. */
  --accent-text: var(--hue-teal);
  /* Die Töne der Sections. Sie kommen aus denselben Illustrations-Hues wie
     die Zeichnungen, damit die Seite und die Übungen dieselbe Palette
     tragen. Jede Section nimmt einen davon, keine zwei nebeneinander
     denselben. */
  --tint-teal: var(--hue-teal);
  --tint-brick: var(--hue-brick);
  --tint-plum: var(--hue-plum);
  --tint-green: var(--hue-green);
  --tint-blue: var(--hue-blue);
  /* Die Breite der Erklärungsseite. Kopfzeile und Bänder teilen sie, damit
     die Spalte über die ganze Länge an derselben Kante steht. */
  --lp-max: 980px;
  --radius: 22px;
  --radius-lg: 32px;

  /* Schriftgrösse als Faktor. Jede Grösse im Stylesheet rechnet damit, die
     Einstellungen setzen ihn auf dem Wurzelelement um. */
  --fs: 1;
  --shadow: 0 2px 4px rgb(36 31 27 / 4%), 0 12px 28px rgb(36 31 27 / 7%);


  /* Die Übungskarte hat einen festen Ton, unabhängig vom Slot und vom Modus:
     derselbe Teal, den die Platte in jeder illustration.svg trägt. Die Fläche
     der Karte und die Fläche der Zeichnung sind dieselbe Farbe, darum steht
     sie hier als Wert und nicht als Variable, die umschalten könnte. */
  --card-bg: #2f6f5e;

  /* Die Figur in der Zeichnung und die Trennlinie zwischen den beiden Posen:
     ebenfalls fest, sie liegen auf dem Teal und nicht auf dem Hintergrund. */
  --card-ink: #fbf8f4;

  /* Der Rahmen des Mockups auf der Landing: ein Gerät, also dunkel. Im
     dunklen Modus heller als die Fläche, sonst verschwände er darin. */
  --phone-frame: #15120f;
}

/* Der dunkle Modus kommt entweder vom System oder aus den Einstellungen.
   Beide Wege tragen dieselben Werte, darum steht der Block zweimal: ein
   Medienblock kann keine Deklarationen an eine zweite Bedingung weiterreichen.
   Wer «Hell» gewählt hat, nimmt der Systemabfrage ihr Recht. Ändert sich
   hier etwas, muss es in beiden Blöcken stehen. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    /* Aufgehellte Varianten der Figma-Hues, damit sie auf dunklen Flächen tragen. */
    --hue-teal-lift:  #7fc9b0;
    --hue-brick-lift: #e0987c;
    --hue-plum-lift:  #d496bd;
    --hue-green-lift: #96cf96;
    --hue-blue-lift:  #7cbcdc;

    --bg: #171412;
    --surface: #221e1b;
    --ink: #f3ece4;
    --ink-soft: #a79b8f;
    --line: #37302a;
    --accent-text: var(--hue-teal-lift);
    --tint-teal: var(--hue-teal-lift);
    --tint-brick: var(--hue-brick-lift);
    --tint-plum: var(--hue-plum-lift);
    --tint-green: var(--hue-green-lift);
    --tint-blue: var(--hue-blue-lift);
    --shadow: 0 2px 4px rgb(0 0 0 / 25%), 0 12px 28px rgb(0 0 0 / 35%);
    --phone-frame: #39312b;
  }
}

:root[data-theme='dark'] {
  --hue-teal-lift:  #7fc9b0;
  --hue-brick-lift: #e0987c;
  --hue-plum-lift:  #d496bd;
  --hue-green-lift: #96cf96;
  --hue-blue-lift:  #7cbcdc;

  --bg: #171412;
  --surface: #221e1b;
  --ink: #f3ece4;
  --ink-soft: #a79b8f;
  --line: #37302a;
  --accent-text: var(--hue-teal-lift);
  --tint-teal: var(--hue-teal-lift);
  --tint-brick: var(--hue-brick-lift);
  --tint-plum: var(--hue-plum-lift);
  --tint-green: var(--hue-green-lift);
  --tint-blue: var(--hue-blue-lift);
  --shadow: 0 2px 4px rgb(0 0 0 / 25%), 0 12px 28px rgb(0 0 0 / 35%);
  --phone-frame: #39312b;
}

/* Formularfelder, Scrollbalken und Auswahlfarben sollen dem gewählten Modus
   folgen, nicht dem des Systems. */
:root[data-theme='light'] { color-scheme: light; }
:root[data-theme='dark'] { color-scheme: dark; }

/* ------------------------------------------------------------------ Basis */
* { box-sizing: border-box; }

/* Manche Bausteine setzen display, das schlägt sonst das hidden-Attribut. */
[hidden] { display: none !important; }

/* iOS zoomt beim Hineintippen in jedes Feld unter 16px und bleibt danach
   zoomt stehen. 16px ist darum eine Untergrenze und keine Vorliebe: die
   Schriftgrösse aus den Einstellungen wirkt nur darüber hinaus. */
input, textarea, select { font-size: max(16px, 1em); }

/* Icons: Phosphor-Symbole aus dem Sprite in index.html. Sie messen in em,
   damit sie der Schriftgrösse ihres Knopfes folgen. */
.sprite { display: none; }

.icon {
  width: 1em;
  height: 1em;
  flex: 0 0 auto;
  fill: currentColor;
}

html, body {
  margin: 0;
  min-height: 100%;
}

body {
  background: var(--bg);
  color: var(--ink);
  font: 17px/1.5 ui-rounded, "SF Pro Rounded", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: calc(17px * var(--fs));
  -webkit-text-size-adjust: 100%;
  /* Doppeltipp zoomt nicht mehr. Aufziehen mit zwei Fingern bleibt möglich:
     das ist die Geste, auf die Leute angewiesen sind, die schlecht sehen. */
  touch-action: manipulation;
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  overflow-x: hidden;
}

#app {
  flex: 1;
  display: flex;
  justify-content: center;
  padding: 20px 16px 8px;
}

.screen {
  width: 100%;
  max-width: 460px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

h1 {
  font-size: calc(clamp(26px, 7vw, 34px) * var(--fs));
  line-height: 1.15;
  letter-spacing: -0.02em;
  margin: 0;
  text-wrap: balance;
}

/* Die Markenzeile trägt den Beta-Hinweis, darum als Zeile mit Lücke. */
.brand { display: flex; align-items: center; gap: 8px; }

.tag {
  padding: 2px 7px;
  border-radius: 999px;
  font-size: calc(11px * var(--fs));
  letter-spacing: 0.06em;
  background: color-mix(in srgb, var(--accent) 14%, var(--surface));
  color: var(--accent-text);
}

.eyebrow {
  margin: 0;
  font-size: calc(13px * var(--fs));
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.lead { margin: 0; color: var(--ink-soft); }

.note {
  margin: 0;
  font-size: calc(14px * var(--fs));
  color: var(--ink-soft);
  text-wrap: pretty;
}

.footer {
  padding: 16px;
  padding-bottom: max(16px, env(safe-area-inset-bottom));
  text-align: center;
  font-size: calc(12px * var(--fs));
  color: var(--ink-soft);
}

/* ------------------------------------------------------------------ Buttons */
.btn {
  appearance: none;
  border: 0;
  border-radius: 999px;
  padding: 16px 22px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: transform 120ms ease, filter 120ms ease,
    background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}

.btn:active:not(:disabled) { transform: scale(0.97); }

/* Ein Knopf, dem noch eine Angabe fehlt, wartet sichtbar: er bleibt stehen,
   wo er ist, und tritt zurück. Was fehlt, sagt das Feld darüber. */
.btn:disabled { cursor: default; opacity: 0.45; box-shadow: none; }

.btn-primary {
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: var(--shadow);
}

.btn-small { padding: 10px 16px; font-size: calc(15px * var(--fs)); }

/* Der zweite Weg auf einem Screen. Er trägt von sich aus eine Fläche, auch
   wenn sie leise ist: ohne sie war er nur ein Stück Text und als Knopf erst
   unter dem Zeiger zu erkennen, auf dem Handy also gar nicht. */
.btn-quiet {
  background: color-mix(in oklab, var(--ink) 8%, transparent);
  color: var(--ink-soft);
  padding: 12px 18px;
}

.btn-soft {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
}

:focus-visible {
  outline: 3px solid var(--accent-text);
  outline-offset: 3px;
}

/* ------------------------------------------------------------------ Hover */
/* Nur wo ein Zeiger ist. Auf dem Handy bliebe ein :hover nach dem Tippen
   stehen, bis woanders hingetippt wird, und die App ist zuerst eine
   Handy-App. Die Regeln stehen beieinander statt bei ihrem Element: so ist
   auf einen Blick zu sehen, was anfassbar ist und was nicht.

   Zwei Antworten reichen. Eine Fläche wird eine Spur heller oder dunkler,
   ein Text tritt von --ink-soft nach --ink vor. Mehr wäre Bewegung ohne
   Aussage; der Druck selbst quittiert schon mit scale(). */
@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover:not(:disabled),
  .chip[aria-pressed='true']:hover:not(:disabled) { filter: brightness(1.1); }

  .btn-soft:hover:not(:disabled) {
    background: color-mix(in oklab, var(--ink) 5%, var(--surface));
    border-color: color-mix(in oklab, var(--ink) 20%, var(--line));
  }

  .chip:hover:not([aria-pressed='true']):not(:disabled),
  .linkbtn-lead:hover,
  .helpbtn:hover {
    background: color-mix(in oklab, var(--ink) 8%, transparent);
    color: var(--ink);
  }

  /* Der zweite Weg trägt seine Fläche schon im Ruhezustand, also geht er
     unter dem Zeiger eine Stufe weiter statt sie erst zu bekommen. */
  .btn-quiet:hover:not(:disabled) {
    background: color-mix(in oklab, var(--ink) 15%, transparent);
    color: var(--ink);
  }

  /* Textknöpfe haben keine Fläche, die heller werden könnte. Sie bekommen
     die Unterstreichung, die ein Link im Fliesstext ohnehin trägt. */
  .peer-edit:hover { opacity: 1; }

  .linkbtn:hover {
    color: var(--ink);
    text-decoration: underline;
    text-underline-offset: 3px;
  }

  .sidequest .linkbtn:hover { color: var(--accent-text); }

  /* Das Zeichen der Kopfzeile, wenn es zurückführt. */
  .lp-brand[role='button']:hover { color: var(--ink); }

  /* Die Übungskarte ist gross. Sie hebt sich, statt sich einzufärben: die
     Illustration darin soll ihre Farbe behalten. */
  button.exercise-card:hover {
    border-color: color-mix(in oklab, var(--ink) 20%, var(--line));
    transform: translateY(-2px);
  }

  .faq summary:hover { color: var(--accent-text); }
  .faq summary:hover .faq-caret { color: inherit; }

  .disclose summary:hover { color: var(--ink); }

  .ex-cue-toggle:hover { color: var(--ink); }
  .ex-cue-toggle:hover .ex-cue-caret { color: inherit; }

  /* Die Zeitvorgabe ist antippbar, die Wiederholungen stehen nur da. Der
     Unterschied ist sonst nur im Zeiger zu sehen, hier auch in der Fläche. */
  .timer:hover { border-color: var(--accent-text); }

}

/* ------------------------------------------------------------------ Paar */
/* Der Push ist der Kern der App, deshalb bekommt er eine eigene Form:
   zwei Plätze, dazwischen eine Verbindung. Ein offener Platz ist die
   Affordance fürs Teilen, eine sichtbare Lücke. */
.pair {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0;
}

/* Das Paar läuft komplett in der Accent-Farbe: gefüllt, wer fertig ist,
   als getönter Umriss, wer noch fehlt. Dazwischen die Verbindung. */
.peer {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
  border-radius: 999px;
  padding: 8px 16px;
  font-size: calc(15px * var(--fs));
  font-weight: 600;
  color: var(--accent-text);
}

.peer b {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent-text) 45%, var(--surface));
  color: var(--surface);
  font-size: calc(11px * var(--fs));
  line-height: 1;
}

/* Das Feld im eigenen Platz des Paares. Keine zweite Form, nur eine Linie
   unter dem Text: der Platz ist schon die Form, die Linie sagt, dass hier
   etwas einzutragen ist. */
.peer-input {
  width: 9ch;
  min-width: 0;
  padding: 0;
  font: inherit;
  /* Unter 16px zoomt iOS beim Hineintippen in das Feld und bleibt danach
     zoomt stehen. Darum ist 16px hier die Untergrenze, nicht eine Vorliebe. */
  font-size: max(16px, calc(15px * var(--fs)));
  color: inherit;
  background: none;
  border: 0;
  border-bottom: 1px dashed currentColor;
}

.peer-input::placeholder { color: inherit; opacity: 0.5; }

/* Ein kurzes Wackeln, kein Zittern: vier kleine Ausschläge, dann steht es
   wieder. Es soll den Blick holen, nicht erschrecken. Wer wenig Bewegung
   will, sieht es gar nicht erst (siehe prefers-reduced-motion). */
@keyframes peer-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-3px); }
  40% { transform: translateX(3px); }
  60% { transform: translateX(-2px); }
  80% { transform: translateX(2px); }
}

.peer-input[data-shake] { animation: peer-shake 420ms ease both; }
.peer-input:focus-visible { outline-offset: 2px; }

.peer[data-done] { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
.peer[data-done] b { background: var(--accent-ink); color: var(--accent); }

.peer[data-pending] {
  background: none;
  border-style: dashed;
  border-color: var(--accent-text);
  color: color-mix(in srgb, var(--accent-text) 65%, var(--ink-soft));
  font-weight: 500;
}

/* Die Verbindung trägt die Farbe der Plätze, nicht einen eigenen Grauton:
   sie gehört zum Paar und ist nicht die Lücke dazwischen. */
.pair-link {
  flex: 0 0 22px;
  height: 3px;
  border-radius: 999px;
  background: var(--accent-text);
}

/* Passen die beiden Plätze nicht nebeneinander, stehen sie untereinander und
   die Verbindung kippt mit: senkrecht und auf der Achse der Marken, damit
   die zwei Plätze weiter als ein Paar zu lesen sind. Ob es reicht, hängt an
   den Namen und nicht an der Fensterbreite, darum misst app.js und setzt das
   Attribut, statt dass hier eine Medienabfrage riete. */
.pair[data-stacked] { flex-direction: column; align-items: flex-start; }

.pair[data-stacked] .pair-link {
  flex: 0 0 14px;
  width: 3px;
  height: 14px;
  /* Mitte der Marke im Platz: 16px Polsterung plus ihr halber Durchmesser. */
  margin-left: calc(16px + 9px - 1.5px);
}

/* Push-Karte auf der Startseite: die offene Geste, falls es eine gibt. Sie
   gehört zur Lage und steht darum im selben Band wie die Woche. Oben rechts
   sitzt das Kreuz, das sie wegräumt: ein Hinweis, keine Aufgabe. */
.pushcard {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-start;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  padding-right: 48px;
}

.pushcard p { margin: 0; font-size: calc(14px * var(--fs)); color: var(--ink-soft); text-wrap: pretty; }

.pushcard-hide {
  position: absolute;
  top: 4px;
  right: 4px;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  font-size: calc(16px * var(--fs));
}

/* Der Hinweis an die Person, die dich gepusht hat. Er steht in der
   Accent-Farbe, weil er die einzige Verbindung nach aussen ist. */
.pushback {
  margin: 0;
  padding: 14px 16px;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 10%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line));
  color: var(--accent-text);
  font-size: calc(15px * var(--fs));
  text-wrap: pretty;
}

.cheer { margin: 0; font-size: calc(44px * var(--fs)); line-height: 1; }

/* Die Zahlen stehen nach dem Push-Moment und treten einen Schritt zurück. */
.stats {
  display: flex;
  flex-direction: column;
  gap: 12px;
  border-top: 1px solid var(--line);
  padding-top: 18px;
}

/* Der Stift am eigenen Namen. Er steht immer da, solange der Name nur
   dasteht: ohne ihn wäre nicht zu sehen, dass er zu ändern ist. Leise, er
   ist ein Angebot und nicht der Schritt, auf den der Screen zuläuft. */
.peer-edit {
  transition: opacity 120ms ease;
  appearance: none;
  display: grid;
  place-items: center;
  margin: -4px -6px -4px 1px;
  padding: 4px 6px;
  background: none;
  border: 0;
  color: inherit;
  font-size: calc(14px * var(--fs));
  line-height: 1;
  opacity: 0.6;
  cursor: pointer;
}

/* Sidequest: eine Zeile, kein zweiter Aufruf. Der Hauptschritt ist getan,
   das hier ist ein Angebot und soll sich auch so anfühlen. */
.sidequest {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 8px;
  margin: 0;
  font-size: calc(13px * var(--fs));
  color: var(--ink-soft);
}

.sidequest .linkbtn {
  padding: 0;
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ------------------------------------------------------------------ Einstieg */
.intro { display: flex; flex-direction: column; gap: 18px; }

.steps {
  list-style: none;
  counter-reset: step;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.steps li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 30px 1fr;
  gap: 12px;
  align-items: start;
  color: var(--ink-soft);
  text-wrap: pretty;
}

.steps li::before {
  content: counter(step);
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink);
  font-size: calc(15px * var(--fs));
  font-weight: 700;
}

.steps li > span { display: block; }

.steps b { color: var(--ink); font-weight: 600; }

/* ------------------------------------------------------------------ Startseite */
/* Die Startseite trägt dieselben Bänder wie die Erklärung, damit ihre
   Bereiche sichtbar auseinanderliegen: ein Thema pro Band, die Kante trennt
   und nicht der Abstand. Die Bänder laufen über die ganze Breite, der Inhalt
   bleibt die schmale Spalte der App, und die Polsterung ist knapper als auf
   der Erklärung: die Seite wird bedient, nicht gelesen. */
body.is-home #app { padding: 0; }

.screen-home {
  max-width: none;
  gap: 0;
}

.screen-home .lp-inner {
  max-width: 460px;
  padding: 24px 16px;
  gap: 16px;
}

/* Oben hängt das erste Band an der Kopfzeile, unten endet die Seite ohne
   weitere Kante. */
.screen-home .lp-band-hero .lp-inner { padding-top: 20px; }
.screen-home .lp-band:last-child { border-bottom: 0; }

/* Der Start ist der Bereich, auf den es ankommt: mehr Luft, etwas mehr Ton
   und eine Kante auf beiden Seiten. */
.screen-home .lp-band-green {
  background: color-mix(in srgb, var(--band) 16%, var(--surface));
  border-top-color: color-mix(in srgb, var(--band) 34%, var(--line));
  border-bottom: 1px solid color-mix(in srgb, var(--band) 34%, var(--line));
}

/* Das Startband trägt den Kern der App, darum nimmt es ein knappes Drittel
   des Fensters und legt seinen Inhalt in die Mitte. */
.screen-home .lp-band-green .lp-inner {
  padding: 34px 16px 36px;
  gap: 18px;
  min-height: 30vh;
  justify-content: center;
}

/* Zwei Kanten übereinander wären eine zu viel. */
.screen-home .lp-band-green + .lp-band { border-top: 0; }

/* Die Zahl der Woche und ihr Zusatz gehören zusammen. Mit dem vollen Abstand
   des Bandes dazwischen läsen sie sich als zwei Aussagen. */
.weekline + .weekmore { margin-top: -6px; }
.lp-inner > .weekline + .weekmore { margin-top: -16px; }

/* --------------------------------------------------------- Einstellungen */
/* Drei Blöcke untereinander: Beschriftung, Bedienelement, bei Bedarf ein
   Hinweis. Keine Karten und keine Trennlinien, der Abstand reicht. */
.setting { display: flex; flex-direction: column; gap: 10px; }

.setting-label {
  margin: 0;
  font-size: calc(14px * var(--fs));
  font-weight: 600;
  color: var(--ink-soft);
}

/* Ein Feld mit eigener Form, anders als das Namensfeld im Paar: hier steht
   es für sich und braucht eine Fläche, an der man sieht, wo getippt wird. */
.field {
  width: 100%;
  padding: 12px 16px;
  font: inherit;
  font-size: max(16px, calc(17px * var(--fs)));
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
}

.field:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }

/* Die Gruppen stehen hier immer über die ganze Spalte: drei Lagen
   nebeneinander, alle gleich gross zu treffen. */
.screen-settings .chips { display: flex; align-self: stretch; }

/* Ein Ausklapper mitten im Text, dieselbe Form wie die Fragen auf der
   Erklärung, nur kleiner und ohne Liste drumherum. */
.disclose { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }

.disclose summary {
  transition: color 120ms ease;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 2px;
  font-size: calc(14px * var(--fs));
  font-weight: 600;
  color: var(--ink-soft);
  cursor: pointer;
  list-style: none;
}

.disclose summary::-webkit-details-marker { display: none; }

.disclose-caret {
  font-size: calc(16px * var(--fs));
  transition: transform 150ms ease;
}

/* Nur der eigene Pfeil dreht, nicht der des inneren Ausklappers. */
.disclose[open] > summary .disclose-caret { transform: rotate(180deg); }

.disclose-body { padding: 0 2px 14px; display: flex; flex-direction: column; gap: 14px; }

/* Der innere Ausklapper hängt an der Kante des äusseren, eine eigene untere
   wäre eine Linie zu viel. */
.disclose-inner { border-bottom: 0; }

/* Begriff und Wert. Auf schmalen Geräten untereinander, sonst bliebe für die
   Werte eine Spalte von zwei Zeichen Breite. */
.datalist {
  margin: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px 16px;
  font-size: calc(14px * var(--fs));
}

.datalist dt { color: var(--ink-soft); }
.datalist dd { margin: 0 0 8px; text-wrap: pretty; }

@media (min-width: 420px) {
  .datalist { grid-template-columns: max-content 1fr; align-items: baseline; }
  .datalist dd { margin: 0; }
}

/* Der Eintrag im Original. Er bricht um, sonst schöbe er die Spalte auf. */
.dataraw {
  margin: 0;
  padding: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: calc(12px * var(--fs));
  line-height: 1.5;
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}


/* ------------------------------------------------------------------ Landing */
/* Der Einstieg, und ab dem Fragezeichen die Erklärung. Er wird gelesen, nicht
   bedient, darum darf er breiter und luftiger sein als die App. Er läuft in
   Bändern über die ganze Breite, abwechselnd getönt: ein Thema pro Band, die
   Kante trennt und nicht der Abstand. Alles andere bleibt die App, er erbt
   Knöpfe, Paar und Schritte und bringt nur eigene Flächen mit. */

/* Die Bänder brauchen die ganze Breite, darum gibt der Rahmen der App seine
   Polsterung ab, solange die Landing steht. */
body.is-landing #app { padding: 0; }

.screen-landing {
  max-width: none;
  gap: 0;
}

.screen-landing h2 {
  margin: 0;
  font-size: calc(clamp(21px, 5.4vw, 27px) * var(--fs));
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

/* -------------------------------------------------------- Kopfzeile */
/* Zurück, Marke, die Stellen, die man im Betrieb sucht, und der Start. Sie
   klebt oben: die Seite ist lang, und der Weg zurück soll nicht am oberen
   Ende liegen. Auf dem Handy trägt sie eine Zeile, die Sprünge kommen erst
   dazu, wenn die Breite dafür da ist. */
.lp-navbar {
  position: sticky;
  top: 0;
  z-index: 6;
  background: color-mix(in oklab, var(--bg) 86%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}

.lp-nav {
  width: 100%;
  max-width: var(--lp-max);
  margin: 0 auto;
  padding: 9px 16px;
  display: flex;
  align-items: center;
  gap: 14px;
}

/* Marke ist Zeichen plus Wortmarke, dasselbe Zeichen wie auf dem Homescreen. */
.lp-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-right: auto;
  min-width: 0;
}

.lp-logo {
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
  border-radius: 8px;
}

/* Das Zeichen führt zurück, wo es ein Zurück gibt (app.js setzt die Rolle).
   Ohne Rolle steht es nur da und sieht auch so aus. */
.lp-brand[role='button'] { cursor: pointer; }

.lp-jump { display: none; gap: 18px; margin-right: 12px; }

.lp-navcta { padding: 9px 16px; font-size: calc(14px * var(--fs)); box-shadow: none; }

/* -------------------------------------------------------- Bänder */
.lp-band {
  width: 100%;
  border-top: 1px solid var(--line);
}

/* Jede Section trägt einen eigenen Ton, damit man beim Scrollen sieht, dass
   ein neues Thema anfängt, und nicht nur eine neue Zeile. Der Ton steht als
   --band im Band; Fläche, Nummern und Ziffern leiten sich daraus ab, und wer
   eine Section umfärbt, tauscht eine Klasse. Zwei Nachbarn tragen nie
   denselben Ton, Grün umklammert die Seite: der Kern und der Abschluss. */
.lp-band-teal { --band: var(--tint-teal); }
.lp-band-brick { --band: var(--tint-brick); }
.lp-band-plum { --band: var(--tint-plum); }
.lp-band-green { --band: var(--tint-green); }
.lp-band-blue { --band: var(--tint-blue); }

.lp-band-teal,
.lp-band-brick,
.lp-band-plum,
.lp-band-green,
.lp-band-blue {
  background: color-mix(in srgb, var(--band) 10%, var(--surface));
  border-top-color: color-mix(in srgb, var(--band) 22%, var(--line));
}

/* Das helle Band ohne Ton. Es steht zwischen zwei getönten und lässt die
   Seite atmen. */
.lp-band-soft { background: var(--surface); }

/* Die Ziffern der Schritte nehmen den Ton ihrer Section. */
.lp-band .steps li::before {
  background: var(--bg);
  border-color: color-mix(in srgb, var(--band, var(--accent)) 30%, var(--line));
  color: var(--band, var(--accent-text));
}

/* Der Hero hängt an der Kopfzeile, zwischen beiden gehört keine Kante. */
.lp-band-hero { border-top: 0; }

.lp-band:last-child { border-bottom: 1px solid var(--line); }

/* Der Inhalt bleibt eine Spalte in der Mitte, egal wie breit das Band ist. */
.lp-inner {
  width: 100%;
  max-width: var(--lp-max);
  margin: 0 auto;
  padding: 52px 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.lp-band-hero .lp-inner { padding-top: 40px; gap: 24px; }

/* Der Text des Heros ist eine eigene Spalte, damit er neben dem Mockup als
   Block steht und nicht Zeile für Zeile auf dessen Höhe verteilt wird. */
.lp-hero-text { display: flex; flex-direction: column; gap: 18px; }

/* Label und Titel gehören zusammen, darum stehen sie enger als der Rest. */
.lp-inner > .eyebrow + h2 { margin-top: -8px; }

/* Ein einzelner Knopf im Band liegt auf dem Handy über die ganze Breite. */
.lp-cta { display: flex; flex-direction: column; gap: 10px; }

/* -------------------------------------------------------- Hero */
/* Der Satz, der die App erklärt, wenn man nur einen liest. */
.lp-claim {
  margin: 0;
  font-size: calc(clamp(17px, 4.6vw, 20px) * var(--fs));
  line-height: 1.45;
  color: var(--ink-soft);
  text-wrap: pretty;
}

.lp-badges { letter-spacing: 0.01em; }

/* -------------------------------------------------------- Mockup */
/* Ein Rahmen, darin derselbe Übungsscreen, den die App zeigt: Kopf,
   Zeichnung, Leiste mit Fortschritt, Timer und Weiter. Nachgebaut und nicht
   abfotografiert, damit er mit den Farben und Formen der App mitläuft. Die
   Masse sind kleiner als in der App, darum eigene Klassen statt der echten.
   Der Rahmen bleibt in beiden Modi dunkel: ein Gerät, kein Papier. */
/* Die Bühne für die zwei Geräte. Sie ist breiter als ein Gerät: das vordere
   steht rechts, das hintere links darunter, und beide überlappen. */
.lp-phones {
  position: relative;
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
}

.lp-phone {
  position: relative;
  z-index: 1;
  /* Das vordere Gerät steht rechts und lässt links Platz für das hintere.
     Als Anteil der Bühne, damit beide auch auf einem schmalen Handy
     nebeneinander Platz haben und nicht über den Rand laufen. */
  width: 78%;
  max-width: 300px;
  margin: 4px 0 0 auto;
  padding: 10px;
  border-radius: 44px;
  background: var(--phone-frame);
  box-shadow: var(--shadow);
}

/* Das hintere Gerät trägt den Abschluss: zwei Momente derselben Einheit, das
   Training und das Weitergeben. Es steht gekippt links darunter und ist
   reine Dekoration. */
.lp-phone-back {
  display: block;
  position: absolute;
  z-index: 0;
  top: 4%;
  left: 0;
  width: 68%;
  transform: rotate(-7deg);
}

.lp-phone-line {
  margin: 0;
  font-size: calc(11px * var(--fs));
  line-height: 1.45;
  color: var(--ink-soft);
}

/* Die Woche als sieben Felder, zwei davon erledigt. Angedeutet, nicht
   nachgebaut: mehr als die Form ist hinter dem vorderen Gerät nicht zu
   sehen. */
.lp-phone .pair { gap: 0; }

.lp-phone .peer {
  gap: 5px;
  padding: 5px 9px;
  font-size: calc(11px * var(--fs));
}

.lp-phone .peer b {
  width: 13px;
  height: 13px;
  font-size: calc(8px * var(--fs));
}

.lp-phone .pair-link { flex-basis: 14px; }

.lp-phone-week { display: flex; gap: 5px; }

.lp-phone-week i {
  flex: 1 1 0;
  height: 26px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
}

.lp-phone-week i[data-on] {
  border-color: transparent;
  background: var(--accent);
}

.lp-phone-screen {
  display: flex;
  flex-direction: column;
  gap: 12px;
  aspect-ratio: 9 / 18;
  padding: 28px 13px 13px;
  border-radius: 34px;
  background: var(--bg);
  overflow: hidden;
}

.lp-phone-head { display: flex; flex-direction: column; gap: 2px; }
.lp-phone-head .eyebrow { font-size: calc(10px * var(--fs)); }
.lp-phone-head b { font-size: calc(17px * var(--fs)); font-weight: 600; letter-spacing: -0.01em; }

.lp-phone-figure {
  flex: 1 1 auto;
  min-height: 0;
  border-radius: var(--radius);
  background: var(--card-bg);
  overflow: hidden;
}

.lp-phone-figure img { display: block; width: 100%; height: 100%; object-fit: contain; }

.lp-phone-bar { display: flex; flex-direction: column; gap: 9px; }

/* Dieselbe Zeile wie in der App, nur kleiner: Füllstand als Balken, Zeit,
   und rechts, was ein Tipp täte. */
.lp-phone-timer {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--surface);
  font-size: calc(13px * var(--fs));
}

.lp-phone-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 32%;
  background: color-mix(in srgb, var(--accent) 20%, transparent);
}

.lp-phone-timer > :not(.lp-phone-fill) { position: relative; }
.lp-phone-icon { font-size: calc(15px * var(--fs)); color: var(--accent-text); }
.lp-phone-time { font-weight: 600; font-variant-numeric: tabular-nums; }
.lp-phone-note { margin-left: auto; font-size: calc(11px * var(--fs)); color: var(--ink-soft); }

.lp-phone-next {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: calc(14px * var(--fs));
  font-weight: 600;
}

.lp-phone-next span { opacity: 0.65; }

/* -------------------------------------------------------- Karten */
/* Die drei Punkte sind kleine Karten, die sich so breit legen, wie der
   Bildschirm hergibt. Jede trägt ein Icon und einen Satz und braucht darum
   Breite: auf dem Handy stehen sie untereinander. */
.lp-facts {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.lp-facts > div {
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
}

/* Auf dem weissen Band wäre eine weisse Karte keine Karte mehr. */
.lp-band-soft .lp-facts > div {
  background: var(--bg);
}

/* Auf getönten Bändern bleibt die Karte weiss, aber ihre Kante nimmt den
   Ton auf, sonst schwämme sie in der Fläche. */
.lp-band-teal .lp-facts > div,
.lp-band-brick .lp-facts > div,
.lp-band-plum .lp-facts > div,
.lp-band-green .lp-facts > div,
.lp-band-blue .lp-facts > div {
  border-color: color-mix(in srgb, var(--band) 22%, var(--line));
}

/* Ein Icon pro Karte, die Zeichnung aus Figma im Rahmen 40x40. */
.lp-fact-icon {
  display: block;
  width: 40px;
  height: 40px;
  margin-bottom: 6px;
}

.lp-facts b { font-weight: 600; }

.lp-facts span { font-size: calc(14px * var(--fs)); color: var(--ink-soft); text-wrap: pretty; }

/* -------------------------------------------------------- Band mit Icon */
/* Ein Band, dessen Text eine Spalte bleibt und daneben ein Icon trägt. Auf
   dem Handy fehlt die Breite dafür, dort steht das Icon über dem Text. */
.lp-side { gap: 24px; }

.lp-side-text {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}

/* Dieselbe Enge wie direkt im Band: Label und Titel gehören zusammen. */
.lp-side-text > .eyebrow + h2 { margin-top: -8px; }

/* Die Zeichnungen kommen aus Figma und stehen im Rahmen 238x238, in beiden
   Modi gleich wie die Illustrationen der Übungen. Auf dem Handy nehmen sie
   die halbe Spalte, nebeneinander ihr volles Mass. */
.lp-side-icon {
  display: block;
  flex: 0 0 auto;
  align-self: flex-start;
  width: min(238px, 46%);
  height: auto;
  aspect-ratio: 1;
}

/* -------------------------------------------------------- Fragen */
/* Eine Liste statt Karten: Fragen werden gesucht, nicht gelesen. Offen ist
   immer nur, was jemand aufgeklappt hat. */
.faq { display: flex; flex-direction: column; }

.faq details { border-bottom: 1px solid var(--line); }
.faq details:first-child { border-top: 1px solid var(--line); }

.faq summary {
  transition: color 120ms ease;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 15px 2px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  text-wrap: pretty;
}

.faq summary::-webkit-details-marker { display: none; }

.faq-caret {
  font-size: calc(18px * var(--fs));
  color: var(--ink-soft);
  transition: transform 150ms ease;
}

.faq details[open] .faq-caret { transform: rotate(180deg); }

.faq p {
  margin: 0;
  padding: 0 2px 16px;
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* Löschen steht leise da: ein unterstrichener Link, der erst nachfragt. Wer
   ihn sucht, findet ihn, und sonst fällt er nicht auf. Er steht an beiden
   Orten im Lesefluss, also linksbündig wie alles daneben. */
.wipe {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  margin-top: 6px;
  text-align: left;
}

.wipe-ask { text-decoration: underline; text-underline-offset: 3px; }

.wipe-row { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }

/* In der Antwort trägt er die Polsterung der Antwort, nicht ihren Abstand. */
.faq .wipe { margin: 0; padding: 0 2px 16px; }

.faq .wipe p { padding: 0; }

/* -------------------------------------------------------- Abschluss */
.lp-final .lp-cta { width: 100%; }

/* Die Uhr bringt ihren Rand selbst mit (der Kreis sitzt mit Abstand im
   Rahmen), darum steht der Text hier näher als beim Installationsbild. */
.lp-final { gap: 0; }

/* Ab einer halbwegs breiten Zeile trägt die Kopfzeile auch die Sprünge. */
@media (min-width: 820px) {
  .lp-jump { display: flex; }
}

/* Ab Tablet steht das Mockup neben dem Text statt darunter, und ein Knopf
   nimmt nur die Breite, die er braucht. */
@media (min-width: 720px) {
  .lp-hero {
    flex-direction: row;
    align-items: center;
    gap: 48px;
  }

  .lp-hero-text { flex: 1 1 auto; }
  .lp-cta { flex-direction: row; flex-wrap: wrap; }

  .lp-phones { flex: 0 0 300px; }
  .lp-phone { margin: 0 0 0 auto; }

  .lp-inner { padding: 64px 20px; }
  .lp-band-hero .lp-inner { padding-top: 72px; }
  .lp-inner > .lp-cta,
  .lp-side-text > .lp-cta { align-self: flex-start; }

  .lp-side {
    flex-direction: row;
    align-items: center;
    gap: 48px;
  }

  .lp-final { gap: 16px; }

  .lp-side-text { flex: 1 1 auto; min-width: 0; }

  .lp-side-icon { align-self: center; width: 238px; }
}

/* Ab dieser Breite trägt die Spalte beide Geräte in voller Grösse statt als
   Anteil der Bühne. */
@media (min-width: 900px) {
  .lp-phones { flex: 0 0 420px; max-width: 420px; }

  .lp-phone { width: 300px; }
  .lp-phone-back { top: 3%; width: 270px; }
}

/* ------------------------------------------------------------------ Update */
/* Eine neue Fassung meldet sich oben, nicht unten: unten sitzt im Training
   die Bedienleiste, und dort hat nichts anderes etwas verloren. */
.toast {
  position: fixed;
  z-index: 10;
  top: max(12px, env(safe-area-inset-top));
  left: 12px;
  right: 12px;
  max-width: 420px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 10px 10px 18px;
  font-size: calc(15px * var(--fs));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--shadow);
  animation: toast-in 240ms ease both;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(-12px); }
  to   { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------- Nebenausgänge */
/* Fragezeichen und Zahnrad: die Erklärung und die Einstellungen. Sie stehen
   fix oben rechts, aber nur auf den Screens, von denen aus es einen Weg
   zurück gibt: nicht im Training, nicht auf der Erklärung selbst. */
.topbtns {
  position: fixed;
  z-index: 8;
  top: max(10px, env(safe-area-inset-top));
  right: 10px;
  display: none;
  gap: 8px;
}

.helpbtn {
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  appearance: none;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: color-mix(in oklab, var(--bg) 82%, transparent);
  backdrop-filter: blur(10px);
  color: var(--ink-soft);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

/* Das Zahnrad trägt ein Symbol und keine Ziffer, es braucht etwas mehr. */
.helpbtn .icon { font-size: calc(20px * var(--fs)); }

body.has-help .topbtns { display: flex; }

/* Die Meldung über die neue Fassung sitzt am selben Platz und ist wichtiger. */
body.has-toast .topbtns { display: none; }

/* ------------------------------------------------------------------ Ziel */
/* Die Woche als sieben Tage, nicht als Bruchzahl: man soll sehen, wie viel
   Woche noch da ist, nicht nur wie viel Soll noch offen ist. */
.week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }

.day {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  aspect-ratio: 1 / 1.15;
  border-radius: 14px;
  background: var(--surface);
  border: 1px solid var(--line);
}

.day i { font-style: normal; font-size: calc(11px * var(--fs)); font-weight: 600; color: var(--ink-soft); }
.day b { font-size: calc(14px * var(--fs)); line-height: 1; min-height: 14px; }

.day[data-future] { background: none; border-style: dashed; opacity: 0.6; }
.day[data-today] { border-color: var(--ink-soft); border-width: 2px; }

.day[data-done] {
  background: var(--accent);
  border-color: transparent;
  color: var(--accent-ink);
}
.day[data-done] i { color: inherit; opacity: 0.75; }

.weekline { margin: 0; font-size: calc(17px * var(--fs)); font-weight: 600; text-wrap: pretty; }

/* ------------------------------------------------------------------ Übungsliste */
.topbar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.exercise-list { display: flex; flex-direction: column; gap: 28px; }

.exercise-group { display: flex; flex-direction: column; gap: 10px; }

.exercise-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px;
}

button.exercise-card {
  cursor: pointer;
  transition: transform 120ms ease, border-color 120ms ease;
}
button.exercise-card:active { transform: scale(0.995); }

.exercise-head { display: flex; flex-direction: column; gap: 2px; }
.exercise-head h2 { margin: 0; font-size: calc(18px * var(--fs)); letter-spacing: -0.01em; }
.exercise-head p { margin: 0; font-size: calc(13px * var(--fs)); color: var(--ink-soft); }

.exercise-figure {
  background: var(--card-bg);
  border-radius: var(--radius);
  padding: 12px;
}

/* ------------------------------------------------------------------ Editor */
/* Minimale Vektor-Werkzeuge: Kreis für ein Gelenk, Raute für den
   Kontrollpunkt einer Kurve, gestrichelte Führung dazwischen. */
.legend { font-size: calc(13px * var(--fs)); }

.field textarea {
  font: inherit;
  font-size: calc(16px * var(--fs));
  line-height: 1.45;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 16px;
  resize: vertical;
}

.editor-actions { display: flex; flex-direction: column; gap: 8px; }

.readout {
  margin: 0;
  font: 12px/1.5 ui-monospace, "SF Mono", monospace;
  white-space: pre;
  overflow-x: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px;
}


/* ------------------------------------------------------------------ Übung */
/* Alles Bedienbare sitzt in einer festen Leiste unten am Daumen, der Inhalt
   steht darüber. Auf dem Handy ist das der Unterschied zwischen Tippen
   und Strecken. */
/* Der Screen ist genau so hoch wie der Platz zwischen Seitenrand und
   Daumenleiste, keinen Pixel mehr. Nichts scrollt: wer die Anleitung
   aufklappt, soll sie lesen können, ohne die Figur aus dem Bild zu schieben. */
.screen-exercise {
  gap: 0;
  height: calc(100dvh - 20px - var(--bar-h));
}

.ex-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Kopfzeile bleibt oben, Figur schlägt direkt darunter an und nimmt die
   restliche Höhe. Der Hinweis hängt sich unten an. */
.ex-main {
  flex: 1;
  min-height: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.ex-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 14px 16px max(14px, env(safe-area-inset-bottom));
  background: color-mix(in oklab, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--line);
}

.ex-bar-top {
  display: flex;
  align-items: center;
  gap: 14px;
  max-width: 460px;
  width: 100%;
  margin: 0 auto;
}

.ex-bar-main {
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: 460px;
  width: 100%;
  margin: 0 auto;
}

.ex-next {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.ex-next [data-slot="step"] {
  font-variant-numeric: tabular-nums;
  font-size: calc(14px * var(--fs));
  opacity: 0.7;
}

.linkbtn {
  transition: color 120ms ease;
  appearance: none;
  background: none;
  border: 0;
  padding: 4px 0;
  font: inherit;
  font-size: calc(13px * var(--fs));
  color: var(--ink-soft);
  cursor: pointer;
  white-space: nowrap;
}

/* Linkknöpfe mit Icon: Pfeil voran, Text danach. */
.linkbtn-lead {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.linkbtn-lead .icon { font-size: calc(15px * var(--fs)); }

/* Platz für die Leiste, sonst verdeckt sie das Ende des Inhalts.
   Sie hat drei Zeilen: Fortschritt, Dosis, Schritte. Dieselbe Zahl braucht
   der Übungsscreen für seine Höhe, darum steht sie als Variable da. */
body.has-bar { --bar-h: 206px; }
body.has-bar #app { padding-bottom: var(--bar-h); }
body.has-bar .footer { display: none; }

/* Titel links, Überspringen oben rechts auf gleicher Höhe wie das Eyebrow. */
.ex-head {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.ex-head-text { display: flex; flex-direction: column; gap: 6px; min-width: 0; }

/* Nur das Icon. Die Fläche bleibt daumengross, auch wenn das Zeichen klein ist. */
.ex-skip {
  flex: 0 0 auto;
  align-self: center;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  font-size: calc(20px * var(--fs));
}

/* Die Fläche trägt den Screen, also darf sie die freie Höhe nehmen. Ihr Ton
   ist fest und für alle Übungen derselbe: die Farbe kommt aus der
   Illustration, nicht aus dem Bereich. */
.ex-figure {
  flex: 1 1 auto;
  display: grid;
  place-items: stretch;
  /* Die Zeile darf unter ihren Inhalt schrumpfen, sonst hielte die
     Illustration ihre Eigenhöhe und schöbe die Anleitung aus dem Bild. */
  grid-auto-rows: minmax(0, 1fr);
  min-height: 0;
  background: var(--card-bg);
  border-radius: var(--radius-lg);
  padding: 0;
}

.ex-figure > * { width: 100%; min-height: 0; }

.cue { margin: 0; color: var(--ink-soft); text-wrap: pretty; }

/* ---------------------------------------------- Anleitung als Schublade */
/* Zugeklappt bleibt nur die Zeile mit dem Pfeil stehen. Aufgeklappt wächst
   der Text nicht nach unten aus dem Screen, sondern nimmt der Figur Höhe
   weg: 0fr auf 1fr animiert das, ohne eine Höhe zu kennen. */
.ex-cue { flex: 0 0 auto; display: flex; flex-direction: column; }

.ex-cue-toggle {
  transition: color 120ms ease;
  appearance: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 10px 0 0;
  font: inherit;
  font-size: calc(13px * var(--fs));
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: none;
  border: 0;
  cursor: pointer;
}

.ex-cue-caret {
  font-size: calc(18px * var(--fs));
  /* Zugeklappt zeigt er nach oben, aufgeklappt nach unten. Beim Aufklappen
     dreht er in derselben Richtung weiter, darum 360 statt zurück auf 0. */
  transform: rotate(180deg);
  transition: transform 180ms ease;
}

.ex-cue[data-open] .ex-cue-caret { transform: rotate(360deg); }

.ex-cue-body {
  display: grid;
  grid-template-rows: 0fr;
  padding-top: 0;
  transition: grid-template-rows 200ms ease, padding-top 200ms ease;
}

.ex-cue[data-open] .ex-cue-body {
  grid-template-rows: 1fr;
  padding-top: 8px;
}

/* Der Text trägt das overflow, sonst stünde er über der Nullhöhe. */
.ex-cue-body > .cue { overflow: hidden; min-height: 0; }

/* Fertige Illustration aus dem Übungsordner. Die Fläche gehört dem Container,
   nicht der Datei: ein Bild mit festem Seitenverhältnis liesse sonst Ränder,
   und die Karte könnte den Bildschirm nie ganz füllen. Die Trennlinie zwischen
   den beiden Posen zieht der Container aus demselben Grund selbst, sie läuft
   so über die volle Breite. */
.ex-figure[data-illu],
.exercise-figure[data-illu] {
  display: block;
  position: relative;
  overflow: hidden;
  padding: 0;
  background: var(--card-bg);
}

.ex-figure[data-illu]::after,
.exercise-figure[data-illu]::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 4px;
  transform: translateY(-50%);
  background: var(--card-ink);
  opacity: 0.5;
}

/* Das Bild sitzt mittig, die Lücke zwischen den Posen liegt damit immer auf
   der halben Höhe, egal wie hoch der Container gerade ist. */
.ex-illu {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.exercise-figure[data-illu] .ex-illu { height: auto; aspect-ratio: 358 / 426; }

/* ------------------------------------------------------- Vor dem Start */
/* Derselbe Aufbau wie eine Übung, damit der Start kein Sprung ist: Kopf,
   Fläche, Bedienung unten. Die Übung legt ihre Leiste fest ans Fenster und
   lässt sich dafür um --bar-h kürzen; hier stehen die zwei Knöpfe im Fluss
   und nehmen dieselbe Höhe weg. Die Fläche misst darum gleich. */
.screen-ready {
  gap: 0;
  height: calc(100dvh - 20px);
}

.screen-ready .ready-actions {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 10px;
  min-height: var(--bar-h, 206px);
  padding: 16px 0 8px;
}

/* Das Maskottchen ist eine Pose, keine zwei. Die Trennlinie auf halber Höhe
   hätte hier nichts zu trennen. */
.screen-ready .ex-figure[data-illu]::after { content: none; }

/* ------------------------------------------------------------- Vorlieben */
/* Eine Frage vor dem Start, zwei Antworten. Mehr Einstellungen hat die App
   nicht, darum stehen sie offen da und nicht hinter einem Zahnrad. */
.prefs { display: flex; flex-direction: column; gap: 6px; }

.prefs:empty { display: none; }

.prefs-label { margin: 0; font-size: calc(14px * var(--fs)); color: var(--ink-soft); }

/* Eine Gruppe, nicht zwei Knöpfe: der gemeinsame Rahmen sagt, dass genau
   eine der beiden Lagen gilt und ein Tippen die andere wählt. */
.chips {
  display: flex;
  align-self: stretch;
  max-width: 100%;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
}

.chip {
  flex: 1 1 auto;
  font: inherit;
  font-size: calc(15px * var(--fs));
  padding: 8px 16px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--ink-soft);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.chip[aria-pressed='true'] {
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
}

/* Auf schmalen Geräten liegt die Gruppe über die ganze Spalte, damit beide
   Lagen gleich gross zu treffen sind. Ab 450px nimmt sie nur ihre Breite. */
@media (min-width: 450px) {
  .chips {
    display: inline-flex;
    align-self: flex-start;
  }
}

.chips:has(.chip:disabled) { opacity: 0.55; }

.chip:disabled { cursor: default; }

/* ------------------------------------------------------------------ Dosis */
/* Dosis auf eigener Zeile über den Schritten. Beide Formen liegen weiss auf
   dem Seitenhintergrund; sie unterscheiden sich darin, dass die Zeitvorgabe
   antippbar ist und Wiederholungen nur dastehen. */
.ex-dose { max-width: 460px; width: 100%; margin: 0 auto; }

.timer {
  transition: border-color 120ms ease;
  position: relative;
  overflow: hidden;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* Der Füllstand läuft als Balken durch die ganze Zeile. */
.timer-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--fill, 0) * 100%);
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  transition: width 300ms linear;
}

.timer > :not(.timer-fill) { position: relative; }

.timer-icon { font-size: calc(20px * var(--fs)); color: var(--accent-text); }

.timer-label {
  font-size: calc(19px * var(--fs));
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  min-width: 2.5ch;
}

.timer-note { margin-left: auto; font-size: calc(13px * var(--fs)); color: var(--ink-soft); }

.timer[data-state="running"] { border-color: var(--accent-text); }

.timer[data-state="done"] {
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  color: var(--accent-text);
  border-color: transparent;
  box-shadow: none;
}

.timer[data-state="done"] .timer-icon,
.timer[data-state="done"] .timer-note { color: inherit; }

/* Wiederholungen sind eine Angabe, kein Bedienelement. Gleiche Fläche wie der
   Timer, aber mittig gesetzt, ohne Cursor und ohne Zustand. */
.reps {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin: 0;
  padding: 13px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
}

.reps .icon { font-size: calc(20px * var(--fs)); color: var(--accent-text); }

.reps-count {
  font-size: calc(15px * var(--fs));
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.reps-note { font-size: calc(15px * var(--fs)); color: var(--ink-soft); }

/* Zurück: nur der Pfeil, quadratisch neben dem Weiter-Knopf. */
.ex-prev {
  flex: 0 0 auto;
  width: 52px;
  height: 52px;
  padding: 0;
  display: grid;
  place-items: center;
  font-size: calc(20px * var(--fs));
  line-height: 1;
}

.ex-stop { border-radius: 999px; }

/* ------------------------------------------------------------------ Fortschritt */
.progress { display: flex; gap: 6px; flex: 1; }

.progress i {
  flex: 1;
  height: 5px;
  border-radius: 999px;
  background: var(--line);
}

.progress i[data-on] { background: var(--accent-text); }
.progress i[data-now] { background: var(--accent-text); }

/* Übersprungen: dieselbe Farbe wie erledigt, nur transparent gefüllt.
   Angefasst, aber nicht abgehakt. */
.progress i[data-skip] { background: color-mix(in srgb, var(--accent-text) 50%, transparent); }

/* ------------------------------------------------------------------ Abschluss */
.share { display: flex; flex-direction: column; gap: 10px; }

.status { margin: 0; min-height: 1.5em; font-size: calc(14px * var(--fs)); color: var(--ink-soft); }

/* Geteilt: aus der grauen Statuszeile wird die Erfolgsmeldung. */
.status[data-ok] {
  padding: 12px 16px;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 32%, var(--line));
  color: var(--accent-text);
  font-size: calc(15px * var(--fs));
  font-weight: 600;
}

/* ------------------------------------------------------------------ Konfetti */
/* Der Container ist eine Zeile ohne Höhe, die Stücke fliegen absolut darüber
   hinaus. So verschiebt der Ausbruch nichts und braucht keinen Platz. */
.party {
  position: relative;
  height: 0;
  z-index: 2;
  /* Die halbe Spaltenlücke auf jeder Seite zurücknehmen, sonst reisst das
     Einblenden eine zusätzliche Lücke zwischen Knopf und Status. */
  margin-block: -9px;
}

.party i {
  position: absolute;
  left: 50%;
  top: 0;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  opacity: 0;
  animation: party-burst 900ms cubic-bezier(0.15, 0.7, 0.3, 1) var(--delay, 0ms) forwards;
}

@keyframes party-burst {
  0%   { opacity: 1; transform: translate(0, 0) rotate(0deg) scale(0.5); }
  70%  { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) rotate(var(--rot)) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 1ms !important; animation-duration: 1ms !important; }

  /* Ein Konfettiknall in 1 ms ist nur ein Zucken. Dann lieber gar keiner. */
  .party { display: none !important; }
}

