/* ==========================================================================
   A11ySHOT – zentrale Stylesheet-Datei
   BEM-Notation (.block__element--modifier), alle Werte über Custom Properties
   ========================================================================== */

:root {
  /* Farben */
  --color-bg: #f6f5fb;
  --color-surface: #ffffff;
  --color-text: #16181d;
  --color-text-muted: #5b6472;
  --color-border: #e1e0ec;

  --color-primary: #6d28d9;
  --color-primary-hover: #5b21b6;
  --color-primary-contrast: #ffffff;
  --color-primary-bg: #efe9fc;
  /* Füllfarbe der Fortschrittsanzeige im Status-Balken: rechnerisch gegen
     den Statustext (--color-primary) geprüft (~4.74:1, weiterhin AA) –
     dunkler als --color-primary-bg, damit die Füllung sichtbar ist, aber
     hell genug, dass der Text in beiden Zuständen lesbar bleibt. */
  --color-primary-bg-fill: #dcccf7;

  --color-success: #0f7a3d;
  --color-success-bg: #e3f6ea;

  --color-danger: #b3261e;
  --color-danger-bg: #fceceb;

  --color-warning: #9a6700;
  --color-warning-bg: #fff4e5;

  /* Fokusring: Blau statt Markenfarbe, damit er unabhängig vom Hintergrund
     (helle Karten wie auch violette Buttons) zuverlässig >= 3:1 Kontrast
     erreicht (WCAG 2.2, 1.4.11 Non-text Contrast). */
  --color-focus: #1d4ed8;

  /* Abstände */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2.5rem;
  --space-7: 3.5rem;

  /* Typografie */
  --font-family-base: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-family-mono: ui-monospace, "SF Mono", "Cascadia Code", "Roboto Mono", Consolas, monospace;
  --font-size-xs: 0.75rem;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-lg: 1.25rem;
  --font-size-xl: 1.75rem;
  --font-size-2xl: 2.25rem;
  --line-height-base: 1.6;

  /* Sonstiges */
  --radius-sm: 0.5rem;
  --radius-base: 0.875rem;
  --radius-lg: 1.25rem;
  --radius-full: 999px;
  --shadow-sm: 0 1px 2px rgba(31, 24, 61, 0.06);
  --shadow-base: 0 12px 28px -12px rgba(31, 24, 61, 0.16), 0 2px 6px rgba(31, 24, 61, 0.06);
  --transition-fast: 150ms ease;
}

/* --------------------------------------------------------------------------
   Reset & Basis
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: var(--font-family-base);
  font-size: var(--font-size-base);
  line-height: var(--line-height-base);
  color: var(--color-text);
  background:
    radial-gradient(ellipse 60rem 30rem at top left, var(--color-primary-bg) 0%, transparent 60%),
    var(--color-bg);
}

h1,
h2,
h3 {
  line-height: 1.25;
}

:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

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

/* Farbwerte (Hex/HSL/OKLCH) und Kontrastverhältnisse: Ziffern/Zeichen in
   Monospace sind deutlich leichter zu lesen und zu vergleichen als in der
   proportionalen Basisschrift. */
.mono {
  font-family: var(--font-family-mono);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   Skip-Link
   -------------------------------------------------------------------------- */

.skip-link {
  position: absolute;
  top: -3rem;
  left: var(--space-3);
  z-index: 100;
  padding: var(--space-2) var(--space-4);
  background-color: var(--color-primary);
  color: var(--color-primary-contrast);
  border-radius: var(--radius-sm);
  text-decoration: none;
  font-weight: 600;
  transition: top var(--transition-fast);
}

.skip-link:focus {
  top: var(--space-3);
}

/* --------------------------------------------------------------------------
   Layout-Container
   -------------------------------------------------------------------------- */

.layout {
  max-width: 64rem;
  margin-inline: auto;
  padding-inline: var(--space-4);
}

.intro {
  margin-block: var(--space-6) 0;
  color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

.app-header {
  background-color: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}

.app-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-5);
}

.app-header__brand {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.app-header__title {
  margin: 0;
  line-height: 0;
}

.app-header__logo {
  display: block;
  height: 2.75rem;
  width: auto;
}

.app-header__controls {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: var(--space-2);
}

.app-header__lang-toggle {
  flex-shrink: 0;
  padding: var(--space-2) var(--space-4);
  background-color: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  font-family: inherit;
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.app-header__lang-toggle:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* --------------------------------------------------------------------------
   Section (generischer Abschnitts-Block für main-Inhalte)
   -------------------------------------------------------------------------- */

.section {
  margin-block: var(--space-6);
  padding: var(--space-5);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-top: 4px solid var(--color-primary);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-base);
}

.section--hidden {
  display: none;
}

/* --------------------------------------------------------------------------
   Color-Format (Hex/HSL/OKLCH-Umschalter direkt an der jeweiligen Farb-Box)
   -------------------------------------------------------------------------- */

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

.color-format__label {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text-muted);
}

.color-format__select {
  padding: var(--space-1) var(--space-3);
  background-color: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  font-family: inherit;
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.color-format__select:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.section__heading-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-end: var(--space-4);
}

.section__heading-row .section__heading {
  margin-block-end: 0;
}

.section__heading {
  margin-block: 0 var(--space-4);
  font-size: var(--font-size-lg);
  font-weight: 700;
}

.section__subheading {
  margin-block: var(--space-5) var(--space-3);
  font-size: var(--font-size-base);
  font-weight: 600;
}

.section__note {
  margin-block: var(--space-4) 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   Dropzone
   -------------------------------------------------------------------------- */

.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-7) var(--space-4);
  text-align: center;
  border: 2px dashed var(--color-border);
  border-radius: var(--radius-base);
  background-color: var(--color-bg);
  transition: border-color var(--transition-fast), background-color var(--transition-fast);
}

.dropzone--dragover {
  border-color: var(--color-primary);
  background-color: var(--color-primary-bg);
}

.dropzone__icon {
  width: 2.75rem;
  height: 2.75rem;
  color: var(--color-primary);
}

.dropzone__text {
  margin: 0;
  font-size: var(--font-size-base);
  font-weight: 600;
}

.dropzone__hint {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.dropzone__button {
  display: inline-block;
  padding: var(--space-2) var(--space-5);
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-hover));
  color: var(--color-primary-contrast);
  border: none;
  border-radius: var(--radius-full);
  font-family: inherit;
  font-size: var(--font-size-base);
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}

.dropzone__button:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 16px -6px rgba(109, 40, 217, 0.5);
}

.dropzone__button:active {
  transform: translateY(0);
}

/* --------------------------------------------------------------------------
   Status (aria-live Region)
   -------------------------------------------------------------------------- */

.status {
  position: relative;
  min-height: 1.5em;
  margin-block: var(--space-4);
  padding: var(--space-3) var(--space-4);
  overflow: hidden;
  border-radius: var(--radius-full);
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text-muted);
  text-align: center;
}

/* Vor dem ersten Bild-Upload ist #status-text leer (siehe app.js/setStatus) –
   ohne diese Regel bliebe trotzdem eine leere Pille mit voller
   Mindesthöhe/Außenabstand stehen und würde unter der Dropzone eine
   auffällige Leerfläche erzeugen. Kollabiert komplett auf 0, sobald der
   allererste Status gesetzt wird (schon beim Start des Bild-Ladens, siehe
   handleLoadStart), erscheint danach also wieder ganz normal. */
.status:has(.status__text:empty) {
  min-height: 0;
  margin-block: 0;
  padding: 0;
}

.status__text {
  position: relative;
  z-index: 1;
}

.status__progress {
  position: absolute;
  inset: 0;
  width: 0%;
}

.status--busy {
  background-color: var(--color-primary-bg);
  color: var(--color-primary);
}

.status--done {
  background-color: var(--color-success-bg);
  color: var(--color-success);
}

.status--error {
  background-color: var(--color-danger-bg);
  color: var(--color-danger);
}

.status--busy .status__progress {
  width: var(--progress-percent, 0%);
  background-color: var(--color-primary-bg-fill);
  transition: width 200ms ease;
}

.status--busy.status--indeterminate .status__progress {
  width: 40%;
  animation: progress-indeterminate 1.2s ease-in-out infinite;
}

@keyframes progress-indeterminate {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(250%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .status--busy.status--indeterminate .status__progress {
    width: 100%;
    opacity: 0.5;
    animation: none;
  }
}

/* --------------------------------------------------------------------------
   Image-Stage
   -------------------------------------------------------------------------- */

/* Eigener Wrapper um #image-stage (statt Positionierung direkt darauf):
   #image-stage trägt role="img" (Screenreader behandeln seinen Inhalt als
   eine einzige, flache Grafik) – #mark-controls muss deshalb als
   Geschwister-Element AUSSERHALB davon liegen, damit seine Buttons für
   Screenreader erreichbar bleiben (siehe Kommentar in index.html). Der
   Wrapper übernimmt Größe/Randabstand, damit beide Kinder exakt
   deckungsgleich übereinanderliegen. */
.image-stage-wrapper {
  position: relative;
  display: inline-block;
  max-width: 100%;
  margin-block: 0;
  line-height: 0;
}

/* Vor dem ersten Bild-Upload (und während der Analyse, siehe Reveal-Stellen
   in handleImageLoaded) sind #image-stage UND #image-busy-overlay beide
   unsichtbar – #mark-controls zählt hier nicht mit, da es absolut
   positioniert ist und ohnehin nie zur Höhe des Wrappers beiträgt. Ohne
   diese Regel bliebe trotz komplett leerem Inhalt der Außenabstand des
   Wrappers stehen und würde unter der Dropzone eine auffällige Leerfläche
   erzeugen. */
.image-stage-wrapper:has(.image-stage--visible),
.image-stage-wrapper:has(#image-busy-overlay:not([hidden])) {
  margin-block: var(--space-4);
}

.image-stage {
  position: relative;
  display: none;
  max-width: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-base);
  overflow: hidden;
  line-height: 0;
  box-shadow: var(--shadow-sm);
}

.image-stage--visible {
  display: inline-block;
}

.image-stage__canvas {
  display: block;
  max-width: 100%;
  height: auto;
}

.image-stage__overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  cursor: zoom-in;
}

/* Crosshair statt Lupe, solange eine Foto-Markierung gezogen werden kann –
   signalisiert den anderen Interaktionsmodus (siehe app.js). */
.image-stage__overlay--marking {
  cursor: crosshair;
}

/* --------------------------------------------------------------------------
   Foto-Markierung (manuelle Korrektur der automatischen Foto-Erkennung)
   -------------------------------------------------------------------------- */

/* Callout-Karte statt einer unauffälligen Button+Text-Zeile – deutlicher
   Rahmen/Hintergrund in der Marken-Akzentfarbe und ein linker Farbstreifen
   heben die Funktion optisch von der umgebenden Seite ab, statt zwischen
   Statuspille und Bild unterzugehen (siehe Nutzer-Feedback). Der Button
   sitzt fest links (flex-shrink: 0), der Hinweistext füllt den Rest der
   Zeile daneben und bricht erst bei wirklich schmalen Breiten unter den
   Button um (siehe .mark-photo-hint min-width unten).
*/
.mark-photo-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  margin-block: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-primary);
  border-inline-start: 4px solid var(--color-primary);
  border-radius: var(--radius-base);
  background-color: var(--color-primary-bg);
}

/* Siehe Kommentar bei .image-busy-overlay[hidden] weiter unten – dieselbe
   Notwendigkeit, da auch hier eine Autoren-Regel display:flex setzt. */
.mark-photo-controls[hidden] {
  display: none;
}

.mark-photo-toggle {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-primary);
  border-radius: var(--radius-full);
  background-color: var(--color-surface);
  color: var(--color-primary-hover);
  font-family: inherit;
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--transition-fast), background-color var(--transition-fast), color var(--transition-fast);
}

.mark-photo-toggle:hover {
  border-color: var(--color-primary-hover);
  background-color: var(--color-primary-hover);
  color: var(--color-primary-contrast);
}

.mark-photo-toggle[aria-pressed="true"] {
  background-color: var(--color-primary);
  color: var(--color-primary-contrast);
}

.mark-photo-toggle__icon {
  width: 1.1em;
  height: 1.1em;
  flex-shrink: 0;
}

.mark-photo-hint {
  flex: 1 1 16rem;
  min-width: 16rem;
  margin: 0;
  color: var(--color-text);
  font-size: var(--font-size-sm);
}

/* Live-Vorschau-Rechteck während des Ziehens (siehe app.js) – ein separates,
   absolut positioniertes Element statt Canvas-Zeichnung, damit während der
   Mausbewegung nicht bei jedem Schritt das komplette Overlay (Marker +
   Farbpaare + bereits bestätigte Markierungen) neu gezeichnet werden muss.
   Position/Größe kommen aus dynamisch berechneten Pixelwerten (siehe
   CLAUDE.md-Vorgabe: Inline-Styles nur für berechnete Werte, hier über
   Custom Properties statt direkter Inline-Angaben). */
.mark-preview {
  position: absolute;
  left: var(--mark-preview-left, 0);
  top: var(--mark-preview-top, 0);
  width: var(--mark-preview-width, 0);
  height: var(--mark-preview-height, 0);
  border: 2px dashed var(--color-primary);
  background-color: var(--color-primary-bg);
  opacity: 0.55;
  pointer-events: none;
}

/* Container für die Entfernen-Buttons je Foto-Markierung (siehe
   renderMarkControls in app.js) – deckungsgleich mit #image-stage, aber
   bewusst kein pointer-events, damit Klicks zwischen den Buttons weiterhin
   ganz normal das Canvas darunter erreichen (Zoom-Dialog, Ziehen einer
   neuen Markierung usw.). Nur die Buttons selbst (s.u.) sind klickbar. */
.mark-controls {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Echter, fokussierbarer Button statt nur "auf die Markierung klicken" –
   Letzteres ist für Tastatur-/Screenreader-Nutzung weder erreichbar noch
   erkennbar. Sitzt an der oberen rechten Ecke der jeweiligen Markierung
   (Position kommt aus renderMarkControls, dynamisch berechnet, daher über
   Custom Properties statt fester Werte). */
.mark-controls__remove {
  position: absolute;
  left: var(--mark-remove-left, 0);
  top: var(--mark-remove-top, 0);
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 2px solid var(--color-surface);
  border-radius: 50%;
  background-color: var(--color-danger);
  color: #ffffff;
  font-size: var(--font-size-base);
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  pointer-events: auto;
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition-fast);
}

.mark-controls__remove:hover,
.mark-controls__remove:focus-visible {
  transform: translate(-50%, -50%) scale(1.15);
}

/* Kleinere Variante für die (potenziell zahlreichen) Textstellen-/Farbpaar-
   Marker – volle Größe wie bei Foto-Markierungen würde bei dicht
   beieinanderliegenden Fundstellen schnell überladen wirken. Bleibt trotzdem
   voll deckend (keine reduzierte Opacity), damit der Kontrast des eigenen
   Löschen-Buttons nicht ausgerechnet in einem Kontrast-Prüf-Tool leidet. */
.mark-controls__remove--small {
  width: 1.15rem;
  height: 1.15rem;
  border-width: 1px;
  font-size: 0.7rem;
}

/* Deckt Canvas + Overlay komplett ab, solange eine Foto-Markierung eine
   Neuauswertung anstößt (siehe reanalyzeAfterMarkChange in app.js) – ohne
   diesen sichtbaren Hinweis wirkt die Seite in diesem kurzen Moment wie
   eingefroren, obwohl im Hintergrund nur Farbpalette/Kontrastprüfung neu
   berechnet werden (keine erneute Texterkennung). Nur noch der abdunkelnde
   Hintergrund – die eigentliche Anzeige (Spinner + Text) sitzt in
   .image-busy-overlay__content, siehe dort. */
/* align-items: flex-start ist hier Pflicht, nicht nur Geschmackssache: ohne
   diese Angabe würde der Flex-Default (stretch) .image-busy-overlay__content
   auf die komplette (bei langen Screenshots sehr große) Bildhöhe dehnen,
   statt seine natürliche Größe zu behalten – dessen eigenes position:sticky
   bräuchte dann eine sinnlos riesige Box, statt sich als kompakte Pille zu
   verhalten. */
.image-busy-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  background-color: rgba(255, 255, 255, 0.85);
}

/* Ohne diese Regel würde die obige display:flex-Deklaration das native
   [hidden]-Verhalten (display:none) überschreiben, da Autoren-Regeln
   unabhängig von der Spezifität Vorrang vor User-Agent-Regeln haben. */
.image-busy-overlay[hidden] {
  display: none;
}

/* position: sticky + top in vh (nicht %) hält den Hinweis bei einem sehr
   langen Screenshot in der aktuellen Bildschirm-Mitte, solange irgendein
   Teil des Bildes im sichtbaren Bereich ist – markiert der Nutzer z.B. ganz
   oben in einem 8000px hohen Bild, würde ein einfach zentrierter Hinweis
   (Mitte der GESAMTEN Bildhöhe) sonst weit außerhalb des aktuellen
   Scroll-Ausschnitts liegen und unsichtbar bleiben. */
.image-busy-overlay__content {
  position: sticky;
  top: 50vh;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-full);
  background-color: var(--color-surface);
  color: var(--color-text);
  font-weight: 600;
  box-shadow: var(--shadow-base);
}

.image-busy-overlay__spinner {
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  border: 3px solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: results-spin 0.7s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .image-busy-overlay__spinner {
    animation: none;
  }
}

/* --------------------------------------------------------------------------
   Rating (Konformitäts-Note)
   -------------------------------------------------------------------------- */

.rating {
  display: none;
  align-items: center;
  gap: var(--space-4);
  margin-block-end: var(--space-5);
  padding: var(--space-4) var(--space-5);
  background-color: var(--color-bg);
  border-radius: var(--radius-base);
}

.rating--visible {
  display: flex;
  animation: rating-pop 0.25s ease-out;
}

@keyframes rating-pop {
  from {
    opacity: 0;
    transform: scale(0.9);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.rating--success {
  --rating-color: var(--color-success);
}

.rating--warning {
  --rating-color: var(--color-warning);
}

.rating--danger {
  --rating-color: var(--color-danger);
}

.rating__badge {
  position: relative;
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  background: conic-gradient(
    var(--rating-color, var(--color-border)) calc(var(--rating-percent, 0) * 1%),
    var(--color-border) 0
  );
  box-shadow: var(--shadow-sm);
}

.rating__badge::before {
  content: "";
  position: absolute;
  inset: 0.3rem;
  border-radius: 50%;
  background-color: var(--color-surface);
}

.rating__grade {
  position: relative;
  font-size: var(--font-size-lg);
  font-weight: 800;
  color: var(--rating-color, var(--color-text));
}

.rating__label {
  margin: 0;
  font-weight: 700;
}

.rating__detail {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   Results
   -------------------------------------------------------------------------- */

.results__filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-5);
  padding: 0;
  border: none;
}

.results__filter-legend {
  padding: 0;
  margin-inline-end: var(--space-2);
  font-weight: 700;
}

.results__filter-option {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background-color: var(--color-bg);
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.results__filter-option:has(input:checked) {
  background-color: var(--color-primary-bg);
  color: var(--color-primary);
  font-weight: 700;
}

.results__filter-option input {
  accent-color: var(--color-primary);
}

.results__filter-option label {
  cursor: pointer;
}

.results__table-wrapper {
  overflow-x: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-base);
}

.results__table {
  width: 100%;
  min-width: max-content;
  border-collapse: collapse;
  font-size: var(--font-size-sm);
}

.results__table caption {
  padding: var(--space-3) var(--space-4) 0;
  text-align: left;
  color: var(--color-text-muted);
}

.results__table th {
  padding: var(--space-3) var(--space-4);
  background-color: var(--color-bg);
  font-size: var(--font-size-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  text-align: left;
}

.results__table td {
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--color-border);
  text-align: left;
  vertical-align: middle;
  white-space: nowrap;
}

/* Entfernen-Spalte bleibt beim horizontalen Scrollen der Tabelle am rechten
   Rand sichtbar, statt dass man erst ganz nach rechts scrollen muss – die
   Zelle braucht dafür eine deckende Hintergrundfarbe (sonst scheinen die
   vorbeiscrollenden Spalten durch die eigentlich transparente Zelle hindurch)
   und einen eigenen Trennstrich, da der normale border-top hier allein nicht
   mehr als Abgrenzung zum darunter durchscrollenden Inhalt ausreicht. */
.results__table th:last-child,
.results__table td:last-child {
  position: sticky;
  right: 0;
  z-index: 1;
  box-shadow: -4px 0 6px -4px rgba(31, 24, 61, 0.15);
}

.results__table td:last-child {
  background-color: var(--color-surface);
}

.results__table tbody tr {
  transition: background-color var(--transition-fast);
}

/* Dezente Grün-/Rot-Einfärbung der gesamten Zeile je nach Bestehen/Nicht-
   Bestehen (siehe tr.className in results-table.js/palette-panel.js) – ein
   zusätzliches, sofort sichtbares Signal neben Marker-Farbe und Badges,
   ohne dass man dafür erst zur AA/AAA-Spalte scrollen muss. Dieselben,
   bereits an anderer Stelle (Badges) verwendeten Hintergrundfarben, daher
   optisch konsistent und ausreichend dezent. Die sonst weiße Entfernen-
   Spalte bekommt denselben Ton, sonst wirkt sie wie ein weißer Fremdkörper
   am Zeilenende. */
.results__table tbody tr.results__row--pass {
  background-color: var(--color-success-bg);
}

.results__table tbody tr.results__row--pass td:last-child {
  background-color: var(--color-success-bg);
}

.results__table tbody tr.results__row--fail {
  background-color: var(--color-danger-bg);
}

.results__table tbody tr.results__row--fail td:last-child {
  background-color: var(--color-danger-bg);
}

/* Hover gewinnt bewusst gegenüber der Status-Einfärbung (gleiche
   Spezifität, aber hier zuletzt notiert) – Hover-Feedback soll auf jeder
   Zeile gleich aussehen, unabhängig von Bestehen/Nicht-Bestehen. */
.results__table tbody tr:hover {
  background-color: var(--color-bg);
}

.results__table tbody tr:hover td:last-child {
  background-color: var(--color-bg);
}

.results__empty {
  color: var(--color-text-muted);
  font-style: italic;
  white-space: normal;
}

.results__badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  font-weight: 700;
  font-size: var(--font-size-xs);
  white-space: nowrap;
}

.results__badge--pass {
  background-color: var(--color-success-bg);
  color: var(--color-success);
}

.results__badge--fail {
  background-color: var(--color-danger-bg);
  color: var(--color-danger);
}

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

.results__marker {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  color: #ffffff;
  font-family: inherit;
  font-weight: 700;
  font-size: var(--font-size-xs);
  cursor: zoom-in;
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}

.results__marker:hover,
.results__marker:focus-visible {
  transform: scale(1.15);
  box-shadow: var(--shadow-base);
}

.results__marker--pass {
  background-color: var(--color-success);
}

.results__marker--fail {
  background-color: var(--color-danger);
}

/* Eckige Variante für Farbpaar-Marker – passend zu den quadratischen
   Bild-Markern aus overlay.js (drawOverlay), im Unterschied zu den runden
   Markern der Textkontrast-Tabelle. */
.results__marker--square {
  border-radius: var(--radius-base);
}

/* Marker-Badge + optionaler "+N"-Button für zusammengefasste Fundstellen
   (siehe createMarkerCell/groupDuplicatePairs in palette-panel.js) – die
   Textkontrast-Tabelle zeigt seit dem Wegfall ihrer eigenen Gruppierung nur
   noch den einzelnen .results__marker ohne Wrapper. */
.results__marker-group {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.results__marker-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 1.75rem;
  padding: 0 var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background-color: var(--color-surface);
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: 700;
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.results__marker-count:hover,
.results__marker-count:focus-visible {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* Entfernen-Button je Tabellenzeile (siehe createRemoveCell in
   results-table.js/palette-panel.js) – bewusst dezent (Umriss statt
   Vollfarbe), damit er nicht mit den Pass/Fail-Bewertungen der übrigen Badges
   konkurriert; erst bei Hover/Fokus wird die Löschabsicht farblich betont. */
.results__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background-color: var(--color-surface);
  color: var(--color-text-muted);
  font-family: inherit;
  font-size: var(--font-size-base);
  line-height: 1;
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.results__remove:hover,
.results__remove:focus-visible {
  border-color: var(--color-danger);
  color: var(--color-danger);
}

.results__marker-range-popover {
  width: 160px;
}

/* --------------------------------------------------------------------------
   Fix-Zelle (leerer Zustand bei bereits konformen Einträgen)
   -------------------------------------------------------------------------- */

.results__fix-none {
  color: var(--color-text-muted);
  text-align: center;
}

/* --------------------------------------------------------------------------
   Copyable (Farbwerte per Klick in die Zwischenablage kopieren)
   -------------------------------------------------------------------------- */

.copyable {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  border-radius: var(--radius-sm);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 2px;
  transition: text-decoration-color var(--transition-fast), color var(--transition-fast);
}

.copyable:hover,
.copyable:focus-visible {
  text-decoration-color: currentColor;
}

.copyable--copied {
  color: var(--color-success);
  text-decoration-color: transparent;
}

/* Dauerhaft sichtbares Icon statt einer nur bei Hover eingeblendeten
   Unterstreichung – sonst sieht der Wert im Ruhezustand aus wie ganz
   normaler, nicht-interaktiver Text und die Kopierbarkeit fällt kaum auf. */
.copyable__icon {
  display: inline-flex;
  width: 1.25em;
  height: 1.25em;
  flex-shrink: 0;
  color: var(--color-text-muted);
  opacity: 0.85;
}

.copyable__icon svg {
  width: 100%;
  height: 100%;
}

.copyable:hover .copyable__icon,
.copyable:focus-visible .copyable__icon {
  opacity: 1;
}

.copyable--copied .copyable__icon {
  color: var(--color-success);
  opacity: 1;
}

.popover-panel {
  position: fixed;
  inset: auto;
  top: var(--popover-top, 0);
  left: var(--popover-left, 0);
  margin: 0;
  padding: var(--space-3);
  /* Zusätzlicher Platz rechts, damit der Inhalt nicht unter der absolut
     positionierten Schließen-Schaltfläche (.popover-panel__close) liegt. */
  padding-inline-end: var(--space-6);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-base);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-base);
  font-size: var(--font-size-sm);
  white-space: normal;
}

.popover-panel__close {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background-color: var(--color-surface);
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--font-size-base);
  line-height: 1;
  cursor: pointer;
}

.popover-panel__close:hover,
.popover-panel__close:focus-visible {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.fix-popover {
  width: 290px;
}

.fix-popover__ratio {
  margin: 0 0 var(--space-2);
  font-weight: 600;
}

.fix-popover__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-end: var(--space-1);
}

.fix-popover__row:last-child {
  margin-block-end: 0;
}

.fix-popover__row-label {
  flex: 1;
  color: var(--color-text-muted);
}

/* Zwei gleichwertige Fix-Kacheln nebeneinander (Vordergrund- vs.
   Hintergrund-Anpassung) statt einer Hauptkachel mit versteckter
   Alternative – siehe createFixCell. */
.results__fix-options {
  display: inline-flex;
  gap: var(--space-4);
}

.results__fix-option {
  display: inline-block;
}

/* --------------------------------------------------------------------------
   Palette (allgemeine Farbpalette-Extraktion + Paarvergleich)
   -------------------------------------------------------------------------- */

.palette {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: 0 0 var(--space-5);
  padding: 0;
  list-style: none;
}

.palette__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  min-width: 6rem;
  font-size: var(--font-size-sm);
  text-align: center;
}

.palette__swatch {
  width: 6rem;
  height: 3.5rem;
  flex-shrink: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background-color: var(--swatch-color, transparent);
  box-shadow: var(--shadow-sm);
}

.palette__hex {
  font-weight: 700;
  white-space: nowrap;
}

.palette__pct {
  color: var(--color-text-muted);
}

.palette__sample {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background-color: var(--sample-bg, transparent);
  color: var(--sample-fg, inherit);
  font-family: inherit;
  font-size: inherit;
  font-weight: 600;
  cursor: zoom-in;
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}

.palette__sample:hover,
.palette__sample:focus-visible {
  transform: scale(1.05);
  box-shadow: var(--shadow-base);
}

/* Zwei nebeneinanderliegende Farbblöcke statt simuliertem Text – für Paare,
   bei denen die "Vordergrund"-Farbe selbst eine Farbfläche ist (Button,
   Badge, Farbband), siehe isFlatColorPair in palette-panel.js. */
.palette__sample--colors {
  display: inline-flex;
  padding: 0;
  overflow: hidden;
}

.palette__sample-half {
  width: 1.75rem;
  height: 1.75rem;
}

.palette__sample-half:first-child {
  background-color: var(--sample-fg);
}

.palette__sample-half:last-child {
  background-color: var(--sample-bg);
}

/* Fix-Vorschlag in der Farbpalette-Tabelle (siehe fix-cell.js): gleicher
   Zwei-Farbblock-Look wie die "Beispiel"-Spalte, aber öffnet ein Popover
   statt des Zoom-Dialogs – daher der abweichende Cursor. */
.palette__sample--fix {
  cursor: pointer;
}

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

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.app-footer {
  margin-block-start: var(--space-6);
  padding-block: var(--space-5);
  text-align: center;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.app-footer__credit {
  margin-block-start: var(--space-2);
}

.app-footer__legal {
  margin-block-start: var(--space-2);
}

.app-footer__credit a,
.app-footer__legal a {
  color: var(--color-primary);
  text-decoration: underline;
}

.app-footer__credit a:hover,
.app-footer__credit a:focus-visible,
.app-footer__legal a:hover,
.app-footer__legal a:focus-visible {
  color: var(--color-primary-hover);
}

/* --------------------------------------------------------------------------
   Zoom-Dialog (vergrößerte Ansicht einer Textstelle)
   -------------------------------------------------------------------------- */

.zoom-dialog {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
}

.zoom-dialog[hidden] {
  display: none;
}

.zoom-dialog__backdrop {
  position: absolute;
  inset: 0;
  background-color: rgb(0 0 0 / 60%);
}

.zoom-dialog__panel {
  position: relative;
  z-index: 1;
  max-width: min(90vw, 44rem);
  max-height: 90vh;
  overflow: auto;
  padding: var(--space-5);
  background-color: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-base);
}

.zoom-dialog__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-block-end: var(--space-4);
}

.zoom-dialog__title {
  margin: 0;
  font-size: var(--font-size-lg);
}

.zoom-dialog__detail {
  margin: var(--space-1) 0 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.zoom-dialog__close {
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background-color: var(--color-surface);
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--font-size-lg);
  line-height: 1;
  cursor: pointer;
}

.zoom-dialog__close:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.zoom-dialog__canvas {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
}
