/* ════════════════════════════════════════════════════════════════════════
   ApoTune Portal — Theme tokens
   ════════════════════════════════════════════════════════════════════════
   Theming follows Bootstrap 5.3 native data-bs-theme switching:
       <html data-bs-theme="light|dark|developer">    (set via JS interop in MainLayout)
       <html data-color-mode="light|dark">            (mirrored dark/light family)

   data-color-mode collapses every non-light theme into "dark" so component
   overrides target one selector instead of an :is() list. A future fourth
   "dark-style" theme just sets data-color-mode="dark" and inherits the whole
   block without touching it; theme-specific tweaks still go on data-bs-theme.

   Token layers:
       :root                            — universal (fonts, brand)
       :root[data-bs-theme="light"]     — light values  (also applied when attr is unset)
       :root[data-color-mode="dark"]    — dark values  (Dark + Developer)
       :root[data-bs-theme="developer"] — developer-only overrides on top

   Legacy custom var names (--bg-color / --text-color / --nav-bg / --card-bg /
   --border-color) are kept as aliases of the corresponding --bs-* tokens so
   MainLayout.razor.css and other consumers don't break. Future slices may
   retire them.
   ════════════════════════════════════════════════════════════════════════ */

:root {
    /* Brand / link tokens — bridged onto the ApoTune design system (--ds-*,
       defined in tokens.css). These reference theme-aware --ds vars, so they
       follow light/dark automatically. Interactive surfaces use the ACTION
       color (blue), never the brand lime — lime stays for identity/success. */
    --bs-primary-color: var(--ds-color-action-primary);
    --bs-primary-bg: var(--ds-color-action-selected-tint);
    --bs-component-active-color: var(--ds-color-action-on-primary);
    --bs-component-active-bg: var(--ds-color-action-primary);
    --bs-component-active-border-color: var(--ds-color-action-primary);
    --bs-link-color: var(--ds-color-text-link);
    --bs-link-hover-color: var(--ds-color-action-primary-hover);
    --bs-text-color: var(--ds-color-text-primary);
    --bs-text-muted-color: var(--ds-color-text-secondary);

    /* Font stacks — body uses Nunito (self-hosted); display roles map to
       Nunito Sans via the --ds-font-display token where used. */
    --bs-font-sans-serif: var(--ds-font-body);
    --bs-font-mono: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;

    /* Corner radius — bridged onto the brand scale (8px default vs Bootstrap's
       6px). Theme-independent, so it lives here with the font stacks. */
    --bs-border-radius: var(--ds-radius-md);
    --bs-border-radius-sm: var(--ds-radius-sm);
    --bs-border-radius-lg: var(--ds-radius-lg);
    --bs-border-radius-xl: var(--ds-radius-xl);
    --bs-border-radius-pill: var(--ds-radius-pill);

    /* Sidebar geometry — theme-independent, and in rem so the rail grows with the
       per-user text scale instead of clipping its own labels. 15rem/3.25rem are
       exactly the former 240px/52px at the Normal step; the reasoning for keeping
       type and geometry on the same unit is in NavMenu.razor.css's header.

       Note when measuring this: `.sidebar` carries `transition: width .22s`, so
       reading its width right after a scale change reports the OLD value —
       mid-transition, not final. Wait out the transition (or suppress it) before
       believing a number. */
    --sidebar-width: 15rem;
    --sb-collapsed: 3.25rem;
}

/* ── Light theme (also the default when data-bs-theme is unset) ──────────
   Values bridge onto --ds-* (tokens.css). Page background = canvas (#F0F0F0),
   so white cards/surfaces lift off it; ink text; blue action accents. */
:root,
:root[data-bs-theme="light"] {
    --bs-body-bg: var(--ds-color-surface-canvas);
    --bs-body-color: var(--ds-color-text-primary);
    --bs-border-color: var(--ds-color-border-strong);

    /* Semantic state colors — bridged onto the brand feedback tokens so every
       badge / alert / .text-* utility routes through the palette:
       success = lime, info = action blue, warning = amber, danger = error.
       The -rgb pairs feed Bootstrap's RGBA badge/alert fills (must match the
       hex of the token above). */
    --bs-success: var(--ds-color-feedback-success);
    --bs-success-rgb: 147, 236, 41;
    --bs-info: var(--ds-color-action-primary);
    --bs-info-rgb: 41, 121, 255;
    --bs-warning: var(--ds-color-feedback-warning);
    --bs-warning-rgb: 255, 196, 0;
    --bs-danger: var(--ds-color-feedback-error);
    --bs-danger-rgb: 255, 61, 0;

    /* Cards — mirrors the dark block further down. NB: Bootstrap 5.3
       redefines --bs-card-bg (and --bs-modal-bg / --bs-dropdown-bg /
       --bs-list-group-bg) *locally on the component element* to
       var(--bs-body-bg) — now the grey canvas. A :root value is shadowed by
       that element-level declaration and never wins for the surface
       background. The working light fix is the element-level
       `[data-color-mode="light"] …` block below; these are kept only for
       parity and for utilities that read the :root value directly. */
    --bs-card-bg: var(--ds-color-surface-base);
    --bs-card-border-color: var(--ds-color-border-strong);
    --bs-card-cap-bg: var(--ds-color-surface-base);
    --bs-card-color: var(--ds-color-text-primary);

    /* Legacy aliases */
    --bg-color: var(--ds-color-surface-canvas);
    --text-color: var(--ds-color-text-primary);
    --nav-bg: var(--ds-color-surface-field-search);
    --card-bg: var(--ds-color-surface-base);
    --border-color: var(--ds-color-border-strong);

    /* Focus ring (Bootstrap 5.3 reads this token natively) — action blue @ 50%. */
    --bs-focus-ring-color: color-mix(in srgb, var(--ds-color-action-primary) 50%, transparent);

    /* Sidebar tokens (consumed by NavMenu.razor.css) */
    --sidebar-bg: linear-gradient(180deg, var(--ds-color-surface-base) 0%, var(--ds-color-surface-field-search) 100%);
    --sidebar-fg: var(--ds-color-text-primary);
    --sidebar-brand-bg: rgba(255, 255, 255, 0.85);
    --sidebar-link-fg: var(--ds-color-text-primary);
    --sidebar-link-fg-hover: var(--ds-color-text-primary);
    --sidebar-link-fg-active: var(--ds-color-action-primary);
    --sidebar-hover-bg: var(--ds-color-action-selected-tint);
    --sidebar-active-bg: var(--ds-color-action-selected-indicator);
    --sidebar-active-border: var(--ds-color-action-selected-indicator);
    --sidebar-border: var(--ds-color-border-default);
    --sidebar-border-strong: var(--ds-color-border-strong);
    --sidebar-footer-btn-bg: rgba(255, 255, 255, 0.72);
    --sidebar-footer-btn-border: var(--ds-color-border-default);
    --sidebar-footer-btn-fg: var(--ds-color-text-primary);
    --sidebar-footer-btn-hover-bg: var(--ds-color-action-selected-tint);
    --sidebar-footer-btn-hover-border: var(--ds-color-action-primary);
    --sidebar-footer-btn-hover-fg: var(--ds-color-action-primary);
}

/* ── Dark theme ───────────────────────────────────────────────────────────
   Re-hued onto the ApoTune teal dark ramp (--ds-* dark set). The dark accent
   (--dm-accent), previously indigo, is now the action blue so every accent
   surface in dark mode reads on-brand. */
:root[data-color-mode="dark"] {
    /* Bootstrap variable overrides */
    --bs-body-bg: var(--ds-color-surface-canvas);
    --bs-body-color: var(--ds-color-text-primary);
    --bs-body-color-rgb: 234, 240, 242;
    --bs-border-color: var(--ds-color-border-strong);
    --bs-secondary-color: var(--ds-color-text-secondary);
    --bs-emphasis-color: var(--ds-color-text-primary);
    --bs-secondary-bg: var(--ds-color-surface-base);
    --bs-tertiary-bg: var(--ds-color-surface-raised);

    /* Semantic state colors — dark variants of the brand feedback tokens.
       -rgb pairs match the dark hex (success lime unchanged). */
    --bs-success: var(--ds-color-feedback-success);
    --bs-success-rgb: 147, 236, 41;
    --bs-info: var(--ds-color-action-primary);
    --bs-info-rgb: 91, 157, 255;
    --bs-warning: var(--ds-color-feedback-warning);
    --bs-warning-rgb: 255, 203, 46;
    --bs-danger: var(--ds-color-feedback-error);
    --bs-danger-rgb: 255, 107, 74;

    /* Cards */
    --bs-card-bg: var(--ds-color-surface-base);
    --bs-card-border-color: var(--ds-color-border-strong);
    --bs-card-cap-bg: var(--ds-color-surface-canvas);
    --bs-card-color: var(--ds-color-text-primary);

    /* Tables */
    --bs-table-color: var(--ds-color-text-primary);
    --bs-table-bg: var(--ds-color-surface-base);
    --bs-table-border-color: var(--ds-color-border-strong);
    --bs-table-striped-color: var(--ds-color-text-primary);
    --bs-table-striped-bg: var(--ds-color-surface-subtle);
    --bs-table-hover-color: var(--ds-color-text-primary);
    --bs-table-hover-bg: var(--ds-color-surface-raised);

    /* table-light thead */
    --bs-light-bg-subtle: var(--ds-color-surface-raised);
    --bs-light-border-subtle: var(--ds-color-border-strong);
    --bs-light-text-emphasis: var(--ds-color-text-primary);

    /* Dark-mode polish accents (formerly in a separate body.dark-mode block) */
    --dm-accent: var(--ds-color-action-primary);
    --dm-accent-soft: var(--ds-color-action-selected-tint);
    --dm-surface-elevated: var(--ds-color-surface-raised);
    --dm-surface-hover: var(--ds-color-surface-raised);

    /* Legacy aliases */
    --bg-color: var(--ds-color-surface-canvas);
    --text-color: var(--ds-color-text-primary);
    --nav-bg: var(--ds-color-surface-canvas);
    --card-bg: var(--ds-color-surface-base);
    --border-color: var(--ds-color-border-strong);

    /* Focus ring — action blue so keyboard focus stays visible on dark. */
    --bs-focus-ring-color: color-mix(in srgb, var(--ds-color-action-primary) 55%, transparent);

    /* Sidebar tokens — full background gradient + dark surface tints. */
    --sidebar-bg: linear-gradient(180deg, var(--ds-color-surface-canvas) 0%, var(--ds-color-surface-base) 100%);
    --sidebar-fg: var(--ds-color-text-primary);
    --sidebar-brand-bg: rgba(15, 23, 42, 0.45);
    --sidebar-link-fg: var(--ds-color-text-secondary);
    --sidebar-link-fg-hover: var(--ds-color-text-primary);
    --sidebar-link-fg-active: var(--ds-color-text-primary);
    --sidebar-hover-bg: var(--dm-surface-hover);
    --sidebar-active-bg: var(--dm-accent-soft);
    --sidebar-active-border: var(--ds-color-action-selected-indicator);
    --sidebar-border: var(--ds-color-border-strong);
    --sidebar-border-strong: var(--ds-color-border-strong);
    --sidebar-footer-btn-bg: rgba(15, 23, 42, 0.35);
    --sidebar-footer-btn-border: var(--ds-color-border-strong);
    --sidebar-footer-btn-fg: var(--ds-color-text-primary);
    --sidebar-footer-btn-hover-bg: var(--ds-color-surface-raised);
    --sidebar-footer-btn-hover-border: var(--ds-color-action-selected-indicator);
    --sidebar-footer-btn-hover-fg: var(--ds-color-text-primary);
}

/* ── Developer / Terminal theme (B-S11) ──────────────────────────────────
   Ayu-Dark-inspired palette: deep blue-black surfaces, amber accents, lime/
   cyan/coral semantic states. Body and chrome switch to monospace. Adding a
   new theme variant only needs another :root[data-bs-theme="..."] block —
   no rule outside this file moves. */
:root[data-bs-theme="developer"] {
    --bs-body-bg: #0a0e14;
    --bs-body-color: #b3b1ad;
    --bs-body-color-rgb: 179, 177, 173;
    --bs-emphasis-color: #cccac2;
    --bs-secondary-color: #5c6773;
    --bs-secondary-bg: #11151c;
    --bs-tertiary-bg: #131820;
    --bs-border-color: #1b2638;

    /* Drive everything through the monospace stack the body inherits. */
    --bs-body-font-family: var(--bs-font-mono);

    /* Square EVERYTHING for the IDE chrome. The brand's rounded scale (bridged
       in :root) is what softened the theme: cards/buttons/badges were each
       squared by their own rules, but every element that reads --bs-border-radius
       straight (form controls, .rounded panels like the /servers KPIs, alerts,
       dropdowns, list groups, nav-pills) kept 6px and clashed with the square
       cards. Zeroing the tokens squares them uniformly — one lever, whole theme.
       Pill stays round: it drives genuine pills/toggles, not box chrome. */
    --bs-border-radius: 0;
    --bs-border-radius-sm: 0;
    --bs-border-radius-lg: 0;
    --bs-border-radius-xl: 0;
    --bs-border-radius-pill: 50rem;

    /* Cards */
    --bs-card-bg: #0f131b;
    --bs-card-border-color: #1b2638;
    --bs-card-cap-bg: #11151c;
    --bs-card-color: #b3b1ad;

    /* Tables — phosphor-amber hover so rows feel like a terminal cursor row. */
    --bs-table-color: #b3b1ad;
    --bs-table-bg: #0f131b;
    --bs-table-border-color: #1b2638;
    --bs-table-striped-color: #b3b1ad;
    --bs-table-striped-bg: rgba(255, 180, 84, 0.05);
    --bs-table-hover-color: #ffd580;
    --bs-table-hover-bg: #1c2433;

    --bs-light-bg-subtle: #11151c;
    --bs-light-border-subtle: #1b2638;
    --bs-light-text-emphasis: #cccac2;

    /* Accent / dm-* — amber dominates so the active pill in the sidebar reads
       like a selected tab in a terminal multiplexer. */
    --dm-accent: #ffb454;
    --dm-accent-soft: rgba(255, 180, 84, 0.15);
    --dm-surface-elevated: #1a2030;
    --dm-surface-hover: #1c2433;

    /* Legacy aliases (still consumed by MainLayout.razor.css and a few pages) */
    --bg-color: #0a0e14;
    --text-color: #b3b1ad;
    --nav-bg: #11151c;
    --card-bg: #0f131b;
    --border-color: #1b2638;

    /* Sidebar tokens */
    --sidebar-bg: #050810;
    --sidebar-fg: #ffb454;
    --sidebar-brand-bg: rgba(255, 180, 84, 0.06);
    --sidebar-link-fg: #95a3b8;
    --sidebar-link-fg-hover: #ffd580;
    --sidebar-link-fg-active: #0a0e14;
    --sidebar-hover-bg: rgba(255, 180, 84, 0.10);
    --sidebar-active-bg: #ffb454;
    --sidebar-active-border: rgba(255, 213, 128, 0.35);
    --sidebar-border: #1b2638;
    --sidebar-border-strong: #1b2638;
    --sidebar-footer-btn-bg: rgba(255, 180, 84, 0.06);
    --sidebar-footer-btn-border: #2b3952;
    --sidebar-footer-btn-fg: #ffd580;
    --sidebar-footer-btn-hover-bg: rgba(255, 180, 84, 0.18);
    --sidebar-footer-btn-hover-border: rgba(255, 213, 128, 0.35);
    --sidebar-footer-btn-hover-fg: #fff3d6;

    /* Focus ring — amber to match the accent. */
    --bs-focus-ring-color: rgba(255, 180, 84, 0.55);
}

/* Apply the monospace family on body (Bootstrap reads --bs-body-font-family
   only via the `body { font-family: ... }` rule it ships; we re-assert it
   per theme so the font swap is reliable across browser caches). */
[data-bs-theme="developer"] body {
    font-family: var(--bs-font-mono);
}

/* ── Light theme: lift components off the grey canvas ──────────────────────
   Bootstrap 5.3 redefines --bs-card-bg / --bs-modal-bg / --bs-dropdown-bg /
   --bs-list-group-bg *locally on each component element* to var(--bs-body-bg)
   — now the grey #F0F0F0 canvas — so a :root override is shadowed and the
   surfaces render grey. Re-point the property on the element itself (higher
   specificity than Bootstrap's own .card declaration, so it wins). Scoped to
   data-color-mode="light", which only the true light theme carries — dark and
   developer collapse to data-color-mode="dark" and paint their surfaces via
   the explicit rules below, so they stay untouched. */
[data-color-mode="light"] .card { --bs-card-bg: var(--ds-color-surface-base); }
[data-color-mode="light"] .modal { --bs-modal-bg: var(--ds-color-surface-base); }
[data-color-mode="light"] .dropdown-menu { --bs-dropdown-bg: var(--ds-color-surface-base); }
[data-color-mode="light"] .list-group { --bs-list-group-bg: var(--ds-color-surface-base); }

/* ── Dark theme: Bootstrap component overrides ─────────────────────────── */

/* Cards */
[data-color-mode="dark"] .card {
    background-color: var(--card-bg);
    border-color: var(--border-color);
    color: var(--text-color);
}

[data-color-mode="dark"] .card-header {
    background-color: var(--nav-bg);
    border-color: var(--border-color);
    color: var(--text-color);
}

[data-color-mode="dark"] .card-body {
    color: var(--text-color);
}

/* Text utilities */
[data-color-mode="dark"] .text-body {
    color: var(--text-color) !important;
}

[data-color-mode="dark"] .text-dark {
    color: var(--text-color) !important;
}

/* Tables */
[data-color-mode="dark"] .table {
    --bs-table-color: var(--ds-color-text-primary);
    --bs-table-bg: var(--ds-color-surface-base);
    --bs-table-border-color: var(--ds-color-border-strong);
    --bs-table-hover-bg: #273449;
    --bs-table-hover-color: var(--ds-color-text-primary);
    color: var(--ds-color-text-primary);
}

[data-color-mode="dark"] .table-light {
    --bs-table-color: var(--ds-color-text-primary);
    --bs-table-bg: var(--ds-color-surface-raised);
    --bs-table-border-color: var(--ds-color-border-strong);
    color: var(--ds-color-text-primary);
}

/* ── Table group/separator rows (table-secondary) ────────── */
[data-color-mode="dark"] .table-secondary {
    --bs-table-color: var(--ds-color-text-secondary);
    --bs-table-bg: #22304a;
    --bs-table-border-color: var(--ds-color-border-strong);
    --bs-table-hover-color: var(--ds-color-text-primary);
    --bs-table-hover-bg: #253247;
}

[data-color-mode="dark"] .table-secondary td,
[data-color-mode="dark"] .table-secondary th {
    background-color: #22304a !important;
    color: var(--ds-color-text-primary) !important;
    border-color: var(--ds-color-border-strong) !important;
}

[data-color-mode="dark"] .table > :not(caption) > * {
    border-color: var(--ds-color-border-strong);
}

[data-color-mode="dark"] .table > :not(caption) > * > * {
    color: var(--ds-color-text-primary);
}

[data-color-mode="dark"] .text-muted {
    color: var(--ds-color-text-secondary) !important;
}

/* Better readability on hovered table rows (Users/Modules role+plugin editors) */
[data-color-mode="dark"] .table-hover > tbody > tr:hover > * {
    color: var(--ds-color-text-primary) !important;
    background-color: #1f2b3f !important;
}

[data-color-mode="dark"] .table-hover > tbody > tr.table-light:hover > * {
    color: var(--ds-color-text-primary) !important;
    background-color: #24324a !important;
}

[data-color-mode="dark"] .table-hover > tbody > tr:hover .text-muted {
    color: var(--ds-color-text-secondary) !important;
}

[data-color-mode="dark"] .table-hover > tbody > tr:hover .form-check-label {
    color: var(--ds-color-text-primary) !important;
}

[data-color-mode="dark"] .table-hover > tbody > tr:hover .form-check-label .text-muted {
    color: #c7d2fe !important;
}

[data-color-mode="dark"] .table-hover > tbody > tr:hover .form-check-input {
    border-color: var(--ds-color-action-primary);
}

/* Dark-mode badge readability in Users/Modules tables */
[data-color-mode="dark"] .table .badge.bg-info.text-dark,
[data-color-mode="dark"] .table .badge.bg-warning.text-dark {
    color: var(--ds-color-on-brand) !important;
}

[data-color-mode="dark"] .table .badge.bg-secondary {
    color: #ffffff !important;
}

/* ── Dark theme: form element overrides ────────────────────── */

/* Form inputs */
[data-color-mode="dark"] .form-control,
[data-color-mode="dark"] .form-select {
    background-color: var(--ds-color-surface-raised);
    color: var(--ds-color-text-primary);
    border-color: var(--ds-color-border-strong);
}

[data-color-mode="dark"] .form-control::placeholder {
    color: var(--ds-color-text-secondary);
}

[data-color-mode="dark"] .form-control:focus,
[data-color-mode="dark"] .form-select:focus {
    background-color: var(--ds-color-surface-raised);
    color: var(--ds-color-text-primary);
    border-color: var(--ds-color-action-primary);
    box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--ds-color-action-primary) 25%, transparent);
}

/* Dropdown menus */
[data-color-mode="dark"] .dropdown-menu {
    background-color: var(--card-bg);
    border-color: var(--border-color);
}

[data-color-mode="dark"] .dropdown-item {
    color: var(--text-color);
}

[data-color-mode="dark"] .dropdown-item:hover {
    background-color: #25324a;
    color: var(--ds-color-text-primary);
}

/* Alerts */
[data-color-mode="dark"] .alert-danger {
    background-color: #3d0f0f;
    border-color: #7a1515;
    color: #f5a0a0;
}

[data-color-mode="dark"] .alert-warning {
    background-color: #3d2e00;
    border-color: #7a5c00;
    color: #ffe08a;
}

/* ── Base ───────────────────────────────────────────────── */
h1:focus {
    outline: none;
}

/* Global :focus-visible policy. Bootstrap covers form-control / btn etc.
   natively; this catches custom interactive surfaces (sidebar links,
   dropdown items, clickable rows, custom buttons) that wouldn't otherwise
   show a focus ring. Both themes drive the colour from --bs-focus-ring-color
   defined under :root[data-bs-theme="..."]. */
:focus-visible {
    outline: 2px solid var(--bs-focus-ring-color, #0d6efd);
    outline-offset: 2px;
}

/* Don't paint the global ring on form-controls — Bootstrap's box-shadow
   focus-ring already handles those and a second ring looks busy. */
.form-control:focus-visible,
.form-select:focus-visible,
.form-check-input:focus-visible {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--ds-color-feedback-success);
}

.invalid {
    outline: 1px solid var(--ds-color-feedback-error);
}

.validation-message {
    color: var(--ds-color-feedback-error);
}

.blazor-error-boundary {
    background: linear-gradient(135deg, #b32121 0%, #8f1a1a 100%);
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
    position: relative;
}

.blazor-error-boundary::before {
    content: "⚠";
    position: absolute;
    left: 1.1rem;
    top: 50%;
    transform: translateY(-50%);
    font-size: 1.5rem;
    line-height: 1;
}

.blazor-error-boundary::after {
    content: "An error has occurred.";
}

.darker-border-checkbox.form-check-input {
    border-color: var(--ds-color-border-strong);
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

body {
    background-color: var(--bg-color);
    color: var(--text-color);
    transition: background-color 0.3s ease, color 0.3s ease;
}

/* ── Per-user text size (data-text-scale on <html>) ───────────────────────────
   One root font-size per step. It works because essentially every font-size in
   this file is expressed in rem, so they all scale proportionally from here —
   there is no per-component work and no second place to keep in sync.

   "normal" is deliberately absent: nothing set a root font-size before this
   feature, so the neutral step has to be *no rule at all* (browser default,
   16px). Adding `html { font-size: 16px }` for it would look equivalent and
   would silently override a user's own browser font-size setting, which is the
   one preference we must not take away — someone who enlarged text browser-wide
   for accessibility would have it reverted by visiting the portal.

   Values, and why not a bigger spread: 15/16/18/20px. Above ~20px the pharmacy
   table's fixed column layout starts wrapping cells, so a larger step would
   promise something the tables cannot honour. Steps are named in
   Domain/Constants/TextScales.cs — that class and these rules must be changed
   together, or a stored preference has no effect. */
html[data-text-scale="compact"]    { font-size: 15px; }
html[data-text-scale="large"]      { font-size: 18px; }
html[data-text-scale="extralarge"] { font-size: 20px; }

/* Brand typography: titles/headings use the display family (Nunito Sans);
   body inherits Nunito via --bs-font-sans-serif. Scoped out of the developer
   theme, which deliberately renders everything in the monospace stack. */
:root:not([data-bs-theme="developer"]) h1,
:root:not([data-bs-theme="developer"]) h2,
:root:not([data-bs-theme="developer"]) h3,
:root:not([data-bs-theme="developer"]) h4,
:root:not([data-bs-theme="developer"]) h5,
:root:not([data-bs-theme="developer"]) h6,
:root:not([data-bs-theme="developer"]) .page-title {
    font-family: var(--ds-font-display);
}

/* ── Brand polish pass: depth + display type ────────────────────────────
   Stays fully on-system (no lime where the system forbids it). Scoped out of
   the developer theme, which renders square/monospace IDE chrome. Three moves:
   (1) display font on header/eyebrow surfaces, (2) heavier card-header titles,
   (3) a soft layered card elevation in light mode. */
:root:not([data-bs-theme="developer"]) .card-header,
:root:not([data-bs-theme="developer"]) .jrt-card-header,
:root:not([data-bs-theme="developer"]) .jrt-ct,
:root:not([data-bs-theme="developer"]) .jrt-hero-title,
:root:not([data-bs-theme="developer"]) .jrt-section-subheader,
:root:not([data-bs-theme="developer"]) .jrt-metric-label,
:root:not([data-bs-theme="developer"]) .nav-group {
    font-family: var(--ds-font-display);
}

:root:not([data-bs-theme="developer"]) .card-header {
    font-weight: 700;
    letter-spacing: -0.01em;
}

/* Soft, layered elevation lifts cards off the #F0F0F0 canvas. Light only —
   the dark theme already defines its own deeper card shadow below, and this
   selector must not override it. */
[data-color-mode="light"] .card {
    box-shadow: 0 1px 2px rgba(43, 56, 62, 0.04), 0 4px 14px rgba(43, 56, 62, 0.07);
    transition: box-shadow var(--ds-duration-fast, 200ms) ease;
}

/* ── Apothekengruppen-Kopfzeile ───────────────────────────────────────────
   The group name carries the weight for scanning a long list. 800, not 700:
   the pharmacy NAME in every row is already .fw-bold (PharmacyRow.razor:22),
   so 700 here would merely tie with the rows the header is supposed to head —
   visibly bold, but not distinguishable. Its <td> contributes .fw-semibold
   (600) by inheritance; the ID/count badges stay .fw-normal.

   800 renders because both brand faces are variable fonts declared
   `font-weight: 400 900` (css/tokens.css). With a static face this would
   silently snap back to 700 — check the @font-face range before nudging it.

   Deliberately a rule here and NOT an .fw-bold utility in the markup:
   Bootstrap's utilities are `!important`, which would make a later per-user
   "Gruppennamen hervorheben"-Präferenz unable to turn the emphasis back off
   (see docs/todo/backlog.md → "Darstellung pro Benutzer"). */
.pharmacy-group-name {
    font-weight: 800;
}

[data-color-mode="dark"] .pharmacy-group-row td {
    background-color: #2c3c5a !important;
    color: var(--ds-color-text-primary) !important;
    border-color: var(--ds-color-border-strong) !important;
}

[data-color-mode="dark"] .pharmacy-group-name {
    color: var(--ds-color-text-primary) !important;
}

/* ── Badge fills: keep text readable now that semantic colors are brand hues ──
   Bridged success (lime) and warning (amber) are light fills → need DARK text;
   info (action blue) and danger (error) are saturated → need LIGHT text. The
   markup sometimes hard-codes .text-dark on these (e.g. the bg-info "ID" group
   badge), so these overrides carry higher specificity to win. Scoped out of the
   developer theme, which styles badges as transparent outlines. */
:root:not([data-bs-theme="developer"]) .badge.bg-success,
:root:not([data-bs-theme="developer"]) .badge.text-bg-success {
    color: var(--ds-color-on-brand) !important;   /* dark ink on lime */
}

:root:not([data-bs-theme="developer"]) .badge.bg-info,
:root:not([data-bs-theme="developer"]) .badge.text-bg-info,
:root:not([data-bs-theme="developer"]) .badge.bg-info.text-dark {
    color: var(--ds-color-action-on-primary) !important;   /* light on action blue */
}

:root:not([data-bs-theme="developer"]) .badge.bg-danger,
:root:not([data-bs-theme="developer"]) .badge.text-bg-danger {
    color: #fff !important;   /* light on error red */
}

/* "Alpha" edition tag — was off-palette purple. Recoloured to a brand charcoal
   chip (theme-aware: ink in light, raised surface in dark) so the existing
   white badge text stays legible and it reads distinct from the grey
   secondary "SmartCourier" tag and the blue "ID" badges. */
.bg-purple {
    background-color: var(--ds-color-text-primary) !important;
}

[data-color-mode="dark"] .bg-purple {
    background-color: var(--ds-color-surface-raised) !important;
}

/* ── High-contrast dark-mode fixes for Users/Modules editor rows ───────── */
[data-color-mode="dark"] tr.table-light > td {
    background-color: #24344f !important;
    color: var(--ds-color-text-primary) !important;
}

[data-color-mode="dark"] tr.table-light:hover > td {
    background-color: #24324a !important;
    color: var(--ds-color-text-primary) !important;
}

[data-color-mode="dark"] tr.table-light .fw-semibold,
[data-color-mode="dark"] tr.table-light .form-check-label {
    color: var(--ds-color-text-primary) !important;
}

[data-color-mode="dark"] tr.table-light:hover .form-check-label {
    color: #ffffff !important;
}

[data-color-mode="dark"] tr.table-light .form-check-label .text-muted,
[data-color-mode="dark"] tr.table-light .text-muted.small,
[data-color-mode="dark"] tr.table-light .text-muted {
    color: #bfdbfe !important;
}

[data-color-mode="dark"] tr.table-light:hover .form-check-label .text-muted,
[data-color-mode="dark"] tr.table-light:hover .text-muted.small,
[data-color-mode="dark"] tr.table-light:hover .text-muted {
    color: #dbeafe !important;
}

/* ── Dark mode polish pass: aesthetics + readability ───────────────────── */

/* Sidebar polish lives in NavMenu.razor.css; rules consume --sidebar-*
   tokens defined in :root[data-bs-theme="..."] above. */

[data-color-mode="dark"] .app-header {
    background: rgba(17, 24, 39, 0.92);
    border-bottom-color: var(--ds-color-border-strong);
    box-shadow: 0 6px 18px rgba(2, 6, 23, 0.35);
    backdrop-filter: blur(8px);
}

[data-color-mode="dark"] .card {
    box-shadow: 0 10px 24px rgba(2, 6, 23, 0.28);
}

[data-color-mode="dark"] .card-header {
    background: linear-gradient(180deg, var(--ds-color-surface-raised) 0%, var(--ds-color-surface-canvas) 100%);
}

[data-color-mode="dark"] .table {
    border-radius: 0.5rem;
    overflow: hidden;
}

[data-color-mode="dark"] .btn {
    border-color: var(--ds-color-border-strong);
}

[data-color-mode="dark"] .btn-primary {
    background-color: var(--ds-color-action-primary);
    border-color: var(--ds-color-action-primary);
    color: var(--ds-color-text-primary);
}

[data-color-mode="dark"] .btn-primary:hover,
[data-color-mode="dark"] .btn-primary:focus {
    background-color: var(--ds-color-action-primary-hover);
    border-color: var(--ds-color-action-primary-hover);
    color: #ffffff;
}

[data-color-mode="dark"] .btn-outline-secondary {
    color: var(--ds-color-text-secondary);
    border-color: var(--ds-color-border-strong);
}

[data-color-mode="dark"] .btn-outline-secondary:hover,
[data-color-mode="dark"] .btn-outline-secondary:focus {
    background-color: var(--ds-color-border-strong);
    border-color: var(--ds-color-text-secondary);
    color: var(--ds-color-text-primary);
}

[data-color-mode="dark"] .badge {
    border: 1px solid rgba(148, 163, 184, 0.35);
}

[data-color-mode="dark"] .badge.bg-secondary {
    background-color: var(--ds-color-border-strong) !important;
    color: var(--ds-color-text-primary) !important;
}

[data-color-mode="dark"] .badge.bg-info {
    background-color: var(--ds-color-feedback-info) !important;
    border-color: rgba(56, 189, 248, 0.5);
}

[data-color-mode="dark"] .badge.bg-warning {
    background-color: var(--ds-color-feedback-warning) !important;
    border-color: rgba(251, 191, 36, 0.5);
}

/* ── Hard override: keep Users/Modules inline editor rows dark in dark mode ── */
[data-color-mode="dark"] table.table tbody tr.table-light > td,
[data-color-mode="dark"] table.table tbody tr.table-light > th {
    --bs-table-bg: #1f2b3f !important;
    --bs-table-color: var(--ds-color-text-primary) !important;
    background-color: #1f2b3f !important;
    color: var(--ds-color-text-primary) !important;
}

[data-color-mode="dark"] table.table.table-hover tbody tr.table-light:hover > td,
[data-color-mode="dark"] table.table.table-hover tbody tr.table-light:hover > th {
    --bs-table-bg: #24324a !important;
    --bs-table-color: #ffffff !important;
    background-color: #24324a !important;
    color: #ffffff !important;
}

[data-color-mode="dark"] table.table tbody tr.table-light .form-check-label,
[data-color-mode="dark"] table.table tbody tr.table-light .text-muted,
[data-color-mode="dark"] table.table tbody tr.table-light .small {
    color: #dbeafe !important;
}

[data-color-mode="dark"] table.table.table-hover tbody tr.table-light:hover .form-check-label,
[data-color-mode="dark"] table.table.table-hover tbody tr.table-light:hover .text-muted,
[data-color-mode="dark"] table.table.table-hover tbody tr.table-light:hover .small {
    color: #eff6ff !important;
}

/* Inline editor/confirm rows for Users/Modules tables */
tr.inline-editor-row > td,
tr.inline-editor-row > th {
    background-color: var(--ds-color-surface-field-search);
}

[data-color-mode="dark"] tr.inline-editor-row > td,
[data-color-mode="dark"] tr.inline-editor-row > th {
    background-color: #1f2b3f !important;
    color: var(--ds-color-text-primary) !important;
    border-color: var(--ds-color-border-strong) !important;
}

[data-color-mode="dark"] .table-hover > tbody > tr.inline-editor-row:hover > * {
    background-color: #24324a !important;
    color: #ffffff !important;
}

[data-color-mode="dark"] tr.inline-editor-row .form-check-label,
[data-color-mode="dark"] tr.inline-editor-row .text-muted,
[data-color-mode="dark"] tr.inline-editor-row .small {
    color: #dbeafe !important;
}

[data-color-mode="dark"] tr.inline-editor-row:hover .form-check-label,
[data-color-mode="dark"] tr.inline-editor-row:hover .text-muted,
[data-color-mode="dark"] tr.inline-editor-row:hover .small {
    color: #eff6ff !important;
}

/* Row-action overflow menu (RowActionMenu.razor). The common actions stay inline; the rarer /
   long-labelled admin actions live in a "⋮" dropdown so the action column stays narrow and the
   inline buttons line up column-to-column across rows without the table overflowing. */
.row-action-menu {
    position: relative;
    display: inline-block;
}

/* Transparent full-viewport catcher so a click anywhere outside the menu closes it. Bootstrap's
   JS (which would do this) is not loaded here. */
.row-action-menu-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1050;
    background: transparent;
}

/* Fallback position for the panel before/without row-action-menu.js: just under the toggle,
   right-aligned. The two-class selector (0,2,0) out-specifies Bootstrap's .dropdown-menu (0,1,0),
   which also sets `position`, so this wins the tie regardless of stylesheet order. The JS then
   upgrades it to position:fixed at the same spot to escape the .table-responsive overflow clip. */
.dropdown-menu.row-action-menu-panel {
    position: absolute;
    top: 100%;
    right: 0;
    left: auto;
    margin-top: 0.125rem;
    z-index: 1060;
}

/* Module plugin picker readability */
.plugin-picker {
    scrollbar-gutter: stable;
}

.plugin-option.form-check {
    padding-left: 0;
    margin-bottom: 0;
}

.plugin-option .form-check-input {
    float: none;
    margin: 0.15rem 0 0 0;
    width: 1.05rem;
    height: 1.05rem;
    border-width: 1.5px;
    border-radius: 0.3rem;
    box-shadow: none;
    cursor: pointer;
}

.plugin-option .form-check-label {
    display: block;
    margin: 0;
    line-height: 1.35;
    cursor: pointer;
}

.plugin-option:hover {
    border-color: var(--ds-color-border-strong) !important;
    background-color: var(--ds-color-surface-field-search);
}

.plugin-option .form-check-input:focus {
    box-shadow: 0 0 0 0.15rem rgba(59, 130, 246, 0.22);
}

[data-color-mode="dark"] .plugin-option {
    background-color: #24324a;
    border-color: var(--ds-color-border-strong) !important;
}

[data-color-mode="dark"] .plugin-option:hover {
    background-color: #2b3a55;
    border-color: var(--ds-color-border-strong) !important;
}

[data-color-mode="dark"] .plugin-option .form-check-label {
    color: var(--ds-color-text-primary) !important;
}

[data-color-mode="dark"] .plugin-option .text-muted {
    color: var(--ds-color-text-secondary) !important;
}

[data-color-mode="dark"] .plugin-option .form-check-input {
    background-color: #0f172a;
    border-color: var(--ds-color-action-primary);
}

[data-color-mode="dark"] .plugin-option .form-check-input:checked {
    background-color: var(--ds-color-action-primary);
    border-color: var(--ds-color-action-primary);
}

[data-color-mode="dark"] .plugin-option .form-check-input:focus {
    box-shadow: 0 0 0 0.15rem rgba(147, 197, 253, 0.28);
}

/* ── Pharmacies context menu ─────────────────────────────── */
.pharmacy-context-menu {
    background-color: #ffffff;
    border: 1px solid var(--ds-color-border-strong);
    box-shadow: 0 10px 28px rgba(15, 23, 42, 0.22);
    backdrop-filter: blur(2px);
}

.pharmacy-context-menu .dropdown-item {
    color: var(--ds-color-text-primary);
    border-radius: 0.35rem;
    margin: 0 0.25rem;
    width: calc(100% - 0.5rem);
}

.pharmacy-context-menu .dropdown-item:hover,
.pharmacy-context-menu .dropdown-item:focus {
    background-color: var(--ds-color-action-selected-tint);
    color: var(--ds-color-text-primary);
}

[data-color-mode="dark"] .pharmacy-context-menu {
    background-color: #0f172a;
    border: 1px solid var(--ds-color-border-strong);
    box-shadow: 0 14px 36px rgba(2, 6, 23, 0.68), 0 0 0 1px rgba(148, 163, 184, 0.22);
}

[data-color-mode="dark"] .pharmacy-context-menu .dropdown-item {
    color: var(--ds-color-text-primary);
}

[data-color-mode="dark"] .pharmacy-context-menu .dropdown-item:hover,
[data-color-mode="dark"] .pharmacy-context-menu .dropdown-item:focus {
    background-color: var(--ds-color-surface-raised);
    color: var(--ds-color-text-primary);
}

/* ── Developer theme: ASCII box-drawing frames on .card (B-S17) ───────────
   Cards render like terminal-UI boxes: square corners, amber edge,
   Unicode box-drawing glyphs (┌ ┐ └ ┘) at the corners. Only the dev
   theme — light + dark are untouched. The ::before / ::after on .card
   draw the diagonal pair (top-left, bottom-right); the second pair is
   hosted on the first .card-header (top-right) and last .card-body
   (bottom-left) so we don't run out of pseudo-element slots on .card
   itself. Body bg is painted under each glyph so the corner sits on top
   of the edge line cleanly. */
[data-bs-theme="developer"] .card {
    border-radius: 0;
    /* Custom dash pattern: 10px stroke + 6px gap. CSS `border-style:
       dashed` produces browser-specific (and short) dashes — we replace
       the 4 borders with 4 background-image lines so we get pixel-precise
       control. The box-shadow side ("inset") would also work but conflicts
       with B-S17 corner positioning. The L-bracket corners (declared
       below) are 2px solid amber, so the eye reads: solid corner glyphs
       plus thin dashed runs between them — same shape as htop/lazygit. */
    border: none;
    position: relative;
    background-image:
        repeating-linear-gradient(to right,  var(--dm-corner-line, rgba(255, 180, 84, 0.4)) 0 10px, transparent 10px 16px),
        repeating-linear-gradient(to right,  var(--dm-corner-line, rgba(255, 180, 84, 0.4)) 0 10px, transparent 10px 16px),
        repeating-linear-gradient(to bottom, var(--dm-corner-line, rgba(255, 180, 84, 0.4)) 0 10px, transparent 10px 16px),
        repeating-linear-gradient(to bottom, var(--dm-corner-line, rgba(255, 180, 84, 0.4)) 0 10px, transparent 10px 16px);
    background-position: 0 0, 0 100%, 0 0, 100% 0;
    background-repeat: no-repeat;
    background-size: 100% 1px, 100% 1px, 1px 100%, 1px 100%;
    background-color: var(--bs-card-bg);
}

[data-bs-theme="developer"] .card > .card-header {
    border-radius: 0;
    position: relative;
    border-bottom: none;
    background-image: repeating-linear-gradient(to right, var(--dm-corner-line, rgba(255, 180, 84, 0.4)) 0 10px, transparent 10px 16px);
    background-position: 0 100%;
    background-repeat: no-repeat;
    background-size: 100% 1px;
    background-color: var(--bs-tertiary-bg);
}

/* Body/footer stay UNpositioned so their corner-bracket pseudo-elements resolve
   against the .card (the positioned ancestor), not against the child's own
   padding box. That makes the bracket land on the card edge regardless of the
   child's padding — a `card-body p-0` wrapping a table (e.g. PharmacyDetail's
   device table) no longer flings the bottom-left/top-right brackets 1rem
   outside the card. It also matches how abs-children behave in light/dark,
   where these elements were never positioned. */
[data-bs-theme="developer"] .card > .card-body,
[data-bs-theme="developer"] .card > .card-footer {
    position: static;
}

[data-bs-theme="developer"] .card > .card-footer {
    border-radius: 0;
    border-top: none;
    background-image: repeating-linear-gradient(to right, var(--dm-corner-line, rgba(255, 180, 84, 0.4)) 0 10px, transparent 10px 16px);
    background-position: 0 0;
    background-repeat: no-repeat;
    background-size: 100% 1px;
}

/* Shared base — each "corner" is a small empty box positioned at one of
   the four card corners. We draw two of its edges with `border-*` so it
   reads as an L-shaped bracket. Pixel-aligned to the card's own 1px
   border, so they always lock onto the corner regardless of font metrics
   (the previous Unicode-glyph approach drifted because a glyph's visual
   meeting point isn't at the cell edge — `┌`'s corner sits inside the
   glyph box, not at its top-left). */
[data-bs-theme="developer"] .card::before,
[data-bs-theme="developer"] .card::after,
[data-bs-theme="developer"] .card > .card-header::after,
[data-bs-theme="developer"] .card:not(:has(> .card-header)) > .card-body:first-child::after,
[data-bs-theme="developer"] .card:not(:has(> .card-header)):not(:has(> .card-body:first-child)) > *:first-child::after,
[data-bs-theme="developer"] .card > .card-body:last-child::before,
[data-bs-theme="developer"] .card > .card-footer:last-child::before,
[data-bs-theme="developer"] .card:not(:has(> .card-body:last-child)):not(:has(> .card-footer:last-child)) > *:last-child::before {
    content: "";
    position: absolute;
    z-index: 1;
    width: 10px;
    height: 10px;
    pointer-events: none;
    background: transparent;
}

/* Top-left ┌ — top + left edges. Cards no longer have an actual `border`
   (the dashed look comes from a background-image), so the L-brackets
   anchor at 0/100% instead of -1px. */
[data-bs-theme="developer"] .card::before {
    top: 0;
    left: 0;
    border-top: 2px solid var(--dm-corner-color, var(--dm-accent));
    border-left: 2px solid var(--dm-corner-color, var(--dm-accent));
}

/* Bottom-right ┘ — bottom + right edges */
[data-bs-theme="developer"] .card::after {
    bottom: 0;
    right: 0;
    border-bottom: 2px solid var(--dm-corner-color, var(--dm-accent));
    border-right: 2px solid var(--dm-corner-color, var(--dm-accent));
}

/* Top-right ┐ — top + right edges, anchored on the card-header. */
[data-bs-theme="developer"] .card > .card-header::after {
    top: 0;
    right: 0;
    border-top: 2px solid var(--dm-corner-color, var(--dm-accent));
    border-right: 2px solid var(--dm-corner-color, var(--dm-accent));
}

/* Top-right ┐ — fallback for header-less cards: anchor on the first
   card-body. The body is unpositioned (see above), so right:0 is the card's
   right edge whatever the body's padding is — no compensation needed. */
[data-bs-theme="developer"] .card:not(:has(> .card-header)) > .card-body:first-child::after {
    top: 0;
    right: 0;
    border-top: 2px solid var(--dm-corner-color, var(--dm-accent));
    border-right: 2px solid var(--dm-corner-color, var(--dm-accent));
}

/* Top-right ┐ — second fallback: card has neither .card-header nor first
   .card-body (e.g. <div class="card"><div class="table-responsive">). */
[data-bs-theme="developer"] .card:not(:has(> .card-header)):not(:has(> .card-body:first-child)) > *:first-child::after {
    top: 0;
    right: 0;
    border-top: 2px solid var(--dm-corner-color, var(--dm-accent));
    border-right: 2px solid var(--dm-corner-color, var(--dm-accent));
}

/* Bottom-left └ — on the last card-body or card-footer. The element is
   unpositioned (see above), so left:0 is the card's left edge for any padding
   — including p-0 table bodies, which the old 1rem compensation pushed out. */
[data-bs-theme="developer"] .card > .card-body:last-child::before,
[data-bs-theme="developer"] .card > .card-footer:last-child::before {
    bottom: 0;
    left: 0;
    border-bottom: 2px solid var(--dm-corner-color, var(--dm-accent));
    border-left: 2px solid var(--dm-corner-color, var(--dm-accent));
}

/* Bottom-left └ — fallback for last-child of any other type. */
[data-bs-theme="developer"] .card:not(:has(> .card-body:last-child)):not(:has(> .card-footer:last-child)) > *:last-child::before {
    bottom: 0;
    left: 0;
    border-bottom: 2px solid var(--dm-corner-color, var(--dm-accent));
    border-left: 2px solid var(--dm-corner-color, var(--dm-accent));
}

/* ── Developer theme: JSON syntax highlighting (B-S18) ─────────────────────
   .dev-only-json containers are hidden in light/dark, revealed in the
   developer theme. dev-highlight.js wraps tokens in <span class="token
   json-...">; the colors below are token-themed for the dev palette
   (Ayu-dark-inspired). Light + Dark stay untouched — they fall through
   to the default `display: none` and never see the highlighted output. */
.dev-only-json {
    display: none;
}

[data-bs-theme="developer"] .dev-only-summary {
    display: none;
}

[data-bs-theme="developer"] .dev-only-json {
    display: block;
    margin: 0;
    padding: 0.5rem 0.75rem;
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 0;
    color: var(--bs-body-color);
    font-family: var(--bs-font-mono);
    font-size: 0.78rem;
    line-height: 1.4;
    white-space: pre-wrap;
    word-break: break-word;
    overflow: visible;
}

[data-bs-theme="developer"] .dev-only-json code {
    background: transparent;
    padding: 0;
    color: inherit;
    font-family: inherit;
    font-size: inherit;
    white-space: inherit;
}

[data-bs-theme="developer"] .dev-only-json .token.json-key {
    color: #59c2ff;
}

[data-bs-theme="developer"] .dev-only-json .token.json-string {
    color: #aad94c;
}

[data-bs-theme="developer"] .dev-only-json .token.json-number {
    color: #d2a6ff;
}

[data-bs-theme="developer"] .dev-only-json .token.json-boolean {
    color: #ffb454;
    font-weight: 600;
}

[data-bs-theme="developer"] .dev-only-json .token.json-null {
    color: #f29668;
    font-style: italic;
}

/* ── Reusable DevJson panel (Components/Shared/DevJson.razor) ──────────────
   The inner .dev-only-json already hides itself in light/dark, but the wrapper
   and its [File] path label would otherwise leak into those themes — so gate
   the whole panel. Dev-theme-only, additive: pages drop <DevJson> next to their
   normal UI and only the developer theme reveals it. */
.dev-only-json-panel {
    display: none;
}

[data-bs-theme="developer"] .dev-only-json-panel {
    display: block;
    margin-bottom: 1rem;
}

[data-bs-theme="developer"] .dev-only-json-path {
    color: var(--bs-secondary-color);
    font-family: var(--bs-font-mono);
    font-size: 0.78rem;
    margin-bottom: 0.15rem;
}

/* ── Per-row JSON expander for tables (Components/Shared/DevJsonRow.razor) ──
   A full-width <tr> holding a native <details> disclosure. Dev-theme-only: the
   whole row is display:none in light/dark; the component also serializes nothing
   there. Uses the .dev-only-json block (above) for the expanded body. */
.dev-json-row {
    display: none;
}

[data-bs-theme="developer"] .dev-json-row {
    display: table-row;
}

[data-bs-theme="developer"] .dev-json-details > summary {
    cursor: pointer;
    list-style: none;
    user-select: none;
    color: var(--dm-accent);
    font-family: var(--bs-font-mono);
    font-size: 0.75rem;
    padding: 0.2rem 0.6rem;
    background: var(--bs-tertiary-bg);
}

[data-bs-theme="developer"] .dev-json-details > summary::-webkit-details-marker {
    display: none;
}

[data-bs-theme="developer"] .dev-json-details > summary::before {
    content: "\25b8 ";
}

[data-bs-theme="developer"] .dev-json-details[open] > summary::before {
    content: "\25be ";
}

/* Per-card JSON disclosure for card lists (Components/Shared/DevJsonBlock.razor).
   Same disclosure as the table-row expander, wrapped in a block instead of a row. */
.dev-json-block {
    display: none;
}

[data-bs-theme="developer"] .dev-json-block {
    display: block;
    margin-top: 0.5rem;
}

/* ════════════════════════════════════════════════════════════════════════
   Developer theme — IDE chrome (B-S20)
   ════════════════════════════════════════════════════════════════════════
   Pushes the developer theme further toward a VS-Code / terminal-IDE look:
       • Sidebar reads as a file tree (DIR / FILE prefix glyphs, square,
         tree-indent feel, accent left-bar on active route).
       • App-header reads as a tab-strip (square, no shadow, accent rail).
       • Page-title gains a [File] ~/views/<title>.json breadcrumb and the
         subtitle becomes a // hint comment.
       • A bottom DevStatusBar (own component) renders a VS-Code-style
         status strip with [USER] / [ROLES] / [VIEW] / [DB] / [API] /
         [THEME]. The bar is hidden in light/dark via the visibility rule
         further down.
   Light + Dark themes are untouched — every rule below is gated under
   [data-bs-theme="developer"].
   ════════════════════════════════════════════════════════════════════════ */

/* ── Sidebar: file-tree look ──────────────────────────────────────────── */
[data-bs-theme="developer"] .sidebar {
    border-right: 1px solid var(--dm-accent-soft);
}

/* Brand line reads "[DIR] ApoTune_Portal/" instead of the pill icon.
   Fixed height (not min-height) so the sidebar-top and main-area-top
   render at the exact same y-coordinate — see .app-header in dev for
   the matching declaration. */
[data-bs-theme="developer"] .sidebar .sidebar-brand {
    font-size: 0.8rem;
    text-transform: none;
    letter-spacing: 0;
    padding: 0 0.85rem;
    height: 2.6rem;
    border-bottom: 1px solid var(--dm-accent-soft);
    gap: 0.4rem;
    box-sizing: border-box;
}

/* Logo light/dark switching via data-color-mode */
.brand-logo-dark { display: none; }
[data-color-mode="dark"] .brand-logo-light { display: none; }
[data-color-mode="dark"] .brand-logo-dark { display: block; }

[data-bs-theme="developer"] .sidebar .sidebar-brand .brand-logo,
[data-bs-theme="developer"] .sidebar .sidebar-brand .brand-logo-light,
[data-bs-theme="developer"] .sidebar .sidebar-brand .brand-logo-dark {
    display: none;
}

/* Collapsed logo variants — hidden by default, swapped in when sidebar is collapsed */
.brand-logo-collapsed { display: none; }

.sidebar.collapsed .brand-logo-light,
.sidebar.collapsed .brand-logo-dark { display: none; }

.sidebar.collapsed .brand-logo-collapsed-light { display: block; }
.sidebar.collapsed .brand-logo-collapsed-dark  { display: none; }

[data-color-mode="dark"] .sidebar.collapsed .brand-logo-collapsed-light { display: none; }
[data-color-mode="dark"] .sidebar.collapsed .brand-logo-collapsed-dark  { display: block; }

[data-bs-theme="developer"] .sidebar .sidebar-brand .brand-logo-collapsed,
[data-bs-theme="developer"] .sidebar .sidebar-brand .brand-logo-collapsed-light,
[data-bs-theme="developer"] .sidebar .sidebar-brand .brand-logo-collapsed-dark {
    display: none;
}

[data-bs-theme="developer"] .sidebar .sidebar-brand::before {
    content: "[DIR] ";
    color: var(--bs-secondary-color);
    font-weight: 400;
}

[data-bs-theme="developer"] .sidebar .sidebar-brand::after {
    content: "/";
    color: var(--bs-secondary-color);
    margin-left: 0.1rem;
}

/* Hide emoji nav-icons — replaced by tree glyphs below. */
[data-bs-theme="developer"] .sidebar .nav-icon {
    display: none;
}

/* Tighter, square nav rows. */
[data-bs-theme="developer"] .sidebar .sidebar-nav {
    padding: 0.5rem 0;
}

[data-bs-theme="developer"] .sidebar .sidebar-nav li {
    margin-bottom: 0;
}

[data-bs-theme="developer"] .sidebar .sidebar-nav a {
    border-radius: 0;
    padding: 0.35rem 0.75rem 0.35rem 1.2rem;
    font-size: 0.82rem;
    border-left: 2px solid transparent;
    border-top: none;
    border-right: none;
    border-bottom: none;
    position: relative;
    gap: 0.5rem;
}

/* Tree glyph: "├─ " for inactive, "└▸ " for active. */
[data-bs-theme="developer"] .sidebar .sidebar-nav a::before {
    content: "├─";
    color: var(--bs-secondary-color);
    font-family: var(--bs-font-mono);
    font-size: 0.8rem;
    line-height: 1;
    flex-shrink: 0;
    margin-right: 0.1rem;
}

[data-bs-theme="developer"] .sidebar .sidebar-nav li:last-child a::before {
    content: "└─";
}

[data-bs-theme="developer"] .sidebar .sidebar-nav a.active {
    background: var(--dm-accent-soft);
    color: var(--dm-accent);
    border-left-color: var(--dm-accent);
    font-weight: 600;
}

[data-bs-theme="developer"] .sidebar .sidebar-nav a.active::before {
    content: "└▸";
    color: var(--dm-accent);
}

/* Footer + theme picker chrome — match the squared, mono look. */
[data-bs-theme="developer"] .sidebar .sidebar-footer {
    border-top: 1px solid var(--dm-accent-soft);
    padding: 0.5rem 0.6rem;
}

[data-bs-theme="developer"] .sidebar .sidebar-footer .btn {
    border-radius: 0;
    font-size: 0.78rem;
    padding: 0.25rem 0.5rem;
}

[data-bs-theme="developer"] .sidebar .theme-toggle-row {
    border-top: 1px solid var(--dm-accent-soft);
    padding: 0.35rem 0.5rem;
}

[data-bs-theme="developer"] .sidebar .theme-pick {
    border-radius: 0;
    width: 30px;
    height: 24px;
    font-size: 0.85rem;
}

/* ── App-header: tab-strip / breadcrumb rail ──────────────────────────── */
[data-bs-theme="developer"] .app-header {
    background: var(--bs-body-bg);
    border-bottom: 1px solid var(--dm-accent-soft);
    box-shadow: none;
    padding: 0 0.85rem;
    height: 2.6rem;
    font-size: 0.8rem;
    backdrop-filter: none;
    box-sizing: border-box;
}

/* Tighter badge in dev app-header so the email pill doesn't push the
   bar taller than the sidebar-brand row. */
[data-bs-theme="developer"] .app-header .badge.bg-primary {
    font-size: 0.7rem;
    line-height: 1.2;
}

[data-bs-theme="developer"] .app-header .text-muted::before {
    content: "$ ";
    color: var(--dm-accent);
    font-weight: 700;
}

[data-bs-theme="developer"] .app-header .badge.bg-primary {
    background-color: transparent !important;
    color: var(--dm-accent);
    border: 1px solid var(--dm-accent-soft);
    border-radius: 0;
    font-family: var(--bs-font-mono);
    font-weight: 400;
    padding: 0.15rem 0.5rem;
}

/* ── Page header: [File] ~/views/<title>.<ext> breadcrumb ─────────────── */
[data-bs-theme="developer"] .page-title {
    font-family: var(--bs-font-mono);
    font-size: 1rem;
    font-weight: 500;
    color: var(--bs-emphasis-color);
    letter-spacing: 0;
}

[data-bs-theme="developer"] .page-title::before {
    content: "[File] ~/views/";
    color: var(--bs-secondary-color);
    font-weight: 400;
    margin-right: 0.05rem;
}

[data-bs-theme="developer"] .page-title::after {
    content: ".json";
    color: var(--bs-secondary-color);
    font-weight: 400;
}

/* Subtitle becomes a // hint comment in dev mode. */
[data-bs-theme="developer"] .page-header p.text-muted {
    font-family: var(--bs-font-mono);
    font-size: 0.75rem;
    color: var(--bs-secondary-color) !important;
}

[data-bs-theme="developer"] .page-header p.text-muted::before {
    content: "// ";
    color: var(--dm-accent);
}

/* ── Bottom DevStatusBar — visible only in dev ────────────────────────── */
.dev-status-bar {
    display: none;
}

[data-bs-theme="developer"] .dev-status-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    padding: 0.2rem 0.9rem;
    border-top: 1px solid var(--dm-accent-soft);
    background: #050810;
    color: var(--bs-secondary-color);
    font-family: var(--bs-font-mono);
    font-size: 0.72rem;
    line-height: 1.4;
    flex-shrink: 0;
    /* Stays clear of any sticky elements above it; the parent .main-area
       controls layout flow so it sits at the bottom of the viewport. */
}

[data-bs-theme="developer"] .dev-status-bar .dev-status-left,
[data-bs-theme="developer"] .dev-status-bar .dev-status-right {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.1rem 1.1rem;
}

[data-bs-theme="developer"] .dev-status-bar .dev-status-cell {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    white-space: nowrap;
}

[data-bs-theme="developer"] .dev-status-bar .dev-status-key {
    color: var(--dm-accent);
    font-weight: 600;
}

[data-bs-theme="developer"] .dev-status-bar .dev-status-val {
    color: var(--bs-emphasis-color);
}

[data-bs-theme="developer"] .dev-status-bar .dev-status-val.dev-status-ok {
    color: #aad94c;
}

[data-bs-theme="developer"] .dev-status-bar .dev-status-glyph {
    color: var(--dm-accent);
    font-size: 0.85rem;
    line-height: 1;
    margin-left: 0.25rem;
}

/* [PERMS] toggle — a plain button dressed as a status cell. */
[data-bs-theme="developer"] .dev-status-bar .dev-status-toggle {
    border: 0;
    background: transparent;
    padding: 0;
    cursor: pointer;
    font: inherit;
}
[data-bs-theme="developer"] .dev-status-bar .dev-status-toggle:hover .dev-status-val {
    text-decoration: underline;
}

/* ── Developer permission overlay (DevPermTag + dev-perm.js) ───────────────
   Hover-reveal only: gated elements get a dashed outline (green = the user
   holds the right, amber = they don't), full detail in a floating tooltip on
   hover. Outline + fixed tooltip sit outside flow, so nothing ever shifts.
   Painted only in the Developer theme with the [PERMS] toggle on. */
[data-bs-theme="developer"].dev-perms-on .dev-perm-target {
    outline: 1px dashed var(--dm-accent-soft);
    outline-offset: 2px;
    border-radius: 2px;
}
[data-bs-theme="developer"].dev-perms-on .dev-perm-target.dev-perm-held {
    outline-color: rgba(170, 217, 76, 0.7);
}
[data-bs-theme="developer"].dev-perms-on .dev-perm-target.dev-perm-missing {
    outline-color: rgba(224, 168, 106, 0.7);
}

/* A container a read-gate wraps (a whole card) gets no full-box outline — only a small dashed
   corner marker at its top-right, so a card-level gate stays legible without drawing a giant box.
   The .dev-perm-box-rel positioning context is added by dev-perm.js only when the box has none. */
/* A read-gated card keeps its L-bracket corners but recolours them by permission: green when the
   user holds the right, red-amber when not. --dm-corner-color cascades from the gated wrapper into
   the descendant .card's corner pseudo-elements; non-gated cards keep the default amber accent. */
[data-bs-theme="developer"].dev-perms-on .dev-perm-target.dev-perm-box {
    outline: none;
}
[data-bs-theme="developer"].dev-perms-on .dev-perm-target.dev-perm-box.dev-perm-held {
    --dm-corner-color: rgba(170, 217, 76, 0.95);
    --dm-corner-line: rgba(170, 217, 76, 0.45);
}
[data-bs-theme="developer"].dev-perms-on .dev-perm-target.dev-perm-box.dev-perm-missing {
    --dm-corner-color: rgba(230, 116, 92, 0.95);
    --dm-corner-line: rgba(230, 116, 92, 0.45);
}

/* Developer theme: swap Bootstrap's rotating ring for a terminal-style braille spinner, so a
   loading state reads like a console. Gated on the theme only (independent of the [PERMS] toggle);
   the .visually-hidden "Loading…" child stays hidden. Content-frame animation is discrete — a
   browser that ignores it falls back to a single static braille glyph, which is still on-theme. */
[data-bs-theme="developer"] .spinner-border,
[data-bs-theme="developer"] .spinner-grow {
    width: auto;
    height: auto;
    border: none;
    border-radius: 0;
    background: none;
    animation: none;
    color: var(--dm-accent);
    font-family: "Cascadia Code", "Consolas", "Courier New", monospace;
    font-size: 1.5rem;
    line-height: 1;
    vertical-align: middle;
}
[data-bs-theme="developer"] .spinner-border.spinner-border-sm,
[data-bs-theme="developer"] .spinner-grow.spinner-grow-sm {
    font-size: 1rem;
}
[data-bs-theme="developer"] .spinner-border::after,
[data-bs-theme="developer"] .spinner-grow::after {
    content: "\280B";
    display: inline-block;
    animation: dev-console-spin 1s steps(1, end) infinite;
}
/* Canonical smooth braille spinner: the two lit dots rotate cleanly around the cell. */
@keyframes dev-console-spin {
    0%   { content: "\280B"; }  /* ⠋ */
    10%  { content: "\2819"; }  /* ⠙ */
    20%  { content: "\2839"; }  /* ⠹ */
    30%  { content: "\2838"; }  /* ⠸ */
    40%  { content: "\283C"; }  /* ⠼ */
    50%  { content: "\2834"; }  /* ⠴ */
    60%  { content: "\2826"; }  /* ⠦ */
    70%  { content: "\2827"; }  /* ⠧ */
    80%  { content: "\2807"; }  /* ⠇ */
    90%  { content: "\280F"; }  /* ⠏ */
}

/* Floating tooltip — appended to <body>, position:fixed, so it never clips or reflows. */
#dev-perm-tip {
    position: fixed;
    z-index: 3000;
    max-width: 340px;
    padding: 0.4rem 0.55rem;
    border: 1px solid var(--dm-accent-soft);
    border-radius: 5px;
    background: #050810;
    color: #cdd4de;
    font-family: var(--bs-font-mono);
    font-size: 0.72rem;
    line-height: 1.5;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
    pointer-events: none;
}
#dev-perm-tip .dpt-head {
    color: var(--dm-accent);
    font-weight: 600;
    margin-bottom: 0.25rem;
}
#dev-perm-tip .dpt-row {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    white-space: nowrap;
}
#dev-perm-tip .dpt-mark {
    width: 0.8rem;
    flex: none;
    text-align: center;
}
#dev-perm-tip .dpt-row.held .dpt-mark,
#dev-perm-tip .dpt-row.held .dpt-key {
    color: #aad94c;
}
#dev-perm-tip .dpt-row.missing .dpt-mark,
#dev-perm-tip .dpt-row.missing .dpt-key {
    color: #e0a86a;
}
#dev-perm-tip .dpt-label {
    color: #8a93a3;
    white-space: normal;
}
#dev-perm-tip .dpt-note {
    margin-top: 0.25rem;
    color: #8a93a3;
}

/* ── Per-page file extension override ─────────────────────────────────── */
/* PageHeader's data-dev-ext attribute selects the ".ext" suffix shown
   after the page title. CSS attr() in content can't traverse up from the
   ::after pseudo-element to .page-header, so we enumerate the supported
   extensions explicitly — same approach as B-S15 keeping the dev-vocab
   discoverable. Default ".json" still fires for pages that don't set
   DevExt (the generic rule above). */
[data-bs-theme="developer"] .page-header[data-dev-ext="json"] .page-title::after {
    content: ".json";
}

[data-bs-theme="developer"] .page-header[data-dev-ext="ini"] .page-title::after {
    content: ".ini";
}

[data-bs-theme="developer"] .page-header[data-dev-ext="sql"] .page-title::after {
    content: ".sql";
}

[data-bs-theme="developer"] .page-header[data-dev-ext="log"] .page-title::after {
    content: ".log";
}

[data-bs-theme="developer"] .page-header[data-dev-ext="yaml"] .page-title::after {
    content: ".yaml";
}

[data-bs-theme="developer"] .page-header[data-dev-ext="md"] .page-title::after {
    content: ".md";
}

/* Pages where the title carries an icon (Bootstrap-icons <i>) hide the
   icon in dev mode — code paths don't carry inline glyphs. */
[data-bs-theme="developer"] .page-title > i.bi {
    display: none;
}

/* ── Buttons: square, mono, amber accents ─────────────────────────────── */
[data-bs-theme="developer"] .btn {
    border-radius: 0;
    font-family: var(--bs-font-mono);
    font-weight: 500;
    font-size: 0.78rem;
    padding: 0.3rem 0.7rem;
    letter-spacing: 0;
}

[data-bs-theme="developer"] .btn-primary {
    background-color: var(--dm-accent-soft);
    border-color: var(--dm-accent);
    color: var(--dm-accent);
}

[data-bs-theme="developer"] .btn-primary:hover,
[data-bs-theme="developer"] .btn-primary:focus,
[data-bs-theme="developer"] .btn-primary:active {
    background-color: var(--dm-accent);
    border-color: var(--dm-accent);
    color: #0a0e14;
}

[data-bs-theme="developer"] .btn-secondary,
[data-bs-theme="developer"] .btn-outline-secondary {
    background-color: transparent;
    /* Bumped from --bs-border-color (~ body-bg, invisible) to a visible
       amber-soft so buttons read as buttons even when not focused. */
    border-color: rgba(255, 180, 84, 0.35);
    color: var(--bs-emphasis-color);
}

[data-bs-theme="developer"] .btn-secondary:hover,
[data-bs-theme="developer"] .btn-outline-secondary:hover {
    background-color: var(--dm-surface-hover);
    border-color: var(--dm-accent);
    color: var(--bs-emphasis-color);
}

[data-bs-theme="developer"] .btn-outline-light,
[data-bs-theme="developer"] .btn-outline-primary {
    background-color: transparent;
    border-color: rgba(255, 180, 84, 0.35);
    color: var(--bs-secondary-color);
}

[data-bs-theme="developer"] .btn-outline-light:hover,
[data-bs-theme="developer"] .btn-outline-primary:hover {
    background-color: var(--dm-accent-soft);
    border-color: var(--dm-accent);
    color: var(--dm-accent);
}

[data-bs-theme="developer"] .btn-danger {
    background-color: transparent;
    border-color: #f07178;
    color: #f07178;
}

[data-bs-theme="developer"] .btn-danger:hover {
    background-color: #f07178;
    color: #0a0e14;
}

[data-bs-theme="developer"] .btn-success {
    background-color: transparent;
    border-color: #aad94c;
    color: #aad94c;
}

[data-bs-theme="developer"] .btn-success:hover {
    background-color: #aad94c;
    color: #0a0e14;
}

[data-bs-theme="developer"] .btn-warning {
    background-color: transparent;
    border-color: var(--dm-accent);
    color: var(--dm-accent);
}

/* Square btn-group (pill segments side-by-side without rounded corners). */
[data-bs-theme="developer"] .btn-group > .btn {
    border-radius: 0;
}

[data-bs-theme="developer"] .btn-group > .btn:not(:last-child) {
    border-right-width: 0;
}

/* ── Filter toggle pill rows → square segmented buttons ───────────────── */
/* Pharmacies' two toolbar segments (status filter + view-mode) are
   .btn-group.btn-group-sm wrapping plain .btn children — the size class
   sits on the group, NOT each button. In dev each segment reads as its
   own button: all four borders, square corners, amber accent for active.
   The :not(:last-child):not(.dropdown-toggle) selector matches Bootstrap's
   own override that strips border-right on non-last children — without
   it our rule has lower specificity and the inner buttons render
   borderless on the right. */
[data-bs-theme="developer"] .btn-group > .btn,
[data-bs-theme="developer"] .btn-group > .btn:not(:last-child):not(.dropdown-toggle) {
    border-radius: 0;
    /* Visible amber-soft border (was --bs-border-color, near-invisible
       against body-bg) so each segment reads as a real button even when
       not focused. */
    border: 1px solid rgba(255, 180, 84, 0.35);
    padding: 0.25rem 0.6rem;
    font-size: 0.75rem;
    background: transparent;
    color: var(--bs-secondary-color);
}

[data-bs-theme="developer"] .btn-group > .btn.active,
[data-bs-theme="developer"] .btn-group > .btn.btn-primary,
[data-bs-theme="developer"] .btn-group > .btn.btn-success,
[data-bs-theme="developer"] .btn-group > .btn.active:not(:last-child):not(.dropdown-toggle),
[data-bs-theme="developer"] .btn-group > .btn.btn-primary:not(:last-child):not(.dropdown-toggle),
[data-bs-theme="developer"] .btn-group > .btn.btn-success:not(:last-child):not(.dropdown-toggle) {
    background: var(--dm-accent-soft);
    color: var(--dm-accent);
    border: 1px solid var(--dm-accent);
}

[data-bs-theme="developer"] .btn-group > .btn:hover,
[data-bs-theme="developer"] .btn-group > .btn:not(:last-child):not(.dropdown-toggle):hover {
    background: var(--dm-accent-soft);
    color: var(--dm-accent);
    border: 1px solid var(--dm-accent);
}

/* ── Form inputs: square, mono ────────────────────────────────────────── */
[data-bs-theme="developer"] .form-control,
[data-bs-theme="developer"] .form-select {
    border-radius: 0;
    background-color: var(--bs-tertiary-bg);
    border-color: var(--bs-border-color);
    color: var(--bs-emphasis-color);
    font-family: var(--bs-font-mono);
    font-size: 0.82rem;
}

[data-bs-theme="developer"] .form-control:focus,
[data-bs-theme="developer"] .form-select:focus {
    background-color: var(--bs-tertiary-bg);
    border-color: var(--dm-accent);
    color: var(--bs-emphasis-color);
    box-shadow: 0 0 0 0.15rem var(--dm-accent-soft);
}

[data-bs-theme="developer"] .form-control::placeholder {
    color: var(--bs-secondary-color);
    font-style: normal;
}

[data-bs-theme="developer"] .input-group-text {
    border-radius: 0;
    background-color: #11151c;
    border-color: var(--bs-border-color);
    color: var(--bs-secondary-color);
    font-family: var(--bs-font-mono);
}

[data-bs-theme="developer"] .form-check-input {
    border-radius: 0;
    background-color: var(--bs-tertiary-bg);
    border-color: var(--bs-border-color);
}

[data-bs-theme="developer"] .form-check-input:checked {
    background-color: var(--dm-accent);
    border-color: var(--dm-accent);
}

[data-bs-theme="developer"] .form-check-input:focus {
    border-color: var(--dm-accent);
    box-shadow: 0 0 0 0.15rem var(--dm-accent-soft);
}

[data-bs-theme="developer"] .form-label {
    font-family: var(--bs-font-mono);
    font-size: 0.78rem;
    color: var(--bs-secondary-color);
}

/* ── Badges: bracketed [active]-style ─────────────────────────────────── */
[data-bs-theme="developer"] .badge {
    border-radius: 0;
    background-color: transparent !important;
    border: 1px solid var(--bs-border-color);
    font-family: var(--bs-font-mono);
    font-weight: 500;
    font-size: 0.7rem;
    color: var(--bs-emphasis-color) !important;
    padding: 0.15rem 0.5rem;
}

[data-bs-theme="developer"] .badge.bg-success,
[data-bs-theme="developer"] .badge.text-bg-success {
    color: #aad94c !important;
    border-color: rgba(170, 217, 76, 0.4);
}

[data-bs-theme="developer"] .badge.bg-danger,
[data-bs-theme="developer"] .badge.text-bg-danger {
    color: #f07178 !important;
    border-color: rgba(240, 113, 120, 0.4);
}

[data-bs-theme="developer"] .badge.bg-warning,
[data-bs-theme="developer"] .badge.text-bg-warning {
    color: var(--dm-accent) !important;
    border-color: var(--dm-accent-soft);
}

[data-bs-theme="developer"] .badge.bg-info,
[data-bs-theme="developer"] .badge.text-bg-info {
    color: #59c2ff !important;
    border-color: rgba(89, 194, 255, 0.4);
}

/* ── Card-header: // comment prefix + flat cap ────────────────────────── */
[data-bs-theme="developer"] .card-header {
    background: var(--bs-tertiary-bg);
    color: var(--bs-emphasis-color);
    font-family: var(--bs-font-mono);
    font-size: 0.85rem;
    padding: 0.4rem 0.75rem;
}

/* The // glyph anchors visually beside whatever text the card-header
   carries — DevLabel-wrapped section names ("masterData", "plugins",
   "faxServer.connection", etc.) read as inline JS-style comments. */
[data-bs-theme="developer"] .card-header > h1::before,
[data-bs-theme="developer"] .card-header > h2::before,
[data-bs-theme="developer"] .card-header > h3::before,
[data-bs-theme="developer"] .card-header > h4::before,
[data-bs-theme="developer"] .card-header > h5::before,
[data-bs-theme="developer"] .card-header > h6::before,
[data-bs-theme="developer"] .card-header > .h5::before,
[data-bs-theme="developer"] .card-header > .h6::before,
[data-bs-theme="developer"] .card-header > strong::before,
[data-bs-theme="developer"] .card-header > .fw-semibold::before,
[data-bs-theme="developer"] .card-header > .fw-bold::before {
    content: "// ";
    color: var(--dm-accent);
    font-weight: 400;
    margin-right: 0.05rem;
}

/* ── Modal-header: // comment prefix + flat ───────────────────────────── */
[data-bs-theme="developer"] .modal-content {
    border-radius: 0;
    background: var(--bs-card-bg);
    border: 1px solid var(--dm-accent-soft);
}

[data-bs-theme="developer"] .modal-header {
    background: var(--bs-tertiary-bg);
    border-bottom: 1px solid var(--dm-accent-soft);
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    padding: 0.5rem 0.75rem;
}

[data-bs-theme="developer"] .modal-header .modal-title {
    font-family: var(--bs-font-mono);
    font-size: 0.95rem;
    color: var(--bs-emphasis-color);
}

[data-bs-theme="developer"] .modal-header .modal-title::before {
    content: "// ";
    color: var(--dm-accent);
    font-weight: 400;
}

[data-bs-theme="developer"] .modal-footer {
    border-top: 1px solid var(--dm-accent-soft);
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    padding: 0.5rem 0.75rem;
}

/* ── Tables: tighter, mono, terminal-cursor accent on active row ──────── */
[data-bs-theme="developer"] .table {
    font-family: var(--bs-font-mono);
    font-size: 0.8rem;
    border-radius: 0;
}

[data-bs-theme="developer"] .table thead th {
    background: var(--bs-tertiary-bg);
    color: var(--bs-secondary-color);
    border-bottom: 1px solid var(--dm-accent-soft);
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
}

/* The pharmacy sub-view tables (plugins/devices/files) are table-layout:fixed with
   a flexible "description" column. In the narrow pharmacy-detail content area — and
   more so in the wider mono dev-theme font — that column collapses until its header
   word wraps one letter per line. Let these tables size columns to their content in
   the dev theme and scroll inside their .table-responsive wrapper instead. The
   mobile card transform (a @media block with table-layout:auto !important) is
   unaffected. Headers never wrap to begin with.

   NOTE the specificity: the tables carry BOTH `.table` and `.table-cards`, so
   `.table.table-cards` is (0,3,0) — it must out-specify the component's OWN scoped
   rule `.plugin-table[b-xxxxx]` (0,2,0) from PharmacyPluginsView.razor.css, which
   loads AFTER app.css and would otherwise win a specificity tie and keep
   table-layout:fixed. A plain `.table-cards` (0,2,0) ties and loses. */
[data-bs-theme="developer"] .table.table-cards {
    table-layout: auto;
}

[data-bs-theme="developer"] .table thead th,
[data-bs-theme="developer"] .table > thead > tr > th {
    white-space: nowrap;
}

/* ------------------------------------------------------------------------
   JSON Reader (global styles)
   NOTE: JsonReader.razor.css is CSS-isolated and does not apply to elements
   created dynamically via JavaScript (missing Blazor scope attribute).
   These global selectors ensure Dymo tables/groups/toggles are actually styled.
   ------------------------------------------------------------------------ */

.json-reader-tool .structured details.node-object > summary {
    font-size: 0.95rem;
}

.json-reader-tool .structured details.node-object > summary.is-by-group {
    background: color-mix(in srgb, var(--bs-primary) 12%, var(--bs-secondary-bg) 88%);
    border-left: 4px solid color-mix(in srgb, var(--bs-primary) 55%, var(--bs-border-color) 45%);
}

.json-reader-tool .section-header,
.json-reader-tool .cluster-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    margin-bottom: 0.55rem;
    padding-bottom: 0.45rem;
    border-bottom: 1px dashed var(--bs-border-color);
}

.json-reader-tool .section-header h4,
.json-reader-tool .cluster-header h4 {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 700;
    flex: 1 1 auto;
    min-width: 0;
}

.json-reader-tool .toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    margin-left: auto;
    min-width: 92px;
    height: 32px;
    padding: 0 0.7rem;
    border-radius: 999px;
    border: 1px solid var(--bs-border-color);
    background: var(--bs-body-bg);
    color: var(--bs-emphasis-color);
    font-size: 0.78rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
}

.json-reader-tool .toggle-btn:hover {
    border-color: var(--bs-primary);
}

.json-reader-tool .collapsed .table-wrap {
    display: none;
}

.json-reader-tool .table-wrap {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    margin: 0.5rem 0;
    padding-bottom: 0.15rem;
}

/* Scrollable data tables – matches ApoTune Analyse .scroll-t pattern */
.json-reader-tool .scroll-t {
    max-height: 320px;
    overflow-y: auto;
}

.json-reader-tool .scroll-t::-webkit-scrollbar {
    width: 3px;
}

.json-reader-tool .scroll-t::-webkit-scrollbar-thumb {
    background: var(--bs-border-color);
    border-radius: 2px;
}

.json-reader-tool .kv {
    width: 100%;
    min-width: 0;
    table-layout: auto;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 0.93rem;
}

.json-reader-tool .kv th,
.json-reader-tool .kv td {
    border-bottom: 1px solid var(--bs-border-color);
    text-align: left;
    vertical-align: top;
    padding: 0.56rem 0.85rem;
    min-width: 120px;
    white-space: normal;
    word-break: break-word;
    overflow-wrap: anywhere;
    line-height: 1.38;
}

.json-reader-tool .kv td {
    min-width: 150px;
}

.json-reader-tool .kv th {
    font-weight: 600;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--jrt-muted, #6B7A99);
    background: transparent;
}

[data-color-mode="dark"] .json-reader-tool .kv th {
    color: var(--bs-secondary-color);
    background: transparent;
}

.json-reader-tool .kv tbody th {
    min-width: 150px;
}

@media (max-width: 992px) {
    .json-reader-tool .kv {
        font-size: 0.9rem;
    }

    .json-reader-tool .kv th,
    .json-reader-tool .kv td {
        padding: 0.5rem 0.7rem;
        min-width: 100px;
    }
}

.json-reader-tool .status {
    margin-top: 0.35rem;
    margin-bottom: 0.8rem;
}

.json-reader-tool .summary-grid {
    margin-top: 0.25rem;
    margin-bottom: 0.9rem;
    gap: 0.7rem;
}

/* Summary cards: styled as ApoTune Analyse metric cards */
.json-reader-tool .summary-grid .card {
    background: var(--jrt-white, #fff);
    border: 1px solid var(--jrt-border, #DDE3EE);
    border-radius: 10px;
    padding: 14px 16px;
    box-shadow: var(--jrt-shadow-sm, 0 1px 4px rgba(27,42,74,.06));
}

[data-color-mode="dark"] .json-reader-tool .summary-grid .card {
    background: var(--bs-secondary-bg);
    border-color: var(--bs-border-color);
    box-shadow: none;
}

/* h3 = metric label (small, muted) */
.json-reader-tool .summary-grid .card h3 {
    font-size: 0.7rem !important;
    font-weight: 600;
    line-height: 1.2;
    margin-bottom: 5px;
    color: var(--jrt-muted, #6B7A99);
    text-transform: none;
    letter-spacing: 0;
}

[data-color-mode="dark"] .json-reader-tool .summary-grid .card h3 {
    color: var(--bs-secondary-color);
}

/* p = metric value (large, navy, bold) */
.json-reader-tool .summary-grid .card p {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.15;
    color: var(--jrt-navy, #1B2A4A);
    margin: 0;
}

[data-color-mode="dark"] .json-reader-tool .summary-grid .card p {
    color: var(--bs-emphasis-color);
}

/* Colored value states (ok/warning/error on the p element) */
.json-reader-tool .summary-grid .card .card-value-ok    { color: var(--jrt-ok,   #22894A); }
.json-reader-tool .summary-grid .card .card-value-warning { color: var(--jrt-warn, #B86400); }
.json-reader-tool .summary-grid .card .card-value-error { color: var(--jrt-err,  #C0392B); }

/* ── Page subtitle: // hint already done above; nothing further needed ── */

/* ── Pharmacies: JSON-card view in dev mode ────────────────────────────
   Pharmacies.razor renders both a table (default) and a JSON-card list
   (.pharmacies-json-view). The two share the same Virtualize source, so
   the active view is decided purely by display gates here.
   Light/Dark — hide JSON view, show table.
   Developer  — hide table, show JSON view. */
.pharmacies-json-view {
    display: none;
}

[data-bs-theme="developer"] .pharmacies-table-view {
    display: none;
}

/* CSS Grid with auto-fill columns so the cards pack side-by-side and
   make use of the horizontal space (one column per ~320px wide). Region
   headers span all columns to keep groups visually separated. Single-
   pharmacy regions still get a full row (the header forces a new row,
   then the lone card fills column 1 and the rest of the row stays
   empty — no implicit re-flow across region boundaries). */
[data-bs-theme="developer"] .pharmacies-json-view {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 0.75rem;
    align-content: start;
    width: 100%;
    height: calc(100dvh - 220px);
    min-height: 320px;
    padding: 0.75rem 0.85rem 1rem;
    overflow-y: auto;
    box-sizing: border-box;
}

[data-bs-theme="developer"] .pharmacy-json-region,
[data-bs-theme="developer"] .pharmacy-json-empty,
[data-bs-theme="developer"] .pharmacy-json-more {
    grid-column: 1 / -1;
}

[data-bs-theme="developer"] .pharmacy-json-region {
    color: var(--dm-accent);
    font-family: var(--bs-font-mono);
    font-size: 0.85rem;
    font-weight: 600;
    margin: 0.75rem 0 0.35rem;
    padding-top: 0.5rem;
    border-top: 1px dashed var(--dm-accent-soft);
}

[data-bs-theme="developer"] .pharmacy-json-region:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

[data-bs-theme="developer"] .pharmacy-json-empty,
[data-bs-theme="developer"] .pharmacy-json-more {
    padding: 0.75rem;
    text-align: center;
    color: var(--bs-secondary-color);
    font-family: var(--bs-font-mono);
    font-size: 0.78rem;
}

[data-bs-theme="developer"] .pharmacy-json-more {
    margin-top: 0.5rem;
    border-top: 1px dashed var(--bs-border-color);
    color: var(--dm-accent);
}

[data-bs-theme="developer"] .pharmacy-json-card {
    margin: 0;
    padding: 0.5rem 0.65rem 0.6rem;
    background: transparent;
    /* Flex column so the JSON body grows to fill remaining card height —
       grid's default align-items:stretch already makes every card in a
       row the same height; flex:1 on the body lets the inner JSON pre
       expand evenly when one card's address wraps to two lines. */
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    /* Subtle dashed slate-blue frame (custom dash pattern: 7px stroke +
       5px gap) so each card reads as a discrete "file" without competing
       with the amber outer card frame. */
    border: none;
    background-image:
        repeating-linear-gradient(to right,  rgba(148, 163, 184, 0.25) 0 7px, transparent 7px 12px),
        repeating-linear-gradient(to right,  rgba(148, 163, 184, 0.25) 0 7px, transparent 7px 12px),
        repeating-linear-gradient(to bottom, rgba(148, 163, 184, 0.25) 0 7px, transparent 7px 12px),
        repeating-linear-gradient(to bottom, rgba(148, 163, 184, 0.25) 0 7px, transparent 7px 12px);
    background-position: 0 0, 0 100%, 0 0, 100% 0;
    background-repeat: no-repeat;
    background-size: 100% 1px, 100% 1px, 1px 100%, 1px 100%;
    /* Grid cell handles outer spacing — see .pharmacies-json-view's gap. */
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-json-body {
    /* Grow to fill remaining vertical space inside the flex card so all
       bodies in the same grid row visually align top + bottom. */
    flex: 1;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-json-path {
    color: var(--bs-secondary-color);
    font-family: var(--bs-font-mono);
    font-size: 0.78rem;
    margin-bottom: 0.15rem;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-json-body {
    margin: 0;
    padding: 0.5rem 0.75rem;
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 0;
    color: var(--bs-body-color);
    font-family: var(--bs-font-mono);
    font-size: 0.78rem;
    line-height: 1.4;
    /* pre-wrap (not pre) lets long values fold to the next line so the card never needs a horizontal scrollbar; max-height removed so the full document is always visible — small per-pharmacy doc, no vertical scrolling needed either. */
    white-space: pre-wrap;
    word-break: break-word;
    overflow: visible;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-json-body code {
    background: transparent;
    padding: 0;
    color: inherit;
    font-family: inherit;
    font-size: inherit;
    white-space: inherit;
}

/* Inherit the JSON token palette established by B-S18 (.dev-only-json
   uses the same selectors). Re-apply here for the new container so the
   highlighter wraps tokens with the same colors. */
[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-json-body .token.json-key {
    color: #59c2ff;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-json-body .token.json-string {
    color: #aad94c;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-json-body .token.json-number {
    color: #d2a6ff;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-json-body .token.json-boolean {
    color: #ffb454;
    font-weight: 600;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-json-body .token.json-null {
    color: #f29668;
    font-style: italic;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-json-actions {
    display: flex;
    gap: 0.75rem;
    margin-top: 0.25rem;
    padding-left: 0.25rem;
    flex-wrap: wrap;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-cli-link {
    background: none;
    border: none;
    padding: 0;
    color: var(--bs-secondary-color);
    font-family: var(--bs-font-mono);
    font-size: 0.78rem;
    cursor: pointer;
    text-decoration: none;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-cli-link:hover {
    color: var(--dm-accent);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-cli-link.pharmacy-cli-link-primary {
    color: var(--dm-accent);
}

[data-bs-theme="developer"] .pharmacy-json-card .pharmacy-cli-link.pharmacy-cli-link-primary:hover {
    color: #ffd580;
}

/* ════════════════════════════════════════════════════════════════════════
   Developer theme — extended component pass (B-S20 stage 4)
   ═════════════════════════════════════════════════════════════════╔═══════
   Polish for Bootstrap components that B-S11/Stage-2 didn't touch:
   nav-tabs, list-group, pagination, alerts (with [INFO]/[WARN] prefixes),
   progress, breadcrumb, spinner, bg-body-tertiary/secondary.
   ════════════════════════════════════════════════════════════════════════ */

/* ── nav-tabs: IDE editor-tab strip ───────────────────────────────────── */
[data-bs-theme="developer"] .nav-tabs {
    border-bottom: 1px solid var(--dm-accent-soft);
    gap: 0;
}

[data-bs-theme="developer"] .nav-tabs .nav-link {
    border: none;
    border-radius: 0;
    border-bottom: 2px solid transparent;
    color: var(--bs-secondary-color);
    font-family: var(--bs-font-mono);
    font-size: 0.82rem;
    padding: 0.4rem 0.85rem;
    background: transparent;
}

[data-bs-theme="developer"] .nav-tabs .nav-link:hover {
    color: var(--dm-accent);
    background: var(--bs-tertiary-bg);
}

[data-bs-theme="developer"] .nav-tabs .nav-link.active {
    color: var(--dm-accent);
    background: var(--bs-tertiary-bg);
    border-bottom-color: var(--dm-accent);
}

/* ── list-group: terminal list rows ──────────────────────────────────── */
[data-bs-theme="developer"] .list-group {
    border-radius: 0;
    border: 1px solid var(--bs-border-color);
}

[data-bs-theme="developer"] .list-group-item {
    border-radius: 0;
    background: transparent;
    border-color: var(--bs-border-color);
    color: var(--bs-body-color);
    font-family: var(--bs-font-mono);
    font-size: 0.82rem;
    padding: 0.4rem 0.7rem;
}

[data-bs-theme="developer"] .list-group-item:hover {
    background: var(--bs-tertiary-bg);
    color: var(--bs-emphasis-color);
}

[data-bs-theme="developer"] .list-group-item.active {
    background: var(--dm-accent-soft);
    color: var(--dm-accent);
    border-color: var(--dm-accent-soft);
}

/* ── pagination: square segmented strip ─────────────────────────────── */
[data-bs-theme="developer"] .pagination {
    gap: 0;
}

[data-bs-theme="developer"] .page-item .page-link {
    border-radius: 0;
    background: transparent;
    border-color: var(--bs-border-color);
    color: var(--bs-secondary-color);
    font-family: var(--bs-font-mono);
    font-size: 0.78rem;
    padding: 0.3rem 0.65rem;
}

[data-bs-theme="developer"] .page-item .page-link:hover {
    background: var(--dm-accent-soft);
    border-color: var(--dm-accent-soft);
    color: var(--dm-accent);
}

[data-bs-theme="developer"] .page-item.active .page-link {
    background: var(--dm-accent);
    border-color: var(--dm-accent);
    color: #0a0e14;
}

[data-bs-theme="developer"] .page-item.disabled .page-link {
    background: transparent;
    border-color: var(--bs-border-color);
    color: var(--bs-secondary-color);
    opacity: 0.5;
}

/* ── alerts: bracketed [INFO]/[WARN]/[ERR]/[OK] prefix ────────────────── */
[data-bs-theme="developer"] .alert {
    border-radius: 0;
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-left-width: 3px;
    color: var(--bs-body-color);
    font-family: var(--bs-font-mono);
    font-size: 0.82rem;
    padding: 0.5rem 0.75rem;
}

[data-bs-theme="developer"] .alert-info {
    border-left-color: #59c2ff;
}

[data-bs-theme="developer"] .alert-info::before {
    content: "[INFO] ";
    color: #59c2ff;
    font-weight: 600;
}

[data-bs-theme="developer"] .alert-warning {
    border-left-color: var(--dm-accent);
}

[data-bs-theme="developer"] .alert-warning::before {
    content: "[WARN] ";
    color: var(--dm-accent);
    font-weight: 600;
}

[data-bs-theme="developer"] .alert-danger {
    border-left-color: #f07178;
}

[data-bs-theme="developer"] .alert-danger::before {
    content: "[ERR] ";
    color: #f07178;
    font-weight: 600;
}

[data-bs-theme="developer"] .alert-success {
    border-left-color: #aad94c;
}

[data-bs-theme="developer"] .alert-success::before {
    content: "[OK] ";
    color: #aad94c;
    font-weight: 600;
}

[data-bs-theme="developer"] .alert .btn-close {
    filter: invert(0.6) sepia(1) saturate(5) hue-rotate(20deg);
    opacity: 0.7;
}

/* ── progress: square + amber ────────────────────────────────────────── */
[data-bs-theme="developer"] .progress {
    border-radius: 0;
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    height: 0.75rem;
}

[data-bs-theme="developer"] .progress-bar {
    background-color: var(--dm-accent);
    color: #0a0e14;
    font-family: var(--bs-font-mono);
    font-size: 0.7rem;
}

/* ── breadcrumb: command-style path ──────────────────────────────────── */
[data-bs-theme="developer"] .breadcrumb {
    background: transparent;
    font-family: var(--bs-font-mono);
    font-size: 0.82rem;
    margin-bottom: 0.5rem;
    padding: 0;
}

[data-bs-theme="developer"] .breadcrumb::before {
    content: "$ cd ";
    color: var(--dm-accent);
    font-weight: 600;
    margin-right: 0.25rem;
}

[data-bs-theme="developer"] .breadcrumb-item {
    color: var(--bs-secondary-color);
}

[data-bs-theme="developer"] .breadcrumb-item a {
    color: var(--bs-secondary-color);
    text-decoration: none;
}

[data-bs-theme="developer"] .breadcrumb-item a:hover {
    color: var(--dm-accent);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

[data-bs-theme="developer"] .breadcrumb-item.active {
    color: var(--bs-emphasis-color);
}

[data-bs-theme="developer"] .breadcrumb-item + .breadcrumb-item::before {
    content: "/";
    color: var(--bs-secondary-color);
}

/* ── spinner: amber ring + loading… text ─────────────────────────────── */
[data-bs-theme="developer"] .spinner-border {
    color: var(--dm-accent) !important;
    border-width: 2px;
}

[data-bs-theme="developer"] .spinner-border.text-primary,
[data-bs-theme="developer"] .spinner-border.text-light {
    color: var(--dm-accent) !important;
}

/* ── bg-body-tertiary / -secondary (Pharmacies launch-settings panel,
   Roles editor): keep them within the dev palette instead of leaking
   the light theme's pale grey. ─────────────────────────────────────── */
[data-bs-theme="developer"] .bg-body-tertiary {
    background-color: var(--bs-tertiary-bg) !important;
    color: var(--bs-body-color);
    border-color: var(--bs-border-color) !important;
}

[data-bs-theme="developer"] .bg-body-secondary {
    background-color: var(--bs-secondary-bg) !important;
    color: var(--bs-body-color);
    border-color: var(--bs-border-color) !important;
}

/* ── form-text / hint utilities: // comment style ────────────────────── */
[data-bs-theme="developer"] .form-text {
    font-family: var(--bs-font-mono);
    font-size: 0.72rem;
    color: var(--bs-secondary-color) !important;
}

[data-bs-theme="developer"] .form-text::before {
    content: "// ";
    color: var(--dm-accent);
}

/* ── dropdown-menu: square + mono ────────────────────────────────────── */
[data-bs-theme="developer"] .dropdown-menu {
    border-radius: 0;
    background: var(--bs-card-bg);
    border-color: var(--dm-accent-soft);
    font-family: var(--bs-font-mono);
    font-size: 0.82rem;
}

[data-bs-theme="developer"] .dropdown-item {
    color: var(--bs-body-color);
    padding: 0.3rem 0.7rem;
}

[data-bs-theme="developer"] .dropdown-item:hover,
[data-bs-theme="developer"] .dropdown-item:focus {
    background: var(--dm-accent-soft);
    color: var(--dm-accent);
}

[data-bs-theme="developer"] .dropdown-divider {
    border-color: var(--dm-accent-soft);
}

/* ── ToolDetail readme markdown frame ────────────────────────────────── */
[data-bs-theme="developer"] .markdown-body,
[data-bs-theme="developer"] .readme-content {
    font-family: var(--bs-font-mono);
    font-size: 0.85rem;
    color: var(--bs-body-color);
}

[data-bs-theme="developer"] .markdown-body pre,
[data-bs-theme="developer"] .readme-content pre {
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 0;
    padding: 0.5rem 0.75rem;
}

[data-bs-theme="developer"] .markdown-body code,
[data-bs-theme="developer"] .readme-content code {
    background: var(--bs-tertiary-bg);
    color: var(--dm-accent);
    padding: 0.1rem 0.3rem;
    border-radius: 0;
    font-family: var(--bs-font-mono);
}

/* ── Empty / placeholder rows in tables (no-results states) ──────────── */
[data-bs-theme="developer"] .table tbody tr td.text-center.text-muted {
    color: var(--bs-secondary-color);
    font-family: var(--bs-font-mono);
    font-size: 0.8rem;
}

/* ── Sticky table headers in dev: square + amber dividing line ───────── */
[data-bs-theme="developer"] .pharmacies-thead-sticky,
[data-bs-theme="developer"] thead.table-light {
    background: var(--bs-tertiary-bg);
    border-bottom: 1px solid var(--dm-accent-soft);
}

/* ── Global scrollbar styling in dev — dark, narrow, amber-tinted ─────── */
/* Webkit (Chromium / Safari): thin amber thumb on transparent track. */
[data-bs-theme="developer"] *::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

[data-bs-theme="developer"] *::-webkit-scrollbar-track {
    background: transparent;
}

[data-bs-theme="developer"] *::-webkit-scrollbar-thumb {
    background: rgba(255, 180, 84, 0.18);
    border-radius: 0;
}

[data-bs-theme="developer"] *::-webkit-scrollbar-thumb:hover {
    background: rgba(255, 180, 84, 0.35);
}

[data-bs-theme="developer"] *::-webkit-scrollbar-corner {
    background: transparent;
}

/* Firefox */
[data-bs-theme="developer"] {
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 180, 84, 0.2) transparent;
}

/* ── Pharmacies "Gelöscht/deleted" status filter — red in dev ─────────── */
/* Selecting "deleted" filters the list to deactivated pharmacies, so the
   active state reads as a destructive/warning surface (#f07178 = the
   coral red the rest of the dev palette uses for danger). Light/dark
   keep the secondary-grey active state from the scoped CSS. */
[data-bs-theme="developer"] .status-filter-btn.is-active-inaktiv {
    background-color: rgba(240, 113, 120, 0.18) !important;
    color: #f07178 !important;
    border-color: #f07178 !important;
}

.json-reader-tool .summary-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.55rem;
    height: 1.4rem;
    padding: 0 0.42rem;
    margin-left: 0.42rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--bs-primary) 18%, var(--bs-secondary-bg) 82%);
    border: 1px solid color-mix(in srgb, var(--bs-primary) 35%, var(--bs-border-color) 65%);
    color: var(--bs-emphasis-color);
    font-size: 0.76rem;
    font-weight: 700;
    line-height: 1;
    vertical-align: middle;
}

.json-reader-tool .json-structured-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.json-reader-tool .json-structured-header h2 {
    margin: 0;
}

.json-reader-tool .json-structured-actions {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    flex-wrap: wrap;
}

/* ── JSON Reader: value coloring (in app.css — not Blazor-scoped so JS-created elements match) ── */

.json-reader-tool .val-bool-true {
    color: var(--bs-success);
    font-weight: 600;
}

.json-reader-tool .val-bool-false {
    color: var(--bs-danger);
    font-weight: 600;
}

.json-reader-tool .val-null {
    color: var(--bs-secondary-color);
}

/* ── JSON Reader: log-level row tinting ──────────────────────────────────── */

.json-reader-tool .row-error > td {
    background: color-mix(in srgb, var(--bs-danger) 8%, transparent 92%) !important;
}

.json-reader-tool .row-warning > td {
    background: color-mix(in srgb, var(--bs-warning) 8%, transparent 92%) !important;
}

/* ── JSON reader: health banner + inline card visuals ───────────────────── */

.json-reader-tool .health-banner {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    gap: 0.45rem;
    padding: 0.35rem 0 0.6rem;
}

.json-reader-tool .health-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.28rem 0.7rem;
    border-radius: 20px;
    font-size: 0.8rem;
    font-weight: 500;
    border: 1px solid;
    white-space: nowrap;
}

.json-reader-tool .health-pill-ok {
    background: var(--jrt-ok-bg,   #E6F6EC);
    border-color: var(--jrt-ok,    #22894A);
    color:        var(--jrt-ok,    #22894A);
}

.json-reader-tool .health-pill-warning {
    background: var(--jrt-warn-bg, #FFF4E0);
    border-color: var(--jrt-warn,  #B86400);
    color:        var(--jrt-warn,  #B86400);
}

.json-reader-tool .health-pill-error {
    background: var(--jrt-err-bg,  #FDECEA);
    border-color: var(--jrt-err,   #C0392B);
    color:        var(--jrt-err,   #C0392B);
}

[data-color-mode="dark"] .json-reader-tool .health-pill-ok { color: var(--bs-success); border-color: var(--bs-success); }
[data-color-mode="dark"] .json-reader-tool .health-pill-warning { color: var(--bs-warning); border-color: var(--bs-warning); }
[data-color-mode="dark"] .json-reader-tool .health-pill-error { color: var(--bs-danger); border-color: var(--bs-danger); }

.json-reader-tool .health-pill-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
}

.json-reader-tool .health-pill-ok .health-pill-dot      { background: var(--jrt-ok,   #22894A); }
.json-reader-tool .health-pill-warning .health-pill-dot { background: var(--jrt-warn, #B86400); }
.json-reader-tool .health-pill-error .health-pill-dot   { background: var(--jrt-err,  #C0392B); }

/* Inline card visuals */
.json-reader-tool .card-visual { margin-top: 0.45rem; width: 100%; }

.json-reader-tool .card-progress-bar {
    height: 5px;
    background: #EEF1F7;
    border-radius: 3px;
    margin-top: 6px;
    overflow: hidden;
}

[data-color-mode="dark"] .json-reader-tool .card-progress-bar {
    background: var(--bs-border-color);
}

.json-reader-tool .card-progress-fill {
    height: 100%;
    border-radius: 3px;
    transition: width 0.4s ease;
}

.json-reader-tool .card-progress-ok .card-progress-fill      { background: var(--jrt-ok,   #22894A); }
.json-reader-tool .card-progress-warning .card-progress-fill { background: var(--jrt-warn, #B86400); }
.json-reader-tool .card-progress-error .card-progress-fill   { background: var(--jrt-err,  #C0392B); }

.json-reader-tool .card-server-dots {
    display: flex;
    flex-wrap: wrap;
    gap: 3px;
}

.json-reader-tool .server-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
}

.json-reader-tool .dot-ok { background: #2ecc71; }
.json-reader-tool .dot-error { background: #e74c3c; }

.json-reader-tool .card-level-bar {
    height: 7px;
    display: flex;
    border-radius: 3px;
    overflow: hidden;
    gap: 1px;
}

.json-reader-tool .level-segment { flex-shrink: 0; min-width: 2px; }

/* ── JSON reader: plain log viewer ─────────────────────────────────────── */

.json-reader-tool .plain-log-content {
    display: block;
    background: var(--bs-secondary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    padding: 1rem;
    font-family: 'Cascadia Code', 'Fira Mono', 'Consolas', monospace;
    font-size: 0.8rem;
    line-height: 1.6;
    overflow-x: auto;
    white-space: pre;
}

.json-reader-tool .log-line {
    display: block;
}

.json-reader-tool .log-line-error {
    color: #e74c3c;
    background: rgba(231, 76, 60, 0.07);
}

.json-reader-tool .log-line-warn {
    color: #b7770d;
}

.json-reader-tool .log-line-info {
    color: var(--bs-primary);
}

/* ── JSON reader: DymoTextLog viewer ───────────────────────────────────── */

.json-reader-tool .dymo-text-log-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
    margin-bottom: 0.75rem;
    font-size: 0.875rem;
}

.json-reader-tool .log-level-toggle {
    padding: 0.2rem 0.75rem;
    border-width: 1px;
    border-style: solid;
    border-radius: 20px;
    font-size: 0.8rem;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}

.json-reader-tool .dymo-text-log-container {
    border: 1px solid var(--bs-border-color);
    border-radius: 8px;
    overflow: hidden;
}

.json-reader-tool .dymo-text-log-pre {
    border: none;
    border-radius: 0;
    max-height: 480px;
    overflow-y: auto;
    margin: 0;
}

.json-reader-tool .log-line-warning {
    color: #8a5f00;
}

.json-reader-tool .log-line-debug {
    color: #95a5a6;
    opacity: 0.75;
}

[data-color-mode="dark"] .json-reader-tool .log-line-warning {
    color: #f5b942;
}

[data-color-mode="dark"] .json-reader-tool .log-line-debug {
    color: #636e72;
}

.json-reader-tool .log-line-problem {
    background: rgba(231, 76, 60, 0.1);
    border-left: 3px solid #e74c3c;
    padding-left: 6px;
    font-weight: 600;
}

.json-reader-tool .log-line-warnung {
    background: rgba(243, 156, 18, 0.08);
    border-left: 3px solid #f39c12;
    padding-left: 6px;
}


/* Missing-plugins list inside a summary card */
.json-reader-tool .plugin-missing-list {
    margin: 0.4rem 0 0 0;
    padding-left: 1.1rem;
    font-size: 0.78rem;
    color: var(--bs-warning-text-emphasis, #664d03);
    list-style: disc;
}

[data-color-mode="dark"] .json-reader-tool .plugin-missing-list {
    color: #f5b942;
}

/* ════════════════════════════════════════════════════════════════════════
   JSON Reader – global jrt-* base classes + insight groups

   Global (unscoped) so both the standalone /json-reader page AND the
   JsonViewerModal pick up the same base styles. JsonReader.razor.css adds
   higher-specificity scoped overrides for the standalone page.
   JsonViewerModal.razor.css provides modal-specific layout tweaks.
   ════════════════════════════════════════════════════════════════════════ */

/* ── Design tokens (global – unscoped so modal inherits them too) ─────
   Bridged onto the ApoTune --ds-* tokens (see tokens.css): navy → ink, cyan
   accent → action blue, status straight through the brand feedback tokens.
   Mirror of the scoped block in JsonReader.razor.css; this global copy is what
   actually styles the JS-injected content and the modal. */
.json-reader-tool {
    --jrt-navy:      var(--ds-color-text-primary);
    --jrt-navy2:     var(--ds-color-text-primary);
    --jrt-cyan:      var(--ds-color-action-primary);
    --jrt-cyan-bg:   var(--ds-color-action-selected-tint);
    --jrt-text:      var(--ds-color-text-primary);
    --jrt-muted:     var(--ds-color-text-secondary);
    --jrt-border:    var(--ds-color-border-strong);
    --jrt-bg:        var(--ds-color-surface-canvas);
    --jrt-white:     var(--ds-color-surface-base);
    --jrt-ok:    var(--ds-color-feedback-success);
    --jrt-ok-bg: color-mix(in srgb, var(--ds-color-feedback-success) 16%, var(--ds-color-surface-base) 84%);
    --jrt-warn:      var(--ds-color-feedback-warning);  --jrt-warn-bg: var(--ds-color-feedback-warning-surface);
    --jrt-err:       var(--ds-color-feedback-error);    --jrt-err-bg:  var(--ds-color-feedback-error-surface);
    --jrt-info:      var(--ds-color-feedback-info);     --jrt-info-bg: var(--ds-color-action-selected-tint);
    --jrt-shadow:    0 2px 8px rgba(43,56,62,.10);
    --jrt-shadow-sm: 0 1px 4px rgba(43,56,62,.06);

    /* Shared aliases — also defined in the scoped block, but the modal and
       JS-injected content live outside that scope, so they must resolve here
       too (otherwise var(--accent)/var(--heading) fall back to navy/cyan). */
    --bg:          var(--jrt-bg);
    --surface:     var(--jrt-white);
    --surface-soft:var(--jrt-bg);
    --heading:     var(--jrt-navy);
    --row-alt:     color-mix(in srgb, var(--ds-color-surface-base) 92%, var(--ds-color-text-primary) 8%);
    --text:        var(--jrt-text);
    --muted:       var(--jrt-muted);
    --accent:      var(--jrt-cyan);
    --border:      var(--jrt-border);
    --success:     var(--jrt-ok);
    --danger:      var(--jrt-err);
    --shadow:      var(--jrt-shadow);
    --shadow-soft: var(--jrt-shadow-sm);
}

[data-color-mode="dark"] .json-reader-tool {
    --jrt-navy:   var(--bs-emphasis-color);
    --jrt-cyan:   var(--bs-primary);
    --jrt-text:   var(--bs-body-color);
    --jrt-muted:  var(--bs-secondary-color);
    --jrt-border: var(--bs-border-color);
    --jrt-bg:     var(--bs-body-bg);
    --jrt-white:  var(--bs-secondary-bg);
}

/* ── Section navigation tab bar ──────────────────────────────────────
   NOTE: in the modal the nav sits OUTSIDE .json-reader-tool (between
   .modal-header and .modal-body), so --jrt-* vars are unavailable here.
   Background uses a hardcoded value; dark override uses Bootstrap vars. */
.jrt-section-nav {
    display: flex;
    align-items: stretch;
    background: var(--ds-color-text-primary);
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none; /* Firefox */
}
.jrt-section-nav::-webkit-scrollbar { display: none; } /* Chrome/Safari */

[data-color-mode="dark"] .jrt-section-nav {
    background: var(--bs-secondary-bg);
    border-bottom: 2px solid var(--bs-border-color);
}

.jrt-nav-tab {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 11px 18px;
    font-size: 0.78125rem;
    font-weight: 500;
    color: rgba(255,255,255,.6);
    background: transparent;
    border: none;
    border-bottom: 3px solid transparent;
    cursor: pointer;
    white-space: nowrap;
    transition: background .12s, color .12s, border-color .12s;
    user-select: none;
}

.jrt-nav-tab .bi { font-size: 0.9375rem; flex-shrink: 0; }

.jrt-nav-tab:hover {
    background: rgba(255,255,255,.07);
    color: #fff;
}

.jrt-nav-tab--active {
    color: var(--ds-color-action-primary) !important;
    border-bottom-color: var(--ds-color-action-primary) !important;
    background: color-mix(in srgb, var(--ds-color-action-primary) 10%, transparent) !important;
}

[data-color-mode="dark"] .jrt-nav-tab { color: var(--bs-secondary-color); }

[data-color-mode="dark"] .jrt-nav-tab:hover {
    color: var(--bs-emphasis-color);
    background: var(--bs-tertiary-bg);
}

[data-color-mode="dark"] .jrt-nav-tab--active {
    color: var(--bs-primary) !important;
    border-bottom-color: var(--bs-primary) !important;
    background: color-mix(in srgb, var(--bs-primary) 10%, transparent 90%) !important;
}

/* ── Sections: hidden by default, shown when active ─────────────────── */
.jrt-section { display: none; }
.jrt-section--active { display: block; }

/* ── File info topbar ────────────────────────────────────────────────── */
.jrt-file-topbar {
    background: var(--jrt-white, #fff);
    border: 1px solid var(--jrt-border, #DDE3EE);
    border-top: none;
    padding: 8px 20px;
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 2.4rem;
}

[data-color-mode="dark"] .jrt-file-topbar {
    background: var(--bs-secondary-bg);
    border-color: var(--bs-border-color);
}

.jrt-file-topbar-left {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.jrt-file-topbar .status {
    margin: 0;
    font-size: 0.75rem;
    font-weight: 600;
}

.jrt-file-topbar .file-type-banner {
    margin: 0;
    padding: 3px 10px;
    font-size: 0.75rem;
    border-radius: 99px;
    background: color-mix(in srgb, var(--ds-color-action-primary) 12%, var(--ds-color-surface-base) 88%);
    border: 1px solid color-mix(in srgb, var(--ds-color-action-primary) 30%, var(--ds-color-border-strong) 70%);
}

.jrt-file-topbar .file-type-banner.visible { display: inline-block; }

/* ── Card header / body pattern ─────────────────────────────────────── */
.jrt-ch {
    padding: 10px 16px;
    border-bottom: 1px solid var(--jrt-border, #DDE3EE);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    background: var(--jrt-white, #fff);
    border-radius: 10px 10px 0 0;
}

[data-color-mode="dark"] .jrt-ch {
    background: var(--bs-secondary-bg);
    border-color: var(--bs-border-color);
}

.jrt-ct {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--jrt-navy, #1B2A4A);
    display: flex;
    align-items: center;
    gap: 7px;
}

.jrt-ct .bi {
    color: var(--jrt-cyan, #00C4CC);
    font-size: 0.9375rem;
}

[data-color-mode="dark"] .jrt-ct       { color: var(--bs-emphasis-color); }
[data-color-mode="dark"] .jrt-ct .bi   { color: var(--bs-primary); }

.jrt-ch-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: nowrap;
}

.jrt-ch-actions .json-search-input {
    max-width: 180px;
    border-radius: 999px;
    background: var(--jrt-bg, #F4F6FB);
    font-size: 0.75rem;
}

[data-color-mode="dark"] .jrt-ch-actions .json-search-input {
    background: var(--bs-body-bg);
}

.jrt-cb {
    padding: 14px 16px;
    background: var(--jrt-white, #fff);
    border-radius: 0 0 10px 10px;
}

[data-color-mode="dark"] .jrt-cb { background: var(--bs-secondary-bg); }

/* ── Panel wrapper (insights + structured sections) ─────────────────── */
.json-reader-tool .panel {
    border: 1px solid var(--jrt-border, #DDE3EE);
    border-radius: 10px;
    background: var(--jrt-white, #fff);
    padding: 0;
    overflow: hidden;
    margin-top: 0;
}

[data-color-mode="dark"] .json-reader-tool .panel {
    border-color: var(--bs-border-color);
    background: var(--bs-secondary-bg);
}

/* Panels inside insights/structured sections connect flush to the tab nav */
.json-reader-tool .jrt-section[data-section="insights"] .panel,
.json-reader-tool .jrt-section[data-section="structured"] .panel {
    border-radius: 0 0 10px 10px;
    border-top: none;
}

/* ── Insight groups (alert-box style: error / warning / ok) ─────────── */
.json-reader-tool .insight-group {
    border-radius: 9px;
    margin-bottom: 8px;
    font-size: 0.75rem;
    overflow: hidden;
}

.json-reader-tool .insight-group-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    font-weight: 600;
    font-size: 0.75rem;
}

.json-reader-tool .insight-item {
    padding: 4px 12px 4px 32px;
    font-size: 0.75rem;
    line-height: 1.45;
}

.json-reader-tool .insight-item:last-child { padding-bottom: 8px; }

/* Error */
.json-reader-tool .insight-group-error {
    background: var(--jrt-err-bg, #FDECEA);
    border: 1px solid #F5C6C2;
}

.json-reader-tool .insight-group-error .insight-group-header,
.json-reader-tool .insight-group-error .insight-item {
    color: var(--jrt-err, #C0392B);
}

/* Warning */
.json-reader-tool .insight-group-warning {
    background: var(--jrt-warn-bg, #FFF4E0);
    border: 1px solid #F5D8A0;
}

.json-reader-tool .insight-group-warning .insight-group-header,
.json-reader-tool .insight-group-warning .insight-item {
    color: var(--jrt-warn, #B86400);
}

/* OK */
.json-reader-tool .insight-group-ok {
    background: var(--jrt-ok-bg, #E6F6EC);
    border: 1px solid #B7DEC8;
}

.json-reader-tool .insight-group-ok .insight-group-header,
.json-reader-tool .insight-group-ok .insight-item {
    color: var(--jrt-ok, #22894A);
}

/* Dark-mode insight groups */
[data-color-mode="dark"] .json-reader-tool .insight-group-error {
    background: color-mix(in srgb, var(--bs-danger) 10%, var(--bs-body-bg) 90%);
    border-color: color-mix(in srgb, var(--bs-danger) 30%, var(--bs-border-color) 70%);
}

[data-color-mode="dark"] .json-reader-tool .insight-group-error .insight-group-header,
[data-color-mode="dark"] .json-reader-tool .insight-group-error .insight-item {
    color: var(--bs-danger-text-emphasis, #f5b942);
}

[data-color-mode="dark"] .json-reader-tool .insight-group-warning {
    background: color-mix(in srgb, var(--bs-warning) 10%, var(--bs-body-bg) 90%);
    border-color: color-mix(in srgb, var(--bs-warning) 30%, var(--bs-border-color) 70%);
}

[data-color-mode="dark"] .json-reader-tool .insight-group-warning .insight-group-header,
[data-color-mode="dark"] .json-reader-tool .insight-group-warning .insight-item {
    color: var(--bs-warning-text-emphasis, #f5b942);
}

[data-color-mode="dark"] .json-reader-tool .insight-group-ok {
    background: color-mix(in srgb, var(--bs-success) 10%, var(--bs-body-bg) 90%);
    border-color: color-mix(in srgb, var(--bs-success) 30%, var(--bs-border-color) 70%);
}

[data-color-mode="dark"] .json-reader-tool .insight-group-ok .insight-group-header,
[data-color-mode="dark"] .json-reader-tool .insight-group-ok .insight-item {
    color: var(--bs-success-text-emphasis, #2ecc71);
}

/* ── JSON Reader: metrics grid (JS-injected, must be global) ─────── */
.json-reader-tool .jrt-metrics-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
    margin-bottom: 1rem;
}
@media (max-width: 900px) {
    .json-reader-tool .jrt-metrics-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
    .json-reader-tool .jrt-metrics-grid { grid-template-columns: 1fr; }
}

/* ── JSON Reader: metric cards ────────────────────────────────────── */
.json-reader-tool .jrt-metric-card {
    background: var(--surface, #fff);
    border: 1px solid var(--border, #DDE3EE);
    border-radius: 10px;
    padding: 14px 16px;
    box-shadow: var(--shadow-soft, 0 1px 4px rgba(27,42,74,.06));
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.json-reader-tool .jrt-metric-card.jrt-metric-err {
    border-color: var(--jrt-err, #C0392B);
    background: color-mix(in srgb, var(--jrt-err, #C0392B) 6%, var(--surface, #fff) 94%);
}

.json-reader-tool .jrt-metric-card.jrt-metric-warn {
    border-color: var(--jrt-warn, #B86400);
    background: color-mix(in srgb, var(--jrt-warn, #B86400) 6%, var(--surface, #fff) 94%);
}

.json-reader-tool .jrt-metric-icon {
    font-size: 1.125rem;
    color: var(--accent, #00C4CC);
    margin-bottom: 4px;
}

.json-reader-tool .jrt-metric-label {
    font-size: 0.625rem;
    font-weight: 600;
    color: var(--muted, #6B7A99);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.json-reader-tool .jrt-metric-value {
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--heading, #1B2A4A);
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.json-reader-tool .jrt-metric-card.jrt-metric-err .jrt-metric-value { color: var(--jrt-err, #C0392B); }
.json-reader-tool .jrt-metric-card.jrt-metric-warn .jrt-metric-value { color: var(--jrt-warn, #B86400); }

.json-reader-tool .jrt-metric-sub {
    font-size: 0.6875rem;
    color: var(--muted, #6B7A99);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

[data-color-mode="dark"] .json-reader-tool .jrt-metric-card {
    background: var(--bs-secondary-bg);
    border-color: var(--bs-border-color);
}

[data-color-mode="dark"] .json-reader-tool .jrt-metric-value {
    color: var(--bs-emphasis-color);
}

/* ── JSON Reader: alert list ──────────────────────────────────────── */
.json-reader-tool .jrt-alert-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.json-reader-tool .jrt-alert-item {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 7px 12px;
    border-radius: 7px;
    font-size: 0.78125rem;
    line-height: 1.4;
}

.json-reader-tool .jrt-alert-icon {
    font-size: 0.8125rem;
    flex-shrink: 0;
    margin-top: 1px;
}

.json-reader-tool .jrt-alert-item.aerr  { background: var(--jrt-err-bg, #FDECEA); color: var(--jrt-err, #C0392B); border-left: 3px solid var(--jrt-err, #C0392B); }
.json-reader-tool .jrt-alert-item.awarn { background: var(--jrt-warn-bg, #FFF4E0); color: var(--jrt-warn, #B86400); border-left: 3px solid var(--jrt-warn, #B86400); }
.json-reader-tool .jrt-alert-item.aok   { background: var(--jrt-ok-bg, #E6F6EC); color: var(--jrt-ok, #22894A); border-left: 3px solid var(--jrt-ok, #22894A); }

[data-color-mode="dark"] .json-reader-tool .jrt-alert-item.aerr  { background: color-mix(in srgb, var(--bs-danger) 12%, var(--bs-body-bg) 88%); color: var(--bs-danger); border-left-color: var(--bs-danger); }
[data-color-mode="dark"] .json-reader-tool .jrt-alert-item.awarn { background: color-mix(in srgb, var(--bs-warning) 12%, var(--bs-body-bg) 88%); color: var(--bs-warning); border-left-color: var(--bs-warning); }
[data-color-mode="dark"] .json-reader-tool .jrt-alert-item.aok   { background: color-mix(in srgb, var(--bs-success) 12%, var(--bs-body-bg) 88%); color: var(--bs-success); border-left-color: var(--bs-success); }

/* ── JSON Reader: generic section card ────────────────────────────── */
.json-reader-tool .jrt-card {
    border: 1px solid var(--border, #DDE3EE);
    border-radius: 10px;
    background: var(--surface, #fff);
    box-shadow: var(--shadow-soft, 0 1px 4px rgba(27,42,74,.06));
    overflow: hidden;
    margin-bottom: 12px;
}

.json-reader-tool .jrt-card:last-child { margin-bottom: 0; }

.json-reader-tool .jrt-card-header {
    padding: 10px 16px;
    border-bottom: 1px solid var(--border, #DDE3EE);
    background: var(--surface, #fff);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--heading, #1B2A4A);
    display: flex;
    align-items: center;
    gap: 7px;
}

.json-reader-tool .jrt-card-header .bi {
    color: var(--accent, #00C4CC);
    font-size: 0.9375rem;
}

.json-reader-tool .jrt-card-body {
    padding: 12px 16px;
}

.json-reader-tool .jrt-card-body.p-0 { padding: 0; }

[data-color-mode="dark"] .json-reader-tool .jrt-card {
    background: var(--bs-secondary-bg);
    border-color: var(--bs-border-color);
}

[data-color-mode="dark"] .json-reader-tool .jrt-card-header {
    background: var(--bs-secondary-bg);
    border-color: var(--bs-border-color);
    color: var(--bs-emphasis-color);
}

[data-color-mode="dark"] .json-reader-tool .jrt-card-header .bi {
    color: var(--bs-primary);
}

/* ── JSON Reader: section container inner padding ─────────────────── */
.json-reader-tool .applikationen-inner,
.json-reader-tool .plugins-inner,
.json-reader-tool .voraussetzungen-inner,
.json-reader-tool .netzwerk-inner,
.json-reader-tool .dateisystem-inner,
.json-reader-tool .sonstiges-inner {
    padding: 0;
}

/* ── JSON Reader: section-specific borders connecting to nav ──────── */
.json-reader-tool .applikationen-inner > .jrt-card:first-child,
.json-reader-tool .plugins-inner > .jrt-card:first-child,
.json-reader-tool .voraussetzungen-inner > .jrt-card:first-child,
.json-reader-tool .netzwerk-inner > .jrt-card:first-child,
.json-reader-tool .dateisystem-inner > .jrt-card:first-child {
    border-top: none;
    border-radius: 0 0 10px 10px;
}

.json-reader-tool .applikationen-inner > .jrt-card:not(:first-child),
.json-reader-tool .plugins-inner > .jrt-card:not(:first-child),
.json-reader-tool .voraussetzungen-inner > .jrt-card:not(:first-child),
.json-reader-tool .netzwerk-inner > .jrt-card:not(:first-child),
.json-reader-tool .dateisystem-inner > .jrt-card:not(:first-child) {
    border-radius: 10px;
    margin: 12px 12px 0;
}

.json-reader-tool .applikationen-inner,
.json-reader-tool .plugins-inner,
.json-reader-tool .voraussetzungen-inner,
.json-reader-tool .netzwerk-inner,
.json-reader-tool .dateisystem-inner {
    padding-bottom: 12px;
}

/* ── Responsive table → cards (shared utility) ─────────────────────────────
   Sub-page tables (plugins / files / devices …) collapse into stacked,
   labelled cards when their container gets too narrow to show every column
   on one line without sideways scrolling — the same treatment the pharmacies
   list uses, but reusable and driven from global CSS (these tables are plain
   page markup, not child components, so no ::deep is needed).

   Opt-in, three steps:
     1. put `table-cards-container` on an ancestor (usually the .card),
     2. put `table-cards` on each <table>,
     3. give each <td> that should show a field label a `data-label="…"`
        (cells without one render label-less and full-width — use for the
        card's title cell and the trailing actions cell).
   An inline continuation row (e.g. an expansion panel spanning colspan) can
   opt out of the card border/margin with `table-cards-skip`.

   Why a container query and not a media query: the sidebar makes the content
   area far narrower than the window, so a viewport breakpoint would leave a
   dead zone where the table is already cramped but the window is still wide.
   See Pharmacies.razor.css for the original rationale. Threshold 900px covers
   the widest of these tables (plugins = 7 cols, devices = 6). */
.table-cards-container {
    container: table-cards / inline-size;
}

@container table-cards (max-width: 900px) {
    .table-cards {
        min-width: 0 !important;
        table-layout: auto !important;
    }

    /* Column headers make no sense once each cell stacks onto its own line. */
    .table-cards > thead {
        display: none;
    }

    /* Collapse the table grid into block flow so rows become stacked cards. */
    .table-cards,
    .table-cards > tbody,
    .table-cards > tbody > tr,
    .table-cards > tbody > tr > td {
        display: block;
        width: auto;
    }

    /* Data rows → bordered cards on the page background (never a stray grey
       table row). Continuation rows opt out via .table-cards-skip. */
    .table-cards > tbody > tr:not(.table-cards-skip) {
        border: 1px solid var(--bs-border-color);
        border-radius: var(--bs-border-radius, 0.375rem);
        margin: 0.5rem 0.75rem;
        padding: 0.4rem 0.75rem;
        background-color: var(--bs-body-bg);
    }

    .table-cards > tbody > tr.table-cards-skip > td {
        padding: 0 !important;
    }

    /* Cells stack; drop table borders, cell backgrounds, widths, truncation. */
    .table-cards > tbody > tr > td {
        border: 0;
        padding: 0.15rem 0 !important;
        white-space: normal !important;
        overflow: visible;
        text-overflow: clip;
        max-width: none;
        background-color: transparent;
        box-shadow: none;
        text-align: left !important;
    }

    /* Labelled cells render as "Label ........ value" on one line. */
    .table-cards > tbody > tr > td[data-label]:not([data-label=""]) {
        display: flex;
        justify-content: space-between;
        align-items: baseline;
        gap: 1rem;
        text-align: right !important;
    }

    .table-cards > tbody > tr > td[data-label]:not([data-label=""])::before {
        content: attr(data-label);
        flex: 0 0 auto;
        font-weight: 600;
        text-align: left;
        white-space: nowrap;
        color: var(--bs-secondary-color);
    }
}

/* Bootstrap 5.3 ships no `.min-w-0` utility, yet several flex rows use it (tool cards, the
   favourites manager, pharmacy rows) so a `text-truncate` child can actually shrink and clip
   instead of overflowing — a flex item defaults to `min-width: auto`, which refuses to shrink
   below its content. Without this rule the class was a silent no-op: a long external-tool URL
   stretched the row and pushed the usage counter out of the card. */
.min-w-0 {
    min-width: 0 !important;
}

/* Changelog: the plain-language summary shown by default and in the "Was ist neu" popup. */
.changelog-summary {
    font-size: 1.05rem;
    line-height: 1.5;
    color: var(--bs-body-color);
    margin-bottom: 0.75rem;
}
