/* ==========================================================================
   base.css – GETEILTE BASIS von RMAFlow, RefurbFlow und OrderFlow.
   ==========================================================================

   DIESE DATEI IST IN ALLEN DREI APPS BYTE-GLEICH. Wer sie in einer App
   aendert, muss sie in die beiden anderen kopieren – sonst laufen die
   Oberflaechen auseinander, und das faellt erst Wochen spaeter auf.
   Pruefen laesst es sich mit:
     md5 <app>/public/css/base.css   (bzw. md5sum)

   App-Eigenes gehoert NICHT hierher, sondern in die jeweilige Datei
   daneben (rma|refurbflow: main.css, orderflow: app.css). Die wird NACH
   dieser hier geladen und darf hier definierte Klassen ueberschreiben.

   EINE REGEL, die die App-Bloecke schuetzt: kein Selektor hier bekommt
   mehr als EINE Klasse Spezifitaet fuer Klassennamen, die in einem
   App-Block vorkommen (.badge-*, .avatar*, .card, .stat, .progress*,
   .fold*, .product-*, .thumb-*). Sonst kippen z.B. OrderFlows sieben
   Statusfarben lautlos auf die alte Vierergruppe zurueck – es fehlt
   nichts, nur die Farben stimmen nicht mehr.

   Herausgeloest am 2026-08-11 aus drei identischen Kopien (Zeilen 1-989).
   Inhaltlich unveraendert; der Umbau beginnt im naechsten Schritt.
   ========================================================================== */

/* ==========================================================================
   TOKEN – drei Schichten, in dieser Reihenfolge zu lesen
   ==========================================================================

   A  GRUNDWERTE   Leitern ohne Bedeutung: --brand-*, --n-*, --sp-*, --r-*,
                   --fs-*, --shadow-*, --dur-*. Sie sagen NICHT, wofuer eine
                   Farbe da ist, nur wie hell sie ist.
   B  BEDEUTUNG    Was die Oberflaeche benutzt: --bg, --surface-*, --text*,
                   --primary*, --tone-* usw. NUR diese Namen duerfen in
                   Regeln und in den App-Bloecken vorkommen.
   C  DUNKEL       ueberschreibt ausschliesslich Schicht B.

   WARUM DIE TRENNUNG: eine Farbe zu aendern heisst dann, EINEN Wert in A zu
   verschieben, statt 40 Stellen zu suchen. Und der Dunkelmodus kann nicht
   mehr halb vergessen werden – er greift genau die Namen aus B ab.

   ZWEI REGELN:
   · Kein Kompo­nenten-CSS greift je auf Schicht A zu. Sonst gibt es zwei
     Vokabulare, und der Dunkelmodus fasst nur noch eines davon.
   · Kein Name aus Schicht B wird geloescht. Die App-Bloecke und ueber 400
     Inline-Styles in den drei Apps zeigen darauf.

   STAND SCHRITT 3 (2026-08-11): Schicht A ist vollstaendig da, wird aber noch
   NICHT benutzt – Schicht B traegt weiter die bisherigen Werte, Zeichen fuer
   Zeichen. Diese Datei aendert das Aussehen also nicht. Erst der naechste
   Schritt haengt B an A.
   ========================================================================== */

/* ==========================================================================
   SCHICHT A – GRUNDWERTE (noch ungenutzt, siehe Kopf)
   ========================================================================== */
:root {
    /* Marke. Jeder heutige CI-Wert ist eine Sprosse dieser Leiter:
       300 = Lime-Flaeche, 400/500 = die beiden hellen Akzente,
       800 = Markengruen hell, 900/950/1000 = die dunklen Enden.
       Neu sind nur 600 und 700 – die Stufen, die heute fehlen und
       deshalb keinen brauchbaren Hover- und keinen Linkton ergeben. */
    --brand-50:   #f6fae8;
    --brand-100:  #ecf6c8;
    --brand-200:  #dcf08d;
    --brand-300:  #d4ff5e;   /* heute --primary-container */
    --brand-400:  #c8f252;   /* heute --primary-fixed */
    --brand-500:  #acd537;   /* heute --primary (dunkel) / --primary-fixed-dim */
    --brand-600:  #8ab01f;   /* neu */
    --brand-700:  #6b8a0d;   /* neu */
    --brand-800:  #4f6600;   /* heute --primary (hell) */
    --brand-900:  #3b4d00;   /* heute --primary-container (dunkel) */
    --brand-950:  #1f2900;   /* heute --on-primary-container */
    --brand-1000: #161f00;   /* heute --on-primary-fixed */

    /* Neutrale. EINE Familie statt der heutigen drei (neutrales Grau neben
       zwei olivstichigen). Ein Hauch Waerme, damit es neben dem Lime nicht
       kalt kippt – zu wenig, um als gruenstichig gelesen zu werden. */
    --n-0:    #ffffff;
    --n-25:   #f7f7f4;
    --n-50:   #f1f1ed;
    --n-100:  #e9e9e4;
    --n-200:  #dededa;
    --n-300:  #cfcfc9;
    --n-350:  #bfbfb8;   /* Trennlinie: exakt das Gewicht des heutigen
                            #c5c9b0, nur ohne Olivstich */
    --n-400:  #b0b0a9;
    --n-500:  #8b8b84;
    --n-600:  #6b6b65;
    --n-700:  #52524d;
    --n-800:  #3a3a36;
    --n-900:  #262623;
    --n-950:  #171715;
    --n-1000: #0f0f0e;

    /* Abstaende: 4px-Raster. Die heutigen Ad-hoc-Werte (0.3rem bis 2rem)
       rasten hier ein. */
    --sp-1:  4px;
    --sp-2:  8px;
    --sp-3:  12px;
    --sp-4:  16px;
    --sp-5:  20px;
    --sp-6:  24px;
    --sp-8:  32px;
    --sp-10: 40px;
    --sp-12: 48px;
    --sp-16: 64px;

    /* Radien. --r-pill ist wirklich rund, anders als das heutige
       --radius-full mit seinen 12px. */
    --r-xs:   6px;
    --r-sm:   8px;
    --r-md:   12px;
    --r-lg:   16px;
    --r-xl:   20px;
    --r-2xl:  28px;
    --r-pill: 999px;

    /* Schriftgroessen mit fester Zeilenhoehe. Der Fliesstext bleibt 14px. */
    --fs-xs:   11px;   --lh-xs:   16px;
    --fs-sm:   12px;   --lh-sm:   18px;
    --fs-base: 14px;   --lh-base: 22px;
    --fs-md:   16px;   --lh-md:   24px;
    --fs-lg:   18px;   --lh-lg:   26px;
    --fs-xl:   22px;   --lh-xl:   28px;
    --fs-2xl:  28px;   --lh-2xl:  34px;

    /* Bewegung. Dazu unten ein prefers-reduced-motion-Block. */
    --dur-fast: 120ms;
    --dur:      180ms;
    --dur-slow: 260ms;
    --ease:     cubic-bezier(.2,.6,.3,1);
}

/* ==========================================================================
   SCHICHT B – BEDEUTUNG (das Vokabular der Oberflaeche)
   --------------------------------------------------------------------------
   Seit Schritt 4 haengt jeder Wert an Schicht A. Wer eine Farbe verschieben
   will, aendert dort EINE Sprosse – nicht 40 Stellen hier.

   DIE FLAECHEN-LEITER, von hell nach dunkel (im Dunkelmodus umgekehrt):
     surface-lowest  Karte, Eingabefeld            weiss
     surface-bright  Kartenkopf, Zeilen-Hover      eine Spur davon abgesetzt
     bg              Seitengrund                   DUNKLER als die Karte
     surface-low     Seitenleiste, Tabellenkopf
     surface-med     aktiver Navigationspunkt
     surface-high    Hover auf Knoepfen und Navigation
   Der entscheidende Unterschied zu vorher: bg war bisher derselbe Wert wie
   die Karte UND wie surface-bright. Karten mussten deshalb ueber ihren Rahmen
   getragen werden, und der Kartenkopf war unsichtbar. Jetzt traegt die
   Flaeche, und Rahmen sind Kuer statt Pflicht.
   ========================================================================== */
:root {
    /* Flaechen */
    --bg:               var(--n-50);
    --surface:          var(--n-50);
    --surface-lowest:   var(--n-0);
    --surface-bright:   var(--n-25);
    --surface-low:      var(--n-100);
    --surface-med:      var(--n-200);
    --surface-high:     var(--n-300);
    --surface-highest:  var(--n-400);
    --surface-variant:  var(--n-300);

    /* Marke */
    --primary:          var(--brand-800);
    --primary-fixed:    var(--brand-400);
    --primary-fixed-dim:var(--brand-500);
    --primary-container:var(--brand-300);
    --on-primary:       var(--n-0);
    --on-primary-fixed: var(--brand-1000);
    --on-primary-container: var(--brand-950);

    --secondary:        var(--n-700);
    --secondary-container: var(--n-200);
    --on-secondary:     var(--n-0);
    --on-secondary-container: var(--n-950);

    --tertiary:         var(--tone-blue);
    --tertiary-container:var(--tone-blue-bg);
    --on-tertiary:      var(--n-0);
    --on-tertiary-container: var(--tone-blue);

    /* Schriftfarben. Drei Grau-Familien sind zu einer geworden. */
    --text:             var(--n-950);
    --text-muted:       var(--n-700);
    --text-faint:       var(--n-600);
    --on-surface:       var(--n-950);
    --on-surface-variant: var(--n-700);

    /* Linien. ZWEI VERSCHIEDENE DINGE, nicht zusammenlegen:
       --border ist eine Alpha-Haarlinie (RefurbFlows Teile-Split-Maske nutzt
       sie als SICHTBAREN 1,5px-Rahmen), --outline-variant die normale Linie
       an Karten, Tabellen und Eingabefeldern – 95 Verwendungen in den drei
       Apps, und sie druckt in RefurbFlow den Rand der 62x29mm-Etiketten.
       Sie ist deshalb bewusst nur eine Spur heller als bisher (#c5c9b0),
       nicht zwei. */
    --outline:          var(--n-500);
    --outline-variant:  var(--n-350);
    --border:           rgba(23,23,21,0.10);
    --border-strong:    var(--n-500);

    /* Status-Toene. Die Reihenfolge folgt dem Arbeitsweg (Amber -> Blau ->
       Violett -> Petrol -> Gruen; Neutral fuer "aus dem Rennen"). Rot ist
       seit Schritt 4 ein eigener Ton und bleibt echten Warnungen vorbehalten.
       Welcher Status welchen Ton bekommt, entscheidet das Badge-Partial der
       jeweiligen App, nicht diese Datei. */
    --tone-amber:      #a15c07; --tone-amber-bg:  #fdf6e8; --tone-amber-bd:  #f5dfa8;
    --tone-blue:       #1d4ed8; --tone-blue-bg:   #f0f5ff; --tone-blue-bd:   #c6d8fb;
    --tone-violet:     #6d28d9; --tone-violet-bg: #f6f3ff; --tone-violet-bd: #ddd6fe;
    --tone-teal:       #0f766e; --tone-teal-bg:   #eefbf9; --tone-teal-bd:   #a5eee5;
    --tone-green:      #2f7d3e; --tone-green-bg:  #f0f8f1; --tone-green-bd:  #bfe2c6;
    --tone-red:        #b42318; --tone-red-bg:    #fef3f2; --tone-red-bd:    #fecdca;
    --tone-neutral:    var(--n-600); --tone-neutral-bg: var(--n-50); --tone-neutral-bd: var(--n-200);

    /* Zustandsfarben sind jetzt VERWEISE auf die Toene. Bis Schritt 3 waren
       es zwei Familien nebeneinander: --warn war Amber in einem anderen Ton
       als --tone-amber, --danger ein sehr lautes Materialrot. */
    --success:          var(--tone-green);
    --success-bg:       var(--tone-green-bg);
    --success-border:   var(--tone-green-bd);

    --warn:             var(--tone-amber);
    --warn-bg:          var(--tone-amber-bg);
    --warn-border:      var(--tone-amber-bd);

    --info:             var(--tone-blue);
    --info-bg:          var(--tone-blue-bg);
    --info-border:      var(--tone-blue-bd);

    --danger:           var(--tone-red);
    --danger-bg:        var(--tone-red-bg);
    --danger-border:    var(--tone-red-bd);

    /* Akzentflaeche hinter Markenelementen (aktiver Filter, Fokusring,
       "Jetzt dran"-Kopf). */
    --accent-soft:      rgba(79,102,0,0.09);

    /* --accent und --accent-2 werden in den Views von RMAFlow und RefurbFlow
       an 12 Stellen benutzt, waren aber NIRGENDS definiert - die Farbe war
       dort seit Monaten tot (2FA-Einrichtung, Teile-Split-Maske). */
    --accent:           var(--primary);
    --accent-2:         var(--tone-teal);

    /* Radien. Die alten Namen bleiben (52 Verwendungen allein bei --radius-lg),
       ihre Werte kommen jetzt aus der Leiter: aus 2 und 4 px werden 8 und 12.
       Genau das ist der Unterschied zwischen "technisch" und "ruhig". */
    --radius:           var(--r-sm);    /* 8px  – Knoepfe, Felder, kleine Flaechen */
    --radius-lg:        var(--r-md);    /* 12px – Karten, Tabellen, Hinweise */
    --radius-xl:        var(--r-xl);    /* 20px – grosse Flaechen, Anmeldekarte */
    --radius-full:      var(--r-pill);  /* wirklich rund, war irrefuehrende 12px */

    /* Schatten in vier Stufen statt zwei. Sie tragen jetzt einen Teil der
       Abgrenzung, die bisher Rahmen leisten mussten: weicher Kern plus enge
       Kontaktkante, damit eine Karte aufliegt statt zu schweben.
       --shadow-sm und --shadow-md behalten ihre Namen; OrderFlow setzt
       --shadow-sm in app.css mit einem eigenen Ring zusammen. */
    --shadow-xs:        0 1px 2px rgba(23,23,21,0.04);
    --shadow-sm:        0 1px 2px rgba(23,23,21,0.05), 0 1px 1px rgba(23,23,21,0.03);
    --shadow-md:        0 4px 12px -2px rgba(23,23,21,0.08), 0 2px 4px -1px rgba(23,23,21,0.04);
    --shadow-lg:        0 14px 32px -8px rgba(23,23,21,0.14);

    --sidebar-width:    260px;

    --font-body:        'Hanken Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    --font-display:     'Space Grotesk', 'Hanken Grotesk', sans-serif;
    --font-mono:        'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
}

/* ==========================================================================
   SCHICHT C – DUNKEL
   --------------------------------------------------------------------------
   Wird per data-theme="dark" am <html> gesetzt (Init-Script im Layout).
   Ueberschreibt AUSSCHLIESSLICH Schicht B – niemals Schicht A: eine Leiter
   ist in beiden Themes dieselbe Leiter, nur anders herum benutzt.
   Die Flaechen-Leiter dreht sich um: die Karte ist HELLER als der Grund.
   ========================================================================== */
[data-theme="dark"] {
    --bg:               #131412;
    --surface:          #131412;
    --surface-lowest:   #1c1d1a;
    --surface-bright:   #212220;
    --surface-low:      #191a17;
    --surface-med:      #232420;
    --surface-high:     #2d2e29;
    --surface-highest:  #383934;
    --surface-variant:  #2d2e29;

    --primary:          var(--brand-500);
    --primary-fixed:    var(--brand-400);
    --primary-fixed-dim:#b8e050;
    --primary-container:var(--brand-900);
    --on-primary:       var(--brand-1000);
    --on-primary-fixed: var(--brand-1000);
    --on-primary-container: var(--brand-300);

    --secondary:        #a8a9a1;
    --secondary-container: #2d2e29;
    --on-secondary:     #131412;
    --on-secondary-container: #e9e9e4;

    --tertiary:         var(--tone-blue);
    --tertiary-container:var(--tone-blue-bg);
    --on-tertiary-container: var(--tone-blue);

    --text:             #e9e9e4;
    --text-muted:       #a8a9a1;
    --text-faint:       #8a8b84;
    --on-surface:       #e9e9e4;
    --on-surface-variant: #a8a9a1;

    --outline:          #6b6c65;
    --outline-variant:  #45463f;
    --border:           rgba(255,255,255,0.09);
    --border-strong:    #6b6c64;

    /* Status-Toene, dunkel: heller Text auf schwach gefaerbter Flaeche. */
    --tone-amber:      #fbbf24; --tone-amber-bg:  rgba(251,191,36,0.12);  --tone-amber-bd:  rgba(251,191,36,0.30);
    --tone-blue:       #93c5fd; --tone-blue-bg:   rgba(147,197,253,0.12); --tone-blue-bd:   rgba(147,197,253,0.30);
    --tone-violet:     #c4b5fd; --tone-violet-bg: rgba(196,181,253,0.12); --tone-violet-bd: rgba(196,181,253,0.30);
    --tone-teal:       #5eead4; --tone-teal-bg:   rgba(94,234,212,0.12);  --tone-teal-bd:   rgba(94,234,212,0.30);
    --tone-green:      #86efac; --tone-green-bg:  rgba(134,239,172,0.12); --tone-green-bd:  rgba(134,239,172,0.30);
    --tone-red:        #fda29b; --tone-red-bg:    rgba(253,162,155,0.12); --tone-red-bd:    rgba(253,162,155,0.30);
    --tone-neutral:    #a8a9a1; --tone-neutral-bg:rgba(168,169,161,0.12); --tone-neutral-bd:rgba(168,169,161,0.30);

    --accent-soft:      rgba(172,213,55,0.14);

    /* Schatten dunkel: gleiche Geometrie, kraeftiger, dazu eine hauchduenne
       helle Innenkante - im Dunkeln traegt nicht der Schatten die Abgrenzung,
       sondern die Kante. */
    --shadow-xs:        0 1px 2px rgba(0,0,0,0.40);
    --shadow-sm:        0 1px 2px rgba(0,0,0,0.45);
    --shadow-md:        0 4px 12px -2px rgba(0,0,0,0.55), inset 0 0 0 1px rgba(255,255,255,0.04);
    --shadow-lg:        0 14px 32px -8px rgba(0,0,0,0.60), inset 0 0 0 1px rgba(255,255,255,0.05);
}

/* === Reset & Base === */
* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 14px;
    line-height: 20px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-display);
    color: var(--text);
    margin: 0;
    font-weight: 600;
    letter-spacing: -0.01em;
}
h1 { font-size: 28px; line-height: 34px; font-weight: 600; letter-spacing: -0.02em; }
h2 { font-size: 18px; line-height: 24px; font-weight: 600; }
h3 { font-size: 14px; line-height: 20px; font-weight: 600; }

a { color: var(--primary); text-decoration: none; transition: opacity var(--dur-fast) var(--ease); }
a:hover { opacity: 0.7; text-decoration: underline; }

code, kbd, pre, .mono { font-family: var(--font-mono); }

/* === Layout === */
.app {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr;
    min-height: 100vh;
}

.sidebar {
    background: var(--surface-low);
    border-right: 1px solid var(--outline-variant);
    padding: 2rem 0 1rem;
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
}

.brand {
    padding: 0 1.5rem;
    margin-bottom: 2rem;
    font-family: var(--font-display);
    font-size: 22px;
    line-height: 28px;
    font-weight: 700;
    color: var(--text);
    letter-spacing: -0.01em;
}
.brand .dot { color: var(--primary); }
/* Mono bleibt genau dort, wo sie etwas leistet: bei Nummern und Codes. */
.mono, .num, .amount, code, kbd, pre, input[type="number"] { font-family: var(--font-mono); }
.brand-sub {
    display: block;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-faint);
    letter-spacing: 0;
    margin-top: 2px;
}

.main {
    padding: var(--sp-6);
    min-width: 0;
    background: var(--bg);
}

/* === Sidebar Navigation === */
.nav {
    list-style: none;
    padding: 0 0.8rem;
    margin: 0;
    flex: 1;
}
.nav li {
    margin: 1px 0;
}
.nav-section {
    font-size: 12px;
    color: var(--text-faint);
    padding: 1.25rem 1rem 0.4rem;
    font-weight: 600;
}
.nav a {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: var(--sp-2) var(--sp-3);
    color: var(--secondary);
    border-radius: var(--radius-lg);
    transition: all var(--dur-fast) var(--ease);
    font-size: 14px;
    font-weight: 500;
}
.nav a:hover {
    color: var(--text);
    background: var(--surface-high);
    text-decoration: none;
    opacity: 1;
}
.nav a.active {
    color: var(--text);
    background: var(--surface-med);
    font-weight: 600;
    border-left: 2px solid var(--primary);
    padding-left: calc(1rem - 2px);
}
.nav-icon { width: 18px; height: 18px; flex-shrink: 0; }

/* Rueckweg zum Startportal — LETZTER Eintrag der Navigation, nicht als eigener
   Block darunter (Entscheidung Philipp 2026-08-27).
   Als eigener Block hatte er zwei Fehler: auf dem Telefon blieb er stehen,
   waehrend das Menue zuklappte, und auf dem Schirm sah er aus wie ein
   angeflanschtes Anhaengsel. Als Navigationseintrag erbt er alles — Farbe,
   Abstand, Zuklappen — und braucht nur eine feine Trennlinie darueber, damit
   er nicht mit den Seiten DIESER App verwechselt wird. */
.nav li > .nav-portal {
    margin-top: 0.4rem;
    padding-top: 0.7rem;
    border-top: 1px solid var(--outline-variant);
    border-radius: 0;
}
.nav li > .nav-portal:hover { border-radius: 0; }

.user-box {
    border-top: 1px solid var(--outline-variant);
    padding: 1rem 1.5rem;
    margin-top: auto;
}

.user-name {
    font-weight: 600;
    color: var(--text);
    font-size: 14px;
}
.user-meta {
    font-size: 12px;
    color: var(--text-faint);
    margin-top: 2px;
    margin-bottom: 0.6rem;
}

.btn-link {
    background: none;
    border: none;
    color: var(--secondary);
    padding: 0;
    cursor: pointer;
    font-size: 13px;
    font-weight: 500;
}
.btn-link:hover { color: var(--primary); text-decoration: underline; }

/* === Top-Bar / Suche === */
.topbar {
    position: sticky;
    top: 0;
    z-index: 50;
    background: var(--bg);
    margin: calc(var(--sp-6) * -1) calc(var(--sp-6) * -1) var(--sp-5);
    padding: var(--sp-4) var(--sp-6) var(--sp-3);
}
.topbar-search {
    position: relative;
    width: 100%;
}
.topbar-search input[type="search"] {
    width: 100%;
    padding: 0.55rem 2.5rem 0.55rem 2.4rem;
    background: var(--surface-lowest);
    color: var(--text);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
    font-family: var(--font-mono);
    font-size: 13px;
    transition: border-color var(--dur-fast) var(--ease);
}
.topbar-search input[type="search"]:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 2px var(--accent-soft);
}
.topbar-search input[type="search"]::placeholder {
    color: var(--secondary);
    font-family: var(--font-mono);
    font-size: 13px;
}
.topbar-search-icon {
    position: absolute;
    left: 0.85rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--secondary);
    font-size: 16px;
    pointer-events: none;
}
.topbar-kbd {
    position: absolute;
    right: 0.7rem;
    top: 50%;
    transform: translateY(-50%);
    font-family: var(--font-mono);
    font-size: 10px;
    color: var(--secondary);
    padding: 2px 6px;
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius);
    background: var(--surface-low);
    pointer-events: none;
}

/* === Headlines / Subtitles === */
.page-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: var(--sp-6);
}
.subtitle {
    font-size: 16px;
    line-height: 24px;
    color: var(--secondary);
    margin-top: 0.25rem;
}

/* === Cards === */
.card {
    --card-pad: var(--sp-5);
    background: var(--surface-lowest);
    border-radius: var(--radius-lg);
    padding: var(--card-pad);
    margin-bottom: var(--sp-4);
    box-shadow: var(--shadow-sm);
}
.card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    /* Nur Abstand, keine abgesetzte Flaeche und keine Trennlinie: die Karte
       traegt seit Schritt 4 ueber ihren eigenen Grund, ein zweiter Ton im
       Kopf macht sie wieder unruhig. */
    margin: 0 0 var(--sp-3);
    padding: 0;
}
.card-header h2 { margin: 0; }

/* === Stats / KPI Cards === */
.stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--sp-3);
    margin-bottom: var(--sp-5);
}
/* Kennzahl-Kachel. Die ZAHL steht oben, die Beschriftung darunter, links
   traegt ein Streifen die Farbe des Zustands.

   Die Reihenfolge macht `order`, nicht das Markup: die drei Apps schreiben
   Beschriftung und Zahl in unterschiedlicher Folge in ihre Views, und keine
   davon soll dafuer angefasst werden muessen. So sehen alle gleich aus.

   Kein Rahmen mehr - wie bei den Karten traegt die Flaeche. */
.stat {
    background: var(--surface-lowest);
    border: 0;
    border-left: 3px solid var(--outline-variant);
    border-radius: var(--radius-lg);
    padding: var(--sp-4);
    display: flex;
    flex-direction: column;
    gap: 2px;
    transition: box-shadow var(--dur-fast) var(--ease);
    box-shadow: var(--shadow-xs);
}
.stat-value { order: -1; }
/* Farbe des Streifens - dieselben Toene wie die Status-Marken. */
.stat-amber   { border-left-color: var(--tone-amber); }
.stat-blue    { border-left-color: var(--tone-blue); }
.stat-violet  { border-left-color: var(--tone-violet); }
.stat-teal    { border-left-color: var(--tone-teal); }
.stat-green   { border-left-color: var(--tone-green); }
.stat-red     { border-left-color: var(--tone-red); }
.stat-neutral { border-left-color: var(--tone-neutral); }
.stat:hover { box-shadow: var(--shadow-sm); }
.stat-label {
    font-size: 13px;
    color: var(--text-muted);
    font-weight: 500;
}
.stat-value.warn { color: var(--warn); }
.stat-value.danger { color: var(--danger); }
.stat-value {
    font-family: var(--font-display);
    font-size: 26px;
    line-height: 30px;
    font-weight: 600;
    color: var(--text);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}
.stat-value.warn { color: var(--warn); }
/* Kacheln stecken in RefurbFlow in einem <a>, in RMAFlow ist die Kachel
   selbst der Verweis - beide Formen muessen gleich aussehen und dieselbe
   Rueckmeldung geben. */
a .stat { color: inherit; }
a:hover .stat { box-shadow: var(--shadow-sm); opacity: 1; }
a:has(> .stat) { text-decoration: none; }

/* === Detail Grid === */
.detail-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem;
}
@media (max-width: 900px) {
    .detail-grid { grid-template-columns: 1fr; }
}

/* === Buttons === */
.btn, button.btn, a.btn {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    padding: var(--sp-2) var(--sp-4);
    font-family: var(--font-body);
    font-size: 13px;
    line-height: 18px;
    font-weight: 600;
    border: 1px solid var(--border-strong);
    background: var(--surface-lowest);
    color: var(--text);
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: all var(--dur-fast) var(--ease);
    text-decoration: none;
}
.btn:hover {
    background: var(--surface-high);
    border-color: var(--outline);
    text-decoration: none;
}
.btn-primary {
    background: var(--primary-container);
    color: var(--on-primary-container);
    border-color: var(--primary-container);
}
.btn-primary:hover {
    background: var(--primary-fixed-dim);
    border-color: var(--primary-fixed-dim);
}
.btn-ghost {
    background: transparent;
    border-color: var(--outline-variant);
}
.btn-ghost:hover { background: var(--surface-low); }
.btn-danger {
    background: var(--danger-bg);
    color: var(--danger);
    border-color: var(--danger-border);
}
.btn-danger:hover { background: var(--danger); color: white; border-color: var(--danger); }
.btn-sm {
    padding: 5px var(--sp-3);
    font-size: 12px;
}

/* === Forms === */
.form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-4) var(--sp-5);
}
.field { display: flex; flex-direction: column; }
.field-full { grid-column: 1 / -1; }
.field label {
    font-size: 12.5px;
    color: var(--text-muted);
    margin-bottom: 0.35rem;
    font-weight: 600;
}
.field input[type="text"],
.field input[type="email"],
.field input[type="password"],
.field input[type="number"],
.field input[type="date"],
.field input[type="search"],
.field textarea,
.field select,
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="date"],
input[type="search"],
textarea,
select {
    padding: var(--sp-2) var(--sp-3);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
    background: var(--surface-lowest);
    color: var(--text);
    font-family: var(--font-body);
    /* 16px, NICHT 14: iOS Safari zoomt beim Fokus automatisch in die Seite
       hinein, sobald ein Eingabefeld kleiner als 16px gesetzt ist - und
       zoomt danach nicht von selbst zurueck. In einer Maske, die Feld fuer
       Feld durchlaufen wird, springt damit bei jedem Tippen die Ansicht.
       Am 2026-08-30 gemessen: davon waren ALLE 39 Felder der
       Wareneingangs-Erfassung betroffen.
       Der Wert steht hier bewusst fest und nicht als var(--fs-md): die
       --fs-Tokens werden in dieser Datei bislang an keiner einzigen Stelle
       benutzt, und eine neue Konvention nebenher einzufuehren macht die
       Basis nicht klarer. */
    font-size: 16px;
    line-height: 24px;
    transition: border-color var(--dur-fast) var(--ease);
}
.field input:focus,
.field textarea:focus,
.field select:focus,
input:focus, textarea:focus, select:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 2px var(--accent-soft);
}
textarea { font-family: var(--font-body); resize: vertical; min-height: 60px; }
input[type="number"] { font-family: var(--font-mono); }
.label-hint {
    font-size: 12px;
    color: var(--secondary);
    margin-top: 0.3rem;
}

.checkbox {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    cursor: pointer;
    font-size: 14px;
}
.checkbox input { width: auto; }

.form-actions {
    display: flex;
    gap: var(--sp-2);
    margin-top: var(--sp-5);
    flex-wrap: wrap;
}

.inline-form {
    display: inline-block;
    margin: 0;
}

/* Auswahlfeld in Tabellenzellen (Statuswechsel am Artikel bzw. Fall).
   Auch hier 16px gegen den iOS-Zoom - dafuer weniger Polsterung, damit die
   Zeile nicht hoeher wird als vorher. */
.select-inline {
    padding: 0.15rem 0.4rem;
    font-size: 16px;
    line-height: 22px;
    border-radius: var(--radius);
}

/* === Tables === */
table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}
thead tr {
    background: var(--surface-low);
    border-bottom: 1px solid var(--outline-variant);
}
th {
    text-align: left;
    padding: var(--sp-2) var(--sp-4);
    font-size: 12px;
    color: var(--text-faint);
    font-weight: 600;
    white-space: nowrap;
}
td {
    padding: var(--sp-3) var(--sp-4);
    border-bottom: 1px solid var(--outline-variant);
    color: var(--text);
    vertical-align: middle;
}
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--surface-bright); }
.num, td.num, th.num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.table-wrap {
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
    overflow-x: auto;
    background: var(--surface-lowest);
}
.card .table-wrap, .card table {
    /* Tabelle innerhalb der Card bleiben, nicht über die Card-Grenze hinausragen */
    margin: 1rem 0 0;
    width: 100%;
    border: none;
    border-radius: 0;
}
.card .table-wrap {
    /* Die Tabelle laeuft bis an die Kartenkante. Frueher stand hier
       width: calc(100% + 3rem) - eine harte Zahl, die bei jeder Aenderung
       des Innenmasses gebrochen waere. Jetzt rechnet sie mit --card-pad. */
    margin: var(--sp-4) calc(var(--card-pad) * -1) calc(var(--card-pad) * -1);
    width: auto;
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    border-top: 1px solid var(--outline-variant);
    overflow-x: auto;
}
.card > table:first-of-type {
    margin-top: 0;
    border-top: none;
}
/* Folgt die Tabelle direkt auf den Kartenkopf, blieb dazwischen ein leerer
   weisser Streifen stehen. Es braucht BEIDE Seiten: der Oberabstand der
   Tabelle allein reichte nicht, weil der Kopf selbst nach unten drueckt.
   (Im Browser nachgemessen, nicht geraten.) */
.card-header + .table-wrap,
.card-header + table {
    margin-top: 0;
    border-top: none;
}
.card-header:has(+ .table-wrap),
.card-header:has(+ table) {
    margin-bottom: var(--sp-3);
}

/* === Badges === */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: var(--r-pill);   /* Marken sind Pillen, keine Kaestchen */
    font-size: 12px;
    font-weight: 600;
    border: 1px solid;
    line-height: 16px;
    white-space: nowrap;
}
.badge-approved, .badge-received, .badge-ok {
    background: var(--success-bg);
    color: var(--success);
    border-color: var(--success-border);
}
.badge-submitted, .badge-partial, .badge-low {
    background: var(--warn-bg);
    color: var(--warn);
    border-color: var(--warn-border);
}
.badge-ordered, .badge-draft {
    background: var(--info-bg);
    color: var(--info);
    border-color: var(--info-border);
}
.badge-rejected, .badge-cancelled {
    background: var(--danger-bg);
    color: var(--danger);
    border-color: var(--danger-border);
}

/* === Alerts === */
.alert {
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radius-lg);
    border: 1px solid;
    margin-bottom: 1rem;
    font-size: 14px;
}
.alert-error {
    background: var(--danger-bg);
    color: var(--danger);
    border-color: var(--danger-border);
}
.alert-success {
    background: var(--success-bg);
    color: var(--success);
    border-color: var(--success-border);
}
.alert-info {
    background: var(--info-bg);
    color: var(--info);
    border-color: var(--info-border);
}
.alert-warn {
    background: var(--warn-bg);
    color: var(--warn);
    border-color: var(--warn-border);
}

.flash-wrap { margin-bottom: 1rem; }

.notice {
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radius-lg);
    border: 1px solid;
    font-size: 14px;
}
.notice-warn {
    background: var(--warn-bg);
    color: var(--warn);
    border-color: var(--warn-border);
}

/* === Empty States === */
.empty-state {
    text-align: center;
    padding: 2rem 1rem;
    color: var(--secondary);
}
.empty-state h3 {
    font-family: var(--font-display);
    font-size: 18px;
    color: var(--text);
    margin-bottom: 0.5rem;
}

/* === Misc helpers === */
.kv {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.5rem 1.25rem;
    margin: 0;
}
.kv dt {
    font-size: 12.5px;
    color: var(--text-faint);
    padding-top: 2px;
}
.kv dd { margin: 0; color: var(--text); }

.meta-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.meta-list li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--outline-variant);
}
.meta-list li:last-child { border-bottom: none; }
.meta-list .label {
    font-size: 12.5px;
    color: var(--text-faint);
}
.amount {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

/* === Filter Bar === */
.filter-bar {
    display: flex;
    gap: var(--sp-2);
    flex-wrap: wrap;
    align-items: center;
    margin-bottom: var(--sp-5);
}
.filter-link {
    padding: 0.4rem 0.8rem;
    background: var(--surface-lowest);
    color: var(--secondary);
    border: 1px solid var(--outline-variant);
    border-radius: var(--r-pill);   /* Filter sind Pillen */
    font-size: 13px;
    font-weight: 500;
    transition: all var(--dur-fast) var(--ease);
}
.filter-link:hover {
    color: var(--text);
    background: var(--surface-high);
    text-decoration: none;
    opacity: 1;
}
.filter-link.active {
    background: var(--accent-soft);
    color: var(--primary);
    border-color: var(--primary);
    font-weight: 600;
}

/* === Supplier Block (OrderFlow) === */
.supplier-block {
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
    padding: 1rem;
    margin-bottom: 1rem;
    background: var(--surface-bright);
}
.supplier-block h3 {
    font-family: var(--font-display);
    font-size: 15px;
    margin: 0 0 0.5rem;
}

/* === Login screen === */
.login-page, .login-wrap {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg);
    padding: 1rem;
}
.login-card {
    background: var(--surface-lowest);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-xl);
    padding: 2.5rem;
    width: 100%;
    max-width: 400px;
    box-shadow: var(--shadow-md);
}
.login-card .brand {
    text-align: center;
    margin-bottom: 2rem;
    padding: 0;
}
.login-card h1 {
    font-family: var(--font-display);
    font-size: 28px;
    margin-bottom: 0.5rem;
}

/* === Print: für Etiketten === */
@media print {
    .sidebar, .topbar, .page-header { display: none; }
    .main { padding: 0; }
    body, .app, .main { background: white; color: black; }
}

/* === Responsive === */
/* Der Umschalter fuer die Navigation auf schmalen Schirmen. Auf dem Rechner
   ist er unsichtbar - dort steht die Seitenleiste ohnehin offen. */
.nav-toggle {
    display: none;
    align-items: center; justify-content: center;
    width: 38px; height: 38px; padding: 0;
    background: transparent; border: 1px solid var(--outline-variant);
    border-radius: var(--radius); color: var(--text-muted); cursor: pointer;
}
.nav-toggle:hover { background: var(--surface-med); color: var(--text); }
.nav-toggle svg { width: 18px; height: 18px; }

@media (max-width: 768px) {
    .app { grid-template-columns: 1fr; }
    .sidebar {
        position: sticky; top: 0; z-index: 60;
        height: auto;
        padding: var(--sp-3) 0;
        border-right: none;
        border-bottom: 1px solid var(--outline-variant);
        background: var(--surface-low);
    }
    .main { padding: var(--sp-4); }
    .topbar {
        margin: calc(var(--sp-4) * -1) calc(var(--sp-4) * -1) var(--sp-4);
        padding: var(--sp-3) var(--sp-4) var(--sp-2);
    }
    .form-grid { grid-template-columns: 1fr; }
    .detail-grid { grid-template-columns: 1fr !important; }

    /* Zusammenklappbare Navigation. Bewusst an :has(.nav-toggle) gebunden:
       In einer App OHNE diesen Knopf bleibt alles wie bisher - sonst haetten
       RefurbFlow und OrderFlow auf dem Telefon plotzlich keine Navigation
       mehr, ohne dass es hier jemand merkt. */
    .sidebar:has(.nav-toggle) {
        display: grid;
        grid-template-columns: 1fr auto;
        align-items: center;
        gap: var(--sp-3);
        padding: var(--sp-2) var(--sp-4);
    }
    .sidebar:has(.nav-toggle) .brand { padding: 0; margin: 0; }
    .sidebar:has(.nav-toggle) .brand-sub { display: none; }
    .sidebar:has(.nav-toggle) .nav-toggle { display: inline-flex; }
    .sidebar:has(.nav-toggle) .nav,
    .sidebar:has(.nav-toggle) .user-box {
        display: none;
        grid-column: 1 / -1;
    }
    .sidebar:has(.nav-toggle).offen .nav,
    .sidebar:has(.nav-toggle).offen .user-box { display: block; }
    .sidebar:has(.nav-toggle).offen { padding-bottom: var(--sp-4); }
    .sidebar:has(.nav-toggle) .user-box { margin-top: var(--sp-3); padding-top: var(--sp-3); }
}

/* === Theme-Switcher (Sidebar bottom) === */
.theme-toggle {
    margin-top: 0.8rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    background: transparent;
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius);
    color: var(--secondary);
    cursor: pointer;
    transition: all var(--dur-fast) var(--ease);
}
.theme-toggle:hover {
    color: var(--text);
    border-color: var(--outline);
    background: var(--surface-high);
}
.theme-toggle .theme-icon { width: 14px; height: 14px; }
/* Default light: Mond-Icon zeigen (klick → dark) */
.theme-toggle .theme-icon-moon { display: block; }
.theme-toggle .theme-icon-sun  { display: none; }
[data-theme="dark"] .theme-toggle .theme-icon-moon { display: none; }
[data-theme="dark"] .theme-toggle .theme-icon-sun  { display: block; }

/* ============================================================
   UI-Klarheit (2026-07-16) — Status-Töne, Fokusringe, Utilities
   Shared-Block, identisch in RefurbFlow main.css + OrderFlow app.css.
   ============================================================ */

/* Die Status-Toene stehen seit Schritt 3 oben bei den Token (Schicht B),
   nicht mehr hier. Nur die Klassen dazu sind unten geblieben. */

/* Badges: minimal größer (10→11px, Lesbarkeit) + Punkt-Marker-Support */
.badge { gap: 5px; }
.badge .badge-dot { width: 6px; height: 6px; border-radius: 99px; background: currentColor; flex: none; }
.badge-tone-amber   { background: var(--tone-amber-bg);   color: var(--tone-amber);   border-color: var(--tone-amber-bd); }
.badge-tone-blue    { background: var(--tone-blue-bg);    color: var(--tone-blue);    border-color: var(--tone-blue-bd); }
.badge-tone-violet  { background: var(--tone-violet-bg);  color: var(--tone-violet);  border-color: var(--tone-violet-bd); }
.badge-tone-teal    { background: var(--tone-teal-bg);    color: var(--tone-teal);    border-color: var(--tone-teal-bd); }
.badge-tone-green   { background: var(--tone-green-bg);   color: var(--tone-green);   border-color: var(--tone-green-bd); }
.badge-tone-neutral { background: var(--tone-neutral-bg); color: var(--tone-neutral); border-color: var(--tone-neutral-bd); }
.badge-tone-danger  { background: var(--danger-bg);       color: var(--danger);       border-color: var(--danger-border); }

/* Tastatur-Fokus: sichtbarer Ring für alles Bedienbare (Inputs behalten
   ihren Border-Fokus aus dem Formular-Block) */
.btn:focus-visible,
button:focus-visible,
a:focus-visible,
.filter-link:focus-visible,
tr[tabindex]:focus-visible,
.theme-toggle:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

/* Klickbare Tabellenzeilen (ganze Zeile = Link) */
tbody tr.row-link { cursor: pointer; }
tbody tr.row-link:hover { background: var(--accent-soft); }
tbody tr.row-link:hover a { text-decoration: underline; }

/* Fix: globales a:hover{opacity:.7} ließ Link-Buttons ausbleichen */
a.btn:hover { opacity: 1; }

/* Typo-Utilities: 4 feste Stufen statt Ad-hoc-Inline-Größen */
.text-sm    { font-size: 13px; line-height: 18px; }
.text-xs    { font-size: 12px; line-height: 16px; }
.text-label {
    font-size: 12.5px; font-weight: 600; color: var(--text-muted);
}
.text-muted { color: var(--text-muted); }
.text-faint { color: var(--text-faint); }
.text-secondary { color: var(--secondary); }

/* Identitäts-Zelle in Listen: Nummer (Link) + Modell darunter */
.cell-id .cell-id-nr { font-family: var(--font-mono); font-size: 13px; font-weight: 600; }
.cell-id .cell-id-sub { color: var(--secondary); font-size: 12.5px; margin-top: 2px; }

/* Mitarbeiter-Avatare (Migration 016: users.photo) */
.avatar {
    width: 32px; height: 32px; border-radius: 99px; object-fit: cover;
    border: 1.5px solid var(--outline-variant); flex: none;
    display: inline-block; vertical-align: middle; background: var(--surface-med);
}
.avatar-lg { width: 56px; height: 56px; }
.avatar-initials {
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--accent-soft); color: var(--primary);
    font-family: var(--font-mono); font-size: 12px; font-weight: 700;
    letter-spacing: 0;
}
.avatar-md { width: 40px; height: 40px; }


/* ==========================================================================
   Bewegung auf Wunsch aus
   --------------------------------------------------------------------------
   Wer im Betriebssystem "Bewegung reduzieren" gesetzt hat, meint es ernst –
   fuer manche Menschen loesen Uebergaenge Schwindel aus. Bisher fehlte dieser
   Block ganz. Nicht 0s: eine Dauer von exakt 0 verschluckt in manchen
   Browsern das transitionend-Ereignis.
   ========================================================================== */
@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;
    }
}


/* ==========================================================================
   UTILITIES UND GETEILTE BAUSTEINE
   --------------------------------------------------------------------------
   Standen bis 2026-08-12 im RMAFlow-Block und waren damit fuer RefurbFlow und
   OrderFlow nicht zu haben - obwohl beide dieselben Seiten kennen (die
   2FA-Einrichtung ist Zeile fuer Zeile dieselbe) und dieselben Inline-Styles
   mit sich herumtragen.
   ========================================================================== */
/* ── Abstands-Helfer ────────────────────────────────────────────
   Ersetzen die häufigsten Inline-Styles in den Views. Vorher stand
   `style="margin: 0"` zwölfmal wortgleich da, `margin-bottom: 1rem` zehnmal —
   beides nur, um Vorgaben des Browsers zu korrigieren. */
.mb-0  { margin-bottom: 0 !important; }
.mb-3  { margin-bottom: var(--sp-3); }
.mb-4  { margin-bottom: var(--sp-4); }
.mb-5  { margin-bottom: var(--sp-5); }
.mt-1  { margin-top: var(--sp-1); }
.mt-3  { margin-top: var(--sp-3); }
.mt-4  { margin-top: var(--sp-4); }
.center { text-align: center; }

/* ── 2FA-Einrichtung ────────────────────────────────────────────
   Fünf Klassen im Markup dieser Seiten waren nie definiert: setup-steps,
   qr-block, secret-text, code-input, backup-codes. Die Seite hing damit
   allein an Browser-Vorgaben und zwei hartcodierten rgba()-Werten aus einer
   Palette, die es nicht mehr gibt. */
.setup-steps { display: grid; gap: var(--sp-4); padding-left: var(--sp-5); margin: 0 0 var(--sp-4); }
.setup-steps li { padding-left: var(--sp-1); }
.qr-block {
    display: flex; justify-content: center; padding: var(--sp-4);
    background: var(--n-0); border-radius: var(--radius-lg); margin: var(--sp-3) 0;
}
.qr-block img { display: block; max-width: 100%; height: auto; }
.secret-text {
    display: inline-block; font-family: var(--font-mono); font-size: 13px;
    background: var(--surface-med); border-radius: var(--radius);
    padding: var(--sp-1) var(--sp-2); word-break: break-all;
}
.code-input {
    font-family: var(--font-mono); font-size: 20px; letter-spacing: 0.3em;
    text-align: center; max-width: 220px;
}
.backup-codes {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: var(--sp-2); margin: var(--sp-3) 0 var(--sp-4);
    padding: var(--sp-4);
    background: var(--tone-teal-bg); border: 1px solid var(--tone-teal-bd);
    border-radius: var(--radius-lg);
}
.backup-codes code {
    font-family: var(--font-mono); font-size: 14px; font-weight: 600;
    color: var(--text); text-align: center;
}

/* Weitere Helfer für die letzten wiederkehrenden Inline-Styles */
.mb-2      { margin-bottom: var(--sp-2); }
.mt-5      { margin-top: var(--sp-5); }
.ml-auto   { margin-left: auto; }
.ml-2      { margin-left: var(--sp-2); }
.w-full    { width: 100%; }
.pre-wrap  { white-space: pre-wrap; }
.self-end  { align-self: end; }

/* Lange Freitextspalte (z.B. Details im Audit-Log) abschneiden statt umbrechen */
.cell-clip { max-width: 360px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nowrap { white-space: nowrap; }

/* Kleine Helfer, die die häufigsten Inline-Styles in den Views ersetzen */
.row      { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.row-end  { margin-left: auto; }
.stack    { display: grid; gap: var(--sp-2); }
.m-0      { margin: 0 !important; }
.mt-2     { margin-top: var(--sp-2); }

/* Name mit Bild in einer Tabellenzelle – viermal fast wortgleich als
   Inline-Flex-Leiste in den Views (Übersicht, Fallliste, Suche, Benutzer). */
.user-cell { display: inline-flex; align-items: center; gap: var(--sp-2); }

/* ── Filterleiste als Formular ──────────────────────────────────
   Auswertung und Audit-Log filtern über Datumsfelder und Auswahllisten, nicht
   über Marken. Sie steckten dafür in einer ganzen Karte mit zweispaltigem
   Raster — ein zweites Filter-Idiom neben dem der Fallliste. Jetzt tragen sie
   denselben flachen Streifen wie deren Feinfilter. */
.filter-form {
    display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-3) var(--sp-4);
    background: var(--surface-lowest); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xs); padding: var(--sp-3) var(--sp-4);
    margin-bottom: var(--sp-5);
}
.filter-form .field { flex: 0 1 auto; min-width: 140px; margin: 0; }
.filter-form .field label { margin-bottom: 2px; }
.filter-form .btn { margin-bottom: 1px; }
.filter-form .filter-form-end { margin-left: auto; display: flex; align-items: flex-end; gap: var(--sp-2); }
.mt-0 { margin-top: 0 !important; }
.text-danger { color: var(--danger); }
.mb-1 { margin-bottom: var(--sp-1); }

/* ── Hinweisleiste auf der Übersicht ────────────────────────────
   Bis Schritt 9 waren das in RMAFlow vier, in RefurbFlow zwei gestapelte Warnbänder, die zusammen ein
   Drittel des ersten Bildschirms belegten — obwohl jede Meldung eine Zeile
   ist. Jetzt stehen sie nebeneinander und sind anklickbar. */
.flag-bar { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-5); }
.flag {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px var(--sp-3); border-radius: var(--r-pill);
    background: var(--surface-lowest); color: var(--text-muted);
    box-shadow: var(--shadow-xs); text-decoration: none;
    font-size: 13px; font-weight: 500; white-space: nowrap;
}
.flag:hover { color: var(--text); text-decoration: none; opacity: 1; box-shadow: var(--shadow-sm); }
.flag .flag-dot { width: 6px; height: 6px; border-radius: 999px; background: currentColor; flex: none; }
.flag-red   { background: var(--tone-red-bg);   color: var(--tone-red); }
.flag-amber { background: var(--tone-amber-bg); color: var(--tone-amber); }

/* Der Markenname führt zur Startseite. Auf dem Telefon ist er oft das
   Einzige, was von der Navigation zu sehen ist, solange sie zugeklappt ist. */
.brand-link { color: inherit; text-decoration: none; }
.brand-link:hover { text-decoration: none; opacity: 1; }

/* --- Anmeldeseite mit Portal-Zwang (2026-08-27) ------------------------- */
/* Der Weg zum Portal ist die Hauptsache, der Notzugang die Fussnote — das
   Groessenverhaeltnis sagt es, nicht nur der Text. */
.portal-hinweis {
    margin: 0 0 1rem; font-size: 13.5px; color: var(--text-muted); line-height: 1.5;
}
.btn-block { display: block; width: 100%; text-align: center; }
.portal-notzugang {
    margin: 1.2rem 0 0; font-size: 11.5px; color: var(--text-faint); line-height: 1.5;
}
.portal-notzugang a { color: var(--text-muted); }

/* ==========================================================================
   MOBILE HUELLE (2026-09-15)
   --------------------------------------------------------------------------
   Markup dazu: @bur/core/mobil, eingebunden in den vier Layouts.

   AM RECHNER AENDERT SICH NICHTS. Alles Neue steht unter 768 px — derselbe
   Bruch, den diese Datei schon benutzt. Darueber sind die vier mob-*-Teile
   display:none, die Seitenleiste bleibt Seitenleiste.

   DIE SICHERUNG: jede Regel, die etwas WEGNIMMT (Suchzeile, Hamburger,
   Seitenleiste), haengt an `body:has(.mob-leiste)`. Eine Seite ohne die neue
   Leiste verhaelt sich also genau wie bisher. Ohne diese Bedingung haette
   eine Ansicht, die das Layout umgeht, auf dem Telefon gar keine Navigation
   mehr — und es wuerde niemandem auffallen, bis jemand sie sucht.
   ========================================================================== */

/* Das Attribut `hidden` setzt display:none mit der Spezifitaet 0,1,0 und
   verliert gegen JEDE eigene display-Regel. Es stand bisher in OrderFlows
   app.css und in start.css, in base.css und RMAFlows main.css fehlte es —
   also dreimal verschieden. Hier ist die eine Stelle dafuer. */
[hidden] { display: none !important; }

/* Text, der NUR in der Kartenansicht auf dem Telefon Sinn hat (das Wort zu
   einer Zahl, die am Rechner ihren Spaltenkopf hat). */
.nur-karte { display: none; }

.mob-kopf, .mob-leiste, .mob-plus, .mob-suche, .mob-blatt, .mob-dunkel { display: none; }

/* Am Rechner klappt das Skript den Filterblock auf; die Zusammenfassung ist
   dort nur im Weg. Gebunden an html.mob-js: ist das Skript nicht gelaufen,
   bleibt sie sichtbar - sonst waere der Filter ohne Javascript unerreichbar. */
@media (min-width: 769px) {
    html.mob-js details.mob-filter > summary { display: none; }
}

@media (max-width: 768px) {
    :root {
        --mob-kopf:   56px;
        --mob-leiste: 64px;
        /* Der Streifen unter der Leiste auf Geraeten mit Gestensteuerung.
           Ohne den Rueckfallwert 0px rechnet calc() in aelteren Browsern mit
           einem leeren Wert und faellt ganz aus. */
        --mob-safe:   env(safe-area-inset-bottom, 0px);
    }

    /* ---------- Kopf ---------- */
    .mob-kopf {
        display: flex; position: fixed; top: 0; left: 0; right: 0; z-index: 70;
        height: var(--mob-kopf); align-items: center; gap: var(--sp-1);
        padding: 0 var(--sp-2) 0 var(--sp-4);
        background: var(--bg); border-bottom: 1px solid transparent;
        transition: border-color var(--dur-fast) var(--ease);
    }
    .mob-kopf.geschoben { border-bottom-color: var(--outline-variant); }
    .mob-marke {
        margin-right: auto; font-family: var(--font-display);
        font-size: 19px; font-weight: 700; letter-spacing: -0.01em;
        color: var(--text); text-decoration: none;
    }
    .mob-marke:hover { opacity: 1; text-decoration: none; }
    .mob-marke .dot { color: var(--primary); }
    .mob-ik {
        width: 44px; height: 44px; flex: none; padding: 0; border: 0;
        background: transparent; color: var(--text-muted);
        border-radius: var(--r-pill); cursor: pointer;
        display: inline-flex; align-items: center; justify-content: center;
    }
    .mob-ik:active { background: var(--surface-med); }
    .mob-ik svg { width: 22px; height: 22px; }
    .mob-initialen {
        width: 34px; height: 34px; border-radius: var(--r-pill);
        background: var(--accent-soft); color: var(--primary);
        font-family: var(--font-mono); font-size: 12px; font-weight: 700;
        display: inline-flex; align-items: center; justify-content: center;
    }
    /* Platz fuer Kopf und Leiste. .app traegt es, damit keine Ansicht es
       einzeln nachziehen muss. */
    body:has(.mob-leiste) .app { padding-top: var(--mob-kopf); }
    body:has(.mob-leiste) .main {
        padding-bottom: calc(var(--mob-leiste) + var(--mob-safe) + var(--sp-4));
    }

    /* ---------- Die alte Suchzeile ----------
       Die SUCHE wandert in die Lupe. Die HAUPTAKTION der Seite (kopfAktion)
       bleibt stehen — sie ist auf manchen Seiten der einzige Weg zum
       Anlegen, und der Plus-Knopf kennt nur den Hauptfall der App. */
    body:has(.mob-leiste) .topbar-search,
    body:has(.mob-leiste) .tsearch,
    body:has(.mob-leiste) .topbar-kbd { display: none; }
    body:has(.mob-leiste) .topbar {
        position: static; margin: 0 0 var(--sp-4); padding: 0; background: none;
    }
    body:has(.mob-leiste) .topbar:not(:has(.topbar-action)) { display: none; }
    body:has(.mob-leiste) .topbar .topbar-action { width: 100%; justify-content: center; }
    /* Hauptaktion, die dasselbe tut wie der Plus-Knopf (siehe Layouts). */
    body:has(.mob-leiste) .topbar-action.mob-doppelt { display: none; }

    /* ---------- Seitenleiste wird Blatt von unten ----------
       Bewusst dieselbe Liste wie am Rechner, nicht eine zweite Fassung: ein
       neuer Menuepunkt erscheint damit automatisch auch auf dem Telefon.
       Die Klasse heisst weiter `offen` — die Zuklapp-Skripte der Apps
       laufen unveraendert weiter. */
    /* Der Hamburger aus der alten Fassung. Die Bedingung `.sidebar:has(
       .nav-toggle) .nav-toggle` weiter oben zaehlt DREI Klassen (die in :has()
       zaehlt mit) und schlaegt eine kuerzere Regel hier - im Blatt blieb der
       Knopf deshalb sichtbar. Also dieselbe Bedingung plus body:has(). */
    body:has(.mob-leiste) .nav-toggle,
    body:has(.mob-leiste) .sidebar:has(.nav-toggle) .nav-toggle { display: none; }
    body:has(.mob-leiste) .sidebar,
    body:has(.mob-leiste) .sidebar:has(.nav-toggle) {
        display: flex; flex-direction: column; align-items: stretch;
        justify-content: flex-start; gap: 0;
        position: fixed; top: auto; left: 0; right: 0; bottom: 0; z-index: 90;
        height: auto; max-height: 78vh; overflow-y: auto;
        padding: var(--sp-2) var(--sp-4) calc(var(--sp-4) + var(--mob-safe));
        background: var(--surface-lowest);
        border: 1px solid var(--outline-variant); border-bottom: 0;
        border-radius: var(--r-xl) var(--r-xl) 0 0;
        box-shadow: var(--shadow-lg);
        transform: translateY(101%);
        visibility: hidden;
        transition: transform var(--dur-slow) var(--ease),
                    visibility 0s linear var(--dur-slow);
    }
    body:has(.mob-leiste) .sidebar.offen {
        transform: none; visibility: visible;
        transition: transform var(--dur-slow) var(--ease), visibility 0s;
    }
    /* Der Griff GANZ oben am Blatt. order: -2, weil der Benutzerkasten auf
       -1 steht - ohne das lag der Griff mitten im Menue, unter den
       Konto-Knoepfen (am 2026-09-15 vom iPhone gemeldet). Pseudo-Elemente
       sind Flex-Kinder und ordnen sich mit ein. */
    body:has(.mob-leiste) .sidebar::before {
        content: ''; order: -2; flex: none;
        width: 40px; height: 4px; margin: 2px auto 14px;
        border-radius: var(--r-pill); background: var(--surface-high);
    }
    /* Die alte Fassung klappte NAV und Benutzerkasten zu, wenn die Leiste
       nicht `offen` war. Im Blatt ist beides immer sichtbar — versteckt ist
       das Blatt selbst. */
    body:has(.mob-leiste) .sidebar:has(.nav-toggle) .nav { display: block; }
    /* Der Benutzerkasten wird im Blatt eine Kopfzeile (Regeln unten) und
       braucht flex. Dieselbe Zahl an Klassen wie die Zeile darueber, sonst
       gewinnt sie mit ihrem display:block. */
    body:has(.mob-leiste) .sidebar:has(.nav-toggle) .user-box { display: flex; }
    /* ---------- Kopf des Blattes: wer ich bin, und was ich mit dem Konto
       tun kann ----------
       Am Rechner ist das die Fusszeile der Seitenleiste: Name, Rolle und
       darunter zwei Textlinks (2FA, Abmelden) plus der Hell/Dunkel-Knopf.
       So gestapelt sah das im Blatt nach Resten aus - zwei nackte Links
       neben einem umrahmten Kasten. Im Blatt werden daraus eine Kopfzeile
       und eine Reihe gleich hoher Knoepfe.

       Die vier Apps bauen diesen Kasten UNTERSCHIEDLICH (RMAFlow und
       RefurbFlow mit zwei Formularen, OrderFlow mit einem div davor, das
       Portal mit Avatar und zwei Symbolknoepfen). Deshalb greifen die Regeln
       an den gemeinsamen Klassen und nicht an der Reihenfolge. */
    body:has(.mob-leiste) .sidebar .user-box {
        order: -1;
        display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
        margin: 0 0 var(--sp-4); padding: 0 0 var(--sp-4);
        border-top: 0; border-bottom: 1px solid var(--outline-variant);
    }
    body:has(.mob-leiste) .sidebar .user-box .user-name,
    body:has(.mob-leiste) .sidebar .user-box .user-name-link {
        flex: 1 1 100%; font-size: 16.5px; font-weight: 600; color: var(--text);
    }
    body:has(.mob-leiste) .sidebar .user-box .user-meta {
        flex: 1 1 100%; margin: -6px 0 2px; font-size: 13px;
    }
    /* Das Portal hat Avatar und Textblock nebeneinander - die bleiben in
       einer Reihe, nur groesser. */
    body:has(.mob-leiste) .sidebar .user-box .avatar {
        width: 42px; height: 42px; flex: none; font-size: 14px;
    }
    body:has(.mob-leiste) .sidebar .user-box .user-txt { flex: 1 1 auto; min-width: 0; }
    /* Die Formulare und Huellen um die Knoepfe sind nur Verpackung. Das
       !important gilt einem margin-left: 0.8rem, das als Inline-Style im
       Markup steht (RMAFlow, RefurbFlow) - anders ist es nicht zu erreichen,
       und am Rechner soll es bleiben. */
    body:has(.mob-leiste) .sidebar .user-box form,
    body:has(.mob-leiste) .sidebar .user-box > div:not(.user-name):not(.user-meta):not(.user-txt) {
        margin: 0 !important; padding: 0; flex: 0 0 auto;
    }
    /* Aus Textlinks werden Pillen mit 44 px Hoehe. */
    body:has(.mob-leiste) .sidebar .user-box .btn-link {
        display: inline-flex; align-items: center; min-height: 44px;
        padding: 0 var(--sp-4); border: 1px solid var(--outline-variant);
        border-radius: var(--r-pill); background: var(--surface-low);
        color: var(--text); font-size: 13.5px; font-weight: 600;
        text-decoration: none;
    }
    body:has(.mob-leiste) .sidebar .user-box .btn-link:hover { text-decoration: none; }
    body:has(.mob-leiste) .sidebar .user-box .theme-toggle,
    body:has(.mob-leiste) .sidebar .user-box .sp-ikon-btn {
        width: 44px; height: 44px; margin: 0; flex: 0 0 auto;
        border-radius: var(--r-pill);
    }
    body:has(.mob-leiste) .sidebar .user-box .abmelden-form { flex: 0 0 auto; }
    body:has(.mob-leiste) .sidebar .brand { display: none; }

    /* ---------- Die Navigation im Blatt ---------- */
    body:has(.mob-leiste) .sidebar .nav { padding: 0; }
    body:has(.mob-leiste) .sidebar .nav li { margin: 0; }
    body:has(.mob-leiste) .sidebar .nav a,
    body:has(.mob-leiste) .sidebar .nav button,
    body:has(.mob-leiste) .sidebar .nav .nav-eintrag {
        min-height: 48px; font-size: 15px; gap: var(--sp-3);
        width: 100%; text-align: left;
    }
    /* Die Symbole sind auf 16 gezeichnet und wirken in einer 48-px-Reihe
       verloren. */
    body:has(.mob-leiste) .sidebar .nav .nav-icon,
    body:has(.mob-leiste) .sidebar .nav svg { width: 20px; height: 20px; }
    body:has(.mob-leiste) .sidebar .nav-section {
        padding: var(--sp-4) var(--sp-3) var(--sp-1);
        font-size: 11.5px; letter-spacing: 0.06em; text-transform: uppercase;
    }
    /* Der Rueckweg ins Portal steht am Ende und darf sich absetzen. */
    body:has(.mob-leiste) .sidebar .nav .nav-portal {
        margin-top: var(--sp-3); border-top: 1px solid var(--outline-variant);
        padding-top: var(--sp-3); border-radius: 0;
    }

    /* ---------- Leiste unten ---------- */
    .mob-leiste {
        display: grid; position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
        grid-template-columns: repeat(4, 1fr);
        height: calc(var(--mob-leiste) + var(--mob-safe));
        padding-bottom: var(--mob-safe);
        background: var(--surface-lowest);
        border-top: 1px solid var(--outline-variant);
    }
    .mob-leiste.mit-plus { grid-template-columns: 1fr 1fr 76px 1fr 1fr; }
    .mob-tab {
        display: flex; flex-direction: column; align-items: center;
        justify-content: center; gap: 3px; min-height: 44px;
        border: 0; background: transparent; padding: 0;
        color: var(--text-faint); text-decoration: none; cursor: pointer;
    }
    .mob-tab:hover { text-decoration: none; opacity: 1; }
    .mob-tab svg { width: 23px; height: 23px; }
    .mob-tab span { font-size: 11px; line-height: 13px; font-weight: 500; }
    .mob-tab.aktiv { color: var(--primary); }
    .mob-tab.aktiv span { font-weight: 700; }
    .mob-plus {
        display: inline-flex; position: fixed; left: 50%; z-index: 81;
        bottom: calc(var(--mob-leiste) + var(--mob-safe) - 42px);
        transform: translateX(-50%);
        width: 58px; height: 58px; border-radius: var(--r-pill);
        align-items: center; justify-content: center;
        background: var(--primary-container); color: var(--on-primary-container);
        border: 3px solid var(--bg); box-shadow: var(--shadow-md); cursor: pointer;
    }
    .mob-plus:active { background: var(--primary-fixed-dim); }
    .mob-plus svg { width: 28px; height: 28px; }

    /* ---------- Such-Overlay ---------- */
    .mob-suche {
        display: flex; flex-direction: column;
        position: fixed; inset: 0; z-index: 95; background: var(--bg);
        opacity: 0; visibility: hidden; transform: translateY(-10px);
        transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
                    visibility 0s linear var(--dur);
    }
    .mob-suche.offen {
        opacity: 1; visibility: visible; transform: none;
        transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
                    visibility 0s;
    }
    .mob-suchkopf {
        display: flex; align-items: center; gap: var(--sp-1);
        height: var(--mob-kopf); padding: 0 var(--sp-2);
        border-bottom: 1px solid var(--outline-variant);
    }
    .mob-suchlupe { display: inline-flex; color: var(--text-faint); }
    .mob-suchlupe svg { width: 18px; height: 18px; }
    .mob-suche input[type="search"] {
        flex: 1; min-width: 0; min-height: 44px;
        border: 0; background: transparent; padding: 0 var(--sp-2);
    }
    .mob-suche input[type="search"]:focus { outline: none; box-shadow: none; }
    .mob-suchkoerper { flex: 1; overflow-y: auto; padding: var(--sp-4); }
    .mob-label {
        font-size: 11.5px; font-weight: 600; letter-spacing: 0.06em;
        text-transform: uppercase; color: var(--text-faint); margin-bottom: var(--sp-2);
    }
    .mob-sprungreihe { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
    .mob-sprung {
        min-height: 44px; display: inline-flex; align-items: center;
        padding: 0 var(--sp-4); border-radius: var(--r-pill);
        border: 1px solid var(--outline-variant); background: var(--surface-lowest);
        color: var(--secondary); font-size: 13.5px; font-weight: 500;
    }
    .mob-sprung:hover { text-decoration: none; opacity: 1; }

    /* ---------- Blatt fuer den Plus-Knopf ---------- */
    .mob-blatt {
        display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
        max-height: 78vh; overflow-y: auto;
        padding: var(--sp-2) var(--sp-4) calc(var(--sp-4) + var(--mob-safe));
        background: var(--surface-lowest);
        border-radius: var(--r-xl) var(--r-xl) 0 0; box-shadow: var(--shadow-lg);
        transform: translateY(101%); visibility: hidden;
        transition: transform var(--dur-slow) var(--ease),
                    visibility 0s linear var(--dur-slow);
    }
    .mob-blatt.offen {
        transform: none; visibility: visible;
        transition: transform var(--dur-slow) var(--ease), visibility 0s;
    }
    .mob-griff {
        width: 40px; height: 4px; border-radius: var(--r-pill);
        background: var(--surface-high); margin: 4px auto 10px;
    }
    .mob-blatt-titel {
        font-family: var(--font-display); font-size: 17px; line-height: 24px;
        margin: 0 0 var(--sp-3);
    }
    .mob-blatt-zeile {
        display: flex; align-items: center; gap: var(--sp-4);
        min-height: 56px; padding: var(--sp-2) var(--sp-1);
        border-bottom: 1px solid var(--outline-variant);
        color: var(--text); font-size: 15px;
    }
    .mob-blatt-zeile:last-child { border-bottom: 0; }
    .mob-blatt-zeile:hover { text-decoration: none; opacity: 1; }
    .mob-blatt-ikon {
        width: 38px; height: 38px; flex: none; border-radius: var(--radius-lg);
        background: var(--accent-soft); color: var(--primary);
        display: inline-flex; align-items: center; justify-content: center;
    }
    .mob-blatt-ikon svg { width: 20px; height: 20px; }
    .mob-blatt-sub { display: block; font-size: 12.5px; color: var(--text-faint); font-weight: 400; }

    /* ---------- Dunkler Grund ---------- */
    .mob-dunkel {
        display: block; position: fixed; inset: 0; z-index: 85;
        background: rgba(0, 0, 0, 0.38);
        opacity: 0; pointer-events: none;
        transition: opacity var(--dur) var(--ease);
    }
    .mob-dunkel.an { opacity: 1; pointer-events: auto; }
    /* Hintergrund festhalten, solange ein Blatt oder die Suche offen ist. */
    html.mob-fest, html.mob-fest body { overflow: hidden; }

    /* ---------- Listen werden Karten ----------
       Eine Tabelle mit 6 bis 9 Spalten ist auf 390 px kein Gitter mehr,
       sondern seitliches Wischen: sichtbar bleibt eine halbe Zeile.

       DIESELBE TABELLE wird hier zur Karte, es gibt KEINE zweite Ausgabe
       daneben. Eine Fallliste zeigt bis zu 300 Zeilen - zweimal ausgegeben
       waere das zweimal alles im Dokument, damit die Haelfte davon
       ausgeblendet werden kann.

       Opt-in in der View: <table class="karten">, und jede Zelle sagt, was
       sie auf dem Telefon ist:
         data-rolle="titel"   Nummer und Bezeichnung, links oben
         data-rolle="marke"   Status o.ae., rechts oben
         data-rolle="meta"    kleine Zeile darunter
         data-rolle="aktion"  eigene Zeile darunter (Eingaben, Knoepfe)
         data-rolle="weg"     auf dem Telefon nicht (steht im Detail)
       Ohne Rolle bleibt eine Zelle eine schlichte Zeile in der Karte.

       WARUM order: Flex ordnet in DOKUMENTreihenfolge, und die ist die
       Spaltenreihenfolge der Tabelle. In der Fallliste steht "Art" VOR dem
       Status - ohne order landete die Fallart oben rechts und der Status
       unten in der Meta-Zeile. Am 2026-09-15 genau so gesehen.

       WARUM 60 % MINUS 10 px UND 40 % MINUS 10 px: Flex entscheidet den
       UMBRUCH nach der Basisbreite und laesst die Kaesten erst danach
       wachsen. Mit `auto` passte neben Nummer und Status oft noch die erste
       Meta-Angabe in die erste Reihe. Zwei Kaesten mit zusammen 100 % lassen
       dort nichts mehr zu - ABER die Luecke (gap: 10 px) zaehlt mit, und
       dann sind 100 % schon zu viel: am 2026-09-15 im Browser gemessen war
       der Inhalt der Zeile 324 px breit, 58 % + 42 % + 10 px ergaben 352 px,
       und der Status rutschte in die zweite Reihe. Deshalb je 10 px abzogen:
       zusammen 100 % minus 20 px, plus eine Luecke von 10 px passt sicher.

       KEINE TRENNPUNKTE zwischen den Meta-Angaben: welche die letzte ist,
       weiss nur der Browser (Zellen koennen ausgeblendet sein), und ein
       Punkt hinter der letzten Angabe sieht nach Fehler aus. Es trennt der
       Abstand. */
    /* tfoot gehoert mit auf Block: sonst bleibt die Summenzeile eine
       Tabellenfussgruppe und die Karte darin nur so breit wie ihr Text.
       Am 2026-09-15 im Bestelldetail genau so gesehen. */
    body:has(.mob-leiste) .karten,
    body:has(.mob-leiste) .karten tbody,
    body:has(.mob-leiste) .karten tfoot { display: block; }
    body:has(.mob-leiste) .karten thead { display: none; }
    body:has(.mob-leiste) .karten tr {
        display: flex; flex-wrap: wrap; align-items: baseline;
        gap: 4px 10px;
        padding: 14px var(--sp-4); margin-bottom: 10px;
        background: var(--surface-lowest);
        border: 1px solid var(--outline-variant);
        border-radius: var(--r-lg);
        box-shadow: var(--shadow-xs);
    }
    body:has(.mob-leiste) .karten tr:hover { background: var(--surface-lowest); }
    body:has(.mob-leiste) .karten tr:active { background: var(--surface-bright); }
    body:has(.mob-leiste) .karten td { display: block; padding: 0; border: 0; }
    /* min-width: 0 ist hier PFLICHT, nicht Kosmetik: ein Flex-Kasten
       schrumpft von sich aus nicht unter die min-content-Breite seines
       Inhalts. "RMA-2609-0042 frei" ueber "ThinkPad T14 Gen 3" ist breiter
       als 58 %, der Titel nahm sich mehr, und der Status fand in der ersten
       Reihe keinen Platz mehr - am 2026-09-15 genau so gesehen. */
    body:has(.mob-leiste) .karten td[data-rolle="titel"] {
        flex: 1 1 calc(60% - 10px); order: 0; min-width: 0;
    }
    body:has(.mob-leiste) .karten td[data-rolle="marke"] {
        flex: 1 1 calc(40% - 10px); order: 1; min-width: 0; text-align: right;
    }
    body:has(.mob-leiste) .karten td[data-rolle="meta"] {
        flex: 0 0 auto; order: 2; font-size: 13px; color: var(--text-faint);
    }
    body:has(.mob-leiste) .karten td[data-rolle="meta"]:empty { display: none; }
    /* Eine Angabe, die nur aus einem Gedankenstrich besteht, ist auf dem
       Telefon Platzverschwendung: in der Tabelle haelt der Strich die Spalte
       offen, in der Karte gibt es keine Spalte. Die View markiert ihn mit
       <span class="leer">. */
    body:has(.mob-leiste) .karten td[data-rolle="meta"]:has(> .leer:only-child) {
        display: none;
    }
    /* Aktionszellen (Ankreuzfeld, Eingabe, Ergebnis) gehoeren in EINE Reihe
       unter den Angaben. Den Umbruch davor macht ein Pseudo-Element mit
       flex-basis 100 % und order 3 - das ist die einzige Moeglichkeit, in
       einer Flex-Zeile einen Umbruch zu erzwingen, ohne ein Element ins
       Markup zu setzen (im Markup waere es eine zusaetzliche SPALTE der
       Tabelle am Rechner). Es steht nur in Zeilen, die Aktionszellen haben -
       sonst waere in jeder Karte eine leere Reihe und damit 4 px Luft. */
    body:has(.mob-leiste) .karten tr:has(td[data-rolle="aktion"])::after {
        content: ''; flex: 0 0 100%; height: 0; order: 3;
    }
    body:has(.mob-leiste) .karten td[data-rolle="aktion"] {
        flex: 0 0 auto; order: 4; margin-top: var(--sp-2);
        display: flex; align-items: center; gap: var(--sp-2);
    }
    /* Die Eingabe nimmt den Platz, der uebrig ist - sie ist das Ziel.
       flex-basis 50 % und min-width 0, nicht `auto`: mit width:100% am Feld
       und Basis `auto` rechnet der Browser die Zelle so breit wie das Feld
       moechte, und die Reihe bricht mitten in der Aktion um. */
    body:has(.mob-leiste) .karten td[data-rolle="aktion"]:has(input[type="text"]) {
        flex: 1 1 50%; min-width: 0;
    }
    body:has(.mob-leiste) .karten td[data-rolle="aktion"] input[type="text"] {
        width: 100%;
    }
    /* Zahlenfelder bleiben schmal: sie stehen in der Inventur zwischen zwei
       44-px-Knoepfen, und eine Vollbreite sprengte die Reihe. Die Breite
       setzt dort die App (app.css). */
    /* Ankreuzfeld mit Beschriftung: 44 px Ziel, nicht 13 px Kaestchen. */
    body:has(.mob-leiste) .karten td[data-rolle="aktion"] .nur-karte {
        font-size: 13px; color: var(--text-muted);
    }
    body:has(.mob-leiste) .karten td[data-rolle="weg"] { display: none; }
    /* Der Rahmen um die Tabelle gehoert zur Tabelle - Karten tragen ihren
       eigenen. Auch innerhalb einer .card, wo .table-wrap negative Raender
       hat, um bis an die Kante zu laufen. */
    body:has(.mob-leiste) .table-wrap:has(.karten),
    body:has(.mob-leiste) .tabelle-scroll:has(.karten) {
        border: 0; background: none; overflow: visible; border-radius: 0;
        margin: 0; padding: 0;
    }
    body:has(.mob-leiste) .card .table-wrap:has(.karten) {
        margin: var(--sp-3) 0 0; width: auto; border-top: 0;
    }
    /* Eine nackte Zahl braucht in der Karte ihr Wort: "3" sagt nichts, in
       der Tabelle sagt es der Spaltenkopf. */
    body:has(.mob-leiste) .karten .nur-karte { display: inline; }
    /* Die Kennung steht in der Karte gross, nicht als Listenzelle. */
    body:has(.mob-leiste) .karten .cell-id .cell-id-nr { font-size: 14.5px; }
    body:has(.mob-leiste) .karten .cell-id .cell-id-sub {
        font-size: 14px; color: var(--text); font-weight: 600; margin-top: 3px;
    }

    /* ---------- Filterblock ----------
       Sieben gestapelte Felder vor der ersten Karte sind auf 390 px ein
       eigener Bildschirm. Zugeklappt sind sie eine Zeile. */
    .mob-filter > summary {
        list-style: none; cursor: pointer;
        display: flex; align-items: center; gap: var(--sp-2);
        min-height: 44px; padding: 0 var(--sp-4);
        background: var(--surface-lowest);
        border: 1px solid var(--outline-variant); border-radius: var(--r-lg);
        font-weight: 600; font-size: 14px;
    }
    .mob-filter > summary::-webkit-details-marker { display: none; }
    .mob-filter > summary::after {
        content: ''; width: 8px; height: 8px; margin-left: auto;
        border-right: 2px solid var(--text-faint);
        border-bottom: 2px solid var(--text-faint);
        transform: rotate(45deg); transition: transform var(--dur-fast) var(--ease);
    }
    .mob-filter[open] > summary::after { transform: rotate(-135deg); }
    .mob-filter[open] > summary { margin-bottom: var(--sp-3); }

    /* ---------- Mehrspaltige Gitter, die als INLINE-STYLE in der View
       stehen ----------
       DER GRUND, WARUM DIE SEITE AUF DEM TELEFON BREITER WAR ALS DER SCHIRM
       (am 2026-09-15 von Philipp gemeldet: "rechts abgeschnitten, Zoom auf
       100"). 29 Stellen in 15 Views setzen ihre Spalten per style-Attribut,
       zum Beispiel `style="grid-template-columns: 3fr 2fr"` auf RefurbFlows
       Uebersicht oder `1fr 2fr 1.5fr` auf der Artikel-Detailseite. Ein
       Inline-Style schlaegt jede Klassenregel - die Regel
       `.form-grid { grid-template-columns: 1fr }` weiter oben lief also ins
       Leere, die Spalten blieben stehen, und jede Spalte hat eine
       Mindestbreite aus ihrem Inhalt.

       Gemessen bei 390 px Schirm: Kategorie bearbeiten 930 px, Marge 797,
       Monatsbericht 619, Uebersicht 388.

       `!important` ist hier kein Notnagel, sondern das einzige Mittel gegen
       ein style-Attribut. Der Attribut-Selektor trifft genau die Stellen,
       die eines tragen - Gitter aus Stylesheets (die .karten, die Leiste,
       die Katalogzeile) bleiben unberuehrt. */
    body:has(.mob-leiste) [style*="grid-template-columns"],
    body:has(.mob-leiste) .form-grid,
    body:has(.mob-leiste) .detail-grid,
    body:has(.mob-leiste) .stats {
        grid-template-columns: minmax(0, 1fr) !important;
    }
    /* minmax(0, 1fr) und nicht 1fr: `1fr` heisst minmax(AUTO, 1fr), und das
       automatische Minimum ist die min-content-Breite des Inhalts - ein
       Kasten darin schrumpft also nicht unter seinen breitesten
       unteilbaren Inhalt, und die Spalte waechst ueber den Schirm hinaus.
       Gemessen auf RefurbFlows Uebersicht: eine Karte wurde 372 px breit,
       obwohl 358 Platz waren. Dasselbe fuer die Kaesten selbst. */
    body:has(.mob-leiste) .app { grid-template-columns: minmax(0, 1fr); }
    body:has(.mob-leiste) .main,
    body:has(.mob-leiste) .card,
    body:has(.mob-leiste) .field { min-width: 0; }

    /* ---------- Tabellen ohne Scrollkasten ----------
       15 Ansichten stellen kleine Tabellen direkt in eine Karte, ohne
       .table-wrap darum (Uebersichten, Mail-Einstellungen, Team, eBay-Konten
       ...). Ohne Kasten gibt es kein overflow-x, und eine Tabelle ist so
       breit, wie ihr Inhalt es verlangt: RefurbFlows Uebersicht zog die
       Seite dadurch auf 368 px bei 360 px Schirm.

       table-layout: fixed laesst die Spalten in die vorhandene Breite und
       bricht den Text um, statt hinauszuragen - und overflow-wrap faengt
       lange unteilbare Zeichenketten (Seriennummern, Artikelnummern).
       Tabellen IN einem Kasten bleiben unberuehrt, die scrollen ja. */
    body:has(.mob-leiste) table:not(.karten):not(.table-wrap table):not(.tabelle-scroll table) {
        width: 100%; min-width: 0; table-layout: fixed;
    }
    /* Ohne table-layout: fixed reicht overflow-wrap NICHT - RefurbFlows
       Uebersicht blieb bei 375 px Schirm 368 px breit (nachgemessen).
       Mit fixem Layout werden alle Spalten gleich breit, und in der ersten
       steht fast immer der Name: aus "Mitarbeiter" und "WE" wurde
       "MitarbeiterWE". Deshalb bekommt die erste Spalte den groesseren
       Anteil, der Rest teilt sich den Platz. */
    body:has(.mob-leiste) table:not(.karten):not(.table-wrap table):not(.tabelle-scroll table) th:first-child,
    body:has(.mob-leiste) table:not(.karten):not(.table-wrap table):not(.tabelle-scroll table) td:first-child { width: 42%; }
    body:has(.mob-leiste) table:not(.karten):not(.table-wrap table):not(.tabelle-scroll table) td,
    body:has(.mob-leiste) table:not(.karten):not(.table-wrap table):not(.tabelle-scroll table) th {
        overflow-wrap: anywhere;
    }

    /* ---------- Touch-Ziele ----------
       Gerechnet, nicht geraten: .btn kam auf 8+18+8+2 = 36 px, .btn-sm auf
       30, .filter-link auf ~35, .theme-toggle auf 32. Alles unter den 44 px,
       die eine Fingerspitze braucht. Nur .btn-sm bleibt bei 40: er steht in
       Tabellenzeilen, und 44 sprengt die Zeilenhoehe. */
    .btn, button.btn, a.btn { min-height: 44px; }
    .btn-sm { min-height: 40px; }
    .filter-link { display: inline-flex; align-items: center; min-height: 44px; }
    .btn-link { display: inline-flex; align-items: center; min-height: 44px; }
    .theme-toggle { width: 44px; height: 44px; }
    .theme-toggle .theme-icon { width: 18px; height: 18px; }
    input[type="text"], input[type="email"], input[type="password"],
    input[type="number"], input[type="date"], input[type="search"],
    select { min-height: 44px; }
    /* Ankreuzfelder bleiben klein — sie sitzen an Beschriftungen, und eine
       Vergroesserung auf 44 px verschiebt jedes Formular. Offen. */
}
