/* ==========================================================================
   PrymACE — Operations layer (an *extension* of public/css/prymace.css)
   ==========================================================================

   The visual language of the PrymACE System Controller and the five Pool
   operations boards (docs/images/FEATURE-GAPS/), plus the Market's resource
   flow pipeline.

   This file is no longer "a dark design of its own". It is a second layer on
   top of the admin design system, and it is loaded after prymace.css on every
   console page (see layouts/ops.blade.php, which documents that order). The
   rules are still namespaced `.pa-ops` / prefixed `pa-ops-`, and the views and
   components still ask for those class names — but their *appearance* is the
   admin's:

     * `.pa-ops-panel`  reads as `.pa-card`
     * `.pa-ops-table`  reads as `.pa-table`
     * `.pa-ops-kpi`    reads as `.pa-stat`
     * `.pa-ops-pill`   reads as `.pa-badge`
     * `.pa-ops-btn`    reads as `.pa-btn`
     * `.pa-ops-empty`  reads as `.pa-empty`
     * `.pa-ops-field`  reads as `.pa-field` / `.pa-input`

   Tokens
   ------
   The console's own tokens (surface, ink, line, muted, success/warning/danger,
   table chrome, geometry) now DEFAULT TO THE ADMIN TOKENS, each with a light
   literal fallback:

       --pa-ops-surface: var(--pa-surface, #ffffff);

   Two consequences, both deliberate:

     1. Light is the default, and the console follows the admin theme
        automatically. When the theme layer redefines the admin tokens on
        `data-theme="dark"` (or any other ancestor selector), the console picks
        up the dark palette without a single dark-console rule existing here —
        custom properties resolve at *use* time, so the `var()` indirection is
        live, not a snapshot. No dark console was written.
     2. The fallbacks keep the console readable on the two public pages that
        load this file *without* prymace.css (resources/views/products/index and
        resources/views/fomtech/index, which render `pa-ops--market` for the
        resource-flow pipeline inside layouts/tailwind-public). There the admin
        tokens are undefined, so the literals apply and those pages stay light.

   The one deliberate exception is the Forge board: `pa-ops--dark`, driven by
   `config('prymace.pools.forge.theme') === 'dark'`. It keeps the original navy
   console treatment and is asserted by
   `MonitorPagesTest::test_the_forge_board_is_the_dark_treatment_and_the_others_are_light`.
   It is expressed as *token overrides* on `.pa-ops--dark` (section 15), so the
   same component rules serve both treatments.

   Contrast (WCAG AA — 4.5:1 body text, 3:1 large text and UI borders)
   ------------------------------------------------------------------
   The pool brand hues are only ever used as fills, dots and borders — never as
   small text on a light surface — because they do not clear AA there
   (amber #f0ad4e is 1.95:1 on white). Every place a pool colour has to carry
   text uses the `--pa-ops-accent-ink` variant, fed from
   `config('prymace.pools.*.ink')`. Section 10 and section 16 verify the pairs.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

.pa-ops {
    /* --- Admin palette aliases ---------------------------------------------
       The admin tokens, with light fallbacks for the public pages that load
       this layer alone. Nothing below redefines an admin token: the console
       consumes them, so a theme change to `--pa-surface`, `--pa-ink`, … flows
       straight through. */
    --pa-ops-surface: var(--pa-surface, #ffffff);
    --pa-ops-surface-alt: var(--pa-surface-alt, #f8f9fa);
    --pa-ops-surface-sunken: var(--pa-surface-sunken, #f0f2f5);

    --pa-ops-border: var(--pa-line, #dee2e6);
    --pa-ops-border-soft: var(--pa-line-soft, #eceff3);
    --pa-ops-border-strong: var(--pa-line, #dee2e6);

    /* --- Ink ---------------------------------------------------------------
       ink               headings and primary text          (--pa-ink)
       ink-soft          body copy inside tables             (--pa-text)
       ink-muted         secondary text on a WHITE panel     (--pa-muted)
       ink-muted-strong  secondary text anywhere else         (a darker --pa-muted)
       ink-muted-soft    secondary text on the dark board     (the alias above)

       The split exists because `--pa-muted` (#6c757d) measures 4.69:1 on white
       but only 4.45:1 on `--pa-surface-alt` and 4.18:1 on
       `--pa-surface-sunken` — both below AA, and both are surfaces this layer
       uses for table heads, even rows, inset status rows and captions. The
       admin has that same shortfall in `.pa-table th`; the console does not
       have to inherit it. `#646b73` is the same grey two steps darker and
       clears 4.5:1 on all three (4.81:1 at worst on the sunken surface). */
    --pa-ops-ink: var(--pa-ink, #1c2733);
    --pa-ops-ink-soft: var(--pa-text, #333333);
    --pa-ops-ink-muted: var(--pa-muted, #6c757d);
    --pa-ops-ink-muted-strong: #646b73;
    --pa-ops-ink-muted-soft: var(--pa-ops-ink-muted-strong);

    /* Text that sits on a permanently dark surface: the Pool visual's photo
       overlay, the Market pipeline's lead stage and the Forge board. These are
       *not* theme tokens — those surfaces are dark in both themes. */
    --pa-ops-ink-on-dark: #ffffff;
    --pa-ops-ink-on-dark-soft: #cbd6e4;

    /* --- Status ------------------------------------------------------------
       Naming note: `-bg` is the tinted background and the bare token is the
       foreground ink, which is how every rule here consumes them.

       All four semantic families are the ADMIN's `-050` tint / `-ink` /
       `-border` tokens, so a dark theme that lifts them (it does: see "1a. DARK
       THEME" in prymace.css) lifts the console's pills and alerts with them,
       and the console has no dark palette of its own to keep in step. The
       literals are the light values, for the two public pages that load this
       layer without the admin one.

       `violet` and `gray` have no admin semantic token — they are console-only
       status colours — so those two stay literal in both themes.

       Every pair below is at 4.5:1 or better on its own tint, in both themes,
       including the cross pair (green ink is also used on the violet tint by
       the Pools tables), which is why light green is #1b7731 rather than the
       admin badge's #1c7c33 (4.39:1 on the violet tint). */
    --pa-ops-green: var(--pa-success-ink, #1b7731);
    --pa-ops-green-bg: var(--pa-success-050, #e7f6eb);
    --pa-ops-green-border: var(--pa-success-border, #bfe6c9);
    --pa-ops-blue: var(--pa-info-ink, #01539c);
    --pa-ops-blue-bg: var(--pa-info-050, #e8f4fe);
    --pa-ops-blue-border: var(--pa-info-border, #b8e2ea);
    --pa-ops-amber: var(--pa-warning-ink, #8a6800);
    --pa-ops-amber-bg: var(--pa-warning-050, #fdf6e3);
    --pa-ops-amber-border: var(--pa-warning-border, #f0dfae);
    --pa-ops-violet: #4b2a86;      /* 8.84:1 on --pa-ops-violet-bg */
    --pa-ops-violet-bg: #eee7fb;
    --pa-ops-gray: var(--pa-muted, #646b73);
    --pa-ops-gray-bg: var(--pa-surface-sunken, #f0f2f5);
    --pa-ops-red: var(--pa-danger-ink, #b3342a);
    --pa-ops-red-bg: var(--pa-danger-050, #fdecea);
    --pa-ops-red-border: var(--pa-danger-border, #f5c6c0);

    /* --- Status DOTS -------------------------------------------------------
       The dot hues above are chosen to clear 4.5:1 as TEXT on their tint, which
       is a stricter bar than the 3:1 a UI indicator needs (WCAG 1.4.11) — but
       not stricter than the one the *dark* theme imposes: there the admin's
       `-ink` tokens are lifted to #7fe0a0 and #6fd8e8, which are only 1.7:1 and
       1.9:1 as dots on `--pa-surface-sunken`. A dot is a one-colour mark with
       nothing to carry it, so it gets its own pair per theme: darker than the
       text ink on a light surface, and mid-tone on a dark one, so the same rule
       is legible in both. */
    --pa-ops-dot-green: #14663a;
    --pa-ops-dot-blue: #01539c;
    --pa-ops-dot-amber: #8a5a00;

    /* --- Table chrome ------------------------------------------------------
       The admin table head is a quiet grey band (`.pa-table th`), not a navy
       bar. Tokenised so the dark board can invert just these two without
       restating the table. */
    --pa-ops-table-head-bg: var(--pa-surface-alt, #f8f9fa);
    --pa-ops-table-head-ink: var(--pa-ops-ink-muted-strong);

    /* --- Geometry ----------------------------------------------------------
       Same radii and elevation as the admin components. */
    --pa-ops-radius: var(--pa-radius, 10px);
    --pa-ops-radius-sm: var(--pa-radius-sm, 6px);
    --pa-ops-radius-lg: var(--pa-radius-lg, 14px);
    --pa-ops-gap: var(--pa-space-4, 1rem);
    --pa-ops-shadow: var(--pa-shadow-sm, 0 2px 6px rgba(16, 24, 40, 0.06));
    --pa-ops-shadow-lg: var(--pa-shadow-lg, 0 12px 32px rgba(16, 24, 40, 0.12));

    /* --- Chrome tones ------------------------------------------------------
       The small surfaces the header, the tab strip and the tables use for a
       hover, a chip or an even row. They are tokens rather than literals because
       the dark board inverts all of them, and keeping them here means the dark
       board is a token block (section 15) rather than a second set of rules. */
    --pa-ops-chip-bg: var(--pa-ops-surface-alt);
    --pa-ops-chip-bg-strong: var(--pa-ops-surface-sunken);
    --pa-ops-row-hover: var(--pa-brand-050, #e8f4fe);
    --pa-ops-tab-ink: var(--pa-ops-ink);
    --pa-ops-tab-ink-soft: var(--pa-ops-ink-muted-strong);
    --pa-ops-link: var(--pa-brand-700, #01539c);

    --pa-ops-max: var(--pa-content-max, 1320px);

    /* --- Per-pool accent ---------------------------------------------------
       Individual boards override these five via a modifier class, and the
       views override them inline from config('prymace.pools.*.accent'|'ink') —
       the tab strip's Pool selector, the balance and capacity tables, the
       region tree, the Network page and the Port board's map markers all read
       the same tokens, which is why they must keep working.

         accent            the raw brand hue — FILLS, dots, borders, meters
         accent-ink        the dark hue that clears AA as TEXT on a light surface
         accent-light      the tint used as the light end of a meter gradient
         accent-soft       a translucent wash behind accent-ink text
         accent-soft-strong an opaque tint for hover states

       Note the fallback style below: the raw hue may be injected inline on an
       element that does not also carry an `ink` override (the Market pipeline
       does exactly that), so every companion token falls back through the raw
       hue when it has not been set. That keeps a fill visible instead of
       resolving to an invalid custom property. */
    --pa-ops-accent: var(--pa-ops-console-accent, var(--pa-brand, #017fe4));
    --pa-ops-accent-ink: var(--pa-ops-console-accent-ink, var(--pa-brand-700, #01539c));
    --pa-ops-accent-light: var(--pa-ops-accent);
    --pa-ops-accent-soft: var(--pa-brand-050, #e8f4fe);
    --pa-ops-accent-soft-strong: var(--pa-brand-100, #cfe7fb);

    /* The console chrome blue: the reference boards keep one blue across the
       KPI caps and icons and reserve the Pool hue for meters, tags and status
       dots. Identical to --pa-brand on light boards; only the dark board
       overrides it. */
    --pa-ops-console-accent: var(--pa-brand, #017fe4);
    --pa-ops-console-accent-light: var(--pa-brand-100, #cfe7fb);
    --pa-ops-console-accent-ink: var(--pa-brand-700, #01539c);
    --pa-ops-console-accent-soft: var(--pa-brand-050, #e8f4fe);

    font-family: var(--pa-font, Figtree, "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif);
    color: var(--pa-ops-ink);
    background: var(--pa-ops-surface-alt);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* Pool accents. The ink variants are the darkened hues that pass AA as text
   (the raw brand hues do not — amber #f0ad4e is 1.95:1 on white). `accent` is
   the fill hue; `accent-ink` is what any accent-coloured *text* must use. */
.pa-ops--port {
    --pa-ops-accent: #017fe4;
    --pa-ops-accent-ink: #01539c;
    --pa-ops-accent-light: #6fb8f2;
    --pa-ops-accent-soft: #e8f4fe;
    --pa-ops-accent-soft-strong: #cfe7fb;
}

.pa-ops--stock {
    --pa-ops-accent: #f0ad4e;
    --pa-ops-accent-ink: #8a5a00;
    --pa-ops-accent-light: #f7d29b;
    --pa-ops-accent-soft: #fdf6e3;
    --pa-ops-accent-soft-strong: #fbe8ce;
}

.pa-ops--forge {
    --pa-ops-accent: #d9534f;
    --pa-ops-accent-ink: #a02622;
    --pa-ops-accent-light: #eb9a97;
    --pa-ops-accent-soft: #fdecea;
    --pa-ops-accent-soft-strong: #f7d5d4;
}

.pa-ops--mine {
    --pa-ops-accent: #5cb85c;
    --pa-ops-accent-ink: #2f6b2f;
    --pa-ops-accent-light: #9bd99b;
    --pa-ops-accent-soft: #e7f6eb;
    --pa-ops-accent-soft-strong: #d8f0d8;
}

.pa-ops--refinery {
    --pa-ops-accent: #6f42c1;
    --pa-ops-accent-ink: #4b2a86;
    --pa-ops-accent-light: #ab8fdc;
    --pa-ops-accent-soft: #eee7fb;
    --pa-ops-accent-soft-strong: #e2d8f7;
}

.pa-ops--market {
    --pa-ops-accent: #017fe4;
    --pa-ops-accent-ink: #01539c;
    --pa-ops-accent-light: #6fb8f2;
    --pa-ops-accent-soft: #e8f4fe;
    --pa-ops-accent-soft-strong: #cfe7fb;
}

/* --------------------------------------------------------------------------
   2. Scope reset
   -------------------------------------------------------------------------- */

/* `body.pa-ops` is the one rule here that is not strictly a `.pa-ops`
   descendant: the console is a full-bleed page, so the UA's 8px body margin
   has to go. Scoped to the class keeps it off every other layout. */
body.pa-ops {
    margin: 0;
    padding: 0;
    background: var(--pa-ops-surface-alt, #f8f9fa);
}

.pa-ops *,
.pa-ops *::before,
.pa-ops *::after {
    box-sizing: border-box;
}

.pa-ops h1, .pa-ops h2, .pa-ops h3, .pa-ops h4, .pa-ops h5, .pa-ops h6,
.pa-ops p, .pa-ops ul, .pa-ops ol, .pa-ops figure, .pa-ops table {
    margin: 0;
    padding: 0;
}

.pa-ops ul, .pa-ops ol { list-style: none; }

.pa-ops img { max-width: 100%; display: block; }

.pa-ops a { color: inherit; text-decoration: none; }

.pa-ops table { border-collapse: collapse; width: 100%; }

/*
 * The console's own content gutter. In the embedded shell the page is
 * full-bleed (`.pa-content--ops` drops the admin gutter), so this is the only
 * thing spacing the boards off the viewport edge.
 */
.pa-ops__inner {
    max-width: var(--pa-ops-max);
    margin: 0 auto;
    padding: 0 var(--pa-space-5, 1.5rem) var(--pa-space-6, 2rem);
}

/* --------------------------------------------------------------------------
   3. Page backdrop
   -------------------------------------------------------------------------- */

/* The admin page band. Was a fixed navy radial-gradient; it is now the same
   `--pa-surface-alt` the rest of the dashboard uses, so a board sits on the
   app's own paper instead of on a second product's. */
.pa-ops__page {
    min-height: 100vh;
    background: var(--pa-ops-surface-alt);
}

/* A whisper of brand at the top of the page, so the console has one piece of
   chrome that is identifiably its own without becoming a second theme. It is
   drawn with a translucent brand wash rather than color-mix(), and it is
   transparent by 240px, well above the first panel. */
.pa-ops:not(.pa-ops--dark) .pa-ops__page {
    background-image: linear-gradient(180deg, rgba(1, 127, 228, 0.06), rgba(1, 127, 228, 0) 240px);
    background-repeat: no-repeat;
}

/* --------------------------------------------------------------------------
   3b. Section navigation (the tab strip)

   Rendered by layouts/ops on every console page from
   config('prymace.monitor.sections'). It sits between the console header and
   the content. On the admin's light chrome it reads as a tab row — a white
   band under the page header, with the current section carrying the brand —
   rather than as the brightest thing on a navy backdrop.
   -------------------------------------------------------------------------- */

.pa-ops-tabs {
    border-bottom: 1px solid var(--pa-ops-border);
    background: var(--pa-ops-surface);
}

.pa-ops-tabs__list,
.pa-ops-tabs__sublist {
    display: flex;
    align-items: center;
    gap: 4px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.pa-ops-tabs__list {
    max-width: var(--pa-ops-max);
    margin: 0 auto;
    padding: var(--pa-space-2, 0.5rem) var(--pa-space-5, 1.5rem) 0;
    gap: 2px;
    overflow-x: auto;
    scrollbar-width: none;
}

.pa-ops-tabs__list::-webkit-scrollbar { display: none; }

/* A section tab is an underline tab. The rule along the bottom of the strip
   is the shared baseline every tab sits on; the current one paints over it
   with the brand and its label goes to full ink. */
.pa-ops-tabs__tab {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 14px 10px;
    border-radius: var(--pa-radius-sm, 6px) var(--pa-radius-sm, 6px) 0 0;
    box-shadow: inset 0 -2px 0 0 transparent;
    color: var(--pa-ops-ink-muted-strong);
    font-size: var(--pa-text-sm, 0.8125rem);
    font-weight: var(--pa-weight-semibold, 600);
    white-space: nowrap;
    text-decoration: none;
    transition: background var(--pa-transition, 180ms ease),
                color var(--pa-transition, 180ms ease),
                box-shadow var(--pa-transition, 180ms ease);
}

.pa-ops-tabs__tab i { font-size: 0.82rem; color: var(--pa-faint, #98a2b3); }

.pa-ops-tabs__tab:hover {
    background: var(--pa-ops-chip-bg);
    color: var(--pa-ops-tab-ink);
    text-decoration: none;
}

/* The current section is the one piece of orientation a reader needs on every
   page: full-strength ink plus the console accent underline. */
.pa-ops-tabs__tab.is-current {
    background: var(--pa-ops-console-accent-soft);
    box-shadow: inset 0 -2px 0 0 var(--pa-ops-console-accent);
    color: var(--pa-ops-tab-ink);
}

.pa-ops-tabs__tab.is-current i { color: var(--pa-ops-console-accent); opacity: 1; }

/* --- the second row: this section's pages ------------------------------- */

.pa-ops-tabs__sub {
    max-width: var(--pa-ops-max);
    margin: 0 auto;
    padding: var(--pa-space-1, 0.25rem) var(--pa-space-5, 1.5rem) var(--pa-space-2, 0.5rem);
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.pa-ops-tabs__sub-label {
    font-size: 0.62rem;
    font-weight: var(--pa-weight-bold, 700);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--pa-ops-tab-ink-soft);
}

.pa-ops-tabs__subtab {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 11px;
    border-radius: var(--pa-radius-pill, 999px);
    border: 1px solid transparent;
    color: var(--pa-ops-tab-ink-soft);
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-semibold, 600);
    white-space: nowrap;
    text-decoration: none;
    transition: background var(--pa-transition, 180ms ease),
                color var(--pa-transition, 180ms ease),
                border-color var(--pa-transition, 180ms ease);
}

.pa-ops-tabs__subtab i { font-size: 0.72rem; }

.pa-ops-tabs__subtab:hover {
    background: var(--pa-ops-chip-bg);
    color: var(--pa-ops-tab-ink);
    text-decoration: none;
}

.pa-ops-tabs__subtab.is-current {
    background: var(--pa-ops-chip-bg-strong);
    border-color: var(--pa-ops-tab-ink-soft);
    color: var(--pa-ops-tab-ink);
}

/*
 * The Pool selector. Each Pool keeps its own accent so the selector matches the
 * board you land on and the markers on its map — the accent is the same token
 * the boards and the Network page read.
 *
 * Both the dot and the label use the Pool's INK here, not its raw hue. A UI
 * indicator has to clear 3:1 against its background (WCAG 1.4.11) and two of
 * the five raw hues do not on a white chip — amber #f0ad4e is 1.95:1 and green
 * #5cb85c is 2.48:1. The inks are all at 5.6:1 or better, so a small chip stays
 * legible and the Pool is still told apart by its own colour. The raw hue is
 * reserved for the meter fills, the KPI caps and the map markers, where it is a
 * large area rather than a mark. Injected inline by x-pa.ops.tabs as
 * `--pa-ops-tab-accent` / `--pa-ops-tab-ink`.
 */
.pa-ops-tabs__subtab--pool { border-color: var(--pa-ops-border); }

.pa-ops-tabs__subtab--pool i { color: var(--pa-ops-tab-ink, var(--pa-brand-700, #01539c)); }

.pa-ops-tabs__subtab--pool::before {
    content: "";
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--pa-ops-tab-ink, var(--pa-brand-700, #01539c));
}

.pa-ops-tabs__subtab--pool:hover {
    background: var(--pa-ops-chip-bg);
    border-color: var(--pa-ops-tab-ink, var(--pa-brand-700, #01539c));
}

.pa-ops-tabs__subtab--pool.is-current {
    background: var(--pa-ops-tab-ink, var(--pa-brand-700, #01539c));
    border-color: var(--pa-ops-tab-ink, var(--pa-brand-700, #01539c));
    color: var(--pa-btn-on, #ffffff);
}

.pa-ops-tabs__subtab--pool.is-current i { color: var(--pa-btn-on, #ffffff); }

.pa-ops-tabs__subtab--pool.is-current::before { background: var(--pa-btn-on, #ffffff); }

@media (max-width: 767.98px) {
    .pa-ops-tabs__list,
    .pa-ops-tabs__sub { padding-left: var(--pa-space-3, 0.75rem); padding-right: var(--pa-space-3, 0.75rem); }

    .pa-ops-tabs__tab { padding: 8px 12px 9px; }
}

@media print {
    .pa-ops-tabs { display: none; }
}

/* --------------------------------------------------------------------------
   4. Console header

   The wordmark / LIVE / switcher band. It is the console's `pa-page-head`: a
   white band with a bottom rule and a Pool-coloured hairline, ink title,
   muted meta — not a navy banner. The flag, LIVE stamp, operator and the
   "← System Controller" back tag are unchanged; only the surface is.
   -------------------------------------------------------------------------- */

.pa-ops-hdr {
    position: relative;
    overflow: hidden;
    border-bottom: 1px solid var(--pa-ops-border);
    background: var(--pa-ops-surface);
}

/* The thin rule along the bottom edge of every board header, in the Pool's own
   hue. This is the header's only accent, and it is a border — not text. */
.pa-ops-hdr::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 2px;
    background: var(--pa-ops-accent);
}

.pa-ops-hdr__inner {
    position: relative;
    z-index: 1;
    max-width: var(--pa-ops-max);
    margin: 0 auto;
    padding: var(--pa-space-5, 1.5rem) var(--pa-space-5, 1.5rem);
    display: flex;
    align-items: center;
    gap: var(--pa-space-4, 1rem);
    flex-wrap: wrap;
}

/* The mark now sits on a light band, so it is a plain chip rather than a
   luminous circle behind a drop-shadowed image. It is scaled to the
   pa-page-head's own rhythm (a page title, not a banner). */
.pa-ops-hdr__logo {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 54px;
    height: 54px;
    border-radius: var(--pa-radius, 10px);
    background: var(--pa-ops-chip-bg);
    border: 1px solid var(--pa-ops-border-soft);
}

.pa-ops-hdr__logo img {
    width: 40px;
    height: 40px;
    object-fit: contain;
}

.pa-ops-hdr__brand {
    flex: 1 1 320px;
    min-width: 0;
}

/* Same weight and colour as `.pa-page-title`, one step down in size because
   the wordmark carries a Pool name as well as the product name. The all-caps
   tracking of the old banner is gone — the title itself is already uppercase
   where the Pool requires it. */
.pa-ops-hdr__wordmark {
    font-size: var(--pa-text-xl, 1.75rem);
    font-weight: var(--pa-weight-bold, 700);
    line-height: 1.2;
    color: var(--pa-ops-ink);
}

/* The Pool half of the wordmark. Used to be a pale tint for a navy banner; on
   a light band it is the brand ink. */
.pa-ops-hdr__wordmark em {
    font-style: normal;
    color: var(--pa-brand-700, #01539c);
}

.pa-ops-hdr__tagline {
    margin-top: var(--pa-space-1, 0.25rem);
    font-size: var(--pa-text-base, 0.9375rem);
    font-weight: var(--pa-weight-normal, 400);
    color: var(--pa-ops-ink-muted-strong);
}

.pa-ops-hdr__meta {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--pa-space-2, 0.5rem);
    text-align: right;
}

/* The station label — "GHANA | OPERATIONS CENTER" — is chrome, so it reads as
   a page-head eyebrow: small, tracked, muted. */
.pa-ops-hdr__place {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    color: var(--pa-ops-ink-muted-strong);
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-bold, 700);
    letter-spacing: 0.09em;
    text-transform: uppercase;
}

.pa-ops-flag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 22px;
    overflow: hidden;
    border-radius: 3px;
    background: #ffffff;
    box-shadow: inset 0 0 0 1px var(--pa-ops-border-strong);
    font-size: 0.68rem;
    font-weight: var(--pa-weight-bold, 700);
    color: var(--pa-ops-ink);
}

/* Flag sprites, keyed by the country's stored ISO 3166-1 alpha-2 code:
   `Country::flagClass()` builds `.pa-ops-flag--<code>`, so nothing in PHP or
   Blade names a country. A country with a code but no rule below shows its code
   on the plain chip — which is why each sprite rule hides `__code`, and why
   adding a flag for a new market is one rule here plus an admin edit of that
   country's code. */
.pa-ops-flag--gh {
    background: linear-gradient(180deg,
        #ce1126 0 33.33%,
        #fcd116 33.33% 66.66%,
        #006b3f 66.66% 100%);
    color: #000000;
    font-size: 0.62rem;
    line-height: 1;
}

.pa-ops-flag--gh::before {
    content: "\2605";
}

.pa-ops-flag--gh .pa-ops-flag__code {
    display: none;
}

/*
 * LIVE • UPDATED …  — a status badge, so it is `.pa-badge--success` in
 * console clothing: a green dot and green ink on the pale green tint. Still
 * the loudest thing in the meta stack, which is what a "is this data live?"
 * cue should be, without being a white-on-navy chip.
 */
.pa-ops-live {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 0.2rem 0.6rem;
    border-radius: var(--pa-radius-pill, 999px);
    background: var(--pa-ops-green-bg);
    color: var(--pa-ops-green);
    font-size: 0.68rem;
    font-weight: var(--pa-weight-semibold, 600);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
}

.pa-ops-live__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--pa-ops-green);
    box-shadow: 0 0 0 3px var(--pa-ops-green-bg);
    animation: pa-ops-pulse 2.4s ease-in-out infinite;
}

.pa-ops-hdr__ops {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    color: var(--pa-ops-ink-soft);
    font-size: var(--pa-text-sm, 0.8125rem);
    font-weight: var(--pa-weight-medium, 500);
}

/* The operator chip is the topbar avatar: brand disc, initials in the theme's
   "on a lifted fill" ink (white in the light theme, near-black in the dark one,
   where `--pa-brand` is lifted to #4da3ff). */
.pa-ops-hdr__avatar {
    display: inline-grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: var(--pa-radius-pill, 999px);
    background: var(--pa-brand, #017fe4);
    color: var(--pa-btn-on, #ffffff);
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-bold, 700);
}

/* "← System Controller" — the route back up to the console landing page. It is
   `.pa-btn--ghost pa-btn--sm`: a bordered chip on the light band, with the
   arrow in the brand ink rather than a pale tint on navy. */
.pa-ops-hdr__back {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0.25rem 0.65rem;
    border-radius: var(--pa-radius-sm, 6px);
    border: 1px solid var(--pa-ops-border);
    background: var(--pa-ops-surface);
    color: var(--pa-brand-700, #01539c);
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-semibold, 600);
    white-space: nowrap;
    transition: background var(--pa-transition, 180ms ease),
                border-color var(--pa-transition, 180ms ease);
}

.pa-ops-hdr__back:hover,
.pa-ops-hdr__back:focus-visible {
    background: var(--pa-ops-chip-bg-strong);
    border-color: var(--pa-ops-border-strong);
    color: var(--pa-ops-link);
}

/* Board switcher — the five Pool boards are one section, so the header
   carries a compact switcher. Off by default (the tab strip's Pool selector
   replaced it) but still supported. */.pa-ops-hdr__switch {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 2px;
}

.pa-ops-hdr__switch a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0.2rem 0.6rem;
    border-radius: var(--pa-radius-pill, 999px);
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-semibold, 600);
    color: var(--pa-ops-ink-muted-strong);
    background: var(--pa-ops-surface-alt);
    border: 1px solid var(--pa-ops-border);
    transition: background var(--pa-transition, 180ms ease),
                color var(--pa-transition, 180ms ease);
}

.pa-ops-hdr__switch a:hover,
.pa-ops-hdr__switch a:focus-visible {
    color: var(--pa-ops-ink);
    background: var(--pa-ops-surface-sunken);
}

.pa-ops-hdr__switch a[aria-current="page"] {
    color: var(--pa-btn-on, #ffffff);
    background: var(--pa-brand-700, #01539c);
    border-color: var(--pa-brand-700, #01539c);
}

/* --------------------------------------------------------------------------
   5. KPI tiles — the `.pa-stat` of the console
   -------------------------------------------------------------------------- */

.pa-ops-kpis {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: var(--pa-ops-gap);
    margin: var(--pa-space-5, 1.5rem) 0 var(--pa-ops-gap);
}

/* Same surface, border, radius and elevation as `.pa-stat`. The coloured cap
   along the top is kept: it is the one thing that makes a row of five tiles
   scannable, and it is a fill rather than text. */
.pa-ops-kpi {
    position: relative;
    overflow: hidden;
    padding: var(--pa-space-4, 1rem);
    border-radius: var(--pa-ops-radius);
    background: var(--pa-ops-surface);
    border: 1px solid var(--pa-ops-border-soft);
    box-shadow: var(--pa-ops-shadow);
    text-align: center;
    transition: box-shadow var(--pa-transition, 180ms ease);
}

.pa-ops-kpi:hover { box-shadow: var(--pa-shadow, 0 4px 14px rgba(16, 24, 40, 0.07)); }

.pa-ops-kpi::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 4px;
    background: linear-gradient(90deg, var(--pa-ops-console-accent), var(--pa-ops-console-accent-light));
}

.pa-ops-kpi__icon {
    position: absolute;
    top: 13px;
    left: 13px;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: var(--pa-radius-sm, 6px);
    background: var(--pa-ops-console-accent-soft);
    color: var(--pa-ops-console-accent-ink);
    font-size: 0.92rem;
}

.pa-ops-kpi__value {
    margin-top: 18px;
    font-size: var(--pa-text-lg, 1.375rem);
    font-weight: var(--pa-weight-bold, 700);
    line-height: 1.15;
    color: var(--pa-ops-ink);
    font-variant-numeric: tabular-nums;
    word-break: break-word;
}

.pa-ops-kpi__label {
    margin-top: var(--pa-space-1, 0.25rem);
    font-size: var(--pa-text-sm, 0.8125rem);
    font-weight: var(--pa-weight-semibold, 600);
    line-height: 1.25;
    color: var(--pa-ops-ink-soft);
}

.pa-ops-kpi__caption {
    margin-top: var(--pa-space-1, 0.25rem);
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-normal, 400);
    line-height: 1.35;
    color: var(--pa-ops-ink-muted-strong);
}

/* --------------------------------------------------------------------------
   6. Body grid & panels — `.pa-card` in console clothing
   -------------------------------------------------------------------------- */

.pa-ops-grid {
    display: grid;
    gap: var(--pa-ops-gap);
    grid-template-columns: minmax(0, 1.32fr) minmax(0, 1fr);
}

.pa-ops-grid--even { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.pa-ops-grid--wide { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); }
.pa-ops-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.pa-ops-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.pa-ops-grid + .pa-ops-grid,
.pa-ops-grid + .pa-ops-panel,
.pa-ops-panel + .pa-ops-panel,
.pa-ops-panel + .pa-ops-grid {
    margin-top: var(--pa-ops-gap);
}

/* The admin card: white surface, hairline border, small shadow. */
.pa-ops-panel {
    display: flex;
    flex-direction: column;
    min-width: 0;
    border-radius: var(--pa-ops-radius);
    background: var(--pa-ops-surface);
    border: 1px solid var(--pa-ops-border-soft);
    box-shadow: var(--pa-ops-shadow);
    overflow: hidden;
}

/* `.pa-card__head`: same padding, same hairline rule. */
.pa-ops-panel__head {
    display: flex;
    align-items: center;
    gap: var(--pa-space-3, 0.75rem);
    padding: var(--pa-space-4, 1rem) var(--pa-space-5, 1.5rem);
    border-bottom: 1px solid var(--pa-ops-border-soft);
}

.pa-ops-panel__title {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: var(--pa-text-base, 0.9375rem);
    font-weight: var(--pa-weight-semibold, 600);
    color: var(--pa-ops-ink);
}

/* The Pool icon in a panel head is accent-coloured TEXT, so it uses the ink
   variant (amber's raw #f0ad4e is 1.95:1 on white). */
.pa-ops-panel__title i { color: var(--pa-ops-accent-ink); }

.pa-ops-panel__meta {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-normal, 400);
    color: var(--pa-ops-ink-muted-strong);
    white-space: nowrap;
}

.pa-ops-panel__body { padding: var(--pa-space-5, 1.5rem); }

.pa-ops-panel__body--flush { padding: 0; }
.pa-ops-panel__body--tight { padding: var(--pa-space-3, 0.75rem) var(--pa-space-5, 1.5rem); }

/* `.pa-card__foot`. */
.pa-ops-panel__foot {
    margin-top: auto;
    padding: var(--pa-space-3, 0.75rem) var(--pa-space-5, 1.5rem);
    border-top: 1px solid var(--pa-ops-border-soft);
    background: var(--pa-ops-surface-alt);
    font-size: var(--pa-text-xs, 0.75rem);
    color: var(--pa-ops-ink-muted-strong);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   7. Visual panel (facility photography + overlay)
   -------------------------------------------------------------------------- */

/* This overlay is permanently dark — it sits on a photograph — so it keeps
   white text in both themes and on the light console. */
.pa-ops-visual {
    position: relative;
    min-height: 260px;
    flex: 1;
    background: var(--pa-ops-surface-sunken);
}

.pa-ops-visual img {
    width: 100%;
    height: 100%;
    min-height: 260px;
    object-fit: cover;
}

.pa-ops-visual__overlay {
    position: absolute;
    inset: auto 0 0 0;
    padding: var(--pa-space-4, 1rem) var(--pa-space-5, 1.5rem);
    background: linear-gradient(to top, rgba(19, 28, 39, 0.94) 12%, rgba(19, 28, 39, 0.72) 58%, transparent);
    color: var(--pa-ops-ink-on-dark);
}

.pa-ops-visual__kicker {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 0.68rem;
    font-weight: var(--pa-weight-bold, 700);
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: #dbe9f8;
}

.pa-ops-visual__list {
    margin-top: 9px;
    display: grid;
    gap: 7px;
}

.pa-ops-visual__list li {
    position: relative;
    padding-left: 15px;
    font-size: var(--pa-text-sm, 0.8125rem);
    font-weight: var(--pa-weight-semibold, 600);
    line-height: 1.4;
    color: var(--pa-ops-ink-on-dark);
}

/* The bullet is a fill on a fixed-dark photo overlay, so the raw hue is fine
   here — it is 3:1 or better against rgba(19,28,39) for all five Pools. */
.pa-ops-visual__list li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.42em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--pa-ops-accent);
}

.pa-ops-visual__badge {
    position: absolute;
    left: 12px;
    bottom: 12px;
    padding: 6px 11px;
    border-radius: var(--pa-radius-pill, 999px);
    background: rgba(19, 28, 39, 0.82);
    color: #ffffff;
    font-size: 0.7rem;
    font-weight: var(--pa-weight-bold, 700);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.pa-ops-visual__stamp {
    position: absolute;
    right: 12px;
    bottom: 12px;
    padding: 4px 9px;
    border-radius: var(--pa-radius-sm, 6px);
    background: rgba(19, 28, 39, 0.78);
    color: #eaf1f9;
    font-size: 0.68rem;
    font-weight: var(--pa-weight-semibold, 600);
    letter-spacing: 0.05em;
}

/* Host element for the Port board's Leaflet map. The sunken background means
   the panel still reads as a map card while tiles load, or if the tile CDN
   is unreachable. */
.pa-ops-portmap {
    height: 300px;
    border-radius: var(--pa-ops-radius-sm);
    background: var(--pa-ops-surface-sunken);
    box-shadow: inset 0 0 0 1px var(--pa-ops-border);
}

.pa-ops-portmap .leaflet-container {
    border-radius: var(--pa-ops-radius-sm);
    font: inherit;
}

/* --------------------------------------------------------------------------
   8. Bar meters
   -------------------------------------------------------------------------- */

.pa-ops-bars {
    display: grid;
    gap: 13px;
}

.pa-ops-bar {
    display: grid;
    grid-template-columns: minmax(72px, 0.62fr) minmax(0, 2.6fr) auto;
    align-items: center;
    gap: 11px;
}

.pa-ops-bar__label {
    font-size: var(--pa-text-sm, 0.8125rem);
    font-weight: var(--pa-weight-medium, 500);
    color: var(--pa-ops-ink-soft);
    overflow-wrap: anywhere;
}

.pa-ops-bar__track {
    position: relative;
    height: 12px;
    border-radius: var(--pa-radius-pill, 999px);
    background: var(--pa-ops-surface-sunken);
    overflow: hidden;
}

.pa-ops-bar__fill {
    height: 100%;
    min-width: 3px;
    border-radius: var(--pa-radius-pill, 999px);
    /* `--pa-ops-bar-to` lets one Pool show a two-stop gradient (Forge's
       orange-to-blue output bars) without a second component. */
    background: linear-gradient(90deg,
        var(--pa-ops-accent-light),
        var(--pa-ops-bar-to, var(--pa-ops-accent)));
    transition: width 500ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.pa-ops-bar__value {
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-semibold, 600);
    color: var(--pa-ops-ink-soft);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* --------------------------------------------------------------------------
   8b. Column chart (time series)
   -------------------------------------------------------------------------- */

/* Used for intake over time. Bars rather than a charting library, because the
   dashboards need one small series each and a runtime would be the largest
   thing on the page. */
.pa-ops-columns {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 150px;
}

.pa-ops-columns__col {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    gap: 4px;
    height: 100%;
}

.pa-ops-columns__bar {
    width: 100%;
    min-height: 2px;
    border-radius: 3px 3px 0 0;
    background: linear-gradient(180deg, var(--pa-ops-accent-light), var(--pa-ops-accent));
}

/* An empty bucket is drawn as a flat baseline rather than nothing, so a gap in
   activity reads as a gap and not as a missing column. */
.pa-ops-columns__bar--empty {
    background: var(--pa-ops-surface-sunken);
}

.pa-ops-columns__label {
    font-size: 0.6rem;
    line-height: 1;
    color: var(--pa-ops-ink-muted-strong);
    white-space: nowrap;
}

.pa-ops-columns__foot {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    margin-top: var(--pa-ops-gap);
    font-size: var(--pa-text-xs, 0.75rem);
    color: var(--pa-ops-ink-muted-strong);
}

/* --------------------------------------------------------------------------
   9. Donut gauge
   -------------------------------------------------------------------------- */

.pa-ops-gauge {
    display: grid;
    place-items: center;
    gap: var(--pa-space-3, 0.75rem);
}

.pa-ops-gauge__ring {
    position: relative;
    width: 168px;
    height: 168px;
}

.pa-ops-gauge__ring svg {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
}

.pa-ops-gauge__track {
    fill: none;
    stroke: var(--pa-ops-surface-sunken);
    stroke-width: 20;
}

.pa-ops-gauge__arc {
    fill: none;
    stroke: var(--pa-ops-accent);
    stroke-width: 20;
    stroke-linecap: round;
    transition: stroke-dashoffset 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.pa-ops-gauge__centre {
    position: absolute;
    inset: 0;
    display: grid;
    place-content: center;
    text-align: center;
}

.pa-ops-gauge__value {
    font-size: var(--pa-text-2xl, 2.25rem);
    font-weight: var(--pa-weight-bold, 700);
    line-height: 1;
    color: var(--pa-ops-ink);
    font-variant-numeric: tabular-nums;
}

.pa-ops-gauge__unit {
    margin-top: 3px;
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-semibold, 600);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--pa-ops-ink-muted-strong);
}

.pa-ops-gauge__legend {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
    gap: var(--pa-space-3, 0.75rem);
    width: 100%;
    padding-top: var(--pa-space-3, 0.75rem);
    border-top: 1px solid var(--pa-ops-border-soft);
}

.pa-ops-gauge__stat {
    text-align: center;
}

.pa-ops-gauge__stat b {
    display: block;
    font-size: var(--pa-text-md, 1.0625rem);
    font-weight: var(--pa-weight-bold, 700);
    color: var(--pa-ops-ink);
    font-variant-numeric: tabular-nums;
}

.pa-ops-gauge__stat span {
    display: block;
    margin-top: 2px;
    font-size: 0.7rem;
    font-weight: var(--pa-weight-semibold, 600);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--pa-ops-ink-muted-strong);
}

.pa-ops-gauge__target {
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-medium, 500);
    color: var(--pa-ops-ink-muted-strong);
    text-align: center;
}

/* --------------------------------------------------------------------------
   10. Status pills and tags — `.pa-badge` in console clothing

   Every pair below is checked against WCAG AA, in BOTH themes. The foreground
   of each `--*` modifier clears 4.5:1 on its own `*-bg` tint. Light theme
   (the admin's light tokens):

       received/planned/approved/processing/derived  #01539c on #e8f4fe   6.92:1
       sorted/processed/operational/paid/measured    #1b7731 on #e7f6eb   5.04:1
       pending/under_development                     #8a6800 on #fdf6e3   4.79:1
       dispatched                                    #4b2a86 on #eee7fb   8.84:1
       completed/unmeasured                          #646b73 on #f0f2f5   4.81:1
       rejected                                      #b3342a on #fdecea   5.34:1

   Dark theme (the admin's dark tokens, which the console reads through the
   same `--pa-ops-*` names):

       received   #6fd8e8 on #0e2a30   9.09:1
       operational #7fe0a0 on #122a1c  9.52:1
       pending     #f0c65a on #2a2312  9.60:1
       rejected    #ff9a94 on #2c1614  8.36:1
       dispatched  #4b2a86 on #eee7fb  8.84:1   (console-only, unchanged)
       completed   #c3d0de on #f0f2f5  4.83:1   (console-only, unchanged)

   The `.pa-ops--dark` board restates these literals because it is dark in both
   themes and must not inherit a light theme's lifted inks onto its light chips.
   -------------------------------------------------------------------------- */

.pa-ops-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.2rem 0.6rem;
    border-radius: var(--pa-radius-pill, 999px);
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-semibold, 600);
    line-height: 1.5;
    text-transform: capitalize;
    white-space: nowrap;
    background: var(--pa-ops-gray-bg);
    color: var(--pa-ops-gray);
}

.pa-ops-pill--received { background: var(--pa-ops-blue-bg); color: var(--pa-ops-blue); }
.pa-ops-pill--sorted { background: var(--pa-ops-green-bg); color: var(--pa-ops-green); }
.pa-ops-pill--processed { background: var(--pa-ops-green-bg); color: var(--pa-ops-green); }
.pa-ops-pill--dispatched { background: var(--pa-ops-violet-bg); color: var(--pa-ops-violet); }
.pa-ops-pill--completed { background: var(--pa-ops-gray-bg); color: var(--pa-ops-gray); }
.pa-ops-pill--operational { background: var(--pa-ops-green-bg); color: var(--pa-ops-green); }
.pa-ops-pill--planned { background: var(--pa-ops-blue-bg); color: var(--pa-ops-blue); }
.pa-ops-pill--under_development { background: var(--pa-ops-amber-bg); color: var(--pa-ops-amber); }
.pa-ops-pill--pending { background: var(--pa-ops-amber-bg); color: var(--pa-ops-amber); }
.pa-ops-pill--approved { background: var(--pa-ops-blue-bg); color: var(--pa-ops-blue); }
.pa-ops-pill--processing { background: var(--pa-ops-blue-bg); color: var(--pa-ops-blue); }
.pa-ops-pill--paid { background: var(--pa-ops-green-bg); color: var(--pa-ops-green); }
.pa-ops-pill--rejected { background: var(--pa-ops-red-bg); color: var(--pa-ops-red); }
.pa-ops-pill--measured { background: var(--pa-ops-green-bg); color: var(--pa-ops-green); }
.pa-ops-pill--derived { background: var(--pa-ops-blue-bg); color: var(--pa-ops-blue); }
.pa-ops-pill--unmeasured { background: var(--pa-ops-gray-bg); color: var(--pa-ops-gray); }

/* The dot is `currentColor`, so it is always the pill's own checked ink. */
.pa-ops-pill__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
}

/* `.pa-badge--brand` with the Pool's ink: colour on a wash. The raw hue is
   never the text colour here. */
.pa-ops-tag {
    display: inline-block;
    padding: 2px 8px;
    border-radius: var(--pa-radius-pill, 999px);
    background: var(--pa-ops-accent-soft);
    color: var(--pa-ops-accent-ink);
    font-size: 0.68rem;
    font-weight: var(--pa-weight-bold, 700);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* --------------------------------------------------------------------------
   11. Tables — `.pa-table` in console clothing
   -------------------------------------------------------------------------- */

.pa-ops-tablewrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.pa-ops-table {
    width: 100%;
    min-width: 640px;
    font-size: var(--pa-text-sm, 0.8125rem);
}

/* The admin table head is a quiet grey band with muted, tracked labels — not
   a navy bar. Tokenised so the dark board can invert it (section 15). */
.pa-ops-table thead th {
    padding: var(--pa-space-3, 0.75rem) var(--pa-space-4, 1rem);
    background: var(--pa-ops-table-head-bg);
    color: var(--pa-ops-table-head-ink);
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-semibold, 600);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-align: left;
    white-space: nowrap;
    border-bottom: 1px solid var(--pa-ops-border);
}

.pa-ops-table tbody td {
    padding: var(--pa-space-3, 0.75rem) var(--pa-space-4, 1rem);
    border-bottom: 1px solid var(--pa-ops-border-soft);
    color: var(--pa-ops-ink-soft);
    vertical-align: middle;
}

.pa-ops-table tbody tr:nth-child(even) td { background: var(--pa-ops-surface-alt); }

.pa-ops-table tbody tr { transition: background var(--pa-transition, 180ms ease); }

.pa-ops-table tbody tr:hover td { background: var(--pa-ops-row-hover); }

.pa-ops-table tbody tr:last-child td { border-bottom: 0; }

.pa-ops-table tbody td.pa-ops-table__strong {
    color: var(--pa-ops-ink);
    font-weight: var(--pa-weight-semibold, 600);
}

.pa-ops-table tbody td.pa-ops-table__num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.pa-ops-table tbody td.pa-ops-table__action { text-align: right; white-space: nowrap; }

/* An inline table action is `.pa-btn--ghost pa-btn--sm`: brand ink on a
   transparent ground, with a wash on hover. It was a filled accent chip, which
   put unreadable amber on white for the Stock board. */
.pa-ops-table__link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0.2rem 0.5rem;
    border-radius: var(--pa-radius-sm, 6px);
    background: transparent;
    color: var(--pa-ops-link);
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-semibold, 600);
    transition: background var(--pa-transition, 180ms ease);
}

.pa-ops-table__link:hover,
.pa-ops-table__link:focus-visible {
    background: var(--pa-ops-chip-bg);
    color: var(--pa-ops-link);
}

.pa-ops-table__time {
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-normal, 400);
    color: var(--pa-ops-ink-muted-strong);
    white-space: nowrap;
}

/* --------------------------------------------------------------------------
   12. Feed lines + facility status list
   -------------------------------------------------------------------------- */

.pa-ops-feed {
    display: grid;
}

.pa-ops-feed__item {
    display: flex;
    align-items: flex-start;
    gap: var(--pa-space-3, 0.75rem);
    padding: var(--pa-space-3, 0.75rem) var(--pa-space-5, 1.5rem);
    border-bottom: 1px solid var(--pa-ops-border-soft);
}

.pa-ops-feed__item:last-child { border-bottom: 0; }

.pa-ops-feed__icon {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    border-radius: var(--pa-radius-sm, 6px);
    background: var(--pa-ops-accent-soft);
    color: var(--pa-ops-accent-ink);
    font-size: 0.76rem;
}

.pa-ops-feed__body { min-width: 0; flex: 1; }

.pa-ops-feed__text {
    font-size: var(--pa-text-sm, 0.8125rem);
    font-weight: var(--pa-weight-medium, 500);
    color: var(--pa-ops-ink);
    line-height: 1.4;
}

.pa-ops-feed__meta {
    margin-top: 3px;
    font-size: var(--pa-text-xs, 0.75rem);
    color: var(--pa-ops-ink-muted-strong);
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
}

.pa-ops-feed__aside {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 9px;
}

/* Facility status rows (the Forge board's "temperature status" list), built
   like the admin's inset rows: a sunken ground with a hairline. */
.pa-ops-status {
    display: grid;
    gap: var(--pa-space-2, 0.5rem);
}

.pa-ops-status__row {
    display: grid;
    grid-template-columns: 14px minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 11px;
    padding: var(--pa-space-3, 0.75rem);
    border-radius: var(--pa-ops-radius-sm);
    background: var(--pa-ops-surface-alt);
    border: 1px solid var(--pa-ops-border-soft);
}

.pa-ops-status__dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--pa-ops-gray);
}

/* Status dots are UI indicators rather than decoration, so each is at least
   3:1 against the row background it sits on (WCAG 1.4.11) — in both themes,
   which is why they read a dedicated dot token rather than the text ink. */
.pa-ops-status__dot--operational { background: var(--pa-ops-dot-green); box-shadow: 0 0 0 4px var(--pa-ops-green-bg); }
.pa-ops-status__dot--planned { background: var(--pa-ops-dot-blue); box-shadow: 0 0 0 4px var(--pa-ops-blue-bg); }
.pa-ops-status__dot--under_development { background: var(--pa-ops-dot-amber); box-shadow: 0 0 0 4px var(--pa-ops-amber-bg); }

.pa-ops-status__name {
    font-size: var(--pa-text-sm, 0.8125rem);
    font-weight: var(--pa-weight-semibold, 600);
    color: var(--pa-ops-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Accent-coloured figure: ink variant, never the raw hue. */
.pa-ops-status__metric {
    font-size: var(--pa-text-sm, 0.8125rem);
    font-weight: var(--pa-weight-bold, 700);
    color: var(--pa-ops-accent-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* --------------------------------------------------------------------------
   12b. Regional facility tree (Country → Region → District → Zone → Facility)
   -------------------------------------------------------------------------- */

.pa-ops-tree {
    display: grid;
    gap: var(--pa-space-2, 0.5rem);
}

.pa-ops-tree__node { border-radius: var(--pa-ops-radius-sm); }

.pa-ops-tree__summary {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: var(--pa-space-3, 0.75rem);
    border-radius: var(--pa-ops-radius-sm);
    background: var(--pa-ops-surface-alt);
    border: 1px solid var(--pa-ops-border-soft);
    cursor: pointer;
    list-style: none;
    font-size: var(--pa-text-sm, 0.8125rem);
}

.pa-ops-tree__summary::-webkit-details-marker { display: none; }
.pa-ops-tree__summary::marker { content: ""; }

.pa-ops-tree__summary:hover { background: var(--pa-ops-surface-sunken); }

.pa-ops-tree__summary:focus-visible {
    outline: 2px solid var(--pa-brand, #017fe4);
    outline-offset: 1px;
}

/* A CSS triangle rather than a Font Awesome glyph, so the tree does not
   depend on the bundled Font Awesome version's family name. */
.pa-ops-tree__summary::after {
    content: "";
    flex: 0 0 auto;
    width: 0;
    height: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 6px solid var(--pa-ops-ink-muted-strong);
    transition: transform 160ms ease;
}

.pa-ops-tree__node[open] > .pa-ops-tree__summary::after { transform: rotate(180deg); }

/* The L1…L5 level chip. It was navy; it is now the neutral badge the admin
   uses for a label, so it does not compete with the Pool pill on the same
   row. */
.pa-ops-tree__level {
    flex: 0 0 auto;
    padding: 2px 6px;
    border-radius: var(--pa-radius-sm, 6px);
    background: var(--pa-ops-surface-sunken);
    color: var(--pa-ops-ink-muted-strong);
    font-size: 0.62rem;
    font-weight: var(--pa-weight-bold, 700);
    letter-spacing: 0.06em;
}

.pa-ops-tree__label {
    font-weight: var(--pa-weight-semibold, 600);
    color: var(--pa-ops-ink);
}

.pa-ops-tree__stats {
    margin-left: auto;
    font-size: var(--pa-text-xs, 0.75rem);
    color: var(--pa-ops-ink-muted-strong);
    white-space: nowrap;
}

.pa-ops-tree__children {
    display: grid;
    gap: 6px;
    margin: 6px 0 2px 14px;
    padding-left: var(--pa-space-3, 0.75rem);
    border-left: 2px solid var(--pa-ops-border);
}

.pa-ops-tree__leaves {
    display: grid;
    gap: 6px;
}

.pa-ops-tree__leaf {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
    padding: var(--pa-space-2, 0.5rem) var(--pa-space-3, 0.75rem);
    border-radius: var(--pa-ops-radius-sm);
    background: var(--pa-ops-surface);
    border: 1px solid var(--pa-ops-border-soft);
    font-size: var(--pa-text-sm, 0.8125rem);
}

.pa-ops-tree__name {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-weight: var(--pa-weight-semibold, 600);
    color: var(--pa-ops-ink);
}

.pa-ops-tree__name:hover { text-decoration: underline; }

.pa-ops-tree__code {
    padding: 2px 6px;
    border-radius: var(--pa-radius-sm, 6px);
    background: var(--pa-ops-surface-sunken);
    color: var(--pa-ops-ink-muted-strong);
    font-family: var(--pa-font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
    font-size: 0.7rem;
}

/* --------------------------------------------------------------------------
   13. Resource flow pipeline (Market)
   -------------------------------------------------------------------------- */

.pa-ops-pipeline {
    display: flex;
    align-items: stretch;
    gap: var(--pa-space-2, 0.5rem);
    flex-wrap: wrap;
}

.pa-ops-stage {
    position: relative;
    flex: 1 1 150px;
    min-width: 140px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--pa-space-2, 0.5rem);
    padding: var(--pa-space-4, 1rem) var(--pa-space-3, 0.75rem);
    border-radius: var(--pa-ops-radius);
    background: var(--pa-ops-surface);
    border: 1px solid var(--pa-ops-border-soft);
    box-shadow: var(--pa-ops-shadow);
    text-align: center;
    transition: transform 160ms ease, box-shadow 160ms ease;
}

.pa-ops-stage:hover,
.pa-ops-stage:focus-visible {
    transform: translateY(-2px);
    box-shadow: var(--pa-ops-shadow-lg);
}

/* The entry point stays the dark card — it is the one inverted surface in the
   pipeline, so it is fixed-dark in both themes. */
.pa-ops-stage--lead {
    background: var(--pa-ink-inverse, #131c27);
    border-color: var(--pa-ink-inverse, #131c27);
    color: var(--pa-ops-ink-on-dark);
}

.pa-ops-stage__icon {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: var(--pa-ops-radius-sm);
    background: var(--pa-ops-accent-soft);
    color: var(--pa-ops-accent-ink);
    font-size: 1.05rem;
}

.pa-ops-stage--lead .pa-ops-stage__icon {
    background: rgba(255, 255, 255, 0.16);
    color: var(--pa-ops-ink-on-dark);
}

.pa-ops-stage__label {
    font-size: 0.76rem;
    font-weight: var(--pa-weight-bold, 700);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--pa-ops-ink);
}

.pa-ops-stage--lead .pa-ops-stage__label { color: var(--pa-ops-ink-on-dark); }

.pa-ops-stage__role {
    font-size: var(--pa-text-xs, 0.75rem);
    color: var(--pa-ops-ink-muted-strong);
    line-height: 1.4;
}

.pa-ops-stage--lead .pa-ops-stage__role { color: var(--pa-ops-ink-on-dark-soft); }

/* Accent-coloured count: ink variant. The pipeline injects only
   `--pa-ops-accent` inline, so `--pa-ops-accent-ink` falls back through the
   console accent — which is a checked brand ink, not the raw amber. */
.pa-ops-stage__count {
    margin-top: 2px;
    font-size: 0.68rem;
    font-weight: var(--pa-weight-bold, 700);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--pa-ops-accent-ink);
}

.pa-ops-stage--lead .pa-ops-stage__count { color: #cfe7fb; }

/* The connector between two light stages: a hairline, not a white arrow on
   navy. */
.pa-ops-stage__arrow {
    align-self: center;
    flex: 0 0 auto;
    color: var(--pa-ops-ink-muted-strong);
    font-size: 0.95rem;
}

/* --------------------------------------------------------------------------
   14. Console footer strip
   -------------------------------------------------------------------------- */

/* `.pa-footer` in the admin shell: a quiet rule-backed band on the page's own
   surface, not a translucent navy strip. */
.pa-ops-foot {
    margin-top: var(--pa-ops-gap);
    border-top: 1px solid var(--pa-ops-border);
    background: var(--pa-ops-surface);
}

.pa-ops-foot__inner {
    max-width: var(--pa-ops-max);
    margin: 0 auto;
    padding: var(--pa-space-3, 0.75rem) var(--pa-space-5, 1.5rem);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pa-space-3, 0.75rem);
    flex-wrap: wrap;
    font-size: var(--pa-text-xs, 0.75rem);
    color: var(--pa-ops-ink-muted-strong);
}

.pa-ops-foot strong { color: var(--pa-ops-ink); font-weight: var(--pa-weight-semibold, 600); }

.pa-ops-foot__badges {
    display: inline-flex;
    align-items: center;
    gap: var(--pa-space-2, 0.5rem);
    flex-wrap: wrap;
}

.pa-ops-foot__badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0.15rem 0.5rem;
    border-radius: var(--pa-radius-pill, 999px);
    background: var(--pa-ops-surface-sunken);
    color: var(--pa-ops-ink-muted-strong);
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-semibold, 600);
    letter-spacing: 0.04em;
}

/* --------------------------------------------------------------------------
   15. Dark board treatment (the Forge board)

   `pa-ops--dark` is set by layouts/ops from config('prymace.pools.forge.theme')
   and is the one deliberate exception to the light console: Forge keeps the
   navy operation-centre look and must stay visually distinct.

   It is expressed purely as token overrides, so every component rule above
   serves it unchanged. Because these tokens are consumed by the same rules,
   the dark board cannot drift away from the light boards' structure.

   NOTE: this is a *board* treatment, not the app's dark theme. The app-wide
   dark theme redefines the admin tokens on an ancestor (data-theme="dark"),
   and because the light boards' tokens are `var(--pa-…)` references the light
   console follows that automatically. The Forge board is dark in both.
   -------------------------------------------------------------------------- */

.pa-ops--dark {
    /* Surfaces: navy, opaque, so a panel reads as raised rather than glassy. */
    --pa-ops-surface: #0d2444;
    --pa-ops-surface-alt: #0a1e3a;
    --pa-ops-surface-sunken: #071730;

    --pa-ops-border: rgba(120, 190, 255, 0.20);
    --pa-ops-border-soft: rgba(120, 190, 255, 0.14);
    --pa-ops-border-strong: rgba(120, 190, 255, 0.30);

    --pa-ops-ink: #ffffff;
    --pa-ops-ink-soft: #dbe7f5;
    --pa-ops-ink-muted: #a9bdd6;
    /* The tokens below are computed FROM the light ink in the base layer
       (`--pa-ops-table-head-ink: var(--pa-ops-ink-muted-strong)` and friends).
       A custom property is substituted where it is DECLARED, not where it is
       used, so redefining `--pa-ops-ink-muted` above would leave those still
       holding the light values. Any alias added to the base layer has to be
       restated here — `storage/app/pa-ops-verify.mjs` checks that. */
    --pa-ops-ink-muted-strong: #a9bdd6;
    --pa-ops-ink-muted-soft: #a9bdd6;
    --pa-ops-table-head-ink: #cfe0f5;

    /* Accent as text has to invert on a dark ground: the ink variants exist to
       clear AA on a LIGHT surface, so on the dark board they take the light
       tint instead. The raw hue keeps working as a fill. */
    --pa-ops-accent-ink: var(--pa-ops-accent-light, #cfe7fb);
    --pa-ops-accent-soft: rgba(255, 255, 255, 0.10);
    --pa-ops-accent-soft-strong: rgba(255, 255, 255, 0.18);

    /* Pills keep their own tints so a status stays recognisable, with ink dark
       enough to read on the tint (all at 4.5:1 or better). The tint/ink pairs
       here are literal rather than var() references to the admin's semantic
       tokens, because this board is dark in BOTH themes and must not follow a
       light theme's lifted inks onto its light chips. */
    --pa-ops-green: #14663a;
    --pa-ops-green-bg: #ddf3e5;
    --pa-ops-blue: #12457f;
    --pa-ops-blue-bg: #dbeafe;
    --pa-ops-amber: #7a4200;
    --pa-ops-amber-bg: #fdead7;
    --pa-ops-violet: #4b2a86;
    --pa-ops-violet-bg: #eae2fb;
    --pa-ops-gray: #3f4c5c;
    --pa-ops-gray-bg: #e8eef6;
    --pa-ops-red: #8f1d1a;
    --pa-ops-red-bg: #fbdedd;

    /* Table chrome inverts too. */
    --pa-ops-table-head-bg: rgba(3, 14, 32, 0.72);
    --pa-ops-table-head-ink: #cfe0f5;

    /* The header band and the tab strip are part of the board's chrome, not a
       light page furniture: on the dark board they keep the dark treatment and
       the Pool-coloured underline, because the light component rules read these
       tones. `--pa-ops-ink-soft` is the full-strength ink here (the label that
       used to be white on navy); `--pa-ops-ink-muted` is the quieter one. */
    --pa-ops-chip-bg: rgba(255, 255, 255, 0.08);
    --pa-ops-chip-bg-strong: rgba(255, 255, 255, 0.16);
    --pa-ops-row-hover: rgba(120, 190, 255, 0.08);
    --pa-ops-tab-ink: #ffffff;
    --pa-ops-tab-ink-soft: #a9bdd6;
    --pa-ops-link: #8fd0ff;

    /* The console chrome follows the Pool hue on the dark board instead of the
       light boards' single blue. */
    --pa-ops-console-accent: var(--pa-ops-accent);
    --pa-ops-console-accent-light: var(--pa-ops-accent-light);
    --pa-ops-console-accent-ink: #ffffff;
    --pa-ops-console-accent-soft: rgba(255, 255, 255, 0.16);

    --pa-ops-shadow: inset 0 0 0 1px rgba(120, 190, 255, 0.10), 0 14px 34px rgba(3, 14, 32, 0.45);
    --pa-ops-shadow-lg: inset 0 0 0 1px rgba(120, 190, 255, 0.16), 0 18px 40px rgba(3, 14, 32, 0.55);

    background: #061c3d;
}

.pa-ops--dark .pa-ops__page,
.pa-ops--dark.pa-ops__page {
    background: linear-gradient(170deg, #0a2348 0%, #061c3d 46%, #030e20 100%);
    background-attachment: scroll;
}

/* The dark board's KPI value is text on the dark panel, so it takes the dark
   ink rather than the light board's `--pa-ops-ink` chain. */
.pa-ops--dark .pa-ops-kpi:hover { box-shadow: var(--pa-ops-shadow); }

.pa-ops--dark .pa-ops-table tbody tr:hover td { background: rgba(120, 190, 255, 0.08); }

.pa-ops--dark .pa-ops-panel__title i { color: var(--pa-ops-accent-light); }

.pa-ops--dark .pa-ops-kpi__icon {
    background: rgba(255, 255, 255, 0.16);
    color: #ffffff;
}

/* Accent-coloured text on the dark board has to follow the board's own light
   accent: the `accent-ink` variants exist to clear AA on a *light* surface and
   are dark by definition, so on navy they would be near-invisible. */
.pa-ops--dark .pa-ops-status__metric,
.pa-ops--dark .pa-ops-accent,
.pa-ops--dark .pa-ops-section-title i,
.pa-ops--dark .pa-ops-stage__count { color: var(--pa-ops-accent-light); }

/* --------------------------------------------------------------------------
   15b. Theme-specific console tokens

   Almost everything the console draws derives from an admin token with a
   `var()`, so the dark theme reaches it without a rule here. The status dots
   cannot: they need a *different* hue from the text ink that carries the same
   meaning, because a 10px one-colour mark has nothing to hold it up. The app
   theme is read off `html[data-theme="dark"]`, the same attribute the admin
   tokens are declared on, so the two can never disagree about the theme.
   -------------------------------------------------------------------------- */

/* Neutral chips (the "completed" / "unmeasured" pills) read `--pa-muted` on
   `--pa-surface-sunken`, which the dark theme moves together — a light ink on a
   raised dark surface — so they need nothing here. That is also why the admin's
   own `.pa-badge--neutral` is a light-theme-only pairing: it keeps the light
   tint and would sit at 2.8:1 in the dark theme.

   The status dots do need stating. The admin lifts its `-ink` tokens for TEXT
   on a dark tint; as one-colour 10px marks those lifted inks would sit at 1.7:1
   on the sunken surface, so the dots take mid-tone hues in the dark theme
   instead. The Forge board restates the same three through its own selector,
   because it is dark whatever the account's theme is. */
html[data-theme="dark"] .pa-ops,
.pa-ops--dark {
    --pa-ops-dot-green: #2fa05a;
    --pa-ops-dot-blue: #2f7fd0;
    --pa-ops-dot-amber: #c8922a;
}

/* --------------------------------------------------------------------------
   16. Utilities
   -------------------------------------------------------------------------- */

/* `.pa-ops-muted` is the console's secondary-text utility and appears on every
   surface this layer draws — white panels, `--pa-surface-alt` table heads and
   even rows, and the dark board. It therefore uses the cross-surface token. */
.pa-ops-muted { color: var(--pa-ops-ink-muted-strong); }

.pa-ops-soft { color: var(--pa-ops-ink-soft); }
.pa-ops-strong { color: var(--pa-ops-ink); font-weight: var(--pa-weight-semibold, 600); }
.pa-ops-num { font-variant-numeric: tabular-nums; }
.pa-ops-sm { font-size: var(--pa-text-sm, 0.8125rem); }
.pa-ops-xs { font-size: var(--pa-text-xs, 0.75rem); }
.pa-ops-center { text-align: center; }
.pa-ops-right { text-align: right; }
.pa-ops-nowrap { white-space: nowrap; }
.pa-ops-mt { margin-top: var(--pa-space-3, 0.75rem); }
.pa-ops-mt-lg { margin-top: var(--pa-space-5, 1.5rem); }
.pa-ops-flex { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pa-ops-between { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.pa-ops-stack { display: grid; gap: 10px; }
.pa-ops-hidden { display: none !important; }

/* Accent-coloured helper text and icons — the ink variant, by definition.
   Used by the batch Hierarchy link, the tree's globe icon and the Pools
   tables' leading icons. */
.pa-ops-accent { color: var(--pa-ops-accent-ink); }

/* `.pa-card__title` size with the admin's section rhythm. It was white, which
   is why it was invisible on the public Market pages that load this layer
   without the admin stylesheet. */
.pa-ops-section-title {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: var(--pa-space-5, 1.5rem) 0 var(--pa-space-3, 0.75rem);
    color: var(--pa-ops-ink);
    font-size: var(--pa-text-md, 1.0625rem);
    font-weight: var(--pa-weight-semibold, 600);
}

.pa-ops-section-title i { color: var(--pa-ops-accent-ink); }

.pa-ops-section-title span {
    margin-left: auto;
    font-size: var(--pa-text-xs, 0.75rem);
    font-weight: var(--pa-weight-normal, 400);
    color: var(--pa-ops-ink-muted-strong);
}

/* `.pa-empty`. */
.pa-ops-empty {
    display: grid;
    place-items: center;
    gap: var(--pa-space-2, 0.5rem);
    padding: var(--pa-space-8, 3rem) var(--pa-space-5, 1.5rem);
    text-align: center;
    color: var(--pa-ops-ink-muted-strong);
}

.pa-ops-empty i {
    display: block;
    font-size: 1.75rem;
    color: var(--pa-faint, #98a2b3);
    margin-bottom: var(--pa-space-1, 0.25rem);
}

.pa-ops-empty strong { color: var(--pa-ops-ink); font-size: var(--pa-text-base, 0.9375rem); }
.pa-ops-empty p { max-width: 42ch; font-size: var(--pa-text-sm, 0.8125rem); line-height: 1.5; }

/* --------------------------------------------------------------------------
   17. Forms & buttons (nearest-Port search, withdrawal request, batch actions)

   `.pa-field` / `.pa-input` / `.pa-btn` in console clothing, so an intake form
   on a Pool board is the same form as one on /admin/users.
   -------------------------------------------------------------------------- */

.pa-ops-field { display: grid; gap: var(--pa-space-2, 0.5rem); }

.pa-ops-label {
    font-size: var(--pa-text-sm, 0.8125rem);
    font-weight: var(--pa-weight-semibold, 600);
    color: var(--pa-ops-ink);
    letter-spacing: 0;
    text-transform: none;
}

.pa-ops-hint {
    font-size: var(--pa-text-xs, 0.75rem);
    color: var(--pa-ops-ink-muted-strong);
}

.pa-ops-input,
.pa-ops-select,
.pa-ops-textarea {
    width: 100%;
    min-height: 42px;
    padding: var(--pa-space-2, 0.5rem) var(--pa-space-3, 0.75rem);
    border: 1px solid var(--pa-ops-border);
    border-radius: var(--pa-radius-sm, 6px);
    background: var(--pa-ops-surface);
    color: var(--pa-ops-ink);
    font: inherit;
    font-size: var(--pa-text-base, 0.9375rem);
    transition: border-color var(--pa-transition, 180ms ease),
                box-shadow var(--pa-transition, 180ms ease);
}

.pa-ops-input::placeholder,
.pa-ops-textarea::placeholder { color: var(--pa-faint, #98a2b3); }

.pa-ops-input:focus,
.pa-ops-select:focus,
.pa-ops-textarea:focus {
    outline: none;
    border-color: var(--pa-brand, #017fe4);
    box-shadow: 0 0 0 3px var(--pa-brand-100, #cfe7fb);
}

/* The console's primary button reads as `.pa-btn--primary`: the same shape,
   size and brand-blue fill as every other admin action (it was a navy
   gradient). The fill is `--pa-brand-700` rather than `--pa-brand` because
   white on `--pa-brand` measures 4.07:1 — the same shortfall the admin's own
   `.pa-btn--primary` has, noted in the report. #01539c is the brand one step
   down and clears 7.7:1 while reading as the same blue.

   The label is `--pa-btn-on`, the admin's own "ink for a lifted fill" token:
   white in the light theme, near-black in the dark theme, where the brand is
   lifted to #4da3ff and white on it would be 1.9:1. */
.pa-ops-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--pa-space-2, 0.5rem);
    min-height: 42px;
    padding: var(--pa-space-2, 0.5rem) var(--pa-space-4, 1rem);
    border: 1px solid var(--pa-brand-700, #01539c);
    border-radius: var(--pa-radius-sm, 6px);
    background: var(--pa-brand-700, #01539c);
    color: var(--pa-btn-on, #ffffff);
    font: inherit;
    font-size: var(--pa-text-sm, 0.8125rem);
    font-weight: var(--pa-weight-semibold, 600);
    cursor: pointer;
    transition: background var(--pa-transition, 180ms ease),
                border-color var(--pa-transition, 180ms ease),
                color var(--pa-transition, 180ms ease);
}

.pa-ops-btn:hover { background: var(--pa-brand-600, #0169c4); border-color: var(--pa-brand-600, #0169c4); color: var(--pa-btn-on, #ffffff); }
.pa-ops-btn:active { transform: translateY(1px); }
.pa-ops-btn:focus-visible { outline: 2px solid var(--pa-brand, #017fe4); outline-offset: 2px; }

/* The Pool-tinted primary. The fill is the Pool's INK, not its raw hue: amber
   #f0ad4e behind white text is 2.1:1, while its ink #8a5a00 is 7.5:1. The raw
   hue is still the identity colour on the KPI caps, meters and dots. On the
   dark board `--pa-ops-accent-ink` is the board's light tint, so the label goes
   to the dark "on" ink through the same token. */
.pa-ops-btn--accent {
    background: var(--pa-ops-accent-ink);
    border-color: var(--pa-ops-accent-ink);
    color: var(--pa-btn-on, #ffffff);
}

.pa-ops-btn--accent:hover {
    filter: brightness(1.15);
    background: var(--pa-ops-accent-ink);
    border-color: var(--pa-ops-accent-ink);
}

/* `.pa-btn--secondary` / `--ghost`. */
.pa-ops-btn--ghost {
    background: var(--pa-ops-surface);
    border-color: var(--pa-ops-border);
    color: var(--pa-ops-ink);
}

.pa-ops-btn--ghost:hover {
    background: var(--pa-ops-surface-alt);
    border-color: var(--pa-ops-ink-muted-strong);
    color: var(--pa-ops-ink);
}

.pa-ops-alert {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: var(--pa-space-3, 0.75rem) var(--pa-space-4, 1rem);
    border-radius: var(--pa-radius-sm, 6px);
    border: 1px solid transparent;
    font-size: var(--pa-text-sm, 0.8125rem);
    line-height: 1.5;
}

/* Same four tones as `.pa-alert--*`, from the same tokens, so a console notice
   and an admin notice of the same kind are the same colour in both themes. */
.pa-ops-alert--info { background: var(--pa-ops-blue-bg); border-color: var(--pa-ops-blue-border); color: var(--pa-ops-blue); }
.pa-ops-alert--warn { background: var(--pa-ops-amber-bg); border-color: var(--pa-ops-amber-border); color: var(--pa-ops-amber); }
.pa-ops-alert--ok { background: var(--pa-ops-green-bg); border-color: var(--pa-ops-green-border); color: var(--pa-ops-green); }
.pa-ops-alert--error { background: var(--pa-ops-red-bg); border-color: var(--pa-ops-red-border); color: var(--pa-ops-red); }

.pa-ops-note {
    padding: var(--pa-space-3, 0.75rem) var(--pa-space-4, 1rem);
    border-left: 3px solid var(--pa-ops-accent);
    border-radius: 0 var(--pa-radius-sm, 6px) var(--pa-radius-sm, 6px) 0;
    background: var(--pa-ops-surface-alt);
    color: var(--pa-ops-ink-soft);
    font-size: var(--pa-text-sm, 0.8125rem);
    line-height: 1.5;
}

/* --------------------------------------------------------------------------
   18. Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 1180px) {
    .pa-ops-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .pa-ops-grid,
    .pa-ops-grid--wide,
    .pa-ops-grid--even { grid-template-columns: minmax(0, 1fr); }
    .pa-ops-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .pa-ops-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 760px) {
    .pa-ops__inner { padding: 0 var(--pa-space-3, 0.75rem) var(--pa-space-4, 1rem); }
    .pa-ops-hdr__inner { padding: var(--pa-space-4, 1rem) var(--pa-space-3, 0.75rem); gap: 13px; }
    .pa-ops-hdr__logo { width: 44px; height: 44px; }
    .pa-ops-hdr__logo img { width: 32px; height: 32px; }
    .pa-ops-hdr__meta { align-items: flex-start; text-align: left; }
    .pa-ops-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .pa-ops-grid--3,
    .pa-ops-grid--4 { grid-template-columns: minmax(0, 1fr); }
    .pa-ops-bar { grid-template-columns: minmax(0, 1fr) auto; row-gap: 5px; }
    .pa-ops-bar__track { grid-column: 1 / -1; }
    .pa-ops-bar__value { justify-self: end; }
    .pa-ops-foot__inner { padding: var(--pa-space-3, 0.75rem); }
    .pa-ops-stage__arrow { display: none; }
}

@media (max-width: 480px) {
    .pa-ops-kpis { grid-template-columns: minmax(0, 1fr); }
    .pa-ops-hdr__wordmark { font-size: var(--pa-text-lg, 1.375rem); }
}

/* --------------------------------------------------------------------------
   19. Motion, print
   -------------------------------------------------------------------------- */

@keyframes pa-ops-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.55; transform: scale(0.86); }
}

@media (prefers-reduced-motion: reduce) {
    .pa-ops-live__dot { animation: none; }
    .pa-ops-bar__fill,
    .pa-ops-gauge__arc,
    .pa-ops-stage { transition: none; }
    .pa-ops-stage:hover { transform: none; }
}

/* --------------------------------------------------------------------------
   20. Console embedded in the admin shell

   The console is admin-only, so it normally renders inside the dashboard shell
   (`pa-sidebar` + `pa-main` + `pa-topbar`) with `prymace.css` loaded before this
   layer. One thing has to give way:

     - `pa-content` caps its width and adds padding, which would letterbox a
       full-bleed board. The console keeps its own `pa-ops__inner` gutter.

   The board itself now sits on the shell's own `--pa-surface-alt`, so it is
   indistinguishable from the page band every other admin screen uses.
   -------------------------------------------------------------------------- */

.pa-content--ops {
    max-width: none;
    padding: 0;
}

.pa-content--ops .pa-ops__page {
    min-height: calc(100vh - var(--pa-navbar-h, 58px));
}

@media print {
    .pa-ops__page { background: #ffffff; }
    .pa-ops-hdr { background: #ffffff; color: #000000; border-bottom: 2px solid #000000; }
    .pa-ops-hdr::after { display: none; }
    .pa-ops-hdr__wordmark,
    .pa-ops-hdr__tagline,
    .pa-ops-hdr__place,
    .pa-ops-live { color: #000000; }
    .pa-ops-kpi,
    .pa-ops-panel { box-shadow: none; border: 1px solid #999999; }
    .pa-ops-foot { background: #ffffff; color: #000000; }
}
