/* Oeffentliche Prospektansicht — mobile first.
   Wird zu ~95% in der WhatsApp-Browseransicht auf Handys geoeffnet:
   keine Web-Fonts, keine Icon-Bibliothek, keine Animationen ausser einer
   kurzen Ladeanzeige. Systemschrift laedt sofort und kostet keine Anfrage.

   Optik: angeglichen an die Flutter-App. Alle Werte stammen aus
   docs/DESIGN_TOKENS.md (aus dem App-Code extrahiert). Farbquelle ist
   AppColors — seit dem Rebrand von Blau auf Orange die einzige; die frueheren
   AppStyles-Duplikate sind dort nur noch Aliasse.

   Die Statusfarben (success/error, "Abgelaufen") sind vom Rebrand
   ausgenommen: sie tragen Ampel-Semantik und sind bewusst KEINE
   Markenfarben.

   KEIN Dark Mode. Die App hat zwar eine vollstaendige dunkle Palette
   (AppColors.darkXxx, AppTheme.darkTheme, ThemeBloc), sie wird aber nie
   gerendert: main.dart uebergibt der MaterialApp weder `darkTheme:` noch
   `themeMode:`, ThemeBloc/ThemeService sind nirgends registriert, und der
   Schalter in den Einstellungen ist fest auf false verdrahtet. Ein
   prefers-color-scheme-Zweig hier wuerde also etwas abbilden, das es im
   Produkt nicht gibt — und zwar mit ungetesteten Werten. Siehe
   docs/DESIGN_TOKENS.md, Abschnitt "Dark Theme". */

:root {
  /* --- Marke: AppColors (Light) ---
     primary faerbt Flaechen, Tints und Icons. primary-dark ist Pflicht,
     sobald WEISSER Text darauf liegt oder der Text klein ist: weiss auf
     primary erreicht nur 3.38:1 und verfehlt AA (Token-Doku, Kontrast). */
  --primary: #e8622c;
  --primary-dark: #c44d1e;
  --primary-light: rgba(232, 98, 44, 0.12);
  /* primary-light deckend ueber Weiss ausgerechnet (Token-Doku: #FCECE6).
     Gebraucht, wo die Pill auf einem beliebigen Prospektfoto liegt — ein
     12-%-Tint waere dort nicht lesbar. */
  --primary-light-solid: #fcece6;
  --accent: #e8622c; /* identisch zu primary */

  /* --- Flaechen und Text --- */
  --background: #faf6f1;
  --background-start: #faf6f1; /* Verlauf oben */
  --background-end: #f0e7dd; /* Verlauf unten */
  --surface: #ffffff;
  --text-primary: #292019;
  --text-secondary: #6e6259;
  --divider: #e7e0d8;
  --grey: rgba(110, 98, 89, 0.5);

  /* --- Statusfarben: Ampel-Semantik, vom Rebrand ausgenommen --- */
  --success: #34d399;
  --error: #f87171;

  /* --- Farben der Prospektkarte --- */
  --card-title: var(--text-primary);
  --card-meta: var(--text-secondary);
  /* Restlaufzeit unter 3 Tagen: primary-dark, NICHT primary — 12 px ohne
     Fettung auf Weiss erreicht mit primary nur 3.38:1. */
  --card-urgent: #c44d1e;
  --card-expired: #f44336; /* Statusfarbe, kein Markenton */
  --card-placeholder: #eeeeee;

  /* --- Eckenradien --- */
  --radius-badge: 4px; /* "Heute"-Badge */
  --radius: 12px; /* Standard: Karten, Bilder, Buttons */
  --radius-chip: 16px; /* Filter-Chips der Startseite */
  --radius-pill: 20px; /* Suchleiste, Pills, Glasflaechen */

  /* --- Schatten (Rohwerte aus der Token-Doku) ---
     Hinweis dort: Flutters blurRadius ist eine Gauss-Standardabweichung,
     CSS nutzt den doppelten Wert — optisch exakt waere blur_css ~ blur x 2.
     Wir fahren die Rohwerte, siehe Bericht. */
  --shadow-subtle: 0 4px 15px rgba(0, 0, 0, 0.05);
  --shadow-circle: 0 4px 10px rgba(0, 0, 0, 0.05);
  --shadow-glass: 0 4px 15px rgba(0, 0, 0, 0.05);
  --shadow-glass-button: 0 4px 20px rgba(232, 98, 44, 0.1);
  /* Deutlich kraeftiger als alle Theme-Schatten — das ist der sichtbare
     Unterschied zwischen Prospektkarten und dem Rest der Oberflaeche.
     Liegt seit dem Karten-Redesign an der KARTE, nicht mehr am Bild. */
  --shadow-card: 0 3px 8px 1px rgba(0, 0, 0, 0.15);

  /* --- Glassmorphism (drei Flaechen nach demselben Muster) ---
     Ein backdrop-filter ist in der App NICHT gesetzt; der Glaseffekt
     entsteht allein aus Transparenz und Verlauf. */
  --glass-bg: rgba(255, 255, 255, 0.8);
  --glass-gradient: linear-gradient(
    to bottom right,
    rgba(255, 255, 255, 0.3),
    rgba(255, 255, 255, 0.1)
  );
  --glass-border: rgba(255, 255, 255, 0.2);
  --glass-border-accent: rgba(232, 98, 44, 0.3);

  /* --- Abstaende: 4er-Skala aus der Verwendung --- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px; /* AppDesign.cardPadding */
  --space-6: 24px;

  /* --- Schriftgroessen: AppTextStyles (im ThemeData verdrahtet) --- */
  --text-headline: 32px; /* 800, letter-spacing -0.5px */
  --text-appbar: 20px; /* headline, verkleinert */
  --text-body-large: 18px; /* 600 */
  --text-body: 16px; /* 400, emptyState */
  --text-body-medium: 14px; /* 500, letter-spacing +0.25px */
  --text-body-small: 12px; /* 400 */
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  /* Scaffold-Verlauf der App. Bewusst ohne background-attachment: fixed —
     das rendert im WhatsApp-Browser und auf iOS unzuverlaessig. Der Verlauf
     spannt sich stattdessen ueber die volle Dokumenthoehe. */
  background: linear-gradient(
      to bottom,
      var(--background-start) 0%,
      var(--background-end) 100%
    )
    no-repeat;
  color: var(--text-primary);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, sans-serif;
  font-size: var(--text-body);
  line-height: 1.45;
}

img {
  max-width: 100%;
  display: block;
}

.wrap {
  max-width: 720px;
  margin: 0 auto;
  padding: 0 var(--space-3) 40px;
}

/* --- Seitenkopf (alle drei Seiten dasselbe Muster) ---
   Linksbuendig wie ein App-Screen: Icon-Chip, daneben die grosse
   Ueberschrift im headline-Stil mit Untertitel darunter. Bewusst KEINE
   zentrierte Landingpage-Optik — die App zentriert nirgends. */

/* Oben ausgerichtet, nicht mittig: bei einzeiliger Ueberschrift sieht beides
   gleich aus, bei einem langen Marktnamen ueber mehrere Zeilen schwimmt der
   Chip sonst in der Mitte statt neben der ersten Zeile zu stehen. */
.page-header {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-6) 0 var(--space-4);
}

.header-chip {
  width: 56px;
  height: 56px;
  flex: 0 0 auto;
  border-radius: var(--radius);
  background: var(--primary-light);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

/* Marktlogos sind beliebige Fotos: sie fuellen den Chip randlos aus. */
.header-chip img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Die Wortmarke ist selbst schon eine gefuellte Flaeche in der Markenfarbe —
   eingerueckt, damit der Chip als Rahmen sichtbar bleibt und nicht zwei
   Quadrate uebereinander stehen. */
.header-chip-brand img {
  object-fit: contain;
  padding: 6px;
}

.header-text {
  min-width: 0; /* erlaubt Ellipsis im Kind */
}

h1 {
  font-size: var(--text-headline);
  font-weight: 800;
  letter-spacing: -0.5px;
  line-height: 1.15;
  margin: 0;
  /* Lange Markt- und Prospektnamen duerfen den Kopf nicht sprengen. */
  overflow-wrap: anywhere;
}

.header-sub {
  margin: var(--space-1) 0 0;
  font-size: var(--text-body-medium);
  font-weight: 500;
  letter-spacing: 0.25px;
  color: var(--text-secondary);
}

/* Rueckfall, wenn der Markt kein Logo hat: Anfangsbuchstabe auf der
   Chip-Flaeche, kein zweites gefuelltes Quadrat. primary-dark statt primary —
   auf dem primary-light-Chip kaeme primary auf 2.94:1 und verfehlte selbst
   die 3:1 fuer grossen Text (Token-Doku, Kontrast). */
.market-logo-fallback {
  width: 100%;
  height: 100%;
  background: transparent;
  color: var(--primary-dark);
  font-size: 24px;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
  text-transform: uppercase;
}

.validity {
  margin: 0 0 var(--space-3);
  color: var(--text-secondary);
  font-size: var(--text-body-medium);
  font-weight: 500;
  letter-spacing: 0.25px;
}

.banner {
  background: rgba(248, 113, 113, 0.12); /* error @ 12 % */
  color: #9b2c2c;
  border-radius: var(--radius);
  padding: 10px var(--space-3);
  font-size: var(--text-body-medium);
  font-weight: 600;
  margin: 0 0 var(--space-3);
}

/* --- Seiten des Prospekts --- */

.pages {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.page {
  margin: 0;
  background: var(--surface);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-subtle);
}

/* Blur-up: die unscharfe Vorschau (Thumbnail, max 400 px) gibt dem Rahmen
   Hoehe und Bildinhalt, das Vollbild liegt deckungsgleich darueber und wird
   eingeblendet, sobald es geladen ist.

   Der Rahmen bekommt seine Hoehe IMMER vom Bild im Fluss: mit Vorschau ist
   das die Vorschau, ohne Vorschau das Vollbild. Deshalb wird das Vollbild
   nur unter `.has-preview` absolut gesetzt — sonst waere der Rahmen ohne
   Vorschau 0 Pixel hoch. */
.page-frame {
  position: relative;
  overflow: hidden; /* klippt die weichen Raender der skalierten Vorschau */
}

.page-frame img {
  display: block;
  width: 100%;
  height: auto;
}

/* 8 px Unschaerfe: genug, damit das 400-px-Thumbnail auf voller Breite nicht
   als grobes Bild gelesen wird, und wenig genug, dass Farben und Aufbau der
   Seite erkennbar bleiben. Die leichte Vergroesserung schiebt den
   ausgefransten Rand, den der Filter erzeugt, aus dem Rahmen heraus. */
.page-preview {
  filter: blur(8px);
  transform: scale(1.05);
}

.page-frame.has-preview .page-full {
  position: absolute;
  inset: 0;
  height: 100%;
  /* Vorschau und Vollbild stammen aus derselben Quelle und haben dasselbe
     Seitenverhaeltnis; `cover` faengt nur Rundungsdifferenzen ab. */
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.25s ease-out;
}

.page-frame.has-preview .page-full.is-loaded {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .page-frame.has-preview .page-full {
    transition: none;
  }
}

.page-label {
  font-size: var(--text-body-small);
  color: var(--text-secondary);
  padding: 6px var(--space-3) var(--space-2);
}

/* --- Zustaende: laden, leer, Fehler --- */

.state {
  text-align: center;
  padding: 56px var(--space-4);
  color: var(--text-secondary);
  font-size: var(--text-body);
}

.state h2 {
  font-size: var(--text-body-large);
  font-weight: 600;
  color: var(--text-primary);
  margin: 0 0 var(--space-2);
}

.state p {
  margin: 0 0 20px;
}

.spinner {
  width: 28px;
  height: 28px;
  margin: 0 auto var(--space-3);
  border: 3px solid var(--divider);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}

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

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation-duration: 3s;
  }
}

/* --- Buttons: Chip-/Pill-Optik der App (Radius 20) --- */

/* Gefuellt mit WEISSEM Text -> primary-dark (4.74:1). primary erreicht dort
   nur 3.38:1 und verfehlt AA — siehe Token-Doku, Abschnitt Kontrast. */
.btn {
  display: inline-block;
  background: var(--primary-dark);
  color: #fff;
  text-decoration: none;
  border: 0;
  border-radius: var(--radius-pill);
  padding: 11px 22px;
  font: inherit;
  font-size: var(--text-body-medium);
  font-weight: 600;
  letter-spacing: 0.25px;
  cursor: pointer;
  box-shadow: var(--shadow-glass-button);
}

/* Glas-Variante wie glassButtonDecoration: transparente Flaeche,
   Verlauf von oben links nach unten rechts, akzentfarbener Rand. */
.btn-secondary {
  background: var(--glass-bg);
  background-image: var(--glass-gradient);
  border: 1.5px solid var(--glass-border-accent);
  color: var(--primary-dark);
}

/* --- Marke / Kopfbereich --- */

.brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-decoration: none;
  color: var(--text-primary);
}

.brand img {
  width: 32px;
  height: 32px;
}

.brand-name {
  font-size: var(--text-appbar);
  font-weight: 800;
  letter-spacing: -0.5px;
}

.site-footer {
  text-align: center;
  padding: 28px var(--space-3) 40px;
  border-top: 1px solid var(--divider);
  margin-top: var(--space-6); /* Sektionswechsel: 24 */
}

/* Rechtliche Pflichtlinks unter der Marke, auf jeder Seite gleich. */
.footer-links {
  margin: var(--space-3) 0 0;
  font-size: var(--text-body-small);
  color: var(--text-secondary);
}

.footer-links a {
  color: inherit;
}

/* --- Abschnitte mit Kachelraster (Startseite + Marktseite) --- */

/* Vertikaler Rhythmus wie auf der Startseite der App (Token-Doku,
   "Vertikaler Rhythmus der Startseite"):

     Kopfblock  -> Sektionsueberschrift   16   (padding-bottom .page-header)
     Ueberschr. -> Chip-Leiste            12
     Chip-Leiste-> erste Kachelreihe      16
     Kachelreihen untereinander           16   (row-gap .tiles)
     Kachelspalten                        12   (column-gap .tiles)
     Sektionswechsel                      24

   Wo eine Ueberschrift direkt an den Seitenkopf anschliesst, traegt der Kopf
   den Abstand — die Ueberschrift bekommt dann kein eigenes margin-top. */
.section-title {
  font-size: var(--text-body-large);
  font-weight: 700;
  margin: var(--space-6) 0 var(--space-3);
}

/* Label-Variante: Kleinkapitel-Ueberschrift ueber einer Liste, wie die
   Abschnittsmarken der App. */
.section-label {
  margin: var(--space-6) 0 var(--space-3);
  font-size: var(--text-body-small);
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-secondary);
}

/* Nur auf der Startseite: dort schliesst die Ueberschrift direkt an den
   Seitenkopf an, und dessen padding-bottom traegt die 16 px. Auf der
   Marktseite steht davor die Info-Karte — da bleibt es beim Sektionswechsel
   von 24 px. */
.home .prospects-section > .section-title:first-child {
  margin-top: 0;
}

/* --- Marktfilter (Chip-Leiste, nur Startseite) ---
   Chip-Optik der App: Radius 16 (Filter-Chips der Startseite, Token-Doku),
   inaktiv weiss mit subtleShadow, aktiv gefuellt in primary-light mit
   Haekchen und primary-dark als Inhaltsfarbe. Horizontal
   scrollbar, wenn mehr Maerkte da sind als Platz — ohne sichtbare
   Scrollbar, wie eine App-Filterzeile. */
.chips {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  /* Ohne diese drei Zeilen steht auf dem Desktop eine Leiste unter den
     Chips; die Schattenkante braucht trotzdem etwas Platz. */
  scrollbar-width: none;
  -ms-overflow-style: none;
  /* Die 2/6 px sind Luft fuer den Chip-Schatten, kein Rhythmus. Sie werden
     oben und unten wieder herausgerechnet, damit sichtbar 12 px zur
     Ueberschrift und 16 px zur ersten Kachelreihe stehen. */
  padding: 2px 0 6px;
  margin-top: -2px;
  margin-bottom: 10px;
  /* Rand-an-Rand scrollen, obwohl .wrap seitlich Innenabstand hat. */
  margin-inline: calc(-1 * var(--space-3));
  padding-inline: var(--space-3);
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}

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

.chip {
  flex: 0 0 auto;
  scroll-snap-align: start;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 0;
  border-radius: var(--radius-chip);
  padding: var(--space-2) var(--space-3);
  font: inherit;
  font-size: var(--text-body-medium);
  font-weight: 500;
  letter-spacing: 0.25px;
  white-space: nowrap;
  cursor: pointer;
  background: var(--surface);
  color: var(--text-primary);
  box-shadow: var(--shadow-subtle);
}

/* Inhaltsfarbe primary-dark, nicht primary: auf der primary-light-Flaeche
   erreicht primary nur 2.94:1 und verfehlt auch die 3:1 fuer Bedienelemente
   (Token-Doku, Kontrast). primary-dark kommt auf 4.13:1. */
.chip[aria-pressed='true'] {
  background: var(--primary-light);
  color: var(--primary-dark);
  box-shadow: none;
}

/* Haekchen nur am aktiven Chip — es soll die Leiste beim Umschalten nicht
   umbrechen lassen, deshalb display statt visibility. */
.chip-check {
  display: none;
  font-weight: 700;
  line-height: 1;
}

.chip[aria-pressed='true'] .chip-check {
  display: inline;
}

.prospects-section .state {
  padding: 32px var(--space-4);
}

/* auto-fill statt fester Spaltenzahl: zwei Kacheln auf dem Handy, mehr auf
   breiten Displays, ohne Media Query. Auf 390 px ergeben sich damit dieselben
   zwei Spalten wie im App-Raster. Spaltenabstand 12, Zeilenabstand 16 — die
   Werte des Startseiten-Grids der App (Token-Doku, "Platzierung im Raster"). */
.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  column-gap: var(--space-3);
  row-gap: var(--space-4);
}

/* ProspectCard-Anatomie nach dem Redesign: EIN geschlossener weisser
   Container aus Bild und Fusszeile. Kein freistehendes Bild mit Text darueber
   mehr — Flaeche, Radius und Schatten gehoeren der Karte, nicht dem Bild.
   Der Aussenabstand kommt weiterhin vom Raster.

   Kartenhoehe = Spaltenbreite x 4/3 + Fusszeile. Genau das ergibt sich hier
   von selbst: das Bild haelt 3:4, die Fusszeile ist inhaltshoch (61 px). */
.tile {
  display: block;
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  text-decoration: none;
  color: var(--card-title);
}

/* Randlos ueber die volle Kartenbreite, Seitenverhaeltnis 3:4 hochkant.
   Nur die OBEREN Ecken gerundet — unten schliesst der weisse Kartenkoerper
   an. Das eigene border-radius zusaetzlich zum overflow der Karte, damit
   Safari die Ecke auch beim Bild sauber beschneidet. */
.tile-thumb {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--card-placeholder);
  overflow: hidden;
}

/* Nur Bild und Platzhalter fuellen die Flaeche — die NEU-Pill liegt darin
   und darf nicht mitgedehnt werden. */
.tile-thumb > img,
.tile-thumb-empty {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover; /* das Bild wird beschnitten, nicht eingepasst */
}

/* Prospekt ohne Bild (Anlage noch nicht abgeschlossen oder Storage-404):
   ruhige Flaeche wie in der App (grey.shade200), kein kaputtes Bildsymbol. */
.tile-thumb-empty {
  display: block;
  background: var(--card-placeholder);
}

/* Schimmer, solange das Thumbnail unterwegs ist. Die Klasse setzt und
   entfernt common.js; die leere Flaeche oben ist ein Endzustand und
   schimmert deshalb NICHT — eine Dauerschleife dort wuerde ein Bild
   versprechen, das nie kommt.

   Der Verlauf liegt als Hintergrund der Flaeche, nicht als Element darueber:
   so bleibt er hinter dem Bild und stoert die von oben nach unten
   aufgebauten Zeilen eines JPEGs nicht. Er ist doppelt so breit wie die
   Kachel und wandert von links nach rechts durch (100% -> -100% verschiebt
   den hellen Streifen genau ueber diese Strecke). */
.tile-thumb.is-loading {
  background-image: linear-gradient(
    90deg,
    transparent 35%,
    rgba(255, 255, 255, 0.7) 50%,
    transparent 65%
  );
  background-repeat: no-repeat;
  background-size: 200% 100%;
  animation: tile-shimmer 1.6s ease-in-out infinite;
}

@keyframes tile-shimmer {
  from {
    background-position: 100% 0;
  }
  to {
    background-position: -100% 0;
  }
}

/* Ohne Animation bleibt die ruhige Platzhalterflaeche — die Geometrie ist
   dieselbe, es fehlt nur die Bewegung. */
@media (prefers-reduced-motion: reduce) {
  .tile-thumb.is-loading {
    background-image: none;
    animation: none;
  }
}

/* "NEU" fuer Prospekte, die juenger als 48 h sind. Oben LINKS — in der App
   ist genau diese Ecke dafuer reserviert, weil dort keine Overlay-Buttons
   sitzen (im Web gibt es die ohnehin nicht).

   Deckendes primary-light statt der 12-%-Variante: die Pill liegt auf einem
   beliebigen Prospektfoto, ein Tint waere dort unlesbar. Der ausgerechnete
   Wert ueber Weiss steht in der Token-Doku (#FCECE6), Inhaltsfarbe
   primary-dark (4.13:1) — dieselbe Regel wie beim Chip. */
.tile-new {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  border-radius: var(--radius-pill);
  padding: 2px var(--space-2);
  background: var(--primary-light-solid);
  color: var(--primary-dark);
  font-size: 11px;
  font-weight: 700;
  line-height: 16px;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}

/* Fusszeile: Innenabstand 12, zwei Zeilen mit 2 px Abstand. Die
   Zeilenhoehen sind fest gesetzt (20 / 15), damit die Fusszeile auf die in
   der App nachgemessenen 61 px kommt: 12 + 20 + 2 + 15 + 12. */
.tile-foot {
  padding: var(--space-3);
}

/* Zeile 1: Marktname ueber die volle Breite, eine Zeile, Ueberlauf mit "…".
   Er ist die Kennung der Kachel — der Prospekttitel lebt auf der
   Prospekt-Detailseite weiter. */
.tile-market {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  line-height: 20px;
  color: var(--card-title);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Zeile 2: Gueltigkeit links. Rechts steht in der App die Entfernung — die
   gibt es im Web nicht (kein Standort), die Seite bleibt hier leer. */
.tile-validity {
  margin: 2px 0 0;
  font-size: var(--text-body-small);
  font-weight: 500;
  line-height: 15px;
  color: var(--card-meta);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Weniger als drei Tage Restlaufzeit. */
.tile-validity.is-urgent {
  color: var(--card-urgent);
}

/* Abgelaufen — Statusrot, kein Markenton. */
.tile-validity.is-expired {
  color: var(--card-expired);
}

/* --- Marktuebersicht (/markets) ---
   Listenzeilen im Kartenstil der App: weisse Flaeche, Radius 12,
   subtleShadow. Links das Logo im Chip, rechts optional das
   Prospekt-Abzeichen. Wo die App-Liste die Entfernung zeigt, steht hier der
   Offen-Status — die Website fragt bewusst keinen Standort ab (siehe
   markets.js). */

.market-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.market-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-subtle);
  text-decoration: none;
  color: var(--text-primary);
}

.market-row-chip {
  width: 44px;
  height: 44px;
}

.market-row-chip .market-logo-fallback {
  font-size: 18px;
}

.market-row-body {
  flex: 1 1 auto;
  min-width: 0; /* erlaubt Ellipsis in den Kindern */
}

.market-row-name {
  margin: 0;
  font-size: var(--text-body);
  font-weight: 700;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.market-row-meta {
  margin: 2px 0 0;
  font-size: var(--text-body-small);
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.market-status {
  font-weight: 600;
}

/* success/error aus AppColors — dieselben Farben, die die App fuer
   "geoeffnet"/"geschlossen" nutzt. */
.market-status.is-open {
  color: var(--success);
}

.market-status.is-closed {
  color: var(--error);
}

/* Kreis mit der Anzahl aktueller Prospekte statt eines Ja/Nein-Labels. Feste
   Breite/Hoehe plus min-width halten den Kreis auch bei zweistelligen Zahlen
   rund statt oval. */
.market-row-count {
  flex: 0 0 auto;
  align-self: center;
  min-width: 24px;
  height: 24px;
  padding: 0 var(--space-1);
  border-radius: 999px;
  background: var(--primary-light); /* wie der aktive Chip */
  color: var(--primary-dark); /* nicht primary: 2.94:1 auf der Chipflaeche */
  font-size: var(--text-body-small);
  font-weight: 700;
  line-height: 24px;
  text-align: center;
  white-space: nowrap;
}

/* Weiterfuehrender Link unter einer Liste ("Alle Märkte ansehen →"). */
.list-link {
  display: inline-block;
  margin-top: var(--space-4);
  /* 14 px halbfett auf hellem Grund: primary erreicht 3.38:1 und liegt damit
     unter AA fuer normalen Text — deshalb primary-dark. */
  color: var(--primary-dark);
  font-size: var(--text-body-medium);
  font-weight: 600;
  letter-spacing: 0.25px;
  text-decoration: none;
}

.list-link::after {
  content: ' →';
}

/* --- Marktseite: Info-Karte ---
   Eine Flaeche statt dreier loser Bloecke: Name mit Offen-Status, Adresse
   als Route-Zeile, Oeffnungszeiten zum Aufklappen. Zeilen durch 1px-Divider
   getrennt. */

.info-card {
  margin-top: var(--space-6);
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-subtle);
  overflow: hidden;
}

.info-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
}

/* Trennlinie zwischen den Zeilen — nicht ueber der ersten. */
.info-row + .info-row,
.info-details {
  border-top: 1px solid var(--divider);
}

.info-chip {
  width: 48px;
  height: 48px;
}

.info-chip .market-logo-fallback {
  font-size: 20px;
}

.info-head-text {
  min-width: 0;
}

.info-name {
  margin: 0;
  font-size: var(--text-body-large);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: normal;
  overflow-wrap: anywhere;
}

/* Freitext-Beschreibung (keine Adresse) unter dem Namen. */
.info-note {
  margin: var(--space-1) 0 0;
  font-size: var(--text-body-small);
  color: var(--text-secondary);
}

/* Offen-Status als gefuellte Pill, wie in der App. Die Farben sind
   success/error aus AppColors, die Flaeche dieselbe Farbe bei 15 %. */
.status-pill {
  display: inline-block;
  margin-top: 6px;
  border-radius: var(--radius-pill);
  padding: 2px var(--space-2);
  font-size: var(--text-body-small);
  font-weight: 600;
}

.status-pill.is-open {
  background: rgba(52, 211, 153, 0.15);
  color: var(--success);
}

.status-pill.is-closed {
  background: rgba(248, 113, 113, 0.15);
  color: var(--error);
}

/* Anklickbare Zeilen: ganze Flaeche ist Ziel, Chevron rechts. */
.info-row-action {
  text-decoration: none;
  color: var(--text-primary);
  cursor: pointer;
}

.info-icon {
  flex: 0 0 auto;
  color: var(--primary);
}

.info-row-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  font-size: var(--text-body-medium);
  font-weight: 500;
  letter-spacing: 0.25px;
}

.info-row-sub {
  margin-top: 2px;
  font-size: var(--text-body-small);
  font-weight: 400;
  letter-spacing: normal;
  color: var(--text-secondary);
}

.info-chevron {
  flex: 0 0 auto;
  color: var(--text-secondary);
  transition: transform 0.15s ease;
}

@media (prefers-reduced-motion: reduce) {
  .info-chevron {
    transition: none;
  }
}

/* Aufklappbare Oeffnungszeiten. Das Standard-Dreieck der Browser entfaellt,
   den Zustand zeigt der gedrehte Chevron. */
.info-details > summary {
  list-style: none;
}

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

.info-details[open] > summary .info-chevron {
  transform: rotate(90deg);
}

/* --- Marktseite: Wochentabelle (in der Karte, aufgeklappt) --- */

.hours {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 2px var(--space-4);
  margin: 0;
  padding: 0 var(--space-4) var(--space-4);
  font-size: var(--text-body-medium);
}

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

.hours dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.hours .is-today {
  font-weight: 700;
  color: var(--text-primary);
}

.market-name-link {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--divider);
}

/* --- App-Hinweis (fix, Prospekt- und Marktseite) --- */

/* Glasflaeche wie glassDecoration: Radius 20, transparente Flaeche mit
   Verlauf, heller Rand. Oben abgerundet, weil der Hinweis am unteren
   Bildschirmrand klebt. */
.app-banner {
  position: fixed;
  left: var(--space-2);
  right: var(--space-2);
  bottom: var(--space-2);
  z-index: 10;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 10px var(--space-3);
  padding-bottom: calc(10px + env(safe-area-inset-bottom));
  background: var(--glass-bg);
  background-image: var(--glass-gradient);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-glass);
  /* EINZIGE Abweichung von der Token-Doku: dort steht, dass die App KEIN
     backdrop-filter setzt. In der App liegen die Glasflaechen aber als
     Suchleiste oben ueber einem Verlauf; hier klebt der Hinweis fix ueber
     durchlaufendem Seiteninhalt. Ohne Weichzeichner scheint bei 80 % Deckung
     der Fusszeilen-Schriftzug hindurch und kollidiert mit dem Bannertext.
     Ersatzlos entfernbar, wenn die Optik naeher an der App liegen soll —
     dann aber den Hinweis deckend machen. */
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.app-banner-link {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--text-primary);
  min-width: 0;
}

.app-banner-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius);
  flex: 0 0 auto;
  background: var(--surface);
  border: 1px solid var(--divider);
  padding: 4px;
}

.app-banner-text {
  font-size: 13px;
  line-height: 1.3;
}

.app-banner-close {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border: 0;
  background: transparent;
  color: var(--text-secondary);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

/* Platz unter dem fixen Hinweis, damit er den Seitenfuss nicht verdeckt.
   Gemessen: Hinweis 58 px hoch plus 8 px Abstand zum Rand — der Rest ist
   Luft, damit der Seitenfuss am Seitenende sichtbar frei steht und nicht
   auf 6 px an den Hinweis heranlaeuft. */
.has-app-banner {
  padding-bottom: calc(96px + env(safe-area-inset-bottom));
}

/* --- "Die App kommt bald" (Startseite, Ziel des App-Hinweises) --- */

.app-soon {
  text-align: center;
  margin: var(--space-6) 0 40px; /* Sektionswechsel: 24 */
  padding: 28px 20px;
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-subtle);
}

.app-soon img {
  margin: 0 auto 10px;
}

.app-soon h2 {
  font-size: var(--text-body-large);
  font-weight: 600;
  margin: 0 0 6px;
}

.app-soon p {
  margin: 0 auto;
  max-width: 380px;
  color: var(--text-secondary);
  font-size: var(--text-body);
}

/* --- Rechtstexte (/impressum, /datenschutz) ---
   Reiner Lesetext statt Kacheln/Karten: Ueberschriften und Absaetze im
   Seitenrhythmus der App-Sektionen (24/12), keine eigene Optik. */

.legal h2 {
  font-size: var(--text-body-large);
  font-weight: 700;
  margin: var(--space-6) 0 var(--space-3);
}

.legal h2:first-of-type {
  margin-top: var(--space-4);
}

.legal p {
  margin: 0 0 var(--space-3);
}

.legal a {
  color: var(--primary-dark);
}

.legal .placeholder {
  background: var(--primary-light);
  border-radius: var(--radius-badge);
  padding: 0 4px;
}

[hidden] {
  display: none !important;
}
