@charset "utf-8";
/* ==== css/pf/compat.legacy.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Legacy Compatibility Shim
   ────────────────────────────────────────────────────────────────────
   Maps legacy token systems (--platforma-*, --se-*, --chub-*,
   --tenant-*) to their PF semantic equivalents. This file is the
   migration bridge: it allows existing component CSS to gain
   theme-awareness WITHOUT being refactored.

   How it works:
     1. tokens.semantic.css declares --pf-color-surface-base etc.
     2. themes.dark.css overrides the SEMANTIC tokens when dark.
     3. compat.legacy.css aliases --platforma-white → --pf-color-surface-raised.
     4. Existing CSS using `var(--platforma-white)` now follows theme.

   IMPORTANT — Maintenance rules:
     ✗ NEVER add NEW component CSS that references legacy tokens.
       Always use --pf-color-* directly in new code.
     ✓ This file is FROZEN — only add aliases when discovering an
       uncovered legacy token still in use.
     ✓ Migration goal: delete this file when zero --platforma-*,
       --se-*, --chub-*, --tenant-* references remain in component CSS.

   Mapping rationale:
     • Legacy tokens often described APPEARANCE (parchment-50, ink-900).
       PF tokens describe INTENT (surface-base, text-primary).
     • The mapping captures original semantic meaning. Where ambiguity
       exists (e.g. parchment-50 used as both "page bg" and "card bg"),
       we map to the most common usage and add a comment for follow-up.

   Categories:
     A. --platforma-* core tokens     (admin chrome, marketing)
     B. --se-*       editor tokens    (CMS editor chrome — DARK.1-6)
     C. --chub-*     public site      (community-hub template)
     D. --tenant-*   brand override   (per-tenant theming — kept as-is,
                                       handled by TenantBranding component)

   Version: 1.0.0
   Last revised: 2026-05-09
   ──────────────────────────────────────────────────────────────────── */

/* SPECIFICITY BOOST (defense-in-depth — wins regardless of load-order):
     html[lang]   = element + attribute = 0,1,1   — <html> always has lang
     html:root    = element + pseudo    = 0,1,1   — <html> always matches :root
     :root        = pseudo only         = 0,1,0   — fallback (lowest priority)
   Both 0,1,1 selectors beat platforma-tokens.css's plain `:root` (0,1,0)
   even if load-order is somehow wrong. Comma-separated so the highest-
   specificity match wins for the actual root element.

   THIS IS LOAD-ORDER INDEPENDENT — even with aggressive browser caching
   or hot-reload race conditions, this declaration will out-rank the
   hardcoded values in platforma-tokens.css because of higher specificity. */
html[lang],
html:root,
:root {
    /* ═════════════════════════════════════════════════════════════
       A. PLATFORMA — Core tokens (admin chrome + marketing)
       ═════════════════════════════════════════════════════════════ */

    /* Surface anchors */
    --platforma-white:           var(--pf-color-surface-raised);

    /* DL-12 — phantom surface tokens: authored against a vocabulary that
       never existed, so `var(--platforma-surface, #fff)` degraded to the
       light literal in every theme (white-on-white card regression, DL-02).
       Aliased here so their consumers (tenant-issued, tables, cms-editor,
       tenant-admin-settings, tenant-control-center) follow theme unedited. */
    --platforma-surface:           var(--pf-color-surface-raised);
    --platforma-surface-elevated:  var(--pf-color-surface-warm-deep);
    --platforma-card-bg:           var(--pf-color-surface-raised);
    --platforma-bg-subtle:         var(--pf-color-surface-sunken);
    /* PHANTOM-TEXT-1 (SA-14a, 2026-09-27) — the same defect class as DL-12, for a text and a line
       token. MEASURED in the browser: --platforma-muted and --platforma-hair resolve to the empty
       string on every admin page, yet var(--platforma-muted) is written 246 times (56 files) WITHOUT a fallback.
       An unresolvable var() in `color` is invalid-at-computed-value-time, so every "muted" caption,
       meta line and unit silently INHERITED its parent's colour — the Plans "DKK/mo" unit inherited
       the red figure beside it (2.85:1 in dark). --platforma-hair did worse: `border-bottom: 1px solid
       var(--platforma-hair-2, var(--platforma-hair))` drops the whole declaration, so the operator
       dashboard's row dividers and bar/meter tracks were never drawn.
       muted → the text-secondary role, the one --platforma-ink-muted already uses: AA on every
       surface in both themes (9.39:1 even on the help panel's pale tint, where tertiary measures
       4.32:1), and the smallest visual step from the inherited colour these 246 sites render today.
       The ~20 call sites that carried an explicit gray-600 / #6b7280 fallback move from tertiary to
       secondary — one step darker, never lighter. --platforma-hair-2 stays undeclared on purpose:
       every use falls back to -hair, and inventing a second hairline would be a design decision. */
    --platforma-muted:             var(--pf-color-text-secondary);
    --platforma-hair:              var(--pf-color-border-subtle);
    --platforma-gray-50:         var(--pf-color-surface-base);
    --platforma-gray-100:        var(--pf-color-surface-sunken);
    --platforma-gray-200:        var(--pf-color-border-subtle);
    --platforma-gray-300:        var(--pf-color-border-strong);
    --platforma-gray-400:        var(--pf-color-text-disabled);
    --platforma-gray-500:        var(--pf-color-text-tertiary);
    --platforma-gray-600:        var(--pf-color-text-tertiary);
    --platforma-gray-700:        var(--pf-color-text-secondary);
    --platforma-gray-800:        var(--pf-color-text-primary);
    --platforma-gray-900:        var(--pf-color-text-primary);

    /* Parchment family (cream-tinted neutrals — admin classic look)
       Mapped to PF semantic tokens so dark theme switches automatically. */
    --platforma-parchment-50:    var(--pf-color-surface-base);
    --platforma-parchment-100:   var(--pf-color-surface-sunken);
    --platforma-parchment-200:   var(--pf-color-border-subtle);
    --platforma-parchment-300:   var(--pf-color-border-strong);

    /* Ink family (text colors — classic typography hierarchy) */
    --platforma-ink:             var(--pf-color-text-primary);
    --platforma-ink-900:         var(--pf-color-text-primary);
    --platforma-ink-strong:      var(--pf-color-text-primary);
    --platforma-ink-primary:     var(--pf-color-text-primary);
    --platforma-ink-muted:       var(--pf-color-text-secondary);
    --platforma-ink-subtle:      var(--pf-color-text-tertiary);

    /* Line family (borders, dividers) */
    --platforma-line-50:         var(--pf-color-border-subtle);
    --platforma-line-100:        var(--pf-color-border-subtle);
    --platforma-line-200:        var(--pf-color-border-strong);
    --platforma-border:          var(--pf-color-border-strong);

    /* Brand (Platforma red — distinct admin/marketing identity)
       Brand color is INTENTIONALLY not theme-switched — Platforma red
       remains red in dark mode. Only foreground variants adjust. */
    --platforma-brand:           var(--pf-color-action-primary);
    --platforma-brand-pressed:   var(--pf-color-action-primary-pressed);
    --platforma-brand-soft:      var(--pf-color-action-primary-soft);
    --platforma-brand-dark:      var(--pf-color-action-primary-pressed);
    --platforma-brand-on-dark:   var(--pf-color-text-on-action);
    --platforma-brand-glow:      rgb(99 102 241 / 0.22);

    /* Accent — deep scandinavian NAVY (#2E5C8A): the Parchment/Ink accent for
       CTAs and chrome actions.
       CONSIST-3b (2026-09-09) BUGFIX: this family was wrongly bound to
       var(--pf-color-action-primary) — the RED brand primary — a copy-paste
       from the brand block above. Because compat.legacy loads AFTER
       platforma-tokens.css (which correctly sets --platforma-accent: #2E5C8A),
       the red clobbered the navy at :root, and since --platforma-chrome-action
       is var(--platforma-accent) the ENTIRE navy chrome-action system
       (LP-11) resolved RED app-wide (links, chips, tabs, accent surfaces,
       non-themed primary buttons, the CMS editor). Grounded to the navy hex
       directly, matching tokens.css; dark mode is handled by platforma-theme.css.
       Brand stays red (the block above, correctly bound to action-primary). */
    --platforma-accent:          #2E5C8A;
    --platforma-accent-soft:     #E8EEF5;
    --platforma-accent-border:   #C7D6E5;
    --platforma-accent-ink:      #1B3D5E;

    /* Status family */
    --platforma-success:         var(--pf-color-status-success);
    --platforma-success-soft:    var(--pf-color-status-success-soft);
    --platforma-warning:         var(--pf-color-status-warning);
    --platforma-warning-soft:    var(--pf-color-status-warning-soft);
    --platforma-danger:          var(--pf-color-status-danger);
    /* AUDIT-ALERT-1 (2026-09-16) — these two pointed at red-400 / sky-400, MID-TONE fills, while
       every consumer treats them as pale surfaces and pairs them with a dark --pf-color-status-*-fg.
       MEASURED in light theme, where nothing else has ever remapped them:
         .platforma-alert--danger  red-800 on red-400   3.00:1   FAILS AA
         .platforma-alert--info    sky-800 on sky-400   3.53:1   FAILS AA
       On the error messages themselves, in the theme most operators use.

       The call sites are unanimous about what they expected: every author who wrote a fallback
       wrote a PALE one — #FEE2E2 (platforma-buttons.css:315), #FFF5F8 / #F8F5FF
       (platforma-status.css:21,23), #EEE7FF (platforma-tenant-issued.css:101,299). Not one site
       wants a mid-tone. The alias was simply wrong, and the -light/-soft split it implied never
       existed in practice.

       Aliased to the -soft tokens rather than back to the old pastels, because those pastels were
       light-only literals: this makes the pair theme-aware in BOTH directions and restores the
       ~7:1 the -fg foregrounds were designed against. --platforma-warning-light is deliberately
       absent from this family and keeps its own pale value, which is why warnings never broke. */
    --platforma-danger-light:    var(--pf-color-status-danger-soft);
    --platforma-danger-soft:     var(--pf-color-status-danger-soft);
    --platforma-info:            var(--pf-color-status-info);
    --platforma-info-light:      var(--pf-color-status-info-soft);
    --platforma-info-soft:       var(--pf-color-status-info-soft);

    /* ── THEME-FALLBACK-1 (2026-09-17) — tokens the app REFERENCES and nothing DECLARED ──
       Found by closing an evasion path in ThemeReachableSurfacesAreTokenisedThemeSweep1Tests:
       the pin used to skip any value containing var(), on the reasoning that a token follows
       the theme. But `background: var(--platforma-success-50, #ecfdf5)` where the token is
       declared NOWHERE falls through to its literal on every single render — a light-only
       value that never flips, wearing the appearance of a token.

       23 such declarations across 11 files were rendering their fallback. The repair is to
       declare the names rather than rewrite the call sites: every one now points at a pf
       semantic role that already flips, so the fallback stops being reachable and the call
       sites need no edit at all.

       No !important and no dark block here, both on purpose. These names are declared nowhere
       else, so there is nothing to out-specify, and they inherit their theme behaviour through
       the pf token they alias. AUDIT-THEME-1's lesson was that an !important in this file beat
       platforma-theme.css's un-important dark declaration and silently flipped 38 backgrounds;
       nothing here can repeat that. */
    --platforma-amber-50:        var(--pf-color-status-warning-soft);
    --platforma-amber-200:       var(--pf-color-status-warning-border);
    --platforma-amber-700:       var(--pf-color-status-warning-fg);
    --platforma-warning-bg:      var(--pf-color-status-warning-soft);
    --platforma-warning-border:  var(--pf-color-status-warning-border);
    --platforma-warning-text:    var(--pf-color-status-warning-fg);

    --platforma-blue-50:         var(--pf-color-status-info-soft);
    --platforma-blue-200:        var(--pf-color-status-info-border);
    --platforma-blue-700:        var(--pf-color-status-info-fg);

    --platforma-danger-50:       var(--pf-color-status-danger-soft);
    --platforma-danger-200:      var(--pf-color-status-danger-border);
    --platforma-danger-700:      var(--pf-color-status-danger-fg);

    --platforma-success-50:      var(--pf-color-status-success-soft);
    --platforma-success-200:     var(--pf-color-status-success-border);
    --platforma-success-700:     var(--pf-color-status-success-fg);

    --platforma-surface-hover:   var(--pf-color-surface-hover);
    --platforma-surface-subtle:  var(--pf-color-surface-sunken);
    --platforma-bg-muted:        var(--pf-color-surface-sunken);
    --platforma-text:            var(--pf-color-text-primary);
    --platforma-text-muted:      var(--pf-color-text-secondary);
    --platforma-border-strong:   var(--pf-color-border-strong);
    --platforma-parchment-400:   var(--pf-color-border-strong);

    /* Brand, NOT themed — the block header above is explicit that brand colours are runtime
       tenant-themed via TenantBranding and must not be folded into the surface/text set. */
    --platforma-brand-primary:   var(--platforma-primary);
    --platforma-primary-tint:    color-mix(in srgb, var(--platforma-primary) 12%, var(--pf-color-surface-raised));

    /* Typography */
    --platforma-font-sans:       var(--pf-font-family-sans);
    --platforma-font-serif:      var(--pf-font-family-serif);
    --platforma-font-mono:       var(--pf-font-family-mono);
    --platforma-mono:            var(--pf-font-family-mono);
    --platforma-font-family:     var(--pf-font-family-sans);

    /* Spacing aliases (legacy s-N convention → PF space scale)
       Note: legacy s-2 was 8px = pf-space-2, s-3 = 12px = pf-space-3, etc. */
    --platforma-s-2:             var(--pf-space-2);
    --platforma-s-3:             var(--pf-space-3);
    --platforma-s-4:             var(--pf-space-4);
    --platforma-s-5:             var(--pf-space-5);
    --platforma-s-6:             var(--pf-space-6);
    --platforma-s-7:             var(--pf-space-7);
    --platforma-s-8:             var(--pf-space-8);
    --platforma-space-2:         var(--pf-space-2);
    --platforma-space-3:         var(--pf-space-3);
    --platforma-space-4:         var(--pf-space-4);
    --platforma-space-5:         var(--pf-space-5);
    --platforma-space-6:         var(--pf-space-6);

    /* Radius */
    --platforma-radius-xs:       var(--pf-radius-xs);
    --platforma-radius-input:    var(--pf-radius-sm);
    --platforma-radius-card:     var(--pf-radius-lg);
    --platforma-radius-panel:    var(--pf-radius-xl);
    --platforma-radius-pill:     var(--pf-radius-full);

    /* Shadows */
    --platforma-shadow:          var(--pf-color-shadow-sm);
    --platforma-shadow-soft:     var(--pf-color-shadow-sm);
    --platforma-shadow-card:     var(--pf-color-shadow-md);

    /* Motion */
    --platforma-duration-fast:   var(--pf-motion-duration-fast);
    --platforma-duration-quick:  var(--pf-motion-duration-fast);
    --platforma-duration-smooth: var(--pf-motion-duration-base);
    --platforma-duration:        var(--pf-motion-duration-base);
    --platforma-ease-out:        var(--pf-motion-ease-out);
    --platforma-ease-premium:    var(--pf-motion-ease-emphasized);
    --platforma-ease-celebration: var(--pf-motion-ease-out);

    /* Focus ring */
    --platforma-focus-ring:      var(--pf-focus-ring);


    /* ═════════════════════════════════════════════════════════════
       B. SE — CMS Editor tokens (added in DARK.1-6 Slice)
       Now redundant — the parent --platforma-* tokens already follow
       theme via this compat layer. Kept for transitional safety;
       slated for removal in Phase B once all editor CSS is refactored.
       ═════════════════════════════════════════════════════════════ */

    --se-surface:                var(--pf-color-surface-raised);
    --se-surface-hover:          var(--pf-color-surface-hover);
    --se-surface-soft:           var(--pf-color-surface-base);
    --se-surface-elevated:       var(--pf-color-surface-overlay);
    --se-text:                   var(--pf-color-text-primary);
    --se-text-muted:             var(--pf-color-text-secondary);
    --se-text-subtle:            var(--pf-color-text-tertiary);
    --se-border:                 var(--pf-color-border-strong);
    --se-border-soft:            var(--pf-color-border-subtle);
    --se-border-strong:          var(--pf-color-border-strong);
    --se-input-bg:               var(--pf-color-surface-sunken);
    --se-input-border:           var(--pf-color-border-strong);
    --se-input-border-focus:     var(--pf-color-border-focus);
    --se-accent:                 var(--pf-color-action-primary);
    --se-accent-soft:            var(--pf-color-action-primary-soft);
    --se-shadow:                 var(--pf-color-shadow-md);
    --se-shadow-elevated:        var(--pf-color-shadow-xl);


    /* ═════════════════════════════════════════════════════════════
       C. CHUB — Community-Hub public site template
       Public site keeps tenant brand identity (--tenant-*); these
       legacy aliases route through PF semantic tokens that respect
       the editor's dark mode for preview, while public visits still
       see the tenant's chosen brand theme.
       ═════════════════════════════════════════════════════════════ */

    /* Surface family */
    --chub-bg:                   var(--pf-color-surface-base);
    --chub-bg-soft:              var(--pf-color-surface-sunken);
    --chub-surface:              var(--pf-color-surface-raised);
    --chub-surface-alt:          var(--pf-color-surface-sunken);
    --chub-surface-hover:        var(--pf-color-surface-hover);
    --chub-surface-soft:         var(--pf-color-surface-sunken);

    /* Text family */
    --chub-text:                 var(--pf-color-text-primary);
    --chub-text-muted:           var(--pf-color-text-secondary);
    --chub-text-soft:            var(--pf-color-text-tertiary);
    --chub-text-strong:          var(--pf-color-text-primary);

    /* Border family */
    --chub-border:               var(--pf-color-border-subtle);
    --chub-border-light:         var(--pf-color-border-subtle);
    --chub-border-mid:           var(--pf-color-border-strong);

    /* Spacing */
    --chub-space-2:              var(--pf-space-2);
    --chub-space-3:              var(--pf-space-3);
    --chub-space-4:              var(--pf-space-4);
    --chub-space-5:              var(--pf-space-5);
    --chub-space-6:              var(--pf-space-6);
    --chub-section-gap:          var(--pf-space-12);
    --chub-container:            1200px;

    /* Radius */
    --chub-radius:               var(--pf-radius-lg);
    --chub-radius-lg:            var(--pf-radius-xl);

    /* Shadow */
    --chub-shadow:               var(--pf-color-shadow-sm);
    --chub-shadow-md:            var(--pf-color-shadow-md);

    /* Note on accent/primary in chub:
       --chub-primary, --chub-primary-dark, --chub-accent etc. are NOT
       aliased here — they are intentionally driven by --tenant-* tokens
       (overridden in _WebsiteLayout.cshtml inline-style based on the
       active BrandTheme). See SEC.16.5 for the bridge. */


    /* ═════════════════════════════════════════════════════════════
       D. TENANT — Brand override hooks (NOT aliased)
       --tenant-primary, --tenant-secondary etc. are deliberately NOT
       mapped here. They are populated at runtime by the
       TenantBranding ViewComponent based on the tenant's active
       BrandTheme. This compat shim lives ABOVE that injection so the
       tenant tokens take precedence as designed.
       ═════════════════════════════════════════════════════════════ */
}

/* ═════════════════════════════════════════════════════════════════════
   NUCLEAR FALLBACK — !important on critical theme-switching tokens
   ─────────────────────────────────────────────────────────────────────
   When site-editor.css base styles use var(--platforma-parchment-50)
   directly in component rules (e.g. .se-page-rail, .se-inspector-tabs,
   .se-inspector-footer, .se-outline-footer, .se-field-image), the
   resolution chain MUST end at our PF semantic tokens — not the
   hardcoded #FBFAF6 declared in platforma-tokens.css.

   Specificity boost (html[lang]) above already wins (0,1,1 > 0,1,0),
   but adding !important to these specific surface/text/border tokens
   provides defense-in-depth against:
     • Future stylesheets that might re-declare with higher specificity
     • Inline-style :root injections from third-party scripts
     • Browser-extensions that override CSS variables
     • Edge-cases in `@layer` cascade ordering

   IMPORTANT scope is INTENTIONALLY NARROW:
     ✓ Only surface, text, border tokens that need theme-switching
     ✗ NOT applied to brand colors (--platforma-brand etc. — those are
       runtime tenant-themed via TenantBranding component)
     ✗ NOT applied to spacing/radius/shadow (no theme-conflict)

   This is a documented compat-shim use of !important — it is the
   correct tool when overriding legacy hardcoded values during
   migration. To remove !important, refactor site-editor.css base
   rules to use --pf-color-* directly (Phase B work).
   ═════════════════════════════════════════════════════════════════════ */
html[lang],
html:root,
:root {
    /* Surface (CRITICAL for theme-switching) */
    --platforma-white:           var(--pf-color-surface-raised) !important;
    --platforma-parchment-50:    var(--pf-color-surface-base) !important;
    --platforma-parchment-100:   var(--pf-color-surface-sunken) !important;
    --platforma-parchment-200:   var(--pf-color-border-subtle) !important;
    --platforma-parchment-300:   var(--pf-color-border-strong) !important;

    /* Gray scale (CRITICAL for theme-switching) */
    --platforma-gray-50:         var(--pf-color-surface-base) !important;
    --platforma-gray-100:        var(--pf-color-surface-sunken) !important;
    --platforma-gray-200:        var(--pf-color-border-subtle) !important;
    --platforma-gray-300:        var(--pf-color-border-strong) !important;
    --platforma-gray-700:        var(--pf-color-text-secondary) !important;
    --platforma-gray-800:        var(--pf-color-text-primary) !important;
    --platforma-gray-900:        var(--pf-color-text-primary) !important;

    /* Ink text hierarchy (CRITICAL for theme-switching) */
    --platforma-ink:             var(--pf-color-text-primary) !important;
    --platforma-ink-900:         var(--pf-color-text-primary) !important;
    --platforma-ink-strong:      var(--pf-color-text-primary) !important;
    --platforma-ink-primary:     var(--pf-color-text-primary) !important;
    --platforma-ink-muted:       var(--pf-color-text-secondary) !important;
    --platforma-ink-subtle:      var(--pf-color-text-tertiary) !important;

    /* Line/border family (CRITICAL for theme-switching) */
    --platforma-line-50:         var(--pf-color-border-subtle) !important;
    --platforma-line-100:        var(--pf-color-border-subtle) !important;
    --platforma-line-200:        var(--pf-color-border-strong) !important;
    --platforma-border:          var(--pf-color-border-strong) !important;
}

/* ═════════════════════════════════════════════════════════════════════
   HF 2026-05-11 — Re-declare *-soft aliases at theme-switch scopes
   ─────────────────────────────────────────────────────────────────────
   CSS Custom Properties resolve var() lookups at DEFINITION SCOPE, not
   USAGE SCOPE. The :root block above declares e.g.
       --platforma-accent-soft: var(--pf-color-action-primary-soft);
   which gets baked in at :root (light-mode value of indigo-50).

   When themes.dark.css later overrides --pf-color-action-primary-soft
   on [data-pf-theme="dark"], [data-cms-editor-theme="dark"] (body/html),
   the :root-scope alias DOES NOT re-compute — it stays indigo-50.

   Bug it caused: .se-field-fit-toggle-option.is-active in editor dark
   mode rendered indigo-50 (light) background with inherited slate-50
   (light) text = invisible "Fyld rammen" label.

   Fix: re-declare every accent/status/soft alias on the same theme-
   switch selectors that themes.dark.css uses. Now each alias resolves
   AT the theme scope, capturing the dark-mode value of the underlying
   --pf-color-* token.

   Surfaces that previously broke under this bug:
   - se-field-fit-toggle-option (focal-point picker)
   - platforma-base.css active-tab tint
   - platforma-buttons.css ghost-button hover
   - platforma-domain-cockpit.css status-pill backgrounds
   - login.css focus-glow + status callouts
   ───────────────────────────────────────────────────────────────────── */
[data-pf-theme="dark"],
[data-cms-editor-theme="dark"] {
    --platforma-brand-soft:      var(--pf-color-action-primary-soft) !important;
    --platforma-accent-soft:     var(--pf-color-action-primary-soft) !important;
    --platforma-accent-border:   var(--pf-color-action-primary-soft-hover) !important;
    --platforma-success-soft:    var(--pf-color-status-success-soft) !important;
    --platforma-warning-soft:    var(--pf-color-status-warning-soft) !important;
    --platforma-danger-soft:     var(--pf-color-status-danger-soft) !important;
    --platforma-info-soft:       var(--pf-color-status-info-soft) !important;
    --se-accent-soft:            var(--pf-color-action-primary-soft) !important;
    /* AUDIT-THEME-1 (2026-09-16) — the -soft family above was aliased and the -light family was
       not, and neither was any of the --tenant-* surface layer. MEASURED in the browser: 17
       tokens whose NAME promises a surface resolve to the same pale value in both themes, and 150
       declarations paint a background with one of them. That is what made a hovered lead row
       unreadable at 1.05:1 — pale pink under text that had flipped to near-white.

       Fixed HERE rather than at the 150 call sites. One line per token corrects every existing
       use, every inline style this sweep could not see, and every future one. It is also bounded:
       this block only applies in dark theme, so light theme is byte-identical.

       WITHDRAWN AFTER REVIEW: this block originally also re-aliased --platforma-primary-light,
       -success-light and -warning-light. platforma-theme.css:112-116 and its system mirror at
       :132-136 ALREADY own all five -light tokens in dark, at html[data-pf-theme="dark"] =
       (0,1,1) and WITHOUT !important. Importance is compared before specificity, so the version
       here won and theirs became dead code — silently flipping 38 backgrounds from a brand-red
       tint to navy, including Views/Shared/_HelpPanel.cshtml on every admin page, and
       invalidating the 13.85:1 help-panel figure REL-17 published. One owner per token, and that
       owner is platforma-theme.css, whose own comment says so.

       --tenant-* is the operator brand and must NOT be inverted — a brand colour stays itself. So
       the tint is mixed INTO the dark surface instead: still recognisably the tenant, still dark
       enough to carry light text. */
    --tenant-surface:            var(--pf-color-surface-raised) !important;
    --tenant-bg:                 var(--pf-color-surface-base) !important;
    --tenant-success-soft:       var(--pf-color-status-success-soft) !important;
    --tenant-warning-soft:       var(--pf-color-status-warning-soft) !important;
    --tenant-danger-soft:        var(--pf-color-status-danger-soft) !important;
    --tenant-primary-soft:       color-mix(in srgb,
                                     var(--tenant-primary, var(--pf-color-action-primary)) 12%,
                                     var(--pf-color-surface-raised)) !important;
}

/* Also fire under auto-dark mode (prefers-color-scheme: dark) unless
   the user has explicitly opted into light via attribute — mirrors the
   same exclusion pattern themes.dark.css uses for its @media block. */
@media (prefers-color-scheme: dark) {
    :root:not([data-pf-theme="light"]):not([data-cms-editor-theme="light"]) {
        --platforma-brand-soft:      var(--pf-color-action-primary-soft) !important;
        --platforma-accent-soft:     var(--pf-color-action-primary-soft) !important;
        --platforma-accent-border:   var(--pf-color-action-primary-soft-hover) !important;
        --platforma-success-soft:    var(--pf-color-status-success-soft) !important;
        --platforma-warning-soft:    var(--pf-color-status-warning-soft) !important;
        --platforma-danger-soft:     var(--pf-color-status-danger-soft) !important;
        --platforma-info-soft:       var(--pf-color-status-info-soft) !important;
        --se-accent-soft:            var(--pf-color-action-primary-soft) !important;
        /* AUDIT-THEME-1 (2026-09-16) — the -soft family above was aliased and the -light family was
           not, and neither was any of the --tenant-* surface layer. MEASURED in the browser: 17
           tokens whose NAME promises a surface resolve to the same pale value in both themes, and 150
           declarations paint a background with one of them. That is what made a hovered lead row
           unreadable at 1.05:1 — pale pink under text that had flipped to near-white.

           Fixed HERE rather than at the 150 call sites. One line per token corrects every existing
           use, every inline style this sweep could not see, and every future one. It is also bounded:
           this block only applies in dark theme, so light theme is byte-identical.

           WITHDRAWN AFTER REVIEW: this block originally also re-aliased --platforma-primary-light,
       -success-light and -warning-light. platforma-theme.css:112-116 and its system mirror at
       :132-136 ALREADY own all five -light tokens in dark, at html[data-pf-theme="dark"] =
       (0,1,1) and WITHOUT !important. Importance is compared before specificity, so the version
       here won and theirs became dead code — silently flipping 38 backgrounds from a brand-red
       tint to navy, including Views/Shared/_HelpPanel.cshtml on every admin page, and
       invalidating the 13.85:1 help-panel figure REL-17 published. One owner per token, and that
       owner is platforma-theme.css, whose own comment says so.

       --tenant-* is the operator brand and must NOT be inverted — a brand colour stays itself. So
           the tint is mixed INTO the dark surface instead: still recognisably the tenant, still dark
           enough to carry light text. */
        --tenant-surface:            var(--pf-color-surface-raised) !important;
        --tenant-bg:                 var(--pf-color-surface-base) !important;
        --tenant-success-soft:       var(--pf-color-status-success-soft) !important;
        --tenant-warning-soft:       var(--pf-color-status-warning-soft) !important;
        --tenant-danger-soft:        var(--pf-color-status-danger-soft) !important;
        --tenant-primary-soft:       color-mix(in srgb,
                                         var(--tenant-primary, var(--pf-color-action-primary)) 12%,
                                         var(--pf-color-surface-raised)) !important;
    }
}
/* ==== css/pf/tokens.components.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Component Tokens (Tier 3)
   ────────────────────────────────────────────────────────────────────
   Component-specific aliases on top of semantic tokens. Each component
   in Phase B (.pf-button, .pf-input, .pf-card, etc.) uses its own
   namespaced tokens that REFERENCE the semantic tier — providing a
   stable component API even as semantic tokens evolve.

   ARCHITECTURAL ROLE
     Tier 1 — Primitive    (raw values: --pf-color-slate-100)
     Tier 2 — Semantic     (intent: --pf-color-surface-base)
     Tier 3 — Component    (this file: --pf-button-bg-primary)

   WHY A SEPARATE TIER?
     • Components can vary independently of base palette refinements
       (e.g. button radius can change without touching --pf-radius-md)
     • Themes can override component tokens for component-level skinning
       without affecting other components (--pf-button-bg in dark mode
       can differ from --pf-input-bg)
     • External design tools (Figma, Style Dictionary) export this tier
       as the public component API
     • Distribution (Phase C) — third-party consumers customize via
       component tokens, never primitive

   NAMING
     --pf-{component}-{property}-{variant}-{state}

   SCOPE — Phase B core components:
     • button   — primary actions, secondary, danger, ghost, link
     • input    — text/number/select/textarea
     • card     — content containers, raised surfaces
     • drawer   — slide-in panels (a11y, health, seo, etc.)
     • modal    — centered overlays (add-section, templates picker)
     • popover  — anchored floating panels (schedule, share)
     • toast    — transient notifications

   Version: 1.0.0
   Last revised: 2026-05-09
   ──────────────────────────────────────────────────────────────────── */

html[lang],
html:root,
:root {
    /* ═════════════════════════════════════════════════════════════
       BUTTON — primary, secondary, ghost, danger, link variants
       ═════════════════════════════════════════════════════════════ */

    /* Primary */
    --pf-button-bg-primary:           var(--pf-color-action-primary);
    --pf-button-bg-primary-hover:     var(--pf-color-action-primary-hover);
    --pf-button-bg-primary-pressed:   var(--pf-color-action-primary-pressed);
    --pf-button-bg-primary-disabled:  var(--pf-color-surface-disabled);
    --pf-button-fg-primary:           var(--pf-color-text-on-action);
    --pf-button-border-primary:       var(--pf-color-action-primary);

    /* Secondary (emphasis: medium) */
    --pf-button-bg-secondary:          var(--pf-color-surface-raised);
    --pf-button-bg-secondary-hover:    var(--pf-color-surface-hover);
    --pf-button-bg-secondary-pressed:  var(--pf-color-surface-sunken);
    --pf-button-fg-secondary:          var(--pf-color-text-primary);
    --pf-button-border-secondary:      var(--pf-color-border-strong);

    /* Ghost (emphasis: low — text-only with hover bg) */
    --pf-button-bg-ghost:              transparent;
    --pf-button-bg-ghost-hover:        var(--pf-color-surface-hover);
    --pf-button-fg-ghost:              var(--pf-color-text-secondary);
    --pf-button-fg-ghost-hover:        var(--pf-color-text-primary);

    /* Danger (destructive — escape hatch from branded mode) */
    --pf-button-bg-danger:             var(--pf-color-action-danger);
    --pf-button-bg-danger-hover:       var(--pf-color-action-danger-hover);
    --pf-button-fg-danger:             var(--pf-color-text-on-action);
    --pf-button-bg-danger-soft:        var(--pf-color-action-danger-soft);

    /* Link (anchor styled as button) */
    --pf-button-fg-link:               var(--pf-color-action-primary);
    --pf-button-fg-link-hover:         var(--pf-color-action-primary-hover);

    /* Common */
    --pf-button-radius:                var(--pf-radius-md);
    --pf-button-padding-y:             var(--pf-space-2);
    --pf-button-padding-x:             var(--pf-space-4);
    --pf-button-font-size:             var(--pf-text-size-sm);
    --pf-button-font-weight:           var(--pf-text-weight-semibold);
    --pf-button-shadow-focus:          var(--pf-focus-ring);

    /* Sizes */
    --pf-button-padding-y-sm:          var(--pf-space-1);
    --pf-button-padding-x-sm:          var(--pf-space-3);
    --pf-button-font-size-sm:          var(--pf-text-size-xs);
    --pf-button-padding-y-lg:          var(--pf-space-3);
    --pf-button-padding-x-lg:          var(--pf-space-5);
    --pf-button-font-size-lg:          var(--pf-text-size-base);

    /* ═════════════════════════════════════════════════════════════
       INPUT — text, number, email, search, select, textarea
       ═════════════════════════════════════════════════════════════ */

    --pf-input-bg:                     var(--pf-color-surface-sunken);
    --pf-input-bg-disabled:            var(--pf-color-surface-disabled);
    --pf-input-fg:                     var(--pf-color-text-primary);
    --pf-input-fg-placeholder:         var(--pf-color-text-tertiary);
    --pf-input-fg-disabled:            var(--pf-color-text-disabled);
    /* PL-3 (2026-09-08): the DS-1 control-border role — border-strong in light (unchanged),
       one step lighter in dark so the boundary meets WCAG 1.4.11 on the sunken fill. */
    --pf-input-border:                 var(--pf-color-border-control, var(--pf-color-border-strong));
    --pf-input-border-hover:           var(--pf-color-border-focus);
    --pf-input-border-focus:           var(--pf-color-border-focus);
    --pf-input-border-error:           var(--pf-color-status-danger);
    --pf-input-radius:                 var(--pf-radius-sm);
    --pf-input-padding-y:              var(--pf-space-2);
    --pf-input-padding-x:              var(--pf-space-3);
    --pf-input-font-size:              var(--pf-text-size-base);
    --pf-input-shadow-focus:           var(--pf-focus-ring);

    /* ═════════════════════════════════════════════════════════════
       CARD — content containers, panels, raised surfaces
       ═════════════════════════════════════════════════════════════ */

    --pf-card-bg:                      var(--pf-color-surface-raised);
    --pf-card-bg-hover:                var(--pf-color-surface-hover);
    --pf-card-fg:                      var(--pf-color-text-primary);
    --pf-card-border:                  var(--pf-color-border-subtle);
    --pf-card-radius:                  var(--pf-radius-lg);
    --pf-card-padding:                 var(--pf-space-5);
    --pf-card-gap:                     var(--pf-space-3);
    --pf-card-shadow:                  var(--pf-color-shadow-sm);
    --pf-card-shadow-hover:            var(--pf-color-shadow-md);

    /* Card sub-elements */
    --pf-card-title-color:             var(--pf-color-text-primary);
    --pf-card-title-size:              var(--pf-text-size-lg);
    --pf-card-title-weight:            var(--pf-text-weight-semibold);
    --pf-card-body-color:              var(--pf-color-text-secondary);
    --pf-card-body-size:               var(--pf-text-size-sm);
    --pf-card-meta-color:              var(--pf-color-text-tertiary);
    --pf-card-meta-size:               var(--pf-text-size-xs);

    /* ═════════════════════════════════════════════════════════════
       DRAWER — slide-in panels (right-edge typically)
       ═════════════════════════════════════════════════════════════ */

    --pf-drawer-bg:                    var(--pf-color-surface-overlay);
    --pf-drawer-fg:                    var(--pf-color-text-primary);
    --pf-drawer-border:                var(--pf-color-border-subtle);
    --pf-drawer-shadow:                var(--pf-color-shadow-xl);
    --pf-drawer-backdrop:              rgb(0 0 0 / 0.50);
    --pf-drawer-padding:               var(--pf-space-6);
    /* A drawer is role="dialog" aria-modal="true" — a modal by ARIA semantics — so its overlay must
       sit at the MODAL layer, above all sticky page chrome. The legacy app chrome (.platforma-header)
       hardcodes z-index:900, which is ABOVE the --pf-z-overlay (500) drawer-backdrop layer; at 500 the
       header painted over the drawer header and intercepted clicks on the drawer close button. Mapping
       to --pf-z-modal (1000) fixes every drawer app-wide (admin, portal, CMS editor) in one place. */
    --pf-drawer-z-index:               var(--pf-z-modal);

    /* ═════════════════════════════════════════════════════════════
       MODAL — centered floating dialog
       ═════════════════════════════════════════════════════════════ */

    --pf-modal-bg:                     var(--pf-color-surface-overlay);
    --pf-modal-fg:                     var(--pf-color-text-primary);
    --pf-modal-border:                 var(--pf-color-border-subtle);
    --pf-modal-radius:                 var(--pf-radius-xl);
    --pf-modal-shadow:                 var(--pf-color-shadow-2xl);
    --pf-modal-backdrop:               rgb(0 0 0 / 0.60);
    --pf-modal-padding:                var(--pf-space-6);
    --pf-modal-z-index:                var(--pf-z-modal);
    --pf-modal-max-width:              640px;

    /* ═════════════════════════════════════════════════════════════
       POPOVER — anchored floating panel (smaller than modal)
       ═════════════════════════════════════════════════════════════ */

    --pf-popover-bg:                   var(--pf-color-surface-overlay);
    --pf-popover-fg:                   var(--pf-color-text-primary);
    --pf-popover-border:               var(--pf-color-border-strong);
    --pf-popover-radius:               var(--pf-radius-md);
    --pf-popover-shadow:               var(--pf-color-shadow-lg);
    --pf-popover-padding:              var(--pf-space-4);
    --pf-popover-z-index:              var(--pf-z-popover);
    --pf-popover-arrow-size:           8px;

    /* ═════════════════════════════════════════════════════════════
       TOAST — transient notification
       ═════════════════════════════════════════════════════════════ */

    --pf-toast-bg:                     var(--pf-color-surface-overlay);
    --pf-toast-fg:                     var(--pf-color-text-primary);
    --pf-toast-border:                 var(--pf-color-border-strong);
    --pf-toast-radius:                 var(--pf-radius-md);
    --pf-toast-shadow:                 var(--pf-color-shadow-lg);
    --pf-toast-padding-y:              var(--pf-space-3);
    --pf-toast-padding-x:              var(--pf-space-4);
    --pf-toast-z-index:                var(--pf-z-toast);
    --pf-toast-max-width:              420px;
    --pf-toast-min-height:             56px;

    /* Toast variants — share semantic status colors */
    --pf-toast-bg-success:             var(--pf-color-status-success-soft);
    --pf-toast-fg-success:             var(--pf-color-status-success-fg);
    --pf-toast-border-success:         var(--pf-color-status-success-border);
    --pf-toast-bg-warning:             var(--pf-color-status-warning-soft);
    --pf-toast-fg-warning:             var(--pf-color-status-warning-fg);
    --pf-toast-border-warning:         var(--pf-color-status-warning-border);
    --pf-toast-bg-danger:              var(--pf-color-status-danger-soft);
    --pf-toast-fg-danger:              var(--pf-color-status-danger-fg);
    --pf-toast-border-danger:          var(--pf-color-status-danger-border);
    --pf-toast-bg-info:                var(--pf-color-status-info-soft);
    --pf-toast-fg-info:                var(--pf-color-status-info-fg);
    --pf-toast-border-info:            var(--pf-color-status-info-border);

    /* ═════════════════════════════════════════════════════════════
       CP-1 (2026-09-08, admin design system Phase 3) — the canonical
       .pf-btn family. ADDITIVE: every Phase B --pf-button-* token above
       keeps its value; .pf-btn shares them and adds the mono / outline
       roles, density-aware heights (DS-1 --pf-control-height), the
       ≥44px pointer target for icon-only buttons and the single
       hairline shadow (demo1's "one shadow" discipline).
       ═════════════════════════════════════════════════════════════ */
    --pf-button-bg-mono:               var(--pf-color-mono);
    --pf-button-bg-mono-hover:         var(--pf-color-mono-hover);
    --pf-button-fg-mono:               var(--pf-color-mono-foreground);
    --pf-button-fg-outline:            var(--pf-color-text-primary);
    --pf-button-border-outline:        var(--pf-color-border-strong);
    --pf-button-bg-outline-hover:      var(--pf-color-surface-hover);
    --pf-button-height:                var(--pf-control-height);
    --pf-button-height-sm:             calc(var(--pf-control-height) - var(--pf-space-2));
    --pf-button-height-lg:             calc(var(--pf-control-height) + var(--pf-space-2));
    --pf-button-hit-target:            2.75rem;   /* 44px — WCAG 2.5.5 target size */
    --pf-button-glyph-size:            1.125rem;  /* 18px */
    --pf-button-glyph-size-sm:         1rem;      /* 16px */
    --pf-button-glyph-size-lg:         1.25rem;   /* 20px */
    --pf-button-shadow:                var(--pf-shadow-xs);

    /* ═════════════════════════════════════════════════════════════
       CP-2 — sectioned card rhythm (header / content / footer / table).
       Section padding rides the DS-1 density band (--pf-card-pad).
       ═════════════════════════════════════════════════════════════ */
    --pf-card-header-min-height:       var(--pf-space-14);   /* 56px — demo1's 3.5rem header rhythm */
    --pf-card-section-pad:             var(--pf-card-pad);

    /* ═════════════════════════════════════════════════════════════
       CP-4 — BADGE (status chip). Soft fill + status foreground by
       default (measured AA/AAA in components/badge.css); the solid
       status fills are deliberately NOT used for text (white on
       emerald-600 is 3.77:1 — fails AA).
       ═════════════════════════════════════════════════════════════ */
    --pf-badge-radius:                 var(--pf-radius-full);
    --pf-badge-font-size:              var(--pf-text-size-xs);
    --pf-badge-font-size-sm:           var(--pf-text-2xs);
    --pf-badge-font-size-lg:           var(--pf-text-2sm);
    --pf-badge-font-weight:            var(--pf-text-weight-semibold);
    --pf-badge-height:                 1.375rem;  /* 22px */
    --pf-badge-height-sm:              1.125rem;  /* 18px */
    --pf-badge-height-lg:              1.625rem;  /* 26px */
    --pf-badge-padding-x:              var(--pf-space-2);
    --pf-badge-padding-x-sm:           var(--pf-space-1-5);
    --pf-badge-padding-x-lg:           var(--pf-space-2-5);
    --pf-badge-bg-neutral:             var(--pf-color-surface-sunken);
    --pf-badge-fg-neutral:             var(--pf-color-text-secondary);
    --pf-badge-border-neutral:         var(--pf-color-border-strong);
    --pf-badge-accent-neutral:         var(--pf-color-text-tertiary);

    /* ═════════════════════════════════════════════════════════════
       CP-4 — AVATAR (initials fallback, sizes, status dot, stack)
       ═════════════════════════════════════════════════════════════ */
    --pf-avatar-size-xs:               1.5rem;    /* 24px */
    --pf-avatar-size-sm:               2rem;      /* 32px */
    --pf-avatar-size-md:               2.5rem;    /* 40px */
    --pf-avatar-size-lg:               3rem;      /* 48px */
    --pf-avatar-size-xl:               4rem;      /* 64px */
    --pf-avatar-bg:                    var(--pf-color-surface-sunken);
    --pf-avatar-fg:                    var(--pf-color-text-secondary);
    --pf-avatar-ring:                  var(--pf-color-surface-raised);
    --pf-avatar-radius:                var(--pf-radius-full);
    --pf-avatar-font-weight:           var(--pf-text-weight-semibold);

    /* ═════════════════════════════════════════════════════════════
       CP-3 — STAT TILE (label + mono number + delta chip + sparkline)
       ═════════════════════════════════════════════════════════════ */
    --pf-stat-bg:                      var(--pf-card-bg);
    --pf-stat-border:                  var(--pf-card-border);
    --pf-stat-radius:                  var(--pf-card-radius);
    --pf-stat-shadow:                  var(--pf-card-shadow);
    --pf-stat-padding:                 var(--pf-card-pad);
    --pf-stat-label-color:             var(--pf-color-text-secondary);
    --pf-stat-value-color:             var(--pf-color-mono);
    --pf-stat-value-size:              var(--pf-text-size-3xl);
    --pf-stat-meta-color:              var(--pf-color-text-tertiary);
    --pf-stat-spark-height:            2.5rem;    /* 40px — DV-1 draws into this box */
    --pf-stat-spark-color:             var(--pf-color-action-primary);

    /* ═════════════════════════════════════════════════════════════
       CP-5 — EMPTY STATE
       ═════════════════════════════════════════════════════════════ */
    --pf-empty-border:                 var(--pf-color-border-strong);
    --pf-empty-radius:                 var(--pf-card-radius);
    --pf-empty-padding-y:              var(--pf-space-10);
    --pf-empty-padding-x:              var(--pf-space-6);
    --pf-empty-icon-size:              3.5rem;    /* 56px tile */
    --pf-empty-icon-bg:                var(--pf-color-surface-sunken);
    --pf-empty-icon-fg:                var(--pf-color-text-tertiary);
    --pf-empty-icon-radius:            var(--pf-radius-xl);
    --pf-empty-title-color:            var(--pf-color-text-primary);
    --pf-empty-hint-color:             var(--pf-color-text-secondary);

    /* ═════════════════════════════════════════════════════════════
       PL-2 — ICON (pf/components/icon.css; the Icon ViewComponent)
       Sizes match the width/height attributes the component emits.
       ═════════════════════════════════════════════════════════════ */
    --pf-icon-size-xs:                 0.875rem;  /* 14px */
    --pf-icon-size-sm:                 1rem;      /* 16px */
    --pf-icon-size-md:                 1.25rem;   /* 20px — nav rhythm (default) */
    --pf-icon-size-lg:                 1.5rem;    /* 24px */
    --pf-icon-size-xl:                 2rem;      /* 32px */
    --pf-icon-stroke-width:            1.75;      /* the house stroke — Lucide ships 2 */

    /* ═════════════════════════════════════════════════════════════
       CP-5 — SKELETON (loading placeholders; shimmer is motion-gated)
       ═════════════════════════════════════════════════════════════ */
    --pf-skeleton-bg:                  var(--pf-color-surface-sunken);
    --pf-skeleton-shine:               var(--pf-color-border-subtle);
    --pf-skeleton-radius:              var(--pf-radius-sm);
    --pf-skeleton-line-height:         0.75rem;   /* 12px */
    --pf-skeleton-duration:            1400ms;

    /* ═════════════════════════════════════════════════════════════
       JS-2 — TOOLTIP (the shared bubble platforma-ui.js positions)
       ═════════════════════════════════════════════════════════════ */
    --pf-tooltip-bg:                   var(--pf-color-text-primary);
    --pf-tooltip-fg:                   var(--pf-color-text-inverse);
    --pf-tooltip-radius:               var(--pf-radius-md);
    --pf-tooltip-shadow:               var(--pf-shadow-md);
    --pf-tooltip-padding-y:            var(--pf-space-1);
    --pf-tooltip-padding-x:            var(--pf-space-2);
    --pf-tooltip-max-width:            16rem;
    --pf-tooltip-z-index:              var(--pf-z-popover);

    /* ═════════════════════════════════════════════════════════════
       JS-3 — TABLE FINISH (toolbar · footer · sort · sticky · select)
       ═════════════════════════════════════════════════════════════ */
    --pf-table-border:                 var(--pf-color-border-subtle);
    --pf-table-head-bg:                var(--pf-color-surface-sunken);
    --pf-table-head-shadow:            var(--pf-shadow-none);
    --pf-table-footer-fg:              var(--pf-color-text-secondary);
    --pf-table-pad-x:                  var(--pf-space-4);
    --pf-table-search-width:           20rem;
    --pf-table-select-width:           2.5rem;    /* 40px */
    --pf-table-sticky-top:             0px;       /* the behaviour sets the chrome offset */
    --pf-table-sort-idle:              var(--pf-color-border-strong);
    --pf-table-sort-active:            var(--pf-color-action-primary);

    /* ═════════════════════════════════════════════════════════════
       DV-1 / DV-2 — CHARTS (inline-SVG micro-charts read these through
       chart.css; the lazy rich wrapper resolves them via getComputedStyle)
       ═════════════════════════════════════════════════════════════ */
    --pf-chart-color:                  var(--pf-color-action-primary);
    --pf-chart-track:                  var(--pf-color-border-subtle);
    --pf-chart-grid:                   var(--pf-color-border-subtle);
    --pf-chart-axis-fg:                var(--pf-color-text-tertiary);
    --pf-chart-legend-fg:              var(--pf-color-text-secondary);
    --pf-chart-cursor:                 var(--pf-color-text-tertiary);
    --pf-chart-select:                 color-mix(in oklab, var(--pf-color-action-primary) 12%, transparent);
    --pf-chart-center-fg:              var(--pf-color-mono);
    --pf-chart-center-size:            9px;       /* SVG user units of the 40-unit ring */
    --pf-chart-stroke:                 2;         /* screen px — strokes are non-scaling */
    --pf-chart-marker-size:            6;         /* screen px — the last-point dot */
    --pf-chart-area-opacity:           0.14;
    --pf-chart-bar-opacity:            0.55;      /* non-accent bars; the last bar is 1 */
    --pf-chart-min-height:             2.5rem;    /* 40px — same box as the stat sparkline */
    --pf-chart-donut-max:              8rem;      /* 128px */
    --pf-chart-rich-min-height:        12rem;     /* 192px — reserved while uPlot loads */
    --pf-chart-duration:               var(--pf-motion-duration-slower);
    --pf-chart-series-1:               var(--pf-color-action-primary);
    --pf-chart-series-2:               var(--pf-color-status-info);
    --pf-chart-series-3:               var(--pf-color-status-success);
    --pf-chart-series-4:               var(--pf-color-status-warning);
    --pf-chart-series-5:               var(--pf-color-status-danger);
    --pf-chart-series-6:               var(--pf-color-mono);
}

/* CP-1 — compact density: the icon-button pointer target collapses to the
   control height (32px) so neighbouring icon buttons in a dense toolbar
   never overlap. html[...] keeps the specificity of the html[lang] block
   above (0,1,1) and wins by source order. Comfortable/spacious keep 44px. */
html[data-pf-density="compact"] {
    --pf-button-hit-target:            var(--pf-control-height);
}
/* ==== css/pf/components/a11y.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Accessibility utilities
   ────────────────────────────────────────────────────────────────────
   CP-1..CP-5 (2026-09-08, admin design system Phase 3). Loaded FIRST in
   the component layer (see _PfDesignSystemCompat.cshtml) because every
   core component leans on .pf-sr-only for its accessible text:
     • .pf-btn         — the "Loading…" label while aria-busy
     • .pf-stat        — the ▲/▼ delta direction ("Up" / "Down" / "No change")
     • .pf-avatar      — the full name behind the initials, the "+N more"
     • .pf-skeleton    — the "Loading…" status text

   .pf-sr-only — visually hidden, still exposed to assistive technology
   (the WebAIM pattern: 1px box, clipped, off-flow). Never use `display:
   none` or `visibility: hidden` for this — both remove the node from
   the accessibility tree.

   Version: 1.0.0
   Created: 2026-09-08
   ──────────────────────────────────────────────────────────────────── */

.pf-sr-only {
    position: absolute !important;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}
/* ==== css/pf/components/button.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Button Component
   ────────────────────────────────────────────────────────────────────
   BEM-named, fully token-driven, theme-agnostic, WCAG AA compliant.

   USAGE
     <button class="pf-button">Default (primary)</button>
     <button class="pf-button pf-button--secondary">Secondary</button>
     <button class="pf-button pf-button--ghost">Ghost</button>
     <button class="pf-button pf-button--danger">Delete</button>
     <button class="pf-button pf-button--link">Link-styled</button>

     <!-- Sizes -->
     <button class="pf-button pf-button--sm">Small</button>
     <button class="pf-button pf-button--lg">Large</button>

     <!-- States (auto via :hover, :active, :focus, :disabled) -->
     <button class="pf-button" disabled>Disabled</button>

     <!-- With icon -->
     <button class="pf-button">
       <svg class="pf-button__icon">…</svg>
       <span class="pf-button__label">Save</span>
     </button>

   ACCESSIBILITY
     • Focus-visible only (no focus on mouse-click) per WCAG 2.4.7
     • Focus ring: --pf-focus-ring (high-contrast indigo on surface)
     • Disabled state: opacity 0.5 + cursor not-allowed + aria-disabled
     • Min touch target: 44px height (WCAG 2.5.5 — auto via padding + line-height)
     • Color contrast: Phase B arch-test pins ≥ 4.5:1 for text-on-bg

   THEMING
     All visual properties consume --pf-button-* component tokens which
     in turn reference --pf-color-* semantic tokens. Override per theme
     by re-declaring component tokens in themes.dark.css (NOT here).

   Version: 1.0.0
   Last revised: 2026-05-09
   ──────────────────────────────────────────────────────────────────── */

/* ─── Block: .pf-button (default = primary variant) ───────────── */

.pf-button {
    /* Layout — flex container so icon + label align cleanly */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--pf-space-2);

    /* Typography */
    font-family: inherit;
    font-size: var(--pf-button-font-size);
    font-weight: var(--pf-button-font-weight);
    line-height: 1.25;
    text-decoration: none;
    white-space: nowrap;

    /* Box */
    padding: var(--pf-button-padding-y) var(--pf-button-padding-x);
    border-radius: var(--pf-button-radius);
    border: 1px solid var(--pf-button-border-primary);
    cursor: pointer;
    user-select: none;

    /* Default = primary variant */
    background: var(--pf-button-bg-primary);
    color: var(--pf-button-fg-primary);

    /* Smooth interactive transitions */
    transition:
        background var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        border-color var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        box-shadow var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        transform var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
}

/* ─── States ──────────────────────────────────────────────────── */

.pf-button:hover:not(:disabled):not(.pf-button--disabled) {
    background: var(--pf-button-bg-primary-hover);
    border-color: var(--pf-button-bg-primary-hover);
}

.pf-button:active:not(:disabled):not(.pf-button--disabled) {
    background: var(--pf-button-bg-primary-pressed);
    border-color: var(--pf-button-bg-primary-pressed);
    transform: translateY(1px);
}

.pf-button:focus-visible {
    outline: none;
    box-shadow: var(--pf-button-shadow-focus);
}

.pf-button:disabled,
.pf-button.pf-button--disabled,
.pf-button[aria-disabled="true"] {
    background: var(--pf-button-bg-primary-disabled);
    border-color: var(--pf-button-bg-primary-disabled);
    color: var(--pf-color-text-disabled);
    cursor: not-allowed;
    opacity: 0.6;
}

/* ─── Modifier: --secondary (medium emphasis) ────────────────── */

.pf-button--secondary {
    background: var(--pf-button-bg-secondary);
    color: var(--pf-button-fg-secondary);
    border-color: var(--pf-button-border-secondary);
}

.pf-button--secondary:hover:not(:disabled):not(.pf-button--disabled) {
    background: var(--pf-button-bg-secondary-hover);
    border-color: var(--pf-button-border-secondary);
}

.pf-button--secondary:active:not(:disabled):not(.pf-button--disabled) {
    background: var(--pf-button-bg-secondary-pressed);
}

/* ─── Modifier: --ghost (low emphasis — text-only with hover bg) ─── */

.pf-button--ghost {
    background: var(--pf-button-bg-ghost);
    color: var(--pf-button-fg-ghost);
    border-color: transparent;
}

.pf-button--ghost:hover:not(:disabled):not(.pf-button--disabled) {
    background: var(--pf-button-bg-ghost-hover);
    color: var(--pf-button-fg-ghost-hover);
    border-color: transparent;
}

/* ─── Modifier: --danger (destructive action) ─────────────────── */

.pf-button--danger {
    background: var(--pf-button-bg-danger);
    color: var(--pf-button-fg-danger);
    border-color: var(--pf-button-bg-danger);
}

.pf-button--danger:hover:not(:disabled):not(.pf-button--disabled) {
    background: var(--pf-button-bg-danger-hover);
    border-color: var(--pf-button-bg-danger-hover);
}

/* Subtle danger — for "Delete with confirmation"-style micro-actions */
.pf-button--danger.pf-button--ghost {
    background: transparent;
    color: var(--pf-color-status-danger);
    border-color: transparent;
}

.pf-button--danger.pf-button--ghost:hover:not(:disabled) {
    background: var(--pf-button-bg-danger-soft);
    color: var(--pf-color-status-danger-fg);
}

/* ─── Modifier: --link (anchor styled minimally as text-link) ───── */

.pf-button--link {
    background: transparent;
    color: var(--pf-button-fg-link);
    border-color: transparent;
    padding: 0;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.pf-button--link:hover:not(:disabled):not(.pf-button--disabled) {
    background: transparent;
    color: var(--pf-button-fg-link-hover);
}

/* ─── Sizes ──────────────────────────────────────────────────── */

.pf-button--sm {
    padding: var(--pf-button-padding-y-sm) var(--pf-button-padding-x-sm);
    font-size: var(--pf-button-font-size-sm);
}

.pf-button--lg {
    padding: var(--pf-button-padding-y-lg) var(--pf-button-padding-x-lg);
    font-size: var(--pf-button-font-size-lg);
}

/* ─── Width modifiers ────────────────────────────────────────── */

.pf-button--block {
    width: 100%;
}

/* ─── Element: __icon (SVG inside button) ────────────────────── */

.pf-button__icon {
    flex-shrink: 0;
    width: 1em;
    height: 1em;
    fill: currentColor;
}

/* ─── Element: __label (wraps text content for advanced layouts) ── */

.pf-button__label {
    /* No styling — exists for accessibility-friendly icon+label structures
       and to allow visually-hidden labels via .pf-visually-hidden helper. */
}

/* ─── Loading state (shows spinner, disables interaction) ───── */

.pf-button--loading {
    color: transparent !important;
    pointer-events: none;
    position: relative;
}

.pf-button--loading::after {
    content: "";
    position: absolute;
    width: 1em;
    height: 1em;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    color: var(--pf-button-fg-primary);
    animation: pf-button-spin 0.6s linear infinite;
}

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

@media (prefers-reduced-motion: reduce) {
    .pf-button--loading::after {
        animation: none;
        border-style: dotted;
    }
}

/* ════════════════════════════════════════════════════════════════════
   CP-1 (2026-09-08) — CANONICAL .pf-btn FAMILY  (admin design system, Phase 3)
   ────────────────────────────────────────────────────────────────────
   docs/design/ADMIN-DESIGN-SYSTEM-PLAN-2026-09-08.md §B3 / §B8 Phase 3.
   The Phase B `.pf-button` BEM block above is UNTOUCHED (pages consume
   it); `.pf-btn` is the canonical single-dash family the plan names.
   Both share the Tier-3 --pf-button-* tokens, so a theme or edition
   re-skins both at once. Clean-room: our own tokens and code only.

   USAGE
     <button class="pf-btn">Primary (default)</button>
     <button class="pf-btn pf-btn-outline">Outline</button>
     <button class="pf-btn pf-btn-ghost">Ghost</button>
     <button class="pf-btn pf-btn-mono">Mono — near-ink emphasis</button>
     <button class="pf-btn pf-btn-danger">Delete</button>
     <button class="pf-btn pf-btn-sm">Small</button>
     <button class="pf-btn pf-btn-lg">Large</button>
     <button class="pf-btn pf-btn-outline pf-btn-icon" aria-label="Edit">
       <svg class="pf-btn-glyph" aria-hidden="true">…</svg>
     </button>
     <button class="pf-btn" aria-busy="true">Saving</button>
     Razor: <pf-button variant="mono" size="sm" icon="plus">Add</pf-button>

   DENSITY  — the height rides --pf-control-height (DS-1 band): 40px
              comfortable, 32px compact, 44px spacious. Icon-only buttons
              extend their POINTER target to --pf-button-hit-target
              (44px) through a transparent ::before, so the visual box
              stays on the control grid while the touch target meets
              WCAG 2.5.5 (compact collapses it — tokens.components.css).
   STATES   — hover/active derived with color-mix() where no hand-picked
              token exists (outline / ghost / mono / danger pressed);
              the navy chrome-action hovers of the primary stay
              hand-picked (tokens.semantic.css LP-12 remap).
   LOADING  — aria-busy="true" (or .pf-btn-loading): label turns
              transparent but STAYS in the accessibility tree, pointer
              events off, a ring spinner is drawn by ::after. The button
              is never `disabled` while busy, so keyboard focus is not
              dropped mid-submit. Spin only under
              prefers-reduced-motion: no-preference — otherwise a static
              broken ring reads as "busy".
   A11Y     — :focus-visible = --pf-focus-ring (box-shadow) PLUS a 2px
              transparent outline that Windows High Contrast renders in
              system colours; the forced-colors block below completes
              the fallback (borders, spinner, disabled).

   MEASURED WCAG CONTRAST (sRGB, 2026-09-08 — text on fill):
     • primary  admin navy #2E5C8A ← white 6.97:1 (AA/AAA-large)
                unscoped brand red #d4213d ← white 5.14:1 (AA)
     • mono     light: white on slate-900 #0f172a 17.9:1 (AAA)
                dark:  slate-900 on slate-100 #f1f5f9 16.3:1 (AAA)
     • danger   white on red-600 #dc2626 4.83:1 (AA)
     • outline  slate-900 on white 17.9:1 (AAA)
                dark: slate-50 #f8fafc on slate-800 #1e293b 13.98:1 (AAA)
     • ghost    slate-700 #334155 on white 10.36:1 (AAA); hover → slate-900
   ──────────────────────────────────────────────────────────────────── */

.pf-btn {
    --pf-btn-fg:            var(--pf-button-fg-primary);
    --pf-btn-bg:            var(--pf-button-bg-primary);
    --pf-btn-bg-hover:      var(--pf-button-bg-primary-hover);
    --pf-btn-bg-active:     var(--pf-button-bg-primary-pressed);
    --pf-btn-border:        var(--pf-button-border-primary);
    --pf-btn-border-hover:  var(--pf-button-bg-primary-hover);
    --pf-btn-border-active: var(--pf-button-bg-primary-pressed);
    --pf-btn-shadow:        var(--pf-button-shadow);
    --pf-btn-height:        var(--pf-button-height);
    --pf-btn-px:            var(--pf-button-padding-x);
    --pf-btn-font-size:     var(--pf-button-font-size);
    --pf-btn-glyph:         var(--pf-button-glyph-size);

    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--pf-space-2);
    box-sizing: border-box;
    min-block-size: var(--pf-btn-height);
    margin: 0;
    padding-block: 0;
    padding-inline: var(--pf-btn-px);

    font-family: inherit;
    font-size: var(--pf-btn-font-size);
    font-weight: var(--pf-button-font-weight);
    line-height: var(--pf-text-leading-tight);
    text-decoration: none;
    white-space: nowrap;
    vertical-align: middle;

    color: var(--pf-btn-fg);
    background: var(--pf-btn-bg);
    border: 1px solid var(--pf-btn-border);
    border-radius: var(--pf-button-radius);
    box-shadow: var(--pf-btn-shadow);

    cursor: pointer;
    user-select: none;
    -webkit-appearance: none;
    appearance: none;
}

/* ─── States ─────────────────────────────────────────────────── */

.pf-btn:hover:not(:disabled):not([aria-disabled="true"]) {
    color: var(--pf-btn-fg-hover, var(--pf-btn-fg));
    background: var(--pf-btn-bg-hover);
    border-color: var(--pf-btn-border-hover);
}

.pf-btn:active:not(:disabled):not([aria-disabled="true"]) {
    background: var(--pf-btn-bg-active);
    border-color: var(--pf-btn-border-active);
    box-shadow: none;
}

.pf-btn:focus-visible {
    outline: 2px solid transparent;
    outline-offset: 2px;
    box-shadow: var(--pf-focus-ring);
}

.pf-btn:disabled,
.pf-btn[aria-disabled="true"]:not([aria-busy="true"]) {
    opacity: 0.55;
    cursor: not-allowed;
    box-shadow: none;
}

/* ─── Variants ───────────────────────────────────────────────── */

/* Explicit alias of the default so markup can be self-describing. */
.pf-btn-primary {
    --pf-btn-bg: var(--pf-button-bg-primary);
}

.pf-btn-outline {
    --pf-btn-fg:            var(--pf-button-fg-outline);
    --pf-btn-bg:            transparent;
    --pf-btn-bg-hover:      var(--pf-button-bg-outline-hover);
    --pf-btn-bg-active:     color-mix(in oklab, var(--pf-button-bg-outline-hover) 88%, black);
    --pf-btn-border:        var(--pf-button-border-outline);
    --pf-btn-border-hover:  var(--pf-button-border-outline);
    --pf-btn-border-active: var(--pf-button-border-outline);
    --pf-btn-shadow:        none;
}

.pf-btn-ghost {
    --pf-btn-fg:            var(--pf-button-fg-ghost);
    --pf-btn-fg-hover:      var(--pf-button-fg-ghost-hover);
    --pf-btn-bg:            transparent;
    --pf-btn-bg-hover:      var(--pf-button-bg-ghost-hover);
    --pf-btn-bg-active:     color-mix(in oklab, var(--pf-button-bg-ghost-hover) 88%, black);
    --pf-btn-border:        transparent;
    --pf-btn-border-hover:  transparent;
    --pf-btn-border-active: transparent;
    --pf-btn-shadow:        none;
}

.pf-btn-mono {
    --pf-btn-fg:            var(--pf-button-fg-mono);
    --pf-btn-bg:            var(--pf-button-bg-mono);
    --pf-btn-bg-hover:      var(--pf-button-bg-mono-hover);
    --pf-btn-bg-active:     color-mix(in oklab, var(--pf-button-bg-mono) 80%, black);
    --pf-btn-border:        var(--pf-button-bg-mono);
    --pf-btn-border-hover:  var(--pf-button-bg-mono-hover);
    --pf-btn-border-active: color-mix(in oklab, var(--pf-button-bg-mono) 80%, black);
}

.pf-btn-danger {
    --pf-btn-fg:            var(--pf-button-fg-danger);
    --pf-btn-bg:            var(--pf-button-bg-danger);
    --pf-btn-bg-hover:      var(--pf-button-bg-danger-hover);
    --pf-btn-bg-active:     color-mix(in oklab, var(--pf-button-bg-danger-hover) 88%, black);
    --pf-btn-border:        var(--pf-button-bg-danger);
    --pf-btn-border-hover:  var(--pf-button-bg-danger-hover);
    --pf-btn-border-active: color-mix(in oklab, var(--pf-button-bg-danger-hover) 88%, black);
}

/* ─── Sizes (density-relative) ───────────────────────────────── */

.pf-btn-sm {
    --pf-btn-height:    var(--pf-button-height-sm);
    --pf-btn-px:        var(--pf-button-padding-x-sm);
    --pf-btn-font-size: var(--pf-button-font-size-sm);
    --pf-btn-glyph:     var(--pf-button-glyph-size-sm);
    gap: var(--pf-space-1-5);
}

.pf-btn-lg {
    --pf-btn-height:    var(--pf-button-height-lg);
    --pf-btn-px:        var(--pf-button-padding-x-lg);
    --pf-btn-font-size: var(--pf-button-font-size-lg);
    --pf-btn-glyph:     var(--pf-button-glyph-size-lg);
    gap: var(--pf-space-2-5);
}

.pf-btn-block {
    display: flex;
    inline-size: 100%;
}

/* ─── Icon-only ──────────────────────────────────────────────── */

.pf-btn-icon {
    --pf-btn-px: 0;
    inline-size: var(--pf-btn-height);
    block-size: var(--pf-btn-height);
    padding: 0;
    flex-shrink: 0;
}

/* Pointer-target extension: symmetric around the visual box.
   comfortable 40px → inset -2px (44px target); spacious 44px → 0;
   compact → 0 (hit target = control height, see tokens.components.css). */
.pf-btn-icon::before {
    content: "";
    position: absolute;
    inset: calc((var(--pf-btn-height) - max(var(--pf-btn-height), var(--pf-button-hit-target))) / 2);
}

/* ─── Glyph (inline SVG from UiIcons / <pf-button icon="…">) ──── */

.pf-btn-glyph {
    flex-shrink: 0;
    inline-size: var(--pf-btn-glyph);
    block-size: var(--pf-btn-glyph);
}

/* ─── Loading ────────────────────────────────────────────────── */

.pf-btn[aria-busy="true"],
.pf-btn.pf-btn-loading {
    color: transparent;
    pointer-events: none;
    cursor: progress;
}

.pf-btn[aria-busy="true"] .pf-btn-glyph,
.pf-btn.pf-btn-loading .pf-btn-glyph {
    visibility: hidden;
}

/* Static broken ring — motion is added ONLY under no-preference below. */
.pf-btn[aria-busy="true"]::after,
.pf-btn.pf-btn-loading::after {
    content: "";
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    inline-size: var(--pf-btn-glyph);
    block-size: var(--pf-btn-glyph);
    margin-block-start: calc(var(--pf-btn-glyph) / -2);
    margin-inline-start: calc(var(--pf-btn-glyph) / -2);
    border: 2px solid var(--pf-btn-fg);
    border-inline-end-color: transparent;
    border-radius: 50%;
}

/* ─── Motion (opt-in only) ───────────────────────────────────── */

@media (prefers-reduced-motion: no-preference) {
    .pf-btn {
        transition:
            background-color var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
            border-color var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
            color var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
            box-shadow var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
    }

    .pf-btn[aria-busy="true"]::after,
    .pf-btn.pf-btn-loading::after {
        animation: pf-btn-spin 0.7s linear infinite;
    }

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

/* ─── Windows High Contrast / forced colours ─────────────────── */

@media (forced-colors: active) {
    .pf-btn {
        border-color: ButtonText;
        forced-color-adjust: auto;
    }

    .pf-btn:focus-visible {
        outline-color: Highlight;
    }

    .pf-btn:disabled,
    .pf-btn[aria-disabled="true"]:not([aria-busy="true"]) {
        color: GrayText;
        border-color: GrayText;
        opacity: 1;
    }

    .pf-btn[aria-busy="true"]::after,
    .pf-btn.pf-btn-loading::after {
        border-color: ButtonText;
        border-inline-end-color: transparent;
    }
}
/* ==== css/pf/components/badge.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Badge Component  (CP-4, 2026-09-08)
   ────────────────────────────────────────────────────────────────────
   Status chip for tables, headers and cards. Full status matrix
   (success / warning / danger / info / mono / neutral), outline and
   dot variants, three sizes. docs/design/ADMIN-DESIGN-SYSTEM-PLAN §B3.

   USAGE
     <span class="pf-badge">Neutral</span>
     <span class="pf-badge pf-badge-success">Active</span>
     <span class="pf-badge pf-badge-warning pf-badge-outline">Pending</span>
     <span class="pf-badge pf-badge-danger pf-badge-dot">
       <span class="pf-badge-marker" aria-hidden="true"></span>Overdue
     </span>
     <span class="pf-badge pf-badge-mono pf-badge-sm">v2</span>
     Razor: @await Component.InvokeAsync("Badge", new PfBadgeModel { Text = "Active", Tone = "success", Dot = true })

   DESIGN
     • SOFT fill + status FOREGROUND text by default — the solid status
       fills are reserved for the dot marker and never carry text
       (white on emerald-600 is only 3.77:1).
     • `-outline` = transparent fill, status border, same foreground.
     • `-mono` = the DS-1 near-ink fill (survives both themes).
     • Colour is never the only signal: the label text carries the
       meaning; the dot marker is aria-hidden.

   MEASURED WCAG CONTRAST (sRGB, 2026-09-08 — foreground on soft fill):
     LIGHT  success emerald-800 #065f46 on emerald-50 #ecfdf5  7.30:1 (AAA)
            warning amber-800   #92400e on amber-50   #fffbeb  6.84:1 (AAA)
            danger  red-800     #991b1b on red-50     #fef2f2  7.60:1 (AAA)
            info    sky-800     #075985 on sky-50     #f0f9ff  7.09:1 (AAA)
            neutral slate-700   #334155 on slate-100  #f1f5f9  9.45:1 (AAA)
            mono    white on slate-900 #0f172a                17.9:1 (AAA)
            outline (on surface-raised white): success 7.69 · warning 7.09
                    · danger 8.31 · info 7.56 (all AAA)
     DARK   success emerald-300 #6ee7b7 on emerald-950 #022c22  9.94:1 (AAA)
            warning amber-300   #fcd34d on amber-950   #451a03 10.39:1 (AAA)
            danger  red-300     #fca5a5 on red-950     #450a0a  8.51:1 (AAA)
            info    sky-300     #7dd3fc on sky-950     #082f49  8.33:1 (AAA)
            mono    slate-900 on slate-100                      16.3:1 (AAA)

   Version: 1.0.0
   Created: 2026-09-08
   ──────────────────────────────────────────────────────────────────── */

.pf-badge {
    --pf-badge-bg:     var(--pf-badge-bg-neutral);
    --pf-badge-fg:     var(--pf-badge-fg-neutral);
    --pf-badge-border: var(--pf-badge-border-neutral);
    --pf-badge-accent: var(--pf-badge-accent-neutral);
    --pf-badge-h:      var(--pf-badge-height);
    --pf-badge-px:     var(--pf-badge-padding-x);
    --pf-badge-fs:     var(--pf-badge-font-size);

    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-1);
    box-sizing: border-box;
    min-block-size: var(--pf-badge-h);
    padding-block: 0;
    padding-inline: var(--pf-badge-px);

    font-size: var(--pf-badge-fs);
    font-weight: var(--pf-badge-font-weight);
    line-height: 1;
    white-space: nowrap;
    vertical-align: middle;

    color: var(--pf-badge-fg);
    background: var(--pf-badge-bg);
    border: 1px solid transparent;
    border-radius: var(--pf-badge-radius);
}

/* ─── Status matrix ──────────────────────────────────────────── */

.pf-badge-neutral {
    --pf-badge-bg:     var(--pf-badge-bg-neutral);
    --pf-badge-fg:     var(--pf-badge-fg-neutral);
    --pf-badge-border: var(--pf-badge-border-neutral);
    --pf-badge-accent: var(--pf-badge-accent-neutral);
}

.pf-badge-success {
    --pf-badge-bg:     var(--pf-color-status-success-soft);
    --pf-badge-fg:     var(--pf-color-status-success-fg);
    --pf-badge-border: var(--pf-color-status-success-border);
    --pf-badge-accent: var(--pf-color-status-success);
}

.pf-badge-warning {
    --pf-badge-bg:     var(--pf-color-status-warning-soft);
    --pf-badge-fg:     var(--pf-color-status-warning-fg);
    --pf-badge-border: var(--pf-color-status-warning-border);
    --pf-badge-accent: var(--pf-color-status-warning);
}

.pf-badge-danger {
    --pf-badge-bg:     var(--pf-color-status-danger-soft);
    --pf-badge-fg:     var(--pf-color-status-danger-fg);
    --pf-badge-border: var(--pf-color-status-danger-border);
    --pf-badge-accent: var(--pf-color-status-danger);
}

.pf-badge-info {
    --pf-badge-bg:     var(--pf-color-status-info-soft);
    --pf-badge-fg:     var(--pf-color-status-info-fg);
    --pf-badge-border: var(--pf-color-status-info-border);
    --pf-badge-accent: var(--pf-color-status-info);
}

.pf-badge-mono {
    --pf-badge-bg:     var(--pf-color-mono);
    --pf-badge-fg:     var(--pf-color-mono-foreground);
    --pf-badge-border: var(--pf-color-mono);
    --pf-badge-accent: var(--pf-color-mono-foreground);
}

/* ─── Outline ────────────────────────────────────────────────── */

.pf-badge-outline {
    background: transparent;
    border-color: var(--pf-badge-border);
}

/* Outlined mono reads as ink-on-surface, not paper-on-nothing. */
.pf-badge-mono.pf-badge-outline {
    --pf-badge-fg:     var(--pf-color-mono);
    --pf-badge-accent: var(--pf-color-mono);
}

/* ─── Dot marker (decorative — the label carries the meaning) ─── */

.pf-badge-marker {
    inline-size: 0.375rem;
    block-size: 0.375rem;
    border-radius: 50%;
    background: var(--pf-badge-accent);
    flex-shrink: 0;
}

.pf-badge > svg {
    inline-size: 0.875rem;
    block-size: 0.875rem;
    flex-shrink: 0;
}

/* ─── Sizes ──────────────────────────────────────────────────── */

.pf-badge-sm {
    --pf-badge-h:  var(--pf-badge-height-sm);
    --pf-badge-px: var(--pf-badge-padding-x-sm);
    --pf-badge-fs: var(--pf-badge-font-size-sm);
}

.pf-badge-sm .pf-badge-marker {
    inline-size: 0.3125rem;
    block-size: 0.3125rem;
}

.pf-badge-lg {
    --pf-badge-h:  var(--pf-badge-height-lg);
    --pf-badge-px: var(--pf-badge-padding-x-lg);
    --pf-badge-fs: var(--pf-badge-font-size-lg);
}

/* ─── Windows High Contrast / forced colours ─────────────────── */

@media (forced-colors: active) {
    .pf-badge {
        border-color: CanvasText;
    }

    .pf-badge-marker {
        background: CanvasText;
    }
}
/* ==== css/pf/components/avatar.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Avatar Component  (CP-4, 2026-09-08)
   ────────────────────────────────────────────────────────────────────
   Person / tenant marker with initials fallback, five sizes, an
   optional status dot and a `-stack` group with a "+N" overflow bubble.
   docs/design/ADMIN-DESIGN-SYSTEM-PLAN §B3.

   USAGE
     <span class="pf-avatar pf-avatar-md"><img class="pf-avatar-img" src="…" alt="Anna Berg"></span>
     <span class="pf-avatar pf-avatar-sm">
       <span class="pf-avatar-initials" aria-hidden="true">AB</span>
       <span class="pf-sr-only">Anna Berg</span>
       <span class="pf-avatar-status pf-avatar-status-success" role="img" aria-label="Online"></span>
     </span>
     <span class="pf-avatar-stack">
       <span class="pf-avatar pf-avatar-sm">…</span> ×N
       <span class="pf-avatar pf-avatar-sm pf-avatar-stack-more"><span aria-hidden="true">+3</span><span class="pf-sr-only">3 more</span></span>
     </span>
     Razor: @await Component.InvokeAsync("Avatar", new PfAvatarModel { Name = "Anna Berg", Size = "sm" })
            @await Component.InvokeAsync("AvatarStack", new PfAvatarStackModel { Avatars = […], Max = 4 })

   DESIGN
     • Initials are aria-hidden; the full name travels as .pf-sr-only
       text (or the <img alt>) so the avatar is announced by name.
     • The status dot is separated from the image by a 2px ring in the
       surface colour (a border, not a shadow) so it stays legible on
       any photo. It is decorative unless the VC is given a StatusLabel.
     • Stack overlap is proportional to the size (30%), the ring keeps
       neighbours apart, and a hovered/focused avatar rises above.

   MEASURED WCAG CONTRAST (sRGB, 2026-09-08 — initials on fill):
     neutral  light slate-700 #334155 on slate-100 #f1f5f9   9.45:1 (AAA)
              dark  slate-300 #cbd5e1 on slate-950 #020617  13.59:1 (AAA)
     primary  white on admin navy #2E5C8A 6.97:1 (AA) · on brand red #d4213d 5.14:1 (AA)
     mono     light white on slate-900 17.9:1 · dark slate-900 on slate-100 16.3:1 (AAA)

   Version: 1.0.0
   Created: 2026-09-08
   ──────────────────────────────────────────────────────────────────── */

.pf-avatar {
    --pf-avatar-size:         var(--pf-avatar-size-md);
    --pf-avatar-fill:         var(--pf-avatar-bg);
    --pf-avatar-ink:          var(--pf-avatar-fg);
    --pf-avatar-status-color: var(--pf-color-text-disabled);

    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    inline-size: var(--pf-avatar-size);
    block-size: var(--pf-avatar-size);
    flex-shrink: 0;
    vertical-align: middle;

    font-size: calc(var(--pf-avatar-size) * 0.4);
    font-weight: var(--pf-avatar-font-weight);
    line-height: 1;
    letter-spacing: var(--pf-text-tracking-wide);
    text-transform: uppercase;
    user-select: none;

    color: var(--pf-avatar-ink);
    background: var(--pf-avatar-fill);
    border-radius: var(--pf-avatar-radius);
}

.pf-avatar-img {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    border-radius: inherit;
    object-fit: cover;
}

.pf-avatar-glyph {
    display: inline-flex;
}

.pf-avatar-glyph > svg {
    inline-size: 55%;
    block-size: 55%;
}

/* ─── Sizes ──────────────────────────────────────────────────── */

.pf-avatar-xs { --pf-avatar-size: var(--pf-avatar-size-xs); }
.pf-avatar-sm { --pf-avatar-size: var(--pf-avatar-size-sm); }
.pf-avatar-md { --pf-avatar-size: var(--pf-avatar-size-md); }
.pf-avatar-lg { --pf-avatar-size: var(--pf-avatar-size-lg); }
.pf-avatar-xl { --pf-avatar-size: var(--pf-avatar-size-xl); }

/* ─── Tones ──────────────────────────────────────────────────── */

.pf-avatar-primary {
    --pf-avatar-fill: var(--pf-color-action-primary);
    --pf-avatar-ink:  var(--pf-color-text-on-action);
}

.pf-avatar-mono {
    --pf-avatar-fill: var(--pf-color-mono);
    --pf-avatar-ink:  var(--pf-color-mono-foreground);
}

.pf-avatar-square {
    border-radius: var(--pf-radius-md);
}

/* ─── Status dot ─────────────────────────────────────────────── */

.pf-avatar-status {
    position: absolute;
    inset-block-end: 0;
    inset-inline-end: 0;
    box-sizing: border-box;
    inline-size: calc(var(--pf-avatar-size) * 0.3);
    block-size: calc(var(--pf-avatar-size) * 0.3);
    border: 2px solid var(--pf-avatar-ring);
    border-radius: 50%;
    background: var(--pf-avatar-status-color);
}

.pf-avatar-status-success { --pf-avatar-status-color: var(--pf-color-status-success); }
.pf-avatar-status-warning { --pf-avatar-status-color: var(--pf-color-status-warning); }
.pf-avatar-status-danger  { --pf-avatar-status-color: var(--pf-color-status-danger); }
.pf-avatar-status-info    { --pf-avatar-status-color: var(--pf-color-status-info); }
.pf-avatar-status-neutral { --pf-avatar-status-color: var(--pf-color-text-disabled); }

/* ─── Stack ──────────────────────────────────────────────────── */

.pf-avatar-stack {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
}

.pf-avatar-stack > .pf-avatar {
    border: 2px solid var(--pf-avatar-ring);
    margin-inline-start: calc(var(--pf-avatar-size) * -0.3);
}

.pf-avatar-stack > .pf-avatar:first-child {
    margin-inline-start: 0;
}

.pf-avatar-stack > .pf-avatar:hover,
.pf-avatar-stack > .pf-avatar:focus-visible {
    z-index: 1;
}

.pf-avatar-stack-more {
    --pf-avatar-fill: var(--pf-avatar-bg);
    --pf-avatar-ink:  var(--pf-avatar-fg);
    font-size: calc(var(--pf-avatar-size) * 0.34);
    text-transform: none;
    letter-spacing: 0;
}

/* Focusable avatars (links) get the shared ring. */
.pf-avatar:focus-visible {
    outline: 2px solid transparent;
    outline-offset: 2px;
    box-shadow: var(--pf-focus-ring);
}

/* ─── Windows High Contrast / forced colours ─────────────────── */

@media (forced-colors: active) {
    .pf-avatar {
        border: 1px solid CanvasText;
    }

    .pf-avatar-status {
        background: CanvasText;
        border-color: Canvas;
    }
}
/* ==== css/pf/components/card.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Card Component
   ────────────────────────────────────────────────────────────────────
   Container component for grouped content. Provides consistent surface
   treatment, padding, and elevation across all card-like UI patterns.

   USAGE
     <article class="pf-card">
       <header class="pf-card__header">
         <h3 class="pf-card__title">Card title</h3>
         <p class="pf-card__meta">Subtitle or metadata</p>
       </header>
       <div class="pf-card__body">
         <p>Card content goes here.</p>
       </div>
       <footer class="pf-card__footer">
         <button class="pf-button pf-button--secondary pf-button--sm">Cancel</button>
         <button class="pf-button pf-button--sm">Save</button>
       </footer>
     </article>

     <!-- Variants -->
     <article class="pf-card pf-card--elevated">High shadow</article>
     <article class="pf-card pf-card--outlined">Border-only, no shadow</article>
     <article class="pf-card pf-card--flat">No border, no shadow</article>
     <article class="pf-card pf-card--interactive">Hover-state for clickable cards</article>

     <!-- Status accents (left-border or top-border) -->
     <article class="pf-card pf-card--success">Success-tinted</article>
     <article class="pf-card pf-card--warning">Warning-tinted</article>
     <article class="pf-card pf-card--danger">Danger-tinted</article>
     <article class="pf-card pf-card--info">Info-tinted</article>

   ACCESSIBILITY
     • Use semantic HTML elements (article, section) — class is presentation-only
     • Interactive cards must use <a> or <button> wrapper, not onclick on div
     • Status colors supplemented by icon (not color alone)
     • Card titles should be h3-h6 depending on document hierarchy
     • prefers-reduced-motion respected for hover transforms

   Version: 1.0.0
   Last revised: 2026-05-10
   ──────────────────────────────────────────────────────────────────── */

/* ─── Block: .pf-card (default = raised with subtle border) ─── */

.pf-card {
    /* Layout */
    display: flex;
    flex-direction: column;
    gap: var(--pf-card-gap);

    /* Surface */
    background: var(--pf-card-bg);
    color: var(--pf-card-fg);
    border: 1px solid var(--pf-card-border);
    border-radius: var(--pf-card-radius);
    padding: var(--pf-card-padding);
    box-shadow: var(--pf-card-shadow);

    /* Smooth interactive transitions */
    transition:
        background var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        border-color var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        box-shadow var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        transform var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
}

/* ─── Element: __header ─────────────────────────────────────── */

.pf-card__header {
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-1);
    /* No padding — parent .pf-card supplies it */
}

/* ─── Element: __title ──────────────────────────────────────── */

.pf-card__title {
    margin: 0; /* Reset h1-h6 default margin */
    font-size: var(--pf-card-title-size);
    font-weight: var(--pf-card-title-weight);
    color: var(--pf-card-title-color);
    line-height: var(--pf-text-leading-snug);
}

/* ─── Element: __meta (subtitle, timestamp, author byline) ──── */

.pf-card__meta {
    margin: 0;
    font-size: var(--pf-card-meta-size);
    color: var(--pf-card-meta-color);
    line-height: var(--pf-text-leading-normal);
}

/* ─── Element: __body (main content area) ────────────────────── */

.pf-card__body {
    color: var(--pf-card-body-color);
    font-size: var(--pf-card-body-size);
    line-height: var(--pf-text-leading-normal);
}

.pf-card__body > :first-child { margin-top: 0; }
.pf-card__body > :last-child  { margin-bottom: 0; }

/* ─── Element: __footer (actions / metadata at bottom) ─────── */

.pf-card__footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--pf-space-2);
    padding-top: var(--pf-space-3);
    border-top: 1px solid var(--pf-card-border);
}

/* Footer alignment modifiers */
.pf-card__footer--start  { justify-content: flex-start; }
.pf-card__footer--center { justify-content: center; }
.pf-card__footer--between { justify-content: space-between; }

/* ─── Element: __media (image/video at top — full-bleed) ───── */

.pf-card__media {
    /* Negative margin breaks out of card padding for full-bleed images */
    margin: calc(var(--pf-card-padding) * -1) calc(var(--pf-card-padding) * -1) 0;
    border-top-left-radius: var(--pf-card-radius);
    border-top-right-radius: var(--pf-card-radius);
    overflow: hidden;
    aspect-ratio: 16 / 9;
    background: var(--pf-color-surface-sunken);
}

.pf-card__media img,
.pf-card__media video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ─── Modifier: --elevated (higher shadow for emphasis) ────── */

.pf-card--elevated {
    box-shadow: var(--pf-card-shadow-hover);
}

/* ─── Modifier: --outlined (border-only, no shadow) ────────── */

.pf-card--outlined {
    box-shadow: none;
    border-color: var(--pf-color-border-strong);
}

/* ─── Modifier: --flat (no border, no shadow) ────────────────── */

.pf-card--flat {
    border-color: transparent;
    box-shadow: none;
}

/* ─── Modifier: --interactive (hover state for clickable cards) ── */

.pf-card--interactive {
    cursor: pointer;
}

.pf-card--interactive:hover {
    background: var(--pf-card-bg-hover);
    border-color: var(--pf-color-border-strong);
    box-shadow: var(--pf-card-shadow-hover);
    transform: translateY(-1px);
}

.pf-card--interactive:active {
    transform: translateY(0);
}

.pf-card--interactive:focus-visible {
    outline: none;
    box-shadow: var(--pf-card-shadow-hover), var(--pf-focus-ring);
}

/* ─── Modifier: --compact (less padding) ────────────────────── */

.pf-card--compact {
    padding: var(--pf-space-3);
}

/* ─── Modifier: --spacious (more padding) ────────────────────── */

.pf-card--spacious {
    padding: var(--pf-space-8);
}

/* ─── Status accents (left-border indicator) ────────────────── */

.pf-card--success,
.pf-card--warning,
.pf-card--danger,
.pf-card--info {
    border-inline-start-width: 4px;
}

.pf-card--success { border-inline-start-color: var(--pf-color-status-success); }
.pf-card--warning { border-inline-start-color: var(--pf-color-status-warning); }
.pf-card--danger  { border-inline-start-color: var(--pf-color-status-danger); }
.pf-card--info    { border-inline-start-color: var(--pf-color-status-info); }

/* ─── Reduced-motion respect ─────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .pf-card,
    .pf-card--interactive:hover,
    .pf-card--interactive:active {
        transition: none;
        transform: none;
    }
}

/* ════════════════════════════════════════════════════════════════════
   CP-2 (2026-09-08) — SECTIONED CARD RHYTHM  (admin design system, Phase 3)
   ────────────────────────────────────────────────────────────────────
   docs/design/ADMIN-DESIGN-SYSTEM-PLAN-2026-09-08.md §B3 (`pf-card`
   -header / -content / -footer / -table). The Phase B `.pf-card` block
   above keeps its padded-box behaviour for every existing consumer; a
   card becomes "sectioned" (no outer padding, each section pads itself
   and draws an internal hairline) either explicitly with
   `.pf-card-sectioned` (the `_Card` partial always emits it) or
   implicitly when it directly contains a section element (`:has()`).

   USAGE
     <section class="pf-card pf-card-sectioned">
       <header class="pf-card-header">
         <div class="pf-card-heading">
           <h3 class="pf-card-title">Bookings</h3>
           <p class="pf-card-subtitle">Last 30 days</p>
         </div>
         <div class="pf-card-toolbar"><button class="pf-btn pf-btn-outline pf-btn-sm">Export</button></div>
       </header>
       <div class="pf-card-content">…</div>            ← or:
       <div class="pf-card-table"><table>…</table></div> ← flush table, no double padding
       <footer class="pf-card-footer pf-card-footer-between">…</footer>
     </section>
     Razor: <partial name="_Card" model="card" />  (PfCardViewModel — named slots)

   RHYTHM   — header min-height = --pf-card-header-min-height (56px);
              section padding = --pf-card-section-pad → --pf-card-pad, so
              the DS-1 density band (compact 12 / comfortable 20 /
              spacious 24px) reaches every card without a JS toggle.
   TABLE    — `.pf-card-table` removes the section padding and instead
              pads the FIRST and LAST cell of each row by the section pad,
              so column text aligns with the card title (demo1 pattern)
              while cell padding stays the table's own.
   COLOURS  — tokens only (--pf-card-*, --pf-text-*). No new colour pair:
              title/subtitle reuse the measured Phase B card tokens.
   ──────────────────────────────────────────────────────────────────── */

.pf-card-sectioned,
.pf-card:has(> .pf-card-header, > .pf-card-content, > .pf-card-footer, > .pf-card-table) {
    padding: 0;
    gap: 0;
}

/* ─── Header: title + toolbar slot ───────────────────────────── */

.pf-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-3);
    min-block-size: var(--pf-card-header-min-height);
    padding-block: var(--pf-space-2);
    padding-inline: var(--pf-card-section-pad);
    border-block-end: 1px solid var(--pf-card-border);
}

.pf-card-heading {
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-0-5);
    min-inline-size: 0;
}

.pf-card-title {
    margin: 0;
    font-size: var(--pf-card-title-size);
    font-weight: var(--pf-card-title-weight);
    color: var(--pf-card-title-color);
    line-height: var(--pf-text-leading-snug);
    overflow-wrap: anywhere;
}

.pf-card-subtitle {
    margin: 0;
    font-size: var(--pf-text-2sm);
    color: var(--pf-card-meta-color);
    line-height: var(--pf-text-leading-normal);
}

.pf-card-toolbar {
    display: flex;
    align-items: center;
    gap: var(--pf-space-2);
    margin-inline-start: auto;
    flex-shrink: 0;
}

/* ─── Content ────────────────────────────────────────────────── */

.pf-card-content {
    padding: var(--pf-card-section-pad);
    color: var(--pf-card-body-color);
    font-size: var(--pf-card-body-size);
    line-height: var(--pf-text-leading-normal);
}

.pf-card-content > :first-child { margin-block-start: 0; }
.pf-card-content > :last-child  { margin-block-end: 0; }

/* Stacked content sections separate with the same hairline. */
.pf-card-content + .pf-card-content {
    border-block-start: 1px solid var(--pf-card-border);
}

/* ─── Footer ─────────────────────────────────────────────────── */

.pf-card-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--pf-space-2);
    padding-block: var(--pf-space-3);
    padding-inline: var(--pf-card-section-pad);
    border-block-start: 1px solid var(--pf-card-border);
}

.pf-card-footer-start   { justify-content: flex-start; }
.pf-card-footer-center  { justify-content: center; }
.pf-card-footer-between { justify-content: space-between; }

/* ─── Table variant — flush, no double padding ───────────────── */

.pf-card-table {
    padding: 0;
    overflow-x: auto;
}

.pf-card-table > table {
    inline-size: 100%;
    margin: 0;
    border-collapse: collapse;
}

.pf-card-table tr > :first-child { padding-inline-start: var(--pf-card-section-pad); }
.pf-card-table tr > :last-child  { padding-inline-end: var(--pf-card-section-pad); }

.pf-card-table:first-child {
    border-start-start-radius: inherit;
    border-start-end-radius: inherit;
}

.pf-card-table:last-child {
    border-end-start-radius: inherit;
    border-end-end-radius: inherit;
}
/* ==== css/pf/components/stat.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Stat Tile Component  (CP-3, 2026-09-08)
   ────────────────────────────────────────────────────────────────────
   The dashboard workhorse: label + big `mono` number (tabular-nums) +
   delta chip (▲/▼ in a status tone, with accessible direction text) +
   an optional sparkline slot that DV-1 (Phase 5) fills.
   docs/design/ADMIN-DESIGN-SYSTEM-PLAN §B3.

   USAGE
     <div class="pf-stat-grid">
       <article class="pf-stat">
         <div class="pf-stat-head"><span class="pf-stat-label">Open bookings</span></div>
         <div class="pf-stat-value">1 284</div>
         <div class="pf-stat-meta">
           <span class="pf-stat-delta pf-stat-delta-success">
             <span class="pf-stat-delta-glyph" aria-hidden="true"><svg …/></span>
             <span class="pf-sr-only">Up</span>
             <span class="pf-stat-delta-text">12%</span>
           </span>
           <span class="pf-stat-delta-label">vs. last month</span>
         </div>
         <div class="pf-stat-spark" data-pf-sparkline-slot></div>
       </article>
     </div>
     Razor: @await Component.InvokeAsync("StatTile", new PfStatTileModel { Label = "…", Value = "1 284", Delta = "12%", DeltaDirection = "up" })

   DESIGN
     • The number uses the DS-1 `mono` neutral (--pf-stat-value-color →
       --pf-color-mono): near-ink in light, near-paper in dark — the one
       emphasis colour that stays crisp in both themes. tabular-nums so
       columns of tiles line up digit-for-digit.
     • The delta chip reuses the measured soft-status pairs (see
       badge.css) — success/danger/warning/info/neutral — and the tone
       is a separate axis from the direction ("down" can be good).
     • Padding rides --pf-card-pad, so tiles follow the density band.

   MEASURED WCAG CONTRAST (sRGB, 2026-09-08):
     value   light slate-900 #0f172a on white 17.9:1 · dark slate-100 on slate-800 13.4:1 (AAA)
     label   slate-700 #334155 on white 10.36:1 (AAA) · dark slate-300 on slate-800 9.6:1 (AAA)
     meta    slate-500 #64748b on white 4.76:1 (AA)
     delta   the badge.css soft pairs — 6.84:1 … 10.39:1 (AAA), neutral 9.45:1

   Version: 1.0.0
   Created: 2026-09-08
   ──────────────────────────────────────────────────────────────────── */

.pf-stat {
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-2);
    box-sizing: border-box;
    min-inline-size: 0;
    padding: var(--pf-stat-padding);

    color: var(--pf-color-text-primary);
    background: var(--pf-stat-bg);
    border: 1px solid var(--pf-stat-border);
    border-radius: var(--pf-stat-radius);
    box-shadow: var(--pf-stat-shadow);
}

.pf-stat-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-2);
    min-inline-size: 0;
}

.pf-stat-label {
    font-size: var(--pf-text-2sm);
    font-weight: var(--pf-text-weight-medium);
    line-height: var(--pf-text-leading-snug);
    color: var(--pf-stat-label-color);
    overflow-wrap: anywhere;
}

.pf-stat-icon {
    display: inline-flex;
    flex-shrink: 0;
    color: var(--pf-stat-meta-color);
}

.pf-stat-value {
    font-size: var(--pf-stat-value-size);
    font-weight: var(--pf-text-weight-bold);
    line-height: 1.1;
    letter-spacing: var(--pf-text-tracking-tight);
    color: var(--pf-stat-value-color);
    font-variant-numeric: tabular-nums lining-nums;
    overflow-wrap: anywhere;
}

.pf-stat-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--pf-space-2);
    font-size: var(--pf-text-2sm);
    color: var(--pf-stat-meta-color);
}

/* ─── Delta chip ─────────────────────────────────────────────── */

.pf-stat-delta {
    --pf-stat-delta-bg: var(--pf-badge-bg-neutral);
    --pf-stat-delta-fg: var(--pf-badge-fg-neutral);

    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-1);
    box-sizing: border-box;
    min-block-size: 1.25rem;
    padding-inline: var(--pf-space-1-5);
    border-radius: var(--pf-badge-radius);
    font-size: var(--pf-text-2xs);
    font-weight: var(--pf-text-weight-semibold);
    line-height: 1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--pf-stat-delta-fg);
    background: var(--pf-stat-delta-bg);
}

.pf-stat-delta-glyph {
    display: inline-flex;
}

.pf-stat-delta-glyph > svg {
    inline-size: 0.75rem;
    block-size: 0.75rem;
}

.pf-stat-delta-success {
    --pf-stat-delta-bg: var(--pf-color-status-success-soft);
    --pf-stat-delta-fg: var(--pf-color-status-success-fg);
}

.pf-stat-delta-danger {
    --pf-stat-delta-bg: var(--pf-color-status-danger-soft);
    --pf-stat-delta-fg: var(--pf-color-status-danger-fg);
}

.pf-stat-delta-warning {
    --pf-stat-delta-bg: var(--pf-color-status-warning-soft);
    --pf-stat-delta-fg: var(--pf-color-status-warning-fg);
}

.pf-stat-delta-info {
    --pf-stat-delta-bg: var(--pf-color-status-info-soft);
    --pf-stat-delta-fg: var(--pf-color-status-info-fg);
}

.pf-stat-delta-neutral {
    --pf-stat-delta-bg: var(--pf-badge-bg-neutral);
    --pf-stat-delta-fg: var(--pf-badge-fg-neutral);
}

.pf-stat-delta-label {
    min-inline-size: 0;
}

.pf-stat-hint {
    margin: 0;
    font-size: var(--pf-text-2xs);
    line-height: var(--pf-text-leading-normal);
    color: var(--pf-stat-meta-color);
}

/* ─── Sparkline slot (DV-1 fills it; empty today) ─────────────── */

.pf-stat-spark {
    margin-block-start: auto;
    block-size: var(--pf-stat-spark-height);
    color: var(--pf-stat-spark-color);
}

.pf-stat-spark > svg {
    display: block;
    inline-size: 100%;
    block-size: 100%;
}

/* ─── Grid helper ────────────────────────────────────────────── */

.pf-stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--pf-space-4);
}

/* ─── Windows High Contrast / forced colours ─────────────────── */

@media (forced-colors: active) {
    .pf-stat,
    .pf-stat-delta {
        border: 1px solid CanvasText;
    }
}
/* ==== css/pf/components/empty.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Empty State Component  (CP-5, 2026-09-08)
   ────────────────────────────────────────────────────────────────────
   icon + title + hint + CTA slot — a first-class "nothing here yet"
   surface for tables, lists and dashboards (a beat-it axis; the
   reference template under-invests here). docs/design/ADMIN-DESIGN-
   SYSTEM-PLAN §B3 / §B7.

   USAGE
     <div class="pf-empty">
       <div class="pf-empty-icon" aria-hidden="true"><svg …/></div>
       <h3 class="pf-empty-title">No bookings yet</h3>
       <p class="pf-empty-hint">Bookings appear here as residents reserve facilities.</p>
       <div class="pf-empty-cta"><button class="pf-btn">Create booking</button></div>
     </div>
     <div class="pf-empty pf-empty-sm pf-empty-plain">…</div>   ← inside a card / table body
     Razor: @await Component.InvokeAsync("EmptyState", new PfEmptyStateModel { Title = "…", Cta = @<pf-button>…</pf-button> })
            (Title / Hint fall back to the localised Pf_Empty_Title / Pf_Empty_Hint)

   DESIGN
     • Dashed border-strong frame on a raised surface; `-plain` drops
       the frame for use inside an already-framed container.
     • The icon sits in a sunken tile (decorative, aria-hidden); the
       title is a real heading so screen-reader users can navigate to it.

   MEASURED WCAG CONTRAST (sRGB, 2026-09-08):
     title slate-900 on white 17.9:1 (AAA) · hint slate-700 on white 10.36:1 (AAA)
     dark: slate-50 on slate-800 13.98:1 · slate-300 on slate-800 9.6:1 (AAA)

   Version: 1.0.0
   Created: 2026-09-08
   ──────────────────────────────────────────────────────────────────── */

.pf-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--pf-space-3);
    box-sizing: border-box;
    padding-block: var(--pf-empty-padding-y);
    padding-inline: var(--pf-empty-padding-x);

    color: var(--pf-empty-hint-color);
    background: var(--pf-color-surface-raised);
    border: 1px dashed var(--pf-empty-border);
    border-radius: var(--pf-empty-radius);
}

.pf-empty-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: var(--pf-empty-icon-size);
    block-size: var(--pf-empty-icon-size);
    color: var(--pf-empty-icon-fg);
    background: var(--pf-empty-icon-bg);
    border-radius: var(--pf-empty-icon-radius);
}

.pf-empty-title {
    margin: 0;
    font-size: var(--pf-text-size-lg);
    font-weight: var(--pf-text-weight-semibold);
    line-height: var(--pf-text-leading-snug);
    color: var(--pf-empty-title-color);
}

.pf-empty-hint {
    margin: 0;
    max-inline-size: 36rem;
    font-size: var(--pf-text-size-sm);
    line-height: var(--pf-text-leading-normal);
    color: var(--pf-empty-hint-color);
}

.pf-empty-cta {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--pf-space-2);
    margin-block-start: var(--pf-space-1);
}

/* ─── Variants ───────────────────────────────────────────────── */

.pf-empty-sm {
    gap: var(--pf-space-2);
    padding-block: var(--pf-space-6);
    padding-inline: var(--pf-space-4);
}

.pf-empty-sm .pf-empty-icon {
    inline-size: 2.5rem;
    block-size: 2.5rem;
    border-radius: var(--pf-radius-lg);
}

.pf-empty-sm .pf-empty-title {
    font-size: var(--pf-text-size-base);
}

.pf-empty-plain {
    background: transparent;
    border-color: transparent;
}

/* ─── Windows High Contrast / forced colours ─────────────────── */

@media (forced-colors: active) {
    .pf-empty {
        border-color: CanvasText;
    }

    .pf-empty-plain {
        border-color: transparent;
    }
}
/* ==== css/pf/components/skeleton.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Skeleton / Loading Component  (CP-5, 2026-09-08)
   ────────────────────────────────────────────────────────────────────
   Shimmer placeholders for rows, cards and text while data loads.
   The shimmer exists ONLY under prefers-reduced-motion: no-preference;
   everyone else gets calm static blocks (WCAG 2.3.3).
   docs/design/ADMIN-DESIGN-SYSTEM-PLAN §B3 / §B6.

   USAGE
     <div class="pf-skeleton pf-skeleton-rows" role="status" aria-busy="true">
       <span class="pf-sr-only">Loading…</span>
       <div class="pf-skeleton-row" aria-hidden="true">
         <span class="pf-skeleton-block pf-skeleton-circle"></span>
         <span class="pf-skeleton-row-lines">
           <span class="pf-skeleton-block pf-skeleton-w-60"></span>
           <span class="pf-skeleton-block pf-skeleton-w-40"></span>
         </span>
       </div>
     </div>
     Razor: <partial name="_Skeleton" model='new PfSkeletonViewModel { Kind = "rows", Count = 5 }' />

   DESIGN
     • Blocks use the sunken surface; the shine is border-subtle mixed
       across a 200%-wide gradient — both are theme tokens, so dark mode
       shimmers on its own surfaces without a second rule set.
     • Row height rides --pf-row-height and card padding --pf-card-pad,
       so a skeleton occupies the same space as the content it stands
       in for at every density (no layout shift on arrival).
     • The container is role="status" + aria-busy; the blocks are
       aria-hidden — assistive tech hears one "Loading…" not N boxes.

   Version: 1.0.0
   Created: 2026-09-08
   ──────────────────────────────────────────────────────────────────── */

.pf-skeleton {
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-3);
    min-inline-size: 0;
}

.pf-skeleton-block {
    display: block;
    box-sizing: border-box;
    inline-size: 100%;
    block-size: var(--pf-skeleton-line-height);
    background-color: var(--pf-skeleton-bg);
    border-radius: var(--pf-skeleton-radius);
}

.pf-skeleton-circle {
    inline-size: var(--pf-avatar-size-md);
    block-size: var(--pf-avatar-size-md);
    border-radius: 50%;
    flex-shrink: 0;
}

.pf-skeleton-title {
    inline-size: 40%;
    block-size: 1rem;
}

.pf-skeleton-button {
    inline-size: 6rem;
    block-size: var(--pf-control-height);
    border-radius: var(--pf-button-radius);
}

/* Width helpers */
.pf-skeleton-w-25 { inline-size: 25%; }
.pf-skeleton-w-40 { inline-size: 40%; }
.pf-skeleton-w-60 { inline-size: 60%; }
.pf-skeleton-w-75 { inline-size: 75%; }

/* ─── Row (table / list placeholder) ─────────────────────────── */

.pf-skeleton-row {
    display: flex;
    align-items: center;
    gap: var(--pf-space-3);
    min-block-size: var(--pf-row-height);
}

.pf-skeleton-row-lines {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--pf-space-2);
    min-inline-size: 0;
}

/* ─── Card placeholder ───────────────────────────────────────── */

.pf-skeleton-card {
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-3);
    padding: var(--pf-card-pad);
    border: 1px solid var(--pf-color-border-subtle);
    border-radius: var(--pf-card-radius);
}

/* ─── Shimmer — motion is opt-in only ────────────────────────── */

@media (prefers-reduced-motion: no-preference) {
    .pf-skeleton-block {
        background-image: linear-gradient(
            90deg,
            var(--pf-skeleton-bg) 0%,
            var(--pf-skeleton-shine) 50%,
            var(--pf-skeleton-bg) 100%
        );
        background-size: 200% 100%;
        background-repeat: no-repeat;
        animation: pf-skeleton-shimmer var(--pf-skeleton-duration) ease-in-out infinite;
    }

    @keyframes pf-skeleton-shimmer {
        from { background-position: 200% 0; }
        to   { background-position: -200% 0; }
    }
}

/* ─── Windows High Contrast / forced colours ─────────────────── */

@media (forced-colors: active) {
    .pf-skeleton-block {
        background: GrayText;
        opacity: 0.35;
    }
}
/* ==== css/pf/components/icon.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Icon  (PL-2, 2026-09-08)
   ────────────────────────────────────────────────────────────────────
   The inline SVG icon the Icon ViewComponent emits from the sprite
   (wwwroot/icons/pf-sprite.svg — Lucide ISC + our own glyphs, provenance
   in icons.manifest.json). docs/design/ADMIN-DESIGN-SYSTEM-PLAN §B5.

   USAGE
     Razor: @await Component.InvokeAsync("Icon", new PfIconModel { Name = "house" })
            @await Component.InvokeAsync("Icon", new PfIconModel { Name = "trash-2", Size = "sm", Label = "Delete" })
     Output: <svg class="pf-icon pf-icon-md" width="20" height="20" viewBox="0 0 24 24"
                  fill="none" stroke="currentColor" stroke-width="1.75" … aria-hidden="true">…</svg>

   DESIGN
     • currentColor — the icon takes the text colour of its parent; tint
       an icon by colouring its container, never the icon itself.
     • One stroke rhythm (1.75, round joins) — the attribute is on the
       svg so a bare <svg><use> renders the same; this sheet mirrors it
       through --pf-icon-stroke-width so a surface can tune it in CSS.
     • Sizes ride tokens (--pf-icon-size-*): xs 14 · sm 16 · md 20 (nav
       rhythm, default) · lg 24 · xl 32. width/height attributes are the
       no-CSS fallback and match the md/xs/… token values.
     • flex: none — an icon never shrinks in a flex row; vertical-align
       middle for inline text runs.
   ════════════════════════════════════════════════════════════════════ */

.pf-icon {
    display: inline-block;
    inline-size: var(--pf-icon-size-md);
    block-size: var(--pf-icon-size-md);
    flex: none;
    vertical-align: middle;
    fill: none;
    stroke: currentColor;
    stroke-width: var(--pf-icon-stroke-width);
    stroke-linecap: round;
    stroke-linejoin: round;
}

.pf-icon-xs { inline-size: var(--pf-icon-size-xs); block-size: var(--pf-icon-size-xs); }
.pf-icon-sm { inline-size: var(--pf-icon-size-sm); block-size: var(--pf-icon-size-sm); }
.pf-icon-md { inline-size: var(--pf-icon-size-md); block-size: var(--pf-icon-size-md); }
.pf-icon-lg { inline-size: var(--pf-icon-size-lg); block-size: var(--pf-icon-size-lg); }
.pf-icon-xl { inline-size: var(--pf-icon-size-xl); block-size: var(--pf-icon-size-xl); }

/* Buttons and nav items already reserve a fixed icon slot; inside them the
   icon sits on the flex cross-axis, so no vertical-align nudge is needed. */
.pf-btn > .pf-icon,
.pf-menu-item > .pf-icon {
    vertical-align: initial;
}
/* ==== css/pf/components/chart.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Charts  (DV-1 / DV-2, 2026-09-08)
   ────────────────────────────────────────────────────────────────────
   The CSS side of platforma-charts.js (Tier 1: inline-SVG sparkline /
   bars / donut) and platforma-charts-rich.js (Tier 2: the lazy uPlot
   wrapper). The JS never paints — every shape is currentColor or carries
   a pf-chart-* class bound HERE to --pf-chart-* component tokens
   (tokens.components.css), so charts follow light / dark / edition /
   tenant theming automatically. docs/design/ADMIN-DESIGN-SYSTEM-PLAN §B5.

   USAGE (Tier 1 — attribute-driven, drawn by the `chart` behaviour)
     <div data-pf-chart="area" data-pf-chart-values="3,5,4,8"></div>
     <div data-pf-chart="bar"  data-pf-chart-values="12,8,15,9" data-pf-chart-tone="info"></div>
     <div data-pf-chart="gauge" data-pf-chart-values="42" data-pf-chart-max="100"
          data-pf-chart-center="42%" data-pf-chart-sweep="270"></div>
     <div data-pf-chart="donut" data-pf-chart-values="40,35,25"
          data-pf-chart-labels="Rent|Fees|Other" data-pf-chart-table></div>
     Razor: @await Component.InvokeAsync("StatTile", new PfStatTileModel { …, SparklineValues = [3, 5, 4, 8] })

   USAGE (Tier 2 — the page includes platforma-charts-rich.js; uPlot loads on demand)
     <div data-pf-chart-rich="line" data-pf-chart-rich-height="240">
       <script type="application/json">{ "x": [1725753600, …], "series": [{ "label": "Bookings", "values": [3, 5, …] }] }</script>
     </div>

   DESIGN
     • One accent per chart (restraint): the container colour is
       --pf-chart-color (action-primary); a StatTile slot hands its own
       --pf-stat-spark-color down. Tones swap the accent for a status /
       mono / muted role — never a raw palette value.
     • Multi-segment donuts use the six-step series palette
       (--pf-chart-series-1..6 = primary → info → success → warning →
       danger → mono); a single gauge arc stays currentColor.
     • Strokes are non-scaling (screen px) so a stretched viewBox never
       fattens a line; the last-point marker is a round-capped zero-length
       line for the same reason.
     • Motion (draw-in / rise / fade) exists ONLY under
       prefers-reduced-motion: no-preference — and the JS adds
       .is-animated only when the OS does not ask for reduced motion.
     • The rich chart's cursor / selection / legend chrome is re-themed
       here with a higher specificity than uPlot.min.css (which is
       appended to <head> at runtime and would otherwise win the cascade).

   MEASURED WCAG CONTRAST (sRGB, 2026-09-08 — non-text graphics, SC 1.4.11 ≥ 3:1):
     accent line  navy #2E5C8A on white 6.28:1 · on parchment 5.9:1 (AA)
     status       success-fg / danger-fg / warning-fg pairs as badge.css (≥ 4.5:1)
     centre text  mono slate-900 on white 17.9:1 · dark slate-100 on slate-800 13.4:1 (AAA)
     track        border-subtle is decorative (not a required signal — the arc carries it)

   Version: 1.0.0
   Created: 2026-09-08
   ──────────────────────────────────────────────────────────────────── */

/* ─── Container ──────────────────────────────────────────────── */

.pf-chart {
    display: block;
    position: relative;
    box-sizing: border-box;
    inline-size: 100%;
    block-size: 100%;
    min-block-size: var(--pf-chart-min-height);
    color: var(--pf-chart-color);
}

/* A StatTile slot hands its own accent down (the slot sets the custom
   property, so a tone class on the chart itself still wins). */
.pf-stat-spark {
    --pf-chart-color: var(--pf-stat-spark-color);
}

.pf-stat-spark > .pf-chart {
    min-block-size: 0;
}

.pf-chart > .pf-chart-svg {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    overflow: visible;
}

.pf-chart-donut {
    block-size: auto;
    max-inline-size: var(--pf-chart-donut-max);
    aspect-ratio: 1 / 1;
}

.pf-chart-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    block-size: 100%;
    min-block-size: inherit;
    font-size: var(--pf-text-2xs);
    color: var(--pf-color-text-tertiary);
}

/* ─── Tones (the container or a single bar / arc) ────────────── */

.pf-chart-tone-primary { --pf-chart-color: var(--pf-color-action-primary); color: var(--pf-chart-color); }
.pf-chart-tone-success { --pf-chart-color: var(--pf-color-status-success); color: var(--pf-chart-color); }
.pf-chart-tone-warning { --pf-chart-color: var(--pf-color-status-warning); color: var(--pf-chart-color); }
.pf-chart-tone-danger  { --pf-chart-color: var(--pf-color-status-danger);  color: var(--pf-chart-color); }
.pf-chart-tone-info    { --pf-chart-color: var(--pf-color-status-info);    color: var(--pf-chart-color); }
.pf-chart-tone-mono    { --pf-chart-color: var(--pf-color-mono);           color: var(--pf-chart-color); }
.pf-chart-tone-muted   { --pf-chart-color: var(--pf-color-text-tertiary);  color: var(--pf-chart-color); }

/* ─── Sparkline ──────────────────────────────────────────────── */

.pf-chart-line {
    fill: none;
    stroke: currentColor;
    stroke-width: var(--pf-chart-stroke);
    stroke-linecap: round;
    stroke-linejoin: round;
}

.pf-chart-area {
    fill: currentColor;
    fill-opacity: var(--pf-chart-area-opacity);
    stroke: none;
}

.pf-chart-marker {
    stroke: currentColor;
    stroke-width: var(--pf-chart-marker-size);
    stroke-linecap: round;
}

.pf-chart-baseline {
    fill: none;
    stroke: var(--pf-chart-grid);
    stroke-width: 1;
    stroke-dasharray: 3 3;
}

/* ─── Bars ───────────────────────────────────────────────────── */

.pf-chart-bar {
    fill: currentColor;
    opacity: var(--pf-chart-bar-opacity);
}

.pf-chart-bar.is-last,
.pf-chart-bar[class*="pf-chart-tone-"] {
    opacity: 1;
}

/* ─── Donut / gauge ──────────────────────────────────────────── */

.pf-chart-track {
    fill: none;
    stroke: var(--pf-chart-track);
}

.pf-chart-arc {
    fill: none;
    stroke: currentColor;
}

.pf-chart-seg-1 { stroke: var(--pf-chart-series-1); }
.pf-chart-seg-2 { stroke: var(--pf-chart-series-2); }
.pf-chart-seg-3 { stroke: var(--pf-chart-series-3); }
.pf-chart-seg-4 { stroke: var(--pf-chart-series-4); }
.pf-chart-seg-5 { stroke: var(--pf-chart-series-5); }
.pf-chart-seg-6 { stroke: var(--pf-chart-series-6); }

.pf-chart-center {
    fill: var(--pf-chart-center-fg);
    font-family: var(--pf-font-family-sans);
    font-size: var(--pf-chart-center-size);
    font-weight: var(--pf-text-weight-semibold);
    font-variant-numeric: tabular-nums lining-nums;
}

/* ─── Rich chart (DV-2: the lazy uPlot wrapper) ──────────────── */

.pf-chart-rich {
    display: block;
    position: relative;
    box-sizing: border-box;
    min-block-size: var(--pf-chart-rich-min-height);
    color: var(--pf-chart-axis-fg);
    font-family: var(--pf-font-family-sans);
    font-size: var(--pf-text-2sm);
}

.pf-chart-rich[aria-busy="true"] {
    background: var(--pf-color-surface-sunken);
    border-radius: var(--pf-radius-md);
}

.pf-chart-rich .uplot {
    inline-size: 100%;
    font-family: inherit;
    line-height: inherit;
}

.pf-chart-rich .uplot .u-legend {
    padding-block-start: var(--pf-space-2);
    font-size: var(--pf-text-2xs);
    text-align: start;
    color: var(--pf-chart-legend-fg);
}

.pf-chart-rich .uplot .u-legend .u-marker {
    border-radius: var(--pf-radius-sm);
}

.pf-chart-rich .uplot .u-select {
    background: var(--pf-chart-select);
}

.pf-chart-rich .u-hz .u-cursor-x,
.pf-chart-rich .u-vt .u-cursor-y {
    border-right-color: var(--pf-chart-cursor);
}

.pf-chart-rich .u-hz .u-cursor-y,
.pf-chart-rich .u-vt .u-cursor-x {
    border-bottom-color: var(--pf-chart-cursor);
}

.pf-chart-rich-error {
    padding: var(--pf-space-2) 0;
    font-size: var(--pf-text-2sm);
    color: var(--pf-color-status-danger-fg);
}

/* ─── Motion (opt-in by the OS; the JS only adds .is-animated then) ── */

@media (prefers-reduced-motion: no-preference) {
    .pf-chart-svg.is-animated .pf-chart-line {
        stroke-dasharray: 1;
        stroke-dashoffset: 1;
        animation: pf-chart-draw var(--pf-chart-duration) var(--pf-motion-ease-out) forwards;
    }

    .pf-chart-svg.is-animated .pf-chart-area,
    .pf-chart-svg.is-animated .pf-chart-marker,
    .pf-chart-svg.is-animated .pf-chart-center,
    .pf-chart-svg.is-animated .pf-chart-arc {
        animation: pf-chart-fade var(--pf-chart-duration) var(--pf-motion-ease-out) both;
    }

    .pf-chart-svg.is-animated .pf-chart-marker,
    .pf-chart-svg.is-animated .pf-chart-center {
        animation-delay: calc(var(--pf-chart-duration) / 2);
    }

    .pf-chart-svg.is-animated .pf-chart-bar {
        transform-box: fill-box;
        transform-origin: bottom;
        animation: pf-chart-rise var(--pf-chart-duration) var(--pf-motion-ease-out) both;
    }

    @keyframes pf-chart-draw {
        to { stroke-dashoffset: 0; }
    }

    @keyframes pf-chart-fade {
        from { opacity: 0; }
    }

    @keyframes pf-chart-rise {
        from { transform: scaleY(0); }
    }
}

/* ─── Windows High Contrast / forced colours ─────────────────── */

@media (forced-colors: active) {
    .pf-chart-line,
    .pf-chart-marker,
    .pf-chart-arc {
        stroke: CanvasText;
    }

    .pf-chart-area,
    .pf-chart-bar,
    .pf-chart-center {
        fill: CanvasText;
    }

    .pf-chart-track,
    .pf-chart-baseline {
        stroke: GrayText;
    }

    .pf-chart-rich {
        border: 1px solid CanvasText;
    }
}
/* ==== css/pf/components/interactions.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Interaction hooks  (JS-2, 2026-09-08)
   ────────────────────────────────────────────────────────────────────
   The CSS side of platforma-ui.js (docs/design/ADMIN-DESIGN-SYSTEM-PLAN
   §B4 / §B8 Phase 4): the [hidden] guards the registry toggles, the
   dropdown anchor, the shared tooltip bubble and the sticky cue. Every
   value is a --pf-* token; motion exists ONLY under
   prefers-reduced-motion: no-preference (WCAG 2.3.3).

   USAGE (behaviour attributes — see the platforma-ui.js header)
     <div data-pf-dropdown data-pf-dropdown-placement="bottom-end">
       <button class="pf-btn" data-pf-dropdown-toggle>Actions</button>
       <div class="pf-popover" role="menu" data-pf-dropdown-panel hidden>
         <div class="pf-popover__body"><button class="pf-popover__item" role="menuitem">Edit</button></div>
       </div>
     </div>
     <button class="pf-btn pf-btn-icon" data-pf-tooltip="Delete">…</button>
     <header data-pf-sticky>…</header>        ← gains .is-stuck once pinned

   MEASURED WCAG CONTRAST (sRGB, 2026-09-08):
     tooltip: text-inverse (white) on text-primary (slate-900) 17.9:1 (AAA)
     dark:    slate-900 on slate-50 17.9:1 (AAA)

   Version: 1.0.0
   Created: 2026-09-08
   ──────────────────────────────────────────────────────────────────── */

/* ─── [hidden] guards — the registry toggles the attribute; win over any
       display rule the host component may set on the same element ──── */

[data-pf-modal][hidden],
[data-pf-drawer][hidden],
[data-pf-dropdown-panel][hidden],
[data-pf-tabs] [role="tabpanel"][hidden],
[data-pf-menu] [hidden] {
    display: none !important;
}

/* ─── Dropdown anchor ─────────────────────────────────────────── */

[data-pf-dropdown] {
    position: relative;
}

/* A panel that is not a .pf-popover still floats under its toggle. */
[data-pf-dropdown] > [data-pf-dropdown-panel]:not(.pf-popover) {
    position: absolute;
    inset-block-start: calc(100% + var(--pf-space-1));
    inset-inline-start: 0;
    z-index: var(--pf-z-dropdown);
    min-inline-size: 100%;
}

[data-pf-dropdown] > [data-pf-dropdown-panel]:not(.pf-popover).pf-popover--top {
    inset-block-start: auto;
    inset-block-end: calc(100% + var(--pf-space-1));
}

/* ─── Tooltip bubble (one shared element, fixed, positioned by JS) ── */

.pf-tooltip {
    position: fixed;
    z-index: var(--pf-tooltip-z-index);
    box-sizing: border-box;
    max-inline-size: var(--pf-tooltip-max-width);
    padding: var(--pf-tooltip-padding-y) var(--pf-tooltip-padding-x);
    background: var(--pf-tooltip-bg);
    color: var(--pf-tooltip-fg);
    border-radius: var(--pf-tooltip-radius);
    box-shadow: var(--pf-tooltip-shadow);
    font-size: var(--pf-text-size-xs);
    line-height: var(--pf-text-leading-snug);
    pointer-events: none;
    opacity: 0;
}

.pf-tooltip.is-visible {
    opacity: 1;
}

.pf-tooltip[hidden] {
    display: none;
}

/* ─── Sticky cue — a hairline shadow once pinned ───────────────── */

[data-pf-sticky].is-stuck {
    box-shadow: var(--pf-shadow-sm);
}

/* ─── Motion — opt-in only ──────────────────────────────────────── */

@media (prefers-reduced-motion: no-preference) {
    .pf-tooltip {
        transition: opacity var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
    }
}

/* ─── Windows High Contrast / forced colours ─────────────────── */

@media (forced-colors: active) {
    .pf-tooltip {
        border: 1px solid CanvasText;
    }
}
/* ==== css/pf/components/table.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Table finish  (JS-3, 2026-09-08)
   ────────────────────────────────────────────────────────────────────
   The CSS side of the opt-in data-pf-table behaviour (platforma-tables.js
   → Platforma.UI 'table'): toolbar (search), footer (page size · status ·
   pager), sortable headers with aria-sort arrows, sticky header, the
   row-select column and the CP-5 state rows (empty / skeleton). Nothing
   here applies until a <table> opts in — existing .platforma-table pages
   are byte-identical. docs/design/ADMIN-DESIGN-SYSTEM-PLAN §B4 / §B8.

   USAGE
     <div class="platforma-table-wrapper">
       <table class="platforma-table" data-pf-table data-pf-table-page-size="25"
              data-pf-table-search data-pf-table-select data-pf-table-sticky>
         <thead><tr>
           <th data-pf-sort="string">Name</th>
           <th data-pf-sort="date" data-pf-priority="3">Created</th>
         </tr></thead>
         <tbody><tr data-pf-row-id="42"><td>…</td><td>…</td></tr></tbody>
       </table>
     </div>
   Responsive priority columns reuse platforma-table-col-prio-{2,3,4}
   (platforma-tables.css: the 1600 / 1280 / 900 discipline).

   MEASURED WCAG CONTRAST (sRGB, 2026-09-08):
     footer text slate-700 on white 10.36:1 (AAA) · sort arrow (active)
     indigo-600 on slate-50 5.9:1 (AA, non-text) · dark: slate-300 on
     slate-800 9.6:1 (AAA)

   Version: 1.0.0
   Created: 2026-09-08
   ──────────────────────────────────────────────────────────────────── */

/* ─── Row visibility — the behaviour toggles [hidden] on <tr> ────── */

[data-pf-table] tr[hidden] {
    display: none !important;
}

/* ─── Toolbar (search) ──────────────────────────────────────────── */

.pf-table-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--pf-space-3);
    padding: var(--pf-space-3) var(--pf-table-pad-x);
    border-block-end: 1px solid var(--pf-table-border);
}

.pf-table-search {
    flex: 1 1 12rem;
    max-inline-size: var(--pf-table-search-width);
}

/* ─── Footer (page size · status · pager) ───────────────────────── */

.pf-table-footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--pf-space-3);
    padding: var(--pf-space-3) var(--pf-table-pad-x);
    border-block-start: 1px solid var(--pf-table-border);
    font-size: var(--pf-text-size-sm);
    color: var(--pf-table-footer-fg);
}

.pf-table-page-size {
    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-2);
    white-space: nowrap;
}

.pf-table-page-size .pf-input {
    inline-size: auto;
}

.pf-table-status {
    flex: 1 1 auto;
    margin: 0;
    min-inline-size: 0;
    font-variant-numeric: tabular-nums lining-nums;
}

.pf-table-pager {
    display: inline-flex;
    gap: var(--pf-space-1);
    margin-inline-start: auto;
}

/* ─── Sortable headers (aria-sort drives the arrow) ─────────────── */

th.pf-table-sortable {
    position: relative;
    cursor: pointer;
    user-select: none;
    padding-inline-end: var(--pf-space-6);
}

th.pf-table-sortable:hover {
    color: var(--pf-color-text-primary);
    background: var(--pf-color-surface-hover);
}

th.pf-table-sortable:focus-visible {
    outline: 2px solid transparent;
    box-shadow: var(--pf-focus-ring);
}

th.pf-table-sortable::after {
    content: '';
    position: absolute;
    inset-inline-end: var(--pf-space-2);
    inset-block-start: 50%;
    inline-size: 0;
    block-size: 0;
    border-inline: 4px solid transparent;
    border-block-start: 5px solid var(--pf-table-sort-idle);
    transform: translateY(-50%);
}

th.pf-table-sortable[aria-sort="ascending"]::after {
    border-block-start-color: var(--pf-table-sort-active);
    transform: translateY(-50%) rotate(180deg);
}

th.pf-table-sortable[aria-sort="descending"]::after {
    border-block-start-color: var(--pf-table-sort-active);
}

/* ─── Sticky header ─────────────────────────────────────────────── */

.pf-table-sticky thead th {
    position: sticky;
    inset-block-start: var(--pf-table-sticky-top);
    z-index: var(--pf-z-raised);
    background: var(--pf-table-head-bg);
    box-shadow: var(--pf-table-head-shadow);
}

/* page-level: the wrapper must not become a scroll container (clip keeps
   the horizontal overflow contained without trapping the sticky header) */
.pf-table-sticky-page {
    overflow-x: clip;
    overflow-y: visible;
}

/* region: the wrapper scrolls (max-block-size set by the behaviour) */
.pf-table-scroll-region {
    overflow: auto;
}

/* ─── Row select ────────────────────────────────────────────────── */

.pf-table-select-col {
    inline-size: var(--pf-table-select-width);
    text-align: center;
    vertical-align: middle;
}

.pf-table-checkbox {
    inline-size: 1rem;
    block-size: 1rem;
    margin: 0;
    accent-color: var(--pf-color-action-primary);
    cursor: pointer;
}

.pf-table-checkbox:focus-visible {
    outline: 2px solid transparent;
    box-shadow: var(--pf-focus-ring);
    border-radius: var(--pf-radius-xs);
}

[data-pf-table] tr.is-selected > td {
    background: var(--pf-color-surface-selected);
}

/* ─── State rows (CP-5 empty / skeleton inside the body) ────────── */

.pf-table-state-row > td {
    padding: var(--pf-space-2) var(--pf-table-pad-x);
}

.pf-table-state-row .pf-skeleton-row {
    padding-block: var(--pf-space-1);
}

/* ─── Windows High Contrast / forced colours ─────────────────── */

@media (forced-colors: active) {
    th.pf-table-sortable::after {
        border-block-start-color: CanvasText;
    }

    [data-pf-table] tr.is-selected > td {
        outline: 1px solid Highlight;
    }
}
/* ==== css/pf/components/drawer.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Drawer Component
   ────────────────────────────────────────────────────────────────────
   Slide-in panel from screen edge. Used for secondary navigation, side
   forms, contextual details (a11y/health/seo drawers in CMS editor).

   USAGE
     <div class="pf-drawer-overlay" data-pf-drawer-open>
       <div class="pf-drawer-overlay__backdrop" data-pf-drawer-close></div>
       <aside class="pf-drawer pf-drawer--right" role="dialog"
              aria-modal="true" aria-labelledby="drawer-title">
         <header class="pf-drawer__header">
           <h2 id="drawer-title" class="pf-drawer__title">Drawer title</h2>
           <button class="pf-drawer__close" data-pf-drawer-close aria-label="Close">
             <svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
               <path d="M3 3l10 10M3 13L13 3" stroke="currentColor" stroke-width="2"/>
             </svg>
           </button>
         </header>
         <div class="pf-drawer__body">
           Drawer content.
         </div>
         <footer class="pf-drawer__footer">
           <button class="pf-button pf-button--ghost" data-pf-drawer-close>Cancel</button>
           <button class="pf-button">Apply</button>
         </footer>
       </aside>
     </div>

     <!-- Sides -->
     <aside class="pf-drawer pf-drawer--left">…</aside>
     <aside class="pf-drawer pf-drawer--top">…</aside>
     <aside class="pf-drawer pf-drawer--bottom">…</aside>

     <!-- Sizes -->
     <aside class="pf-drawer pf-drawer--right pf-drawer--sm">…</aside>
     <aside class="pf-drawer pf-drawer--right pf-drawer--lg">…</aside>

   ACCESSIBILITY
     • role="dialog" + aria-modal="true" required
     • aria-labelledby points to drawer title
     • Focus moves into drawer on open (JS responsibility)
     • Esc key closes drawer (JS responsibility)
     • Focus trap while open (JS responsibility)
     • Backdrop click closes (data-pf-drawer-close)
     • Returns focus to trigger element on close (JS responsibility)

   Version: 1.0.0
   Last revised: 2026-05-10
   ──────────────────────────────────────────────────────────────────── */

/* ─── Block: .pf-drawer-overlay (positioning + backdrop wrapper) ── */

.pf-drawer-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--pf-drawer-z-index);
    display: flex;
    pointer-events: none; /* So body content stays clickable when overlay hidden */
}

.pf-drawer-overlay[data-pf-drawer-open] {
    pointer-events: auto;
}

.pf-drawer-overlay[hidden] { display: none; }

/* ─── Element: __backdrop (full-screen scrim) ────────────────── */

.pf-drawer-overlay__backdrop {
    position: absolute;
    inset: 0;
    background: var(--pf-drawer-backdrop);
    opacity: 0;
    transition: opacity var(--pf-motion-duration-base) var(--pf-motion-ease-out);
    cursor: pointer;
}

.pf-drawer-overlay[data-pf-drawer-open] .pf-drawer-overlay__backdrop {
    opacity: 1;
}

/* ─── Block: .pf-drawer (panel itself) ────────────────────────── */

.pf-drawer {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--pf-drawer-bg);
    color: var(--pf-drawer-fg);
    box-shadow: var(--pf-drawer-shadow);
    overflow: hidden;
    /* Default — right side */
    width: 420px;
    max-width: 100vw;
    height: 100vh;
    margin-inline-start: auto; /* Push to right edge */
    transform: translateX(100%);
    transition: transform var(--pf-motion-duration-base) var(--pf-motion-ease-out);
}

.pf-drawer-overlay[data-pf-drawer-open] .pf-drawer {
    transform: translateX(0);
}

/* ─── Modifiers: --right / --left / --top / --bottom ────────── */

.pf-drawer--right {
    /* Default behaviour — already encoded above */
    margin-inline-start: auto;
}

.pf-drawer--left {
    margin-inline-end: auto;
    margin-inline-start: 0;
    transform: translateX(-100%);
}

.pf-drawer-overlay[data-pf-drawer-open] .pf-drawer--left {
    transform: translateX(0);
}

.pf-drawer--top {
    width: 100vw;
    max-width: 100vw;
    height: auto;
    max-height: 80vh;
    margin: 0;
    transform: translateY(-100%);
}

.pf-drawer-overlay[data-pf-drawer-open] .pf-drawer--top {
    transform: translateY(0);
}

.pf-drawer--bottom {
    width: 100vw;
    max-width: 100vw;
    height: auto;
    max-height: 80vh;
    margin: auto 0 0 0;
    transform: translateY(100%);
}

.pf-drawer-overlay[data-pf-drawer-open] .pf-drawer--bottom {
    transform: translateY(0);
}

/* ─── Sizes ──────────────────────────────────────────────────── */

.pf-drawer--sm { width: 320px; }
.pf-drawer--md { width: 420px; } /* default */
.pf-drawer--lg { width: 560px; }
.pf-drawer--xl { width: 720px; }
.pf-drawer--full { width: 100vw; }

/* ─── Modifier: --panel (content-height floating overlay card) ────────────────────────
   A quick-glance overlay — per-object history, an activity peek — must HUG its content and float
   as a rounded card near the top-right, NOT fill 100vh with empty space below a few rows. This is
   the notification-bell panel idiom generalised into the shared drawer: content-height with a cap +
   internal scroll, frosted, no layout shift. It reuses the SAME overlay factory (open/close/focus/
   Esc/backdrop) — only the panel box changes. Use it (instead of a bare --right) for any short,
   glanceable overlay. The canonical guard OverlayPanelsHugContentAndNeverHScroll1Tests pins that this
   variant stays content-hugging + scroll-free so a drawer can never regress to a 100vh slab. */
.pf-drawer--panel {
    /* The overlay is display:flex (align-items:stretch), which would stretch the drawer to full height
       and defeat height:auto — align to the cross-start so the card takes only its content height. */
    align-self: flex-start;
    height: auto;                                   /* hug content instead of 100vh */
    max-height: min(72vh, calc(100dvh - 7rem));     /* …but cap, then scroll inside the body */
    margin-top: 4.5rem;                             /* clear the sticky app header (z=900) */
    margin-inline-end: var(--pf-space-4, 1rem);     /* detach from the right edge → floating card */
    margin-bottom: var(--pf-space-4, 1rem);
    border: 1px solid var(--pf-drawer-border);
    border-radius: var(--pf-radius-lg, 16px);
}

/* The body must HUG its content in a panel (so 2 rows are a short card, not an 886px slab): drop the
   full-height drawer's flex:1 GROW. It still shrinks + scrolls (min-height:0 + overflow-y:auto on the
   base body) once the panel reaches its max-height, so long histories stay usable. */
.pf-drawer--panel .pf-drawer__body {
    flex: 0 1 auto;
}

/* Frost the panel variant (match the bell the operator approved): translucent + blurred WHERE
   supported; the solid --pf-drawer-bg below the @supports is the AA fallback, also restored under
   prefers-reduced-transparency. 88% keeps the overlay surface comfortably readable in both themes. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .pf-drawer--panel {
        background: color-mix(in srgb, var(--pf-drawer-bg) 88%, transparent);
        -webkit-backdrop-filter: blur(22px) saturate(150%);
        backdrop-filter: blur(22px) saturate(150%);
    }
}

@media (prefers-reduced-transparency: reduce) {
    .pf-drawer--panel {
        background: var(--pf-drawer-bg);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

/* The panel floats WITHOUT dimming the page (the bell idiom — the operator does not need to read
   behind it, only to glance): keep the backdrop clickable for click-outside close, but invisible. */
.pf-drawer-overlay:has(.pf-drawer--panel) .pf-drawer-overlay__backdrop {
    background: transparent;
}

/* Tablet-portrait and down: the floating card becomes an inset, near-full-width sheet so it never
   runs off a narrow screen (same 768px breakpoint + gutter idiom as the notification bell). */
@media (max-width: 768px) {
    .pf-drawer--panel {
        /* fill the main (horizontal) flex axis so the card becomes an inset, near-full-width sheet
           instead of shrinking to content width and leaving a large gap on one side. */
        flex: 1 1 auto;
        width: auto;
        max-width: none;
        margin: 3.5rem var(--pf-space-3, 0.75rem) var(--pf-space-3, 0.75rem);
        max-height: calc(100dvh - 4.75rem);
    }
}

/* ─── Element: __header ──────────────────────────────────────── */

.pf-drawer__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--pf-space-3);
    padding: var(--pf-drawer-padding);
    padding-bottom: var(--pf-space-3);
    border-bottom: 1px solid var(--pf-drawer-border);
    flex-shrink: 0;
}

.pf-drawer__title {
    margin: 0;
    font-size: var(--pf-text-size-lg);
    font-weight: var(--pf-text-weight-semibold);
    color: var(--pf-color-text-primary);
    line-height: var(--pf-text-leading-snug);
}

.pf-drawer__subtitle {
    margin: var(--pf-space-1) 0 0;
    font-size: var(--pf-text-size-sm);
    color: var(--pf-color-text-secondary);
    line-height: var(--pf-text-leading-normal);
}

.pf-drawer__close {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    background: transparent;
    color: var(--pf-color-text-secondary);
    border: 1px solid transparent;
    border-radius: var(--pf-radius-sm);
    cursor: pointer;
    transition: background var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
}

.pf-drawer__close:hover,
.pf-drawer__close:focus-visible {
    background: var(--pf-color-surface-hover);
    color: var(--pf-color-text-primary);
}

.pf-drawer__close:focus-visible {
    outline: none;
    box-shadow: var(--pf-focus-ring);
}

/* ─── Element: __body (scrolling content area) ──────────────── */

.pf-drawer__body {
    flex: 1;
    min-height: 0;        /* allow the body to shrink + scroll inside a height-capped column (--panel) */
    overflow-y: auto;
    overflow-x: hidden;   /* a drawer body never scrolls horizontally — content wraps (systematic backstop) */
    padding: var(--pf-drawer-padding);
    padding-top: var(--pf-space-4);
    padding-bottom: var(--pf-space-4);
}

.pf-drawer__body > :first-child { margin-top: 0; }
.pf-drawer__body > :last-child  { margin-bottom: 0; }

/* ─── Element: __footer (sticky actions at bottom) ──────────── */

.pf-drawer__footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--pf-space-2);
    padding: var(--pf-drawer-padding);
    padding-top: var(--pf-space-3);
    padding-bottom: var(--pf-space-3);
    border-top: 1px solid var(--pf-drawer-border);
    background: var(--pf-drawer-bg);
    flex-shrink: 0;
}

/* ─── Reduced-motion respect ─────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .pf-drawer-overlay__backdrop,
    .pf-drawer {
        transition: none;
    }
}

/* ─── Object-history timeline (stacked, drawer-safe) ─────────────
   A timeline/table inside a narrow drawer must STACK its fields, never force a horizontal scroll.
   This is the canonical pattern for any per-object history rendered in a drawer/panel. */
.pf-objhist {
    list-style: none;
    margin: 0;
    padding: 0;
}

.pf-objhist__entry {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--pf-color-border-subtle, rgba(0, 0, 0, 0.08));
}

.pf-objhist__entry:last-child {
    border-bottom: 0;
}

.pf-objhist__when {
    font-size: 0.8rem;
}
/* ==== css/pf/components/input.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Input Component
   ────────────────────────────────────────────────────────────────────
   Form-field component covering text, number, email, search, tel, url,
   date, datetime-local, password, select, textarea, checkbox, radio.

   USAGE
     <!-- Basic input with label -->
     <label class="pf-field">
       <span class="pf-field__label">Email</span>
       <input type="email" class="pf-input" placeholder="you@example.com">
       <span class="pf-field__hint">We'll never share it.</span>
     </label>

     <!-- Required + error state -->
     <label class="pf-field pf-field--invalid">
       <span class="pf-field__label">Title <abbr title="required">*</abbr></span>
       <input type="text" class="pf-input" required aria-invalid="true">
       <span class="pf-field__error">Title is required.</span>
     </label>

     <!-- Sizes -->
     <input class="pf-input pf-input--sm">
     <input class="pf-input pf-input--lg">

     <!-- Select -->
     <select class="pf-input pf-input--select">…</select>

     <!-- Textarea -->
     <textarea class="pf-input pf-input--textarea" rows="4"></textarea>

     <!-- Checkbox / Radio -->
     <label class="pf-checkbox">
       <input type="checkbox" class="pf-checkbox__input">
       <span class="pf-checkbox__indicator" aria-hidden="true"></span>
       <span class="pf-checkbox__label">I agree</span>
     </label>

   ACCESSIBILITY
     • Focus-visible ring with --pf-focus-ring (WCAG 2.4.7)
     • Invalid state via [aria-invalid="true"] AND .pf-field--invalid wrap
     • Required marker via <abbr title="required">*</abbr> in label
     • Placeholder is supplementary, never replaces label
     • Min touch target: 44px on mobile (auto via padding + line-height)
     • prefers-reduced-motion respected for transitions
     • Color-blind friendly: icon + color for invalid (not color alone)

   Version: 1.0.0
   Last revised: 2026-05-10
   ──────────────────────────────────────────────────────────────────── */

/* ─── Block: .pf-field (wrapper for label + input + hint/error) ── */

.pf-field {
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-1-5);
    font-family: inherit;
}

/* ─── Element: __label (form field label) ────────────────────── */

.pf-field__label {
    font-size: var(--pf-text-size-sm);
    font-weight: var(--pf-text-weight-medium);
    color: var(--pf-color-text-primary);
    line-height: var(--pf-text-leading-snug);
}

.pf-field__label abbr[title="required"] {
    color: var(--pf-color-status-danger);
    text-decoration: none;
    margin-inline-start: 2px;
}

/* ─── Element: __hint (helper text below input) ──────────────── */

.pf-field__hint {
    font-size: var(--pf-text-size-xs);
    color: var(--pf-color-text-tertiary);
    line-height: var(--pf-text-leading-normal);
}

/* ─── Element: __error (error message — always pairs with aria-invalid) ── */

.pf-field__error {
    font-size: var(--pf-text-size-xs);
    color: var(--pf-color-status-danger-fg);
    line-height: var(--pf-text-leading-normal);
    display: flex;
    align-items: center;
    gap: var(--pf-space-1);
}

.pf-field__error::before {
    /* Color-blind friendly: icon supplements color signal */
    content: "⚠";
    font-size: 1em;
}

/* ─── Block: .pf-input (text-like inputs + select + textarea) ─── */

.pf-input {
    /* Layout */
    display: block;
    width: 100%;
    min-height: 40px; /* Touch target — auto via padding for inputs */

    /* Typography */
    font-family: inherit;
    font-size: var(--pf-input-font-size);
    line-height: var(--pf-text-leading-normal);
    color: var(--pf-input-fg);

    /* Box */
    padding: var(--pf-input-padding-y) var(--pf-input-padding-x);
    background: var(--pf-input-bg);
    border: 1px solid var(--pf-input-border);
    border-radius: var(--pf-input-radius);

    /* Removed default browser styling */
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;

    /* Smooth transitions */
    transition:
        border-color var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        box-shadow var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        background var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
}

.pf-input::placeholder {
    color: var(--pf-input-fg-placeholder);
    opacity: 1; /* Firefox normalises to 0.54 — restore */
}

.pf-input:hover:not(:disabled):not(:read-only) {
    border-color: var(--pf-input-border-hover);
}

.pf-input:focus-visible {
    outline: none;
    border-color: var(--pf-input-border-focus);
    box-shadow: var(--pf-input-shadow-focus);
}

.pf-input:disabled,
.pf-input[aria-disabled="true"] {
    background: var(--pf-input-bg-disabled);
    color: var(--pf-input-fg-disabled);
    cursor: not-allowed;
    opacity: 0.7;
}

.pf-input:read-only:not([type="checkbox"]):not([type="radio"]) {
    background: var(--pf-color-surface-base);
    cursor: default;
}

/* Invalid state — paired with aria-invalid="true" + .pf-field--invalid */
.pf-input[aria-invalid="true"],
.pf-field--invalid .pf-input {
    border-color: var(--pf-input-border-error);
}

.pf-input[aria-invalid="true"]:focus-visible,
.pf-field--invalid .pf-input:focus-visible {
    box-shadow: 0 0 0 3px color-mix(in srgb,
        var(--pf-color-status-danger) 20%,
        transparent);
}

/* ─── Modifier: --select (custom chevron + extra padding) ────── */

.pf-input--select {
    padding-inline-end: var(--pf-space-8);
    cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--pf-space-3) center;
    background-size: 12px 8px;
}

.pf-input--select:disabled {
    cursor: not-allowed;
}

/* ─── Modifier: --textarea (multi-line) ─────────────────────── */

.pf-input--textarea {
    min-height: 96px;
    resize: vertical;
    font-family: inherit; /* Some browsers default to monospace */
    line-height: var(--pf-text-leading-relaxed);
}

/* ─── Modifier: --search (rounded + clear button affordance) ── */

.pf-input--search {
    border-radius: var(--pf-radius-full);
    padding-inline-start: var(--pf-space-9, 2.25rem);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='7' cy='7' r='5'/%3E%3Cpath d='M11 11l4 4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: var(--pf-space-3) center;
    background-size: 16px 16px;
}

/* ─── Sizes ──────────────────────────────────────────────────── */

.pf-input--sm {
    min-height: 32px;
    padding: var(--pf-space-1) var(--pf-space-2);
    font-size: var(--pf-text-size-sm);
}

.pf-input--lg {
    min-height: 48px;
    padding: var(--pf-space-3) var(--pf-space-4);
    font-size: var(--pf-text-size-lg);
}

/* ─── Block: .pf-checkbox / .pf-radio ────────────────────────── */

.pf-checkbox,
.pf-radio {
    display: inline-flex;
    align-items: flex-start;
    gap: var(--pf-space-2);
    cursor: pointer;
    user-select: none;
    font-size: var(--pf-text-size-sm);
    color: var(--pf-color-text-primary);
    line-height: var(--pf-text-leading-snug);
}

.pf-checkbox__input,
.pf-radio__input {
    /* Visually hidden but accessible — paired with __indicator */
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    border: 0;
    white-space: nowrap;
}

.pf-checkbox__indicator,
.pf-radio__indicator {
    /* Custom indicator drawn with CSS */
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    margin-top: 1px; /* baseline-align with first text-line */
    background: var(--pf-input-bg);
    border: 1.5px solid var(--pf-input-border);
    transition:
        background var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        border-color var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        box-shadow var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
}

.pf-checkbox__indicator {
    border-radius: var(--pf-radius-xs);
}

.pf-radio__indicator {
    border-radius: var(--pf-radius-full);
}

/* Hover — only when not disabled */
.pf-checkbox:hover .pf-checkbox__input:not(:disabled) ~ .pf-checkbox__indicator,
.pf-radio:hover .pf-radio__input:not(:disabled) ~ .pf-radio__indicator {
    border-color: var(--pf-input-border-hover);
}

/* Focus — visible ring (keyboard only) */
.pf-checkbox__input:focus-visible ~ .pf-checkbox__indicator,
.pf-radio__input:focus-visible ~ .pf-radio__indicator {
    box-shadow: var(--pf-input-shadow-focus);
}

/* Checked — fill + checkmark / dot */
.pf-checkbox__input:checked ~ .pf-checkbox__indicator {
    background: var(--pf-color-action-primary);
    border-color: var(--pf-color-action-primary);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='2 7.5 5.5 11 12 3.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 14px 14px;
}

.pf-radio__input:checked ~ .pf-radio__indicator {
    border-color: var(--pf-color-action-primary);
    border-width: 5px; /* Inner dot via thick border */
    background: var(--pf-input-bg);
}

/* Disabled */
.pf-checkbox__input:disabled ~ .pf-checkbox__indicator,
.pf-radio__input:disabled ~ .pf-radio__indicator,
.pf-checkbox__input:disabled ~ .pf-checkbox__label,
.pf-radio__input:disabled ~ .pf-radio__label {
    cursor: not-allowed;
    opacity: 0.6;
}

/* Indeterminate state for checkboxes */
.pf-checkbox__input:indeterminate ~ .pf-checkbox__indicator {
    background: var(--pf-color-action-primary);
    border-color: var(--pf-color-action-primary);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round'%3E%3Cline x1='3' y1='7' x2='11' y2='7'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 14px 14px;
}

/* ─── Reduced-motion respect ─────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .pf-input,
    .pf-checkbox__indicator,
    .pf-radio__indicator {
        transition: none;
    }
}
/* ==== css/pf/components/modal.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Modal Component
   ────────────────────────────────────────────────────────────────────
   Centered floating dialog. Used for confirmations, focused tasks,
   add-section pickers, template choosers.

   Differs from .pf-drawer in:
     • Centered (vs slide-in from edge)
     • Bounded width (max-width — never full-screen except --full)
     • Stronger backdrop (modal blocks the underlying UI more emphatically)
     • Smaller default size — modals are for focused tasks

   USAGE
     <div class="pf-modal-overlay" data-pf-modal-open>
       <div class="pf-modal-overlay__backdrop" data-pf-modal-close></div>
       <div class="pf-modal" role="dialog" aria-modal="true"
            aria-labelledby="modal-title">
         <header class="pf-modal__header">
           <h2 id="modal-title" class="pf-modal__title">Confirm action</h2>
           <button class="pf-modal__close" data-pf-modal-close aria-label="Close">×</button>
         </header>
         <div class="pf-modal__body">
           <p>Are you sure you want to delete this section?</p>
         </div>
         <footer class="pf-modal__footer">
           <button class="pf-button pf-button--ghost" data-pf-modal-close>Cancel</button>
           <button class="pf-button pf-button--danger">Delete</button>
         </footer>
       </div>
     </div>

     <!-- Sizes -->
     <div class="pf-modal pf-modal--sm">…</div>     <!-- 400px max -->
     <div class="pf-modal pf-modal--md">…</div>     <!-- 640px max (default) -->
     <div class="pf-modal pf-modal--lg">…</div>     <!-- 800px max -->
     <div class="pf-modal pf-modal--xl">…</div>     <!-- 1024px max -->
     <div class="pf-modal pf-modal--full">…</div>   <!-- 95vw max -->

   ACCESSIBILITY
     • role="dialog" + aria-modal="true" required
     • aria-labelledby points to modal title
     • Focus moves into modal on open (JS responsibility)
     • Esc key closes modal (JS responsibility)
     • Focus trap while open (JS responsibility)
     • Backdrop click closes (data-pf-modal-close — confirm before destructive)
     • Returns focus to trigger element on close (JS responsibility)
     • For destructive confirmations, primary button = .pf-button--danger
       and Cancel = ghost variant (so danger gets visual emphasis)

   Version: 1.0.0
   Last revised: 2026-05-10
   ──────────────────────────────────────────────────────────────────── */

/* ─── Block: .pf-modal-overlay (positioning + backdrop) ──────── */

.pf-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--pf-modal-z-index);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--pf-space-4);
    pointer-events: none;
}

.pf-modal-overlay[data-pf-modal-open] {
    pointer-events: auto;
}

.pf-modal-overlay[hidden] { display: none; }

/* ─── Element: __backdrop ────────────────────────────────────── */

.pf-modal-overlay__backdrop {
    position: absolute;
    inset: 0;
    background: var(--pf-modal-backdrop);
    opacity: 0;
    transition: opacity var(--pf-motion-duration-base) var(--pf-motion-ease-out);
    cursor: pointer;
}

.pf-modal-overlay[data-pf-modal-open] .pf-modal-overlay__backdrop {
    opacity: 1;
}

/* ─── Block: .pf-modal (the dialog itself) ────────────────────── */

.pf-modal {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: var(--pf-modal-max-width);
    max-height: calc(100vh - var(--pf-space-8) * 2);
    background: var(--pf-modal-bg);
    color: var(--pf-modal-fg);
    border: 1px solid var(--pf-modal-border);
    border-radius: var(--pf-modal-radius);
    box-shadow: var(--pf-modal-shadow);
    overflow: hidden;
    /* Entrance animation */
    transform: scale(0.95);
    opacity: 0;
    transition:
        transform var(--pf-motion-duration-base) var(--pf-motion-ease-emphasized),
        opacity var(--pf-motion-duration-base) var(--pf-motion-ease-out);
}

.pf-modal-overlay[data-pf-modal-open] .pf-modal {
    transform: scale(1);
    opacity: 1;
}

/* ─── Sizes ──────────────────────────────────────────────────── */

.pf-modal--sm   { max-width: 400px; }
.pf-modal--md   { max-width: 640px; } /* default */
.pf-modal--lg   { max-width: 800px; }
.pf-modal--xl   { max-width: 1024px; }
.pf-modal--full { max-width: 95vw; max-height: 95vh; }

/* ─── Element: __header ──────────────────────────────────────── */

.pf-modal__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--pf-space-3);
    padding: var(--pf-modal-padding);
    padding-bottom: var(--pf-space-3);
    border-bottom: 1px solid var(--pf-modal-border);
    flex-shrink: 0;
}

.pf-modal__title {
    margin: 0;
    font-size: var(--pf-text-size-xl);
    font-weight: var(--pf-text-weight-semibold);
    color: var(--pf-color-text-primary);
    line-height: var(--pf-text-leading-snug);
}

.pf-modal__subtitle {
    margin: var(--pf-space-1) 0 0;
    font-size: var(--pf-text-size-sm);
    color: var(--pf-color-text-secondary);
    line-height: var(--pf-text-leading-normal);
}

.pf-modal__close {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    background: transparent;
    color: var(--pf-color-text-secondary);
    border: 1px solid transparent;
    border-radius: var(--pf-radius-sm);
    cursor: pointer;
    font-size: 24px; /* Larger × character */
    line-height: 1;
    transition: background var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
}

.pf-modal__close:hover,
.pf-modal__close:focus-visible {
    background: var(--pf-color-surface-hover);
    color: var(--pf-color-text-primary);
}

.pf-modal__close:focus-visible {
    outline: none;
    box-shadow: var(--pf-focus-ring);
}

/* ─── Element: __body (scrolling content area) ──────────────── */

.pf-modal__body {
    flex: 1;
    overflow-y: auto;
    padding: var(--pf-modal-padding);
    padding-top: var(--pf-space-4);
    padding-bottom: var(--pf-space-4);
}

.pf-modal__body > :first-child { margin-top: 0; }
.pf-modal__body > :last-child  { margin-bottom: 0; }

/* ─── Element: __footer ──────────────────────────────────────── */

.pf-modal__footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--pf-space-2);
    padding: var(--pf-modal-padding);
    padding-top: var(--pf-space-3);
    padding-bottom: var(--pf-space-3);
    border-top: 1px solid var(--pf-modal-border);
    background: var(--pf-modal-bg);
    flex-shrink: 0;
}

.pf-modal__footer--start   { justify-content: flex-start; }
.pf-modal__footer--center  { justify-content: center; }
.pf-modal__footer--between { justify-content: space-between; }

/* ─── Reduced-motion respect ─────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .pf-modal-overlay__backdrop,
    .pf-modal {
        transition: opacity var(--pf-motion-duration-fast) linear;
        transform: none;
    }
}
/* ==== css/pf/components/popover.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Popover Component
   ────────────────────────────────────────────────────────────────────
   Anchored floating panel with optional arrow pointing to trigger
   element. Used for tooltips, menus, contextual hints, share-link UI.

   Differs from .pf-modal in:
     • Anchored to a trigger element (not centered on screen)
     • No backdrop — click outside closes (less intrusive)
     • Smaller typically — for quick contextual info or actions
     • Arrow pointing to trigger element (visual connection)

   USAGE
     <div class="pf-popover-anchor">
       <button class="pf-button" data-pf-popover-trigger>Open menu</button>
       <div class="pf-popover" role="dialog" aria-label="Menu" hidden>
         <div class="pf-popover__arrow" aria-hidden="true"></div>
         <div class="pf-popover__body">
           <button class="pf-popover__item">Edit</button>
           <button class="pf-popover__item">Duplicate</button>
           <button class="pf-popover__item pf-popover__item--danger">Delete</button>
         </div>
       </div>
     </div>

     <!-- Placement -->
     <div class="pf-popover pf-popover--top">…</div>     <!-- arrow points down -->
     <div class="pf-popover pf-popover--bottom">…</div>  <!-- arrow points up (default) -->
     <div class="pf-popover pf-popover--left">…</div>    <!-- arrow points right -->
     <div class="pf-popover pf-popover--right">…</div>   <!-- arrow points left -->

     <!-- Sizes -->
     <div class="pf-popover pf-popover--sm">…</div>      <!-- 200px max -->
     <div class="pf-popover pf-popover--md">…</div>      <!-- 320px max (default) -->
     <div class="pf-popover pf-popover--lg">…</div>      <!-- 480px max -->

     <!-- As tooltip (smaller, no body padding) -->
     <div class="pf-popover pf-popover--tooltip">Quick hint</div>

   ACCESSIBILITY
     • Anchor: aria-haspopup="dialog" + aria-expanded="true|false"
       + aria-controls="popover-id" on trigger
     • Popover: role="dialog" or role="menu" + aria-label
     • Esc key closes (JS responsibility)
     • Click outside closes (JS responsibility)
     • Tab cycles within (no focus trap — popovers are non-blocking)
     • Returns focus to trigger on close (JS responsibility)
     • Tooltip variant: role="tooltip" + aria-describedby on trigger

   Version: 1.0.0
   Last revised: 2026-05-10
   ──────────────────────────────────────────────────────────────────── */

/* ─── Block: .pf-popover-anchor (relative positioning context) ── */

.pf-popover-anchor {
    position: relative;
    display: inline-block;
}

/* ─── Block: .pf-popover (the floating panel) ───────────────── */

.pf-popover {
    position: absolute;
    z-index: var(--pf-popover-z-index);
    display: flex;
    flex-direction: column;
    min-width: 160px;
    max-width: 320px;
    background: var(--pf-popover-bg);
    color: var(--pf-popover-fg);
    border: 1px solid var(--pf-popover-border);
    border-radius: var(--pf-popover-radius);
    box-shadow: var(--pf-popover-shadow);
    /* Default placement = bottom-aligned to anchor */
    top: calc(100% + var(--pf-space-2));
    left: 0;
    /* Entrance animation */
    opacity: 0;
    transform: translateY(-4px);
    transition:
        opacity var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        transform var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
    pointer-events: none;
}

.pf-popover[data-pf-popover-open],
.pf-popover:not([hidden]) {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.pf-popover[hidden] { display: none; }

/* ─── Element: __arrow (12px triangle pointing to anchor) ──── */

.pf-popover__arrow {
    position: absolute;
    width: var(--pf-popover-arrow-size);
    height: var(--pf-popover-arrow-size);
    background: var(--pf-popover-bg);
    border-top: 1px solid var(--pf-popover-border);
    border-left: 1px solid var(--pf-popover-border);
    transform: rotate(45deg);
    /* Default — pointing up (popover below anchor) */
    top: calc(var(--pf-popover-arrow-size) * -0.5 - 1px);
    left: var(--pf-space-3);
}

/* ─── Element: __body (content container with padding) ────── */

.pf-popover__body {
    padding: var(--pf-popover-padding);
    overflow-y: auto;
    max-height: 60vh;
}

.pf-popover__body > :first-child { margin-top: 0; }
.pf-popover__body > :last-child  { margin-bottom: 0; }

/* ─── Element: __title (optional header) ────────────────────── */

.pf-popover__title {
    margin: 0 0 var(--pf-space-2);
    font-size: var(--pf-text-size-sm);
    font-weight: var(--pf-text-weight-semibold);
    color: var(--pf-color-text-primary);
}

/* ─── Element: __item (menu item / button row) ─────────────── */

.pf-popover__item {
    display: flex;
    align-items: center;
    gap: var(--pf-space-2);
    width: 100%;
    padding: var(--pf-space-2) var(--pf-space-3);
    background: transparent;
    color: var(--pf-color-text-primary);
    border: none;
    border-radius: var(--pf-radius-sm);
    font: inherit;
    font-size: var(--pf-text-size-sm);
    text-align: left;
    cursor: pointer;
    transition: background var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
}

.pf-popover__item:hover,
.pf-popover__item:focus-visible {
    background: var(--pf-color-surface-hover);
}

.pf-popover__item:focus-visible {
    outline: none;
    box-shadow: var(--pf-focus-ring);
}

.pf-popover__item--danger {
    color: var(--pf-color-status-danger-fg);
}

.pf-popover__item--danger:hover,
.pf-popover__item--danger:focus-visible {
    background: var(--pf-color-action-danger-soft);
    color: var(--pf-color-status-danger-fg);
}

/* ─── Element: __divider ─────────────────────────────────────── */

.pf-popover__divider {
    height: 1px;
    margin: var(--pf-space-1) 0;
    background: var(--pf-popover-border);
    border: none;
}

/* ─── Modifiers: --top / --bottom / --left / --right ────────── */

.pf-popover--top {
    top: auto;
    bottom: calc(100% + var(--pf-space-2));
    transform: translateY(4px);
}

.pf-popover--top[data-pf-popover-open],
.pf-popover--top:not([hidden]) {
    transform: translateY(0);
}

.pf-popover--top .pf-popover__arrow {
    top: auto;
    bottom: calc(var(--pf-popover-arrow-size) * -0.5 - 1px);
    border-top: none;
    border-left: none;
    border-right: 1px solid var(--pf-popover-border);
    border-bottom: 1px solid var(--pf-popover-border);
}

.pf-popover--left {
    top: 0;
    left: auto;
    right: calc(100% + var(--pf-space-2));
    transform: translateX(4px);
}

.pf-popover--left[data-pf-popover-open],
.pf-popover--left:not([hidden]) {
    transform: translateX(0);
}

.pf-popover--left .pf-popover__arrow {
    top: var(--pf-space-3);
    left: auto;
    right: calc(var(--pf-popover-arrow-size) * -0.5 - 1px);
    border: none;
    border-top: 1px solid var(--pf-popover-border);
    border-right: 1px solid var(--pf-popover-border);
}

.pf-popover--right {
    top: 0;
    left: calc(100% + var(--pf-space-2));
    transform: translateX(-4px);
}

.pf-popover--right[data-pf-popover-open],
.pf-popover--right:not([hidden]) {
    transform: translateX(0);
}

.pf-popover--right .pf-popover__arrow {
    top: var(--pf-space-3);
    left: calc(var(--pf-popover-arrow-size) * -0.5 - 1px);
    border: none;
    border-bottom: 1px solid var(--pf-popover-border);
    border-left: 1px solid var(--pf-popover-border);
}

/* ─── Sizes ──────────────────────────────────────────────────── */

.pf-popover--sm { max-width: 200px; }
.pf-popover--md { max-width: 320px; } /* default */
.pf-popover--lg { max-width: 480px; }

/* ─── Modifier: --tooltip (compact, dark-on-light variant) ─── */

.pf-popover--tooltip {
    max-width: 240px;
    background: var(--pf-color-text-primary);
    color: var(--pf-color-text-inverse);
    border-color: var(--pf-color-text-primary);
    font-size: var(--pf-text-size-xs);
    line-height: var(--pf-text-leading-snug);
}

.pf-popover--tooltip .pf-popover__body {
    padding: var(--pf-space-2) var(--pf-space-3);
}

.pf-popover--tooltip .pf-popover__arrow {
    background: var(--pf-color-text-primary);
    border-color: var(--pf-color-text-primary);
}

/* ─── Reduced-motion respect ─────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .pf-popover {
        transition: opacity var(--pf-motion-duration-fast) linear;
        transform: none !important;
    }
}
/* ==== css/pf/components/toast.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Toast Component
   ────────────────────────────────────────────────────────────────────
   Transient notification that appears in a corner of the screen,
   auto-dismisses after a short timeout. Used for save confirmations,
   error notifications, background-job updates.

   USAGE
     <!-- Toast region container (singleton per page) -->
     <div class="pf-toast-region pf-toast-region--bottom-right"
          role="region" aria-label="Notifications" aria-live="polite">
       <!-- Individual toasts -->
       <div class="pf-toast pf-toast--success" role="status">
         <span class="pf-toast__icon" aria-hidden="true">✓</span>
         <div class="pf-toast__body">
           <strong class="pf-toast__title">Saved</strong>
           <p class="pf-toast__message">Your changes have been saved.</p>
         </div>
         <button class="pf-toast__close" aria-label="Dismiss">×</button>
       </div>
     </div>

     <!-- Variants -->
     <div class="pf-toast pf-toast--success">…</div>  <!-- ✓ green -->
     <div class="pf-toast pf-toast--warning">…</div>  <!-- ⚠ amber -->
     <div class="pf-toast pf-toast--danger">…</div>   <!-- ✗ red    role="alert" -->
     <div class="pf-toast pf-toast--info">…</div>     <!-- ℹ blue   default -->

   POSITIONING
     <div class="pf-toast-region pf-toast-region--top-left">…</div>
     <div class="pf-toast-region pf-toast-region--top-right">…</div>
     <div class="pf-toast-region pf-toast-region--top-center">…</div>
     <div class="pf-toast-region pf-toast-region--bottom-left">…</div>
     <div class="pf-toast-region pf-toast-region--bottom-right">…</div>  <!-- default -->
     <div class="pf-toast-region pf-toast-region--bottom-center">…</div>

   ACCESSIBILITY
     • Toast region: role="region" + aria-label + aria-live
     • Polite toasts (info/success): aria-live="polite" on region, role="status" on toast
     • Assertive toasts (danger): aria-live="assertive" on region, role="alert" on toast
     • Auto-dismiss must be ≥ 6s for screen-reader users to hear announcement
     • Close button always present so keyboard/screen-reader users can dismiss
     • prefers-reduced-motion: skip slide-in, just fade

   Version: 1.0.0
   Last revised: 2026-05-10
   ──────────────────────────────────────────────────────────────────── */

/* ─── Block: .pf-toast-region (positioning container) ────────── */

.pf-toast-region {
    position: fixed;
    z-index: var(--pf-toast-z-index);
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-2);
    padding: var(--pf-space-4);
    pointer-events: none;
    /* Default: bottom-right */
    bottom: 0;
    right: 0;
    align-items: flex-end;
}

/* Position modifiers */
.pf-toast-region--top-left      { top: 0;    left: 0;          right: auto; bottom: auto; align-items: flex-start; }
.pf-toast-region--top-right     { top: 0;    right: 0;         left: auto;  bottom: auto; align-items: flex-end; }
.pf-toast-region--top-center    { top: 0;    left: 50%;        transform: translateX(-50%); right: auto; bottom: auto; align-items: center; }
.pf-toast-region--bottom-left   { bottom: 0; left: 0;          right: auto; top: auto;    align-items: flex-start; }
.pf-toast-region--bottom-right  { bottom: 0; right: 0;         left: auto;  top: auto;    align-items: flex-end; }
.pf-toast-region--bottom-center { bottom: 0; left: 50%;        transform: translateX(-50%); right: auto; top: auto;    align-items: center; }

/* Top regions stack newest first; bottom regions stack newest last */
.pf-toast-region--top-left,
.pf-toast-region--top-right,
.pf-toast-region--top-center {
    flex-direction: column;
}

.pf-toast-region--bottom-left,
.pf-toast-region--bottom-right,
.pf-toast-region--bottom-center {
    flex-direction: column-reverse;
}

/* ─── Block: .pf-toast (single notification) ──────────────────── */

.pf-toast {
    display: flex;
    align-items: flex-start;
    gap: var(--pf-space-3);
    width: 100%;
    max-width: var(--pf-toast-max-width);
    min-height: var(--pf-toast-min-height);
    padding: var(--pf-toast-padding-y) var(--pf-toast-padding-x);
    background: var(--pf-toast-bg);
    color: var(--pf-toast-fg);
    border: 1px solid var(--pf-toast-border);
    border-radius: var(--pf-toast-radius);
    box-shadow: var(--pf-toast-shadow);
    pointer-events: auto;
    /* Entrance animation — slide in + fade */
    opacity: 0;
    transform: translateX(20px);
    transition:
        opacity var(--pf-motion-duration-base) var(--pf-motion-ease-out),
        transform var(--pf-motion-duration-base) var(--pf-motion-ease-emphasized);
}

.pf-toast[data-pf-toast-shown],
.pf-toast.is-shown {
    opacity: 1;
    transform: translateX(0);
}

.pf-toast[data-pf-toast-leaving],
.pf-toast.is-leaving {
    opacity: 0;
    transform: translateX(20px);
}

/* Adjust slide direction based on toast-region position */
.pf-toast-region--top-left .pf-toast,
.pf-toast-region--bottom-left .pf-toast {
    transform: translateX(-20px);
}

.pf-toast-region--top-left .pf-toast[data-pf-toast-shown],
.pf-toast-region--bottom-left .pf-toast[data-pf-toast-shown] {
    transform: translateX(0);
}

.pf-toast-region--top-center .pf-toast,
.pf-toast-region--bottom-center .pf-toast {
    transform: translateY(-20px);
}

.pf-toast-region--top-center .pf-toast[data-pf-toast-shown],
.pf-toast-region--bottom-center .pf-toast[data-pf-toast-shown] {
    transform: translateY(0);
}

.pf-toast-region--bottom-center .pf-toast {
    transform: translateY(20px);
}

/* ─── Element: __icon ─────────────────────────────────────────── */

.pf-toast__icon {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: var(--pf-radius-full);
    font-size: 14px;
    font-weight: var(--pf-text-weight-bold);
    line-height: 1;
}

/* ─── Element: __body (title + message) ──────────────────────── */

.pf-toast__body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-0-5);
}

.pf-toast__title {
    font-size: var(--pf-text-size-sm);
    font-weight: var(--pf-text-weight-semibold);
    line-height: var(--pf-text-leading-snug);
    margin: 0;
}

.pf-toast__message {
    margin: 0;
    font-size: var(--pf-text-size-sm);
    line-height: var(--pf-text-leading-normal);
    color: inherit;
    opacity: 0.9;
}

/* ─── Element: __close (dismiss button) ─────────────────────── */

.pf-toast__close {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    background: transparent;
    color: inherit;
    border: none;
    border-radius: var(--pf-radius-sm);
    cursor: pointer;
    font-size: 18px;
    line-height: 1;
    opacity: 0.7;
    transition:
        opacity var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
        background var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
}

.pf-toast__close:hover,
.pf-toast__close:focus-visible {
    opacity: 1;
    background: color-mix(in srgb, currentColor 10%, transparent);
}

.pf-toast__close:focus-visible {
    outline: none;
    box-shadow: var(--pf-focus-ring);
}

/* ─── Element: __action (inline button — undo, retry) ──────── */

.pf-toast__action {
    flex-shrink: 0;
    align-self: center;
    background: transparent;
    color: inherit;
    border: none;
    padding: 0;
    font: inherit;
    font-size: var(--pf-text-size-sm);
    font-weight: var(--pf-text-weight-semibold);
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
    opacity: 0.9;
}

.pf-toast__action:hover,
.pf-toast__action:focus-visible {
    opacity: 1;
}

.pf-toast__action:focus-visible {
    outline: none;
    box-shadow: var(--pf-focus-ring);
    border-radius: var(--pf-radius-xs);
}

/* ─── Variants ───────────────────────────────────────────────── */

.pf-toast--success {
    background: var(--pf-toast-bg-success);
    color: var(--pf-toast-fg-success);
    border-color: var(--pf-toast-border-success);
}

.pf-toast--success .pf-toast__icon {
    background: var(--pf-color-status-success);
    color: var(--pf-color-text-on-status);
}

.pf-toast--warning {
    background: var(--pf-toast-bg-warning);
    color: var(--pf-toast-fg-warning);
    border-color: var(--pf-toast-border-warning);
}

.pf-toast--warning .pf-toast__icon {
    background: var(--pf-color-status-warning);
    /* A11Y-TOAST-1 — amber is a light fill in BOTH themes, so it is the one status that
       cannot share the theme's default on-status colour. See tokens.semantic.css. */
    color: var(--pf-color-text-on-status-warning);
}

.pf-toast--danger {
    background: var(--pf-toast-bg-danger);
    color: var(--pf-toast-fg-danger);
    border-color: var(--pf-toast-border-danger);
}

.pf-toast--danger .pf-toast__icon {
    background: var(--pf-color-status-danger);
    color: var(--pf-color-text-on-status);
}

.pf-toast--info {
    background: var(--pf-toast-bg-info);
    color: var(--pf-toast-fg-info);
    border-color: var(--pf-toast-border-info);
}

.pf-toast--info .pf-toast__icon {
    background: var(--pf-color-status-info);
    color: var(--pf-color-text-on-status);
}

/* ─── Reduced-motion respect ─────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .pf-toast {
        transition: opacity var(--pf-motion-duration-fast) linear;
        transform: none !important;
    }
}
/* ==== css/pf/components/filter.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Filter primitive (W0.1, 2026-09-20)
   ────────────────────────────────────────────────────────────────────
   Bar layout + the two enhancement popovers ONLY. The controls themselves
   (.pf-field, .pf-field__label, .pf-input, .pf-input--select / --sm / --lg)
   are REUSED from components/input.css — nothing here re-styles a field.

   Token discipline (DS-3): every colour is a SEMANTIC role token — never a
   raw palette primitive, never a hex/rgb literal — so every surface flips
   with the theme. Every radius/shadow uses the --pf-radius-* / --pf-shadow-*
   scale. The two popovers also carry a forced-colors (Windows High Contrast)
   fallback. Motion is opt-in under prefers-reduced-motion: no-preference.

   PURELY ADDITIVE: no page renders these classes yet (Wave 1 adopts them).
   ──────────────────────────────────────────────────────────────────── */

/* ─── Bar layout ─────────────────────────────────────────────────── */

.pf-filterbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--pf-space-3);
}

.pf-filterbar__field {
    min-width: 0;
}

.pf-filterbar__actions {
    display: flex;
    align-items: flex-end;
    gap: var(--pf-space-2);
    /* push the actions cluster to the far end of the bar */
    margin-inline-start: auto;
}

/* LIVE-STATUS-1 (2026-09-27, SA-14a "Tilstande" · FG-07a result count · FG-07e states) — the Live filter's
   result line: "Showing X of Y" while a filter is active, a no-match message when nothing matches. It is ALWAYS in
   the DOM (role="status") so the first update is announced; empty = unfiltered = no space taken.
   flex-basis: a page that wraps the partial in a flex row (Recyclebin's .rb-controls) would otherwise put the
   line BESIDE the bar and stretch the no-match box to the bar's height; in a block parent it has no effect. */
.pf-filterbar__status {
    flex-basis: 100%;
    margin: var(--pf-space-2) 0 0;
    font-size: var(--pf-text-size-sm);
    color: var(--pf-color-text-secondary);
}
.pf-filterbar__status:empty {
    margin: 0;
}
.pf-filterbar__status.is-empty {
    padding: var(--pf-space-3) var(--pf-space-4);
    border: 1px dashed var(--pf-color-border-subtle);
    border-radius: var(--pf-radius-md);
    color: var(--pf-color-text-primary);
}

/* W0.2 (2026-09-20) — the Apply/Clear buttons use the ONE canonical button vocabulary
   (.platforma-btn / .platforma-btn-primary / .platforma-btn-ghost), not bespoke filter-bar
   button styling. Rod-traad: one button system + one hierarchy everywhere. Only the layout
   wrapper (.pf-filterbar__actions, above) is filter-specific. */

/* ─── Select → combobox ──────────────────────────────────────────── */

.pf-select {
    position: relative;
}

.pf-select__button {
    text-align: start;
}

.pf-select-menu {
    position: absolute;
    z-index: var(--pf-z-dropdown);
    inset-inline-start: 0;
    inset-block-start: calc(100% + var(--pf-space-1));
    min-width: 100%;
    max-height: 18rem;
    overflow-y: auto;
    padding: var(--pf-space-1);
    background: var(--pf-color-surface-overlay);
    border: 1px solid var(--pf-color-border-subtle);
    border-radius: var(--pf-radius-md);
    box-shadow: var(--pf-shadow-lg);
}

.pf-select-menu[hidden] {
    display: none;
}

.pf-select-menu__search {
    margin-block-end: var(--pf-space-1);
}

.pf-select-menu__list {
    display: flex;
    flex-direction: column;
}

.pf-select-menu__option {
    display: flex;
    align-items: center;
    gap: var(--pf-space-2);
    padding: var(--pf-space-1-5) var(--pf-space-2);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-color-text-primary);
    cursor: pointer;
}

.pf-select-menu__option[hidden] {
    display: none;
}

.pf-select-menu__option:hover,
.pf-select-menu__option.is-active {
    background: var(--pf-color-surface-hover);
}

.pf-select-menu__option.is-selected {
    background: var(--pf-color-surface-selected);
}

.pf-select-menu__option.is-selected::before {
    content: "";
    inline-size: 0.5rem;
    block-size: 0.5rem;
    border-radius: var(--pf-radius-full);
    background: var(--pf-color-action-primary);
}

.pf-select-menu__option:focus-visible {
    outline: none;
    box-shadow: var(--pf-focus-ring);
}

.pf-select-menu__empty {
    padding: var(--pf-space-2);
    color: var(--pf-color-text-tertiary);
    text-align: center;
}

.pf-select-menu__empty[hidden] {
    display: none;
}

/* ─── Date range wrapper ─────────────────────────────────────────── */

.pf-daterange {
    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-2);
}

.pf-daterange__sep {
    color: var(--pf-color-text-tertiary);
}

/* ─── Date → calendar popover ────────────────────────────────────── */

.pf-datepicker {
    position: absolute;
    z-index: var(--pf-z-popover);
    inset-block-start: calc(100% + var(--pf-space-1));
    inset-inline-start: 0;
    padding: var(--pf-space-2);
    background: var(--pf-color-surface-overlay);
    border: 1px solid var(--pf-color-border-subtle);
    border-radius: var(--pf-radius-md);
    box-shadow: var(--pf-shadow-lg);
}

.pf-datepicker[hidden] {
    display: none;
}

.pf-datepicker__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-2);
    margin-block-end: var(--pf-space-2);
}

.pf-datepicker__title {
    font-weight: var(--pf-text-weight-medium);
    color: var(--pf-color-text-primary);
}

.pf-datepicker__nav {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 1.75rem;
    block-size: 1.75rem;
    color: var(--pf-color-text-secondary);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--pf-radius-sm);
    cursor: pointer;
}

.pf-datepicker__nav:hover {
    background: var(--pf-color-surface-hover);
}

.pf-datepicker__nav:focus-visible {
    outline: none;
    box-shadow: var(--pf-focus-ring);
}

.pf-datepicker__grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}

.pf-datepicker__day {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 2rem;
    block-size: 2rem;
    font: inherit;
    color: var(--pf-color-text-primary);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--pf-radius-sm);
    cursor: pointer;
}

.pf-datepicker__day--pad {
    visibility: hidden;
}

.pf-datepicker__day:hover {
    background: var(--pf-color-surface-hover);
}

.pf-datepicker__day:focus-visible {
    outline: none;
    box-shadow: var(--pf-focus-ring);
}

.pf-datepicker__day--today {
    outline: 1px solid var(--pf-color-border-focus);
    outline-offset: -1px;
}

.pf-datepicker__day--selected {
    color: var(--pf-color-text-on-action);
    background: var(--pf-color-action-primary);
}

.pf-datepicker__day--in-range {
    background: color-mix(in oklab, var(--pf-color-action-primary) 14%, var(--pf-color-surface-overlay));
}

/* ─── Forced colours (Windows High Contrast) ─────────────────────── */

@media (forced-colors: active) {
    .pf-select-menu,
    .pf-datepicker {
        background: Canvas;
        border: 1px solid CanvasText;
    }

    .pf-select-menu__option.is-selected,
    .pf-datepicker__day--selected {
        background: Highlight;
        color: HighlightText;
        forced-color-adjust: none;
    }

    .pf-datepicker__day--today {
        outline: 1px solid CanvasText;
    }
}

/* ─── Motion (opt-in) ────────────────────────────────────────────── */

@media (prefers-reduced-motion: no-preference) {
    .pf-select-menu__option,
    .pf-datepicker__nav,
    .pf-datepicker__day {
        transition: background var(--pf-motion-duration-fast) var(--pf-motion-ease-out),
                    color var(--pf-motion-duration-fast) var(--pf-motion-ease-out);
    }
}
/* ==== css/pf/themes.brand-accents.css ==== */
/* ════════════════════════════════════════════════════════════════════
   PF DESIGN SYSTEM — Branded Chrome Accents (opt-in)
   ────────────────────────────────────────────────────────────────────
   Phase B / Option C — Subtle branded touches on editor chrome that
   reflect the active tenant's brand-theme color (--tenant-primary).
   Disabled by default; enable per-page or per-tenant by setting
   `data-pf-tenant-accent` on <body> or any ancestor.

   DESIGN PHILOSOPHY
   ─────────────────────────────────────────────────────────────────────
   Three constraints inform every accent rule:
     1. CHROME REMAINS NEUTRAL — A 1-2px tenant-colored stroke or focus-
        ring is enough to signal "you are working on Acme Corp's site".
        Full-bleed brand colors on chrome would distract from the work.
     2. TEXT-ON-ACCENT MUST PASS WCAG — Any token derived from
        --tenant-primary used as a text/bg pair must compose to ≥ 4.5:1.
        Where impossible (light brand colors), fall back to neutral.
     3. OPERATOR CONSISTENCY OVERRIDES VISUAL FLAIR — When the operator
        is performing a destructive action (delete, publish), the chrome
        snaps back to platform danger/success colors. Brand accents
        appear ONLY on idle / informational chrome.

   USAGE
   ─────────────────────────────────────────────────────────────────────
   Default (neutral chrome):
       <body data-cms-editor-theme="dark">           ← chrome is neutral

   Branded chrome (subtle accent on top of neutral chrome):
       <body data-cms-editor-theme="dark"
             data-pf-tenant-accent>                  ← accent stripes appear

   The attribute can be set:
     • By TenantBranding ViewComponent (auto-on for all editor pages)
     • By operator preference (toggle in editor topbar — Phase C)
     • By admin setting (per-tenant flag — Phase D)

   COVERED SURFACES (10 chrome touchpoints)
   ─────────────────────────────────────────────────────────────────────
     • Topbar bottom border   — 2px tenant-primary
     • Active page-tab        — bottom indicator stripe
     • Active inspector-tab   — bottom indicator stripe
     • Active outline-item    — left indicator bar
     • Focus ring (inputs)    — outline color
     • Primary CTA button     — uses tenant-primary instead of platform indigo
     • Section-add button (+) — accent ring on hover
     • Theme-swatch active    — outline color
     • Save-status pill bg    — tinted with tenant-primary-soft
     • Logo wordmark hover    — color shift to tenant-primary

   Version: 1.0.0
   Last revised: 2026-05-09
   ──────────────────────────────────────────────────────────────────── */

/* ─────────────────────────────────────────────────────────────────────
   TOPBAR — 2px bottom stripe in tenant primary
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-topbar {
    border-bottom: 2px solid var(--pf-color-action-primary);
}

/* ─────────────────────────────────────────────────────────────────────
   PAGE TAB STRIP — Active tab indicator + tenant-tinted hover
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-page-tab.is-active {
    box-shadow: inset 0 -3px 0 var(--pf-color-action-primary);
}

[data-pf-tenant-accent] .se-page-tab:hover:not(.is-active):not(.is-dragging) {
    background: color-mix(in srgb,
        var(--pf-color-action-primary) 8%,
        transparent);
}

/* ─────────────────────────────────────────────────────────────────────
   INSPECTOR TABS — Active tab indicator
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-inspector-tab.is-active {
    box-shadow: inset 0 -2px 0 var(--pf-color-action-primary);
    color: var(--pf-color-action-primary);
}

/* ─────────────────────────────────────────────────────────────────────
   OUTLINE — Active item left-bar indicator
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-outline-item.is-active {
    box-shadow: inset 3px 0 0 var(--pf-color-action-primary);
}

/* ─────────────────────────────────────────────────────────────────────
   FOCUS RING — Form inputs use tenant-primary outline
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-inspector input:focus,
[data-pf-tenant-accent] .se-inspector textarea:focus,
[data-pf-tenant-accent] .se-inspector select:focus,
[data-pf-tenant-accent] .se-field-input:focus {
    border-color: var(--pf-color-border-focus);
    box-shadow: 0 0 0 3px color-mix(in srgb,
        var(--pf-color-border-focus) 20%,
        transparent);
}

/* ─────────────────────────────────────────────────────────────────────
   PRIMARY CTA — Uses tenant-primary instead of platform indigo
   Caveat: only when --tenant-primary has sufficient contrast against
   white text. Tenants with light brand colors fall back to neutral
   via --pf-color-action-primary.
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-btn--primary {
    background: var(--pf-color-action-primary);
    border-color: var(--pf-color-action-primary);
}

[data-pf-tenant-accent] .se-btn--primary:hover:not([disabled]) {
    background: var(--pf-color-action-primary-hover);
    border-color: var(--pf-color-action-primary-hover);
}

[data-pf-tenant-accent] .se-btn--primary:active:not([disabled]) {
    background: var(--pf-color-action-primary-pressed);
}

/* ─────────────────────────────────────────────────────────────────────
   SECTION ADD-BUTTON — accent ring on hover
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-add-section-btn:hover,
[data-pf-tenant-accent] .se-add-section-btn:focus-visible {
    border-color: var(--pf-color-action-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb,
        var(--pf-color-action-primary) 18%,
        transparent);
}

/* ─────────────────────────────────────────────────────────────────────
   THEME SWATCHES — Active swatch outline matches the swatch's own color
   (always tinted regardless of accent mode — but accent mode adds a
   stronger ring for the currently-applied theme)
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-theme-swatch.is-active {
    outline: 3px solid var(--pf-color-action-primary);
    outline-offset: 2px;
}

/* ─────────────────────────────────────────────────────────────────────
   SAVE STATUS PILL — Tinted background reflecting tenant brand
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-status-pill:not(.is-saving):not(.is-error) {
    background: var(--pf-color-action-primary-soft);
    border-color: color-mix(in srgb,
        var(--pf-color-action-primary) 30%,
        transparent);
}

/* ─────────────────────────────────────────────────────────────────────
   LOGO WORDMARK — Color shift on hover to tenant-primary
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-breadcrumb a:hover,
[data-pf-tenant-accent] .se-breadcrumb-tenant:hover {
    color: var(--pf-color-action-primary);
}

/* ─────────────────────────────────────────────────────────────────────
   ESCAPE HATCHES — Destructive actions snap back to platform danger
   regardless of branded mode. Operator must NEVER mistake a tenant's
   brand color for a delete/publish confirmation.
   ───────────────────────────────────────────────────────────────────── */
[data-pf-tenant-accent] .se-btn--danger,
[data-pf-tenant-accent] .se-inspector-delete,
[data-pf-tenant-accent] .se-status-pill.is-error {
    background: var(--pf-color-action-danger);
    border-color: var(--pf-color-action-danger);
    color: var(--pf-color-text-on-action);
}

[data-pf-tenant-accent] .se-status-pill.is-saving {
    background: var(--pf-color-status-info-soft);
    border-color: var(--pf-color-status-info-border);
    color: var(--pf-color-status-info-fg);
}
