/* PixMop Theme — Apple-nativ, zwei Modi, gesteuert von der Systemeinstellung.
   Dunkel ist der Default (die App lebt über Fotos, Schwarz tritt zurück), Hell kommt
   über `prefers-color-scheme: light`. Beide Modi sind vollständig; die Komponenten
   konsumieren ausschließlich die Tokens unten und wissen nichts vom aktiven Modus.

   Palette: die finale Token-Liste des Nutzers — warme Neutrale (OKLCH-Hue ~34-58,
   Stone-Familie) plus eine blaue Primärrampe. Blau ist die Signaturfarbe in BEIDEN
   Modi; Dunkel ist nicht mehr monochrom.

   Zwei Blau-Rollen, weil ein Ton nicht beides kann:
     --accent      Füllfarbe (primary). Dunkel bewusst tief (Blue-800) — darauf liegt
                   immer --accent-contrast, nie der Hintergrund.
     --accent-ink  Blau auf dem App-Hintergrund: Text, Icons, Ringe, Spinner.
                   Dunkel eine Stufe heller (Blue-500, 5.3:1 auf --bg-a), hell = primary.
   Wer Blau auf eine Fläche schreibt, nimmt --accent-ink. Wer eine Fläche füllt, --accent. */
:root {
  color-scheme: dark light;

  /* Eine Kurve fuer die ganze App. Die eingebauten CSS-Easings sind zu weich,
     um sich wie eine Reaktion anzufuehlen. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);

  /* Flächen — background / card / muted der Token-Liste */
  --bg-a: oklch(0.147 0.004 49.25);
  --bg-b: oklch(0.216 0.006 56.043);
  /* Der Schein oben ist jetzt blau: die Signaturfarbe liegt schon im Hintergrund. */
  --bg-glow: oklch(0.623 0.214 259.815 / 14%);
  --glass: oklch(0.268 0.007 34.298 / 55%);
  --glass-strong: oklch(0.268 0.007 34.298 / 85%);
  --glass-border: oklch(1 0 0 / 10%);
  --glass-highlight: oklch(1 0 0 / 15%);
  --media-placeholder: oklch(0.216 0.006 56.043);
  --backdrop-scrim: oklch(0.147 0.004 49.25 / 66%);
  --track: oklch(1 0 0 / 15%);

  /* Text */
  --text: oklch(0.985 0.001 106.423);
  --text-dim: oklch(0.709 0.01 56.259);

  /* Akzente */
  --accent: oklch(0.424 0.199 265.638);
  --accent-hover: oklch(0.424 0.199 265.638 / 90%);
  --accent-contrast: oklch(0.97 0.014 254.604);
  --accent-ink: oklch(0.623 0.214 259.815);
  --accent-soft: oklch(0.623 0.214 259.815 / 16%);
  /* Kante der gefüllten Taste: Blue-800 allein hebt sich vom fast schwarzen Grund
     nicht ab (2.2:1). Die hellere Kante trägt die Komponentengrenze (>3:1). */
  --accent-edge: oklch(0.623 0.214 259.815 / 70%);

  --danger: oklch(0.704 0.191 22.216);
  --danger-hover: oklch(0.704 0.191 22.216 / 90%);
  --danger-contrast: oklch(0.216 0.006 56.043);
  --success: oklch(0.796 0.152 158);
  --success-contrast: oklch(0.216 0.006 56.043);
  --gold: oklch(0.853 0.118 87);
  --gold-contrast: oklch(0.216 0.006 56.043);

  /* Fokus: eigener Ring-Token (nicht der Akzent), wie im Token-Satz vorgegeben. */
  --ring: oklch(0.553 0.013 58.071);
  --ring-soft: oklch(0.553 0.013 58.071 / 50%);

  /* Schatten tragen den Hintergrundton, nie reines Schwarz auf Verdacht */
  --shadow-card: 0 1px 2px oklch(0 0 0 / 40%), 0 12px 32px -8px oklch(0 0 0 / 55%);
  --shadow-raised: 0 2px 4px oklch(0 0 0 / 45%), 0 24px 60px -12px oklch(0 0 0 / 70%);

  /* Radien: 0.875rem ist der Basisradius des Token-Satzes, die größeren sind
     Vielfache davon (1× innen, 1.5× Karte, 2× umschließende Leiste). */
  --radius-base: 0.875rem;
  --radius-sm: var(--radius-base);
  --radius: calc(var(--radius-base) * 1.5);
  --radius-lg: calc(var(--radius-base) * 2);
  --radius-pill: 999px;

  /* Spacing-Skala — 4er-Raster, damit der vertikale Rhythmus überall derselbe ist */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
}

@media (prefers-color-scheme: light) {
  :root {
    /* Weiß auf warmem Stone — die Karten sind gefrostetes Weiß, der Akzent bleibt Blau. */
    --bg-a: oklch(1 0 0);
    --bg-b: oklch(0.97 0.001 106.424);
    --bg-glow: oklch(0.623 0.214 259.815 / 10%);
    --glass: oklch(1 0 0 / 74%);
    --glass-strong: oklch(0.97 0.001 106.424 / 92%);
    --glass-border: oklch(0.923 0.003 48.717);
    --glass-highlight: oklch(1 0 0 / 80%);
    --media-placeholder: oklch(0.923 0.003 48.717);
    --backdrop-scrim: oklch(1 0 0 / 72%);
    --track: oklch(0.923 0.003 48.717);

    --text: oklch(0.147 0.004 49.25);
    --text-dim: oklch(0.553 0.013 58.071);

    /* Hell trägt primary auch als Schrift: 6.8:1 auf Weiß — Füllung und Tinte sind
       hier derselbe Ton, die Kante darf verschwinden. */
    --accent: oklch(0.488 0.243 264.376);
    --accent-hover: oklch(0.488 0.243 264.376 / 90%);
    --accent-contrast: oklch(0.97 0.014 254.604);
    --accent-ink: oklch(0.488 0.243 264.376);
    --accent-soft: oklch(0.488 0.243 264.376 / 10%);
    --accent-edge: transparent;

    --danger: oklch(0.577 0.245 27.325);
    --danger-hover: oklch(0.577 0.245 27.325 / 90%);
    --danger-contrast: oklch(1 0 0);
    /* Grün und Gold sind hier dunkler als im Dunkelmodus: auf Weiß muss beides
       als Schrift lesbar bleiben (5.0:1 bzw. 4.9:1), nicht nur als Fläche. */
    --success: oklch(0.52 0.14 158);
    --success-contrast: oklch(1 0 0);
    --gold: oklch(0.55 0.13 75);
    --gold-contrast: oklch(1 0 0);

    --ring: oklch(0.709 0.01 56.259);
    --ring-soft: oklch(0.709 0.01 56.259 / 55%);

    /* Warm getönt statt neutralgrau — der Schatten gehört zur Fläche, auf der er liegt. */
    --shadow-card: 0 1px 2px oklch(0.147 0.004 49.25 / 7%), 0 10px 28px -8px oklch(0.147 0.004 49.25 / 14%);
    --shadow-raised: 0 2px 6px oklch(0.147 0.004 49.25 / 9%), 0 20px 48px -12px oklch(0.147 0.004 49.25 / 20%);
  }
}

* { box-sizing: border-box; margin: 0; }

html, body, #root { height: 100%; }

/* Apple-nativ: keine Web-Artefakte */
html { -webkit-text-size-adjust: 100%; }

body {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif;
  color: var(--text);
  /* Der radiale Schein bricht die gleichmäßige Verlaufsfläche auf — ohne ihn wirkt
     der Hintergrund wie ein Farbverlauf-Preset. */
  background:
    radial-gradient(120% 80% at 50% -10%, var(--bg-glow), transparent 60%),
    linear-gradient(170deg, var(--bg-a), var(--bg-b));
  background-attachment: fixed;
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  text-rendering: optimizeLegibility;
  font-variant-numeric: tabular-nums;
}

::-webkit-scrollbar { display: none; }

/* iOS-Text-Styles (Human Interface Guidelines) — Tracking und Leading sind
   größenabhängig, exakt nach Apples SF-Pro-Tabelle. */
.text-large-title { font-size: 34px; line-height: 41px; font-weight: 700; letter-spacing: 0.37px; }
.text-title2 { font-size: 22px; line-height: 28px; font-weight: 700; letter-spacing: 0.35px; }
.text-body { font-size: 17px; line-height: 22px; letter-spacing: -0.41px; }
.text-footnote { font-size: 13px; line-height: 18px; letter-spacing: -0.08px; color: var(--text-dim); }

/* Überschriften brechen nie mit einem einzelnen Wort in der letzten Zeile. */
h1, h2 { text-wrap: balance; }
p { text-wrap: pretty; }

/* Sektionslabel: klein, ruhig, nicht in Versalien geschrien. */
.section-label {
  font-size: 13px; line-height: 18px; font-weight: 600; letter-spacing: -0.08px;
  color: var(--text-dim);
}

.glass {
  background: var(--glass);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  backdrop-filter: blur(24px) saturate(1.4);
  -webkit-backdrop-filter: blur(24px) saturate(1.4);
  /* Innenkante: das Licht, das sich in echter Glaskante bricht. */
  box-shadow: var(--shadow-card), inset 0 1px 0 var(--glass-highlight);
}

.glass-strong { background: var(--glass-strong); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 14px 20px; border-radius: var(--radius-sm);
  border: 1px solid var(--glass-border);
  background: var(--glass-strong); color: var(--text);
  font-size: 16px; font-weight: 600; letter-spacing: -0.2px; cursor: pointer;
  backdrop-filter: blur(20px) saturate(1.4);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  box-shadow: inset 0 1px 0 var(--glass-highlight);
  /* Asymmetrisch: der Druck schnappt, das Loslassen entspannt. Und eine eigene
     Kurve — das eingebaute `ease` hat für eine Rueckmeldung zu wenig Zug. */
  transition: transform 180ms var(--ease-out), filter 180ms var(--ease-out),
              opacity 150ms var(--ease-out), background-color 150ms ease;
}
.btn:active {
  transform: scale(0.96);
  transition: transform 90ms var(--ease-out), filter 90ms var(--ease-out);
}
/* Gesperrt heißt gesperrt: kein Hover, kein Cursor, halbe Deckkraft (shadcn-Konvention). */
.btn:disabled { opacity: 0.5; cursor: default; pointer-events: none; }
.btn-accent {
  background: var(--accent); border-color: var(--accent-edge);
  color: var(--accent-contrast);
  box-shadow: var(--shadow-card);
}
.btn-danger {
  background: var(--danger); border-color: transparent; color: var(--danger-contrast);
  box-shadow: var(--shadow-card);
}
/* Navigations-Button: Text in der Akzentfarbe, keine Fläche. In der Titelleiste
   ist die Aktion selbst die Information — eine Kachel drumherum ist Lärm.
   Blau in beiden Modi, im Dunkeln eine Stufe heller: genau iOS. */
.btn-quiet {
  background: transparent; border-color: transparent; box-shadow: none;
  backdrop-filter: none; -webkit-backdrop-filter: none;
  color: var(--accent-ink); padding: 10px 6px;
}
.btn-quiet:disabled { opacity: 0.35; }

/* Hover nur, wo es einen Zeiger gibt — auf dem Touchscreen bliebe der Zustand
   nach dem Tippen kleben. Die Abstufung ist shadcns `bg-primary/90`: dieselbe
   Farbe, 10 % durchlässiger, damit der Grund leicht durchkommt. */
@media (hover: hover) {
  .btn:hover:not(:disabled) { background: var(--glass-highlight); }
  .btn-accent:hover:not(:disabled) { background: var(--accent-hover); }
  .btn-danger:hover:not(:disabled) { background: var(--danger-hover); }
  .btn-quiet:hover:not(:disabled) { background: var(--accent-soft); }
  .action-bar > .btn:hover:not(:disabled) { background: var(--glass-strong); }
}

/* Entscheidungsleiste: ein Material mit vier Feldern statt vier schwebender Kacheln —
   die vier Optionen gehören zusammen, also sitzen sie auf einer Fläche. */
.action-bar { display: flex; gap: var(--sp-1); padding: 6px; border-radius: var(--radius-lg); }
.action-bar > .btn {
  flex: 1; min-width: 0; flex-direction: column; gap: 5px;
  padding: 10px 4px; font-size: 12px; font-weight: 500; letter-spacing: -0.08px;
  background: transparent; border-color: transparent; box-shadow: none;
  backdrop-filter: none; -webkit-backdrop-filter: none;
  border-radius: var(--radius-sm);
}
.action-bar > .btn:active { background: var(--glass-strong); }
.action-bar > .btn > span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}

/* Toast: schwebt als Pille über allem, kommt von unten herein. */
.toast {
  position: fixed; z-index: 10;
  bottom: calc(env(safe-area-inset-bottom) + 28px);
  left: 50%; transform: translateX(-50%);
  max-width: calc(100% - 2 * var(--sp-4));
  padding: 12px 20px; border-radius: var(--radius-pill);
  font-size: 14px; text-align: center;
  opacity: 1;
  /* Keyframe fuer den Eingang, nicht @starting-style: das gibt es erst ab
     iOS 17.5, das Deployment-Target ist iOS 15. Wiederholbar wird die
     Animation ueber einen Remount (key={msg} in App.tsx). */
  animation: pixmop-toast-in 260ms var(--ease-out);
}

@keyframes pixmop-toast-in {
  from { opacity: 0; transform: translate(-50%, 12px); }
}

/* Ausgang auf demselben Weg, auf dem er hereinkam. Kuerzer als der Eingang:
   das Verschwinden ist die Systemantwort, nicht die Aussage. */
.toast.is-leaving {
  opacity: 0; transform: translate(-50%, 12px);
  transition: opacity 180ms var(--ease-out), transform 180ms var(--ease-out);
}

/* Combo-Pille: die laufende Serie neben dem Fortschritt. Klein und in Gold —
   sie ist eine Belohnung, kein zweiter Fortschrittsbalken, und darf den Zähler
   daneben nicht überstimmen. Der Sprung bei jedem Zuwachs kommt über einen
   Remount (key={combo}), damit die Animation wirklich neu startet. */
.combo-pill {
  display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto;
  padding: 3px 8px; border-radius: var(--radius-pill);
  font-size: 12px; font-weight: 600; letter-spacing: -0.08px;
  color: var(--gold); line-height: 16px;
  /* Der volle Kartenschatten wäre für eine 22 px hohe Pille zuviel Gewicht. */
  box-shadow: inset 0 1px 0 var(--glass-highlight);
  /* Kurz und ohne Ueberschwingen: die Pille springt bei JEDEM Zuwachs, also
     dutzendfach pro Sitzung. Ein Pop mit Bounce waere hier Dauerbewegung. */
  animation: pixmop-combo-pop 120ms var(--ease-out);
}

/* Basis-Maßstab 1, damit der reduced-motion-Block (animation: none) die Pille
   einfach ruhig stehen lässt, statt sie in einer Zwischengröße einzufrieren. */
@keyframes pixmop-combo-pop {
  0% { transform: scale(1.08); }
  100% { transform: scale(1); }
}

/* Icon-only: quadratisch, damit die Trefferfläche nicht vom Glyph abhängt. */
.btn-icon { padding: 0; width: 44px; height: 44px; }

/* Press-State: Feedback auf pointer-down, nicht erst beim Loslassen. */
.pressable { transition: transform 180ms var(--ease-out), filter 180ms var(--ease-out); }
.pressable:active {
  transform: scale(0.96); filter: brightness(1.15);
  transition: transform 90ms var(--ease-out), filter 90ms var(--ease-out);
}

@media (prefers-color-scheme: light) {
  /* Auf Weiß macht Aufhellen die Fläche flach — dort dunkelt der Druck ab. */
  .pressable:active { filter: brightness(0.96); }
}

/* Tastatur-Fokus sichtbar halten (Pointer-Klicks bekommen keinen Ring).
   Nach shadcn: ein 3 px breiter, halbtransparenter Ring aus --ring plus eine
   deckende Kante in derselben Farbe. Der weiche Ring liest sich auf Foto,
   Glas und Fläche gleich gut, ohne wie ein Systemdialog zu schreien. */
.pressable:focus-visible,
.btn:focus-visible {
  outline: 3px solid var(--ring-soft);
  outline-offset: 2px;
  border-color: var(--ring);
}

/* Ladeanzeige: ein Ring, der sich dreht — kein Emoji, das je nach Plattform anders aussieht.
   Bei prefers-reduced-motion steht er still und bleibt als Form lesbar. */
.spinner {
  width: 28px; height: 28px; border-radius: 50%;
  border: 2.5px solid var(--track);
  border-top-color: var(--accent-ink);
  animation: pixmop-spin 0.9s linear infinite;
}
.spinner-sm { width: 20px; height: 20px; border-width: 2px; }

@keyframes pixmop-spin { to { transform: rotate(360deg); } }

/* Foto-Hintergrund hinter dem Kartenstapel — eigene Compositing-Schicht, keine
   Zeigerannahme, z-index -1 damit er unter dem Screen-Inhalt und über dem
   Body-Verlauf liegt. Während des Drags wird hier nichts neu gezeichnet. */
.photo-backdrop {
  position: fixed; inset: 0; z-index: -1;
  pointer-events: none; overflow: hidden;
  transform: translateZ(0);
}

.photo-backdrop-layer {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  filter: blur(40px) saturate(1.5);
  /* Der Blur frisst die Ränder — leicht überskalieren, sonst leuchtet der Rand durch. */
  transform: scale(1.25);
  opacity: 1;
  animation: pixmop-backdrop-in 450ms var(--ease-out);
  /* Kein dauerhaftes will-change: eine bildschirmfuellende blur(40px)-Ebene
     dauerhaft auf eine eigene Compositing-Schicht zu heben kostet Speicher —
     auf genau den aelteren Geraeten, fuer die diese App gedacht ist. Die
     einmalige Einblendung schafft der Compositor auch ohne Vorwarnung. */
}

/* Basis-Deckkraft 1, die Animation startet bei 0: bei prefers-reduced-motion
   (animation: none) steht die Ebene damit einfach sofort da, statt unsichtbar zu bleiben. */
@keyframes pixmop-backdrop-in { from { opacity: 0; } }

.photo-backdrop-scrim {
  position: absolute; inset: 0;
  background: var(--backdrop-scrim);
}

.screen {
  min-height: 100dvh; display: flex; flex-direction: column;
  padding: calc(env(safe-area-inset-top) + var(--sp-4)) var(--sp-4)
           calc(env(safe-area-inset-bottom) + var(--sp-5));
}

/* Materialien werden frostiger statt transparenter, wenn der Nutzer das so will.
   Die gefüllten Varianten behalten ihre Farbe — sie sind ohnehin deckend, und ihre
   Fläche ist die Aussage. */
@media (prefers-reduced-transparency: reduce) {
  .glass, .btn:not(.btn-accent):not(.btn-danger):not(.btn-quiet) {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: var(--bg-b);
  }
}

@media (prefers-contrast: more) {
  :root {
    --glass-border: currentColor;
    --text-dim: var(--text);
    /* Volle Deckkraft auf der Fläche statt Ton-in-Ton. */
    --accent-soft: transparent;
    --ring-soft: var(--ring);
  }
}

/* Reduzierte Bewegung heißt sanfter, nicht aus: Deckkraft und Farbe tragen
   Bedeutung und bleiben deshalb animiert. Nur was sich durch den Raum bewegt,
   verschwindet — genau die Klasse von Bewegung, die Beschwerden verursacht. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-property: opacity, background-color, border-color, color, filter !important;
    transition-duration: 150ms !important;
  }
  /* Helligkeit bleibt als Rückmeldung, die Skalierung entfällt. */
  .pressable:active { transform: none; }
  .btn:active { transform: none; }
  .toast, .toast.is-leaving { transform: translateX(-50%); }

  /* Ein stehender Spinner liest sich als Absturz. Statt Rotation ein Puls —
     Bewegung ohne Ortsveränderung ist die nicht-vestibuläre Entsprechung. */
  .spinner {
    animation: pixmop-spinner-pulse 1.4s ease-in-out infinite !important;
    animation-duration: 1.4s !important;
    border-top-color: var(--accent-ink);
  }
  @keyframes pixmop-spinner-pulse {
    0%, 100% { opacity: 0.35; }
    50% { opacity: 1; }
  }
}
