/* === MediaForce theme variables ===
 * Default values match the existing light palette so legacy hardcoded
 * colors remain unchanged. Dark theme below redefines them.
 *
 * data-theme is set on <html> by the layout based on the user's pref.
 *   data-theme="auto"  -> respect prefers-color-scheme
 *   data-theme="light" -> always light
 *   data-theme="dark"  -> always dark
 */
:root {
    /* Declare we handle both colour schemes — prevents OS forced-dark and
       Dark Reader from overriding our deliberate palette. */
    color-scheme: light dark;

    --mf-bg: #f5f5f7;
    --mf-surface: #ffffff;
    --mf-surface-alt: #fafbfd;
    --mf-surface-2: #ffffff;
    --mf-text: #1a1a1a;
    --mf-text-muted: #666;
    --mf-text-faint: #888;
    --mf-border: #e0e0e0;
    --mf-border-light: #f0f0f0;
    --mf-primary: #0066cc;
    --mf-primary-hover: #1a73e8;
    --mf-link: #0066cc;
    --mf-link-hover: #1a73e8;
    --mf-success: #2a7a2a;
    --mf-danger: #c0392b;
    --mf-warning: #b35900;
    --mf-input-bg: #ffffff;
    --mf-shadow: 0 2px 8px rgba(0,0,0,0.06);
    --mf-shadow-strong: 0 4px 16px rgba(0,0,0,0.1);

    /* Typography + button shape tokens (#679). A theme controls more than
       colour now: the UI font, base text size, and the button vocabulary
       (corner radius, weight, padding) all resolve through these so a skin —
       or a Themes & Fonts customisation — can restyle buttons and text, not
       just the palette. The defaults reproduce the previous hardcoded look. */
    --mf-font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    --mf-font-mono: "SF Mono", Menlo, Consolas, monospace;
    --mf-font-size: 14px;
    --mf-btn-radius: 6px;
    --mf-btn-weight: 600;
    --mf-btn-pad-y: 4px;
    --mf-btn-pad-x: 12px;

    /* AI (Claddy) accent + code/chat surfaces. The purple is the canonical
       AI signature; these tokens let the AI panels sit correctly on ANY skin
       instead of hardcoding the colour. Code + user-bubble surfaces likewise. */
    --mf-ai-accent: #6b3fa0;
    --mf-ai-accent-strong: #4a2a78;
    --mf-ai-accent-soft: #f3eaff;
    --mf-ai-accent-text: #ffffff;
    --mf-code-bg: #f3efe7;
    --mf-code-text: #2d2820;
    --mf-user-bubble: #2a3f6b;
    --mf-user-bubble-text: #e8eefb;

    /* Derived semantic tokens — defined ONCE in terms of the base tokens
       above, so they track every skin (light AND dark) automatically with no
       per-theme block. Used by status pills, soft badge fills, progress
       tracks, scrims, and the generic "accent" alias (orders #637–#640). */
    --mf-accent: var(--mf-primary);
    --mf-accent-soft: color-mix(in srgb, var(--mf-primary) 14%, var(--mf-surface));
    --mf-info: var(--mf-primary);
    --mf-info-soft: color-mix(in srgb, var(--mf-primary) 14%, var(--mf-surface));
    --mf-info-text: var(--mf-primary);
    --mf-success-soft: color-mix(in srgb, var(--mf-success) 16%, var(--mf-surface));
    --mf-success-text: var(--mf-success);
    --mf-danger-soft: color-mix(in srgb, var(--mf-danger) 16%, var(--mf-surface));
    --mf-warning-soft: color-mix(in srgb, var(--mf-warning) 18%, var(--mf-surface));
    --mf-border-strong: color-mix(in srgb, var(--mf-border) 60%, var(--mf-text));
    --mf-track: var(--mf-surface-alt);
    --mf-text-2: var(--mf-text-muted);
    --mf-text-3: var(--mf-text-faint);
    --mf-card-bg: var(--mf-surface);
    --mf-row-hover: var(--mf-surface-alt);
    --mf-primary-soft: color-mix(in srgb, var(--mf-primary) 14%, var(--mf-surface));
    --mf-danger-text: var(--mf-danger);
    --mf-warning-text: var(--mf-warning);
    --mf-on-accent: #ffffff; /* theme-audit-allow: text/icon on a coloured fill, constant */
    --mf-on-primary: var(--mf-on-accent); /* text on a --mf-primary fill; auto-contrasted in the @supports block below */
    --mf-overlay: rgba(0, 0, 0, 0.5); /* theme-audit-allow: modal scrim, theme-neutral */
    --mf-primary-dark: var(--mf-primary-hover);
    --mf-code-block-bg: var(--mf-code-bg);
    --mf-code-block-text: var(--mf-code-text);

    /* Admin chrome — top menu bar + side-nav. Defined ONCE over the base
       tokens so the chrome follows EVERY skin (light and dark) instead of
       staying frozen WordPress-admin black. The bar and sidebar read as a
       recessed surface; the active item uses the accent. This is the fix for
       the "sidebar never changes colour" bug and what finally makes a
       full-dark skin paint the WHOLE screen dark (orders #667 / #670). */
    --mf-chrome-bg: var(--mf-surface-alt);
    --mf-chrome-fg: var(--mf-text);
    --mf-chrome-fg-muted: var(--mf-text-muted);
    --mf-chrome-fg-faint: var(--mf-text-faint);
    --mf-chrome-border: var(--mf-border);
    --mf-chrome-hover-bg: var(--mf-surface-2);
    --mf-chrome-hover-fg: var(--mf-text);
    --mf-chrome-elev: var(--mf-surface-2);
    --mf-chrome-active-bg: var(--mf-primary);
    --mf-chrome-active-fg: var(--mf-on-primary);
    --mf-chrome-accent: var(--mf-primary);
}

/* Auto-contrasting text colour for any fill painted with --mf-primary: pick
   black or white by the accent's OKLCH lightness, so a button label stays
   legible AT REST on every skin — including the light accents (lime, amber,
   mint, gold) where the old constant white text was invisible until you
   hovered (#705). Threshold 0.56 keeps all 42 shipped themes — and any accent
   the Webmaster customises — at WCAG AA. Gated on @supports so engines without
   relative-colour syntax keep the plain white fallback defined above. */
@supports (color: oklch(from white l c h)) { /* theme-audit-allow: feature query, not a rendered colour */
    :root {
        --mf-on-primary: oklch(from var(--mf-primary) clamp(0, (0.56 - l) * 1000, 1) 0 0);
    }
}

/* Soft dark — backgrounds in the #15-1f range, comfortable for long sessions.
 * --mf-surface-2 sits one notch lighter than --mf-surface for elevated
 * components (modals, dropdowns, popovers).
 * --mf-text-faint bumped from #7a828c to #8a929e for legibility against
 * --mf-bg (#15171a). */
:root[data-theme="dark"] {
    --mf-bg: #15171a;
    --mf-surface: #1f2227;
    --mf-surface-alt: #1a1c20;
    --mf-surface-2: #262a31;
    --mf-text: #e8eaed;
    --mf-text-muted: #a8b0bb;
    --mf-text-faint: #8a929e;
    --mf-border: #2a2e34;
    --mf-border-light: #23262c;
    --mf-primary: #4da3ff;
    --mf-primary-hover: #7ab8ff;
    --mf-link: #6cb1ff;
    --mf-link-hover: #93c6ff;
    --mf-success: #4ec27c;
    --mf-danger: #ef6b6b;
    --mf-warning: #e6a45a;
    --mf-input-bg: #1a1c20;
    --mf-shadow: 0 2px 8px rgba(0,0,0,0.4);
    --mf-shadow-strong: 0 4px 16px rgba(0,0,0,0.5);

    /* AI accent + code/chat surfaces — dark variants (accent-text and the
       user bubble stay constant; they are accent-on-fill by design). */
    --mf-ai-accent: #b08fe0;
    --mf-ai-accent-strong: #d8c4f5;
    --mf-ai-accent-soft: #2a2342;
    --mf-code-bg: #15120e;
    --mf-code-text: #e8e2d6;
}

/* Auto: follow OS-level prefers-color-scheme.
 * The inline script in control/_layout.php normally rewrites
 * data-theme="auto" to "light" or "dark" before this CSS paints, so the
 * per-component overrides below (which key on data-theme="dark") fire
 * correctly under auto mode. The @media block here is a fallback for
 * users with JS disabled — they at least get the right body/text vars. */
@media (prefers-color-scheme: dark) {
    :root[data-theme="auto"] {
        --mf-bg: #15171a;
        --mf-surface: #1f2227;
        --mf-surface-alt: #1a1c20;
        --mf-surface-2: #262a31;
        --mf-text: #e8eaed;
        --mf-text-muted: #a8b0bb;
        --mf-text-faint: #8a929e;
        --mf-border: #2a2e34;
        --mf-border-light: #23262c;
        --mf-primary: #4da3ff;
        --mf-primary-hover: #7ab8ff;
        --mf-link: #6cb1ff;
        --mf-link-hover: #93c6ff;
        --mf-success: #4ec27c;
        --mf-danger: #ef6b6b;
        --mf-warning: #e6a45a;
        --mf-input-bg: #1a1c20;
        --mf-shadow: 0 2px 8px rgba(0,0,0,0.4);
        --mf-shadow-strong: 0 4px 16px rgba(0,0,0,0.5);

        --mf-ai-accent: #b08fe0;
        --mf-ai-accent-strong: #d8c4f5;
        --mf-ai-accent-soft: #2a2342;
        --mf-code-bg: #15120e;
        --mf-code-text: #e8e2d6;
    }
}

/* Apply variables to the layout chrome.
 * Specific overrides for the dark theme — using descendant selectors so
 * they win against the legacy hardcoded values.
 */
:root[data-theme="dark"] body.admin-body,
:root[data-theme="auto"] body.admin-body {
    background: var(--mf-bg);
    color: var(--mf-text);
}

@media (prefers-color-scheme: dark) {
    :root[data-theme="auto"] body.admin-body { background: var(--mf-bg); color: var(--mf-text); }
}

/* Dark theme overrides for major surfaces.
 * The existing :root selectors below (:root[data-theme="dark"] ...) target
 * components that hardcode #fff or specific greys.
 */
:root[data-theme="dark"] code,
:root[data-theme="dark"] pre {
    background: var(--mf-surface);
    border-color: var(--mf-border);
    color: var(--mf-text);
}

:root[data-theme="dark"] .card,
:root[data-theme="dark"] .mf-card,
:root[data-theme="dark"] .mf-tile,
:root[data-theme="dark"] .mf-cal-month,
:root[data-theme="dark"] .mf-cal-week,
:root[data-theme="dark"] .mf-cal-day-list,
:root[data-theme="dark"] .mf-worker-table,
:root[data-theme="dark"] .mf-mem-table,
:root[data-theme="dark"] .mf-pref-table,
:root[data-theme="dark"] .mf-bell-panel,
:root[data-theme="dark"] .mf-sysmenu-panel,
:root[data-theme="dark"] .mf-event-form,
:root[data-theme="dark"] .mf-cal-create-form,
:root[data-theme="dark"] .mf-add-form,
:root[data-theme="dark"] .mf-cal-toolbar,
:root[data-theme="dark"] .mf-cal-list,
:root[data-theme="dark"] .mf-notif-toolbar,
:root[data-theme="dark"] .mf-notif-list,
:root[data-theme="dark"] .mf-worker-toolbar,
:root[data-theme="dark"] .mf-access-card,
:root[data-theme="dark"] .mf-access-picker,
:root[data-theme="dark"] .mf-access-detail .mf-access-card,
:root[data-theme="dark"] .ap-stat,
:root[data-theme="dark"] .mf-cal-day-cell,
:root[data-theme="dark"] .mf-event-attendees-grid,
:root[data-theme="dark"] table {
    background: var(--mf-surface);
    color: var(--mf-text);
    border-color: var(--mf-border);
}

:root[data-theme="dark"] th {
    background: var(--mf-surface-alt) !important;
    color: var(--mf-text-muted) !important;
    border-color: var(--mf-border) !important;
}

:root[data-theme="dark"] td,
:root[data-theme="dark"] tr {
    border-color: var(--mf-border-light) !important;
}

:root[data-theme="dark"] input,
:root[data-theme="dark"] select,
:root[data-theme="dark"] textarea {
    background: var(--mf-input-bg);
    color: var(--mf-text);
    border-color: var(--mf-border);
}

:root[data-theme="dark"] .btn,
:root[data-theme="dark"] button {
    border-color: var(--mf-border);
}
:root[data-theme="dark"] .btn-secondary {
    background: var(--mf-surface);
    color: var(--mf-text);
}
/* Content links pick up the accent in dark mode, but NOT anchors styled as
   buttons (.btn): those carry their own variant colours, and letting the
   accent bleed into an a.btn.btn-primary painted accent-on-accent text —
   invisible until hover (#705). */
:root[data-theme="dark"] a:not(.btn) {
    color: var(--mf-primary);
}

:root[data-theme="dark"] .mf-cal-day-cell.other-month { background: var(--mf-surface-alt); }
:root[data-theme="dark"] .mf-cal-day-cell.weekend { background: var(--mf-bg); }
:root[data-theme="dark"] .mf-cal-day-cell.today { background: color-mix(in srgb, var(--mf-warning) 16%, var(--mf-surface)); }

/* Soft text/muted overrides for any element using hardcoded greys */
:root[data-theme="dark"] .mf-card-foot,
:root[data-theme="dark"] .mf-bell-empty,
:root[data-theme="dark"] .mf-notif-empty {
    color: var(--mf-text-faint);
}

/* --- User dropdown (top-right) -------------------------------------------- */
:root[data-theme="dark"] .admin-user-dropdown {
    background: var(--mf-surface-2);
    border-color: var(--mf-border);
    color: var(--mf-text);
}
:root[data-theme="dark"] .admin-user-dropdown-head { border-bottom-color: var(--mf-border); }
:root[data-theme="dark"] .admin-user-dropdown-head strong { color: var(--mf-text); }
:root[data-theme="dark"] .admin-user-dropdown-head small  { color: var(--mf-text-faint); }
:root[data-theme="dark"] .admin-user-dropdown-avatar--initials {
    background: var(--mf-surface-alt);
    color: var(--mf-text-muted);
}
:root[data-theme="dark"] .admin-user-dropdown-item { color: var(--mf-text); }
:root[data-theme="dark"] .admin-user-dropdown-item:hover {
    background: var(--mf-surface-alt);
    color: var(--mf-link-hover);
}
:root[data-theme="dark"] .admin-user-dropdown-sep { background: var(--mf-border); }
:root[data-theme="dark"] .admin-user-dropdown-weather { color: var(--mf-text); }
:root[data-theme="dark"] .admin-user-dropdown-weather:hover {
    background: var(--mf-surface-alt);
    color: var(--mf-link-hover);
}
:root[data-theme="dark"] .admin-user-dropdown-weather-city { color: var(--mf-text-faint); }
:root[data-theme="dark"] .admin-user-dropdown-logout { color: var(--mf-danger); }
:root[data-theme="dark"] .admin-user-dropdown-logout:hover {
    background: var(--mf-danger-soft);
    color: var(--mf-danger);
}
:root[data-theme="dark"] .admin-user-dropdown-item.is-current .admin-user-dropdown-badge { color: var(--mf-link); }

/* --- Footer & breadcrumbs ------------------------------------------------- */
:root[data-theme="dark"] .admin-footer {
    background: var(--mf-surface);
    border-top-color: var(--mf-border);
    color: var(--mf-text-faint);
}
:root[data-theme="dark"] .breadcrumbs          { color: var(--mf-text-faint); }
:root[data-theme="dark"] .breadcrumbs .sep     { color: var(--mf-border); }
:root[data-theme="dark"] .breadcrumbs a        { color: var(--mf-text-muted); }
:root[data-theme="dark"] .breadcrumbs .current { color: var(--mf-text); }

/* --- Card border ---------------------------------------------------------- */
:root[data-theme="dark"] .card { border-color: var(--mf-border); }

/* --- Forms ---------------------------------------------------------------- */
:root[data-theme="dark"] .form-row label { color: var(--mf-text); }
:root[data-theme="dark"] .form-row .help  { color: var(--mf-text-faint); }
:root[data-theme="dark"] .form-row input[type=text],
:root[data-theme="dark"] .form-row input[type=email],
:root[data-theme="dark"] .form-row input[type=password],
:root[data-theme="dark"] .form-row input[type=number],
:root[data-theme="dark"] .form-row textarea,
:root[data-theme="dark"] .form-row select,
:root[data-theme="dark"] .form-row input[type=file] {
    background: var(--mf-input-bg);
    color: var(--mf-text);
    border-color: var(--mf-border);
}

/* Visibility pills, buttons, flash, pills, login/error/installer shells,
   check items, plugin cards, logo preview, kv-list and danger zone no longer
   need a separate [data-theme="dark"] block: their base rules now resolve
   through semantic --mf-* tokens (success/danger/warning/-soft/-text, surface,
   text, border), so they track every skin — light AND dark — automatically.
   The old hardcoded-rgba dark overrides were removed because they masked the
   skin on non-default dark themes (orders #667 / #670). */

/* --- Notification bell internals ----------------------------------------- */
:root[data-theme="dark"] .mf-bell-head {
    background: var(--mf-surface-alt);
    border-bottom-color: var(--mf-border);
}
:root[data-theme="dark"] .mf-bell-mark-all      { color: var(--mf-link); }
:root[data-theme="dark"] .mf-bell-item          { border-bottom-color: var(--mf-border-light); }
:root[data-theme="dark"] .mf-bell-item:hover    { background: var(--mf-surface-alt); }
:root[data-theme="dark"] .mf-bell-item-icon {
    background: var(--mf-surface-alt);
    color: var(--mf-text);
}
:root[data-theme="dark"] .mf-bell-item-body { color: var(--mf-text-muted); }
:root[data-theme="dark"] .mf-bell-item-time { color: var(--mf-text-faint); }
:root[data-theme="dark"] .mf-bell-foot {
    background: var(--mf-surface-alt);
    border-top-color: var(--mf-border);
}
:root[data-theme="dark"] .mf-bell-view-all     { color: var(--mf-link); }
:root[data-theme="dark"] .mf-bell-prefs        { color: var(--mf-text-faint); }
:root[data-theme="dark"] .mf-bell-prefs:hover  { color: var(--mf-text); }

/* --- Sysmenu internals (panel itself is in the .card group above) -------- */
:root[data-theme="dark"] .mf-sysmenu-panel { color: var(--mf-text); }
:root[data-theme="dark"] .mf-sysmenu-overview              { border-bottom-color: var(--mf-border); }
:root[data-theme="dark"] .mf-sysmenu-overview:hover        { background: var(--mf-surface-alt); }
:root[data-theme="dark"] .mf-sysmenu-section + .mf-sysmenu-section { border-top-color: var(--mf-border-light); }
:root[data-theme="dark"] .mf-sysmenu-section-title         { color: var(--mf-text-faint); }
:root[data-theme="dark"] .mf-sysmenu-item:hover            { background: var(--mf-surface-alt); }

/* === Blanket dark overrides for plugin-level inline-style patterns ========
 *
 * Plugin admin pages (and some core pages) embed <style> blocks with
 * hardcoded hex values (#fff, #e0e0e0, #333, etc.).  Rather than editing
 * every plugin file, we cover the most common class-name patterns here.
 * Specificity of ":root[data-theme="dark"] .class" beats a plain ".class"
 * rule in an inline <style> block, so these win without !important.
 *
 * Naming conventions seen across plugins:
 *   *-card, *-panel, *-box, *-block, *-section   → surface containers
 *   *-toolbar, *-header, *-footer                 → chrome strips
 *   *-row, *-item, *-entry                        → list rows
 *   *-badge, *-pill, *-tag, *-chip                → small labels
 *   *-grid, *-list                                → layout wrappers (transparent)
 *   *-stat, *-metric, *-kpi                       → dashboard tiles
 *   *-empty                                       → placeholder states
 *   *-desc, *-meta, *-date, *-label               → muted text helpers
 *   *-sep, *-divider                              → horizontal rules
 *   page-header, page-actions                     → standard page chrome
 */

/* --- auto mode must also fire these overrides ----------------------------- */
:root[data-theme="dark"],
:root[data-theme="auto"]:not([data-theme-resolved="light"]) {
    /* Nothing here — the per-selector rules below explicitly list both
       data-theme="dark" and the auto dark variant handled by the inline
       script that rewrites auto→dark/light before paint.  The auto case
       is therefore covered by data-theme="dark" once the inline script
       runs; the @media fallback below covers no-JS auto. */
}

/* Surface containers */
:root[data-theme="dark"] [class*="-card"],
:root[data-theme="dark"] [class*="-panel"]:not(.admin-main-menu-panel):not(.smb-msg-banner),
:root[data-theme="dark"] [class*="-box"]:not(input):not(select):not(textarea),
:root[data-theme="dark"] [class*="-block"],
:root[data-theme="dark"] [class*="-stat"],
:root[data-theme="dark"] [class*="-metric"],
:root[data-theme="dark"] [class*="-kpi"],
:root[data-theme="dark"] [class*="-tile"]:not(.mf-mail-theme-tile) {
    background: var(--mf-surface);
    border-color: var(--mf-border);
    color: var(--mf-text);
}

/* Chrome strips */
:root[data-theme="dark"] [class*="-toolbar"]:not(toolbar),
:root[data-theme="dark"] [class*="-header"]:not(.admin-header):not(.admin-main-menu-bar):not(.page-header) {
    background: var(--mf-surface);
    border-color: var(--mf-border);
    color: var(--mf-text);
}

/* List rows */
:root[data-theme="dark"] [class*="-row"]:not(tr),
:root[data-theme="dark"] [class*="-item"]:not(.admin-user-dropdown-item):not(.mf-sidenav-item):not(.mf-bell-item):not(.mf-sysmenu-item),
:root[data-theme="dark"] [class*="-entry"] {
    border-color: var(--mf-border-light);
    color: var(--mf-text);
}

/* Muted text helpers */
:root[data-theme="dark"] [class*="-desc"],
:root[data-theme="dark"] [class*="-meta"]:not(meta),
:root[data-theme="dark"] [class*="-date"],
:root[data-theme="dark"] [class*="-label"]:not(label),
:root[data-theme="dark"] [class*="-hint"],
:root[data-theme="dark"] [class*="-sub"],
:root[data-theme="dark"] [class*="-small"],
:root[data-theme="dark"] [class*="-empty"] {
    color: var(--mf-text-muted);
}

/* Separators */
:root[data-theme="dark"] [class*="-sep"],
:root[data-theme="dark"] [class*="-divider"] {
    background: var(--mf-border);
    border-color: var(--mf-border);
}

/* Page chrome */
:root[data-theme="dark"] .page-header { color: var(--mf-text); }

/* Changelog specific */
:root[data-theme="dark"] .changelog-version {
    background: var(--mf-surface);
    border-left-color: var(--mf-border);
    color: var(--mf-text);
}
:root[data-theme="dark"] .changelog-version.is-current {
    background: color-mix(in srgb, var(--mf-primary) 12%, var(--mf-surface));
    border-left-color: var(--mf-primary);
}
:root[data-theme="dark"] .changelog-version-title { color: var(--mf-text); }
:root[data-theme="dark"] .changelog-date,
:root[data-theme="dark"] .changelog-headline { color: var(--mf-text-muted); }
:root[data-theme="dark"] .changelog-list li { color: var(--mf-text-muted); }

/* System mailbox */
:root[data-theme="dark"] .smb-toolbar,
:root[data-theme="dark"] .smb-table,
:root[data-theme="dark"] .smb-msg-card,
:root[data-theme="dark"] .smb-empty,
:root[data-theme="dark"] .smb-attach,
:root[data-theme="dark"] .smb-msg-body-text {
    background: var(--mf-surface);
    border-color: var(--mf-border);
    color: var(--mf-text);
}
:root[data-theme="dark"] .smb-table th {
    background: var(--mf-surface-alt) !important;
    color: var(--mf-text-muted) !important;
}
:root[data-theme="dark"] .smb-table tr.is-unread td { background: color-mix(in srgb, var(--mf-primary) 9%, var(--mf-surface)); }
:root[data-theme="dark"] .smb-table tr:hover { background: var(--mf-surface-alt); }
:root[data-theme="dark"] .smb-table td.smb-date,
:root[data-theme="dark"] .smb-table td.smb-size,
:root[data-theme="dark"] .smb-table td.smb-flags { color: var(--mf-text-muted); }
:root[data-theme="dark"] .smb-table td.smb-from { color: var(--mf-text); }
:root[data-theme="dark"] .smb-table td.smb-subject { color: var(--mf-text); }
:root[data-theme="dark"] .smb-msg-meta dt { color: var(--mf-text-faint); }
:root[data-theme="dark"] .smb-msg-meta dd { color: var(--mf-text); }
:root[data-theme="dark"] .smb-msg-banner {
    background: var(--mf-warning-soft);
    border-color: color-mix(in srgb, var(--mf-warning) 30%, transparent);
    color: var(--mf-text);
}
:root[data-theme="dark"] .smb-pager a,
:root[data-theme="dark"] .smb-pager span { border-color: var(--mf-border); color: var(--mf-text-muted); }
:root[data-theme="dark"] .smb-pager .disabled { color: var(--mf-text-faint); border-color: var(--mf-border-light); }

/* Code section cards (cd-card) */
:root[data-theme="dark"] .cd-card {
    background: var(--mf-surface);
    border-color: var(--mf-border);
    color: var(--mf-text);
}
:root[data-theme="dark"] .cd-card:hover { box-shadow: var(--mf-shadow-strong); }
:root[data-theme="dark"] .cd-card-desc { color: var(--mf-text-muted); }

/* Apps section cards (ap-card) */
:root[data-theme="dark"] .ap-card {
    background: var(--mf-surface);
    border-color: var(--mf-border);
    color: var(--mf-text);
}
:root[data-theme="dark"] .ap-card:hover { box-shadow: var(--mf-shadow-strong); }
:root[data-theme="dark"] .ap-card-desc { color: var(--mf-text-muted); }
:root[data-theme="dark"] .ap-section h2 { color: var(--mf-text-faint); }
:root[data-theme="dark"] .ap-section::after { background: var(--mf-border); }
:root[data-theme="dark"] .ap-stat { background: var(--mf-surface); border-color: var(--mf-border); color: var(--mf-text); }

/* Pages inventory (pgi-*) */
:root[data-theme="dark"] .pgi-table { background: var(--mf-surface); border-color: var(--mf-border); }
:root[data-theme="dark"] .pgi-table th { background: var(--mf-surface-alt) !important; color: var(--mf-text-muted) !important; }
:root[data-theme="dark"] .pgi-table td { border-color: var(--mf-border-light); color: var(--mf-text); }
:root[data-theme="dark"] .pgi-table tr:hover { background: var(--mf-surface-alt); }
:root[data-theme="dark"] .pgi-filter { background: var(--mf-surface); border-color: var(--mf-border); color: var(--mf-text); }
:root[data-theme="dark"] .pgi-filter input,
:root[data-theme="dark"] .pgi-filter select { background: var(--mf-input-bg); border-color: var(--mf-border); color: var(--mf-text); }
:root[data-theme="dark"] .pgi-badge-orphan { background: var(--mf-danger-soft);  color: var(--mf-danger-text); }
:root[data-theme="dark"] .pgi-badge-api    { background: var(--mf-info-soft);    color: var(--mf-info-text); }
:root[data-theme="dark"] .pgi-badge-menu   { background: var(--mf-success-soft); color: var(--mf-success-text); }
:root[data-theme="dark"] .pgi-url          { color: var(--mf-link); }

/* === end theme block === */

/* =========================================================================
   Viewport safety net + canonical layout primitives.

   mf-viewport.js (kernel inlined by ViewportBootstrap::inlineHead() in
   every layout, full file deferred-loaded from the admin layout) writes
   vp-xs..vp-xl, pointer-coarse/-fine, hover-hover/-none, orient-portrait/
   -landscape, is-ios, is-android classes on <html> plus --vw, --vh and
   --app-height custom properties — all before first paint. CSS below can
   read them without flicker; JS reads them via window.MF.viewport.

   overflow-x: clip on html+body is the global anti-swipe-left guard:
   no matter what a plugin renders, the page itself never produces a
   horizontal scrollbar. Use overflow-x: auto on the offending inner
   container when you actually want a scrollable wide region (tables,
   <pre>, …) — clip just stops the rogue width from leaking up to the
   root. clip doesn't establish a new scrolling/positioning context, so
   sticky headers and popovers anchored to <body> keep working.

   --app-height is the actual window.innerHeight in pixels at this
   moment. Use it wherever you'd reach for 100vh / 100dvh — it's the only
   value that survives iOS Safari's address-bar collapse. Pattern:
       max-height: calc(var(--app-height, 100dvh) - 64px);
   ========================================================================= */

/* overflow-x: clip on BODY ONLY — not html. When clip is set on html,
   several browsers (iOS Safari notably) end up clipping the vertical
   axis as well, which crops every position: absolute dropdown panel
   that extends below the visible viewport — the symptom is a "halfway
   visible" panel that fills the lower half of the menu and just stops.
   Body alone with max-width: 100vw gives us the no-horizontal-page-
   scroll guarantee without that side-effect.

   overflow-x: hidden on <html> is the second-layer guard. clip would
   propagate to the vertical axis (the bug above), but hidden does not —
   the spec doesn't coerce overflow-y when overflow-x is hidden. This
   catches the case where a fixed-positioned descendant (overlay,
   popover, debug widget, error banner) extends past the viewport: body's
   clip doesn't reach fixed elements (they anchor to the initial
   containing block, not body), so without an html-level guard the
   viewport itself accepts a horizontal swipe gesture during iOS Safari's
   momentum scroll. hidden on html plugs that. */
html { overflow-x: hidden; }
body { overflow-x: clip; }
body.admin-body { max-width: 100vw; }

/* scroll-padding-top stops iOS Safari from pushing the sticky top menu
   off-screen when the soft keyboard opens. When you focus an input,
   iOS scrolls the document so the input clears the keyboard; without
   this padding, that scroll briefly moves the sticky .admin-main-menu
   (z:100, top:0) above the visible viewport — the menu visibly
   disappears while you type, only resettling once the scroll lands.
   With scroll-padding-top: 56px (52px on phone, +36 with status bar),
   the browser reserves that strip during programmatic scroll so the
   menu stays put. The "every time i write to you, the top menu
   disappears" bug. */
html { scroll-padding-top: 56px; }
@media (max-width: 600px) {
    html { scroll-padding-top: 52px; }
}
body.mf-has-status-bar { /* +36px under the menu */ }
html:has(body.mf-has-status-bar) { scroll-padding-top: 92px; }
@media (max-width: 600px) {
    html:has(body.mf-has-status-bar) { scroll-padding-top: 88px; }
}

img, video, iframe, canvas, svg {
    max-width: 100%;
    height: auto;
}

@media (max-width: 768px) {
    /* Long URLs and other unbreakable strings break onto the next line
       instead of pushing the page wider on phones. Scoped to text-bearing
       elements so we don't accidentally re-flow flex/grid containers. */
    p, li, dd, dt, td, th, blockquote { overflow-wrap: anywhere; }
}

/* === Webmaster ?vpdebug=1 overlay ====================================== */
.mf-vpdebug {
    position: fixed;
    right: 8px;
    bottom: 8px;
    z-index: 10000;
    background: rgba(20, 20, 20, 0.92); /* theme-audit-allow: fixed diagnostic HUD, must stay legible over any page */
    color: #fff; /* theme-audit-allow: fixed diagnostic HUD */
    border: 1px solid #444; /* theme-audit-allow: fixed diagnostic HUD */
    border-radius: 8px;
    padding: 8px 10px;
    font-family: ui-monospace, Menlo, monospace;
    font-size: 11px;
    line-height: 1.4;
    display: flex;
    flex-direction: column;
    gap: 6px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.4);
    pointer-events: auto;
}
.mf-vpdebug-row {
    display: flex;
    gap: 10px;
    align-items: center;
    flex-wrap: wrap;
}
.mf-vpdebug-tier {
    background: #0066cc; /* theme-audit-allow: fixed diagnostic HUD */
    color: #fff; /* theme-audit-allow: fixed diagnostic HUD */
    padding: 1px 6px;
    border-radius: 4px;
    font-weight: 600;
}
.mf-vpdebug-size,
.mf-vpdebug-input,
.mf-vpdebug-orient { color: #ccc; /* theme-audit-allow: fixed diagnostic HUD */ }
.mf-vpdebug-btn {
    background: #333; /* theme-audit-allow: fixed diagnostic HUD */
    color: #fff; /* theme-audit-allow: fixed diagnostic HUD */
    border: 1px solid #555; /* theme-audit-allow: fixed diagnostic HUD */
    border-radius: 4px;
    padding: 2px 8px;
    font-family: inherit;
    font-size: 11px;
    cursor: pointer;
    text-decoration: none;
    line-height: 1.4;
}
.mf-vpdebug-btn:hover {
    background: #444; /* theme-audit-allow: fixed diagnostic HUD */
    color: #fff; /* theme-audit-allow: fixed diagnostic HUD */
    text-decoration: none;
}
.mf-vpdebug-close {
    margin-left: auto;
    padding: 0 8px;
    font-size: 14px;
    line-height: 1.6;
}
.mf-vpdebug-hit {
    outline: 2px solid #e74c3c !important; /* theme-audit-allow: layout-debug highlight, fixed signal colour */
    outline-offset: -1px !important;
    background: rgba(231, 76, 60, 0.08) !important; /* theme-audit-allow: layout-debug highlight */
}

/* =========================================================================
   CANONICAL PANEL CLAMP

   Every popover, dropdown panel, modal panel, and dialog surface in
   MediaForce is structurally guaranteed to fit inside the visible
   viewport by this single block. Individual rules later in the file
   (or in plugin stylesheets) can still set a TIGHTER cap (e.g. a
   modal that should be 420px wide on desktop), but the baseline
   max-width / max-height never lets a panel run off-screen.

   It catches:
     - .mf-bell-panel, .mf-sysmenu-panel, .mf-mediapicker-panel,
       .mf-aichat-panel, .mf-ai-overlay-panel — explicit panel classes.
     - .mf-mail-theme-popover and any class ending in -popover via the
       attribute selector — plugin popovers without manual clamping.
     - .admin-user-dropdown and any class ending in -dropdown — same.
     - [role="dialog"] / [role="menu"] — primitives a plugin can use
       without touching this file.

   --app-height is set by mf-viewport.js (kernel inlined in every
   layout). The dvh fallback covers the no-JS / first-paint case
   without the iOS 100vh quirk biting too hard.

   Why both max-height AND overscroll-behavior: contain — the
   max-height keeps the panel inside the viewport; overscroll-behavior
   stops a scroll-to-end inside the panel from scrolling the page
   underneath.
   ========================================================================= */
.mf-bell-panel,
.mf-sysmenu-panel,
.mf-mediapicker-panel,
.mf-aichat-panel,
.mf-ai-overlay-panel,
.admin-user-dropdown,
.mf-vpdebug,
[class*="-popover"],
[class*="-dropdown-menu"],
[role="dialog"],
[role="menu"],
[role="listbox"] {
    max-width: calc(100vw - 16px);
    max-height: calc(var(--app-height, 100dvh) - 16px);
    overscroll-behavior: contain;
}

/* When the panel ends up scrollable, give it a sensible default. Most
   panels already declare overflow-y; this fills the gap for any that
   forgot. */
.mf-bell-panel,
.mf-sysmenu-panel,
.mf-mediapicker-panel,
.mf-aichat-panel,
.admin-user-dropdown,
[class*="-popover"],
[class*="-dropdown-menu"],
[role="dialog"],
[role="menu"],
[role="listbox"] {
    overflow-y: auto;
}

/* MediaForce - Admin Stylesheet */

* { box-sizing: border-box; }

body.admin-body {
    margin: 0;
    font-family: var(--mf-font-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);
    font-size: var(--mf-font-size, 14px);
    background: var(--mf-bg);
    color: var(--mf-text);
    line-height: 1.5;
}

a { color: var(--mf-link); text-decoration: none; }
a:hover { text-decoration: underline; color: var(--mf-link-hover); }
code { background: var(--mf-surface); padding: 2px 6px; border-radius: 3px; border: 1px solid var(--mf-border); color: var(--mf-text); font-family: "SF Mono", Menlo, monospace; font-size: 0.9em; }
pre { background: var(--mf-surface); padding: 12px; border-radius: 6px; border: 1px solid var(--mf-border); color: var(--mf-text); font-family: "SF Mono", Menlo, monospace; font-size: 13px; overflow-x: auto; line-height: 1.5; }

.admin-main-menu { background: var(--mf-chrome-bg); color: var(--mf-chrome-fg); border-bottom: 1px solid var(--mf-chrome-border); position: sticky; top: 0; z-index: 100; }
.admin-main-menu-inner { max-width: 1400px; margin: 0 auto; padding: 0 24px; display: flex; align-items: center; height: 56px; gap: 32px; }
.admin-brand { color: var(--mf-chrome-fg); font-weight: 600; font-size: 16px; display: flex; align-items: center; gap: 10px; }
.admin-brand-logo { height: 28px; width: auto; background: transparent; padding: 4px 6px; border-radius: 4px; box-sizing: content-box; }
.admin-brand:hover { text-decoration: none; color: var(--mf-chrome-fg); }
.admin-main-menu-widgets { display: flex; gap: 16px; align-items: center; padding: 0 4px; }
.admin-main-menu-widgets-left { display: flex; gap: 16px; align-items: center; padding: 0 4px; }
.admin-main-menu-widgets-left:empty { display: none; }
.admin-main-menu-widget { color: var(--mf-chrome-fg-muted); font-size: 13px; line-height: 1; position: relative; }
.admin-main-menu-widget a { color: inherit; }
.admin-main-menu-widget a:hover { color: var(--mf-chrome-fg); text-decoration: none; }

/* phone-security widget: always visible on all device sizes.
   Cancel the right-side user menu's margin-left:auto when the same
   admin-user-menu class is used inside the left zone.
   Open leftward triggers rightward so the dropdown doesn't bleed off
   the left edge of the viewport (right:0 would anchor it only ~40px
   in from the left — the 240px panel would mostly be off-screen). */
.admin-main-menu-widgets-left .admin-user-menu { margin-left: 0; }
.admin-main-menu-widgets-left .admin-user-dropdown { right: auto; left: 0; }

/* Per-AI beacon dots on the topbar lightbulb. The strip pins to the
   bulb glyph's bottom-left so the build-count badge (top-right) has
   room. Idle dots are dim and desaturated; lit dots get their AI's
   colour through --mf-beacon-color and pulse on the canonical
   1.2s rhythm shared with .mf-ai-thinking-spinner. */
.mf-ai-beacon-strip {
    position: absolute;
    left: -3px;
    bottom: -2px;
    display: inline-flex;
    gap: 2px;
    pointer-events: none;
}
.mf-ai-beacon-dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--mf-text-faint);
    opacity: 0.35;
    transition: opacity 160ms ease, background-color 160ms ease, box-shadow 160ms ease;
}
.mf-ai-beacon-dot.lit {
    background: var(--mf-beacon-color, #a64ee5);
    opacity: 1;
    box-shadow: 0 0 4px var(--mf-beacon-color, #a64ee5);
    animation: mf-ai-beacon-pulse 1.2s ease-in-out infinite;
}
@keyframes mf-ai-beacon-pulse {
    0%, 100% { opacity: 0.55; transform: scale(0.85); }
    50%      { opacity: 1;    transform: scale(1); }
}

/* Flex spacer between the left and right widget clusters. Every menu icon
   lives in .admin-main-menu-widgets; on phone, anything beyond the four
   essentials collapses behind the ⋯ overflow popover (no separate drawer). */
.admin-spacer { flex: 1; }
/* AI bulb glow-pulse when any agent is mid-turn — same 1.2s rhythm as aii thinking spinner */
[data-ai-bulb].lit {
    animation: mf-ai-bulb-pulse 1.2s ease-in-out infinite;
}
@keyframes mf-ai-bulb-pulse {
    0%, 100% { filter: drop-shadow(0 0 0px rgba(255,200,0,0)); }
    50%       { filter: drop-shadow(0 0 8px rgba(255,200,0,0.95)); }
}

/* ⋯ overflow toggle — phone-only. Hidden by default; the <=600px media
   block below switches it on. Sits between the right-widget cluster and
   the user menu so it's reachable with the same thumb. */
.admin-main-menu-more {
    display: none;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    padding: 0;
    background: transparent;
    border: 0;
    color: var(--mf-chrome-fg-muted);
    cursor: pointer;
    border-radius: 6px;
}
.admin-main-menu-more:hover { background: var(--mf-chrome-hover-bg); color: var(--mf-chrome-fg); }
.admin-main-menu-more-glyph { font-size: 24px; line-height: 1; }
.admin-user { display: flex; align-items: center; gap: 16px; font-size: 14px; }
.admin-user-name { color: var(--mf-chrome-fg-muted); }
.admin-logout { color: var(--mf-chrome-fg); }

/* User dropdown menu (top-right of admin) */
.admin-user-menu {
    position: relative;
    margin-left: auto;
}
.admin-user-menu summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    border-radius: 4px;
    color: var(--mf-chrome-fg-muted);
    font-size: 14px;
    user-select: none;
}
.admin-user-menu summary::-webkit-details-marker { display: none; }
.admin-user-menu summary:hover { background: var(--mf-chrome-hover-bg); color: var(--mf-chrome-fg); }
.admin-user-menu[open] summary { background: var(--mf-chrome-hover-bg); color: var(--mf-chrome-fg); }
.admin-user-summary .admin-user-caret { font-size: 10px; opacity: 0.7; transition: transform 0.1s; }
.admin-user-menu[open] .admin-user-caret { transform: rotate(180deg); }

/* Avatar inside the summary trigger — always visible. On desktop it sits
   left of the name; on phone the name + caret hide and the avatar IS the
   trigger (a compact circle pinned to the right edge of the main menu). */
.admin-user-summary-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    background: var(--mf-chrome-hover-bg);
}
.admin-user-summary-avatar--initials {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 600;
    color: var(--mf-chrome-fg);
    text-transform: uppercase;
}

.admin-user-dropdown {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    min-width: 240px;
    background: var(--mf-surface-2, #fff);
    border: 1px solid var(--mf-border, #d0d0d0);
    border-radius: 6px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.15);
    z-index: 9999;
    padding: 6px 0;
    color: var(--mf-text, #222);
}
.admin-user-dropdown-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px 12px;
    border-bottom: 1px solid var(--mf-border-light, #eee);
    margin-bottom: 4px;
}
.admin-user-dropdown-head-text { min-width: 0; flex: 1; }
.admin-user-dropdown-head strong { display: block; color: var(--mf-text, #111); font-size: 14px; }
.admin-user-dropdown-head small { display: block; color: var(--mf-text-faint, #888); font-size: 12px; margin-top: 2px; }
.admin-user-dropdown-avatar {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}
.admin-user-dropdown-avatar--initials {
    background: var(--mf-surface-alt, #e0e0e0);
    color: var(--mf-text-muted, #666);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    font-weight: 600;
}

.admin-user-dropdown-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 16px;
    color: var(--mf-text, #333);
    font-size: 14px;
    text-decoration: none;
    white-space: nowrap;
}
.admin-user-dropdown-item:hover { background: var(--mf-surface-alt, #f0f4ff); color: var(--mf-primary, #1a73e8); text-decoration: none; }
.admin-user-dropdown-icon { width: 20px; text-align: center; opacity: 0.85; }
.admin-user-dropdown-label { flex: 1; }
.admin-user-dropdown-badge {
    background: var(--mf-danger);
    color: var(--mf-on-accent);
    font-size: 11px;
    font-weight: 600;
    padding: 1px 7px;
    border-radius: 10px;
    min-width: 18px;
    text-align: center;
}
.admin-user-dropdown-sep { height: 1px; background: var(--mf-border-light, #eee); margin: 4px 0; }
.admin-user-dropdown-logout { color: var(--mf-danger, #c0392b); }
.admin-user-dropdown-logout:hover { background: var(--mf-danger-soft); color: var(--mf-danger, #c0392b); }

/* Desktop clamp — aligns with bell/sysmenu which subtract 72-80px.
   The canonical panel clamp only subtracts 16px, which is too loose for
   a panel that opens ~60px below the top of the page. */
html.mf-desktop .admin-user-dropdown {
    max-height: calc(var(--app-height, 100dvh) - 72px);
}

/* macOS overlay scrollbars are invisible until hover — force a thin
   visible track so users can tell the panel is scrollable on Mac. */
html.mf-os-mac .admin-user-dropdown,
html.mf-os-mac .mf-sysmenu-panel,
html.mf-os-mac .mf-bell-list {
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--mf-text) 28%, transparent) transparent;
}
html.mf-os-mac .admin-user-dropdown::-webkit-scrollbar,
html.mf-os-mac .mf-sysmenu-panel::-webkit-scrollbar,
html.mf-os-mac .mf-bell-list::-webkit-scrollbar { width: 5px; }
html.mf-os-mac .admin-user-dropdown::-webkit-scrollbar-thumb,
html.mf-os-mac .mf-sysmenu-panel::-webkit-scrollbar-thumb,
html.mf-os-mac .mf-bell-list::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--mf-text) 28%, transparent);
    border-radius: 3px;
}

/* user-menu zone widgets (weather lives here). Rendered between the
   avatar header and the nav items inside .admin-user-dropdown. */
.admin-user-dropdown-widget { display: block; }
.admin-user-dropdown-weather {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 16px;
    color: var(--mf-text, #333);
    font-size: 14px;
    text-decoration: none;
    white-space: nowrap;
}
.admin-user-dropdown-weather:hover { background: var(--mf-surface-alt, #f0f4ff); color: var(--mf-primary, #1a73e8); text-decoration: none; }
.admin-user-dropdown-weather-icon {
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.admin-user-dropdown-weather-icon img { width: 28px; height: 28px; display: block; }
.admin-user-dropdown-weather-temp { font-weight: 600; font-size: 15px; }
.admin-user-dropdown-weather-city {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--mf-text-faint, #888);
    font-size: 12px;
}

/* Language switcher: current language is bold; the ✓ badge gets a
   neutral pill instead of the red unread-count style. */
.admin-user-dropdown-item.is-current .admin-user-dropdown-label { font-weight: 600; }
.admin-user-dropdown-item.is-current .admin-user-dropdown-badge {
    background: transparent;
    color: var(--mf-link, #1a73e8);
    font-size: 13px;
    padding: 0 4px;
    border-radius: 0;
    min-width: 0;
}

/* Main-menu widget (between brand and nav) container styles already defined above */

/* --admin-main-px exposes the active horizontal padding to descendants so
   plugin pages that want to "bleed to page edges" (mf-ai chat root, mf-chat
   inbox list, …) can use `margin-inline: calc(-1 * var(--admin-main-px))`
   instead of hard-coding -24px, which used to overshoot on pad/phone
   where the padding is 12px / 8px and produced right-edge overflow. */
/* ── Side-nav sidebar (WordPress-style, always visible) ──────────────────── */
.mf-sidenav {
    position: fixed;
    top: 91px; /* header (56px + 1px border) + full-width breadcrumb bar (34px, #661) */
    left: 0;
    width: 190px;
    /* Ends above the always-on full-width footer (34px) so the footer spans
       edge-to-edge and the sidebar never overlaps it (order #588); starts
       below the full-width breadcrumb bar (34px) for the same reason (#661). */
    height: calc(var(--app-height, 100vh) - 91px - 34px);
    transition: width 0.12s ease;
    background: var(--mf-chrome-bg);
    border-right: 1px solid var(--mf-chrome-border);
    overflow-y: auto;
    overflow-x: hidden;
    z-index: 90;
    display: flex;
    flex-direction: column;
    overscroll-behavior: contain;
}
.mf-sidenav-body { flex: 1; padding: 12px 0 16px; overflow-y: auto; overflow-x: hidden; }
.mf-sidenav-item {
    display: flex;
    align-items: center;
    gap: 0;
    padding: 0 8px 0 0;
    color: var(--mf-chrome-fg);
    text-decoration: none;
    font-size: 14px;
    font-weight: 400;
    min-height: 34px;
    transition: box-shadow 0.1s linear, color 0.1s ease-in-out, background 0.1s;
    white-space: nowrap;
    overflow: hidden;
}
/* Icon: fixed 36px wide, flush left — matches WP's wp-menu-image area */
.mf-sidenav-icon {
    flex-shrink: 0;
    width: 36px;
    align-self: stretch;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    line-height: 1;
    opacity: 0.6;
    transition: opacity 0.1s;
}
.mf-sidenav-item:hover { box-shadow: inset 4px 0 0 0 var(--mf-chrome-accent); color: var(--mf-chrome-accent); text-decoration: none; }
.mf-sidenav-item:hover .mf-sidenav-icon { opacity: 1; }
/* #674: the active panel no longer paints a filled highlight bar — under many
   skins the active bg/fg pair was unreadable, and flagging the page you are
   already on serves no purpose. Keep only the brighter icon, matching the
   sub-item treatment below. */
.mf-sidenav-item.is-active { background: transparent; color: var(--mf-chrome-fg); }
.mf-sidenav-item.is-active .mf-sidenav-icon { opacity: 1; }
.mf-sidenav-label { flex: 1; overflow: hidden; text-overflow: ellipsis; padding: 8px 0; }
.mf-sidenav-badge {
    flex-shrink: 0; background: var(--mf-danger); color: var(--mf-on-accent);
    font-size: 10px; font-weight: 700; padding: 1px 6px;
    border-radius: 9px; min-width: 18px; text-align: center; line-height: 1.5;
    margin-right: 4px;
}
.mf-sidenav-sep { border: none; height: 5px; margin: 0 0 6px; }
.mf-sidenav-foot { padding: 8px 14px; font-size: 11px; color: var(--mf-chrome-fg-muted); border-top: 1px solid var(--mf-chrome-border); flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; }
/* Sub-items — icon in same 36px column, smaller text, muted colour */
.mf-sidenav-sub { font-size: 13px; color: var(--mf-chrome-fg-muted); min-height: 0; }
.mf-sidenav-sub .mf-sidenav-icon { font-size: 13px; opacity: 0.5; }
.mf-sidenav-sub .mf-sidenav-label { padding: 5px 0; }
.mf-sidenav-sub:hover { color: var(--mf-chrome-accent); }
.mf-sidenav-sub:hover .mf-sidenav-icon { opacity: 1; }
.mf-sidenav-sub.is-active { background: transparent; color: var(--mf-chrome-fg); }
.mf-sidenav-sub.is-active .mf-sidenav-icon { opacity: 0.8; }

/* Panel groups — always expanded; flyout appears on individual items that have sub-pages */
.mf-sidenav-ph { display: flex; align-items: stretch; }
.mf-sidenav-ph > .mf-sidenav-item { flex: 1; min-width: 0; }
/* Publisher Panel heading shown to Editors (Articles/Media only) who cannot
   open the panel itself — a non-clickable group label, no hover affordance. */
.mf-sidenav-ph-label { cursor: default; }
.mf-sidenav-ph-label:hover { box-shadow: none; color: var(--mf-chrome-fg); }
.mf-sidenav-ph-label:hover .mf-sidenav-icon { opacity: 0.6; }
.mf-sn-toggle { display: none; }
.mf-sng-body { display: block; }
/* Flyout popup — appended to <body> by JS; positioned via JS */
.mf-sng-flyout-popup {
    position: fixed;
    left: 190px;
    min-width: 200px;
    background: var(--mf-chrome-elev);
    border: 1px solid var(--mf-chrome-border);
    padding: 6px 0;
    box-shadow: var(--mf-shadow-strong, 0 3px 5px rgba(0,0,0,0.2));
    z-index: 9999;
    display: none;
}
.mf-sng-flyout-popup.is-visible { display: block; }
.mf-sng-flyout-head {
    background: var(--mf-chrome-bg);
    font-size: 13px;
    font-weight: 600;
    color: var(--mf-chrome-fg);
    padding: 5px 12px;
    display: block;
    white-space: nowrap;
    margin-bottom: 4px;
}
.mf-sng-flyout-popup .mf-sidenav-item {
    white-space: nowrap;
    overflow: visible;
    color: var(--mf-chrome-fg);
}
.mf-sng-flyout-popup .mf-sidenav-item:hover {
    box-shadow: inset 4px 0 0 0 var(--mf-chrome-accent);
    color: var(--mf-chrome-accent);
}

/* Push content right of the sidebar. The footer is fixed full-width
   (order #588), so it is NEVER indented for the sidebar. */
body.has-quicknav .admin-main { margin-left: 190px; }
/* Collapsed sidebar = icon-only rail (order #589): content shifts to the
   narrow rail width instead of the full 190px. */
body.has-quicknav.nav-rail .admin-main { margin-left: 48px; }

/* Sidebar hide toggle — desktop only */
.mf-sidenav-toggle-btn {
    background: none; border: none; cursor: pointer;
    color: var(--mf-chrome-fg-muted); padding: 4px 6px;
    font-size: 15px; line-height: 1; flex-shrink: 0;
    transition: color 0.1s;
}
.mf-sidenav-toggle-btn:hover { color: var(--mf-chrome-fg); }
.mf-sidenav-show-tab {
    display: none; position: fixed; top: 114px; left: 0; z-index: 91;
    background: var(--mf-chrome-bg); border: 1px solid var(--mf-chrome-border);
    border-left: none; border-radius: 0 4px 4px 0;
    color: var(--mf-chrome-fg-muted); padding: 10px 5px;
    cursor: pointer; font-size: 15px; line-height: 1;
    transition: color 0.1s, background 0.1s;
}
.mf-sidenav-show-tab:hover { color: var(--mf-chrome-accent); background: var(--mf-chrome-elev); }
/* Collapsed sidebar = icon-only rail, not hidden (order #589). Desktop only. */
@media (min-width: 901px) {
    body.nav-rail .mf-sidenav { width: 48px; }
    body.nav-rail .mf-sidenav-label,
    body.nav-rail .mf-sidenav-badge,
    body.nav-rail .mf-sidenav-sub,
    body.nav-rail .mf-sng-flyout-head,
    body.nav-rail .mf-sidenav-foot span { display: none; }
    body.nav-rail .mf-sidenav-icon { width: 48px; }
    body.nav-rail .mf-sidenav-item { padding-right: 0; }
    body.nav-rail .mf-sidenav-foot { justify-content: center; padding: 8px 0; }
}
/* On pad — hide sidebar entirely at ≤900px */
@media (max-width: 900px) {
    .mf-sidenav { display: none; }
    .mf-sng-flyout-popup { display: none !important; }
    body.has-quicknav .admin-main { margin-left: 0; }
}

/* On phone — hide sidebar entirely */
@media (max-width: 600px) {
    .mf-sidenav { display: none; }
    .mf-sng-flyout-popup { display: none !important; }
    body.has-quicknav .admin-main { margin-left: 0; }
}

.admin-main { --admin-main-px: 24px; max-width: 1400px; margin: 0 auto; padding: 50px 24px 48px; min-height: calc(var(--app-height, 100vh) - 56px - 60px - 34px); }
/* Widen to the side on desktop, site-wide (#822). The 1400px cap above kept
   every admin surface pinned to a centred column on a wide browser — content
   "didn't move to the side when the browser widened". Lifting the cap on
   desktop is the single source of truth; the side padding stays so content
   never slams the viewport edge. Pad/phone (and ≤900px) keep their own rules
   above/below. Individual apps that need full-height/full-bleed layout
   (Calendar, Mail) still add their own flex rules — this only removes the cap. */
html.mf-desktop .admin-main { max-width: none; }
/* Footer: one full-width bar, fixed to the bottom on EVERY page. Never
   indented by the sidebar, never moves, always the same height (#582/#588).
   Themed via --mf-* tokens so it follows the site skin. Height comes from
   site-themes.css (34px). */
.admin-footer {
    position: fixed; left: 0; right: 0; bottom: 0; width: 100%;
    box-sizing: border-box; z-index: 95; margin: 0; max-width: none;
    border-top: 1px solid var(--mf-border, #e0e0e0);
    background: var(--mf-surface, #fff); color: var(--mf-text-faint, #888);
    font-size: 12px; padding: 6px 16px;
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
}

/* Order #773: app status messages surface in the MIDDLE of the footer,
   site-wide. An absolutely-centred overlay keeps the message dead-centre
   regardless of the left/right chrome widths; it covers the copyright line
   while shown, then fades back to it. Coloured by type, single line with
   ellipsis (full text in the title). */
.admin-footer-status {
    position: absolute; left: 50%; top: 0; bottom: 0;
    transform: translateX(-50%);
    display: none; align-items: center; gap: 6px;
    max-width: min(70%, 720px); padding: 0 14px;
    font-size: 12px; line-height: 1; white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis;
    border-radius: 6px; cursor: default;
    background: var(--mf-surface, #fff);
    transition: opacity .35s ease;
}
.admin-footer-status.is-show { display: inline-flex; }
.admin-footer-status.is-fade { opacity: 0; }
.admin-footer-status .admin-footer-status-msg {
    overflow: hidden; text-overflow: ellipsis;
}
.admin-footer-status::before {
    content: ""; flex: 0 0 auto;
    width: 7px; height: 7px; border-radius: 50%;
    background: currentColor;
}
.admin-footer-status--success { color: var(--mf-success-text, #1a7f37); }
.admin-footer-status--error   { color: var(--mf-danger-text, #c0392b); }
.admin-footer-status--warning { color: var(--mf-warning-text, #b45309); }
.admin-footer-status--info    { color: var(--mf-info-text, #0b6bcb); }

/* Breadcrumb: a full-width bar pinned just below the header, mirroring the
   full-width footer (#661). position:fixed + left/right:0 makes it span
   edge-to-edge regardless of the sidebar offset — exactly like .admin-footer.
   The sidebar (top:91px) starts below it and .admin-main carries a matching
   padding-top so page content clears it. Height matches the footer (34px). */
.breadcrumbs {
    position: fixed; top: 57px; left: 0; right: 0; z-index: 96;
    box-sizing: border-box; height: 34px; margin: 0;
    padding: 4px 16px;
    background: var(--mf-surface, #fff);
    border-bottom: 1px solid var(--mf-border, #e0e0e0);
    font-size: 13px; color: var(--mf-text-faint, #888);
    display: flex; flex-wrap: nowrap; align-items: center;
    gap: 8px 14px; justify-content: space-between;
    overflow: hidden;
}
.breadcrumbs .breadcrumb-trail { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.breadcrumbs .sep { margin: 0 8px; color: var(--mf-border); }
.breadcrumbs a { color: var(--mf-text-muted); }
.breadcrumbs .current { color: var(--mf-text); font-weight: 500; }
.breadcrumb-roles { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.breadcrumb-roles .visibility-pill {
    margin: 0; padding: 1px 8px; font-size: 11px; font-weight: 600;
    line-height: 1.5; letter-spacing: 0.01em;
}

/* Device-bucket indicator on the breadcrumb row.
 * Janus 2026-05-17: visual proof of which html.mf-* bucket the layout
 * picked — so a wrong classification (e.g. iPad reading as phone)
 * shows up where you'd already be looking. Mono so it reads as a
 * diagnostic readout, not a control. */
.breadcrumb-back {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; flex-shrink: 0;
    font-size: 14px; line-height: 1; color: var(--mf-text-faint); text-decoration: none;
    border: 1px solid var(--mf-border); border-radius: 3px;
    transition: color 0.1s, border-color 0.1s;
}
.breadcrumb-back:hover { color: var(--mf-text); border-color: var(--mf-text-muted); }
:root[data-theme="dark"] .breadcrumb-back { color: var(--mf-text-muted); border-color: var(--mf-border); }
:root[data-theme="dark"] .breadcrumb-back:hover { color: var(--mf-text); border-color: var(--mf-text-muted); }

.breadcrumb-device {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 11px;
    color: var(--mf-text-faint);
    white-space: nowrap;
    padding: 1px 6px;
    border: 1px solid var(--mf-border);
    border-radius: 3px;
    line-height: 1.5;
    letter-spacing: 0.02em;
}

/* Code-in-progress / DEFCON indicator on the breadcrumb row.
 * Only present when a build lock is held (PHP guards visibility).
 * Janus 2026-05-16 LAW: same line as the breadcrumbs, colour-coded
 * by current DEFCON level. Lean: text only, no chrome. */
.breadcrumb-defcon { font-size: 12px; font-weight: 600; white-space: nowrap; }
.breadcrumb-defcon a { color: inherit; text-decoration: none; }
.breadcrumb-defcon a:hover { text-decoration: underline; }
.breadcrumb-defcon--1 {
    animation: mf-defcon-pulse 1.2s infinite alternate;
}
@keyframes mf-defcon-pulse {
    from { opacity: 1;   }
    to   { opacity: 0.55; }
}

/* Card chrome — content beats padding. See lean-UI LAW. */
.card { background: var(--mf-surface, #fff); border: 1px solid var(--mf-border, #e0e0e0); border-radius: 8px; padding: 14px 18px; margin-bottom: 12px; }
.card h2 { margin: 0 0 10px; font-size: 15px; font-weight: 600; }
.card h3 { margin: 10px 0 6px; font-size: 13px; font-weight: 600; }

/* Page header — lean. The breadcrumb above already names where we are,
   so the H1 is a quiet subtitle, not a slab. See lean-UI LAW. */
.page-header { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 14px; flex-wrap: wrap; gap: 10px; }
.page-header h1 { margin: 0; font-size: 16px; font-weight: 600; color: var(--mf-text); letter-spacing: -0.005em; }
.page-actions { display: flex; gap: 6px; }

/* Visibility pill — single canonical badge for "who can see this page".
   Green = personal to the viewer; yellow shades = role-gated. */
.visibility-pill {
    display: inline-flex; align-items: center; gap: 6px;
    margin: 4px 0 14px; padding: 4px 10px;
    border-radius: 999px;
    font-size: 12px; font-weight: 500; line-height: 1.3;
}
.page-header + .visibility-pill { margin-top: -16px; }
.visibility-pill--you       { background: var(--mf-success-soft); color: var(--mf-success-text); border: 1px solid color-mix(in srgb, var(--mf-success) 35%, transparent); }
.visibility-pill--webmaster { background: var(--mf-warning-soft); color: var(--mf-warning-text); border: 1px solid color-mix(in srgb, var(--mf-warning) 35%, transparent); }
.visibility-pill--ceo       { background: var(--mf-warning-soft); color: var(--mf-warning-text); border: 1px solid color-mix(in srgb, var(--mf-warning) 35%, transparent); }
.visibility-pill--authors   { background: var(--mf-warning-soft); color: var(--mf-warning-text); border: 1px solid color-mix(in srgb, var(--mf-warning) 35%, transparent); }
.visibility-pill--sellers   { background: var(--mf-warning-soft); color: var(--mf-warning-text); border: 1px solid color-mix(in srgb, var(--mf-warning) 35%, transparent); }
.visibility-pill--worker    { background: var(--mf-success-soft); color: var(--mf-success-text); border: 1px solid color-mix(in srgb, var(--mf-success) 35%, transparent); }
.visibility-pill--neutral   { background: var(--mf-surface-alt);  color: var(--mf-text-muted);   border: 1px solid var(--mf-border); }

/* Form rows — tight. See lean-UI LAW. */
.form-row { margin-bottom: 12px; }
.form-row label { display: block; font-size: 12px; font-weight: 600; margin-bottom: 4px; color: var(--mf-text); }
.form-row input[type=text], .form-row input[type=email], .form-row input[type=password],
.form-row input[type=number], .form-row textarea, .form-row select, .form-row input[type=file] {
    width: 100%; padding: 6px 10px; border: 1px solid var(--mf-border, #d0d0d0); border-radius: 6px;
    font-size: 13px; font-family: inherit; background: var(--mf-input-bg, #fff); color: var(--mf-text, #1a1a1a);
}
.form-row input:focus, .form-row textarea:focus, .form-row select:focus {
    outline: none; border-color: var(--mf-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mf-primary) 18%, transparent);
}
.form-row .help { display: block; font-size: 12px; color: var(--mf-text-faint); margin-top: 4px; }
.form-row.inline { display: flex; gap: 12px; align-items: center; }
.form-row.inline label { margin-bottom: 0; }
.form-row.inline input[type=checkbox] { width: auto; }

/* Lean buttons — modeled on the mf-ai chat (build-btn / archive-btn) so the
   whole admin UI shares one compact button vocabulary. See lean-UI LAW. */
.btn { display: inline-block;
    padding: var(--mf-btn-pad-y, 4px) var(--mf-btn-pad-x, 12px);
    border: 1px solid transparent; border-radius: var(--mf-btn-radius, 6px);
    font-size: 13px; font-weight: var(--mf-btn-weight, 600); line-height: 1.5; font-family: inherit;
    cursor: pointer; text-decoration: none; transition: background 0.15s; }
.btn:hover { text-decoration: none; }
.btn:disabled, .btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.btn-primary { background: var(--mf-primary); color: var(--mf-on-primary); }
.btn-primary:hover:not(:disabled) { background: var(--mf-primary-hover); color: var(--mf-on-primary); }
.btn-secondary { background: var(--mf-surface, #fff); color: var(--mf-text, #1a1a1a); border-color: var(--mf-border, #d0d0d0); }
.btn-secondary:hover:not(:disabled) { background: var(--mf-surface-alt, #f5f5f5); color: var(--mf-text, #1a1a1a); }
.btn-danger { background: var(--mf-danger); color: var(--mf-on-accent); }
.btn-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--mf-danger) 86%, #000); color: var(--mf-on-accent); }

.flash { padding: 7px 12px; border-radius: 6px; margin-bottom: 12px; font-size: 13px; }
.flash-success { background: var(--mf-success-soft); color: var(--mf-success-text); border: 1px solid color-mix(in srgb, var(--mf-success) 35%, transparent); }
.flash-error { background: var(--mf-danger-soft); color: var(--mf-danger-text); border: 1px solid color-mix(in srgb, var(--mf-danger) 35%, transparent); }
.flash-info { background: var(--mf-info-soft); color: var(--mf-info-text); border: 1px solid color-mix(in srgb, var(--mf-primary) 35%, transparent); }
.flash-warning { background: var(--mf-warning-soft); color: var(--mf-warning-text); border: 1px solid color-mix(in srgb, var(--mf-warning) 35%, transparent); }

/* Tables — tight rows. See lean-UI LAW. */
.table { width: 100%; border-collapse: collapse; background: var(--mf-surface, #fff); border: 1px solid var(--mf-border, #e0e0e0); border-radius: 8px; overflow: hidden; font-size: 13px; }
.table th, .table td { padding: 7px 12px; text-align: left; border-bottom: 1px solid var(--mf-border-light, #f0f0f0); }
.table th { background: var(--mf-surface-alt, #fafafa); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--mf-text-muted, #666); }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--mf-surface-alt, #fafafa); }

.pill { display: inline-block; padding: 3px 10px; border-radius: 12px; font-size: 12px; font-weight: 500; }
.pill-success { background: var(--mf-success-soft); color: var(--mf-success-text); }
.pill-warning { background: var(--mf-warning-soft); color: var(--mf-warning-text); }
.pill-error { background: var(--mf-danger-soft); color: var(--mf-danger-text); }
.pill-info { background: var(--mf-info-soft); color: var(--mf-info-text); }
.pill-neutral { background: var(--mf-surface-alt); color: var(--mf-text-muted); }

.login-shell { min-height: var(--app-height, 100vh); display: flex; align-items: center; justify-content: center; background: var(--mf-bg); padding: 24px; }
.login-card { background: var(--mf-surface, #fff); padding: 40px; border-radius: 12px; border: 1px solid var(--mf-border, #e0e0e0); width: 100%; max-width: 420px; box-shadow: 0 4px 24px rgba(0,0,0,0.04); }
.login-card .login-logo { display: block; margin: 0 auto 16px; max-height: 60px; max-width: 200px; }
.login-card h1 { margin: 0 0 8px; font-size: 22px; font-weight: 600; text-align: center; }
.login-card .subtitle { text-align: center; color: var(--mf-text-faint); font-size: 14px; margin: 0 0 32px; }

.installer-shell { max-width: 760px; margin: 60px auto; padding: 0 24px; }
.installer-card { background: var(--mf-surface, #fff); border: 1px solid var(--mf-border, #e0e0e0); border-radius: 12px; padding: 40px; }
.installer-card h1 { margin: 0 0 8px; font-size: 26px; font-weight: 600; letter-spacing: -0.01em; }
.installer-card .step-label { color: var(--mf-text-faint); font-size: 13px; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 4px; }
.installer-progress { display: flex; gap: 8px; margin: 24px 0 32px; }
.installer-progress .step { flex: 1; height: 4px; background: var(--mf-border); border-radius: 2px; }
.installer-progress .step.active { background: var(--mf-primary); }
.installer-progress .step.done { background: var(--mf-success); }

.check-item { display: flex; align-items: flex-start; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--mf-border-light); }
.check-item:last-child { border-bottom: 0; }
.check-icon { flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: bold; color: var(--mf-on-accent); }
.check-icon.pass { background: var(--mf-success); }
.check-icon.fail { background: var(--mf-danger); }
.check-icon.warn { background: var(--mf-warning); }
.check-text { flex: 1; }
.check-name { font-weight: 500; }
.check-message { font-size: 13px; color: var(--mf-text-muted); }

.progress-log { background: var(--mf-surface-2); color: var(--mf-text); border: 1px solid var(--mf-border); padding: 16px; border-radius: 6px; font-family: "SF Mono", Menlo, monospace; font-size: 13px; max-height: 400px; overflow-y: auto; line-height: 1.6; }
.progress-log .log-line { display: block; }
.progress-log .log-line.error { color: var(--mf-danger-text); }
.progress-log .log-line.warn { color: var(--mf-warning-text); }
.progress-log .log-line.info { color: var(--mf-success-text); }
.progress-log .log-line.heading { color: var(--mf-text); font-weight: bold; margin-top: 8px; }

.error-shell { min-height: var(--app-height, 100vh); display: flex; align-items: center; justify-content: center; background: var(--mf-bg); padding: 24px; }
.error-card { background: var(--mf-surface, #fff); padding: 48px; border-radius: 12px; border: 1px solid var(--mf-border, #e0e0e0); max-width: 540px; width: 100%; text-align: center; box-shadow: 0 4px 24px rgba(0,0,0,0.04); }
.error-logo { max-height: 60px; max-width: 200px; margin-bottom: 24px; }
.error-code { font-size: 64px; font-weight: 700; color: var(--mf-danger); line-height: 1; margin-bottom: 8px; }
.error-card h1 { margin: 0 0 16px; font-size: 24px; font-weight: 600; }
.error-message { color: var(--mf-text-muted); margin: 0 0 32px; }
.error-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.error-footer { color: var(--mf-text-faint); font-size: 12px; margin-top: 32px; }

.plugin-card { background: var(--mf-surface, #fff); border: 1px solid var(--mf-border, #e0e0e0); border-radius: 8px; padding: 20px; margin-bottom: 12px; display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; }
.plugin-card-info { flex: 1; min-width: 250px; }
.plugin-card-info h3 { margin: 0 0 4px; font-size: 16px; }
.plugin-card-info .plugin-meta { font-size: 13px; color: var(--mf-text-muted); }
.plugin-card-actions { display: flex; gap: 8px; flex-wrap: wrap; }

.logo-preview { background: var(--mf-surface-alt); border: 1px solid var(--mf-border); border-radius: 8px; padding: 16px; text-align: center; min-height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 8px; }
.logo-preview img { max-width: 100%; max-height: 80px; }
.logo-preview .empty { color: var(--mf-text-faint); font-size: 13px; }

.kv-list { width: 100%; }
.kv-list dt { font-weight: 600; color: var(--mf-text-muted); font-size: 13px; margin-top: 8px; }
.kv-list dd { margin: 0 0 8px; color: var(--mf-text); font-family: "SF Mono", Menlo, monospace; font-size: 13px; }

.danger-zone { border: 2px solid var(--mf-danger); border-radius: 8px; padding: 20px; background: var(--mf-danger-soft); }
.danger-zone h3 { margin-top: 0; color: var(--mf-danger); }

/* ========================================================================
   Mobile / responsive admin layout
   ========================================================================
   Breakpoints:
   - >=900px: full desktop, all elements visible inline
   - 600-899: pad, main-menu widgets condensed, name + caret hidden on
              the user trigger so just the avatar shows
   - <600px:  phone, brand text hidden (logo only), tighter spacing, four
              widget essentials inline + ⋯ overflow popover for the rest
   ======================================================================== */

/* === Tablet: <= 900px =================================================== */
@media (max-width: 900px) {
    .admin-main-menu-inner {
        padding: 0 12px;
        /* 20px not 10px — the logo carries a black-padded box (4px top/
           bottom, 6px left/right), so at the previous 10px gap its
           visible right edge sat ~4px from the bulb's emoji, reading
           as 'squashed together'. 20px puts a clear ~20px visible
           gap between the logo and the first left-zone widget on
           every pad width. */
        gap: 20px;
    }

    /* Weather is dropped from the mobile + pad main menu entirely. It's a
       status indicator whose verbose title ("Copenhagen, DK - 11°.
       Humidity 65%. Wind 3.2. Updated …") chewed every horizontal pixel
       it touched. Desktop keeps it. Other left-zone widgets (mf-ai's 💡
       bulb, etc.) stay visible. */
    .admin-main-menu-widgets-left > [data-widget="weather"] { display: none; }

    /* Tighter spacing in the main-menu widget cluster so the full set of
       icons fits at pad widths without crowding the brand or the
       user menu. */
    .admin-main-menu-widgets { gap: 10px; padding: 0 2px; }
    .admin-main-menu-widgets-left { gap: 10px; padding: 0 2px; }
    .admin-main-menu-widget { font-size: 14px; }

    /* Bullet-proof readability for the tools/system dropdown panels on
       phones. Desktop sizing (13px items, 10px section titles, 7px
       padding) is unreadable on a touch device — bump everything so
       fingers can hit and eyes can parse. Wider panel, bigger icons,
       bigger labels, taller rows. Lives only inside <=900px so desktop
       keeps its denser layout. */
    .mf-sysmenu-panel {
        width: min(360px, calc(100vw - 32px));
        max-height: 70vh;
    }
    .mf-sysmenu-section-title {
        font-size: 12px;
        letter-spacing: 0.4px;
        padding: 10px 16px 4px;
    }
    .mf-sysmenu-item {
        padding: 12px 16px;
        gap: 12px;
    }
    .mf-sysmenu-item-label { font-size: 16px; }
    .mf-sysmenu-item-icon  { width: 26px; font-size: 18px; }
    .mf-sysmenu-overview {
        padding: 12px 16px;
        font-size: 16px;
        gap: 12px;
    }

    /* Hide the descriptive 'MediaForce' text next to the logo. Logo alone
       is enough for branding once you're inside the admin. */
    .admin-brand span { display: none; }

    /* User menu trigger compressed to just the avatar; name + caret hide
       so the rightmost element is a single 28px circle. The full name +
       email still show inside the open dropdown header. */
    .admin-user-menu summary { padding: 4px 6px; }
    .admin-user-name { display: none; }
    .admin-user-summary .admin-user-caret { display: none; }
    /* User dropdown stays anchored to its trigger — the .admin-user-menu
       summary sits at the far right of .admin-main-menu-widgets, so
       right: 0 of the trigger lines up with the viewport's right edge
       and content (~220–260px wide) flows leftward inside the viewport
       without needing a full-width promotion. */
    .admin-user-dropdown { right: 8px; min-width: 220px; max-width: calc(100vw - 16px); }
    /* Left-zone shield: still open rightward on tablet. */
    .admin-main-menu-widgets-left .admin-user-dropdown { right: auto; left: 0; }

    /* Tablet portrait fix: 🔔 bell and 🛠 system are anchored to their
       <details> trigger via `position: absolute; right: 0` in the desktop
       rule. On pad portrait (768px iPad) the trigger sits mid-row
       inside .admin-main-menu-widgets — anchoring right: 0 to a mid-row
       trigger pushes the panel off the left edge of the viewport. Same
       pattern the phone (<=600px) block uses below; extending it up to
       <=900px catches the pad gap. .admin-user-dropdown is NOT in this
       list — its trigger is the rightmost summary in the menu so
       right: 0 already lines up with the viewport edge.

       <=600px overrides these with top: 60px (52px menu + 8px gap) since
       the menu is shorter on phones — both blocks coexist via the
       source-order cascade (this one first, phone block later). */
    .mf-bell-panel,
    .mf-sysmenu-panel {
        position: fixed;
        top: 64px;
        /* 4px gutters (not 8px) — on a phone in landscape or a phablet
           reporting 700-900px CSS pixels, every extra px of panel width
           is one less wrapped headline in the notification list. */
        left: 4px;
        right: 4px;
        bottom: auto;
        width: auto;
        min-width: 0;
        max-width: none;
        max-height: calc(var(--app-height, 100dvh) - 76px);
        overflow-y: auto;
        overscroll-behavior: contain;
    }
    body.mf-has-status-bar .mf-bell-panel,
    body.mf-has-status-bar .mf-sysmenu-panel {
        top: 100px;
        max-height: calc(var(--app-height, 100dvh) - 112px);
    }

    /* Main content padding */
    .admin-main { --admin-main-px: 12px; padding: 50px var(--admin-main-px) 16px; max-width: 100%; }
    /* Pad keeps the base top:57px (header is still 57px at ≤900px) — just
       tighten the bar's horizontal padding/font. Pills still fit one line. */
    .breadcrumbs { padding: 4px 8px; font-size: 12px; }

    /* Cards + page-header reflow */
    .page-header {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
    }
    .page-actions {
        width: 100%;
        flex-wrap: wrap;
        gap: 6px;
    }
    .page-actions .btn { font-size: 13px; padding: 6px 10px; }

    /* Footer stays one fixed-height row on every device (#582/#588). On
       narrow screens drop the copyright + trim the version, but keep the
       theme picker and the same height. */
    .admin-footer { gap: 8px; padding: 6px 12px; }
    .admin-footer > span:nth-child(2) { display: none; }
    .admin-footer > span:nth-child(3) { overflow: hidden; text-overflow: ellipsis; }
}

/* === Phone: <= 600px ==================================================== */
@media (max-width: 600px) {
    .admin-main-menu-inner {
        height: 52px;
        padding: 0 8px;
        gap: 8px;
    }
    /* The brand carries a black-padded box (~6px on each side) around the
       logo image, so an 8px row gap leaves only a ~2px visible strip
       between the box's right edge and the next widget — reads as
       "smushed". Adding 6px on the brand specifically gives the logo
       breathing room without widening the gap between every other widget
       icon in the row. Same fix the <=900px pad block makes with
       gap: 20px, scoped down to "brand only" for the tighter phone row. */
    .admin-brand { margin-right: 6px; }
    .admin-brand-logo { height: 22px; }

    /* Status bar adapts on phone — keep the +28px it added over the base
       padding now that the base cleared the fixed breadcrumb bar (#661). */
    body.mf-has-status-bar .admin-main { padding-top: 78px; }

    /* Breadcrumbs collapse to just the current page on phone */
    .breadcrumbs ol { flex-wrap: wrap; }
    .breadcrumbs li:not(:last-child):not(:nth-last-child(2)) { display: none; }
    /* Phone header is 52px (.admin-main-menu-inner above), so the fixed
       full-width breadcrumb bar sits at top:52px (#661). The role-access +
       device diagnostic pills are hidden here — they wrap past the single-line
       bar and are desktop-oriented anyway; trail + back + DEFCON stay. */
    .breadcrumbs { top: 52px; padding: 4px 8px; }
    .breadcrumbs .breadcrumb-roles,
    .breadcrumbs .breadcrumb-device { display: none; }

    /* Tables in cards become horizontally scrollable rather than overflowing */
    .card table {
        display: block;
        overflow-x: auto;
        white-space: nowrap;
    }

    /* Narrower padding inside cards */
    .card { padding: 14px; }
    .page-header h1 { font-size: 22px; }

    /* Phone icons that don't fit are clipped horizontally; they remain
       accessible via the logo menu. overflow-x:clip (not overflow:hidden) so
       the vertical axis stays visible — hidden clips icon tops and badge dots
       that sit at top:-3px above the summary. Panels use position:fixed so
       overflow-x:clip here does not clip them either. */
    .admin-main-menu-more { display: none; }
    .admin-spacer { display: none; }
    .admin-main-menu-widgets { gap: 4px; overflow-x: clip; min-width: 0; flex-shrink: 1; }
    .admin-main-menu-widgets-left { gap: 4px; }
    /* Tighter icon padding so more icons fit on a narrow phone */
    details.mf-bell > summary.mf-bell-summary,
    details.mf-sysmenu > summary.mf-sysmenu-summary { padding: 0 2px; }
    /* Logo panel on phone: full-width below the logo, using the JS-measured variable */
    .mf-logo-panel.is-open {
        top: var(--mf-logo-bottom, 52px);
        left: 8px;
        right: 8px;
        width: auto;
    }
}

/* ========================================================================
   GLOBAL MOBILE OVERRIDES — high specificity, end of file.
   ======================================================================== */

@media (max-width: 768px) {
    /* STRUCTURAL GUARANTEE: every element inside the admin shell is
       capped at viewport width on small screens. This makes "code
       exceeds device size" impossible by construction — a plugin
       template that ships <div style="width: 800px"> still renders
       at 100vw on phone, because max-width: 100vw combines with the
       inline width (min(800px, 100vw) = 100vw). No !important needed:
       width and max-width are different properties; CSS picks the
       smaller of the two when both apply.

       Applies to .admin-main (the page body) and the main menu shell
       so plugin widgets in the topbar are also held to the viewport. */
    .admin-main,
    .admin-main *,
    .admin-main-menu,
    .admin-main-menu * {
        max-width: 100vw;
    }

    /* Anything containing "minmax(NNNpx, 1fr)" inline becomes single column.
       The selector matches the inline-style attribute literally — when an
       admin page does <div style="display: grid; grid-template-columns:
       repeat(auto-fit, minmax(280px, 1fr))">, this forces single-column. */
    [style*="minmax(280px"],
    [style*="minmax(320px"],
    [style*="minmax(240px"],
    [style*="minmax(220px"],
    [style*="minmax(200px"],
    [style*="minmax(180px"] {
        grid-template-columns: 1fr !important;
    }

    /* Two-column inline grids collapse to one column. */
    [style*="grid-template-columns: 2fr 1fr"],
    [style*="grid-template-columns: 1fr 2fr"],
    [style*="grid-template-columns: 1fr 1fr"],
    [style*="grid-template-columns: 220px 1fr"],
    [style*="grid-template-columns: 240px 1fr"],
    [style*="grid-template-columns: 280px 1fr"],
    [style*="grid-template-columns: 320px 1fr"] {
        grid-template-columns: 1fr !important;
    }

    /* Cards: shrink padding so they don't waste edge space */
    .card { padding: 14px !important; }

    /* Forms: full-width inputs, larger tap targets, prevent iOS auto-zoom */
    input[type="text"],
    input[type="email"],
    input[type="password"],
    input[type="number"],
    input[type="search"],
    input[type="url"],
    input[type="tel"],
    input[type="date"],
    input[type="time"],
    input[type="datetime-local"],
    input[type="file"],
    select,
    textarea {
        font-size: 16px !important;  /* iOS no-zoom */
        max-width: 100%;
        box-sizing: border-box;
    }
    .form-row input,
    .form-row select,
    .form-row textarea {
        width: 100% !important;
    }

    /* Tables: when too wide for the viewport, become horizontally
       scrollable instead of forcing the page wider. */
    .card table,
    .table {
        display: block;
        overflow-x: auto;
        white-space: nowrap;
        max-width: 100%;
    }

    /* Pre + code blocks scroll instead of overflow */
    pre, code {
        max-width: 100%;
        overflow-x: auto;
        word-break: break-word;
    }

    /* Buttons: 44px minimum tap target, can shrink horizontal padding */
    .btn,
    button {
        min-height: 40px;
    }
    .btn {
        font-size: 14px;
    }

    /* Page header reflow */
    .page-header {
        flex-direction: column;
        align-items: stretch !important;
        gap: 10px;
    }
    .page-header h1 {
        font-size: 22px;
        margin: 0;
    }
    .page-actions {
        display: flex;
        flex-wrap: wrap;
        gap: 6px;
    }
    .page-actions .btn,
    .page-actions a {
        font-size: 13px;
        padding: 6px 10px;
        min-height: 36px;
    }

    /* Settings panel two-column collapses on mobile */
    .settings-layout,
    .settings-grid {
        grid-template-columns: 1fr !important;
    }

    /* Branding logo previews go single-column */
    .logo-preview { padding: 12px; }

    /* Plugin cards: actions wrap below info instead of squeezed beside */
    .plugin-card { flex-direction: column; }
    .plugin-card-actions { width: 100%; }
}

@media (max-width: 480px) {
    .admin-main {
        --admin-main-px: 8px;
        /* Tighten only the sides and bottom on tiny phones. The TOP padding
           is load-bearing: it clears the fixed full-width breadcrumb bar
           (sticky header 52px + bar 34px = bottom at 86px), so it must stay
           on the breadcrumb-clearing value set above (50px base, 78px with
           the status bar). The old `padding: 12px !important` shorthand
           collapsed the top too, sliding the first card up to y:65 — under
           the "Control Panel" label, which made it unreadable (#942). */
        padding-right: var(--admin-main-px) !important;
        padding-left: var(--admin-main-px) !important;
        padding-bottom: 12px !important;
    }
    .card {
        padding: 12px !important;
        border-radius: 6px;
    }
    .page-header h1 {
        font-size: 20px;
    }

    /* Activity log / debug detail rows that often have long file paths */
    code {
        font-size: 11px;
        padding: 1px 4px;
    }

    /* Tighter status bar text on tiny screens */
    .mf-status-bar-summary {
        padding: 4px 8px;
        gap: 6px;
        font-size: 11px;
    }
    .mf-status-bar-actions a {
        padding: 1px 5px;
        margin-left: 2px;
    }
}

/* === Notification bell === */
details.mf-bell {
    position: relative;
}
details.mf-bell > summary.mf-bell-summary {
    cursor: pointer;
    list-style: none;
    padding: 0 6px;
    color: var(--mf-chrome-fg-muted);
    display: inline-flex;
    align-items: center;
    position: relative;
    user-select: none;
}
details.mf-bell > summary.mf-bell-summary::-webkit-details-marker { display: none; }
details.mf-bell > summary.mf-bell-summary::marker { display: none; }
.mf-bell-icon { font-size: 18px; line-height: 1; }
.mf-bell-badge {
    position: absolute;
    top: -3px; right: -3px;
    background: var(--mf-danger); color: var(--mf-on-accent);
    border-radius: 50%;
    min-width: 15px; height: 15px;
    font-size: 9px; font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    padding: 0 2px;
    box-shadow: 0 0 0 1.5px #2e2e2e;
    pointer-events: none;
}
.mf-bell-badge[hidden] { display: none; }

.mf-bell-panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    width: 340px;
    /* Safety net: even if a media-query breakpoint misfires (phone in a
       desktop-mode browser, or a viewport reported wider than the
       pad/phone breakpoints below), the panel must never exceed the
       viewport width — otherwise content runs off the right edge and is
       unreadable. 340px stays the design target; max-width clamps it to
       viewport-minus-gutters whenever the screen is narrower. */
    max-width: calc(100vw - 16px);
    /* max-height: design wants 500px, but on a short viewport (phone in
       landscape, pad portrait with browser chrome) 500px extends past
       the bottom of the screen and the panel is "halfway visible." min()
       caps it at design height OR available space below the 56px main
       menu (with a 16px breathing margin), whichever is smaller. The
       inner .mf-bell-list still scrolls inside the panel either way. */
    max-height: min(500px, calc(var(--app-height, 100dvh) - 72px));
    background: var(--mf-surface-2, #fff);
    color: var(--mf-text, #333);
    border: 1px solid var(--mf-border, #d0d0d0);
    border-radius: 6px;
    box-shadow: 0 6px 20px rgba(0,0,0,0.15);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.mf-bell-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 14px;
    border-bottom: 1px solid var(--mf-border-light, #eee);
    background: var(--mf-surface-alt, #fafafa);
}
.mf-bell-head strong { font-size: 13px; }
.mf-bell-mark-all {
    background: none;
    border: none;
    color: var(--mf-link, #1a73e8);
    font-size: 12px;
    cursor: pointer;
    padding: 2px 6px;
}
.mf-bell-mark-all:hover { text-decoration: underline; }

.mf-bell-list {
    overflow-y: auto;
    flex: 1;
}
.mf-bell-empty {
    padding: 30px 14px;
    text-align: center;
    color: var(--mf-text-faint, #888);
    font-size: 13px;
}

.mf-bell-item {
    display: flex;
    gap: 10px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--mf-border-light, #f0f0f0);
    text-decoration: none;
    color: inherit;
    transition: background 0.1s;
}
.mf-bell-item:hover { background: var(--mf-surface-alt, #f5f8fb); }
.mf-bell-item.is-read { opacity: 0.6; }
.mf-bell-item-icon {
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    background: var(--mf-surface-alt, #eef2f6);
    border-radius: 50%;
}
.mf-bell-item-text {
    flex: 1;
    min-width: 0;
}
.mf-bell-item-title {
    font-size: 13px;
    font-weight: 600;
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
}
.mf-bell-item-body {
    font-size: 12px;
    color: var(--mf-text-muted, #666);
    margin-top: 2px;
    line-height: 1.3;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.mf-bell-item-time {
    font-size: 11px;
    color: var(--mf-text-faint, #999);
    margin-top: 3px;
}

.mf-bell-item-row {
    display: flex;
    align-items: stretch;
    border-bottom: 1px solid var(--mf-border-light, #f0f0f0);
}
.mf-bell-item-row .mf-bell-item {
    border-bottom: none;
    flex: 1;
    min-width: 0;
}
.mf-bell-ai-btn {
    flex-shrink: 0;
    align-self: center;
    margin: 0 8px;
    font-size: 11px;
    padding: 2px 7px;
    border-radius: 3px;
    cursor: pointer;
    background: var(--mf-ai-accent-soft);
    color: var(--mf-ai-accent);
    border: 1px solid color-mix(in srgb, var(--mf-ai-accent) 40%, transparent);
    white-space: nowrap;
}
.mf-bell-ai-btn:hover { background: color-mix(in srgb, var(--mf-ai-accent) 20%, var(--mf-surface)); }
:root[data-theme="dark"] .mf-bell-item-row { border-bottom-color: var(--mf-border-light); }

.mf-bell-foot {
    border-top: 1px solid var(--mf-border-light, #eee);
    padding: 8px 14px;
    background: var(--mf-surface-alt, #fafafa);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* === Grouped bell list ===
   The bell dropdown groups notifications by source module (articles,
   calendar, mail, security…). Each group renders a sticky header with
   the module label, its unread count, and a per-group "Mark read"
   button so a noisy module can be muted without nuking everything else. */
.mf-bell-group {
    border-bottom: 1px solid var(--mf-border-light, #eee);
}
.mf-bell-group:last-child { border-bottom: none; }
.mf-bell-group-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 14px;
    background: var(--mf-surface-alt, #f3f5f8);
    border-bottom: 1px solid var(--mf-border-light, #eaeaea);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--mf-text-muted, #5a6470);
    letter-spacing: 0.04em;
    position: sticky;
    top: 0;
    z-index: 1;
}
.mf-bell-group-label { display: inline-flex; align-items: center; gap: 6px; }
.mf-bell-group-count {
    background: var(--mf-danger);
    color: var(--mf-on-accent);
    border-radius: 9px;
    padding: 0 6px;
    font-size: 10px;
    font-weight: 700;
    min-width: 16px;
    text-align: center;
    line-height: 1.5;
}
.mf-bell-group-count[hidden] { display: none; }
.mf-bell-group-clear {
    background: transparent;
    border: none;
    color: var(--mf-link, #1a73e8);
    font-size: 11px;
    cursor: pointer;
    padding: 2px 6px;
    text-transform: none;
    letter-spacing: 0;
}
.mf-bell-group-clear:hover { text-decoration: underline; }

:root[data-theme="dark"] .mf-bell-group-head {
    background: var(--mf-surface-alt);
    border-bottom-color: var(--mf-border);
    color: var(--mf-text-muted);
}
:root[data-theme="dark"] .mf-bell-group-clear { color: var(--mf-link); }
.mf-bell-view-all {
    font-size: 12px;
    color: var(--mf-link, #1a73e8);
    text-decoration: none;
}
.mf-bell-view-all:hover { text-decoration: underline; }
.mf-bell-prefs {
    color: var(--mf-text-faint, #888);
    text-decoration: none;
    font-size: 14px;
}
.mf-bell-prefs:hover { color: var(--mf-text, #333); }

/* === System menu dropdown ===
   Same shape as the notification bell — a <details> trigger in the main menu
   with an absolutely-positioned panel underneath. Used by the Webmaster-only
   System dropdown registered in _layout.php. */
details.mf-sysmenu { position: relative; }
details.mf-sysmenu > summary.mf-sysmenu-summary {
    cursor: pointer;
    list-style: none;
    padding: 0 6px;
    color: var(--mf-chrome-fg-muted);
    display: inline-flex;
    align-items: center;
    user-select: none;
}
details.mf-sysmenu > summary.mf-sysmenu-summary::-webkit-details-marker { display: none; }
details.mf-sysmenu > summary.mf-sysmenu-summary::marker { display: none; }
.mf-sysmenu-icon { font-size: 18px; line-height: 1; }
.mf-sysmenu-panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    width: 280px;
    max-height: calc(var(--app-height, 100vh) - 80px);
    overflow-y: auto;
    background: var(--mf-surface-2, #fff);
    color: var(--mf-text, #333);
    border: 1px solid var(--mf-border, #d0d0d0);
    border-radius: 6px;
    box-shadow: 0 6px 20px rgba(0,0,0,0.15);
    z-index: 1000;
    padding: 6px 0;
}
/* JS-driven logo menu (replaces the <details> approach) */
.mf-logo-menu { position: relative; }
.mf-logo-menu-btn {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
}
/* Panel anchored flush to the logo bottom — no gap means mouseleave on the
   wrapper div never fires in transit from button to panel. JS sets
   --mf-logo-bottom from getBoundingClientRect so it tracks scrolling and
   the status bar automatically. Phone block (<=600px) overrides left/right/width. */
@media (min-width: 601px) {
    .mf-logo-panel.is-open {
        position: fixed;
        top: var(--mf-logo-bottom, 56px);
        left: 0;
        right: auto;
    }
}
.mf-sysmenu-overview {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px;
    font-weight: 600;
    text-decoration: none;
    color: inherit;
    border-bottom: 1px solid var(--mf-border-light, #eee);
    margin-bottom: 4px;
}
.mf-sysmenu-overview:hover { background: var(--mf-surface-alt, #f5f8fb); color: inherit; text-decoration: none; }
.mf-sysmenu-section { padding: 4px 0; }
.mf-sysmenu-section + .mf-sysmenu-section { border-top: 1px solid var(--mf-border-light, #f0f0f0); }
.mf-sysmenu-section-title {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--mf-text-faint, #888);
    padding: 4px 14px 2px;
}
.mf-sysmenu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 14px;
    text-decoration: none;
    color: inherit;
    transition: background 0.1s;
}
.mf-sysmenu-item:hover { background: var(--mf-surface-alt, #f5f8fb); color: inherit; text-decoration: none; }
.mf-sysmenu-item-icon { width: 22px; text-align: center; font-size: 14px; flex-shrink: 0; }
.mf-sysmenu-item-label { font-size: 13px; }

/* === Impersonation banner === */
.mf-impersonation-bar {
    background: linear-gradient(90deg, #c0392b 0%, #e67e22 100%);
    color: #fff; /* theme-audit-allow: white on fixed danger-alert banner */
    padding: 10px 0;
    text-align: center;
    font-size: 13px;
    font-weight: 500;
    position: sticky;
    top: 0;
    z-index: 9999;
    box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
.mf-impersonation-bar-inner {
    max-width: 1400px;
    margin: 0 auto;
    padding: 0 16px;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    justify-content: center;
}
.mf-impersonation-icon { font-size: 16px; }
.mf-impersonation-text { flex: 1; text-align: left; }
.mf-impersonation-time {
    background: rgba(255,255,255,0.2); /* theme-audit-allow: translucent white pill on fixed danger banner */
    padding: 1px 8px;
    border-radius: 10px;
    font-size: 11px;
    margin-left: 6px;
}
.mf-impersonation-stop {
    background: #fff; /* theme-audit-allow: white button on fixed danger banner */
    color: #c0392b; /* theme-audit-allow: danger text on white button */
    border: 1px solid #fff; /* theme-audit-allow: white button on fixed danger banner */
    padding: 6px 14px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    flex-shrink: 0;
    transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.mf-impersonation-stop:hover {
    background: #fff; /* theme-audit-allow: white button on fixed danger banner */
    color: #c0392b; /* theme-audit-allow: danger text on white button */
    transform: translateY(-1px);
    box-shadow: 0 2px 6px rgba(0,0,0,0.3);
}
.mf-impersonation-stop:active {
    transform: translateY(0);
}



/* ========================================================================
   SITE-TYPE TILES — used by /control/sites/add.php (slice C of Add Site
   rewrite, 1.0.2.70). The pattern is generic enough that future "pick
   one of N flavors" choices can reuse it: a row of tile-shaped labels,
   each wrapping a hidden radio, with a selected/focus visual state.
   Four-layout LAW: tiles stack on phone, sit side-by-side from pad
   upward, gain a high-contrast focus ring for TV/D-pad.
   ======================================================================== */

.site-type-tiles {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    margin: 0;
}
.site-type-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 14px 16px;
    border: 1px solid var(--mf-border);
    border-radius: 8px;
    background: var(--mf-surface-alt);
    cursor: pointer;
    transition: border-color 120ms, background 120ms, box-shadow 120ms;
}
.site-type-tile:hover {
    border-color: var(--mf-primary);
    background: var(--mf-surface);
}
.site-type-tile input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.site-type-tile:has(input[type="radio"]:checked) {
    border-color: var(--mf-primary);
    background: var(--mf-surface);
    box-shadow: inset 0 0 0 2px var(--mf-primary);
}
.site-type-tile:has(input[type="radio"]:focus-visible) {
    outline: 3px solid var(--mf-primary-hover);
    outline-offset: 2px;
}
.site-type-tile-icon {
    font-size: 22px;
    line-height: 1;
}
.site-type-tile-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--mf-text);
}
.site-type-tile-desc {
    font-size: 12px;
    color: var(--mf-text-muted);
    line-height: 1.4;
}

/* Phone: stack the tiles, full-width. */
@media (max-width: 600px) {
    .site-type-tiles {
        grid-template-columns: 1fr;
        gap: 8px;
    }
    .site-type-tile {
        padding: 12px 14px;
    }
}

/* TV / 10-foot UI: bigger tile, fatter focus ring for D-pad clarity. */
@media (min-width: 1600px) and (pointer: coarse) {
    .site-type-tile {
        padding: 18px 22px;
        gap: 6px;
    }
    .site-type-tile-icon  { font-size: 28px; }
    .site-type-tile-title { font-size: 16px; }
    .site-type-tile-desc  { font-size: 14px; }
    .site-type-tile:has(input[type="radio"]:focus-visible) {
        outline-width: 4px;
        outline-offset: 3px;
    }
}

/* Disclosure for advanced credential override on Add Site. Lean spacing
   per LAW — summary is a one-liner, opens to compact fields below. */
.site-db-advanced > summary {
    cursor: pointer;
    font-size: 13px;
    color: var(--mf-text-muted);
    padding: 4px 0;
    user-select: none;
}
.site-db-advanced > summary:hover {
    color: var(--mf-link);
}
.site-db-advanced[open] > summary {
    color: var(--mf-text);
    font-weight: 600;
}


/* Touch devices in any orientation (covers landscape iPad at 1024px+
   which falls outside the max-width: 768px block above). */
@media (pointer: coarse) {
    input[type="datetime-local"] {
        font-size: 16px !important;  /* iOS no-zoom */
    }
}

/* ── Theme toggle button (topbar) ─────────────────────────────── */
.mf-theme-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px;
    border: 1px solid var(--mf-border, #d8d8d8);
    border-radius: 50%;
    background: transparent;
    color: var(--mf-text-2, #555);
    cursor: pointer;
    font-size: 14px; line-height: 1;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
    flex-shrink: 0;
}
.mf-theme-toggle:hover {
    background: var(--mf-surface-alt, #f0f0f2);
    border-color: var(--mf-border-strong, #b8b8b8);
    color: var(--mf-text, #111);
}
:root[data-theme="dark"] .mf-theme-toggle:hover {
    background: var(--mf-surface-alt, #1a1c20);
}

/* ── Nextcloud sync settings pages (mf-notes, mf-tasks) ───────────────
   Generic helpers layered on the standard .card / .form-row / .btn
   components so the sync pages match the rest of the admin UI and theme
   for light/dark via the --mf-* tokens. */
.mf-sync-page .mf-sync-lead {
    color: var(--mf-text-muted, #666); font-size: 13px; margin: 0 0 16px; max-width: 60ch;
}
.mf-sync-dl {
    display: grid; grid-template-columns: max-content 1fr; gap: 6px 16px;
    margin: 0 0 14px; font-size: 13px;
}
.mf-sync-dl dt { color: var(--mf-text-muted, #666); font-weight: 600; }
.mf-sync-dl dd { margin: 0; color: var(--mf-text, #1a1a1a); word-break: break-word; }
.mf-sync-dl dd.mf-sync-err { color: var(--mf-danger); }
.mf-sync-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.mf-sync-actions form { margin: 0; }
