/*
 * ===========================================================================
 *  PrintPilot — designový systém
 * ===========================================================================
 *
 *  Načítá se AŽ ZA `tabler.min.css`, takže v kaskádě vyhrává. Tabler zůstává
 *  základem: nepřepisujeme jeho komponenty, jen jim podstrkujeme vlastní
 *  hodnoty proměnných. Značkování v Blade se kvůli tomuhle souboru měnit
 *  nemusí.
 *
 *  Pravidla, ze kterých soubor vychází, jsou v `docs/DESIGN_DNA.md`
 *  (závazný vstup) a jejich překlad do praxe v `docs/DESIGN_SYSTEM.md`.
 *
 *  Stavba:
 *    0. Písmo (vendorované, žádné CDN — CSP `font-src 'self' data:`)
 *    1. Tokeny — světlé téma
 *    2. Tokeny — tmavé téma (navržené, ne odvozené inverzí)
 *    3. Základ — typografie a čísla
 *    4. Kompozice — stránka, hlavička, postranní panel
 *    5. Komponenty — karty, tlačítka, odznaky, formuláře
 *    6. Tabulky a hustota
 *    7. Stavy — brána cyklu, doklady, schvalování marží
 *    8. Prázdné a chybové stavy
 *    9. Přepínač témat
 *   10. Drobnosti převzaté z původního tématu
 *   11. Dashboard — konfigurovatelné widgety
 *   12. Měřidlo a graf
 *   13. Hutný seznam — filtrační lišta a odlehčené řádky
 *   14. Matice pozice × varianta (CRM)
 *   15. Přihlašovací obrazovky (auth/)
 *   16. Nápověda — sazba kapitoly manuálu (help/)
 *
 *  MANTINEL (F*-S3): žádná externí adresa — ani importované cizí stylopisy,
 *  ani odkaz na CDN uvnitř url(). Písmo je vendorované ve `public/fonts/`,
 *  CSP (`font-src 'self' data:`) se kvůli němu nerozvolňuje. Hlídá to
 *  `DesignSystemTest::test_stylesheet_has_no_external_url`; příkaz na ruční
 *  ověření je v docs/DESIGN_SYSTEM.md.
 */

/* ===========================================================================
   0. PÍSMO — Nunito Sans (DNA §5: geometricko-humanistický sans)
   ---------------------------------------------------------------------------
   Variabilní řez 200–1000 ve dvou podmnožinách. `latin` nese základ včetně
   á é í ó ú ý, `latin-ext` české háčky a kroužek (ř U+0159, ě U+011B,
   ů U+016F, š ž č ť ď ň). Bez druhého souboru by diakritika spadla na
   systémový fallback a text by v půlce slova změnil písmo.

   Číslice jsou v Nunito Sans stejně široké už z výroby (600/1000 em všechny),
   takže `tabular-nums` v §3 jen potvrzuje, co písmo dělá samo.

   Licence: SIL OFL 1.1 — `public/fonts/OFL.txt`.
   =========================================================================== */
@font-face {
    font-family: 'Nunito Sans';
    font-style: normal;
    font-weight: 200 1000;
    font-stretch: 100%;
    font-display: swap;
    src: url('../fonts/nunito-sans-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                   U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
                   U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Nunito Sans';
    font-style: normal;
    font-weight: 200 1000;
    font-stretch: 100%;
    font-display: swap;
    src: url('../fonts/nunito-sans-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                   U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ===========================================================================
   1. TOKENY — SVĚTLÉ TÉMA
   ---------------------------------------------------------------------------
   Směr „nordický klid" z DNA §2: chladná šedomodrá plocha, bílé karty,
   značková červená zůstává akcentem (ne plochou). Vlastní tokeny mají prefix
   `--pp-`; hned pod nimi je most do Tableru (`--tblr-`), aby se stávající
   komponenty převzaly bez zásahu do šablon.
   =========================================================================== */
:root,
[data-bs-theme=light] {
    /* --- plochy a text ---------------------------------------------------- */
    --pp-bg: #eef2f8;               /* podklad stránky */
    --pp-surface: #ffffff;          /* karta, vyvýšená plocha */
    --pp-surface-2: #f5f8fc;        /* hlavička karty, pruhování tabulky */
    --pp-surface-3: #e6ecf5;        /* zapuštěná plocha, wells */
    --pp-ink: #101a28;              /* hlavní text */
    --pp-ink-2: #45546b;            /* doplňkový text */
    --pp-ink-3: #74839a;            /* tichý text, popisky os */
    --pp-line: #dde5f0;             /* jemná linka */
    --pp-line-strong: #c7d3e3;      /* výraznější linka, oddělovače */

    /* --- značka a akcenty -------------------------------------------------- */
    --pp-brand: #d63939;
    --pp-brand-rgb: 214, 57, 57;
    --pp-brand-strong: #b52a2a;
    --pp-brand-soft: #fdeded;
    --pp-brand-on: #ffffff;
    --pp-accent: #0e7c86;           /* chladný modrozelený akcent (DNA §2) */
    --pp-accent-rgb: 14, 124, 134;
    --pp-accent-soft: #e2f4f5;

    /* --- sémantika stavů --------------------------------------------------- */
    --pp-success: #1c8a52;
    --pp-success-rgb: 28, 138, 82;
    --pp-success-soft: #e3f5ea;
    --pp-warning: #a86a00;
    --pp-warning-rgb: 168, 106, 0;
    --pp-warning-soft: #fdf1dc;
    --pp-danger: #c62f2f;
    --pp-danger-rgb: 198, 47, 47;
    --pp-danger-soft: #fdeaea;
    --pp-info: #2360c4;
    --pp-info-rgb: 35, 96, 196;
    --pp-info-soft: #e7effc;
    --pp-neutral: #64748b;
    --pp-neutral-rgb: 100, 116, 139;
    --pp-neutral-soft: #eceff4;
    --pp-orange: #b45309;
    --pp-orange-rgb: 180, 83, 9;
    --pp-orange-soft: #fdf0e3;
    --pp-azure: #1f7fbd;
    --pp-azure-rgb: 31, 127, 189;
    --pp-azure-soft: #e6f1f9;

    /* --- toner (dávka 1: hladiny a spotřeba v detailu tiskárny) ------------
       Jediné místo v aplikaci, kde barva není sémantika, ale sám údaj:
       azurová křivka MUSÍ být azurová, jinak graf lže. Přesto to patří do
       tokenu — ve tmě se černý toner musí rozsvítit, jinak jeho čára splyne
       s podkladem, a žlutá se naopak musí ztlumit, aby se dala číst. */
    --pp-toner-black: #2f3a4d;
    --pp-toner-cyan: #0e8fc4;
    --pp-toner-magenta: #bd3b86;
    --pp-toner-yellow: #a97b06;

    /* Text na plné barevné ploše (odznak, tlačítko). Ve světle jsou plné
       barvy dost tmavé na bílý text; ve tmě jsou to světlé pastely, takže
       se text obrací. Bez tohohle tokenu vychází „oranžová na oranžové". */
    --pp-on-solid: #ffffff;

    /* --- typografie -------------------------------------------------------- */
    --pp-font-sans: 'Nunito Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
                    'Helvetica Neue', Arial, sans-serif;
    --pp-font-mono: 'JetBrains Mono', Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
    /* Škála povyrostla v 0.9.5 zhruba o 7 % (základ 14 → 15 px) na podnět
       zadavatele: na 1440p monitoru bylo písmo zbytečně drobné. Posunuly se
       VŠECHNY stupně naráz, aby zůstaly poměry mezi nimi — kdyby povyrostl
       jen základ, splynul by s `--pp-text-md` a škála by ztratila stupeň. */
    --pp-text-xs: 0.75rem;
    --pp-text-sm: 0.8125rem;
    --pp-text-base: 0.9375rem;
    --pp-text-md: 1rem;
    --pp-text-lg: 1.125rem;
    --pp-text-xl: 1.4375rem;
    --pp-text-2xl: 1.875rem;
    --pp-text-3xl: 2.375rem;
    --pp-lh-tight: 1.2;
    --pp-lh-base: 1.45;
    --pp-lh-loose: 1.6;
    --pp-weight-normal: 400;
    --pp-weight-medium: 500;
    --pp-weight-semibold: 600;
    --pp-weight-bold: 700;
    --pp-weight-black: 800;
    --pp-tracking-caps: 0.06em;

    /* --- rozteče (DNA §6: hustota je řízená, ne náhodná) -------------------- */
    --sp-0: 0;
    --sp-1: 0.25rem;
    --sp-2: 0.5rem;
    --sp-3: 0.75rem;
    --sp-4: 1rem;
    --sp-5: 1.25rem;
    --sp-6: 1.5rem;
    --sp-7: 2rem;
    --sp-8: 3rem;

    /* --- poloměry (DNA §4: 6–14 px podle velikosti prvku) ------------------- */
    --pp-radius-sm: 6px;
    --pp-radius-md: 8px;
    --pp-radius-lg: 12px;
    --pp-radius-xl: 14px;
    --pp-radius-pill: 100rem;

    /* --- stíny (měkké, laděné do chladu; DNA §4: bez „plovoucího" přehánění) */
    --pp-shadow-xs: 0 1px 2px rgba(16, 26, 40, .05);
    --pp-shadow-sm: 0 1px 2px rgba(16, 26, 40, .05), 0 4px 10px -4px rgba(16, 26, 40, .08);
    --pp-shadow-md: 0 2px 6px -2px rgba(16, 26, 40, .08), 0 12px 26px -10px rgba(16, 26, 40, .16);
    --pp-shadow-lg: 0 24px 48px -18px rgba(16, 26, 40, .28);
    --pp-ring: 0 0 0 3px rgba(var(--pp-brand-rgb), .18);

    /* --- vrstvení a hloubka (DNA §4) --------------------------------------- */
    --pp-hero: linear-gradient(135deg, #f7f9fd 0%, #eaf0f9 45%, #e4ecf7 100%);
    --pp-hero-line: rgba(var(--pp-accent-rgb), .22);
    --pp-rail: linear-gradient(180deg, #14203a 0%, #101a2e 55%, #0d1626 100%);

    /* =======================================================================
       Most do Tableru — od téhle čáry níž se jen přepisují jeho proměnné.
       ======================================================================= */
    --tblr-font-sans-serif: var(--pp-font-sans);
    --tblr-font-monospace: var(--pp-font-mono);
    --tblr-body-font-family: var(--pp-font-sans);
    --tblr-body-font-size: var(--pp-text-base);
    --tblr-body-line-height: var(--pp-lh-base);

    --tblr-body-bg: var(--pp-bg);
    --tblr-body-bg-rgb: 238, 242, 248;
    --tblr-body-color: var(--pp-ink);
    --tblr-body-color-rgb: 16, 26, 40;
    --tblr-secondary-color: var(--pp-ink-2);
    --tblr-secondary-color-rgb: 69, 84, 107;
    --tblr-tertiary-color: var(--pp-ink-3);
    --tblr-muted: var(--pp-ink-3);
    --tblr-muted-rgb: 116, 131, 154;

    --tblr-bg-surface: var(--pp-surface);
    --tblr-bg-surface-primary: var(--pp-surface);
    --tblr-bg-surface-secondary: var(--pp-surface-2);
    --tblr-bg-surface-tertiary: var(--pp-surface-2);
    --tblr-bg-forms: var(--pp-surface);
    --tblr-secondary-bg: var(--pp-surface-3);
    --tblr-tertiary-bg: var(--pp-surface-2);

    --tblr-border-color: var(--pp-line);
    --tblr-border-color-translucent: rgba(16, 26, 40, .08);
    --tblr-border-radius: var(--pp-radius-md);
    --tblr-border-radius-sm: var(--pp-radius-sm);
    --tblr-border-radius-lg: var(--pp-radius-lg);
    --tblr-border-radius-xl: var(--pp-radius-xl);

    --tblr-primary: var(--pp-brand);
    --tblr-primary-rgb: var(--pp-brand-rgb);
    --tblr-primary-fg: var(--pp-brand-on);
    --tblr-primary-darken: var(--pp-brand-strong);
    --tblr-primary-lt: var(--pp-brand-soft);
    --tblr-link-color: #c02f2f;
    --tblr-link-color-rgb: 192, 47, 47;
    --tblr-link-hover-color: #982323;
    --tblr-link-hover-color-rgb: 152, 35, 35;
    --tblr-active-bg: rgba(var(--pp-brand-rgb), .08);
    --tblr-active-bg-subtle: rgba(var(--pp-brand-rgb), .08);
    --tblr-focus-ring-color: rgba(var(--pp-brand-rgb), .2);

    /* Barevné škály. Vždy trojice `--tblr-X`, `--tblr-X-rgb` a `--tblr-X-lt`:
       `.text-X` čte první, `.bg-X` výhradně `-rgb` a `.bg-X-lt` obě. Kdyby se
       přepsala jen jedna z nich, měl by odznak jednu barvu textu a druhou
       barvu pozadí. `-fg` je text na plné ploše. */
    --tblr-green: var(--pp-success);
    --tblr-green-rgb: var(--pp-success-rgb);
    --tblr-green-lt: var(--pp-success-soft);
    --tblr-green-fg: var(--pp-on-solid);
    --tblr-success: var(--pp-success);
    --tblr-success-rgb: var(--pp-success-rgb);
    --tblr-success-lt: var(--pp-success-soft);
    --tblr-success-fg: var(--pp-on-solid);
    --tblr-yellow: var(--pp-warning);
    --tblr-yellow-rgb: var(--pp-warning-rgb);
    --tblr-yellow-lt: var(--pp-warning-soft);
    --tblr-yellow-fg: var(--pp-on-solid);
    --tblr-warning: var(--pp-warning);
    --tblr-warning-rgb: var(--pp-warning-rgb);
    --tblr-warning-lt: var(--pp-warning-soft);
    --tblr-warning-fg: var(--pp-on-solid);
    --tblr-orange: var(--pp-orange);
    --tblr-orange-rgb: var(--pp-orange-rgb);
    --tblr-orange-lt: var(--pp-orange-soft);
    --tblr-orange-fg: var(--pp-on-solid);
    --tblr-red: var(--pp-danger);
    --tblr-red-rgb: var(--pp-danger-rgb);
    --tblr-red-lt: var(--pp-danger-soft);
    --tblr-red-fg: var(--pp-on-solid);
    --tblr-danger: var(--pp-danger);
    --tblr-danger-rgb: var(--pp-danger-rgb);
    --tblr-danger-lt: var(--pp-danger-soft);
    --tblr-danger-fg: var(--pp-on-solid);
    --tblr-blue: var(--pp-info);
    --tblr-blue-rgb: var(--pp-info-rgb);
    --tblr-blue-lt: var(--pp-info-soft);
    --tblr-blue-fg: var(--pp-on-solid);
    --tblr-info: var(--pp-info);
    --tblr-info-rgb: var(--pp-info-rgb);
    --tblr-info-lt: var(--pp-info-soft);
    --tblr-info-fg: var(--pp-on-solid);
    --tblr-azure: var(--pp-azure);
    --tblr-azure-rgb: var(--pp-azure-rgb);
    --tblr-azure-lt: var(--pp-azure-soft);
    --tblr-azure-fg: var(--pp-on-solid);
    --tblr-teal: var(--pp-accent);
    --tblr-teal-rgb: var(--pp-accent-rgb);
    --tblr-teal-lt: var(--pp-accent-soft);
    --tblr-teal-fg: var(--pp-on-solid);
    --tblr-secondary: var(--pp-neutral);
    --tblr-secondary-rgb: var(--pp-neutral-rgb);
    --tblr-secondary-lt: var(--pp-neutral-soft);
    --tblr-secondary-fg: var(--pp-on-solid);

    --tblr-shadow: var(--pp-shadow-xs);
    --tblr-shadow-card: var(--pp-shadow-sm);
    --tblr-shadow-card-hover: var(--pp-shadow-md);
    --tblr-shadow-input: none;
    --tblr-shadow-dropdown: var(--pp-shadow-md);
}

/* ===========================================================================
   2. TOKENY — TMAVÉ TÉMA
   ---------------------------------------------------------------------------
   Navržené samostatně, ne převrácené (DNA §2). Podklad je hluboká chladná
   modrošedá, karty o krok výš, linky tlumené — hloubka se dělá odstupem ploch,
   ne rámečkem. Značková červená se rozsvěcí (na tmavém podkladu by #d63939
   ztmavla pod čitelnou mez) a modrozelený akcent nabírá sytost, protože DNA §2
   ho v tmavém režimu vyloženě chce.

   Selektor platí i pro postranní panel, který má `data-bs-theme="dark"`
   natvrdo — díky tomu je rail tmavý i ve světlém tématu, což je záměr.
   =========================================================================== */
[data-bs-theme=dark] {
    color-scheme: dark;

    --pp-bg: #0b1220;
    --pp-surface: #141d2d;
    --pp-surface-2: #1b2637;
    --pp-surface-3: #0f1826;
    --pp-ink: #e8eef8;
    --pp-ink-2: #aab8cc;
    --pp-ink-3: #7d8ca3;
    --pp-line: #24314a;
    --pp-line-strong: #35486a;

    --pp-brand: #f07070;
    --pp-brand-rgb: 240, 112, 112;
    --pp-brand-strong: #f79191;
    --pp-brand-soft: #33202a;
    --pp-brand-on: #1a0d0d;
    --pp-accent: #3ec9c0;
    --pp-accent-rgb: 62, 201, 192;
    --pp-accent-soft: #13333a;

    --pp-success: #4cc98a;
    --pp-success-rgb: 76, 201, 138;
    --pp-success-soft: #12321f;
    --pp-warning: #e8b04b;
    --pp-warning-rgb: 232, 176, 75;
    --pp-warning-soft: #35280f;
    --pp-danger: #f07070;
    --pp-danger-rgb: 240, 112, 112;
    --pp-danger-soft: #35191d;
    --pp-info: #6ba6f0;
    --pp-info-rgb: 107, 166, 240;
    --pp-info-soft: #142337;
    --pp-neutral: #93a3b8;
    --pp-neutral-rgb: 147, 163, 184;
    --pp-neutral-soft: #1d2739;
    --pp-orange: #e59248;
    --pp-orange-rgb: 229, 146, 72;
    --pp-orange-soft: #35240f;
    --pp-azure: #62a9dd;
    --pp-azure-rgb: 98, 169, 221;
    --pp-azure-soft: #13273a;

    /* Toner ve tmě: černá se rozsvěcí do studené šedomodré (černá čára na
       #0b1220 není čára), žlutá se ztlumí, aby nepálila. */
    --pp-toner-black: #a8b8cf;
    --pp-toner-cyan: #55c3ea;
    --pp-toner-magenta: #e97cb8;
    --pp-toner-yellow: #dcae44;

    /* Plné barvy jsou ve tmě světlé pastely — text na nich musí být tmavý. */
    --pp-on-solid: #0b1220;

    --pp-shadow-xs: 0 1px 2px rgba(0, 0, 0, .45);
    --pp-shadow-sm: 0 1px 2px rgba(0, 0, 0, .45), 0 6px 14px -8px rgba(0, 0, 0, .6);
    --pp-shadow-md: 0 4px 10px -4px rgba(0, 0, 0, .55), 0 18px 32px -16px rgba(0, 0, 0, .7);
    --pp-shadow-lg: 0 28px 56px -20px rgba(0, 0, 0, .8);
    --pp-ring: 0 0 0 3px rgba(var(--pp-brand-rgb), .28);

    --pp-hero: linear-gradient(135deg, #16223a 0%, #111b2c 48%, #0c1421 100%);
    --pp-hero-line: rgba(var(--pp-accent-rgb), .3);
    --pp-rail: linear-gradient(180deg, #101a2c 0%, #0d1524 60%, #0a111d 100%);

    /* --- most do Tableru --------------------------------------------------- */
    --tblr-body-bg: var(--pp-bg);
    --tblr-body-bg-rgb: 11, 18, 32;
    --tblr-body-color: var(--pp-ink);
    --tblr-body-color-rgb: 232, 238, 248;
    --tblr-secondary-color: var(--pp-ink-2);
    --tblr-secondary-color-rgb: 170, 184, 204;
    --tblr-tertiary-color: var(--pp-ink-3);
    --tblr-muted: var(--pp-ink-3);
    --tblr-muted-rgb: 125, 140, 163;
    --tblr-emphasis-color: #ffffff;

    --tblr-bg-surface: var(--pp-surface);
    --tblr-bg-surface-primary: var(--pp-surface);
    --tblr-bg-surface-secondary: var(--pp-surface-2);
    --tblr-bg-surface-tertiary: var(--pp-surface-2);
    --tblr-bg-forms: var(--pp-surface-3);
    --tblr-secondary-bg: var(--pp-surface-2);
    --tblr-tertiary-bg: var(--pp-surface-3);

    --tblr-border-color: var(--pp-line);
    --tblr-border-color-translucent: rgba(148, 176, 220, .14);

    --tblr-primary: var(--pp-brand);
    --tblr-primary-rgb: var(--pp-brand-rgb);
    --tblr-primary-fg: var(--pp-brand-on);
    --tblr-primary-darken: var(--pp-brand-strong);
    --tblr-primary-lt: var(--pp-brand-soft);
    --tblr-link-color: #f2938f;
    --tblr-link-color-rgb: 242, 147, 143;
    --tblr-link-hover-color: #f8b6b3;
    --tblr-link-hover-color-rgb: 248, 182, 179;
    --tblr-active-bg: rgba(var(--pp-brand-rgb), .16);
    --tblr-active-bg-subtle: rgba(var(--pp-brand-rgb), .16);
    --tblr-focus-ring-color: rgba(var(--pp-brand-rgb), .3);

    --tblr-green: var(--pp-success);
    --tblr-green-rgb: var(--pp-success-rgb);
    --tblr-green-lt: var(--pp-success-soft);
    --tblr-green-fg: var(--pp-on-solid);
    --tblr-success: var(--pp-success);
    --tblr-success-rgb: var(--pp-success-rgb);
    --tblr-success-lt: var(--pp-success-soft);
    --tblr-success-fg: var(--pp-on-solid);
    --tblr-yellow: var(--pp-warning);
    --tblr-yellow-rgb: var(--pp-warning-rgb);
    --tblr-yellow-lt: var(--pp-warning-soft);
    --tblr-yellow-fg: var(--pp-on-solid);
    --tblr-warning: var(--pp-warning);
    --tblr-warning-rgb: var(--pp-warning-rgb);
    --tblr-warning-lt: var(--pp-warning-soft);
    --tblr-warning-fg: var(--pp-on-solid);
    --tblr-orange: var(--pp-orange);
    --tblr-orange-rgb: var(--pp-orange-rgb);
    --tblr-orange-lt: var(--pp-orange-soft);
    --tblr-orange-fg: var(--pp-on-solid);
    --tblr-red: var(--pp-danger);
    --tblr-red-rgb: var(--pp-danger-rgb);
    --tblr-red-lt: var(--pp-danger-soft);
    --tblr-red-fg: var(--pp-on-solid);
    --tblr-danger: var(--pp-danger);
    --tblr-danger-rgb: var(--pp-danger-rgb);
    --tblr-danger-lt: var(--pp-danger-soft);
    --tblr-danger-fg: var(--pp-on-solid);
    --tblr-blue: var(--pp-info);
    --tblr-blue-rgb: var(--pp-info-rgb);
    --tblr-blue-lt: var(--pp-info-soft);
    --tblr-blue-fg: var(--pp-on-solid);
    --tblr-info: var(--pp-info);
    --tblr-info-rgb: var(--pp-info-rgb);
    --tblr-info-lt: var(--pp-info-soft);
    --tblr-info-fg: var(--pp-on-solid);
    --tblr-azure: var(--pp-azure);
    --tblr-azure-rgb: var(--pp-azure-rgb);
    --tblr-azure-lt: var(--pp-azure-soft);
    --tblr-azure-fg: var(--pp-on-solid);
    --tblr-teal: var(--pp-accent);
    --tblr-teal-rgb: var(--pp-accent-rgb);
    --tblr-teal-lt: var(--pp-accent-soft);
    --tblr-teal-fg: var(--pp-on-solid);
    --tblr-secondary: var(--pp-neutral);
    --tblr-secondary-rgb: var(--pp-neutral-rgb);
    --tblr-secondary-lt: var(--pp-neutral-soft);
    --tblr-secondary-fg: var(--pp-on-solid);

    --tblr-shadow: var(--pp-shadow-xs);
    --tblr-shadow-card: var(--pp-shadow-sm);
    --tblr-shadow-card-hover: var(--pp-shadow-md);
    --tblr-shadow-input: none;
    --tblr-shadow-dropdown: var(--pp-shadow-md);
}

/* ===========================================================================
   3. ZÁKLAD — typografie a čísla
   =========================================================================== */
body {
    font-family: var(--pp-font-sans);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    letter-spacing: 0;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6,
.card-title, .page-title, .navbar-brand {
    font-weight: var(--pp-weight-bold);
    line-height: var(--pp-lh-tight);
    letter-spacing: -0.005em;
}

.page-title { font-size: var(--pp-text-xl); }
.card-title { font-size: var(--pp-text-md); }

.subheader,
.form-label small,
.table thead th {
    text-transform: uppercase;
    letter-spacing: var(--pp-tracking-caps);
    font-size: var(--pp-text-xs);
    font-weight: var(--pp-weight-semibold);
}

/* `.card-subtitle` je v PrintPilotu nosič CELÝCH vysvětlujících vět (modul
   print-assessment, ~110 znaků) — verzálky v 11 px z něj dělaly nejhůř
   čitelnou podobu právě toho, co DNA §1 žádá (RV-009 z revize FÁZE 2).
   Mluví proto stejnou řečí jako `.explain`, protože plní stejnou roli. */
.card-subtitle {
    text-transform: none;
    letter-spacing: 0;
    font-size: var(--pp-text-sm);
    font-weight: var(--pp-weight-normal);
    line-height: var(--pp-lh-loose);
    color: var(--pp-ink-2);
}

/* DNA §5: tabulková číslice všude, kde čísla stojí pod sebou nebo se
   porovnávají. Nunito Sans má stejně široké číslice už z výroby, tohle je
   pojistka pro případ fallbacku na systémové písmo. */
.table,
.badge,
.datagrid-content,
.progress,
.card-title,
.h1, .h2, .h3, .h4,
.num,
input[type=number],
.form-control {
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum' 1;
}

/* Mono výhradně na kódy a identifikátory (DNA §5) — sériová čísla, čísla
   dokladů, IČO. Použití: <span class="ident">RP-2026-041</span> */
code, kbd, samp, pre, .ident {
    font-family: var(--pp-font-mono);
    font-size: 0.925em;
    font-variant-numeric: tabular-nums;
}
.ident {
    letter-spacing: -0.01em;
    color: var(--pp-ink-2);
}

/* Vysvětlující věta u čísla (DNA §1). Ne popisek, ale interpretace:
   „platí o 24 dní později, než má". */
.explain {
    display: block;
    font-size: var(--pp-text-sm);
    line-height: var(--pp-lh-loose);
    color: var(--pp-ink-2);
    max-width: 46ch;
}
.explain strong { color: var(--pp-ink); font-weight: var(--pp-weight-semibold); }

/* Velké číslo v čele karty — hodnota, pak jednotka, pak teprve graf (DNA §7) */
.metric {
    display: flex;
    align-items: baseline;
    gap: var(--sp-2);
    font-size: var(--pp-text-2xl);
    font-weight: var(--pp-weight-black);
    line-height: var(--pp-lh-tight);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}
.metric-unit {
    font-size: var(--pp-text-md);
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink-3);
}

/* ===========================================================================
   4. KOMPOZICE — stránka, hlavička, postranní panel
   =========================================================================== */

/* Hlavička stránky dostává vrstvu (DNA §4: hloubka na hlavičkách a hero
   plochách, nikdy pod hustou tabulkou). */
.page-header.d-print-none {
    background: var(--pp-hero);
    border-bottom: 1px solid var(--pp-line);
    box-shadow: inset 0 -1px 0 var(--pp-hero-line);
    padding-top: var(--sp-5);
    padding-bottom: var(--sp-5);
    margin-bottom: 0;
}
.page-header .page-title + div { color: var(--pp-ink-2); }

.page-body { margin-top: var(--sp-6); }

/* Šířka obsahu (0.9.5) — DNA §6 žádá u seznamů „maximum informace na
   obrazovku", a Tablerův `.container-xl` se zastavil na 1320 px. Na monitoru
   zadavatele (2560 px) tím zůstávala ležet **tisícovka pixelů** a využito bylo
   61 % plochy včetně postranního panelu.

   Roste se po stupních, ne plynule. Plynulá šířka (`vw`, `clamp`) vypadá
   v CSS elegantněji, ale při běžných šířkách 1440–1680 px by obsah zúžila pod
   dnešních 1320 — a to je zhoršení pro většinu, aby se pomohlo jednomu
   monitoru. Stupně mění jen to, co měnit mají: pod 1400 px se nesahá vůbec.

   Strop je vědomě NIŽŠÍ než dostupná plocha. Obsah přes celou šířku by sice
   „nic neplýtval", ale tabulka roztažená na 2320 px má mezi sloupci tolik
   místa, že se řádek přestane číst jako řádek — a to je proti hustotě, kvůli
   které se sem šířka přidává. Na 2560 px vychází 1960 + 240 panel = 86 %.

   Platí pro VŠECHNY tři `.container-xl` v layoutu (hlavička, tělo, patička)
   — kdyby se lišily, rozešly by se svislé osy stránky. */
@media (min-width: 1400px) {
    .page-wrapper .container-xl,
    .page-header .container-xl { max-width: 1560px; }
}
@media (min-width: 1920px) {
    .page-wrapper .container-xl,
    .page-header .container-xl { max-width: 1800px; }
}
@media (min-width: 2400px) {
    .page-wrapper .container-xl,
    .page-header .container-xl { max-width: 1960px; }
}

/* Postranní panel — značková „kolej". Je tmavý v obou tématech (má
   `data-bs-theme="dark"` v šabloně), ale ve tmě sedne o tón níž, aby se
   neodděloval od zbytku plochy. */
.navbar-vertical.navbar-expand-lg {
    background: var(--pp-rail);
    border-right: 1px solid rgba(148, 176, 220, .1);
}
.navbar-vertical .nav-link {
    border-radius: var(--pp-radius-sm);
    margin: 1px var(--sp-2);
    padding-top: 0.4rem;
    padding-bottom: 0.4rem;
    font-weight: var(--pp-weight-medium);
    transition: background-color .15s ease, color .15s ease;
}
.navbar-vertical .nav-item.active > .nav-link {
    color: #fff;
    background: rgba(240, 112, 112, .16);
    box-shadow: inset 3px 0 0 #f07070;
}
.navbar-vertical .nav-link:hover {
    color: #ffe0e0;
    background: rgba(255, 255, 255, .05);
}
.navbar-vertical .nav-link-icon { opacity: .85; }

/* Horní lišta — plochá, oddělená linkou, ne stínem. */
.navbar:not(.navbar-vertical) {
    background: var(--pp-surface);
    border-bottom: 1px solid var(--pp-line);
}

/* ===========================================================================
   5. KOMPONENTY — karty, tlačítka, odznaky, formuláře
   =========================================================================== */

/* Karta drží plochu barvou a stínem, ne rámečkem (DNA §4). Ve tmě rámeček
   zůstává jako vlásková linka — bez ní by karty splynuly s podkladem. */
.card {
    --tblr-card-border-color: transparent;
    --tblr-card-border-radius: var(--pp-radius-lg);
    --tblr-card-bg: var(--pp-surface);
    --tblr-card-cap-bg: transparent;
    box-shadow: var(--pp-shadow-sm);
}
[data-bs-theme=dark] .card {
    --tblr-card-border-color: var(--pp-line);
}
.card-header {
    border-bottom: 1px solid var(--pp-line);
    padding-top: var(--sp-4);
    padding-bottom: var(--sp-4);
}
.card-footer {
    background: var(--pp-surface-2);
    border-top: 1px solid var(--pp-line);
}
.card.card-lift:hover { box-shadow: var(--pp-shadow-md); }

/* Zapuštěná plocha uvnitř karty — místo dalšího rámečku. */
.pp-well {
    background: var(--pp-surface-3);
    border-radius: var(--pp-radius-md);
    padding: var(--sp-3) var(--sp-4);
}

.btn {
    border-radius: var(--pp-radius-md);
    font-weight: var(--pp-weight-semibold);
    letter-spacing: 0;
}
.btn-primary {
    --tblr-btn-color: var(--pp-brand-on);
    --tblr-btn-bg: var(--pp-brand);
    --tblr-btn-border-color: var(--pp-brand);
    --tblr-btn-hover-color: var(--pp-brand-on);
    --tblr-btn-hover-bg: var(--pp-brand-strong);
    --tblr-btn-hover-border-color: var(--pp-brand-strong);
    --tblr-btn-active-color: var(--pp-brand-on);
    --tblr-btn-active-bg: var(--pp-brand-strong);
    --tblr-btn-active-border-color: var(--pp-brand-strong);
    box-shadow: var(--pp-shadow-xs);
}
.btn-outline-primary {
    --tblr-btn-color: var(--pp-brand);
    --tblr-btn-border-color: var(--pp-brand);
    --tblr-btn-hover-color: var(--pp-brand-on);
    --tblr-btn-hover-bg: var(--pp-brand);
    --tblr-btn-hover-border-color: var(--pp-brand);
    --tblr-btn-active-bg: var(--pp-brand);
    --tblr-btn-active-border-color: var(--pp-brand);
}
.btn:focus-visible,
.btn-check:focus + .btn { box-shadow: var(--pp-ring); }

/* Tabler dává `.btn-icon` jen nulový vodorovný padding, takže z tlačítka
   vyjde svislá pilulka široká přesně jako ikona. Ikonové tlačítko má být
   čtvercové — jinak se v liště ani v tabulce nedá trefit. */
.btn-icon {
    width: 2.25rem;
    min-width: 2.25rem;
    padding-left: 0;
    padding-right: 0;
}
.btn-icon.btn-sm {
    width: 1.85rem;
    min-width: 1.85rem;
}

/* Odznaky — podbarvená ploška, ne obrys. */
.badge {
    --tblr-badge-border-radius: var(--pp-radius-sm);
    font-weight: var(--pp-weight-semibold);
    letter-spacing: 0.01em;
}

/* Formuláře */
.form-control,
.form-select {
    border-radius: var(--pp-radius-md);
    border-color: var(--pp-line-strong);
    background-color: var(--tblr-bg-forms);
    transition: border-color .15s ease, box-shadow .15s ease;
}
.form-control::placeholder { color: var(--pp-ink-3); }
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
    border-color: var(--pp-brand);
    box-shadow: var(--pp-ring);
}
.form-label {
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink-2);
    margin-bottom: var(--sp-1);
}
.form-hint { color: var(--pp-ink-3); font-size: var(--pp-text-sm); }

.dropdown-menu {
    border-radius: var(--pp-radius-lg);
    border-color: var(--pp-line);
    box-shadow: var(--pp-shadow-md);
    padding: var(--sp-1);
}
.dropdown-item { border-radius: var(--pp-radius-sm); }

.alert {
    border-radius: var(--pp-radius-lg);
    border: 0;
    box-shadow: inset 0 0 0 1px var(--pp-line);
}

.progress {
    background: var(--pp-surface-3);
    border-radius: var(--pp-radius-pill);
}
.progress-bar { border-radius: var(--pp-radius-pill); }

/* ===========================================================================
   6. TABULKY A HUSTOTA (DNA §6)
   ---------------------------------------------------------------------------
   Výchozí tabulka je čitelná, `.table-dense` je hutná varianta pro seznamy,
   registry a fronty — maximum informace na obrazovku.
   =========================================================================== */
.table {
    --tblr-table-striped-bg: var(--pp-surface-2);
    --tblr-table-hover-bg: rgba(var(--pp-accent-rgb), .07);
    --tblr-table-border-color: var(--pp-line);
}
.table thead th {
    background: var(--pp-surface-2);
    color: var(--pp-ink-3);
    border-bottom: 1px solid var(--pp-line);
    white-space: nowrap;
}
.table > :not(caption) > * > * { padding: 0.55rem 0.75rem; }
/* Tablerova hutná varianta `.table-sm > :not(caption) > * > *` má PŘESNĚ stejnou
   specificitu (0,1,1) jako řádek výš, ale tenhle stylopis se načítá později —
   bez následujícího řádku by `.table-sm` ve 13 šablonách přestala cokoli dělat
   a padding v ní vyskočil 2,2× svisle a 3× vodorovně (RV-008 z revize FÁZE 2).
   Sestavení Tableru nemá `--tblr-table-cell-padding-*` (grep vrací 0 výskytů),
   takže se hodnota musí zopakovat, ne podstrčit proměnnou.
   Vztah tříd: `.table-sm` je Tablerova hutná varianta, `.table-dense` níž je
   naše pro seznamy a registry (menší písmo, odznaky i tlačítka). Třetí se
   nezavádí. */
.table-sm > :not(caption) > * > * { padding: 0.25rem 0.25rem; }
.table tbody tr { transition: background-color .12s ease; }

.table-dense {
    font-size: var(--pp-text-sm);
    line-height: 1.35;
}
.table-dense > :not(caption) > * > * { padding: 0.3rem 0.6rem; }
.table-dense thead th { font-size: var(--pp-text-xs); }
.table-dense .badge { padding: 0.15rem 0.4rem; font-size: var(--pp-text-xs); }
.table-dense .btn-sm { padding: 0.1rem 0.4rem; }

/* Číselné sloupce zarovnat doprava — jinak tabulková číslice nemá co srovnávat. */
.table .num,
.table .text-end { font-variant-numeric: tabular-nums; }

/* Karta s tabulkou: tabulka jde od kraje ke kraji a nese vlastní zaoblení. */
.card > .table-responsive > .table,
.card > .table { margin-bottom: 0; }

/* ===========================================================================
   7. STAVY — brána cyklu, doklady, schvalování marží
   ---------------------------------------------------------------------------
   Sémantické tokeny mají hodnotu v OBOU tématech (dědí se z §1/§2), takže
   stav se nikdy nekreslí natvrdo zapsanou barvou. Použití v šabloně:
       <span class="badge state-gate-ok">Brána otevřená</span>
       <span class="badge state-doc-paid">Zaplaceno</span>
       <span class="badge state-appr-pending">Čeká na schválení</span>
   =========================================================================== */
:root,
[data-bs-theme=light],
[data-bs-theme=dark] {
    /* brána fakturačního cyklu 🟢/🟠/🔴 */
    --pp-gate-ok: var(--pp-success);
    --pp-gate-ok-bg: var(--pp-success-soft);
    --pp-gate-watch: var(--pp-warning);
    --pp-gate-watch-bg: var(--pp-warning-soft);
    --pp-gate-block: var(--pp-danger);
    --pp-gate-block-bg: var(--pp-danger-soft);

    /* stavy dokladu */
    --pp-doc-draft: var(--pp-neutral);
    --pp-doc-draft-bg: var(--pp-neutral-soft);
    --pp-doc-ready: var(--pp-info);
    --pp-doc-ready-bg: var(--pp-info-soft);
    --pp-doc-paid: var(--pp-success);
    --pp-doc-paid-bg: var(--pp-success-soft);
    --pp-doc-exported: var(--pp-accent);
    --pp-doc-exported-bg: var(--pp-accent-soft);
    --pp-doc-cancelled: var(--pp-danger);
    --pp-doc-cancelled-bg: var(--pp-danger-soft);

    /* segmentace zákazníka — stupeň péče 1/2/3 (dávka 3, §4.10).
       Není to stav, ale zařazení, takže rodiny jdou po SESTUPNÉM důrazu
       (informace → akcent → neutrál), ne po škále dobře/špatně. Barva sama
       nic neříká; odznak vždy nese i slovo („Kategorie 1").

       Stupeň 1 mířil do značky, jenže `--pp-brand` je v tmavém tématu doslova
       týž hex jako `--pp-danger` (#f07070) — z „1. kategorie" se tak stal
       odznak nerozeznatelný od poruchy, tedy přesně to, čemu se tahle rodina
       chtěla vyhnout (nález RV-513). Rodina proto jde do modré `--pp-info`,
       která se s chybou nepotká ani v jednom tématu; hlídá to test nad OBĚMA
       bloky proměnných. */
    --pp-cat-1: var(--pp-info);
    --pp-cat-1-bg: var(--pp-info-soft);
    --pp-cat-2: var(--pp-accent);
    --pp-cat-2-bg: var(--pp-accent-soft);
    --pp-cat-3: var(--pp-neutral);
    --pp-cat-3-bg: var(--pp-neutral-soft);

    /* e-mailová pipeline odečtů — osud jednoho e-mailu (dávka 5, §4.11).
       Sedm stavů, ale PĚT barev, a je to rozhodnutí, ne úspora:

       • `needs_review` a `needs_manual_entry` jsou pro člověka TÝŽ úkol
         („otevři to a rozhodni"), liší se jen tím, co parser stihl přečíst.
         Barvy by ten rozdíl stejně neunesly: `--pp-warning` (#e8b04b) a
         `--pp-orange` (#e59248) jsou v tmavém tématu prakticky k nerozeznání,
         takže by z rozdílu zbyl jen dojem barvy navíc — přesně past RV-513.
         Rozdíl nese slovo a ikona;
       • `spam` a `ignored` jsou obojí tichý odpad, jen z jiného důvodu
         (junk × odprodaný stroj na dožití). Taky týž neutrál a taky slovo;
       • `auto_approved` a `approved_by_operator` naopak dvě barvy MAJÍ, i když
         obojí končí zapsaným odečtem: „stroj to udělal sám" a „rozhodl člověk"
         se rozeznat musí (§4.4 — automatický přechod není rozhodnutí). Proto
         akcent × úspěch, tedy tentýž pár jako „exportováno" × „zaplaceno". */
    --pp-mail-auto: var(--pp-accent);
    --pp-mail-auto-bg: var(--pp-accent-soft);
    --pp-mail-done: var(--pp-success);
    --pp-mail-done-bg: var(--pp-success-soft);
    --pp-mail-wait: var(--pp-warning);
    --pp-mail-wait-bg: var(--pp-warning-soft);
    --pp-mail-rejected: var(--pp-danger);
    --pp-mail-rejected-bg: var(--pp-danger-soft);
    --pp-mail-off: var(--pp-neutral);
    --pp-mail-off-bg: var(--pp-neutral-soft);

    /* sklad — čtyři rodiny, čtyři různé otázky (dávka 6, §4.12).
       Do téhle dávky měl celý modul na stavy JEDNU třídu (`bg-secondary-lt`),
       takže „objednáno", „dodáno" i „zrušeno" byly týž šedý odznak — a řádek
       pod minimem se poznal podle `bg-warning-lt` přes CELÝ řádek, tedy podle
       barvy plochy, ne stavu.

       1) `--pp-stock-*` — zdraví jedné položky na jednom skladě. Čtvrtý člen
          `nomin` není odstín navíc: `isBelowMin()` vrací false, když minimum
          není nastavené, takže položka BEZ pravidla vypadá úplně stejně jako
          položka v pořádku a upozornění na ni nikdy nepřijde. To je opačná
          zpráva, ne slabší — proto vlastní barva (neutrál) a vlastní slovo. */
    --pp-stock-ok: var(--pp-success);
    --pp-stock-ok-bg: var(--pp-success-soft);
    --pp-stock-low: var(--pp-warning);
    --pp-stock-low-bg: var(--pp-warning-soft);
    --pp-stock-out: var(--pp-danger);
    --pp-stock-out-bg: var(--pp-danger-soft);
    --pp-stock-nomin: var(--pp-neutral);
    --pp-stock-nomin-bg: var(--pp-neutral-soft);

    /* 2) `--pp-move-*` — co řádek knihy udělal s množstvím. Výdej ZÁMĚRNĚ není
          červený: vydat toner technikovi je práce, ne porucha, a červená by
          z běžného provozu udělala poplach (táž past jako RV-514). Červená
          v téhle rodině není vůbec. Převod je neutrál, protože nemění, KOLIK
          toho je — jen kde to leží. Jediná výstraha patří korekci: to je
          jediný řádek knihy BEZ fyzického pohybu, přepis stavu na zjištěný,
          tedy doklad o tom, že papír neseděl. */
    --pp-move-in: var(--pp-success);
    --pp-move-in-bg: var(--pp-success-soft);
    --pp-move-out: var(--pp-info);
    --pp-move-out-bg: var(--pp-info-soft);
    --pp-move-shift: var(--pp-neutral);
    --pp-move-shift-bg: var(--pp-neutral-soft);
    --pp-move-fix: var(--pp-warning);
    --pp-move-fix-bg: var(--pp-warning-soft);

    /* 3) `--pp-goods-*` — osud jednoho kusu zboží-tiskárny. Pět stavů, pět
          barev, protože každý z nich znamená jiné peníze: na skladě = zásoba,
          prodáno = tržba, aktivováno = majetek v pronájmu (týž akcent jako
          „exportováno", tedy „odešlo to jinam, ale pořád je to naše"),
          spotřebováno = interní použití, vyřazeno = hodnota zmizela bez
          protihodnoty. Jen to poslední je ztráta, a proto jediné v červené. */
    --pp-goods-stock: var(--pp-success);
    --pp-goods-stock-bg: var(--pp-success-soft);
    --pp-goods-sold: var(--pp-info);
    --pp-goods-sold-bg: var(--pp-info-soft);
    --pp-goods-asset: var(--pp-accent);
    --pp-goods-asset-bg: var(--pp-accent-soft);
    --pp-goods-used: var(--pp-neutral);
    --pp-goods-used-bg: var(--pp-neutral-soft);
    --pp-goods-scrap: var(--pp-danger);
    --pp-goods-scrap-bg: var(--pp-danger-soft);

    /* 4) `--pp-po-*` — stav objednávky u dodavatele. Vlastní rodina, ne
          půjčené `--pp-doc-*`: to jsou stavy DOKLADU, který vystavujeme my,
          a půjčovat je na cizí objednávku je přesně nález RV-514. Škála jde
          po cestě zboží (nikdo o ní neví → objednáno → něco dorazilo → všechno
          dorazilo) a `cancelled` z ní vypadává stranou. */
    --pp-po-draft: var(--pp-neutral);
    --pp-po-draft-bg: var(--pp-neutral-soft);
    --pp-po-ordered: var(--pp-info);
    --pp-po-ordered-bg: var(--pp-info-soft);
    --pp-po-partial: var(--pp-warning);
    --pp-po-partial-bg: var(--pp-warning-soft);
    --pp-po-received: var(--pp-success);
    --pp-po-received-bg: var(--pp-success-soft);
    --pp-po-cancelled: var(--pp-danger);
    --pp-po-cancelled-bg: var(--pp-danger-soft);

    /* Print Assessment — dvě rodiny, dvě různé otázky (dávka 7, §4.14).

       1) `--pp-est-*` — ODKUD je odhad objemu, ze kterého se počítají
          všechny peníze v návrhu. Čtyři členy = čtyři metody `VolumeEstimator`
          (faktury → odečty → jeden odečet a stáří → nic); `confidence` (kolik
          faktur, kolik odečtů) patří do VĚTY u řádku, ne do barvy — od FÁZE 10,
          kdy se ukázalo, že tečka klíčovaná spolehlivostí a vzorník klíčovaný
          metodou slibují každý něco jiného (nález `RV-911`).
          `VolumeEstimator` vrací vedle čísel i metodu
          a `confidence`, jenže do téhle dávky se to na obrazovce neobjevilo
          nikde: „úspora 12 400 Kč" spočítaná ze tří faktur vypadala úplně
          stejně jako táž částka odvozená z JEDNOHO odečtu a stáří stroje.
          Rodina má čtyři členy, protože poslední z nich není slabší odhad, ale
          ŽÁDNÝ: bez faktury i bez odečtu vrací kalkulačka nulu a ta se pak
          sčítá do celkového nákladu jako fakt. Chybějící vstup se tu tedy
          nechová jako chybějící — proto červená, ne šedá (týž tvar jako
          `--pp-stock-nomin` v §4.12, jen s opačným závěrem). */
    --pp-est-high: var(--pp-success);
    --pp-est-high-bg: var(--pp-success-soft);
    --pp-est-medium: var(--pp-info);
    --pp-est-medium-bg: var(--pp-info-soft);
    --pp-est-low: var(--pp-warning);
    --pp-est-low-bg: var(--pp-warning-soft);
    --pp-est-none: var(--pp-danger);
    --pp-est-none-bg: var(--pp-danger-soft);

    /* 2) `--pp-acq-*` — jak zákazník stroj pořídil. Není to stav, ale
          ZAŘAZENÍ (jako `--pp-cat-*` v §4.10), a rozhoduje o tom, KTERÝM
          vzorcem se počítá měsíční náklad: pronájem a servisní smlouva jedou
          přes nájem + klik z faktury, vlastní stroj přes amortizaci + tonery.
          Škála proto nejde po dobře/špatně, ale po sestupné vazbě na
          dodavatele (akcent → azurová → neutrál). */
    --pp-acq-rental: var(--pp-accent);
    --pp-acq-rental-bg: var(--pp-accent-soft);
    --pp-acq-service: var(--pp-azure);
    --pp-acq-service-bg: var(--pp-azure-soft);
    --pp-acq-own: var(--pp-neutral);
    --pp-acq-own-bg: var(--pp-neutral-soft);

    /* 3) `--pp-pa-*` — stav SAMOTNÉ ANALÝZY (dávka 7, část 2, §4.15). Vlastní
          rodina, ne půjčené `--pp-doc-*`: to jsou stavy dokladu, který
          vystavujeme a účtujeme, kdežto analýza je podklad, ze kterého teprve
          vznikne nabídka — půjčit si na ni doklad je přesně nález RV-514.
          Škála jde po cestě ven z domu (rozpracováno → hotovo → odešlo
          zákazníkovi), takže poslední člen nese týž akcent jako „exportováno"
          a „aktivováno" jinde v systému: je to pořád naše, ale už to není
          jen u nás. Zapisuje se dnes JEN `draft` (viz `RV-1004`), a i tak má
          rodina všechny tři členy — mapa musí umět nakreslit každý stav, který
          model připouští, jinak výpis spadne na tom, co ještě nepřišlo. */
    --pp-pa-draft: var(--pp-neutral);
    --pp-pa-draft-bg: var(--pp-neutral-soft);
    --pp-pa-done: var(--pp-info);
    --pp-pa-done-bg: var(--pp-info-soft);
    --pp-pa-sent: var(--pp-accent);
    --pp-pa-sent-bg: var(--pp-accent-soft);

    /* Reporty a administrace — tři rodiny, tři různé otázky (dávka 8, §4.16).

       1) `--pp-cov-*` — pokrytí toneru proti PRAHU. Není to stupnice krásy:
          nad 5 % je provoz znatelně dražší na toner, nad 7 % se o tom volá
          zákazníkovi. Prahy do téhle dávky žily v `text-warning`/`text-danger`
          přímo v šabloně a v legendě nad tabulkou — tedy v Tablerově paletě
          a mimo graf. Čtvrtý člen `none` NENÍ nižší pokrytí, ale ŽÁDNÉ:
          `CoverageReportService` vrací výhradně stroje, které pokrytí hlásí
          (`average_coverage_percent` plní jen `StatusDumpParser`), takže stroj
          bez stavového e-mailu v reportu prostě není — a průměr flotily je
          průměr hlásících. Je to týž tvar jako `--pp-stock-nomin` v §4.12
          („nehlídá se" ≠ „je v pořádku") a `--pp-est-none` v §4.14, jen na
          třetí obrazovce: neměřeno není nula. Proto neutrál, ne zelená —
          mlčení stroje není dobrá zpráva, ale prázdné místo. */
    --pp-cov-normal: var(--pp-success);
    --pp-cov-normal-bg: var(--pp-success-soft);
    --pp-cov-notable: var(--pp-warning);
    --pp-cov-notable-bg: var(--pp-warning-soft);
    --pp-cov-critical: var(--pp-danger);
    --pp-cov-critical-bg: var(--pp-danger-soft);
    --pp-cov-none: var(--pp-neutral);
    --pp-cov-none-bg: var(--pp-neutral-soft);

    /* 2) `--pp-audit-*` — DRUH události v auditu. Modul má 71 různých akcí
          (`Audit::log('billing.document.paid', …)`) a do téhle dávky měly
          všechny jeden odznak `bg-secondary-lt`, takže „někdo se přihlásil"
          a „někdo smazal uživatele" vypadaly stejně — táž vada jako jediná
          třída na čtyři enumy skladu v §4.12. Rodina nekopíruje jmenný prostor
          akce (ten má osm předpon), ale otázku, kvůli které se do auditu
          kouká: kdo byl uvnitř (`auth`), co se změnilo na datech (`data`),
          kde tekly peníze (`money`), kdo si sáhl na práva nebo cizí identitu
          (`access`) a co se NEPOVEDLO (`fail`). Poslední člen je jediný
          v červené a je to záměr: nepovedený pokus o přihlášení a uzamčení
          účtu jsou přesně ty dva řádky, kvůli kterým se log otevírá. */
    --pp-audit-auth: var(--pp-info);
    --pp-audit-auth-bg: var(--pp-info-soft);
    --pp-audit-data: var(--pp-neutral);
    --pp-audit-data-bg: var(--pp-neutral-soft);
    --pp-audit-money: var(--pp-accent);
    --pp-audit-money-bg: var(--pp-accent-soft);
    --pp-audit-access: var(--pp-warning);
    --pp-audit-access-bg: var(--pp-warning-soft);
    --pp-audit-fail: var(--pp-danger);
    --pp-audit-fail-bg: var(--pp-danger-soft);

    /* 3) `--pp-acct-*` — stav jednoho účtu. Tři členy, protože účet má tři
          podoby a jen dvě z nich jsou v datech: `is_active` říká „smí se
          přihlásit", ale NEŘÍKÁ, jestli se někdy přihlásil. Účet, kterému
          vyprší pozvánka a nikdo si ji nevyzvedne, je tak v seznamu
          k nerozeznání od používaného — a přitom je to díra: někdo za něj
          platí a nikdo v něm nepracuje. Třetí člen (`invited`) se proto počítá
          z auditu (`auth.login`), ne ze sloupce.

          Vypnutý účet je NEUTRÁL, ne červená: deaktivovat odcházejícího
          kolegu je správný postup, ne porucha — táž věta jako „výdej není
          chyba" u `--pp-move-*` v §4.12. */
    --pp-acct-active: var(--pp-success);
    --pp-acct-active-bg: var(--pp-success-soft);
    --pp-acct-invited: var(--pp-warning);
    --pp-acct-invited-bg: var(--pp-warning-soft);
    --pp-acct-off: var(--pp-neutral);
    --pp-acct-off-bg: var(--pp-neutral-soft);

    /* schvalování marží */
    --pp-appr-pending: var(--pp-warning);
    --pp-appr-pending-bg: var(--pp-warning-soft);
    --pp-appr-approved: var(--pp-success);
    --pp-appr-approved-bg: var(--pp-success-soft);
    --pp-appr-rejected: var(--pp-danger);
    --pp-appr-rejected-bg: var(--pp-danger-soft);
    --pp-appr-none: var(--pp-neutral);
    --pp-appr-none-bg: var(--pp-neutral-soft);
}

.state-gate-ok,
.state-gate-watch,
.state-gate-block,
.state-doc-draft,
.state-doc-ready,
.state-doc-paid,
.state-doc-exported,
.state-doc-cancelled,
.state-appr-pending,
.state-appr-approved,
.state-appr-rejected,
.state-appr-none,
.state-cat-1,
.state-cat-2,
.state-cat-3,
.state-mail-auto,
.state-mail-done,
.state-mail-wait,
.state-mail-rejected,
.state-mail-off,
.state-stock-ok,
.state-stock-low,
.state-stock-out,
.state-stock-nomin,
.state-move-in,
.state-move-out,
.state-move-shift,
.state-move-fix,
.state-goods-stock,
.state-goods-sold,
.state-goods-asset,
.state-goods-used,
.state-goods-scrap,
.state-po-draft,
.state-po-ordered,
.state-po-partial,
.state-po-received,
.state-po-cancelled,
.state-est-high,
.state-est-medium,
.state-est-low,
.state-est-none,
.state-acq-rental,
.state-acq-service,
.state-acq-own,
.state-pa-draft,
.state-pa-done,
.state-pa-sent,
.state-cov-normal,
.state-cov-notable,
.state-cov-critical,
.state-cov-none,
.state-audit-auth,
.state-audit-data,
.state-audit-money,
.state-audit-access,
.state-audit-fail,
.state-acct-active,
.state-acct-invited,
.state-acct-off {
    background-color: var(--pp-state-bg) !important;
    color: var(--pp-state-fg) !important;
    border: 0;
}

.state-gate-ok        { --pp-state-fg: var(--pp-gate-ok);        --pp-state-bg: var(--pp-gate-ok-bg); }
.state-gate-watch     { --pp-state-fg: var(--pp-gate-watch);     --pp-state-bg: var(--pp-gate-watch-bg); }
.state-gate-block     { --pp-state-fg: var(--pp-gate-block);     --pp-state-bg: var(--pp-gate-block-bg); }
.state-doc-draft      { --pp-state-fg: var(--pp-doc-draft);      --pp-state-bg: var(--pp-doc-draft-bg); }
.state-doc-ready      { --pp-state-fg: var(--pp-doc-ready);      --pp-state-bg: var(--pp-doc-ready-bg); }
.state-doc-paid       { --pp-state-fg: var(--pp-doc-paid);       --pp-state-bg: var(--pp-doc-paid-bg); }
.state-doc-exported   { --pp-state-fg: var(--pp-doc-exported);   --pp-state-bg: var(--pp-doc-exported-bg); }
.state-doc-cancelled  { --pp-state-fg: var(--pp-doc-cancelled);  --pp-state-bg: var(--pp-doc-cancelled-bg); }
.state-appr-pending   { --pp-state-fg: var(--pp-appr-pending);   --pp-state-bg: var(--pp-appr-pending-bg); }
.state-appr-approved  { --pp-state-fg: var(--pp-appr-approved);  --pp-state-bg: var(--pp-appr-approved-bg); }
.state-appr-rejected  { --pp-state-fg: var(--pp-appr-rejected);  --pp-state-bg: var(--pp-appr-rejected-bg); }
.state-appr-none      { --pp-state-fg: var(--pp-appr-none);      --pp-state-bg: var(--pp-appr-none-bg); }
.state-cat-1          { --pp-state-fg: var(--pp-cat-1);          --pp-state-bg: var(--pp-cat-1-bg); }
.state-cat-2          { --pp-state-fg: var(--pp-cat-2);          --pp-state-bg: var(--pp-cat-2-bg); }
.state-cat-3          { --pp-state-fg: var(--pp-cat-3);          --pp-state-bg: var(--pp-cat-3-bg); }
.state-mail-auto      { --pp-state-fg: var(--pp-mail-auto);      --pp-state-bg: var(--pp-mail-auto-bg); }
.state-mail-done      { --pp-state-fg: var(--pp-mail-done);      --pp-state-bg: var(--pp-mail-done-bg); }
.state-mail-wait      { --pp-state-fg: var(--pp-mail-wait);      --pp-state-bg: var(--pp-mail-wait-bg); }
.state-mail-rejected  { --pp-state-fg: var(--pp-mail-rejected);  --pp-state-bg: var(--pp-mail-rejected-bg); }
.state-mail-off       { --pp-state-fg: var(--pp-mail-off);       --pp-state-bg: var(--pp-mail-off-bg); }
.state-stock-ok       { --pp-state-fg: var(--pp-stock-ok);       --pp-state-bg: var(--pp-stock-ok-bg); }
.state-stock-low      { --pp-state-fg: var(--pp-stock-low);      --pp-state-bg: var(--pp-stock-low-bg); }
.state-stock-out      { --pp-state-fg: var(--pp-stock-out);      --pp-state-bg: var(--pp-stock-out-bg); }
.state-stock-nomin    { --pp-state-fg: var(--pp-stock-nomin);    --pp-state-bg: var(--pp-stock-nomin-bg); }
.state-move-in        { --pp-state-fg: var(--pp-move-in);        --pp-state-bg: var(--pp-move-in-bg); }
.state-move-out       { --pp-state-fg: var(--pp-move-out);       --pp-state-bg: var(--pp-move-out-bg); }
.state-move-shift     { --pp-state-fg: var(--pp-move-shift);     --pp-state-bg: var(--pp-move-shift-bg); }
.state-move-fix       { --pp-state-fg: var(--pp-move-fix);       --pp-state-bg: var(--pp-move-fix-bg); }
.state-goods-stock    { --pp-state-fg: var(--pp-goods-stock);    --pp-state-bg: var(--pp-goods-stock-bg); }
.state-goods-sold     { --pp-state-fg: var(--pp-goods-sold);     --pp-state-bg: var(--pp-goods-sold-bg); }
.state-goods-asset    { --pp-state-fg: var(--pp-goods-asset);    --pp-state-bg: var(--pp-goods-asset-bg); }
.state-goods-used     { --pp-state-fg: var(--pp-goods-used);     --pp-state-bg: var(--pp-goods-used-bg); }
.state-goods-scrap    { --pp-state-fg: var(--pp-goods-scrap);    --pp-state-bg: var(--pp-goods-scrap-bg); }
.state-po-draft       { --pp-state-fg: var(--pp-po-draft);       --pp-state-bg: var(--pp-po-draft-bg); }
.state-po-ordered     { --pp-state-fg: var(--pp-po-ordered);     --pp-state-bg: var(--pp-po-ordered-bg); }
.state-po-partial     { --pp-state-fg: var(--pp-po-partial);     --pp-state-bg: var(--pp-po-partial-bg); }
.state-po-received    { --pp-state-fg: var(--pp-po-received);    --pp-state-bg: var(--pp-po-received-bg); }
.state-po-cancelled   { --pp-state-fg: var(--pp-po-cancelled);   --pp-state-bg: var(--pp-po-cancelled-bg); }
.state-est-high       { --pp-state-fg: var(--pp-est-high);       --pp-state-bg: var(--pp-est-high-bg); }
.state-est-medium     { --pp-state-fg: var(--pp-est-medium);     --pp-state-bg: var(--pp-est-medium-bg); }
.state-est-low        { --pp-state-fg: var(--pp-est-low);        --pp-state-bg: var(--pp-est-low-bg); }
.state-est-none       { --pp-state-fg: var(--pp-est-none);       --pp-state-bg: var(--pp-est-none-bg); }
.state-acq-rental     { --pp-state-fg: var(--pp-acq-rental);     --pp-state-bg: var(--pp-acq-rental-bg); }
.state-acq-service    { --pp-state-fg: var(--pp-acq-service);    --pp-state-bg: var(--pp-acq-service-bg); }
.state-acq-own        { --pp-state-fg: var(--pp-acq-own);        --pp-state-bg: var(--pp-acq-own-bg); }
.state-pa-draft       { --pp-state-fg: var(--pp-pa-draft);       --pp-state-bg: var(--pp-pa-draft-bg); }
.state-pa-done        { --pp-state-fg: var(--pp-pa-done);        --pp-state-bg: var(--pp-pa-done-bg); }
.state-pa-sent        { --pp-state-fg: var(--pp-pa-sent);        --pp-state-bg: var(--pp-pa-sent-bg); }
.state-cov-normal     { --pp-state-fg: var(--pp-cov-normal);     --pp-state-bg: var(--pp-cov-normal-bg); }
.state-cov-notable    { --pp-state-fg: var(--pp-cov-notable);    --pp-state-bg: var(--pp-cov-notable-bg); }
.state-cov-critical   { --pp-state-fg: var(--pp-cov-critical);   --pp-state-bg: var(--pp-cov-critical-bg); }
.state-cov-none       { --pp-state-fg: var(--pp-cov-none);       --pp-state-bg: var(--pp-cov-none-bg); }
.state-audit-auth     { --pp-state-fg: var(--pp-audit-auth);     --pp-state-bg: var(--pp-audit-auth-bg); }
.state-audit-data     { --pp-state-fg: var(--pp-audit-data);     --pp-state-bg: var(--pp-audit-data-bg); }
.state-audit-money    { --pp-state-fg: var(--pp-audit-money);    --pp-state-bg: var(--pp-audit-money-bg); }
.state-audit-access   { --pp-state-fg: var(--pp-audit-access);   --pp-state-bg: var(--pp-audit-access-bg); }
.state-audit-fail     { --pp-state-fg: var(--pp-audit-fail);     --pp-state-bg: var(--pp-audit-fail-bg); }
.state-acct-active    { --pp-state-fg: var(--pp-acct-active);    --pp-state-bg: var(--pp-acct-active-bg); }
.state-acct-invited   { --pp-state-fg: var(--pp-acct-invited);   --pp-state-bg: var(--pp-acct-invited-bg); }
.state-acct-off       { --pp-state-fg: var(--pp-acct-off);       --pp-state-bg: var(--pp-acct-off-bg); }

/* Tečka stavu pro hutné seznamy, kde na odznak není místo.
   Sytý tón uvnitř, měkký prstenec kolem — jinak z tečky s halo zbude jednolitý
   bledý puntík a dva sousední stavy splynou (nález RV-712 z revize FÁZE 7:
   „Koncept" a „Objednáno" byly v tmavém tématu dvě totožné šedomodré tečky).
   `!important` tu není síla navíc, je to nutnost: pravidlo odznaku o padesát
   řádků výš má `background-color: … !important` při STEJNÉ specificitě, takže
   by zkratka `background` prohrála a tečka by se kreslila měkkým tónem. */
.state-dot {
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: var(--pp-radius-pill);
    background-color: var(--pp-state-fg, var(--pp-neutral)) !important;
    box-shadow: 0 0 0 3px var(--pp-state-bg, var(--pp-neutral-soft));
    margin-right: var(--sp-2);
    vertical-align: middle;
}

/* Tabler používá na stavy `bg-*-lt` — přemapované škály z §1/§2 tyhle
   odznaky převezmou samy, takže stávající obrazovky se srovnají bez zásahu
   do šablon. */
/* Odznak na plné barevné ploše žádnou barvu textu nedostával a dědil ji po
   rodiči — v hlavičce karty `bg-orange-lt` z toho byla oranžová na oranžové.
   Plná barva má vlastní popředí, které se s tématem obrací. */
.badge.bg-green, .badge.bg-success,
.badge.bg-yellow, .badge.bg-warning,
.badge.bg-orange,
.badge.bg-red, .badge.bg-danger,
.badge.bg-blue, .badge.bg-info,
.badge.bg-azure,
.badge.bg-teal,
.badge.bg-secondary,
.badge.bg-dark {
    color: var(--pp-on-solid) !important;
}

.bg-primary { background-color: var(--pp-brand) !important; color: var(--pp-brand-on) !important; }
.text-primary { color: var(--pp-brand) !important; }
.bg-primary-lt { background-color: var(--pp-brand-soft) !important; color: var(--pp-brand-strong) !important; }
[data-bs-theme=dark] .bg-primary-lt { color: var(--pp-brand) !important; }

/* ===========================================================================
   8. PRÁZDNÉ A CHYBOVÉ STAVY (DNA §8: vysvětlení + akce)
   =========================================================================== */
.empty {
    padding: var(--sp-8) var(--sp-4);
    background: var(--pp-surface);
    border-radius: var(--pp-radius-lg);
}
.empty-icon,
.empty-img { color: var(--pp-ink-3); opacity: .7; margin-bottom: var(--sp-4); }
.empty-title {
    font-size: var(--pp-text-lg);
    font-weight: var(--pp-weight-bold);
    color: var(--pp-ink);
}
.empty-subtitle {
    color: var(--pp-ink-2);
    max-width: 46ch;
    margin-left: auto;
    margin-right: auto;
    line-height: var(--pp-lh-loose);
}
.empty-action { margin-top: var(--sp-5); }

/* ===========================================================================
   9. PŘEPÍNAČ TÉMAT
   ---------------------------------------------------------------------------
   Tři stavy: světlé → tmavé → auto. Značka `data-theme-choice` na <html> nese
   volbu uživatele, `data-bs-theme` už jen vypočtený výsledek — v režimu auto
   se dopočítá z `prefers-color-scheme`. Ikony se přepínají jen CSS, skript
   nastavuje výhradně atributy (viz `layouts/partials/theme-boot.blade.php`).
   =========================================================================== */
.theme-toggle {
    border-radius: var(--pp-radius-md);
    color: var(--pp-ink-2);
    border: 1px solid var(--pp-line-strong);
    background: var(--pp-surface);
    line-height: 1;
    transition: color .15s ease, background-color .15s ease, border-color .15s ease;
}
.theme-toggle:hover {
    color: var(--pp-ink);
    background: var(--pp-surface-3);
    border-color: var(--pp-line-strong);
}
.theme-toggle:focus-visible { box-shadow: var(--pp-ring); outline: none; }

.theme-toggle .theme-icon { display: none; }
[data-theme-choice=light] .theme-toggle .theme-icon-light { display: inline-block; }
[data-theme-choice=dark]  .theme-toggle .theme-icon-dark  { display: inline-block; }
[data-theme-choice=auto]  .theme-toggle .theme-icon-auto  { display: inline-block; }
/* Bez JS (a tedy bez `data-theme-choice`) se ukáže sluníčko, ať tlačítko
   nezůstane prázdné. */
html:not([data-theme-choice]) .theme-toggle .theme-icon-light { display: inline-block; }

/* ===========================================================================
   10. DROBNOSTI PŘEVZATÉ Z PŮVODNÍHO TÉMATU
   =========================================================================== */
.printpilot-brand {
    font-weight: var(--pp-weight-black);
    letter-spacing: .01em;
}
/* V koleji je logotyp bílý (kolej je tmavá v obou tématech), na přihlašovací
   obrazovce jde o text na světlé/tmavé ploše — tam se řídí tokenem. */
.navbar-vertical .printpilot-brand { color: #fff; }
.page-center .printpilot-brand { color: var(--pp-ink); }
.navbar-brand-image {
    height: 28px;
    width: 28px;
    margin-right: .5rem;
    vertical-align: -7px;
    /* Tabler defaultně přebarvuje brand image (filter: brightness(0) invert(1))
       — předpokládá monochromní siluety. PrintPilot logo je barevné, override. */
    filter: none !important;
}

/* Odkazy dědí Tablerovo `a { color: rgba(var(--tblr-link-color-rgb), …) }` —
   přepis `--tblr-link-color*` v §1/§2 je obarví. Obecné pravidlo
   `a { color: … }` schválně NEPŘIDÁVÁME: přebilo by barvu textu
   u <a class="btn btn-primary">. */

/* Karta na přihlašovací obrazovce — vrstvení podle DNA §4. */
.page-center .card-md { max-width: 26rem; }
.page-center .card {
    box-shadow: var(--pp-shadow-lg);
    border-radius: var(--pp-radius-xl);
}
.page-center { background: var(--pp-hero); }

/* Inline nápověda — malý šedý otazník vedle popisků a tlačítek */
.help-tip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.15em;
    height: 1.15em;
    color: var(--pp-ink-3);
    cursor: help;
    margin-left: 0.4rem;
    font-size: 1em;
    line-height: 1;
    vertical-align: middle;
    transition: color .15s ease;
}
.help-tip:hover,
.help-tip:focus {
    color: var(--pp-brand);
    outline: none;
}
.help-tip i { font-size: 1.1em; line-height: 1; }
.tooltip { --tblr-tooltip-max-width: 360px; }
.tooltip-inner {
    text-align: left;
    padding: .55rem .7rem;
    line-height: 1.45;
    border-radius: var(--pp-radius-md);
}

/* ===========================================================================
   11. DASHBOARD — KONFIGUROVATELNÉ WIDGETY (DNA §3)
   ---------------------------------------------------------------------------
   Dashboard je mřížka o dvanácti sloupcích; každý widget je její položka.
   Pořadí se řídí vlastností `order` (Alpine ji nastavuje inline), šířka
   atributem `data-span` — tedy CSS, ne přesouváním uzlů v DOM. Díky tomu se
   rozložení dá měnit i po vykreslení a nic se nemusí překreslovat.

   Volba se ukládá do `localStorage` (žádná route navíc, mantinel F3-S7).
   =========================================================================== */
/* Než Alpine nabootuje, nic z toho, co řídí, nesmí probliknout v defaultním
   stavu — jinak se dashboard vykreslí v původním pořadí a hned přeskládá. */
[x-cloak] { display: none !important; }

.pp-dash {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--sp-5);
    align-items: start;
}
.pp-widget {
    grid-column: span 12;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}
/* Půlená šířka má smysl až tam, kde se do poloviny obrazovky vejde karta —
   pod 992 px je každý widget přes celou šířku bez ohledu na volbu. */
@media (min-width: 992px) {
    .pp-widget[data-span="6"] { grid-column: span 6; }
}

.pp-widget-head {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    min-height: 1.5rem;
}
.pp-widget-title {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-2);
    margin: 0;
    font-size: var(--pp-text-xs);
    font-weight: var(--pp-weight-semibold);
    text-transform: uppercase;
    letter-spacing: var(--pp-tracking-caps);
    color: var(--pp-ink-3);
}
.pp-widget-title > a { color: inherit; text-decoration: none; }
.pp-widget-title > a:hover { color: var(--pp-brand); }
/* Doplněk v hlavičce widgetu je věta, ne popisek — verzálky se na něj nedávají. */
.pp-widget-note {
    text-transform: none;
    letter-spacing: 0;
    font-weight: var(--pp-weight-normal);
    font-size: var(--pp-text-sm);
    color: var(--pp-ink-3);
}

.pp-widget-tools {
    margin-left: auto;
    display: flex;
    gap: 2px;
    opacity: .45;
    transition: opacity .15s ease;
}
.pp-widget:hover .pp-widget-tools,
.pp-widget-tools:focus-within { opacity: 1; }
.pp-tool {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    border: 0;
    border-radius: var(--pp-radius-sm);
    background: transparent;
    color: var(--pp-ink-3);
    font-size: 0.95rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color .12s ease, color .12s ease;
}
.pp-tool:hover:not([disabled]) { background: var(--pp-surface-3); color: var(--pp-ink); }
.pp-tool:focus-visible { box-shadow: var(--pp-ring); outline: none; }
.pp-tool[disabled] { opacity: .25; cursor: default; }

/* Dlaždice klíčového čísla: číslo v čele, pod ním věta (DNA §1 + §7). */
.pp-tile { height: 100%; }
.pp-tile .card-body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    padding: var(--sp-4);
}
.pp-tile-head {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    color: var(--pp-ink-3);
    font-size: var(--pp-text-xs);
    font-weight: var(--pp-weight-semibold);
    text-transform: uppercase;
    letter-spacing: var(--pp-tracking-caps);
}
.pp-tile-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: var(--pp-radius-sm);
    background: var(--pp-brand-soft);
    color: var(--pp-brand-strong);
    font-size: 1rem;
}
[data-bs-theme=dark] .pp-tile-icon { color: var(--pp-brand); }
.pp-tile .metric { margin-bottom: 0; }
.pp-tile .explain { margin-bottom: 0; }
.card-link.pp-tile:hover { box-shadow: var(--pp-shadow-md); }

/* ===========================================================================
   12. MĚŘIDLO A GRAF (DNA §3 měřidlo jen k poměru ke stropu, §7 nejdřív číslo)
   =========================================================================== */
.pp-gauge {
    display: block;
    width: 100%;
    max-width: 15rem;
    margin-inline: auto;
}
.pp-gauge-track {
    fill: none;
    stroke: var(--pp-surface-3);
    stroke-width: 14;
    stroke-linecap: round;
}
.pp-gauge-value {
    fill: none;
    stroke: var(--pp-gauge-color, var(--pp-success));
    stroke-width: 14;
    stroke-linecap: round;
}
.pp-gauge-num {
    fill: var(--pp-ink);
    font-size: 30px;
    font-weight: var(--pp-weight-black);
    font-variant-numeric: tabular-nums;
}
.pp-gauge-cap { fill: var(--pp-ink-3); font-size: 11px; }
.pp-gauge-scale { fill: var(--pp-ink-3); font-size: 10px; font-variant-numeric: tabular-nums; }

/* Graf má mřížku, výplň a zvýrazněný poslední bod — holá čára je málo (DNA §7).
   Kresba je roztažené SVG, popisky jsou HTML nad ním: kdyby byly uvnitř, ve
   widgetu v poloviční šířce by se z jedenáctibodového písma stalo šestibodové. */
.pp-chart-wrap {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas: 'y plot' '. x';
    column-gap: var(--sp-2);
    font-variant-numeric: tabular-nums;
}
.pp-chart-y {
    grid-area: y;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    font-size: var(--pp-text-xs);
    color: var(--pp-ink-3);
    text-align: right;
}
.pp-chart-plot { grid-area: plot; position: relative; height: 9rem; }
.pp-chart-x {
    grid-area: x;
    display: flex;
    justify-content: space-between;
    font-size: var(--pp-text-xs);
    color: var(--pp-ink-3);
    margin-top: var(--sp-1);
}
.pp-chart { display: block; width: 100%; height: 100%; overflow: visible; }
.pp-chart-grid { stroke: var(--pp-line-strong); stroke-width: 1; }
.pp-chart-grid-soft { stroke: var(--pp-line); stroke-width: 1; stroke-dasharray: 3 4; }
.pp-chart-avg { stroke: var(--pp-ink-3); stroke-width: 1; stroke-dasharray: 5 4; }
.pp-chart-line {
    fill: none;
    stroke: var(--pp-accent);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.pp-chart-avg-label {
    position: absolute;
    left: 0;
    transform: translateY(-115%);
    font-size: var(--pp-text-xs);
    color: var(--pp-ink-3);
    background: var(--pp-surface);
    padding-inline: 0.25rem;
}
.pp-chart-dot {
    position: absolute;
    width: 0.55rem;
    height: 0.55rem;
    border-radius: var(--pp-radius-pill);
    background: var(--pp-accent);
    box-shadow: 0 0 0 3px var(--pp-surface);
    transform: translate(-50%, -50%);
}
.pp-chart-callout {
    position: absolute;
    transform: translate(-100%, -180%);
    margin-left: -0.5rem;
    white-space: nowrap;
    font-size: var(--pp-text-sm);
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink);
    background: var(--pp-surface);
    border-radius: var(--pp-radius-sm);
    padding: 0.05rem 0.3rem;
}

/* Práh v grafu — LINKA S POPISKEM, ne položka v legendě (dávka 8, §4.16).
   „Nad 7 % se volá zákazníkovi" je pravidlo o hodnotě, takže patří k ose,
   ne pod tabulku: v legendě se čte jako barevný klíč a čtenář si musí sám
   domyslet, kde ta hranice na křivce leží. Barvu bere ze stavu (`--pp-state-fg`
   nastaví `.state-cov-*` na tomtéž prvku), takže se práh a odznak v tabulce
   nemůžou rozejít. Čárkování je hustší než u průměru: průměr je pozorování,
   práh je rozhodnutí. */
.pp-chart-limit {
    stroke: var(--pp-state-fg, var(--pp-ink-3));
    stroke-width: 1.5;
    stroke-dasharray: 2 3;
}
.pp-chart-limit-label {
    position: absolute;
    right: 0;
    transform: translateY(-115%);
    font-size: var(--pp-text-xs);
    font-weight: var(--pp-weight-medium);
    color: var(--pp-state-fg, var(--pp-ink-3));
    background: var(--pp-surface);
    padding-inline: 0.25rem;
    border-radius: var(--pp-radius-sm);
    white-space: nowrap;
}

/* Vodorovný pruh s číslem i procentem — podíly se nekreslí koláčem (DNA §7). */
.pp-bars { display: flex; flex-direction: column; gap: var(--sp-2); }
.pp-bar-row { display: grid; grid-template-columns: 1fr auto; gap: var(--sp-1) var(--sp-3); align-items: center; }
.pp-bar-label { font-size: var(--pp-text-sm); color: var(--pp-ink-2); }
.pp-bar-value { font-size: var(--pp-text-sm); color: var(--pp-ink); font-variant-numeric: tabular-nums; }
.pp-bar-track {
    grid-column: 1 / -1;
    height: 0.5rem;
    border-radius: var(--pp-radius-pill);
    background: var(--pp-surface-3);
    overflow: hidden;
}
.pp-bar-fill { height: 100%; border-radius: var(--pp-radius-pill); background: var(--pp-bar-color, var(--pp-accent)); }

/* ===========================================================================
   13. HUTNÝ SEZNAM — filtrační lišta a odlehčené řádky (DNA §6)
   ---------------------------------------------------------------------------
   Registry mají mít maximum informace nad zlomem. Filtry proto stojí v jednom
   pruhu a to, co se používá zřídka, je schované pod „Další filtry"; aktivní
   filtry se ukazují jako štítky, ať se nedá přehlédnout zúžený výběr.
   =========================================================================== */
.pp-filterbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
}
.pp-filterbar .form-control,
.pp-filterbar .form-select { height: 2rem; padding-block: 0.2rem; font-size: var(--pp-text-base); }
.pp-filterbar .input-icon-addon { height: 2rem; }
.pp-filterbar-search { flex: 1 1 16rem; min-width: 12rem; }
.pp-filter-more { margin-top: var(--sp-3); }
.pp-filter-chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.pp-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    padding: 0.1rem 0.5rem;
    border-radius: var(--pp-radius-pill);
    background: var(--pp-accent-soft);
    color: var(--pp-accent);
    font-size: var(--pp-text-xs);
    font-weight: var(--pp-weight-semibold);
}
.pp-chip-muted { background: var(--pp-surface-3); color: var(--pp-ink-2); }

/* Hutný řádek drží vše na jedné lince — druhý řádek v buňce zvedne výšku
   tabulky o třetinu a z dvaceti řádků nad zlomem je rázem třináct. */
.pp-list-strong { font-weight: var(--pp-weight-semibold); color: var(--pp-ink); }
.pp-list-sub { color: var(--pp-ink-3); }
.pp-list-sub::before { content: '·'; margin: 0 0.35rem; }
.table-dense td, .table-dense th { white-space: nowrap; }

/* Nowrap sám o sobě řádek na jedné lince udrží, ale tabulku přitom roztáhne přes
   kraj karty — a ustřihne se pravý sloupec, tedy zrovna stav. Široké textové
   buňky se proto ořezávají třemi tečkami; celá informace zůstává v detailu. */
.pp-cell-clip { max-width: 13rem; overflow: hidden; text-overflow: ellipsis; }
.pp-cell-clip-sm { max-width: 9rem; overflow: hidden; text-overflow: ellipsis; }

/* Podřádek, který si stoupne POD hodnotu, místo aby stál za ní. Je to výjimka
   z pravidla o jedné lince (o pár řádků výš) a platí tam, kde buňka veze
   DVOJICI, ne hodnotu s poznámkou: „kdo" je v cizí firmě vždycky člověk
   + firma. Vedle sebe drží obojí `nowrap` na jedné lince a nejširší tabulka
   aplikace (audit očima super admina) přetekla na 1440 px o 35 px — nález
   `RV-1211` brány. Volba je táž jako u úzkého okna níž: raději o řádek vyšší
   řádek než sloupec mimo obraz. Tečka oddělovače tu nedává smysl, na vlastní
   lince nic neodděluje. */
.pp-cell-stack { display: block; }
.pp-cell-stack::before { content: none; }

/* Na úzkém okně nowrap padá: ořezy mají pevnou šířku v rem, takže se součet
   sloupců s oknem nezmenší a tabulka vyjede za kraj karty i s posledním
   sloupcem (typicky stav) a s tlačítkem detailu. Naměřeno 257 px přetečení
   na 768 px. Hustota je kritérium jen na širokém okně, takže se tu jednořádkovosti
   vzdáváme — raději o řádek vyšší řádek než sloupec mimo obraz. */
@media (max-width: 991.98px) {
    .table-dense td, .table-dense th { white-space: normal; }
    .table-dense .pp-cell-clip,
    .table-dense .pp-cell-clip-sm { max-width: none; }
}
/* Prázdný stav uvnitř hutné tabulky se MUSÍ zalomit.
   `.table-dense td` dává všem buňkám `nowrap` (o pár řádků výš) a `<x-empty-state>`
   bydlí v buňce přes všechny sloupce — takže se vysvětlující věta nezalomila
   a její šířka na jednu linku se stala nejmenší šířkou celé tabulky. Naměřeno
   na 1440 px u „Neznámých tiskáren": tabulka nešla zúžit pod 1 173 px v kartě
   široké 1 166 px, tedy 7 px přes kraj — a to prázdná.

   Je to sdílená vrstva, ne vada jedné obrazovky: platí pro každý prázdný stav
   v každé hutné tabulce, a čím lepší je věta, tím spíš to nastane. */
.table-dense td .empty,
.table-dense td .empty * { white-space: normal; }

.pp-truncate {
    display: inline-block;
    max-width: 18rem;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: bottom;
}

/* ===========================================================================
   14. MATICE POZICE × VARIANTA (CRM — hutná spodní část detailu)
   ---------------------------------------------------------------------------
   Nabídka je matice: řádek je pozice (co zákazník poptává), sloupec varianta
   (jak mu to nabízíme). Šestnáctipolový formulář řádku se otevírá pod maticí,
   takže hustotu nerozbíjí a přitom je pořád na dosah.
   =========================================================================== */
.pp-matrix { width: 100%; }
.pp-matrix th.pp-matrix-corner { width: 18rem; }
.pp-matrix .pp-matrix-col {
    border-left: 1px solid var(--pp-line);
    vertical-align: top;
}
.pp-matrix thead th.pp-matrix-col { background: var(--pp-surface-2); }
.pp-matrix .pp-matrix-col.is-expected { background: var(--pp-brand-soft); }
[data-bs-theme=dark] .pp-matrix .pp-matrix-col.is-expected { background: rgba(var(--pp-brand-rgb), .16); }
.pp-matrix-head-name {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--pp-text-base);
    font-weight: var(--pp-weight-bold);
    color: var(--pp-ink);
    text-transform: none;
    letter-spacing: 0;
}
.pp-matrix-cell { display: flex; flex-direction: column; gap: 0.1rem; }
.pp-matrix-price { font-variant-numeric: tabular-nums; font-weight: var(--pp-weight-semibold); color: var(--pp-ink); }
.pp-matrix-clicks { font-size: var(--pp-text-xs); color: var(--pp-ink-3); font-variant-numeric: tabular-nums; }
.pp-matrix-foot td { background: var(--pp-surface-2); }

/* ---------------------------------------------------------------------------
   FÁZE 2 kola CRM — čtyři varianty vedle sebe.

   Do téhle chvíle matice žádnou minimální šířku neměla: sloupce se s každou
   další variantou zmáčkly, až se v buňce lámalo „12 400 Kč/měs" na tři řádky.
   Brána přitom hlásila nulové přetečení — tabulka se totiž nevylila za kraj,
   jen se stala nečitelnou (HANDOFF_DESIGN §5.2).

   Řešení je posun, ne zmáčknutí: sloupec varianty má svou nejmenší čitelnou
   šířku a co se nevejde, to se odsune vodorovně POD ukotveným prvním sloupcem.
   Bez ukotvení by se při posunu ztratilo, ke které pozici cena patří — a tím
   i celý smysl matice.
   --------------------------------------------------------------------------- */
.pp-scroll-x { overflow-x: auto; }
.pp-matrix .pp-matrix-col { min-width: 12.5rem; }
/* Šířka prvního sloupce se řídí obalem UVNITŘ buňky: `max-width` na
   `display: table-cell` prohlížeč ignoruje, takže popis pozice jinak natáhne
   sloupec na svou celou délku a na varianty zbyde, co zbyde.
   `white-space: normal` je k té šířce povinné — hutná tabulka má buňky nowrap
   (ř. 1297), takže by se popis do 14 rem nezalomil, jen by z obalu vytekl přes
   ukotvené pozadí do sloupce vedle. */
.pp-matrix-rowhead { width: 14rem; white-space: normal; }
/* FÁZE 3 kola CRM — číslo nabídky, sleva a platnost v hlavičce sloupce.
   Táž past jako u popisu pozice o pár řádků výš, jen na druhém konci tabulky:
   hutná tabulka má buňky `nowrap`, takže věta „Platnost skončila … pošli novou
   verzi." se nezalomila a roztáhla sloupec na svou celou délku — naměřeno
   365 px místo 12,5 rem, čímž se čtyři varianty přestaly vejít do 1440 px bez
   posunu. `.explain` má sice `max-width: 46ch`, ale to bez zalomení nic
   neudělá. Šířku proto drží obal UVNITŘ buňky a je o kus užší než nejmenší
   šířka sloupce, aby se do ní vešel i s odsazením buňky. */
.pp-matrix-headnote { display: block; width: 11rem; white-space: normal; }

.pp-matrix th.pp-matrix-corner,
.pp-matrix tbody td:first-child,
.pp-matrix tfoot td:first-child {
    position: sticky;
    left: 0;
    /* Neprůhledné pozadí je podmínka, ne ozdoba: přes průsvitnou buňku by při
       posunu prosvítaly ceny, které pod ní zrovna jedou. */
    background: var(--pp-surface);
    /* `border-collapse` sebere ukotvené buňce pravou linku, jakmile se odjede —
       stín ji nahradí a zároveň odděluje ukotvený sloupec od posouvaných. */
    box-shadow: 1px 0 0 var(--pp-line);
    z-index: 1;
}
.pp-matrix th.pp-matrix-corner,
.pp-matrix tfoot td:first-child { background: var(--pp-surface-2); }
.pp-matrix thead th.pp-matrix-corner { z-index: 2; }

/* Nenabízená varianta (`is_offered = false`) — poznat na první pohled, ne až
   v detailu buňky. Zůstává v matici kvůli srovnání, ale nepočítá se do ničeho:
   `ApprovalService` i `TcoService` berou jen nabízené řádky. */
.pp-matrix .pp-matrix-col.is-not-offered {
    background: var(--pp-surface-3);
}
.pp-matrix .pp-matrix-col.is-not-offered .pp-matrix-price,
.pp-matrix .pp-matrix-col.is-not-offered .pp-list-strong {
    color: var(--pp-ink-3);
    text-decoration: line-through;
}

/* Na úzkém okně si ukotvený sloupec nesmí vzít třetinu obrazovky — pak by na
   varianty zbylo míň, než je jejich nejmenší čitelná šířka, a posouvalo by se
   po půl sloupci. Zároveň nesmí spadnout pod čitelnou mez: bez vlastní
   nejmenší šířky ho tabulka smáčkla na 78 px (naměřeno na 768 px), protože
   ostatní sloupce si svou minimální šířku vzaly první. */
@media (max-width: 991.98px) {
    .pp-matrix th.pp-matrix-corner { width: 10rem; min-width: 10rem; }
    .pp-matrix-rowhead { width: 10rem; }
}

/* Kartička nástěnky CRM (FÁZE 5 kola CRM). Ovládání fáze sedí vpravo vedle
   názvu příležitosti — a ten bývá dlouhý. Flexový prvek má implicitně
   `min-width: auto`, takže se nezkrátí a tlačítko vytlačí MIMO kartu, do
   sloupce vedle; `text-truncate` na něm samo nezabere. Vlastní třída proto
   drží obojí: prostor pro text se smí zúžit, ovládání zůstává na svém. */
.pp-kanban-card { display: flex; align-items: flex-start; gap: var(--sp-2); }
.pp-kanban-card__main { flex: 1 1 auto; min-width: 0; }

/* Souhrn nahoře je komponovaný: klíčové číslo, pod ním věta (DNA §6). */
.pp-summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: var(--sp-4);
}
.pp-summary-item { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.pp-summary-label {
    font-size: var(--pp-text-xs);
    font-weight: var(--pp-weight-semibold);
    text-transform: uppercase;
    letter-spacing: var(--pp-tracking-caps);
    color: var(--pp-ink-3);
}
.pp-summary-value {
    font-size: var(--pp-text-lg);
    font-weight: var(--pp-weight-bold);
    color: var(--pp-ink);
    font-variant-numeric: tabular-nums;
}

/* ===========================================================================
   15. PŘIHLAŠOVACÍ OBRAZOVKY (auth/) — FÁZE 1 plošného průchodu
   ---------------------------------------------------------------------------
   Šest šablon v `auth/` si dosud kartu skládalo každá po svém. Kompozice teď
   žije tady a v `components/auth-card.blade.php`.

   Hloubka podle DNA §4 je v HLAVIČCE karty — přechod nad plochou karty, která
   sama leží na `--pp-hero` celé stránky (§10). Pod formulářem by vrstvení jen
   ubíralo čitelnost, takže tam žádné není.
   =========================================================================== */
.pp-auth-card { overflow: hidden; }
.pp-auth-head {
    padding: var(--sp-5) var(--sp-5) var(--sp-4);
    background: var(--pp-hero);
    border-bottom: 1px solid var(--pp-hero-line);
}
.pp-auth-title {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin: 0;
    font-size: var(--pp-text-xl);
    font-weight: var(--pp-weight-bold);
    line-height: var(--pp-lh-tight);
    color: var(--pp-ink);
}
.pp-auth-title i { color: var(--pp-brand); font-size: 1.1em; }
.pp-auth-lead { margin: var(--sp-2) 0 0; }
.pp-auth-foot {
    margin-top: var(--sp-4);
    text-align: center;
    font-size: var(--pp-text-sm);
    color: var(--pp-ink-2);
}

/* Podtitul stránky je taky vysvětlující věta (`.explain` v `layouts/app`), jen
   stojí nad celou obrazovkou — 46 znaků by ji lámalo po třech slovech. */
.page-header .explain { max-width: 72ch; }

/* Blok „číslo + věta" (`components/metric.blade.php`). Sám o sobě nic nekreslí,
   jen drží dvojici pohromadě — ale díky němu se dá mezera mezi číslem a větou
   měnit na jednom místě místo v každé šabloně zvlášť. */
.pp-metric-block { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.pp-metric-block .metric > a { color: inherit; text-decoration: none; }
.pp-metric-block .metric > a:hover { color: var(--pp-brand); }

/* ===========================================================================
   16. NÁPOVĚDA — sazba kapitoly manuálu (help/)
   ---------------------------------------------------------------------------
   Do FÁZE 1 tahle sazba bydlela v `<style>` uvnitř `help/index.blade.php`
   a odkazovala se na Tablerovy proměnné (`--tblr-azure`, `--tblr-border-color`),
   tedy mimo paletu systému. Přesunuto sem a přepsáno na tokeny `--pp-*`:
   kapitola manuálu je souvislý text, a ten se v obou tématech čte jinak než
   tabulka.
   =========================================================================== */
.help-body { color: var(--pp-ink); }
.help-body h1 {
    font-size: var(--pp-text-xl);
    font-weight: var(--pp-weight-bold);
    line-height: var(--pp-lh-tight);
    margin: 0 0 var(--sp-4);
}
.help-body h2 {
    font-size: var(--pp-text-lg);
    font-weight: var(--pp-weight-bold);
    margin: var(--sp-6) 0 var(--sp-3);
    padding-bottom: var(--sp-2);
    border-bottom: 1px solid var(--pp-line);
}
.help-body h3 {
    font-size: var(--pp-text-md);
    font-weight: var(--pp-weight-semibold);
    margin: var(--sp-5) 0 var(--sp-2);
    color: var(--pp-ink-2);
}
.help-body p,
.help-body ul,
.help-body ol { line-height: var(--pp-lh-loose); }
.help-body code {
    font-family: var(--pp-font-mono);
    font-size: .875em;
    padding: .1rem .4rem;
    border-radius: var(--pp-radius-sm);
    background: var(--pp-surface-3);
    color: var(--pp-ink);
}
.help-body pre {
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--pp-radius-md);
    background: var(--pp-surface-3);
    overflow-x: auto;
}
.help-body pre code { background: none; padding: 0; }
.help-body table {
    width: 100%;
    margin: var(--sp-4) 0;
    border-collapse: collapse;
}
.help-body table th,
.help-body table td {
    border: 1px solid var(--pp-line);
    padding: var(--sp-2) var(--sp-3);
}
.help-body table th {
    background: var(--pp-surface-2);
    text-align: left;
    font-weight: var(--pp-weight-semibold);
}
.help-body blockquote {
    margin: var(--sp-4) 0;
    padding: var(--sp-2) var(--sp-4);
    border-left: 3px solid var(--pp-accent);
    border-radius: 0 var(--pp-radius-md) var(--pp-radius-md) 0;
    background: var(--pp-accent-soft);
    color: var(--pp-ink-2);
}
.help-body a { color: var(--pp-accent); text-decoration: none; }
.help-body a:hover { text-decoration: underline; }
/* Kotvy, které commonmark věší k nadpisům — v aplikaci nejsou k ničemu. */
.help-body .heading-anchor { display: none; }

/* Rejstřík kapitol vlevo. Je to seznam, ne obsah — tedy hutný (DNA §6). */
.pp-help-toc .list-group-item { padding: .35rem var(--sp-3); font-size: var(--pp-text-sm); }
.pp-help-toc .list-group-item .pp-help-toc-num {
    color: var(--pp-ink-3);
    font-variant-numeric: tabular-nums;
    margin-right: var(--sp-2);
}
.pp-help-toc .list-group-item.active .pp-help-toc-num { color: inherit; opacity: .8; }

/* ===========================================================================
   17. DETAIL ZAŘÍZENÍ (printers/ — dávka 1 plošného průchodu)
   ---------------------------------------------------------------------------
   Detail je povolená kombinace obou hustot (§4): nahoře komponovaný souhrn
   s klíčovými čísly a větami, dole hutné záložky — odečty, náklady, historie.
   Hloubka je v hlavičce stránky (§10), tady už ne: pod souhrnem začíná
   tabulka a vrstvení by jí ubralo čitelnost (DNA §4).
   =========================================================================== */

/* Souhrn v čele detailu. Mřížka je stejná jako u příležitosti (§14), jen
   položkou je `<x-metric>` — číslo a POD ním věta, ne popisek nad číslem. */
.pp-detail-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: var(--sp-4) var(--sp-5); }
.pp-detail-summary .metric { font-size: var(--pp-text-2xl); }
/* Popisek nad číslem (`.pp-metric-label`) je od dávky 2 části 1 globální (§21) —
   mřížka si nechává jen rozvržení a velikost čísla. */

/* Tabulka údajů (identita zařízení). Je to dvojice název–hodnota, ne registr:
   levý sloupec je tichý, pravý nese informaci, řádky se nelámou po slovech.
   `.table-dense` sama o sobě dává všem buňkám `nowrap` — u adresy nebo
   poznámky to je přesně to, co roztáhne kartu za kraj. */
.pp-facts th,
.pp-facts td { white-space: normal; vertical-align: top; }
.pp-facts th {
    width: 40%;
    background: none;
    color: var(--pp-ink-3);
    font-weight: var(--pp-weight-normal);
    text-transform: none;
    letter-spacing: 0;
    font-size: var(--pp-text-sm);
}
.pp-facts > :not(caption) > *:last-child > * { border-bottom-width: 0; }

/* Hladina toneru a životnost dílu se čtou jako vodorovný pruh s číslem
   i procentem (§12, DNA §7). Barva pruhu je barva toneru, ne stav. */
.pp-toner-k { --pp-bar-color: var(--pp-toner-black);   --pp-toner-color: var(--pp-toner-black); }
.pp-toner-c { --pp-bar-color: var(--pp-toner-cyan);    --pp-toner-color: var(--pp-toner-cyan); }
.pp-toner-m { --pp-bar-color: var(--pp-toner-magenta); --pp-toner-color: var(--pp-toner-magenta); }
.pp-toner-y { --pp-bar-color: var(--pp-toner-yellow);  --pp-toner-color: var(--pp-toner-yellow); }

.pp-toner-swatch {
    display: inline-block;
    width: 0.55rem;
    height: 0.55rem;
    border-radius: var(--pp-radius-pill);
    background: var(--pp-toner-color, var(--pp-neutral));
    margin-right: var(--sp-2);
    vertical-align: middle;
}

/* Graf spotřeby toneru. Čtyři řady nad společnou mřížkou; popisky os jsou
   HTML nad SVG (`.pp-chart-*` z §12), protože roztažené SVG by je zmenšilo
   spolu se sebou. Barva se předává proměnnou z třídy řady — v prezentačním
   atributu `stroke` by se `var()` nevyhodnotil, v CSS vlastnosti ano. */
.pp-toner-line {
    fill: none;
    stroke: var(--pp-toner-color, var(--pp-accent));
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.pp-toner-dot { fill: var(--pp-toner-color, var(--pp-accent)); }
.pp-toner-legend { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); }
.pp-toner-legend span { font-size: var(--pp-text-xs); color: var(--pp-ink-2); white-space: nowrap; }

/* Formulář zařízení: sekce jako zapuštěná plocha, ne jako další rámeček
   (DNA §4). Nadpis sekce je popisek, ne nadpis stránky — proto verzálky
   v 11 px a ne `h4`. */
.pp-form-section + .pp-form-section { margin-top: var(--sp-4); }
.pp-form-section-title {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--pp-text-xs);
    font-weight: var(--pp-weight-semibold);
    text-transform: uppercase;
    letter-spacing: var(--pp-tracking-caps);
    color: var(--pp-ink-3);
    margin-bottom: var(--sp-3);
}
.pp-form-section-title::after {
    content: '';
    flex: 1 1 auto;
    height: 1px;
    background: var(--pp-line);
}

/* Pruh životnosti dílu nese STAV (na rozdíl od toneru, kde je barva údaj) —
   proto ukazuje do rodin z §3.3, ne do vlastní palety. */
/* Pruh, jehož barvu určuje STAV na obalu (dávka 8). Sytý tón do výplně,
   měkký zůstane na dráze — táž dvojice jako u `.state-dot` v §7, jen
   naplocho. Bez toho by se pruh musel obarvit druhou mapou a ta by se
   s odznakem v témž řádku dřív nebo později rozešla. */
.pp-bar-state { --pp-bar-color: var(--pp-state-fg, var(--pp-accent)); }

.pp-bar-ok    { --pp-bar-color: var(--pp-success); }
.pp-bar-watch { --pp-bar-color: var(--pp-warning); }
.pp-bar-block { --pp-bar-color: var(--pp-danger); }
.pp-bar-none  { --pp-bar-color: var(--pp-neutral); }

/* Dráha i výplň pruhu jsou v šablonách `<div>`: řádkovému prvku se výška ani
   šířka nepřiřadí, takže `<span class="pp-bar-fill">` se sice vysázel, ale
   nebyl vidět (nález z první sady snímků FÁZE 2). Uvnitř mřížky `.pp-bars` to
   nebylo poznat — položka gridu se blokuje sama —, v buňce tabulky ano. */
.table .pp-bar-track { display: block; }

/* Poslední bod řady je HTML kolečko (v roztaženém SVG by z něj byla elipsa),
   takže si barvu bere z proměnné řady, ne z akcentu. */
.pp-chart-dot[class*='pp-toner-'] { background: var(--pp-toner-color); }

/* Hlavička hutné tabulky se NELÁME nikde jinde v aplikaci (`.table thead th`
   z §6 má `nowrap` a vyšší specificitu než uvolnění v pásmu do 992 px), takže
   tabulka s mnoha sloupci roste podle NADPISŮ, ne podle hodnot. U historie
   odečtů to znamenalo 63 px mimo obraz na 1440 px a 358 px na 768 px:
   „Celkem černobílých stránek" je čtyřikrát širší než číslo pod ním.
   Třída je vědomě opt-in — plošně by přeskládala hlavičky i tam, kam FÁZE 2
   nesahá. Další dávky si ji přiberou, kde ji potřebují. */
.pp-head-wrap thead th { white-space: normal; }

/* ===========================================================================
   18. PRŮVODCE NABÍDKOU A PODLAHY MARŽE (crm/ — FÁZE 1 kola CRM)
   =========================================================================== */

/* Podlaha marže u pole, ve kterém se navýšení zadává. Do téhle fáze se o ní
   člověk dozvěděl až z blokovaného PDF, tedy až po celé nabídce.

   Klidné znění je obyčejná vysvětlující věta (`.explain` z §3), varovné bere
   barvu ze stavu SCHVALOVÁNÍ (§7, `--pp-appr-pending`) — je to totiž přesně
   ten stav, do kterého se varianta uloženým podkročením dostane. Vlastní
   barva by se s odznakem v hlavičce sloupce matice rozešla. */
.pp-floor {
    display: block;
    font-size: var(--pp-text-sm);
    line-height: var(--pp-lh-loose);
    max-width: 46ch;
    margin-top: var(--sp-1);
}
.pp-floor-ok { color: var(--pp-ink-3); }
.pp-floor-warn {
    display: block;
    color: var(--pp-appr-pending);
    background: var(--pp-appr-pending-bg);
    border-radius: var(--pp-radius-sm);
    padding: var(--sp-1) var(--sp-2);
    font-weight: var(--pp-weight-medium);
}
.pp-floor-warn .ti { vertical-align: -0.15em; margin-right: var(--sp-1); }

/* Nadpis sekce formuláře je popisek, ne řádek s tlačítkem — jenže „pokročilé"
   se otevírá právě z něj. Čára za nadpisem (`::after` z §17) by tlačítko
   odstrčila k pravému okraji, proto tady mezera mezi prvky a čára až za nimi. */
.pp-form-section-title .btn { text-transform: none; letter-spacing: 0; }
.pp-form-section-title .badge { text-transform: none; letter-spacing: 0; }

/* ===========================================================================
   19. NABÍDKA PRO ZÁKAZNÍKA (crm/offer-customer — FÁZE 7 kola CRM)
   ---------------------------------------------------------------------------
   Jediná obrazovka aplikace, kterou vidí NĚKDO ZVENKU. Nemá kolej, topbar ani
   nabídku — jen dokument uprostřed stránky.

   A právě proto tady vrstvení z DNA §4 dává smysl v plné míře: hlavička je
   jediná plocha dokumentu, kde se má poznat, kdo nabídku posílá, a `--pp-hero`
   je na to táž hloubka jako na přihlašovací obrazovce (§15). Pod tabulkou
   s cenami žádná není — tam by ubírala čitelnost.

   Papírová estetika je zakázaná (DNA §4, §7 zákazů): žádný serif, žádné
   dvojité linky, žádná bílá plocha s ostrými rohy „jako výkaz". Dokument se
   čte na obrazovce a vypadá jako zbytek systému — jen bez ovládání.
   =========================================================================== */
.pp-offer-page { background: var(--pp-bg); color: var(--pp-ink); min-height: 100vh; }

.pp-offer-card { overflow: hidden; }
.pp-offer-head {
    padding: var(--sp-5);
    background: var(--pp-hero);
    border-bottom: 1px solid var(--pp-hero-line);
}
/* Hlavička firmy a číslo nabídky na jedné lince; na úzkém okně pod sebou,
   protože adresa firmy se do poloviny 768 px nevejde. */
.pp-offer-head-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-3);
}
.pp-offer-vendor { display: flex; align-items: flex-start; gap: var(--sp-3); min-width: 0; }
.pp-offer-logo { max-height: 2.75rem; max-width: 11rem; object-fit: contain; }
.pp-offer-vendor-name {
    font-size: var(--pp-text-md);
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink);
}
.pp-offer-vendor-line {
    font-size: var(--pp-text-sm);
    line-height: var(--pp-lh-base);
    color: var(--pp-ink-2);
}
.pp-offer-ident { text-align: right; margin-left: auto; }
/* Číslo nabídky je identifikátor (DNA §5) — mono, ne ozdobný nadpis. Zákazník
   ho opisuje do objednávky, takže se musí dát přečíst po znacích. */
.pp-offer-number {
    font-size: var(--pp-text-lg);
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink);
}
.pp-offer-title {
    margin: var(--sp-4) 0 0;
    font-size: var(--pp-text-xl);
    font-weight: var(--pp-weight-bold);
    line-height: var(--pp-lh-tight);
    color: var(--pp-ink);
}
.pp-offer-lead {
    margin-top: var(--sp-2);
    font-size: var(--pp-text-sm);
    line-height: var(--pp-lh-loose);
    color: var(--pp-ink-2);
}
.pp-offer-foot {
    font-size: var(--pp-text-sm);
    line-height: var(--pp-lh-loose);
    color: var(--pp-ink-3);
    max-width: 78ch;
}

/* ===========================================================================
   20. CRM PŘEHLED — TRYCHTÝŘ (crm/dashboard — FÁZE 8 kola CRM)
   ---------------------------------------------------------------------------
   Do téhle fáze kreslil CRM přehled win-rate jako PRSTENEC a celý svůj vzhled
   si vezl v `<style>` uvnitř šablony: vlastní písmo z Google Fonts, dvacet
   hexů, vlastní karta se zaoblením 20 px. Bylo to jediné místo v aplikaci,
   které porušovalo tři zákazy z §7 najednou (CDN písmo, koláčový graf, barva
   zapsaná rukou) — a zároveň jediné, kde by se to nasazením CSP bez
   `'unsafe-inline'` tiše rozsypalo.

   Trychtýř je proto obyčejná řada vodorovných pruhů z §12 (`.pp-bar-track`,
   `.pp-bar-fill`), jen se stupni pod sebou a s hlavičkou nad každým z nich.
   Nová je jen sazba stupně; barvu, poloměr ani písmo si tenhle blok nedefinuje.
   =========================================================================== */
.pp-funnel {
    list-style: none;
    margin: 0 0 var(--sp-3);
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}
.pp-funnel-step { min-width: 0; }
.pp-funnel-head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--sp-1) var(--sp-2);
    margin-bottom: var(--sp-1);
}
.pp-funnel-name {
    font-size: var(--pp-text-md);
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Peníze doprava a tabulkově — fáze se čtou pod sebou a nezarovnané číslice
   se porovnávat nedají (DNA §7). */
.pp-funnel-value {
    margin-left: auto;
    font-size: var(--pp-text-md);
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.pp-funnel-note {
    margin-top: var(--sp-1);
    font-size: var(--pp-text-sm);
    color: var(--pp-ink-3);
    font-variant-numeric: tabular-nums;
}
/* Stupeň trychtýře je vyšší než pruh v §12: čte se jako samostatná položka,
   ne jako řádek legendy. */
.pp-funnel .pp-bar-track { height: 0.7rem; }

/* ===========================================================================
   21. SMLOUVA (contracts/ — dávka 2, část 1 plošného průchodu)
   ---------------------------------------------------------------------------
   Detail smlouvy jede na vzoru z §17 (komponovaný souhrn nahoře, hutné záložky
   dole) a nová třída k tomu potřeba nebyla — kromě jedné: srovnání
   fakturačních modelů ve formuláři řádku.

   Modely se totiž nevybírají přečtením toho jednoho, který je zrovna vybraný,
   ale porovnáním všech tří: „paušál s minimem" nikomu neřekne, že se
   nevytištěné stránky nevracejí, dokud nestojí vedle „standardu", kde se platí
   jen to, co se opravdu vytisklo. Je to definiční seznam (`dl`), protože to
   definiční seznam opravdu je — název modelu a věta, co znamená pro fakturaci.
   =========================================================================== */
.pp-model-guide {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--sp-2) var(--sp-4);
    margin: 0;
}
.pp-model-guide dt {
    font-size: var(--pp-text-md);
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink);
    margin-bottom: 0.1rem;
}
/* Věta pod názvem je `.explain` (§3), tady se jen ruší odsazení, které `dd`
   dědí po prohlížeči — jinak by seznam vypadal jako citace. */
.pp-model-guide dd { margin: 0; }

/* Popisek nad klíčovým číslem byl do dávky 2 části 1 vázaný na mřížku souhrnu
   (`.pp-detail-summary .pp-metric-label`, §17). Záložky smlouvy ho potřebují
   i samostatně — v čele záložky stojí JEDNO číslo, ne mřížka —, takže se
   pravidlo z mřížky VYZVEDLO na globální a scoped verze se smazala: měla pět
   týchž deklarací, takže neměla co přidat ani přebít. Vyzvednutí platí i tam,
   kde mřížka je (souhrn detailu zařízení, smlouvy, období i dokladu) —
   vzhled se tím nemění, mění se jen to, odkud pravidlo přichází. */
.pp-metric-label {
    font-size: var(--pp-text-xs);
    font-weight: var(--pp-weight-semibold);
    text-transform: uppercase;
    letter-spacing: var(--pp-tracking-caps);
    color: var(--pp-ink-3);
}

/* ===========================================================================
   22. FAKTURACE A DOKLADY (fakturace, billing-documents/, cycle_show —
       dávka 2, část 2 plošného průchodu)
   ---------------------------------------------------------------------------
   Dávka nepotřebovala novou kompozici: board fakturace i detail cyklu jedou na
   vzoru z §17 (komponovaný souhrn nahoře, hutné tabulky dole) a stavy berou
   sémantické tokeny z §3.4, které pro ně existovaly od FÁZE 2, jen je do téhle
   chvíle nikdo nepoužil.

   Zbyla jediná věc, která do stylopisu opravdu patřila: dvě pole, jejichž
   šířku si šablony nesly v `style="width:…"`. Inline šířka není barva, takže by
   ji `grep` na hex nechytil — ale je to totéž provinění: hodnota kompozice
   zapsaná v šabloně, kterou nejde změnit na jednom místě. Obě pole jsou
   ČÍSELNÁ nebo krátká textová, takže široká být nemají: v hutné tabulce roztáhne
   pole na plnou šířku sloupec a s ním celou tabulku za kraj karty.
   =========================================================================== */
.pp-input-counter { max-width: 8rem; }
.pp-input-note { min-width: 10rem; }

/* Popis položky dokladu se zalamuje. `.table-dense` dává všem buňkám `nowrap`
   (§6), takže „Pronájem, Canon i-SENSYS MF445dw (01. 06. – 30. 06.)" na jedné
   lince roztáhl sloupec na 647 px v kartě široké 771 px. Doklad má řádků
   jednotky, ne stovky — dvouřádkový popis je levnější než ustřižený.

   Specificita je vědomě dvoutřídní: `.table-dense td` z §13 je (0,1,1),
   takže samotné `.pp-desc-cell` by prohrálo a buňka by se dál nezalomila. */
/* Spodní mez je 9 rem, ne 12: na 768 px má karta dokladu 494 px vnitřní šířky
   a pět číselných sloupců si vezme 317 z nich — dvanáct rem popisu by ji
   přetáhlo o 14 px. */
.table-dense .pp-desc-cell { white-space: normal; min-width: 9rem; }

/* Nadpis stránky se smí zalomit. Tablerova `.page-title` je řádkový flex
   (`display: flex; align-items: center`) BEZ zalomení, takže odznak stavu vedle
   nadpisu zůstane na první lince i tehdy, když se sám nadpis na dvě linky zalomí
   — a vyteče ze svého sloupce pod tlačítka akcí. Naměřeno na 768 px u detailu
   fakturačního období („Fakturační období #105" + odznak „Otevřené"): odznak byl
   z poloviny schovaný pod tlačítkem „Zpět na smlouvu". `pageOverflow` přitom mlčí,
   protože stránka jako celek se nehne — je to překryv, ne přetečení.

   Odznak stavu vedle nadpisu je od dávky 1 vzor pro každý detail, takže pravidlo
   patří do sdílené vrstvy, ne do jedné šablony. */
.page-title { flex-wrap: wrap; }

/* ===========================================================================
   23. ODEČTY A IMPORTY (odecty/, meter_readings/, imports/ — dávka 5)
   ---------------------------------------------------------------------------
   Dávka nová kompozici nepotřebovala: fronta e-mailů i výpis odečtů jedou na
   vzoru z §13 (hutný seznam se souhrnem v čele), detail návrhu na vzoru z §17
   (komponovaný souhrn nahoře, hutné tabulky dole) a stavy berou novou rodinu
   `--pp-mail-*` z §7. Zbyly tři věci, které se bez stylopisu udělat nedaly.
   =========================================================================== */

/* 1. Surové tělo e-mailu. Do dávky si ho šablona vezla ve
   `style="max-height: 500px; overflow-y: auto; white-space: pre-wrap"` —
   tedy tři hodnoty kompozice zapsané v Blade, které nejde změnit na jednom
   místě. Je to jediné místo v aplikaci, kde se ukazuje cizí text, nad kterým
   nemáme kontrolu: musí se zalamovat (jinak roztáhne kartu za kraj obrazovky
   jediným dlouhým řádkem hlavičky) a musí mít strop výšky (jinak je pod ním
   zbytek detailu nedosažitelný). */
.pp-raw-mail {
    max-height: 22rem;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
    font-family: var(--pp-font-mono);
    font-size: var(--pp-text-xs);
    line-height: var(--pp-lh-base);
    color: var(--pp-ink-2);
    background: var(--pp-surface-3);
    border-radius: var(--pp-radius-md);
    padding: var(--sp-3);
    margin: 0;
}

/* 2. Náhled importu — jediná tabulka aplikace, jejíž sloupce určuje CIZÍ
   soubor. Zákaznický importér jich zná dvacet, takže „vejde se to" není otázka
   šířky karty, ale otázka toho, co dělá uživatel: čte řádek, který spadl, a
   hledá v něm sloupec, kvůli kterému spadl. Vodorovný posun je proto ZÁMĚR
   (§4.4 — značka `data-pp-scroll="x"`), ale platí za něj tutéž cenu jako
   matice: první dva sloupce (číslo řádku a stav) se ukotví, jinak po odjetí
   doprava nikdo neví, ke kterému řádku ta hodnota patří.

   Chybový sloupec ukotvený není: leží vpravo, a kdo si ho chce postavit vedle
   hodnoty, ten se k němu posune. Zato se zalamuje — hláška „recorded_at musí
   být ve tvaru YYYY-MM-DD" je věta, ne identifikátor. */
.pp-preview th.pp-preview-num,
.pp-preview td.pp-preview-num,
.pp-preview th.pp-preview-state,
.pp-preview td.pp-preview-state {
    position: sticky;
    background: var(--pp-surface);
    z-index: 1;
}
.pp-preview th.pp-preview-num,
.pp-preview td.pp-preview-num { left: 0; width: 3.5rem; }
.pp-preview th.pp-preview-state,
.pp-preview td.pp-preview-state {
    left: 3.5rem;
    box-shadow: 1px 0 0 var(--pp-line);
}
.pp-preview thead th.pp-preview-num,
.pp-preview thead th.pp-preview-state { background: var(--pp-surface-2); z-index: 2; }
/* Řádek s chybou se nepodbarvuje Tablerovou `.table-danger`, ale tokenem —
   a jen levou linkou. Celý řádek načervenalý přebije v hutné tabulce úplně
   všechno včetně hodnot, které jsou v pořádku. */
.table tr.is-error td { background: var(--pp-danger-soft); }
.pp-preview tr.is-error td.pp-preview-num {
    box-shadow: inset 3px 0 0 var(--pp-danger);
}
.pp-preview tr.is-duplicate td { color: var(--pp-ink-3); }
/* Přepínač „jen chyby" schovává řádky atributem `hidden`, ne inline stylem —
   ať se dá stav přečíst z DOM (brána ho měří) a ať se nemíchá s ničím, co
   šablona nastavuje. Bootstrapí reboot `[hidden]` řeší, ale spoléhat se na
   cizí reset u věci, kterou hlídá kontrola, se nevyplácí. */
.pp-preview tr[hidden] { display: none; }
.pp-preview .pp-preview-why {
    white-space: normal;
    min-width: 14rem;
    color: var(--pp-danger);
    font-size: var(--pp-text-sm);
}

/* 3. Legenda stavů. Fronta e-mailů má sedm stavů a pět barev (§7), takže
   „co ta barva znamená" musí být na obrazovce napsané — jinak je to hádanka,
   kterou vyhraje jen ten, kdo aplikaci psal. Je to řádek štítků, ne tabulka:
   čte se jednou a pak už jen okrajem oka. */
.pp-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2) var(--sp-4);
    font-size: var(--pp-text-sm);
    color: var(--pp-ink-2);
}
.pp-legend-item { display: inline-flex; align-items: center; gap: var(--sp-1); }

/* ===========================================================================
   24. SKLAD — FORMULÁŘE A DETAIL OBJEDNÁVKY (warehouse/… — dávka 6, část 2)
   ---------------------------------------------------------------------------
   Druhá polovina dávky 6 jsou obrazovky, na kterých se ROZHODUJE: co se zapíše
   do knihy, co se stane s kusem, kdy se položka začne hlídat. Kompozice jede
   na vzoru z §17 (sekce popiskem s linkou, ne nadpisem) a nová třída k tomu
   nebyla potřeba — až na jednu věc, kterou Tabler neumí.

   `.pp-choice` je volba, u které se každá možnost PŘEDSTAVÍ VĚTOU. Dřív to byl
   `btn-group` (pohyby) a `select` (výdej stroje): u obojího se název možnosti
   vešel, ale důsledek ne — a přitom právě důsledek je ta informace. „Inventura"
   nikomu neřekne, že se do pole píše NAPOČÍTANÝ STAV, ne rozdíl; „Pronájem"
   neřekne, že tím vznikne spravovaná tiskárna u zákazníka. Čtyři, resp. pět
   možností v jednom řádku tlačítek se navíc na 768 px nevejde.

   Je to mřížka, ne řada: `auto-fit` srovná možnosti do sloupců, dokud se vejdou
   po 13 rem, a pod tím je poskládá pod sebe. Vstup je schovaný, ne vypnutý —
   `:focus-visible` na něm překresluje prstenec obalu, takže klávesnice funguje
   jako u nativního přepínače (fokus se podle §3.6 nikdy neruší, jen kreslí).
   =========================================================================== */
.pp-choice {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--sp-2);
}
.pp-choice-option { display: block; margin: 0; cursor: pointer; }
.pp-choice-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}
.pp-choice-body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    height: 100%;
    padding: var(--sp-3);
    border: 1px solid var(--pp-line);
    border-radius: var(--pp-radius-md);
    background: var(--pp-surface);
}
.pp-choice-option:hover .pp-choice-body { border-color: var(--pp-line-strong); }
.pp-choice-input:checked + .pp-choice-body {
    border-color: var(--pp-brand);
    background: var(--pp-brand-soft);
    box-shadow: var(--pp-shadow-xs);
}
.pp-choice-input:focus-visible + .pp-choice-body { box-shadow: var(--pp-ring); }
.pp-choice-name {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink);
}
.pp-choice-input:checked + .pp-choice-body .pp-choice-name { color: var(--pp-brand); }
.pp-choice-note {
    font-size: var(--pp-text-sm);
    line-height: var(--pp-lh-loose);
    color: var(--pp-ink-2);
}

/* Výsledek asynchronní akce pod polem (dohledání v ARESu). Do téhle dávky si
   ho šablona barvila Tablerovým `text-danger` / `text-success`, tedy paletou
   místo sémantiky — týž tvar, jaký dávka 6 část 1 vymýtila z odznaků. Rodina
   je stejná jako u stavů (§3.3), takže se mění na jednom místě.
   Dvě třídy schválně: `.form-hint` z Tableru má (0,1,0) a jednotřídní pravidlo
   by s ním prohrálo na pořadí, ne na síle. */
.form-hint.pp-hint-ok  { color: var(--pp-success); }
.form-hint.pp-hint-bad { color: var(--pp-danger); }

/* Příjem řádku objednávky bydlí V ŘÁDKU tabulky a veze tři ovládací prvky
   (kolik, kam, potvrdit). V hutné tabulce je to nejširší buňka obrazovky:
   na 768 px si tři prvky vedle sebe berou 316 px z 688, takže by tabulku
   protlačily za kraj karty a ustřihly by pravý sloupec.

   Řešení není posuvník, ale zalomení: `flex-wrap` nechá „kolik + potvrdit" na
   první lince a sklad spadne pod ně, jakmile místo dojde. Buňka proto ruší
   `nowrap` z §13 (dvoutřídní specificita, `.table-dense td` je (0,1,1)). */
.pp-receive {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-1);
}
.table-dense td.pp-receive-cell { white-space: normal; }
.pp-input-qty { max-width: 6rem; }
.pp-receive-where { min-width: 9rem; flex: 1 1 9rem; }

/* ===========================================================================
   25. PRINT ASSESSMENT — PRŮVODCE (print-assessment/wizard/… — dávka 7, část 1)
   ---------------------------------------------------------------------------
   Průvodce je sedm obrazovek, které sbírají vstupy do JEDNÉ kalkulačky, a její
   výsledek jde ven jako PDF pro zákazníka. Celá dávka stojí na jedné větě:
   CHYBĚJÍCÍ VSTUP SE TU NECHOVÁ JAKO CHYBĚJÍCÍ. Stroj bez faktury vrátí
   `monthly_cost = 0`, barevná stránka bez čtyř tonerů vyjde na 0 Kč a scénář
   bez jediného stroje se v porovnání zobrazí jako stoprocentní úspora — a nic
   z toho nebylo do téhle dávky na obrazovce vidět.

   Nové třídy jsou tři a všechny nesou právě tenhle rozdíl:

   `.pp-wizard` je kolej kroků. Tablerovy `.steps` uměly říct, KDE stojíš, ale
   ne CO V KROKU JE — a přitom „krok 3" a „krok 3, ve kterém dva stroje ze čtyř
   nemají žádná data" jsou dvě úplně jiné situace. Každý krok proto nese číslo,
   jméno a údaj; kroky, které kalkulaci nechávají díru, k tomu tečku rodiny
   `--pp-est-*`. Je to mřížka, ne řada: sedm kroků se na 768 px do jedné linky
   nevejde v čitelné velikosti ani teoreticky.

   `.pp-swap` je dlaždice „dnes → nabízíme" pro živou kalkulačku. Rozdíl mezi
   dvěma čísly je ta informace, kvůli které obrazovka existuje, takže stojí
   vpravo jako vlastní údaj — ne jako přebarvené druhé číslo.

   `.pp-checklist` je soupis toho, co do reportu půjde a co v něm bude nula.
   Tečka je stav, věta je důsledek; bez věty by z toho byl jen seznam fajfek.
   =========================================================================== */
.pp-wizard {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
    gap: var(--sp-2);
    list-style: none;
    margin: 0;
    padding: 0;
}
.pp-wizard-step {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding: var(--sp-2) var(--sp-3);
    border: 1px solid var(--pp-line);
    border-top: 3px solid var(--pp-line-strong);
    border-radius: var(--pp-radius-md);
    background: var(--pp-surface);
    color: inherit;
    text-decoration: none;
}
/* Hover nesahá na horní linku — ta nese stav kroku, ne zvýraznění. */
a.pp-wizard-step:hover {
    border-inline-color: var(--pp-line-strong);
    border-bottom-color: var(--pp-line-strong);
    background: var(--pp-surface-2);
}
.pp-wizard-step.is-done { border-top-color: var(--pp-success); }
.pp-wizard-step.is-current {
    border-top-color: var(--pp-brand);
    background: var(--pp-brand-soft);
    box-shadow: var(--pp-shadow-xs);
}
/* `.is-locked` (krok, na který se u nové analýzy ještě nedá jít) tu byl do
   FÁZE 12 a nikdy se nevykreslil: kolej se u nové analýzy neincluduje vůbec.
   Pravidlo i větev v šabloně jsou pryč (nález `RV-916`). */
.pp-wizard-n {
    font-size: var(--pp-text-xs);
    letter-spacing: var(--pp-tracking-caps);
    text-transform: uppercase;
    color: var(--pp-ink-3);
}
.pp-wizard-step.is-current .pp-wizard-n { color: var(--pp-brand); }
.pp-wizard-name {
    font-size: var(--pp-text-sm);
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink);
}
.pp-wizard-note {
    font-size: var(--pp-text-xs);
    line-height: var(--pp-lh-base);
    color: var(--pp-ink-2);
    font-variant-numeric: tabular-nums;
}

.pp-swap {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--sp-2);
    height: 100%;
    padding: var(--sp-3);
    border: 1px solid var(--pp-line);
    border-radius: var(--pp-radius-md);
    background: var(--pp-surface-2);
}
.pp-swap.is-total { border-color: var(--pp-line-strong); background: var(--pp-surface-3); }
.pp-swap-label {
    font-size: var(--pp-text-xs);
    letter-spacing: var(--pp-tracking-caps);
    text-transform: uppercase;
    color: var(--pp-ink-3);
}
.pp-swap-from { font-size: var(--pp-text-sm); color: var(--pp-ink-3); font-variant-numeric: tabular-nums; }
.pp-swap-to {
    font-size: var(--pp-text-md);
    font-weight: var(--pp-weight-semibold);
    color: var(--pp-ink);
    font-variant-numeric: tabular-nums;
}
.pp-swap-delta {
    text-align: right;
    font-size: var(--pp-text-sm);
    font-weight: var(--pp-weight-semibold);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.pp-swap-delta.is-down { color: var(--pp-success); }
.pp-swap-delta.is-up { color: var(--pp-danger); }

.pp-checklist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.pp-checklist li { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-2); align-items: start; }
.pp-checklist .state-dot { margin-right: 0; margin-top: 0.4rem; }
.pp-checklist-text {
    font-size: var(--pp-text-sm);
    line-height: var(--pp-lh-loose);
    color: var(--pp-ink-2);
}
.pp-checklist-text strong { color: var(--pp-ink); font-weight: var(--pp-weight-semibold); }

/* Logo zákazníka se tiskne na titulní stranu reportu, takže se ukazuje i tady
   — a rozměr náhledu patří do stylopisu, ne do `style=` v šabloně. */
.pp-logo-preview {
    max-height: 3.25rem;
    max-width: 9.5rem;
    object-fit: contain;
    padding: var(--sp-1);
    border: 1px solid var(--pp-line);
    border-radius: var(--pp-radius-sm);
    background: var(--pp-surface);
}

/* ===========================================================================
   26. PRINT ASSESSMENT — VÝSTUPY A ZÁZNAMY (print-assessment/… — dávka 7, část 2)
   ---------------------------------------------------------------------------
   Druhá polovina modulu je výpis, detail a čtyři formuláře podřízených
   záznamů. Nová třída pro ni potřeba nebyla — hutný registr, souhrn v čele,
   `.pp-choice` u volby, `.pp-checklist` u důsledků i `.pp-well` u vzorníku
   uměl systém už z dávek 6 a 7 části 1. Přibyla jediná rodina tokenů
   (`--pp-pa-*`, viz §3.4) a jedna vlastnost, kterou nešlo vzít odjinud:

   Poznámka k analýze je volný text, ve kterém obchodník ODŘÁDKOVAL schválně
   („rozhoduje jednatelka / rozpočet se schvaluje na konci čtvrtletí"). Do
   FÁZE 10 to řešil `style="white-space: pre-line"` přímo v šabloně, tedy
   pravidlo zapsané v Blade místo ve stylopisu (§7). Je to jedno pravidlo,
   ne komponenta, takže nemá vlastní blok.
   =========================================================================== */
.pp-pre-line { white-space: pre-line; }

/* ===========================================================================
   27. REPORTY A ADMINISTRACE (reports/, admin/, users/, roles/, settings/,
       audit/, profile/ — dávka 8)
   ---------------------------------------------------------------------------
   Dávka osm je z devadesáti procent složená z toho, co systém uměl: hutný
   registr, souhrn v čele, `.pp-form-section` u formulářů, `.pp-choice` u volby
   role, `.pp-checklist` u důsledků, `.pp-facts` u matice práv. Přibyly tři
   rodiny tokenů (§3.4) a čtyři pravidla, která nešlo vzít odjinud:

   1. práh v grafu (`.pp-chart-limit`, `.pp-chart-limit-label` — u grafu v §12,
      protože patří ke kresbě, ne k téhle dávce),
   2. pruh, jehož barvu určuje stav na obalu (`.pp-bar-state`, tamtéž v §12),
   3. náhled loga — jediné místo, kde měly obě šablony rozměr zapsaný
      v `style=` (§7 zákazů: rozměr patří do stylopisu),
   4. rozbalovací detail v hutném řádku: `<summary>` bez ukazováčku vypadá
      jako běžný text a nikoho nenapadne na něj kliknout. Bylo to
      `style="cursor:pointer"` v šabloně auditu.
   =========================================================================== */
.pp-logo-preview {
    max-width: 100%;
    max-height: 10rem;
    object-fit: contain;
}

details > summary {
    cursor: pointer;
    list-style: revert;
}
details > summary:focus-visible { outline: none; box-shadow: var(--pp-ring); border-radius: var(--pp-radius-sm); }

/* Identifikátor v úzké buňce faktů se musí zalomit. `.pp-facts` má sice
   `white-space: normal`, jenže IBAN zapsaný bez mezer je JEDNO slovo — dvacet
   čtyři znaků mono písma dá 190 px a v třetinové kartě na 768 px roztáhne
   tabulku o třicet přes kraj. Je to táž past jako `.pp-matrix-rowhead` v §4.4:
   zalomení se povoluje tam, kde se ta hodnota opravdu čte, ne globálně —
   v hutném seznamu má identifikátor zůstat na jedné lince. */
.pp-facts .ident { overflow-wrap: anywhere; }

/* Matice práv je hutná tabulka s vysvětlující větou v prvním sloupci, takže
   potřebuje obojí naráz: těsné řádky (`.table-dense`) a zalomení (`.pp-facts`).
   Věta pod jménem modulu je `.explain`, ta má `max-width: 46ch` — v buňce
   s `nowrap` by se ale nezalomila vůbec (táž past jako `.pp-matrix-headnote`
   v §4.4), a proto ta dvojice tříd. Zbytek je jen odsazení popisku od
   zaškrtávátka. */
.pp-facts td .explain,
.pp-facts th .explain { margin-top: 0.15rem; }
