/* design-system: migriert */
/* ==========================================================================
   Optik-Stufe 3, AP6 (2026-10-11), nach docs/design/DESIGNRICHTUNG.md:
   - Monatlich/Jährlich: Schieber auf --accent-fill, gewählte Schrift
     --on-accent-fill (Weiß, 5.55:1). Vorher `color:#fff` auf dem hellen
     --accent (2.3:1) — das war unter jeder Lesbarkeitsschwelle.
   - Fluchtlinie (H3): Kopf, Kartenraster, Vergleich und FAQ teilen jetzt
     dieselbe Spalte (--content-max, 1080px). Vorher lag das Raster (bis
     1180px) breiter als die Kopfkarte (860px) und ragte links und rechts
     darüber hinaus.
   - Hierarchie: Seitentitel und Preis aus der Typo-Skala, Ribbon in
     Satzschreibung auf --accent-fill, Karten als --panel-Flächen; Hover nur
     noch als Randtönung, damit die empfohlene Karte die einzige mit vollem
     Akzentrand bleibt.
   - Die seitenlokalen --space-*-Kopien entfallen (gleiche Werte stehen seit
     Stufe 1 global in tokens.css); --fs-* zeigen auf die Skala.
   - Bewegung nur noch über Token-Dauern; Wege skalieren mit --motion-scale.
   ==========================================================================

   Pläne-Seite (/plaene) — VOLLSTÄNDIGER NEUAUFBAU, keine Weiterentwicklung
   der vorherigen Datei. Nutzer-Feedback zum letzten Stand war explizit
   "komplette Katastrophe" — deshalb hier keine punktuelle Korrektur, sondern
   ein neuer Anfang mit einer bewusst einfacheren Grundidee:

     Sechs Tarife sind KEIN Karussell-Anwendungsfall. Ein Karussell verbirgt
     im Regelfall fünf von sechs Karten und zwingt zu Bewegung (Scroll/Pfeil/
     Wischen), nur um den Rest zu sehen — genau das Gegenteil von "auf einen
     Blick vergleichen", was eine Tarifseite eigentlich leisten soll. Diese
     Fassung zeigt darum alle sechs Karten gleichzeitig in einem
     umbrechenden CSS-Grid (siehe .plans-grid unten). Das ist zugleich der
     Grund, warum "keine Karte wird bei irgendeiner Breite abgeschnitten"
     hier eine STRUKTURELLE Eigenschaft ist, keine an acht Stichproben-
     Breiten nachträglich erkämpfte: ohne Scroll-/Transform-Zustand gibt es
     schlicht keinen Zustand, in dem eine Karte halb im Bild steht.

   Design-Grundlage (Skill ui-ux-pro-max, Domänen design-system/ux/landing):
   - Produktprofil "Developer Tool/IDE" + Palette "Dark Mode (OLED)" treffen
     exakt das, was in style.css bereits als App-weites Theme existiert
     (--bg #05070f, --panel-elevated #131a30, --accent #3d8bff) — die
     Skill-Empfehlung ist hier also eine BESTÄTIGUNG des vorhandenen Themas,
     kein Anlass, ein zweites Farbsystem einzuführen. Es werden ausschließlich
     Tokens aus style.css verwendet (--bg/--panel/--panel-elevated/--border/
     --border-soft/--text-primary/--text-secondary/--text-dim/--accent/
     --accent-soft/--radius-s/-m/-l/--ease/--font-display/--font-body).
   - Landing-Pattern "Pricing-Focused Landing": genau EIN hervorgehobener
     Tarif (Rahmen/Glow/Ribbon), alle übrigen optisch gleichrangig, Free
     bewusst zurückhaltend (siehe .plan-card.is-recommended weiter unten).
   - UX-Regel "Tables can overflow on mobile → horizontal scroll wrapper"
     bleibt für die Vergleichstabelle bestehen (.table-scroll), gilt aber
     NICHT mehr für die Tarifkarten selbst (kein Scroll-Container mehr nötig,
     da umbrechendes Grid).

   Zwei seitenlokale Skalen (Abstand + Schriftgröße) bündeln alle Werte
   dieser Seite an einer Stelle, statt sie im Markup verteilt zu wiederholen
   — keine neuen Farben, kein zweites Theme-System. */

.plans-page {
  width: 100%;

  /* Innerhalb einer Tarifkarte werden bewusst nur drei Textstufen benutzt
     (--fs-price für den Betrag, --fs-title für den Kartentitel, --fs-body
     für den Rest: Beschreibung, Feature-Liste, Preis-Zusatzzeilen). Die
     übrigen Stufen bedienen die Seite AUSSERHALB der Karten. --fs-body ist
     gegenüber dem vorherigen Stand (13px) auf 14px angehoben — Kernprodukt-
     seite für eine Kaufentscheidung, da darf die Lesegröße etwas über dem
     dichtesten App-internen Wert liegen. */
  --fs-body: var(--size-body);
  --fs-title: var(--size-title-3);
  --fs-price: var(--size-title-1);
  --fs-lead: var(--size-headline);
  --fs-section: var(--size-title-2);
  --fs-page-title: var(--size-title-1);
}

/* Drei aufeinanderfolgende Abschnitte (Kopf / Kartenraster / Vergleich+FAQ)
   statt eines einzigen — zwei davon sind .page-wrap (860px, siehe
   style.css), dazwischen sitzt die breitere .plans-cards-Sektion. Jedes
   .page-wrap bringt regulär eigene vertikale Innenabstände mit; hier auf
   0 zurückgesetzt und nur am jeweils ersten/letzten Kind der Seite wieder
   hergestellt, damit der Gesamtabstand zum Rest von .main unverändert
   bleibt und zwischen den drei Abschnitten nicht doppelt wirkt. */
.plans-page > .page-wrap {
  padding-top: 0;
  padding-bottom: 0;
  /* Gemeinsame Spalte mit dem Kartenraster (.plans-cards), siehe Kopf. */
  max-width: var(--content-max);
}
.plans-page > .page-wrap:first-child {
  padding-top: var(--space-6);
}
.plans-page > .page-wrap:last-child {
  padding-bottom: var(--space-8);
}

/* --------------------------------------------------------------------
   Kopfbereich: ruhiger Flächenanker vor dem app-weiten, mausreaktiven
   Kachelraster (#bgCanvas, static/js/tile-background.js — diese Datei
   bleibt unangetastet). .plans-comparison/.plans-footer/.plans-invoices
   nutzen dieselbe Fläche (var(--panel) + Rahmen + Radius); der Kopf zieht
   hier nach, damit an keiner Stelle der Seite das Kachelraster unvermittelt
   durchscheint. -------------------------------------------------------- */
.plans-page .plans-hero {
  background: var(--panel);
  border: var(--border-width) solid var(--border-soft);
  border-radius: var(--radius-l);
  padding: var(--space-8) var(--space-8) var(--space-6);
}

.plans-page .plans-header {
  text-align: center;
}

/* Status-Streifen "Aktueller Plan": ein ruhiger Streifen direkt über dem
   Seitentitel, links ausgerichteter Text + rechts der kompakte
   Portal-Button, abgesetzt durch einen linken Akzentstrich statt eines
   zweiten, mit .plans-hero konkurrierenden Vollrahmens. */
.plans-page .plan-status-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  text-align: left;
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
  background: var(--fill-1);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-s);
}

.plans-page .plan-status-bar-text {
  margin: 0;
  font-size: var(--fs-body);
  color: var(--text-secondary);
}

.plans-page .plan-status-bar-text strong {
  color: var(--text-primary);
}

.plans-page .plan-status-bar-form {
  margin: 0;
  flex-shrink: 0;
}

.plans-page .plan-status-bar-warning {
  text-align: left;
  margin: 0 0 var(--space-4);
}

.plans-page .plan-status-bar-hint {
  text-align: left;
  font-size: var(--fs-body);
  margin: calc(-1 * var(--space-2)) 0 var(--space-4);
}

.plans-page .page-title {
  font-size: var(--fs-page-title);
  line-height: var(--leading-title-1);
  letter-spacing: var(--tracking-title-1);
  font-weight: var(--weight-semibold);
  margin-bottom: var(--space-2);
}

/* Alle Überschriften der Seite in der Anzeigeschrift (Space Grotesk), nicht
   nur der Seitentitel.

   Vorher lief ausschließlich das h1 in --font-display, weil das die globale
   .page-title-Regel mitbringt; die Karten-, Vergleichs- und FAQ-Überschriften
   erbten dagegen --font-body (Inter) vom body. Am Bildschirm sah das aus wie
   zwei verschiedene Seiten übereinander: ein kantiger Titel über durchweg
   neutralen Zwischenüberschriften. Nachgemessen am Live-Server über
   CSS.getPlatformFontsForNode — also die tatsächlich gerenderte Schrift, nicht
   die deklarierte Liste: h1 "Space Grotesk", .plan-card-title/.comparison-title
   "Inter".

   Nur die Familie, bewusst ohne Farbverlauf: der bleibt dem Seitentitel
   vorbehalten. Auf jeder Zwischenüberschrift wiederholt wirkt er unruhig statt
   sauber, und der Verlauf soll die eine Überschrift auszeichnen, die die Seite
   anführt. */
.plans-page .plan-card-title,
.plans-page .comparison-title,
.plans-page .plans-footer h2,
.plans-page .faq-item h3 {
  font-family: var(--font-display);
}

.plans-page .page-subtitle {
  font-size: var(--fs-lead);
  line-height: var(--leading-headline);
  color: var(--text-secondary);
  margin-bottom: var(--space-6);
}

/* Nur für Screenreader sichtbarer Text — z.B. der "Nicht enthalten:"-Präfix
   vor einem reinen "—" in der Feature-Liste (siehe plans.html), damit dort
   nicht nur ein kontextloser Gedankenstrich vorgelesen wird. */
.plans-page .visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Gemeinsamer Fokus-Look für alle interaktiven Elemente auf dieser Seite —
   style.css definiert für .btn-primary/.btn-secondary/Links bewusst KEINEN
   eigenen :focus-visible-Ring (sie verlassen sich anderswo auf den
   Browser-Default), auf einer Kaufentscheidungsseite soll der Ring aber
   klar erkennbar UND auf den Seiten-Akzent abgestimmt sein. */
.plans-page a:focus-visible,
.plans-page button:focus-visible,
.plans-page input:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-s);
}

/* Monat/Jahr-Umschalter — Pill-Switch mit Schiebeanimation: die beiden
   Radios bleiben die Zustandsquelle (siehe <script> in plans.html), hier
   nur die Optik. .billing-toggle-thumb wird per JS exakt auf die
   Bounding-Box des aktiven Labels gesetzt (left/top/width/height), nicht
   über eine feste 50%-Rechnung — die versagte, sobald ein Label (das mit
   dem "2 Monate gratis"-Badge) breiter war als das andere. Die Radios
   selbst sind unsichtbar, aber weiterhin fokussier-/klickbar
   (position:absolute + opacity:0 statt display:none). */
.plans-page .billing-toggle {
  position: relative;
  display: flex;
  width: 340px;
  max-width: 100%;
  margin: 0 auto;
  padding: 4px;
  background: var(--fill-1);
  border: var(--border-width) solid var(--border-soft);
  border-radius: var(--radius-full);
}

.plans-page .billing-toggle-thumb {
  position: absolute;
  /* Startwerte, bevor das <script> die echte Label-Bounding-Box einträgt —
     verhindert nur einen unpositionierten Flash im no-js-Fall. */
  top: 4px;
  left: 4px;
  width: calc(50% - 4px);
  height: calc(100% - 8px);
  border-radius: var(--radius-full);
  background: var(--accent-fill);
  box-shadow: var(--shadow-s);
  /* Feder ohne Überschwingen; unter prefers-reduced-motion setzt tokens.css
     Kurve und Dauer auf eine kurze Überblendung herunter. */
  transition: left var(--dur-spring) var(--spring), width var(--dur-spring) var(--spring),
              top var(--dur-spring) var(--spring), height var(--dur-spring) var(--spring);
  z-index: 0;
}

.plans-page .billing-toggle-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.plans-page .billing-toggle-option {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-full);
  font-size: var(--fs-body);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}

.plans-page .billing-toggle-input:not(:checked) + .billing-toggle-option:hover {
  color: var(--text-primary);
}

/* Gedrückt: Fläche nur unter der NICHT gewählten Option, damit sie den
   Schieber nicht überdeckt. Kein scale — das Skript misst die Label-Box für
   den Schieber, ein transform würde die Messung verfälschen. */
.plans-page .billing-toggle-input:not(:checked) + .billing-toggle-option:active {
  background: var(--fill-2);
}

/* Weiß auf --accent-fill: 5.55:1 (vorher #fff auf --accent: 2.3:1). */
.plans-page .billing-toggle-input:checked + .billing-toggle-option {
  color: var(--on-accent-fill);
}

.plans-page .billing-toggle-input:focus-visible + .billing-toggle-option {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
}

/* Badge "2 Monate gratis": auf dem Schieber eine Stufe tiefer
   (--accent-fill-pressed, Weiß 6.61:1), sonst Akzent auf --accent-soft. */
.plans-page .billing-toggle-badge {
  font-size: var(--size-caption);
  letter-spacing: var(--tracking-caption);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  background: var(--accent-fill-pressed);
  color: var(--on-accent-fill);
}

.plans-page .billing-toggle-input:not(:checked) + .billing-toggle-option .billing-toggle-badge {
  background: var(--accent-soft);
  color: var(--accent);
}

.plans-page .plans-invoices {
  margin-bottom: var(--space-12);
  padding: var(--space-6);
  background: var(--panel);
  border: var(--border-width) solid var(--border-soft);
  border-radius: var(--radius-m);
}

/* Skip-Credits (Einmalkauf): ruhiges Panel wie .plans-invoices, zwei
   Pakete nebeneinander, auf schmalen Bildschirmen untereinander. Nur Tokens,
   keine eigenen Farben. */
.plans-page .plans-skip-credits {
  margin-top: var(--space-8);
  scroll-margin-top: var(--space-8);
}

.plans-page .plans-skip-credits-panel {
  padding: var(--space-6);
  background: var(--panel);
  border: var(--border-width) solid var(--border-soft);
  border-radius: var(--radius-m);
}

.plans-page .plans-skip-credits-panel .comparison-title {
  margin-bottom: var(--space-3);
}

.plans-page .plans-skip-credits-intro {
  margin: 0 0 var(--space-5);
}

.plans-page .plans-skip-credits-options {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-5);
}

.plans-page .plans-skip-credits-option {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  background: var(--panel-elevated);
  border: var(--border-width) solid var(--border-soft);
  border-radius: var(--radius-m);
}

.plans-page .plans-skip-credits-name {
  margin: 0;
  font-size: var(--size-headline);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.plans-page .plans-skip-credits-price {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
}

.plans-page .plans-skip-credits-form {
  margin: 0;
  margin-top: auto;
}

.plans-page .plans-skip-credits-form .btn-primary,
.plans-page .plans-skip-credits-guest .btn-primary,
.plans-page .plans-skip-credits-guest .btn-secondary {
  min-height: 48px;
  justify-content: center;
  text-align: center;
}

.plans-page .plans-skip-credits-form .btn-primary {
  width: 100%;
}

.plans-page .plans-skip-credits-guest {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin: 0 0 var(--space-5);
}

.plans-page .plans-skip-credits-off {
  margin: 0 0 var(--space-5);
  font-size: var(--fs-body);
  color: var(--text-secondary);
}

.plans-page .plans-skip-credits-notice {
  margin: 0;
}

@media (max-width: 640px) {
  .plans-page .plans-skip-credits-panel { padding: var(--space-5) var(--space-4); }
  .plans-page .plans-skip-credits-options { grid-template-columns: minmax(0, 1fr); }
  .plans-page .plans-skip-credits-guest { flex-direction: column; align-items: stretch; }
  .plans-page .plans-skip-credits-guest .btn-primary,
  .plans-page .plans-skip-credits-guest .btn-secondary { width: 100%; }
}

/* --------------------------------------------------------------------
   Kartenraster — der eigentliche Kern des Neuaufbaus.
   -------------------------------------------------------------------- */

/* .plans-cards ist die breitere Sektion AUSSERHALB der 860px-.page-wrap-
   Spalte (siehe Kommentar in plans.html): width:100% + max-width heißt, sie
   nutzt so viel von .main aus wie tatsächlich da ist (schrumpft von selbst,
   wenn die Sidebar aufgeklappt ist oder der Viewport schmaler wird),
   gedeckelt bei 1180px, damit die Karten auf sehr breiten Monitoren nicht
   unnötig auseinandergezogen wirken. Bewusst OHNE eigenen Panel-Rahmen um
   das gesamte Raster (anders als vorher): jede einzelne Karte ist selbst
   schon eine deckende Fläche (var(--panel-elevated) + Rahmen), die zwischen
   den Karten sichtbaren Lücken zeigen ruhig das Kachelraster durch — genau
   der "professionelle Bezug, der nicht dominiert" aus dem Auftrag, ohne die
   Karten zusätzlich in einer zweiten, konkurrierenden Box zu verschachteln
   (Box-in-Box wirkte im vorherigen Stand zusammen mit dem Akzent-Rahmen der
   empfohlenen Karte unruhig). */
.plans-page .plans-cards {
  width: 100%;
  /* Seit 2026-10-11 dieselbe Spalte wie Kopf und FAQ (vorher 1180px). */
  max-width: var(--content-max);
  margin: var(--space-8) auto var(--space-12);
}

/* Echtes CSS-Grid statt horizontal scrollendem Flex-Streifen: bricht je
   nach verfügbarer Breite auf 3/2/1 Spalten um (siehe Media Queries unten).
   Unterhalb 901px (2 bzw. 1 Spalte) sind weiterhin IMMER alle sechs Karten
   gleichzeitig sichtbar — es gibt dort keinen Ausschnitts-/Scroll-Zustand,
   der irgendeine Karte anschneiden könnte. Ab 901px (3 Spalten, wo eine
   "Seite" im Sinn von WP4-Paging überhaupt Sinn ergibt) blendet
   .plan-card:not(.is-plans-page-active) weiter unten sechs auf drei
   gleichzeitig sichtbare Karten ein — die <li> selbst bleiben dabei
   IMMER alle sechs im DOM (siehe plans.html-Kommentar zum Karten-Paging),
   nur `display` wechselt. list-style:none nimmt der <ul> die
   Aufzählungspunkte; role="list" im Markup ist NICHT nötig, weil hier
   (anders als bei .plan-features) keine Screenreader-Ausgabe wie "Liste mit
   6 Einträgen" gebraucht wird — die Karten sind über ihre eigene
   Überschrift (<h2>) selbst navigierbar. */
.plans-page .plans-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6);
  /* Platz über der ersten Kartenreihe, damit das Ribbon der empfohlenen
     Karte (position:absolute, ragt oben etwas über den Kartenrand hinaus)
     nicht mit dem Abstand zum Kopfbereich kollidiert. */
  padding-top: var(--space-4);
  /* Der Browser gibt <ul> links 40px Einzug. Ohne diese Zeile begann das
     Raster 40px rechts der Kopfkarte (live gemessen 2026-10-12: Kopf x=296,
     Karten x=336) und verfehlte die gemeinsame Fluchtlinie. */
  padding-inline: 0;
  list-style: none;
  margin: 0;
}

/* Paging (WP4): nur ab 901px aktiv — bewusst 901px statt der im Auftrag
   genannten 900px, damit sich diese Regel NICHT mit dem bestehenden
   Zwei-Spalten-Breakpoint weiter unten überschneidet, der ebenfalls
   "max-width: 900px" nutzt (bei exakt 900px Viewportbreite träfen sonst
   beide Regeln gleichzeitig zu: zwei Spalten UND nur drei sichtbare Karten
   — die verbleibenden drei würden dann als 2+1 statt als sauberer
   Dreier-Reihe umbrechen). Unterhalb 901px passen nie drei Spalten
   nebeneinander, dort bleibt das Grid bei allen sechs Karten (siehe Regel
   oben) — "immer 3 pro Reihe" ist unterhalb dieser Breite strukturell nicht
   erfüllbar, deshalb deaktiviert reines CSS das Paging hier komplett,
   ergänzt um das Ausblenden von .plans-pager im Media-Block weiter unten. */
@media (min-width: 901px) {
  .plans-page .plan-card:not(.is-plans-page-active) {
    display: none;
  }
}

/* Bedienblock über dem Kartenraster: zwei echte <button>, dazwischen die
   Seitenanzeige. Bewusst ohne eigenen Panel-Hintergrund (anders als z.B.
   .plan-status-bar) — an dieser Stelle würde eine zweite Fläche direkt über
   den bereits deckenden Kartenflächen unruhig wirken, ein einfacher
   zentrierter Streifen reicht. */
.plans-page .plans-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

.plans-page .plans-pager-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

/* style.css definiert für .btn-secondary keinen eigenen :disabled-Zustand
   (nur .onboarding-btn-secondary hat einen) — ohne das hier wäre ein Rand-
   Button an der ersten/letzten Seite optisch nicht von einem aktiven Button
   zu unterscheiden, obwohl ein Klick wirkungslos bleibt. */
.plans-page .plans-pager-btn:disabled,
.plans-page .plans-pager-btn[aria-disabled="true"] {
  opacity: .45;
  cursor: not-allowed;
}

.plans-page .plans-pager-status {
  min-width: 96px;
  text-align: center;
  font-size: var(--fs-body);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

.plans-page .plan-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--space-6) var(--space-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-m);
  background: var(--panel);
  /* Alle sechs Karten bekommen dieselbe Mindesthöhe, UNABHÄNGIG von ihrer
     Grid-Zeile (Auftrag Punkt 3: "Alle 6 Karten gleich hoch"). Ohne das
     würde CSS Grid Karten nur INNERHALB derselben Zeile automatisch auf
     gleiche Höhe strecken (align-items:stretch, Standardverhalten), aber
     nicht über Zeilen hinweg. Der eigentliche, strukturelle Baustein dafür
     ist trotzdem NICHT diese Zahl, sondern dass plans.html jetzt für jede
     Karte exakt dieselben zehn Feature-Zeilen rendert (siehe dortiger
     Kommentar) — die Mindesthöhe hier ist nur die letzte Meile für die paar
     Pixel Unterschied, die unterschiedlich lange Titel/Beschreibungen durch
     Zeilenumbrüche noch verursachen können. */
  /* Absichtlich hoch angesetzter, gemeinsamer Boden für alle sechs Karten
     (nicht nur "hoch genug für den Normalfall"): einzelne Feature-Zeilen
     brechen bei manchen Plänen/Breiten auf zwei Zeilen um, bei anderen
     nicht (z.B. die Generierungen/Tag-Zusatzangabe beim KI-Plugin-
     Generator) — ein zu knapp bemessener Boden würde also bei genau
     dieser Textlänge wieder auseinanderlaufen. Diese Zahl liegt bewusst
     über dem höchsten in der Praxis (alle 8 Referenzbreiten, alle sechs
     Pläne) beobachteten natürlichen Kartenbedarf, damit .plan-features
     (flex-grow:1, siehe unten) den Rest IMMER bis zu genau diesem Boden
     auffüllt — Kartenhöhe wird dadurch von Textlänge/Zeilenumbruch
     entkoppelt, statt bei jeder künftigen Textänderung neu nachgemessen
     werden zu müssen. */
  min-height: 782px;
  /* Bewusst OHNE transform/translateY im Hover — ein sich bewegender
     Kartenrahmen direkt über dem Checkout-Link würde Playwrights
     Stabilitätsprüfung (unveränderte Bounding-Box vor einem Klick) unnötig
     verzögern oder im Extremfall verfehlen lassen, und der Auftrag
     verbietet 3D-Transforms auf .plan-card ausdrücklich. Farbe/Rahmen/
     Schatten genügen als Hover-Signal völlig. */
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}

/* Elfte Feature-Zeile (nostudio, siehe plans.html) hebt den oben gemessenen
   Boden an: EIN zusätzliches <li> braucht auf JEDER Karte automatisch mehr
   Platz (padding + Zeilenhöhe), unabhängig vom angezeigten Text — der
   bisherige Boden von 782px (kalibriert auf zehn Zeilen) reicht deshalb bei
   den zweispaltigen Breiten (ca. 700–840px, siehe Kommentar oben zum
   Grid-Zeilen-Problem) sowie in der dreispaltigen Seitenansicht des Pagings
   nicht mehr aus, ohne dass Karten wieder in der Höhe auseinanderlaufen.
   Bewusst als EIGENE, spätere Regel statt Änderung des Werts oben (nur für
   die neue Zeile ergänzt, siehe Auftrag) — der gemessene Spitzenwert lag bei
   832.47px (alle 8 Referenzbreiten + 1024/1280/1440/1920, jeweils volle
   Kartenrotation berücksichtigt), 840px lässt denselben kleinen Sicherheits-
   abstand wie beim ursprünglichen Boden. Unterhalb von ca. 700px (bereits
   VOR dieser Zeile nicht mehr vollständig angeglichen, siehe Git-Historie)
   bleibt eine Restabweichung bestehen — das ist ein vorbestehendes,
   eigenständiges Problem des zweispaltigen Layouts bei sehr schmalen
   Kartenbreiten, nicht Gegenstand dieser Ergänzung. */
.plans-page .plan-card {
  min-height: 840px;
}

/* Nur Randtönung: der volle Akzentrand bleibt der empfohlenen Karte. */
.plans-page .plan-card:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
}

/* Eintritts-Animation beim Seitenwechsel (WP4-Paging, siehe <script> in
   plans.html): reines 2D-translateY + Fade, KEIN 3D-Transform/perspective
   (im Auftrag ausdrücklich verboten — das abgelehnte alte Karussell nutzte
   genau das). .is-plans-page-entering wird NUR per JS beim Klick auf
   Zurück/Weiter kurz gesetzt, nie serverseitig beim ersten Laden — die
   Karten der Startseite erscheinen also ohne jede Bewegung, nur der
   tatsächliche Seitenwechsel animiert. Bewusst kein Transform im
   Ruhezustand von .plan-card selbst (siehe Kommentar oben zu :hover) — die
   Animation lebt ausschließlich auf dieser transienten Klasse und ist
   spätestens nach ENTER_CLEANUP_MS (plans.html) wieder entfernt. */
@keyframes plansCardEnter {
  from {
    opacity: 0;
    transform: translateY(calc(var(--motion-scale) * 14px));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.plans-page .plan-card.is-plans-page-entering {
  /* --dur-base + max. 80ms Versatz bleibt unter ENTER_CLEANUP_MS (360ms,
     plans.html); eine Feder (--dur-spring, 520ms) würde dort abgeschnitten. */
  animation: plansCardEnter var(--dur-base) var(--ease) both;
}

/* Leichter Versatz je Spaltenposition (nicht je absolutem <li>-Index!) —
   :nth-child(3n+1/2/3) trifft je nach aktiver Seite entweder Free/Solo/
   Engineer (Seite 1, Kind 1-3) oder Team/Enterprise/Enterprise+ (Seite 2,
   Kind 4-6), bezieht sich aber immer auf dieselbe VISUELLE Spalte, weil
   ausgeblendete <li> (display:none) im Grid keinen Platz belegen und die
   drei sichtbaren Karten so oder so Spalte 1/2/3 füllen. Dadurch bleibt der
   Stagger unabhängig davon, welche Seite gerade einblendet. */
.plans-page .plan-card.is-plans-page-entering:nth-child(3n+2) {
  animation-delay: 40ms;
}
.plans-page .plan-card.is-plans-page-entering:nth-child(3n+3) {
  animation-delay: 80ms;
}

/* PFLICHT: eigener Block statt sich auf style.css:2341 zu verlassen — die
   globale Regel dort schaltet nur `transition` global ab (siehe Kommentar
   dort), nicht `animation`. Ohne diesen Block würde ein Seitenwechsel bei
   aktivierter Systemeinstellung "Bewegung reduzieren" trotzdem sichtbar
   hoch-/reinschieben. */
@media (prefers-reduced-motion: reduce) {
  .plans-page .plan-card.is-plans-page-entering {
    animation: none !important;
  }
}

/* Genau EINE Stufe ist optisch hervorgehoben (Auftrag: "klare visuelle
   Hierarchie, keine konkurrierenden Zustände"). Kräftiger Akzent-Rahmen +
   leichtes Glühen + ein Ribbon oben — das einzige Element auf der Seite,
   das so behandelt wird. .is-current bekommt bewusst nur ein
   ZURÜCKHALTENDES Signal (Tonwert + Text-Tag, kein Rahmen/Ring), damit
   nichts mit der Empfehlung verwechselt wird oder um Aufmerksamkeit
   konkurriert, selbst wenn eine Karte zufällig beides ist (empfohlen UND
   aktueller Plan). */
.plans-page .plan-card.is-recommended {
  border-color: var(--accent);
  border-width: 2px;
  /* 1px Ausgleich, damit die dickere Umrandung die Karte nicht 2px größer
     macht als ihre fünf Nachbarn (gleiche Kartenhöhe/-breite). */
  padding: calc(var(--space-6) - 1px) calc(var(--space-5) - 1px);
  box-shadow: 0 16px 40px -20px var(--accent-soft);
}

.plans-page .plan-card-ribbon {
  position: absolute;
  top: calc(-1 * var(--space-3));
  left: var(--space-5);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--accent-fill);
  color: var(--on-accent-fill);
  font-size: var(--size-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-caption);
  white-space: nowrap;
  box-shadow: var(--shadow-s);
}

/* Aktueller Plan des Nutzers: ein kleines Textlabel neben dem Titel statt
   eines zweiten, mit .is-recommended konkurrierenden Rahmens/Rings um die
   ganze Karte. */
.plans-page .plan-card.is-current {
  background: color-mix(in srgb, var(--panel) 88%, var(--accent) 12%);
}

.plans-page .plan-card-current-tag {
  display: inline-block;
  margin-left: var(--space-2);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  background: var(--fill-2);
  color: var(--text-secondary);
  font-size: var(--size-caption);
  letter-spacing: var(--tracking-caption);
  font-weight: var(--weight-semibold);
  vertical-align: middle;
  text-transform: none;
}

.plans-page .plan-card-header {
  margin-bottom: var(--space-4);
  /* Die Beschreibungstexte der sechs Pläne sind unterschiedlich lang (siehe
     config.py, PLANS[*].description — von 60 bis gut 100 Zeichen) und
     brechen deshalb bei gleicher Kartenbreite in unterschiedlich vielen
     Zeilen um. Card-Grid-Stretch gleicht Karten nur INNERHALB derselben
     Zeile aus (Standardverhalten von CSS Grid), nicht über Zeilen hinweg —
     diese Mindesthöhe ist deshalb bewusst so groß bemessen, dass sie den
     längsten Beschreibungstext (Enterprise+, drei Zeilen) bereits VOR jeder
     Zeilenausgleichs-Logik abdeckt, damit alle sechs Kopfbereiche (und
     damit alle sechs Karten) unabhängig davon, in welcher Zeile sie
     landen, dieselbe Höhe erreichen. */
  min-height: 112px;
}

.plans-page .plan-card-title {
  font-size: var(--fs-title);
  line-height: var(--leading-title-3);
  letter-spacing: var(--tracking-title-3);
  font-weight: var(--weight-semibold);
  margin: 0 0 var(--space-2);
}

.plans-page .plan-card-description {
  font-size: var(--fs-body);
  color: var(--text-secondary);
  line-height: var(--leading-body);
  margin: 0;
}

/* Gemeinsame Grundlinie für den Preisblock: feste Mindesthöhe, damit
   "0 €/für immer" (zwei sichtbare Zeilen) und "10 €/pro Monat/(2 Monate
   gratis)" (drei Zeilen) trotzdem auf derselben Höhe enden und die
   Feature-Liste darunter bei allen sechs Karten auf gleicher Höhe beginnt.
   Free und Enterprise+ bekommen im Markup dieselbe dritte (leere) Zeile wie
   die vier bezahlten Pläne, rein für eine identische DOM-Form — die
   Mindesthöhe hier ist trotzdem die eigentliche Absicherung, falls
   Schriftgrößen/Zoom die Zeilenhöhe verschieben. */
.plans-page .plan-card-price {
  display: flex;
  flex-direction: column;
  margin-bottom: var(--space-6);
  min-height: 88px;
}

.plans-page .price-amount {
  font-family: var(--font-display);
  font-size: var(--fs-price);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  line-height: var(--leading-title-1);
  letter-spacing: var(--tracking-title-1);
  font-variant-numeric: tabular-nums;
}

.plans-page .plan-card.is-recommended .price-amount {
  color: var(--accent);
}

.plans-page .price-period {
  font-size: var(--fs-body);
  color: var(--text-secondary);
  margin-top: var(--space-1);
}

.plans-page .price-hint {
  font-size: var(--fs-body);
  color: var(--text-dim);
  margin-top: var(--space-1);
}

.plans-page .plan-features {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-6) 0;
  flex-grow: 1;
}

.plans-page .plan-features li {
  padding: var(--space-2) 0;
  font-size: var(--fs-body);
  color: var(--text-primary);
  border-bottom: var(--border-width) solid var(--separator);
  line-height: var(--leading-headline);
}

.plans-page .plan-features li:last-child {
  border-bottom: none;
}

.plans-page .plan-features strong {
  color: var(--accent);
  font-weight: 600;
}

/* Fehlende Fähigkeit: gedämpfter Text + "—", statt die Zeile ganz
   wegzulassen (siehe Kommentar zur Feature-Liste in plans.html) — hält
   nicht nur die Zeilenzahl je Karte gleich, sondern macht für Sehende UND
   Screenreader-Nutzer explizit, DASS eine Fähigkeit fehlt, statt einfach
   nichts zu sagen. */
.plans-page .plan-features li:has(> span[aria-hidden="true"]) {
  color: var(--text-dim);
}

/* Gruppen der Feature-Liste (Kernfunktionen, Kollaboration, KI, Turnier):
   nur Abstand vor der ersten Zeile jeder Gruppe, kein zusaetzliches <li> -
   die Zeilenzahl je Karte bleibt fuer alle Tarife gleich. */
.plans-page .plan-features li.is-group-start {
  margin-top: var(--space-4);
}

/* Hinweis unter der Vergleichstabelle (Gast-Einsendungen). */
.plans-page .plans-guest-note {
  margin: var(--space-4) 0 0 0;
  color: var(--text-secondary);
  font-size: var(--fs-body);
}

.plans-page .plan-card-actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  /* Aktions-Button unten bündig über alle sechs Karten: .plan-card ist
     flex-column mit .plan-features als flex-grow:1 — margin-top:auto
     drückt die Aktionen zusätzlich ans Ende, falls eine Karte durch
     Zeilenumbrüche in Titel/Beschreibung insgesamt kürzeren Inhalt hat. */
  margin-top: auto;
}

.plans-page .plan-card-actions .btn-primary,
.plans-page .plan-card-actions .btn-secondary,
.plans-page .plan-card-actions .btn-badge {
  width: 100%;
  justify-content: center;
  text-align: center;
}

/* Portal-Formular (Doppel-Abo-Fix, siehe plans.html): kein UA-Standardabstand,
   damit der umschließende Flex-Container (.plan-card-actions, gap über
   var(--space-3)) allein über den Abstand entscheidet — genau wie schon bei
   .plan-status-bar-form oben. */
.plans-page .plan-card-portal-form,
.plans-page .plan-card-checkout-form {
  margin: 0;
}

/* Zweite Aktionszeile — bei fünf der sechs Pläne nur ein unsichtbarer
   Platzhalter (siehe Kommentar in plans.html: "derselbe Kniff wie beim
   leeren --price-hint"), bei Enterprise+ der echte mailto:-Fallback neben
   dem "Kontaktieren"-Button. Feste Zeilenhöhe (20px, eine Textzeile bei
   --fs-body) statt eines zweiten vollwertigen .btn-secondary — dadurch ist
   dieselbe Zeile bei ALLEN sechs Karten exakt gleich hoch, unabhängig
   davon, ob dort echter Linktext oder nur ein Leerzeichen steht. */
.plans-page .plan-card-actions-secondary {
  display: block;
  height: 20px;
  line-height: 20px;
  font-size: var(--size-footnote);
  text-align: center;
  color: var(--text-dim);
  text-decoration: none;
}

.plans-page .plan-card-actions-secondary.plan-contact-fallback:hover {
  color: var(--text-secondary);
  text-decoration: underline;
}

.plans-page .btn-badge {
  display: inline-block;
  padding: var(--space-2) var(--space-3);
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: var(--radius-s);
  font-size: var(--fs-body);
  font-weight: var(--weight-semibold);
}

/* "In deinem Plan enthalten" (Tarife mit gleichem/niedrigerem Rang als der
   gebuchte Tarif, siehe plans.html) — bewusst NICHT die akzentfarbene Optik
   von .btn-badge ("Aktueller Plan"), damit beide Zustände klar auseinander-
   zuhalten sind: Akzentfarbe bleibt exklusiv dem tatsächlich aktuellen Tarif
   vorbehalten. Erbt Breite/Zentrierung über die gemeinsame .btn-badge-Regel
   oben (.plan-card-actions .btn-primary/.btn-secondary/.btn-badge), hier
   wird nur die Farbgebung überschrieben — Box-Model bleibt identisch, damit
   alle sechs Karten weiterhin exakt gleich hoch bleiben. */
/* --text-secondary auf --fill-1 statt --text-dim: --text-dim fällt auf
   Füllflächen unter 4.5:1 (tokens.css). */
.plans-page .btn-badge.btn-badge-muted {
  background: var(--fill-1);
  color: var(--text-secondary);
}

/* Kompakter Button für den Status-Streifen — derselbe .btn-secondary, nur
   enger gepolstert, damit er neben dem Statustext nicht wie ein
   vollwertiger, gleichrangiger Call-to-Action wirkt (der bleibt den
   Tarif-Buttons in den Karten vorbehalten). */
.plans-page .btn-compact {
  padding: var(--space-2) var(--space-4);
  font-size: var(--fs-body);
}

/* --------------------------------------------------------------------
   Vergleichstabelle, FAQ
   -------------------------------------------------------------------- */

/* Tabellen-Wrapper: overflow:hidden + border-radius direkt auf einem
   <table> greift bei Tabellen nicht zuverlässig (Tabellen sind kein
   normaler Block-Container) — deshalb liegen Radius/Overflow auf diesem
   Wrapper-Div, die Tabelle selbst scrollt bei Bedarf horizontal innerhalb,
   statt aus dem Panel herauszulaufen oder die ganze Seite aufzureißen. */
.plans-page .table-scroll {
  overflow-x: auto;
  border-radius: var(--radius-m);
}

.plans-page .plans-comparison {
  margin-bottom: var(--space-12);
  padding: var(--space-8);
  background: var(--panel);
  border: var(--border-width) solid var(--border-soft);
  border-radius: var(--radius-m);
}

.plans-page .comparison-title {
  font-size: var(--fs-section);
  line-height: var(--leading-title-2);
  letter-spacing: var(--tracking-title-2);
  font-weight: var(--weight-semibold);
  margin: 0 0 var(--space-6);
}

.plans-page .comparison-table {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  border: var(--border-width) solid var(--border-soft);
}

.plans-page .comparison-table th,
.plans-page .comparison-table td {
  padding: var(--space-3) var(--space-4);
  text-align: left;
  border-bottom: var(--border-width) solid var(--separator);
  font-size: var(--fs-body);
}

.plans-page .comparison-table th {
  background: var(--fill-1);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.plans-page .comparison-table tbody tr:last-child td,
.plans-page .comparison-table tbody tr:last-child th {
  border-bottom: none;
}

/* Zeilenköpfe (th scope="row") sehen aus wie vorher die erste Zelle: kein
   Kopfzeilen-Hintergrund, gleiche Schrift. */
.plans-page .comparison-table tbody th[scope="row"] {
  background: transparent;
  font-weight: 600;
}

.plans-page .comparison-table td:first-child {
  font-weight: 600;
  color: var(--text-primary);
}

.plans-page .plans-footer {
  margin-top: var(--space-2);
  padding: var(--space-8);
  background: var(--panel);
  border: var(--border-width) solid var(--border-soft);
  border-radius: var(--radius-m);
}

.plans-page .plans-footer h2 {
  font-size: var(--fs-section);
  line-height: var(--leading-title-2);
  letter-spacing: var(--tracking-title-2);
  font-weight: var(--weight-semibold);
  margin: 0 0 var(--space-8);
}

.plans-page .plans-faq {
  display: grid;
  gap: var(--space-8);
  /* min(300px, 100%) statt fixem 300px: verhindert, dass die FAQ-Karten auf
     schmalen Viewports (< 300px Innenbreite, z.B. Mobilgeräte mit
     ausgeklappter Sidebar) breiter als der Container werden und dadurch
     die ganze Seite horizontal aufreißen. */
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}

.plans-page .faq-item h3 {
  font-size: var(--fs-lead);
  line-height: var(--leading-headline);
  font-weight: var(--weight-semibold);
  margin: 0 0 var(--space-2);
}

.plans-page .faq-item p {
  font-size: var(--fs-body);
  color: var(--text-secondary);
  line-height: var(--leading-body);
  margin: 0;
}

.plans-page .faq-item a {
  color: var(--accent);
  text-decoration: none;
}

.plans-page .faq-item a:hover {
  text-decoration: underline;
}

/* --------------------------------------------------------------------
   Responsive — geprüft bei 375, 390, 480, 768, 1024, 1280, 1440, 1920px
   (Referenzbreiten aus dem Auftrag). Die beiden Stufen unten fallen bewusst
   mit der bereits vorhandenen 900px-Stufe von .main zusammen (siehe
   style.css, Abschnitt "Breakpoint-Leiter"), an der die App-Shell ihr
   Innenpolster von 40px auf 20px reduziert — dieselbe Stufe wiederzuverwenden
   statt eine eigene, knapp daneben liegende einzuführen hält beide Systeme
   konsistent. -------------------------------------------------------- */
@media (max-width: 900px) {
  .plans-page .plans-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .plans-page .page-title {
    font-size: var(--size-title-2);
    line-height: var(--leading-title-2);
  }

  .plans-page .comparison-table th,
  .plans-page .comparison-table td {
    padding: var(--space-2) var(--space-3);
    font-size: var(--size-footnote);
  }

  /* Der Umschalter bricht in eine Spalte um — die Thumb-Position kommt
     weiterhin per JS aus der tatsächlichen Bounding-Box des aktiven Labels,
     das funktioniert unabhängig davon, ob die Labels neben- oder
     untereinanderstehen. Statt align-items:center (das die Labels auf ihre
     Inhaltsbreite schrumpft und mittig setzt, wodurch Thumb-Breite und
     Klickfläche je Label variieren) strecken sich beide Optionen jetzt auf
     volle Breite. */
  .plans-page .billing-toggle {
    flex-direction: column;
    align-items: stretch;
  }

  .plans-page .billing-toggle-option {
    width: 100%;
  }

  .plans-page .plans-hero {
    padding: var(--space-6) var(--space-4) var(--space-4);
  }

  .plans-page .plan-status-bar {
    justify-content: flex-start;
  }

  /* Paging (WP4) ist strukturell nur bei drei Spalten sinnvoll (siehe
     @media (min-width: 901px) weiter oben, das ab hier ohnehin nicht mehr
     greift) — die Bedienelemente selbst müssen hier zusätzlich versteckt
     werden, sonst stünden zwei funktionslose Buttons über einem Raster, das
     schon alle sechs Karten zeigt. */
  .plans-page .plans-pager {
    display: none;
  }
}

@media (max-width: 480px) {
  .plans-page .plans-grid {
    grid-template-columns: 1fr;
    gap: var(--space-4);
  }

  /* Bei genau einer Spalte steht nie mehr als eine Karte je "Zeile" — eine
     erzwungene Mindesthöhe hat hier keinen Ausgleichs-Nutzen mehr (es gibt
     keine Nachbarkarte, mit der die Höhe noch übereinstimmen müsste) und
     würde auf sehr schmalen Geräten nur unnötig viel Leerraum unter kurzen
     Karten erzeugen. */
  .plans-page .plan-card {
    min-height: 0;
  }
}

/* Wer reduzierte Bewegung bevorzugt: die globale Regel "* { transition:
   none !important }" (siehe style.css, @media (prefers-reduced-motion))
   deckt den Übergang der Thumb-Bewegung technisch bereits ab, weil
   !important unabhängig von Spezifität gewinnt — hier trotzdem explizit
   wiederholt, direkt neben der Deklaration, die sie ausschaltet: falls die
   globale Regel je enger gefasst würde (z.B. auf bestimmte Selektoren
   statt *), bleibt die Abschaltung der EINZIGEN nennenswerten Bewegung auf
   dieser Seite trotzdem lokal garantiert. */
@media (prefers-reduced-motion: reduce) {
  .plans-page .billing-toggle-thumb {
    transition: none !important;
  }
}

/* Handy hochkant (<=640px): Safe-Area, 44px+ Touch-Ziele, fluide Schrift,
   Tabellen im eigenen Scroll-Container, ruhige Press-Rückmeldung. */
@media (max-width: 640px) {
  .plans-page {
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    padding-bottom: env(safe-area-inset-bottom);
    overflow-x: clip;
  }
  .plans-page .page-title {
    font-size: clamp(1.5rem, 7vw, 1.875rem);
    letter-spacing: -0.02em;
    line-height: 1.1;
  }
  .plans-page .page-subtitle { font-size: var(--size-body); }
  .plans-page .plans-hero { padding: var(--space-5) var(--space-3) var(--space-3); }
  .plans-page .plan-status-bar {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
  }
  .plans-page .plan-status-bar .btn-secondary,
  .plans-page .plan-status-bar-form { width: 100%; }
  .plans-page .billing-toggle-option {
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .plans-page .plans-grid { gap: var(--space-4); }
  .plans-page .plan-card { padding: var(--space-5) var(--space-4); }
  .plans-page .plan-card-actions .btn-primary,
  .plans-page .plan-card-actions .btn-secondary,
  .plans-page .plan-card-actions .btn-badge,
  .plans-page .plan-card-portal-form,
  .plans-page .plan-card-checkout-form,
  .plans-page .plan-card-portal-form .btn-primary,
  .plans-page .plan-card-checkout-form .btn-primary {
    min-height: 48px;
    width: 100%;
    justify-content: center;
    text-align: center;
  }
  .plans-page .plan-contact-fallback {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
  }
  .plans-page .table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    margin-inline: calc(var(--space-3) * -1);
    padding-inline: var(--space-3);
  }
  .plans-page .comparison-table th:first-child,
  .plans-page .comparison-table td:first-child {
    position: sticky;
    left: 0;
    background: var(--panel);
  }
  .plans-page .faq-item h3 { font-size: var(--size-body); }
  .plans-page .plan-card-actions .btn-primary:active,
  .plans-page .plan-card-actions .btn-secondary:active {
    transform: scale(0.98);
    transition: transform var(--dur-fast) ease-out;
  }
}
