/* ─────────────────────────────────────────────────────────────────────────
   biodanza-cockpit — css/components.css

   Geschichtserzaehlung: Das Aussehen aller Bausteine aus js/ui/ — in der
   Reihenfolge, in der man sie auf einem Screen trifft: Buttons, Karten,
   Listen, Suche und Filter, Eingabefelder, Fortschritt, Abschnitte, dann
   die Ebenen darueber (Sheet, Dialog, Toast) und zuletzt die Shell
   (TopBar, Tab-Leiste, "Laeuft gerade", Kern-Screens von core/ wie
   Platzhalter, Fehler-Screen, Ersatz-Auswahl, Autosave-Status, Update-Hinweis).

   Alle Farben kommen aus tokens.css (var(--color-...)), alle Masse aus den
   Mass-Tokens — so wechselt der Ruhige Modus Farben UND Tastengroessen,
   ohne dass hier eine Zeile davon weiss.

   ── DECISION — BEM-artige Klassen (.card__title) statt Element-Selektoren ──
     vs. .card h3 / .card span. Grund: Module stecken beliebige Inhalte in
     Karten und Sheets; Element-Selektoren wuerden in fremde Inhalte
     hineinwirken. Eine Klasse wirkt nur dort, wo der Baustein sie setzt.

   ── DECISION — Druckrueckmeldung per :active + filter: brightness ──
     vs. eigene Hover-/Pressed-Farbtoene je Theme. Grund: Ein Mechanismus
     fuer alle Farben und Themes; Hover nur auf Geraeten mit Maus
     (@media (hover: hover)), damit am Handy nichts "kleben" bleibt.
   ───────────────────────────────────────────────────────────────────────── */


/* ── Button (D9) ──
      44-48 px hoch, Radius 8, Innenabstand 8/12 (D8); Varianten primaer,
      sekundaer, ghost, danger; Groessen sm/md/lg ueber Tokens.
      Bis 2026-10-08 stand hier seitlich var(--space-4) = 16 px — gegen D8
      und ohne DECISION (Review core-E); im 360-px-Dialog mit zwei Knoepfen
      fehlten der Beschriftung dadurch 8 px. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--btn-h-md);
  padding: var(--btn-pad-y) var(--btn-pad-x);
  border: 2px solid transparent;
  border-radius: var(--radius-m);
  font-size: var(--font-size-button);
  font-weight: var(--font-weight-semibold);
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  overflow-wrap: normal;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
  transition: background-color var(--duration-fast), border-color var(--duration-fast), filter var(--duration-fast);
}

.btn--primary {
  background: var(--color-primary);
  color: var(--color-on-primary);
}

.btn--secondary {
  background: var(--color-surface);
  color: var(--color-primary-text);
  border-color: var(--color-primary-text);
}

.btn--ghost {
  background: transparent;
  color: var(--color-primary-text);
}

.btn--danger {
  background: var(--color-danger);
  color: var(--color-on-danger);
}

.btn--sm {
  min-height: var(--btn-h-sm);
}

/* ── DECISION — lg-Variante mit 24 px seitlich statt D8-12 px ──
     vs. dieselben 12 px wie md. Grund: lg ist die eine Hauptaktion eines
     Screens (Session starten/fortsetzen, App installieren), 56-68 px hoch
     und meist volle Breite (btn--block) — bei voller Breite wirkt der
     Abstand gar nicht, bei freier Breite haelt er die Proportion zur
     groesseren Hoehe und Schrift (18 px). */
.btn--lg {
  min-height: var(--btn-h-lg);
  padding-inline: var(--space-5);
  font-size: 18px;
}

.btn--block {
  display: flex;
  width: 100%;
}

.btn .icon {
  width: var(--icon-size-btn);
  height: var(--icon-size-btn);
}

.btn:disabled {
  background: var(--color-disabled-bg);
  color: var(--color-disabled-text);
  border-color: transparent;
  cursor: not-allowed;
}

.btn--ghost:disabled {
  background: transparent;
}

.btn[aria-busy="true"] {
  cursor: progress;
  opacity: 0.7;
}

.btn:active:not(:disabled):not([aria-busy="true"]) {
  filter: brightness(0.92);
}


/* ── IconButton ──
      Quadratisch, mindestens Touch-Groesse; aria-pressed zeigt an/aus. */
.icon-btn {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: var(--btn-h-md);
  height: var(--btn-h-md);
  padding: 0;
  border: 2px solid transparent;
  border-radius: var(--radius-m);
  background: transparent;
  color: var(--color-primary-text);
  touch-action: manipulation;
  transition: background-color var(--duration-fast), filter var(--duration-fast);
}

.icon-btn--sm {
  width: var(--btn-h-sm);
  height: var(--btn-h-sm);
}

.icon-btn--lg {
  width: var(--btn-h-lg);
  height: var(--btn-h-lg);
}

.icon-btn--primary {
  background: var(--color-primary);
  color: var(--color-on-primary);
}

.icon-btn--secondary {
  background: var(--color-surface);
  color: var(--color-primary-text);
  border-color: var(--color-primary-text);
}

.icon-btn--danger {
  color: var(--color-danger-text);
}

.icon-btn[aria-pressed="true"] {
  background: var(--color-primary-soft);
}

.icon-btn:disabled {
  color: var(--color-disabled-text);
  cursor: not-allowed;
}

.icon-btn:active:not(:disabled) {
  filter: brightness(0.9);
}

/* Favorit-Stern: Gold mit dunkler Kontur (Gold auf Weiss allein 1.66:1) */
.is-favorite .icon--star-filled {
  color: var(--color-favorite);
  stroke: var(--color-favorite-stroke);
}

@media (hover: hover) {
  .btn--primary:hover:not(:disabled),
  .btn--danger:hover:not(:disabled) {
    filter: brightness(1.08);
  }

  .btn--secondary:hover:not(:disabled),
  .btn--ghost:hover:not(:disabled),
  .icon-btn:hover:not(:disabled) {
    background-color: var(--color-primary-soft);
  }
}


/* ── Card (D10) ──
      Flaeche, Radius 8, Schatten 0 2px 4px; Titel oben links, Infos
      darunter, Aktionen unten rechts (oder rechts daneben). Die
      Klickflaeche .card__main traegt das Innenpolster 16 px. */
.card {
  background: var(--color-surface);
  color: var(--color-text);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-card);
}

.card__row {
  display: flex;
  align-items: flex-start;
}

.card__main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--card-pad);
  border: 0;
  border-radius: var(--radius-m);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  text-decoration: none;
}

button.card__main,
a.card__main {
  cursor: pointer;
  touch-action: manipulation;
}

.card--clickable .card__main:active {
  background: var(--color-primary-soft);
}

.card__leading {
  display: grid;
  place-items: center;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-m);
  background: var(--color-primary-soft);
  color: var(--color-primary-text);
}

.card__body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.card__title {
  font-size: 18px;
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-tight);
}

.card__subtitle {
  color: var(--color-text-secondary);
}

.card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px var(--space-2);
  font-size: var(--font-size-small);
  color: var(--color-text-secondary);
}

.card__meta-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

/* Trenner NACH dem Eintrag statt davor: bricht die Zeile um, stand der Punkt
   sonst am Anfang der naechsten Zeile ("· 120 Min."). Betrifft alle Module. */
.card__meta-item:not(:last-child)::after {
  content: "·";
  margin-left: var(--space-2);
}

.card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: var(--space-1);
}

/* Kurzbeschreibung: hoechstens drei Zeilen, damit lange Texte die Liste nicht sprengen */
.card__description {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
  margin-top: 2px;
}

.card__badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: var(--space-1);
}

/* ── Abzeichen (Status, "bitte prüfen", "Datei fehlt") ──
   Ton ueber Klasse; Farben nur aus Tokens (Dunkel/Ruhig passen sich an).
   --color-text-secondary nie auf --color-surface-muted (Falle 19). */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  max-width: 100%;
  padding: 1px 10px;
  border-radius: var(--radius-pill);
  background: var(--color-surface-muted);
  color: var(--color-text);
  font-size: var(--font-size-small);
  font-weight: var(--font-weight-medium);
  line-height: 1.6;
}

.badge--info { background: var(--color-primary-soft); color: var(--color-primary-text); }
.badge--warn { background: var(--color-warning-soft); color: var(--color-warning-text); }
.badge--success { background: var(--color-surface-muted); color: var(--color-success-text); }
.badge--danger { background: var(--color-surface-muted); color: var(--color-danger-text); }

.card__favorite {
  flex: none;
  margin: var(--space-1) var(--space-1) 0 0;
}

/* Der gefuellte Stern IST der Zustand — kein Druck-Hintergrund dazu */
.card__favorite[aria-pressed="true"] {
  background: transparent;
}

span.card__favorite {
  display: grid;
  place-items: center;
  width: var(--btn-h-md);
  height: var(--btn-h-md);
}

.card__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-1);
  padding: 0 var(--space-2) var(--space-2);
  margin-top: calc(-1 * var(--space-2));
}

.card__actions--right {
  flex: none;
  align-self: center;
  margin: 0;
  padding: var(--space-1) var(--space-2) var(--space-1) 0;
}


/* ── Tag-Pillen ──
      Klein und still in Karten; im TagSelector entfernbar und gross. */
.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  max-width: 100%;
  padding: 1px 10px;
  border-radius: var(--radius-pill);
  background: var(--color-surface-muted);
  color: var(--color-text);
  font-size: var(--font-size-small);
  line-height: 1.6;
}

.tag--removable {
  min-height: var(--touch-min);
  padding: 0 0 0 var(--space-4);
  font-size: var(--font-size-body);
}

.tag__remove {
  display: grid;
  place-items: center;
  width: var(--touch-min);
  height: var(--touch-min);
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: inherit;
}


/* ── Link-Zeile (ui/row.js) ──
      Fuehrt woanders hin: Icon, Titel, Erklaerung, Pfeil. In Flaechen-
      Abschnitten (.section--card) flach, sonst eine eigene kleine Flaeche. */
.link-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: 56px;
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4);
  border: 0;
  border-radius: var(--radius-m);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-card);
  font: inherit;
  text-align: left;
  text-decoration: none;
  touch-action: manipulation;
}

.link-row:active {
  filter: brightness(0.95);
}

.link-row__icon {
  display: grid;
  color: var(--color-primary-text);
}

.link-row__text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.link-row__title {
  font-weight: var(--font-weight-semibold);
}

.link-row__description {
  font-size: var(--font-size-small);
  color: var(--color-text-secondary);
}

.link-row__value {
  color: var(--color-text-secondary);
  white-space: nowrap;
}

.link-row__chevron {
  display: grid;
  color: var(--color-text-secondary);
}

.section--card .link-row {
  padding-inline: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}


/* ── Liste und Leer-Zustand ──
      Karten im Abstand von 8 px (D8 Card-Aussenabstand). */
.list {
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
}

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-4);
  text-align: center;
}

.empty__icon {
  display: grid;
  place-items: center;
  width: 88px;
  height: 88px;
  border-radius: 50%;
  background: var(--color-primary-soft);
  color: var(--color-primary-text);
}

.empty__text {
  font-size: 18px;
  font-weight: var(--font-weight-semibold);
}

.empty__hint {
  max-width: 34ch;
  color: var(--color-text-secondary);
}

.empty__action {
  margin-top: var(--space-2);
}


/* ── Suchfeld ── */
.searchbar {
  position: relative;
  display: flex;
  align-items: center;
}

.searchbar__icon {
  position: absolute;
  left: var(--space-3);
  display: grid;
  color: var(--color-text-secondary);
  pointer-events: none;
}

.searchbar__input {
  width: 100%;
  min-height: var(--input-h);
  padding: 0 var(--btn-h-md) 0 44px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text);
  -webkit-appearance: none;
  appearance: none;
}

.searchbar__input::-webkit-search-cancel-button,
.searchbar__input::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
}

.searchbar__input::placeholder {
  color: var(--color-text-secondary);
  opacity: 1;
}

.searchbar__input:focus {
  outline: none;
  border-color: var(--color-focus);
  box-shadow: inset 0 0 0 1px var(--color-focus);
}

.searchbar__clear {
  position: absolute;
  right: 0;
  color: var(--color-text-secondary);
  border-radius: var(--radius-pill);
}


/* ── Filter-Pillen ──
      Gross genug zum Treffen (Touch-Hoehe), gewaehlt = Petrol + Haekchen. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.chips--scroll {
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  margin-inline: calc(-1 * var(--screen-pad));
  padding-inline: var(--screen-pad);
}

.chips--scroll::-webkit-scrollbar {
  display: none;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  min-height: var(--touch-min);
  padding: 0 var(--space-4);
  border: 1.5px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--color-surface-muted);
  color: var(--color-text);
  font-size: 15px;
  font-weight: var(--font-weight-medium);
  white-space: nowrap;
  overflow-wrap: normal;
  touch-action: manipulation;
}

.chip__check {
  display: none;
  margin-left: -4px;
}

.chip.is-selected {
  background: var(--color-primary);
  color: var(--color-on-primary);
}

.chip.is-selected .chip__check {
  display: inline-grid;
}

.chip__count {
  min-width: 24px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: var(--font-size-small);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.chip--suggestion {
  background: var(--color-surface);
  border: 1.5px dashed var(--color-primary-text);
  color: var(--color-primary-text);
  padding-inline: var(--space-3) var(--space-4);
}

.chip:active {
  filter: brightness(0.92);
}


/* ── Eingabefelder (D11) ──
      Label oben (16 px halbfett — gut lesbar im Stehen), Rahmen #CCCCCC,
      Fokus Petrol, Radius 6, Innenabstand 12. */
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.field__label {
  font-weight: var(--font-weight-semibold);
}

.field__required {
  color: var(--color-danger-text);
}

.field__hint {
  font-size: var(--font-size-small);
  color: var(--color-text-secondary);
}

.field__error {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--font-size-small);
  font-weight: var(--font-weight-medium);
  color: var(--color-danger-text);
}

.input,
.select__control {
  width: 100%;
  min-height: var(--input-h);
  padding: 0 var(--input-pad);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-s);
  background: var(--color-surface);
  color: var(--color-text);
}

.input::placeholder {
  color: var(--color-text-secondary);
  opacity: 1;
}

.input:focus,
.select__control:focus {
  outline: none;
  border-color: var(--color-focus);
  box-shadow: inset 0 0 0 1px var(--color-focus);
}

.field--invalid .input,
.field--invalid .select__control {
  border-color: var(--color-danger-text);
  box-shadow: inset 0 0 0 1px var(--color-danger-text);
}

.textarea {
  display: block;
  padding: var(--input-pad);
  line-height: var(--line-height-body);
  resize: vertical;
}

/* Datum/Uhrzeit: iOS zentriert sonst und laesst leere Felder schrumpfen */
.input--date,
.input--time {
  -webkit-appearance: none;
  appearance: none;
  text-align: left;
}

.input--date::-webkit-date-and-time-value,
.input--time::-webkit-date-and-time-value {
  text-align: left;
}

.select {
  position: relative;
}

.select__control {
  -webkit-appearance: none;
  appearance: none;
  padding-right: 44px;
}

.select__chevron {
  position: absolute;
  top: 50%;
  right: var(--space-3);
  display: grid;
  transform: translateY(-50%);
  color: var(--color-text-secondary);
  pointer-events: none;
}

/* Geld: Betrag rechtsbuendig in Ziffern gleicher Breite, Waehrung als Suffix */
.money {
  position: relative;
  display: flex;
  align-items: center;
}

.money__input {
  padding-right: 40px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.money__suffix {
  position: absolute;
  right: var(--input-pad);
  color: var(--color-text-secondary);
  font-weight: var(--font-weight-medium);
  pointer-events: none;
}


/* ── Toggle (D11) ──
      Ganze Zeile antippbar; Spur aktiv Petrol, inaktiv #AAAAAA. Das echte
      Kontrollkaestchen liegt unsichtbar ueber der Spur (Fokus, Screenreader). */
.toggle {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--touch-min);
  padding: var(--space-2) 0;
  cursor: pointer;
  touch-action: manipulation;
}

.toggle__text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.toggle__label {
  font-weight: var(--font-weight-medium);
}

.toggle__description {
  font-size: var(--font-size-small);
  color: var(--color-text-secondary);
}

/* Unsichtbar, aber OBEN auf der Spur: ein Tipp/Klick trifft das echte
   Kontrollkaestchen (auch Test-Klicks auf [role="switch"]). */
.toggle__input {
  position: absolute;
  top: 50%;
  right: 0;
  z-index: 1;
  width: 52px;
  height: 32px;
  margin: 0;
  opacity: 0;
  cursor: pointer;
  transform: translateY(-50%);
}

.toggle__track {
  position: relative;
  flex: none;
  width: 52px;
  height: 32px;
  border-radius: var(--radius-pill);
  background: var(--color-toggle-off);
  transition: background-color var(--duration-fast);
}

.toggle__knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--color-toggle-knob);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  transition: transform var(--duration-fast) var(--ease-out);
}

.toggle__input:checked + .toggle__track {
  background: var(--color-toggle-on);
}

.toggle__input:checked + .toggle__track .toggle__knob {
  transform: translateX(20px);
}

.toggle__input:focus-visible + .toggle__track {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

/* aria-disabled = "speichert gerade" (ui/fields.js): sieht aus wie gesperrt,
   behaelt aber den Fokus */
.toggle__input:disabled + .toggle__track,
.toggle__input[aria-disabled="true"] + .toggle__track {
  opacity: 0.55;
}

/* Ruhiger Modus: groessere Spur (D3 grosse Bedienelemente) */
:root[data-quiet="true"] .toggle__track,
:root[data-quiet="true"] .toggle__input {
  width: 60px;
  height: 36px;
}

:root[data-quiet="true"] .toggle__knob {
  width: 30px;
  height: 30px;
}

:root[data-quiet="true"] .toggle__input:checked + .toggle__track .toggle__knob {
  transform: translateX(24px);
}


/* ── Slider ──
      Spur wie die Progress-Bar (D11), Daumen 28 px — gross genug fuer den
      Daumen. --fill setzt ui/fields.js (Chromium/WebKit), Firefox nutzt
      ::-moz-range-progress. */
.field--slider {
  gap: var(--space-1);
}

.slider__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}

.slider__value {
  font-size: 18px;
  font-weight: var(--font-weight-bold);
  font-variant-numeric: tabular-nums;
  color: var(--color-primary-text);
}

.slider {
  --fill: 0%;
  width: 100%;
  height: var(--touch-min);
  margin: 0;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  touch-action: pan-y;
}

/* Spur und Daumen aus eigenen Tokens (--color-slider-*, tokens.css): im
   Dunkel- und Ruhig-Modus >= 3:1 zur Flaeche (WCAG 1.4.11); der Ring in
   Flaechenfarbe trennt den Daumen von der Spur. */
.slider::-webkit-slider-runnable-track {
  height: 8px;
  border-radius: var(--radius-progress);
  background: linear-gradient(to right,
    var(--color-progress-fill) 0 var(--fill),
    var(--color-slider-track) var(--fill) 100%);
}

.slider::-webkit-slider-thumb {
  width: 28px;
  height: 28px;
  margin-top: -10px;
  border: 3px solid var(--color-surface);
  border-radius: 50%;
  background: var(--color-slider-thumb);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
  -webkit-appearance: none;
  appearance: none;
}

.slider::-moz-range-track {
  height: 8px;
  border-radius: var(--radius-progress);
  background: var(--color-slider-track);
}

.slider::-moz-range-progress {
  height: 8px;
  border-radius: var(--radius-progress);
  background: var(--color-progress-fill);
}

.slider::-moz-range-thumb {
  width: 22px;
  height: 22px;
  border: 3px solid var(--color-surface);
  border-radius: 50%;
  background: var(--color-slider-thumb);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}

.slider:focus-visible {
  outline: none;
}

.slider:focus-visible::-webkit-slider-thumb {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

.slider:focus-visible::-moz-range-thumb {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}


/* ── Tag-Auswahl ── */
.tag-selector__chips,
.tag-selector__suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.tag-selector__entry {
  display: flex;
  gap: var(--space-2);
}

.tag-selector__entry .input {
  flex: 1 1 auto;
  min-width: 0;
}


/* ── Fortschritt (D11) ──
      Spur #A3B9C9, Fuellung Petrol, Radius 4. Die Spur schneidet die
      Fuellung ab (overflow) — so bleiben die Ecken rund, auch wenn die
      Fuellung per scaleX waechst. */
.progress {
  position: relative;
  height: 8px;
  border-radius: var(--radius-progress);
  background: var(--color-progress-track);
  overflow: hidden;
}

.progress__fill {
  position: absolute;
  inset: 0;
  background: var(--color-progress-fill);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--duration-base) var(--ease-out);
}

.progress__caption {
  margin-top: 6px;
  font-size: var(--font-size-small);
  color: var(--color-text-secondary);
  font-variant-numeric: tabular-nums;
}


/* ── Abschnitt ──
      Ueberschrift 20 px (D7 Untertitel); mit card: true auf einer Flaeche,
      Zeilen darin durch feine Linien getrennt (Einstellungs-Listen). */
.section {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.section + .section {
  margin-top: var(--space-5);
}

.section__header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.section__title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--font-size-subtitle);
}

.section__actions {
  display: flex;
  gap: var(--space-1);
}

.section__description {
  margin-top: calc(-1 * var(--space-2));
  font-size: var(--font-size-small);
  color: var(--color-text-secondary);
}

.section--card .section__content {
  padding: var(--space-1) var(--card-pad);
  border-radius: var(--radius-m);
  background: var(--color-surface);
  box-shadow: var(--shadow-card);
}

.section--card .section__content > * + * {
  border-top: 1px solid var(--color-divider);
}


/* ── Modal-Ebenen: Sheet und Dialog ──
      Telefon: Sheet faehrt von unten (Ecken oben rund, Home-Indikator-
      Abstand). Tablet (>= 600 px): Sheet mittig wie ein Dialog. */
#modal-root {
  position: relative;
  z-index: var(--z-modal);
}

.modal-layer {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.modal-layer--dialog {
  align-items: center;
  padding: var(--space-4);
}

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: var(--color-backdrop);
  opacity: 0;
  transition: opacity var(--duration-base) ease;
}

.modal-layer[data-state="open"] .modal-backdrop {
  opacity: 1;
}

.modal-layer[data-state="closing"] {
  pointer-events: none;
}

.sheet {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 640px;
  max-height: 92vh;
  max-height: 92dvh;
  padding-bottom: env(safe-area-inset-bottom, 0px);
  border-radius: var(--radius-l) var(--radius-l) 0 0;
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-sheet);
  transform: translateY(100%);
  transition: transform var(--duration-base) var(--ease-out);
}

.sheet:focus,
.dialog:focus {
  outline: none;
}

.modal-layer[data-state="open"] .sheet {
  transform: none;
}

.sheet__header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 60px;
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--color-divider);
}

.sheet__title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--font-size-subtitle);
}

.sheet__body {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-4);
}

.sheet__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--color-divider);
}

.sheet__actions .btn {
  flex: 1 1 140px;
}

/* Sheets mit Suchfeld: FESTE Hoehe statt Inhaltshoehe.
   ── DECISION — feste Hoehe (92dvh) statt "so hoch wie der Inhalt" ──
     Grund (gemessen, Review core-E, logs/tmp/review-sec-pickerkbd.mjs, 360x780,
     Chromium + WebKit): Das Sheet klebt unten; filtert die Suche die Liste
     kuerzer, schrumpfte es — das Suchfeld rutschte von y=363 auf y=648, also
     dorthin, wo am Handy die Tastatur liegt (Chrome Android ab 108 und iOS
     verkleinern nur den sichtbaren Bereich, nicht das Layout). Mit fester
     Hoehe bleibt das Feld oben, die Treffer stehen zwischen Feld und Tastatur.
     --keyboard-inset (ui/modal.js, aus visualViewport) haelt den Rest der
     Liste ueber der Tastatur scrollbar. Zwei Regeln, weil ein Browser ohne
     :has() sonst die ganze Selektor-Liste verwerfen wuerde. */
.picker-sheet,
.sheet--search {
  height: 92vh;
  height: 92dvh;
  padding-bottom: max(env(safe-area-inset-bottom, 0px), var(--keyboard-inset, 0px));
}

.sheet:has(.searchbar) {
  height: 92vh;
  height: 92dvh;
  padding-bottom: max(env(safe-area-inset-bottom, 0px), var(--keyboard-inset, 0px));
}

.dialog {
  position: relative;
  width: 100%;
  max-width: 420px;
  padding: var(--space-5);
  border-radius: var(--radius-l);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-sheet);
  opacity: 0;
  transform: scale(0.96);
  transition: opacity var(--duration-base) ease, transform var(--duration-base) var(--ease-out);
}

.modal-layer[data-state="open"] .dialog {
  opacity: 1;
  transform: none;
}

.dialog__title {
  font-size: var(--font-size-subtitle);
}

.dialog__message {
  margin-top: var(--space-3);
}

.dialog__actions {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-5);
}

.dialog__actions .btn {
  flex: 1 1 0;
}

@media (min-width: 600px) {
  .modal-layer--sheet {
    align-items: center;
    padding: var(--space-5);
  }

  .sheet {
    max-height: 85vh;
    padding-bottom: 0;
    border-radius: var(--radius-l);
    opacity: 0;
    transform: translateY(24px);
    transition: opacity var(--duration-base) ease, transform var(--duration-base) var(--ease-out);
  }

  .modal-layer[data-state="open"] .sheet {
    opacity: 1;
  }

  /* Tablet: mittiges Sheet, feste Hoehe aus demselben Grund wie am Handy */
  .picker-sheet,
  .sheet--search {
    height: 85vh;
    padding-bottom: var(--keyboard-inset, 0px);
  }

  .sheet:has(.searchbar) {
    height: 85vh;
    padding-bottom: var(--keyboard-inset, 0px);
  }
}


/* ── Toast ──
      Oben unter der TopBar, ueber Sheets (z-index), nie ueber den
      Workshop-Tasten unten. Fehler rot, alles andere dunkel (invertiert). */
#toast-root {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + var(--topbar-h) + var(--space-2));
  left: 0;
  right: 0;
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  max-width: 480px;
  min-height: 48px;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-m);
  background: var(--color-inverse-bg);
  color: var(--color-inverse-text);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.22);
  font-weight: var(--font-weight-medium);
  pointer-events: auto;
  cursor: pointer;
  animation: toast-in var(--duration-base) var(--ease-out);
  transition: opacity var(--duration-base), transform var(--duration-base);
}

.toast--error {
  background: var(--color-danger);
  color: var(--color-on-danger);
}

.toast__text {
  flex: 1 1 auto;
  min-width: 0;
}

.toast.is-leaving {
  opacity: 0;
  transform: translateY(-8px);
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
}


/* ── TopBar ──
      Hell: Petrol mit weisser Schrift (D12 "Petrol als Primaerfarbe", klare
      Orientierung oben; die Android-Statusleiste nimmt dieselbe Farbe an,
      ui/shell.js); dunkel/ruhig: Flaechenton. env(safe-area-*, 0px) haelt
      Abstand zu Notch und Rundungen (Querformat, randlose Geraete). */
.topbar {
  padding-top: env(safe-area-inset-top, 0px);
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
  background: var(--color-topbar-bg);
  color: var(--color-topbar-text);
}

.topbar__inner {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  max-width: var(--content-max);
  min-height: var(--topbar-h);
  margin: 0 auto;
  padding: 0 var(--space-1);
}

.topbar__title {
  flex: 1 1 auto;
  min-width: 0;
  padding-inline: var(--space-2);
  font-size: var(--font-size-subtitle);
  font-weight: var(--font-weight-semibold);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topbar__title--root {
  padding-left: var(--space-3);
}

.topbar__actions {
  display: flex;
  gap: 2px;
}

.topbar .icon-btn,
.topbar .btn {
  background: transparent;
  color: inherit;
}

.topbar .btn {
  border-color: currentColor;
}

.topbar :focus-visible {
  outline-color: var(--color-topbar-focus);
}

/* Ruhig: TopBar hat dieselbe Farbe wie der Grund — eine Haarlinie trennt
   sie, wenn Inhalt darunter durchscrollt. */
:root[data-quiet="true"] .topbar {
  box-shadow: 0 1px 0 var(--color-divider);
}

@media (hover: hover) {
  .topbar .icon-btn:hover:not(:disabled) {
    background-color: rgba(255, 255, 255, 0.14);
  }
}


/* ── Tab-Leiste (D5) ──
      Vier gleich breite Tabs, Icon + Label; der aktive Tab bekommt eine
      Pille hinter dem Icon und Petrol-Schrift. */
.bottomnav {
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  border-top: 1px solid var(--color-divider);
  background: var(--color-nav-bg);
  box-shadow: var(--shadow-raised);
}

.bottomnav__list {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  max-width: var(--content-max);
  margin: 0 auto;
}

.bottomnav__link {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: var(--bottomnav-h);
  padding: 6px 2px;
  color: var(--color-nav-text);
  font-size: var(--font-size-small);
  font-weight: var(--font-weight-medium);
  text-decoration: none;
  touch-action: manipulation;
}

.bottomnav__icon {
  display: grid;
  place-items: center;
  width: 56px;
  height: 30px;
  border-radius: var(--radius-pill);
  transition: background-color var(--duration-fast);
}

.bottomnav__label {
  max-width: 100%;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Aktiv = Farbe + Pille, NICHT fett: fett waere "Einstellungen" bei 360 px
   breiter als der Tab (gemessen 89 > 86 px, logs/tmp/app-shots.mjs). */
.bottomnav__link.is-active {
  color: var(--color-nav-active);
}

.bottomnav__link.is-active .bottomnav__icon {
  background: var(--color-primary-soft);
}

.bottomnav__link:focus-visible {
  outline-offset: -3px;
}


/* ── "Laeuft gerade"-Leiste ──
      Ueber der Tab-Leiste, nur wenn Musik ausserhalb des Session-Flows
      spielt. Duenne Fortschrittslinie oben, Titel, Zeit, Pause und Stopp. */
.nowplaying {
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
  border-top: 1px solid var(--color-divider);
  background: var(--color-surface);
  box-shadow: var(--shadow-raised);
}

.nowplaying__inner {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  max-width: var(--content-max);
  min-height: 60px;
  margin: 0 auto;
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
}

.nowplaying__progress {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--color-progress-track);
  overflow: hidden;
}

.nowplaying__progress-fill {
  height: 100%;
  background: var(--color-progress-fill);
  transform: scaleX(0);
  transform-origin: left center;
}

.nowplaying__icon {
  display: grid;
  color: var(--color-primary-text);
}

.nowplaying__text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  line-height: 1.3;
}

.nowplaying__eyebrow {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

.nowplaying__title {
  font-weight: var(--font-weight-semibold);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nowplaying__detail {
  font-size: var(--font-size-small);
  color: var(--color-text-secondary);
  font-variant-numeric: tabular-nums;
}

.nowplaying__inner[data-status="fading"] .nowplaying__detail {
  color: var(--color-primary-text);
  font-weight: var(--font-weight-semibold);
}


/* ── Kern-Screens (core/router.js, main.js, core/pickers.js, core/autosave.js) ──
      Platzhalter "Wird gebaut", "Nicht gefunden"/Fehler-Screen, Start-
      Fehler, Ersatz-Auswahl im Sheet und der Autosave-Status. Diese Teile
      baut core ohne ui/-Bausteine (sie muessen auch dann zeichnen, wenn ein
      Baustein kaputt ist) — darum hier eigene, schlichte Regeln. */
.placeholder-screen,
.route-message {
  padding: var(--space-5) var(--card-pad);
  border-radius: var(--radius-l);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-card);
}

/* Platzhalter: gestrichelt — sichtbar "noch nicht fertig", nie mit echter
   Funktion zu verwechseln */
.placeholder-screen {
  border: 2px dashed var(--color-border);
  box-shadow: none;
}

.placeholder-screen__title {
  font-size: var(--font-size-subtitle);
}

.placeholder-screen__facts {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-1) var(--space-3);
  font-size: var(--font-size-small);
}

.placeholder-screen__facts dt {
  color: var(--color-text-secondary);
}

.placeholder-screen__facts dd {
  min-width: 0;
  overflow-wrap: anywhere;
}

.route-message__lead {
  font-size: 18px;
  font-weight: var(--font-weight-semibold);
}

.route-message__details summary {
  display: flex;
  align-items: center;
  min-height: var(--touch-min);
  color: var(--color-text-secondary);
  cursor: pointer;
}

.route-message pre {
  max-height: 40vh;
  overflow: auto;
  padding: var(--space-3);
  border-radius: var(--radius-s);
  background: var(--color-surface-muted);
  color: var(--color-text);
  font-size: var(--font-size-small);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Start-Fehler/-Hinweis (main.js): ohne Shell, darum etwas Abstand oben */
.boot-fatal,
.boot-message {
  margin-top: var(--space-5);
}

/* Ersatz-Auswahl (core/pickers.js): Suchfeld, darunter grosse Zeilen */
.picker-sheet .sheet__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.picker-list > li + li {
  border-top: 1px solid var(--color-divider);
}

/* Eintrag mit Zusatz-Knopf daneben (chooseItem renderExtra, z.B. Vorhoeren) */
.picker-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.picker-row .picker-item { flex: 1; min-width: 0; }

.picker-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  width: 100%;
  min-height: 56px;
  padding: var(--space-2);
  border: 0;
  border-radius: var(--radius-m);
  background: transparent;
  color: inherit;
  text-align: left;
  touch-action: manipulation;
}

.picker-item:active {
  background: var(--color-primary-soft);
}

.picker-item__label {
  font-weight: var(--font-weight-semibold);
}

.picker-item__detail {
  font-size: var(--font-size-small);
}

.picker-list__empty {
  padding: var(--space-5) var(--space-2);
  text-align: center;
}

@media (hover: hover) {
  .picker-item:hover {
    background: var(--color-primary-soft);
  }
}

/* Teilen gescheitert (core/files.js shareText): Vorschau + Knopf "Kopieren" */
.share-fallback__title {
  font-weight: var(--font-weight-semibold);
}

.share-fallback__preview {
  margin-top: var(--space-2);
  white-space: pre-line;
  overflow-wrap: anywhere;
}

/* Autosave: leise neben dem Feld; gespeichert mit Haken, Fehler rot + fett */
.autosave-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 1.5em;
  font-size: var(--font-size-small);
  color: var(--color-text-secondary);
}

.autosave-status[data-state="saved"]::before,
.autosave-status[data-state="restored"]::before {
  content: "✓";
  color: var(--color-success-text);
  font-weight: var(--font-weight-bold);
}

/* Aus dem Notfall-Journal gerettet (core/autosave.js): wie "Gespeichert",
   aber in Textfarbe — Anton soll merken, dass die App etwas zurueckgeholt hat. */
.autosave-status[data-state="restored"] {
  color: var(--color-text);
}

.autosave-status[data-state="error"] {
  color: var(--color-danger-text);
  font-weight: var(--font-weight-semibold);
}


/* ── Update-Hinweis ──
      Petrol-Band ueber "Laeuft gerade"; im Ruhigen Modus und im
      Session-Flow blendet ihn ui/shell.js aus. Inhalt am Tablet in der
      Inhaltsspalte (Innenabstand waechst mit der Breite). */
/* Handy: Icon · Text · Schliessen in Zeile 1, "Jetzt aktualisieren"
   darunter (einzeilig gequetscht brach der Text auf drei Zeilen um). */
.update-banner {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--space-2);
  padding: var(--space-1) var(--space-1) var(--space-1) var(--space-4);
  padding-inline: max(var(--space-4), calc((100% - var(--content-max)) / 2)) max(var(--space-1), calc((100% - var(--content-max)) / 2));
  background: var(--color-primary);
  color: var(--color-on-primary);
}

.update-banner > .icon {
  grid-column: 1;
  grid-row: 1;
}

.update-banner__text {
  grid-column: 2;
  grid-row: 1;
  font-weight: var(--font-weight-medium);
}

.update-banner__dismiss {
  grid-column: 3;
  grid-row: 1;
}

.update-banner__apply {
  grid-column: 2 / 4;
  grid-row: 2;
  justify-self: start;
  min-height: var(--btn-h-sm);
  margin-bottom: var(--space-2);
  padding: 0 var(--btn-pad-x);
  border: 2px solid currentColor;
  border-radius: var(--radius-m);
  background: transparent;
  color: inherit;
  font-weight: var(--font-weight-semibold);
  white-space: nowrap;
}

.update-banner .icon-btn {
  color: inherit;
}

@media (min-width: 600px) {
  .update-banner {
    grid-template-columns: auto minmax(0, 1fr) auto auto;
  }

  .update-banner__apply {
    grid-column: 3;
    grid-row: 1;
    margin-bottom: 0;
  }

  .update-banner__dismiss {
    grid-column: 4;
  }
}
