﻿/* ============================================================================
   portflow.css — the single stylesheet for PortFlow.
   ----------------------------------------------------------------------------
   Phase A2a: the TOKEN LAYER only. This file is additive and loads last.
   Nothing in the existing UI consumes these tokens yet, so adding it changes
   no rendered pixel; it exists so Radzen resolves its whole variable graph
   from our palette, and so later phases have one place to fold into.

   How the theming works
   ---------------------
   Radzen ships `standard-base.css`, which declares ~1,760 --rz-* variables,
   almost all of them var() chains over ~60 literal primitives (grey scale,
   brand, status, type, density). Override those primitives and every Radzen
   component re-resolves. That is all this file does for Radzen.

   Light/dark is the single axis. The class goes on BOTH <html> and <body>:
     <html class="pf-theme-dark"> selects the palette here,
     <body class="pf-theme-dark"> is what the legacy site.css rules match on.
   The palette is Night Watch, chosen in phase A4 from three candidates.

   Layer order — later layers win regardless of selector specificity.
   ============================================================================ */

@layer pf-tokens, pf-base, pf-layout, pf-components, pf-pages, pf-utilities;

/* NOTE ON LAYERS: the token blocks below are deliberately UNLAYERED. Radzen
   declares its ~1,760 --rz-* variables unlayered in standard-base.css, and an
   unlayered declaration always beats a layered one regardless of source order —
   so a bridge inside @layer would silently never apply. The @layer list above
   orders the RULES written in later phases, not these declarations. */


/* ============================================================================
   FROZEN — SLOT TYPE COLOURS. BUSINESS CRITICAL.
   ----------------------------------------------------------------------------
   These values are identical in light and dark and must never be themed.
   They mirror, exactly:
     - PortFlow.Shared/Helpers/SlotDisplayStyleHelper.cs  (authoritative; the
       Syncfusion Schedule reads its colours from there, not from CSS)
     - SlotCard.razor.css, AgentNominationSlotCard.razor.css,
       SlotEditor.razor.css, ShipperSlotListPanel.razor,
       TerminalOperatorSlotListPanel.razor
   Declared here as tokens so new markup can reference them by name instead of
   retyping hex. The existing rules are NOT changed to use them in this phase.
   DoubleBank (#efe4da / #5c4033) exists only in the C# helper today.
   ============================================================================ */

:root {
  --pf-slot-permanent-bg:      #e1efff;
  --pf-slot-permanent-border:  #78afd9;
  --pf-slot-permanent-hover:   #d4e7ff;

  --pf-slot-opportunistic-bg:     #e4f4e9;
  --pf-slot-opportunistic-border: #5fa777;
  --pf-slot-opportunistic-hover:  #d8eedf;

  --pf-slot-priority-bg:      #f9e3e3;
  --pf-slot-priority-border:  #d16a6a;
  --pf-slot-priority-hover:   #f4d6d6;

  --pf-slot-reserved-bg:      #fff0df;
  --pf-slot-reserved-border:  #d89a4b;
  --pf-slot-reserved-hover:   #ffe6c7;

  --pf-slot-terminal-bg:      #94e8d2;
  --pf-slot-terminal-border:  #4da98e;
  --pf-slot-terminal-hover:   #87dec7;

  --pf-slot-inport-bg:        #d8daef;
  --pf-slot-inport-border:    #aab3d8;
  --pf-slot-inport-hover:     #cdd2eb;
  --pf-slot-inport-fg:        #12304b;

  --pf-slot-doublebank-bg:    #efe4da;
  --pf-slot-doublebank-fg:    #5c4033;

  --pf-slot-virtualgap-bg:     #fff8dc;
  --pf-slot-virtualgap-border: #d4b106;
  --pf-slot-virtualgap-hover:  #fff3c2;

  --pf-slot-fallback-bg:      #e2e8f0;
  --pf-slot-fg:               #12304b;

  /* KPI performance bands — carried over verbatim from site.css:1248-1260 */
  --pf-band-darkgreen:    #1b5e20;  --pf-band-darkgreen-bg: rgba(27, 94, 32, .12);
  --pf-band-green:        #2e7d32;  --pf-band-green-bg:     rgba(46, 125, 50, .12);
  --pf-band-orange:       #ef6c00;  --pf-band-orange-bg:    rgba(239, 108, 0, .14);
  --pf-band-red:          #c62828;  --pf-band-red-bg:       rgba(198, 40, 40, .14);
  --pf-band-darkred:      #7f1d1d;  --pf-band-darkred-bg:   rgba(127, 29, 29, .16);
  --pf-band-none:         #94a3b8;  --pf-band-none-bg:      rgba(148, 163, 184, .12);
}

:root.pf-theme-dark {
  --pf-band-darkgreen:    #4ade80;  --pf-band-darkgreen-bg: rgba(74, 222, 128, .16);
  --pf-band-green:        #86efac;  --pf-band-green-bg:     rgba(134, 239, 172, .14);
  --pf-band-orange:       #fb923c;  --pf-band-orange-bg:    rgba(251, 146, 60, .18);
  --pf-band-red:          #f87171;  --pf-band-red-bg:       rgba(248, 113, 113, .18);
  --pf-band-darkred:      #fca5a5;  --pf-band-darkred-bg:   rgba(252, 165, 165, .22);
  --pf-band-none:         #94a3b8;  --pf-band-none-bg:      rgba(148, 163, 184, .16);
}

/* ============================================================================
   SHARED SCALES — type, spacing, radius, elevation, motion, z-index.
   Type, spacing, radius, elevation, motion, z-index.
   Small, tight and readable is the brief: 13px base, 1.4 line-height, a
   compact control height, and a numeric variant that tabular-aligns.
   ============================================================================ */

:root {
  /* Type */
  --pf-font-sans: 'Source Sans 3', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --pf-font-head: 'Plus Jakarta Sans', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --pf-font-mono: 'Roboto Mono', 'Cascadia Mono', Consolas, 'Courier New', monospace;

  --pf-fs-2xs:  0.6875rem;  /* 11px — dense table meta, chips            */
  --pf-fs-xs:   0.75rem;    /* 12px — captions, secondary labels          */
  --pf-fs-sm:   0.8125rem;  /* 13px — BASE. body, inputs, grid cells      */
  --pf-fs-md:   0.875rem;   /* 14px — emphasised body, panel titles       */
  --pf-fs-lg:   1rem;       /* 16px — section headings                    */
  --pf-fs-xl:   1.125rem;   /* 18px — page title                          */
  --pf-fs-2xl:  1.375rem;   /* 22px — dashboard hero numerals             */
  --pf-fs-3xl:  1.75rem;    /* 28px — KPI headline figure                 */

  --pf-lh-tight: 1.25;
  --pf-lh-base:  1.4;
  --pf-lh-loose: 1.6;

  --pf-fw-normal:   400;
  --pf-fw-medium:   500;
  --pf-fw-semibold: 600;
  --pf-fw-bold:     700;

  --pf-tracking-tight: -0.01em;
  --pf-tracking-wide:   0.04em;

  /* Spacing — 4px rhythm */
  --pf-space-0: 0;
  --pf-space-1: 0.25rem;
  --pf-space-2: 0.5rem;
  --pf-space-3: 0.75rem;
  --pf-space-4: 1rem;
  --pf-space-5: 1.25rem;
  --pf-space-6: 1.5rem;
  --pf-space-8: 2rem;
  --pf-space-10: 2.5rem;

  /* Radius — Quay: generous, soft */
  --pf-radius-sm: 7px;
  --pf-radius:    10px;
  --pf-radius-lg: 14px;
  --pf-radius-pill: 999px;

  /* Density — control heights */
  --pf-control-h-xs: 1.375rem;
  --pf-control-h-sm: 1.75rem;
  --pf-control-h:    2rem;
  --pf-control-h-lg: 2.5rem;

  /* Layout geometry — must match the current shell exactly */
  --pf-topbar-h:        56px;
  --pf-sidebar-w:       260px;
  --pf-sidebar-mini-w:  64px;
  --pf-page-pad-x:      20px;
  --pf-page-pad-y:      16px;

  /* Motion */
  --pf-ease:        cubic-bezier(0.4, 0, 0.2, 1);
  --pf-dur-fast:    120ms;
  --pf-dur:         200ms;
  --pf-dur-slow:    280ms;

  /* Z-index — preserves the existing stack.

     TRIED AND REVERTED: raising --pf-z-dialog above 2000 (Radzen's hardcoded popup z-index —
     every dropdown/autocomplete/datepicker panel opens at that value via Radzen's own JS, not
     themeable through any variable Radzen exposes). The idea was that a Radzen popup left open
     on a page (a filter dropdown, say) when something then opens a dialog would otherwise paint
     over the dialog -- 2000 beats 1080 -- and eat the click meant for Save/Cancel, which looks
     exactly like "the button doesn't work".

     Reverted because that same popup mechanism is used to OPEN dropdowns from WITHIN a dialog,
     and at least one of those -- the Direction dropdown inside JobCardCargoDialog, a Radzen
     DialogService modal -- renders its panel as a child of <body>, not of the dialog: a sibling
     of the dialog wrapper, not a descendant of it. --rz-dialog-zindex bridges to this same
     token, so raising it would have raised that dialog's wrapper to 2200 while its own portaled
     dropdown stayed at 2000 -- the dropdown would render BEHIND its own dialog. This app opens
     Radzen dropdowns and datepickers from inside dialogs in many places (9 dialogs built this
     session alone), and whether each one portals this way was not checked for all of them, so
     the safe assumption is that several do. Fixing the dialog-vs-stray-popup case by breaking
     the popup-vs-its-own-dialog case is not a fix. Left at the original values; the underlying
     complaint (a popup not disappearing when a dialog opens) is reported to the user as
     investigated but not resolved, rather than shipped with an unverified regression risk
     across dialogs already in production. */
  --pf-z-sidebar:   1040;
  --pf-z-backdrop:  1039;
  --pf-z-topbar:    1050;
  --pf-z-dialog:    1080;
  --pf-z-toast:     1090;
}

/* ============================================================================
   PALETTE — NIGHT WATCH
   The chosen direction. Dark-first, built for a 24-hour operations room:
   near-black ground so the screen does not light the room, cyan as the working
   colour, amber reserved strictly for states that need a human. Light mode,
   below, is the inversion for daytime desk use.

   Dark is the designed state. When a value has to give, give it in light.
   ============================================================================ */

:root {
  --pf-surface-0:  #ffffff;
  --pf-surface-1:  #eef2f6;
  --pf-surface-2:  #f5f8fb;
  --pf-surface-3:  #e3e9f0;
  --pf-surface-sunken: #e3e9f0;

  --pf-border:        #dbe3ec;
  --pf-border-strong: #b9c6d5;
  --pf-border-subtle: #e6ecf2;

  /* Ink for surfaces that stay light in BOTH themes — status tints that carry
     meaning (risk red/orange/green, tidal pink) and so cannot flip with the
     theme. Text on those grounds cannot use --pf-text, which turns near-white
     in dark mode and vanishes. Deliberately NOT redefined in the dark block:
     the whole point is that it does not move. */
  --pf-ink-on-tint:       #152130;
  --pf-ink-on-tint-muted: #46586b;

  /* Dialog form surfaces. The surface ramp is not monotonic across themes
     (light: surface-1 #eef2f6 is DARKER than surface-2 #f5f8fb; dark: it is the
     other way round), so a dialog that picks raw surface-N for its sections
     reads correctly in one theme and inverts in the other. These four say what
     they mean instead: a section is a tinted ground, a field is a well cut into
     it, and the relationship holds in both themes. */
  --pf-dlg-section-bg:     #e9eff6;
  --pf-dlg-section-border: #ccd9e6;
  --pf-dlg-field-bg:       #ffffff;
  --pf-dlg-field-border:   #a8bacd;
  /* A field is a well, so it carries a soft inner shadow rather than a glow;
     the dark theme swaps this for a lit edge. */
  --pf-dlg-field-glow:     inset 0 1px 2px rgba(21, 33, 48, .06);

  --pf-text:          #152130;
  --pf-text-muted:    #46586b;
  --pf-text-subtle:   #6f8093;
  --pf-text-inverse:  #ffffff;

  --pf-brand:          #155e94;
  --pf-brand-hover:    #1a71b0;
  --pf-brand-active:   #0f4b78;
  --pf-brand-subtle:   rgba(21, 94, 148, 0.10);
  --pf-on-brand:       #ffffff;
  /* Filled deep-blue action button (VBP/TO planner toolbars). Stays a dark
     control in both themes so its white ink holds; --pf-brand is light in dark
     mode, so using it as the second stop put the ink at 1.06 contrast. */
  --pf-action-grad:    linear-gradient(135deg, #1a4a72 0%, #155e94 100%);

  --pf-accent:         #b45309;
  --pf-accent-hover:   #d2650f;
  --pf-accent-subtle:  rgba(180, 83, 9, 0.14);
  --pf-on-accent:      #ffffff;

  --pf-focus-ring:     #155e94;

  --pf-chrome-bg:      #ffffff;
  --pf-chrome-fg:      var(--pf-text);
  --pf-nav-bg:         #0f2540;
  --pf-nav-fg:         #c7d5e4;
  --pf-nav-hover-bg:   rgba(255, 255, 255, 0.06);
  --pf-nav-active-bg:  rgba(255, 255, 255, 0.10);
  --pf-nav-active-fg:  #ffffff;
  --pf-nav-active-marker: #5aa9e6;

  --pf-success: #047857;  --pf-on-success: #ffffff;
  --pf-warning: #b45309;  --pf-on-warning: #ffffff;
  --pf-danger:  #b91c1c;  --pf-on-danger:  #ffffff;
  --pf-info:    #0369a1;  --pf-on-info:    #ffffff;

  --pf-shadow-sm: 0 1px 2px rgba(21, 33, 48, .05);
  --pf-shadow:    0 1px 2px rgba(21, 33, 48, .05), 0 4px 14px rgba(21, 33, 48, .06);
  --pf-shadow-lg: 0 24px 60px rgba(21, 33, 48, .28);

  /* ── PANEL SYSTEM — "Ledger, banded cards" ────────────────────────
     THREE PLANES, and they have to stay three. The page ground, the
     panel floating on it, and the card wells sunk into the panel. The
     previous round collapsed the header onto the panel surface and the
     panel onto the ground — same colour, one hairline between them —
     which is exactly what "no clear distinction between the panels and
     backgrounds" meant. Every value below exists to hold those three
     apart, in both modes.

     The family colour is carried by --pf-fam, set per panel by the
     .pf-panel__header--* modifiers and inherited by everything inside.
     A default is mandatory: an unset --pf-fam makes every rule below
     invalid at computed-value time, and the header loses its colour. */
  --pf-fam: var(--pf-brand);

  --pf-panel-bg:      var(--pf-surface-0);
  --pf-panel-border:  var(--pf-border-strong);
  --pf-panel-radius:  8px;
  --pf-panel-shadow:  var(--pf-shadow-sm);

  /* The card well. Sunk INTO the panel, never lifted off it — that is
     what separates a card from the panel carrying it. */
  --pf-card-bg:      #eef3f8;
  --pf-card-border:  #c3d0de;
  --pf-card-inset:   inset 0 1px 0 rgba(255, 255, 255, .7);

  /* Header band: a tint of the family colour over the panel, capped by
     a rule in that colour. Deliberately not a filled slab — --pf-brand
     is #5aa9e6 in dark mode, and white text on it fails contrast. */
  --pf-panel-head-tint: 12%;
  --pf-panel-head-bg:   color-mix(in srgb, var(--pf-fam) var(--pf-panel-head-tint), var(--pf-panel-bg));
  --pf-panel-head-fg:   color-mix(in srgb, var(--pf-fam) 85%, #000);

  /* Family accents. Semantic and deliberately separate from the frozen
     --pf-band-* KPI palette, which must never be re-used for chrome. */
  --pf-fam-brand:   var(--pf-brand);
  --pf-fam-danger:  var(--pf-danger);
  --pf-fam-success: var(--pf-success);
  --pf-fam-warning: var(--pf-warning);
  --pf-fam-info:    var(--pf-info);
  --pf-fam-slate:   #475569;
  --pf-fam-teal:    #0f766e;

  /* Chart palette. Read by wwwroot/js/pfCharts.js through
     getComputedStyle at render time, so charts re-theme from here. */
  --pf-chart-1: #155e94;  --pf-chart-2: #0f766e;  --pf-chart-3: #475569;
  --pf-chart-4: #047857;  --pf-chart-5: #b45309;  --pf-chart-6: #0369a1;
  --pf-chart-7: #6b46c1;  --pf-chart-8: #0e7490;
  --pf-chart-grid:       #e6ecf2;
  --pf-chart-tick:       #46586b;
  --pf-chart-target:     #c62828;
  --pf-chart-tooltip-bg: #152130;
}

:root.pf-theme-dark {
  --pf-surface-0:  #1b2532;   /* panel                          */
  --pf-surface-1:  #0f1721;   /* page ground                    */
  --pf-surface-2:  #222e3d;
  --pf-surface-3:  #2b3848;
  --pf-surface-sunken: #0a1119;

  --pf-border:        #2b3848;
  --pf-border-strong: #3d4d61;
  --pf-border-subtle: #26323f;

  /* Inverted deliberately: on dark the panel is #1b2532, so the field has to be
     DARKER than its section to read as a well, not lighter. Blue rather than
     neutral, and lit at the edge instead of shadowed, so a field reads as an
     instrument face on the bridge rather than a hole cut in the panel. */
  --pf-dlg-section-bg:     #253243;
  --pf-dlg-section-border: #3d4d61;
  --pf-dlg-field-bg:       #132538;
  --pf-dlg-field-border:   #3f6d99;
  --pf-dlg-field-glow:     inset 0 1px 0 rgba(140, 190, 235, .10),
                           0 0 0 1px rgba(90, 169, 230, .08),
                           0 0 6px rgba(90, 169, 230, .10);

  --pf-text:          #e7edf4;
  --pf-text-muted:    #b0bccb;
  --pf-text-subtle:   #7f8ea0;
  --pf-text-inverse:  #06203a;

  --pf-brand:          #5aa9e6;
  --pf-brand-hover:    #7dbcec;
  --pf-brand-active:   #3f8fcf;
  --pf-brand-subtle:   rgba(90, 169, 230, 0.14);
  --pf-on-brand:       #06203a;
  --pf-action-grad:    linear-gradient(135deg, #123a5e 0%, #1d6098 100%);

  --pf-accent:         #fbbf24;
  --pf-accent-hover:   #fcd34d;
  --pf-accent-subtle:  rgba(251, 191, 36, 0.16);
  --pf-on-accent:      #2b1d02;

  --pf-focus-ring:     #5aa9e6;

  --pf-chrome-bg:      #0b1420;
  --pf-chrome-fg:      var(--pf-text);
  --pf-nav-bg:         #0b1420;
  --pf-nav-fg:         #b0bccb;
  --pf-nav-hover-bg:   rgba(255, 255, 255, 0.05);
  --pf-nav-active-bg:  rgba(90, 169, 230, 0.14);
  --pf-nav-active-fg:  #ffffff;
  --pf-nav-active-marker: #5aa9e6;

  --pf-success: #34d399;  --pf-on-success: #022c1e;
  --pf-warning: #fbbf24;  --pf-on-warning: #2b1d02;
  --pf-danger:  #fb7185;  --pf-on-danger:  #37060f;
  --pf-info:    #38bdf8;  --pf-on-info:    #04202e;

  --pf-shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);
  --pf-shadow:    0 1px 2px rgba(0, 0, 0, .3), 0 4px 14px rgba(0, 0, 0, .35);
  --pf-shadow-lg: 0 24px 60px rgba(0, 0, 0, .6);

  /* Panel system — dark. Only what differs; everything else re-resolves
     through the light declarations, because a custom property that
     references another resolves at the element that uses it, not where
     it was declared.

     The card well goes DARKER than the panel here, not lighter. A
     lighter well reads as raised, and the whole point of the plane is
     that it is recessed — inverting it in dark mode would quietly undo
     the separation this system exists to create. */
  --pf-card-bg:      #131c27;
  --pf-card-border:  #3d4d61;
  --pf-card-inset:   inset 0 1px 0 rgba(255, 255, 255, .04);

  /* A heavier tint, because the family colours are brighter and the
     surface beneath them is darker. The title takes the family colour
     as-is: darkening it toward black, as light mode does, would sink it
     into the panel. */
  --pf-panel-head-tint: 24%;
  --pf-panel-head-fg:   var(--pf-fam);

  --pf-fam-slate:   #94a3b8;
  --pf-fam-teal:    #2dd4bf;

  --pf-chart-1: #5aa9e6;  --pf-chart-2: #22d3ee;  --pf-chart-3: #9cc9ee;
  --pf-chart-4: #34d399;  --pf-chart-5: #fbbf24;  --pf-chart-6: #38bdf8;
  --pf-chart-7: #a78bfa;  --pf-chart-8: #2dd4bf;
  --pf-chart-grid:       #26323f;
  --pf-chart-tick:       #b0bccb;
  --pf-chart-target:     #f87171;
  --pf-chart-tooltip-bg: #0f1721;
}

/* ============================================================================
   RADZEN BRIDGE
   Maps our tokens onto the ~60 Radzen primitives. Radzen's own base sheet
   derives its remaining ~1,700 variables from these through var() chains, so
   overriding here re-themes every Radzen component in both modes and all
   three designs, with no per-component CSS.

   Declared alongside the palette on :root so both resolve against the same
   element. The palette must NOT live on <body>: with it there, body's own var()
   substitutions resolved against a stale table while child elements resolved
   correctly. Root-declared tokens inherit everywhere and avoid that entirely.
   ============================================================================ */

:root {
  /* --- Neutral scale. Radzen reads surfaces and text off --rz-base-*. --- */
  --rz-white:  var(--pf-surface-0);
  --rz-black:  var(--pf-text);

  --rz-base-50:   var(--pf-surface-0);
  --rz-base-100:  var(--pf-surface-1);
  --rz-base-200:  var(--pf-surface-2);
  --rz-base-300:  var(--pf-border);
  --rz-base-400:  var(--pf-border-strong);
  --rz-base-500:  var(--pf-text-subtle);
  --rz-base-600:  var(--pf-text-subtle);
  --rz-base-700:  var(--pf-text-muted);
  --rz-base-800:  var(--pf-text);
  --rz-base-900:  var(--pf-text);

  --rz-base:          var(--pf-surface-2);
  --rz-base-light:    var(--pf-surface-2);
  --rz-base-lighter:  var(--pf-surface-1);
  --rz-base-dark:     var(--pf-text-muted);
  --rz-base-darker:   var(--pf-text);

  --rz-on-base:          var(--pf-text);
  --rz-on-base-light:    var(--pf-text);
  --rz-on-base-lighter:  var(--pf-text);
  --rz-on-base-dark:     var(--pf-text-inverse);
  --rz-on-base-darker:   var(--pf-text-inverse);

  /* --- Brand --- */
  --rz-primary:          var(--pf-brand);
  --rz-primary-light:    var(--pf-brand-hover);
  --rz-primary-lighter:  var(--pf-brand-subtle);
  --rz-primary-dark:     var(--pf-brand-active);
  --rz-primary-darker:   var(--pf-brand-active);
  --rz-on-primary:          var(--pf-on-brand);
  --rz-on-primary-light:    var(--pf-on-brand);
  --rz-on-primary-dark:     var(--pf-on-brand);
  --rz-on-primary-darker:   var(--pf-on-brand);
  --rz-on-primary-lighter:  var(--pf-brand);

  --rz-secondary:          var(--pf-accent);
  --rz-secondary-light:    var(--pf-accent-hover);
  --rz-secondary-lighter:  var(--pf-accent-subtle);
  --rz-secondary-dark:     var(--pf-accent-hover);
  --rz-secondary-darker:   var(--pf-accent-hover);
  --rz-on-secondary:          var(--pf-on-accent);
  --rz-on-secondary-light:    var(--pf-on-accent);
  --rz-on-secondary-dark:     var(--pf-on-accent);
  --rz-on-secondary-darker:   var(--pf-on-accent);
  --rz-on-secondary-lighter:  var(--pf-accent);

  /* --- Status --- */
  --rz-info:      var(--pf-info);
  --rz-info-light: var(--pf-info);   --rz-info-dark: var(--pf-info);
  --rz-info-darker: var(--pf-info);  --rz-info-lighter: var(--pf-brand-subtle);
  --rz-on-info: var(--pf-on-info);   --rz-on-info-light: var(--pf-on-info);
  --rz-on-info-dark: var(--pf-on-info); --rz-on-info-darker: var(--pf-on-info);
  --rz-on-info-lighter: var(--pf-info);

  --rz-success:      var(--pf-success);
  --rz-success-light: var(--pf-success);  --rz-success-dark: var(--pf-success);
  --rz-success-darker: var(--pf-success); --rz-success-lighter: var(--pf-band-green-bg);
  --rz-on-success: var(--pf-on-success);  --rz-on-success-light: var(--pf-on-success);
  --rz-on-success-dark: var(--pf-on-success); --rz-on-success-darker: var(--pf-on-success);
  --rz-on-success-lighter: var(--pf-success);

  --rz-warning:      var(--pf-warning);
  --rz-warning-light: var(--pf-warning);  --rz-warning-dark: var(--pf-warning);
  --rz-warning-darker: var(--pf-warning); --rz-warning-lighter: var(--pf-band-orange-bg);
  --rz-on-warning: var(--pf-on-warning);  --rz-on-warning-light: var(--pf-on-warning);
  --rz-on-warning-dark: var(--pf-on-warning); --rz-on-warning-darker: var(--pf-on-warning);
  --rz-on-warning-lighter: var(--pf-warning);

  --rz-danger:      var(--pf-danger);
  --rz-danger-light: var(--pf-danger);   --rz-danger-dark: var(--pf-danger);
  --rz-danger-darker: var(--pf-danger);  --rz-danger-lighter: var(--pf-band-red-bg);
  --rz-on-danger: var(--pf-on-danger);   --rz-on-danger-light: var(--pf-on-danger);
  --rz-on-danger-dark: var(--pf-on-danger); --rz-on-danger-darker: var(--pf-on-danger);
  --rz-on-danger-lighter: var(--pf-danger);

  /* --- Typography --- */
  --rz-text-font-family: var(--pf-font-sans);
  --rz-body-font-size:   var(--pf-fs-sm);
  --rz-body-line-height: var(--pf-lh-base);
  --rz-text-color:       var(--pf-text);

  --rz-text-body1-font-size:   var(--pf-fs-md);
  --rz-text-body2-font-size:   var(--pf-fs-sm);
  --rz-text-caption-font-size: var(--pf-fs-xs);
  --rz-text-button-font-size:  var(--pf-fs-sm);
  --rz-text-button-font-weight: var(--pf-fw-semibold);
  --rz-text-subtitle1-font-size: var(--pf-fs-md);
  --rz-text-subtitle2-font-size: var(--pf-fs-sm);

  /* Headings retuned down from Radzen's marketing-scale clamp() defaults —
     this is an operations console, not a landing page. */
  --rz-text-h1-font-size: var(--pf-fs-3xl);
  --rz-text-h2-font-size: var(--pf-fs-2xl);
  --rz-text-h3-font-size: var(--pf-fs-xl);
  --rz-text-h4-font-size: var(--pf-fs-lg);
  --rz-text-h5-font-size: var(--pf-fs-md);
  --rz-text-h6-font-size: var(--pf-fs-sm);
  --rz-text-h1-line-height: var(--pf-lh-tight);
  --rz-text-h2-line-height: var(--pf-lh-tight);
  --rz-text-h3-line-height: var(--pf-lh-tight);
  --rz-text-h4-line-height: var(--pf-lh-tight);
  --rz-text-h5-line-height: var(--pf-lh-tight);
  --rz-text-h6-line-height: var(--pf-lh-tight);

  /* --- Shape and density --- */
  --rz-border-radius:   var(--pf-radius);
  --rz-border-radius-1: var(--pf-radius-sm);
  --rz-border-radius-2: var(--pf-radius);
  --rz-border-radius-3: var(--pf-radius-lg);

  --rz-input-size-xs: var(--pf-control-h-xs);
  --rz-input-size-sm: var(--pf-control-h-sm);
  --rz-input-size-md: var(--pf-control-h);
  --rz-input-size-lg: var(--pf-control-h-lg);
  --rz-input-font-size-xs: var(--pf-fs-xs);
  --rz-input-font-size-lg: var(--pf-fs-md);

  /* --- Slot lifecycle steps ---
     The SLOT STATUS STEPS section says colours "come from the bridged
     --rz-steps-* variables", but nothing ever set them, so the strip has been
     running on Radzen's defaults — which is why the step titles were unreadable
     on a dark dialog. These are the bridge that comment describes. */
  --rz-steps-color:                    var(--pf-text-muted);
  --rz-steps-title-selected-color:     var(--pf-text);
  --rz-steps-number-background-color:  var(--pf-surface-3);
  --rz-steps-number-color:             var(--pf-text);
  --rz-steps-number-selected-background: var(--pf-brand);
  --rz-steps-number-selected-color:    var(--pf-on-brand);
  --rz-steps-title-margin-inline:      0.4rem;

  /* --- Date picker popup ---
     The popup renders at the end of <body>, not inside whatever dialog opened
     it, so none of the .pf-dialog__body form rules reach it. Driving Radzen's
     own variables themes it in place, and keeps working when Radzen changes its
     internal markup. */
  --rz-datepicker-panel-background-color: var(--pf-surface-0);
  --rz-datepicker-header-background-color: var(--pf-dlg-section-bg);
  --rz-datepicker-header-color:            var(--pf-text);
  --rz-datepicker-calendar-color:          var(--pf-text);
  --rz-datepicker-calendar-header-color:   var(--pf-text-muted);
  --rz-timepicker-background-color:        var(--pf-dlg-field-bg);
  --rz-timepicker-color:                   var(--pf-text);

  --rz-card-padding:  var(--pf-space-4);
  --rz-panel-padding: var(--pf-space-3);
  --rz-card-shadow:   var(--pf-shadow);
  --rz-panel-shadow:  var(--pf-shadow-sm);
  --rz-dialog-shadow: var(--pf-shadow-lg);
  --rz-header-shadow: var(--pf-shadow-sm);

  /* --- Grid: dense by default; this is a data application --- */
  --rz-grid-cell-padding:        0.375rem 0.5rem;
  --rz-grid-header-padding:      0.5rem;
  --rz-grid-header-font-size:    var(--pf-fs-xs);
  --rz-grid-header-font-weight:  var(--pf-fw-semibold);
  --rz-grid-header-text-transform: uppercase;
  --rz-grid-stripe-background-color: color-mix(in srgb, var(--pf-text) 4%, transparent);
  --rz-grid-stripe-odd-background-color: transparent;
  --rz-grid-selected-background-color: var(--pf-brand-subtle);
  --rz-grid-selected-color:            var(--pf-text);
  --rz-grid-header-background-color:   var(--pf-surface-2);

  /* The rest of what Radzen's grid actually reads. Its structural sheet
     supplies a fallback for none of these, and the colour theme that would
     normally define them is deliberately not loaded (App.razor takes
     standard-base.css alone). An undefined custom property falls back to
     the property's INITIAL value, so every cell border resolved to "none"
     and every row background to transparent: the fifteen RadzenDataGrid
     pages have been rendering borderless while the forty-two plain-table
     pages drew full token borders. That is the largest single reason two
     grids in this app did not look alike. */
  --rz-grid-background-color:          transparent;
  --rz-grid-color:                     var(--pf-text);
  --rz-grid-cell-color:                var(--pf-text);
  --rz-grid-header-color:              var(--pf-brand);
  --rz-grid-border:                    1px solid var(--pf-border);
  --rz-grid-cell-border:               1px solid var(--pf-border-subtle);
  --rz-grid-bottom-cell-border:        1px solid var(--pf-border-subtle);
  /* No vertical rules between cells: the plain tables do not draw them
     either, and column separators on a dense grid read as noise. */
  --rz-grid-right-cell-border:         0 none;
  --rz-grid-header-cell-border:        0 none;
  --rz-grid-header-cell-border-bottom: 1px solid var(--pf-border);
  --rz-grid-hover-background-color:    color-mix(in srgb, var(--pf-brand) 10%, transparent);
  --rz-grid-hover-color:               var(--pf-text);

  /* --- Dialog: one look for every modal in the app --- */
  --rz-dialog-title-font-size:   var(--pf-fs-lg);
  --rz-dialog-title-font-weight: var(--pf-fw-semibold);
  --rz-dialog-title-letter-spacing: var(--pf-tracking-tight);
  --rz-dialog-content-padding:   var(--pf-space-5);
  --rz-dialog-zindex:            var(--pf-z-dialog);
  --rz-dialog-mask-zindex:       calc(var(--pf-z-dialog) - 1);

  /* --- Shell geometry: match the existing PortFlow chrome exactly --- */
  --rz-sidebar-width:    var(--pf-sidebar-w);
  --rz-header-min-height: var(--pf-topbar-h);
  --rz-sidebar-z:        var(--pf-z-sidebar);
  --rz-header-z:         var(--pf-z-topbar);

  /* --- Panel menu (Radzen's nav) tuned to the PortFlow sidebar --- */
  --rz-panel-menu-item-background-color:        transparent;
  --rz-panel-menu-item-color:                   var(--pf-nav-fg);
  --rz-panel-menu-item-hover-background-color:  var(--pf-nav-hover-bg);
  --rz-panel-menu-item-active-background-color: var(--pf-nav-active-bg);
  --rz-panel-menu-item-active-color:            var(--pf-nav-active-fg);
  --rz-panel-menu-item-active-indicator:        var(--pf-nav-active-marker);
  --rz-panel-menu-item-border:                  none;
  --rz-panel-menu-item-border-radius:           var(--pf-radius);
  --rz-panel-menu-item-padding-block:           0.4375rem;
  --rz-panel-menu-icon-color:                   var(--pf-nav-fg);
  --rz-panel-menu-item-2nd-level-background-color:       transparent;
  --rz-panel-menu-item-2nd-level-hover-background-color: var(--pf-nav-hover-bg);
  --rz-panel-menu-item-2nd-level-active-background-color: var(--pf-nav-active-bg);
}

/* ==========================================================================
   FOLDED GLOBAL STYLESHEETS
   --------------------------------------------------------------------------
   Everything below arrived from the five global sheets that used to be linked
   separately, concatenated in their original load order so the cascade is
   unchanged. Colours were rewritten to tokens property-aware (a hex means a
   different thing as a foreground, a background and a border); anything not in
   a mapping was left as a literal rather than guessed at.

   Rules under .pf-theme-dark that hardcoded the old marine palette are now
   redundant — the tokenized light rule already resolves to the dark value under
   that selector — but they are kept. A redundant correct rule costs nothing;
   deleting a hundred of them on the same pass would make any regression
   impossible to attribute.

   Per-component .razor.css files and <style> blocks are NOT here. Each is folded
   in by the work package that migrates its component, so those files are opened
   once, not twice. REDESIGN_PROGRESS.md tracks them per file.
   ========================================================================== */


/* ==========================================================================
   FOLDED FROM app.css
   app.css — brand links/buttons/focus, plus an unscoped copy of the layout that exists as a safety net for the scoped CSS
   ========================================================================== */

:root {
    --primary-color:   #12304b;
    --accent-color:    #78afd9;
}

html, body {
    color: var(--pf-text);
}

a, .btn-link {
    color: var(--pf-brand);
}

a:hover, .btn-link:hover {
    color: var(--pf-brand-hover);
}

.btn-primary {
    color: var(--pf-text-inverse);
    background-color: var(--pf-brand);
    border-color: var(--pf-brand-active);
}

.btn-primary:hover, .btn-primary:focus {
    background-color: #1a4266;
    border-color: var(--pf-brand);
}

.btn-outline-primary {
    color: var(--pf-brand);
    border-color: var(--pf-brand);
}

.btn-outline-primary:hover {
    background-color: var(--pf-brand);
    color: var(--pf-text-inverse);
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
    box-shadow: 0 0 0 0.1rem #fff, 0 0 0 0.25rem #78afd9;
}

.content {
    padding-top: 1.1rem;
}

/* === FALLBACK SIDEBAR STYLES (safety net for scoped CSS) === */
.pf-layout {
    display: flex;
    min-height: 100vh;
    background: var(--pf-surface-1);
}

.pf-page-content {
    flex: 1;
    min-width: 0;
    padding: calc(56px + 24px) 28px 24px;
    transition: margin-left 0.28s ease;
}

.pf-topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 56px;
    background: var(--pf-chrome-bg);
    display: flex;
    align-items: center;
    padding: 0 1rem;
    gap: 0.75rem;
    z-index: 1050;
    box-shadow: none;
    border-bottom: 1px solid var(--pf-border);
}

.pf-topbar-toggle {
    background: transparent;
    border: none;
    color: var(--pf-text);
    padding: 0.3rem 0.5rem;
    border-radius: 4px;
    cursor: pointer;
    line-height: 1;
    font-size: 1.4rem;
}

.pf-topbar-brand {
    display: flex;
    align-items: center;
    gap: 8px;
    text-decoration: none;
    flex: 1;
    overflow: hidden;
}

.pf-topbar-right {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--pf-text);
    font-size: 0.85rem;
    white-space: nowrap;
    font-weight: 600;
}

.pf-sidebar {
    width: 260px;
    position: fixed;
    left: 0;
    top: 56px;
    height: calc(100vh - 56px);
    background: var(--pf-surface-2);
    color: var(--pf-brand);
    display: flex;
    flex-direction: column;
    z-index: 1040;
    transition: transform 0.28s ease, width 0.28s ease;
    overflow: hidden;
    border-right: 1px solid color-mix(in srgb, var(--pf-brand) 12%, transparent);
    box-shadow: 2px 0 16px color-mix(in srgb, var(--pf-brand) 13%, transparent);
}

.pf-sidebar-body {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 6px 0;
}

.pf-nav-list,
.pf-nav-sub-list {
    list-style: none;
}

.pf-nav-list {
    padding: 0;
    margin: 0;
}

.pf-nav-section-label {
    padding: 14px 18px 4px;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: color-mix(in srgb, var(--pf-brand) 55%, transparent);
    white-space: nowrap;
    overflow: hidden;
}

.pf-nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 14px;
    color: var(--pf-brand) !important;
    text-decoration: none !important;
    border-radius: 6px;
    margin: 1px 6px;
    transition: background 0.15s ease;
    font-size: 0.88rem;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    width: calc(100% - 12px);
    box-sizing: border-box;
    background: transparent;
}

.pf-nav-item:hover {
    background: color-mix(in srgb, var(--pf-nav-fg) 9%, transparent);
    color: var(--pf-nav-fg) !important;
}

.pf-nav-item.active {
    background: var(--pf-nav-active-bg);
    color: var(--pf-nav-fg) !important;
    font-weight: 600;
    box-shadow: inset 3px 0 0 var(--pf-nav-active-marker);
}

.pf-nav-item.disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

.pf-nav-icon {
    flex-shrink: 0;
    width: 22px;
    text-align: center;
    font-size: 1rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.pf-nav-label {
    flex: 1;
    display: flex;
    align-items: center;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pf-nav-sub-list {
    padding: 2px 0;
    margin: 0 6px 2px;
    background: color-mix(in srgb, var(--pf-brand) 7%, transparent);
    border-radius: 6px;
    overflow: hidden;
}

/* === FALLBACK NAV GROUP COLLAPSIBLE STYLES === */
.pf-nav-group-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0.62rem 1rem 0.62rem 0.875rem;
    margin: 2px 0 0;
    background: color-mix(in srgb, var(--pf-brand) 7%, transparent);
    border: none;
    border-top: 1px solid color-mix(in srgb, var(--pf-brand) 10%, transparent);
    border-radius: 0;
    cursor: pointer;
    color: var(--pf-brand);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    line-height: 1.3;
    transition: background 0.15s ease;
    white-space: nowrap;
    overflow: hidden;
}

.pf-nav-group-header:hover {
    background: color-mix(in srgb, var(--pf-brand) 13%, transparent);
}

.pf-nav-group-header:focus-visible {
    outline: 2px solid var(--pf-brand-hover);
    outline-offset: -2px;
}

.pf-nav-group-title {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pf-nav-group-chevron {
    flex-shrink: 0;
    font-size: 0.72rem;
    color: color-mix(in srgb, var(--pf-brand) 55%, transparent);
    transition: transform 0.2s ease;
    margin-left: 6px;
}

.pf-nav-group-chevron--collapsed {
    transform: rotate(-90deg);
}

.pf-nav-group-body {
    overflow: hidden;
}

.pf-nav-group-body--collapsed {
    display: none;
}

.pf-nav-group-children {
    padding: 3px 0 4px;
    margin: 0;
    background: color-mix(in srgb, var(--pf-brand) 3%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--pf-brand) 7%, transparent);
}

.pf-sidebar--mini .pf-nav-group-header {
    justify-content: center;
    padding: 0.62rem 0;
}

.pf-sidebar--mini .pf-nav-group-body {
    display: none;
}

.pf-sidebar-footer {
    padding: 8px 0 6px;
    border-top: 1px solid color-mix(in srgb, var(--pf-brand) 15%, transparent);
    flex-shrink: 0;
}

.pf-user-panel {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 14px 4px;
    color: var(--pf-brand);
    overflow: hidden;
}

.pf-user-avatar {
    flex-shrink: 0;
    color: var(--pf-brand-hover);
    font-size: 1.5rem;
    line-height: 1;
}

.pf-user-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.pf-user-name {
    font-size: 0.84rem;
    font-weight: 600;
    color: var(--pf-brand);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pf-user-role {
    font-size: 0.7rem;
    color: var(--pf-nav-fg) !important;
    white-space: nowrap;
}

.pf-sidebar-backdrop {
    position: fixed;
    top: 56px;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 1039;
}

@media (max-width: 991.98px) {
    .pf-page-content {
        margin-left: 0;
    }

    .pf-sidebar {
        transform: translateX(-100%);
    }

    .pf-sidebar.pf-sidebar--open {
        transform: translateX(0);
    }
}

@media (min-width: 992px) {
    .pf-page-content {
        margin-left: 260px;
    }

    body.pf-sidebar-mini .pf-page-content {
        margin-left: 64px;
    }

    .pf-sidebar {
        transform: translateX(0) !important;
    }

    .pf-sidebar.pf-sidebar--mini {
        width: 64px;
    }

    .pf-sidebar--mini .pf-nav-label,
    .pf-sidebar--mini .pf-nav-section-label,
    .pf-sidebar--mini .pf-user-info,
    .pf-sidebar--mini .pf-nav-sub-list {
        display: none !important;
    }

    .pf-sidebar--mini .pf-nav-item,
    .pf-sidebar--mini .pf-user-panel {
        justify-content: center;
    }
}

/* === FALLBACK SYNCFUSION SCHEDULE STYLES === */
.e-schedule .e-schedule-toolbar-container,
.e-schedule .e-schedule-toolbar-container .e-toolbar,
.e-schedule .e-schedule-toolbar-container .e-toolbar-items,
.e-schedule .e-schedule-toolbar-container .e-toolbar-left,
.e-schedule .e-schedule-toolbar-container .e-toolbar-center,
.e-schedule .e-schedule-toolbar-container .e-toolbar-right,
.e-schedule .e-schedule-toolbar,
.e-schedule .e-schedule-toolbar.e-toolbar,
.e-schedule .e-schedule-toolbar .e-toolbar-items,
.e-schedule .e-schedule-toolbar .e-toolbar-left,
.e-schedule .e-schedule-toolbar .e-toolbar-center,
.e-schedule .e-schedule-toolbar .e-toolbar-right {
    background: var(--pf-brand) !important;
    background-color: var(--pf-brand) !important;
    border-color: var(--pf-brand) !important;
    box-shadow: none !important;
}

.e-schedule .e-schedule-toolbar-container {
    border-bottom: 1px solid var(--pf-border) !important;
}

.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn .e-btn-icon,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn .e-icons,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn .e-btn-icon,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn .e-icons,
.e-schedule .e-date-range .e-tbar-btn-text {
    color: var(--pf-text-inverse) !important;
    background: transparent !important;
    background-color: transparent !important;
}

.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn:hover,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn:hover {
    background: color-mix(in srgb, var(--pf-brand-hover) 18%, transparent) !important;
    background-color: color-mix(in srgb, var(--pf-brand-hover) 18%, transparent) !important;
}

.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn:hover .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn:hover .e-icons,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn:hover .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn:hover .e-icons {
    color: var(--pf-brand-hover) !important;
}

.e-schedule .e-schedule-toolbar-container .e-active-view .e-tbar-btn,
.e-schedule .e-schedule-toolbar-container .e-active-view .e-tbar-btn .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar .e-active-view .e-tbar-btn,
.e-schedule .e-schedule-toolbar .e-active-view .e-tbar-btn .e-tbar-btn-text {
    color: var(--pf-brand-hover) !important;
    font-weight: 600 !important;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--pf-success);
}

.invalid {
    outline: 1px solid var(--pf-danger);
}

.validation-message {
    color: var(--pf-danger);
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: var(--pf-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;
}

.home-icon {
    background-image: url('images/home.png');
    background-size: cover;
    width: 30px; /* Adjust as needed */
    height: 30px; /* Adjust as needed */
    display: inline-block;
}

/* Added this CSS for the ports/precint/berths pages*/
/* Datagrid columns colour*/
/* Target the grid root (Syncfusion adds .e-grid) plus your CssClass for max specificity */
.e-grid.grid-light-theme .e-gridheader,
.e-grid.grid-light-theme .e-gridheader .e-headercell,
.e-grid.grid-light-theme .e-gridheader .e-rowcell {
    background: linear-gradient(180deg, var(--pf-surface-1) 0%, var(--pf-surface-2) 100%) !important;
    color: var(--pf-text) !important;
    font-weight: 600 !important;
    border-bottom: 1px solid var(--pf-border) !important;
}

/* Header text specifically */
.e-grid.grid-light-theme .e-headercell .e-headertext {
    color: var(--pf-text) !important;
}

/* pager & footer matching theme */
.e-grid.grid-light-theme .e-gridpager,
.e-grid.grid-light-theme .e-gridfooter {
    background: linear-gradient(180deg, var(--pf-surface-1) 0%, var(--pf-surface-2) 100%) !important;
    border-top: 1px solid var(--pf-border) !important;
}

/* overall grid card look */
.e-grid.grid-light-theme .e-grid {
    border-radius: 0.5rem;
    border: 1px solid var(--pf-border) !important;
}

.master-detail-container {
    display: grid;
    grid-template-columns: 1fr 1fr 2fr;
    gap: 8px;
    height: 80vh;
}

.master-panel, .detail-panel, .sub-detail-panel {
    padding: 2px;
    overflow-y: auto;
}

.no-selection {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--pf-text-subtle);
}

.port-item, .precinct-item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}

.list-group-item.active {
    background-color: color-mix(in lab, var(--primary-color) 35%, transparent);
    border-color: color-mix(in lab, var(--primary-color) 50%, transparent);
}

.btn-group-sm > .btn {
    padding: 0.25rem 0.5rem;
}

.crud-actions {
    border-bottom: 1px solid var(--pf-border);
    padding-bottom: 1rem;
}

/* Responsive design */
@media (max-width: 768px) {
    .master-detail-container {
        grid-template-columns: 1fr;
        grid-template-rows: auto auto auto;
    }
}
/* -- ShoreTensionDeployment: Deployment Status DDL text colour ----- */
/* site.css is NOT loaded by App.razor � this fix must live in app.css */
/* CssClass="stu-status-ddl" is placed on the outer wrapper span by    */
/* Syncfusion. Target all descendant .e-input elements from there.     */
/* Deployment Status DDL � force visible text and opaque background on dark card */
.deployment-status-ddl .e-input-group,
.deployment-status-ddl .e-input-group.e-control-wrapper {
    background: var(--pf-surface-0) !important;
    border-radius: 4px !important;
}
.deployment-status-ddl input,
.deployment-status-ddl input.e-input,
.deployment-status-ddl .e-input,
.deployment-status-ddl span.e-input-value,
.deployment-status-ddl .e-dropdownlist,
.deployment-status-ddl * {
    color: var(--pf-text) !important;
    background: transparent;
}


/* ==========================================================================
   FOLDED FROM css/MainLayout.css
   css/MainLayout.css — despite the name, only Syncfusion Schedule toolbar theming
   ========================================================================== */

/* Active sidebar and layout styles now live in `Components/Layout/MainLayout.razor.css`
   and are also duplicated in `wwwroot/app.css` as a production fallback. Keep this file
   only for global non-layout overrides that should remain outside CSS isolation. */

/* ── Syncfusion Schedule Toolbar – navy theme ────────────────────────── */
.e-schedule .e-schedule-toolbar-container,
.e-schedule .e-schedule-toolbar-container .e-toolbar,
.e-schedule .e-schedule-toolbar-container .e-toolbar-items,
.e-schedule .e-schedule-toolbar-container .e-toolbar-left,
.e-schedule .e-schedule-toolbar-container .e-toolbar-center,
.e-schedule .e-schedule-toolbar-container .e-toolbar-right,
.e-schedule .e-schedule-toolbar,
.e-schedule .e-schedule-toolbar.e-toolbar,
.e-schedule .e-schedule-toolbar .e-toolbar-items,
.e-schedule .e-schedule-toolbar .e-toolbar-left,
.e-schedule .e-schedule-toolbar .e-toolbar-center,
.e-schedule .e-schedule-toolbar .e-toolbar-right {
    background: var(--pf-brand) !important;
    background-color: var(--pf-brand) !important;
    border-color: var(--pf-brand) !important;
    box-shadow: none !important;
}

.e-schedule .e-schedule-toolbar-container {
    border-bottom: 1px solid var(--pf-border) !important;
}

/* Button text and icons: white on navy */
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn .e-btn-icon,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn .e-icons,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn .e-btn-icon,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn .e-icons,
.e-schedule .e-date-range .e-tbar-btn-text {
    color: var(--pf-text-inverse) !important;
    background: transparent !important;
    background-color: transparent !important;
}

/* Hover state */
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn:hover,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn:hover {
    background: color-mix(in srgb, var(--pf-brand-hover) 18%, transparent) !important;
    background-color: color-mix(in srgb, var(--pf-brand-hover) 18%, transparent) !important;
}

.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn:hover .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn:hover .e-icons,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn:hover .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn:hover .e-icons {
    color: var(--pf-brand-hover) !important;
}

/* Active / selected view */
.e-schedule .e-schedule-toolbar-container .e-active-view .e-tbar-btn,
.e-schedule .e-schedule-toolbar-container .e-active-view .e-tbar-btn .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar .e-active-view .e-tbar-btn,
.e-schedule .e-schedule-toolbar .e-active-view .e-tbar-btn .e-tbar-btn-text {
    color: var(--pf-brand-hover) !important;
    font-weight: 600 !important;
}


/* ==========================================================================
   FOLDED FROM css/vbp-shell.css
   css/vbp-shell.css — berth planner shell, shared by the VTS and Terminal Operator planners
   ========================================================================== */

/* ═══════════════════════════════════════════════════════════
   Berth planner shell — shared chrome
   Extracted from VisualBerthPlanner.razor.css so the Terminal
   Operator planner renders identically. Blazor's CSS isolation
   scopes a .razor.css file to one component, so anything two
   planner pages must share has to live here as a global sheet.

   Consumers: /visual-berth-planner (VTS),
              /terminaloperators/berth-planner (Terminal Operator)

   Panel and dialog styles stay isolated on VisualBerthPlanner —
   only the VTS page renders those.
   ═══════════════════════════════════════════════════════════ */

/* ── Shell ───────────────────────────────────────────────── */
.vbp-shell {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding-top: 0.5rem;
    padding-bottom: 1.5rem;
}

/* ── Row 1: Breadcrumb ───────────────────────────────────── */
.vbp-breadcrumb-row {
    padding: 0 0.25rem;
}

/* ── Row 2: Toolbar ──────────────────────────────────────── */
.vbp-toolbar-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem;
    background: var(--pf-surface-0);
    border: 1px solid var(--pf-border);
    border-radius: 10px;
    padding: 0.55rem 1rem;
    box-shadow: 0 1px 4px color-mix(in srgb, var(--pf-brand) 7%, transparent);
}

/* Left side: port label + selector */
.vbp-toolbar-left {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.vbp-port-label {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--pf-text-muted);
    white-space: nowrap;
}

.vbp-port-name {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--pf-brand);
}

.vbp-port-name .bi-geo-alt-fill {
    color: var(--pf-brand-hover);
}

.vbp-port-selector {
    min-width: 180px;
}

/* Right side: action buttons */
.vbp-toolbar-right {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Primary action — "Add Slot" */
.vbp-btn-action {
    background: var(--pf-action-grad);
    color: #ffffff;
    border: none;
    border-radius: 7px;
    font-size: 0.82rem;
    font-weight: 600;
    padding: 0.38rem 0.9rem;
    transition: background 0.18s ease, box-shadow 0.18s ease, transform 0.1s ease;
    box-shadow: 0 2px 6px color-mix(in srgb, var(--pf-brand) 25%, transparent);
}

.vbp-btn-action:hover:not(:disabled) {
    background: linear-gradient(135deg, #1e5484 0%, #1a3d5c 100%);
    box-shadow: 0 4px 10px color-mix(in srgb, var(--pf-brand) 35%, transparent);
    transform: translateY(-1px);
    color: #ffffff;
}

.vbp-btn-action:active:not(:disabled) {
    transform: translateY(0);
    box-shadow: 0 1px 4px color-mix(in srgb, var(--pf-brand) 20%, transparent);
}

.vbp-btn-action:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

/* Secondary — "Refresh" */
.vbp-btn-secondary {
    background: var(--pf-surface-0);
    color: var(--pf-brand);
    border: 1.5px solid var(--pf-border);
    border-radius: 7px;
    font-size: 0.82rem;
    font-weight: 600;
    padding: 0.36rem 0.85rem;
    transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.vbp-btn-secondary:hover:not(:disabled) {
    background: color-mix(in srgb, var(--pf-brand) 10%, var(--pf-surface-0));
    border-color: var(--pf-brand-hover);
    box-shadow: 0 2px 6px color-mix(in srgb, var(--pf-brand-hover) 25%, transparent);
    color: var(--pf-brand);
}

.vbp-btn-secondary:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* ── Row 3: Schedule card ────────────────────────────────── */
.vbp-schedule-row {
    background: var(--pf-surface-0);
    border: 1px solid var(--pf-border);
    border-radius: 12px;
    box-shadow: 0 2px 10px color-mix(in srgb, var(--pf-brand) 8%, transparent);
    overflow: hidden;
}


/* ==========================================================================
   FOLDED FROM css/ais-map.css
   css/ais-map.css — Leaflet tooltips; must stay global because Leaflet appends to the map pane, out of reach of scoped CSS
   ========================================================================== */

/* Leaflet tooltips for the AIS charts.

   Global rather than scoped, and not optional: Leaflet appends its tooltips to the map pane, outside
   the component that created them, so Blazor's scoped CSS never reaches them. Everything here is
   namespaced under .ais-tip so it cannot touch a tooltip drawn by anything else. */

.leaflet-tooltip.ais-tip-wrap {
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    box-shadow: 0 6px 18px rgba(11, 26, 41, .28);
    white-space: nowrap;
}

/* Leaflet draws the little arrow with a border colour it inherits from the tooltip; matched to the
   card's own background so the two do not disagree at the join. */
.leaflet-tooltip.ais-tip-wrap::before {
    border-top-color: var(--pf-brand);
}

.ais-tip {
    min-width: 148px;
    overflow: hidden;
    font-size: .72rem;
    line-height: 1.35;
    color: var(--pf-text);
    background: var(--pf-surface-0);
    border: 1px solid var(--pf-border);
    border-radius: 6px;
}

.ais-tip__title {
    padding: .3rem .55rem .25rem;
    font-size: .76rem;
    font-weight: 700;
    letter-spacing: .02em;
    color: var(--pf-text-inverse);
    background: linear-gradient(180deg, #2c4d65, var(--pf-brand));
}

.ais-tip__sub {
    padding: .2rem .55rem 0;
    font-size: .66rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--pf-text-subtle);
}

.ais-tip__rows {
    padding: .3rem .55rem;
    display: grid;
    /* Labels sized to content, values filling the rest: the values line up in a column however long
       the labels are, which is what makes a stack of these scannable. */
    grid-template-columns: auto 1fr;
    gap: .08rem .6rem;
}

.ais-tip__row {
    display: contents;
}

.ais-tip__k {
    color: var(--pf-text-subtle);
}

.ais-tip__v {
    font-weight: 600;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.ais-tip__foot {
    padding: .22rem .55rem .3rem;
    font-size: .66rem;
    color: var(--pf-text-subtle);
    border-top: 1px solid var(--pf-border);
    background: #f6f9fc;
}

/* Anything the feed could not vouch for. Amber rather than red: an old fix is still information,
   it just must not be read as current. */
.ais-tip__stale {
    color: var(--pf-warning);
    font-weight: 600;
}


/* ==========================================================================
   FOLDED FROM css/site.css
   css/site.css — the main sheet. Loaded last today, so its values are the ones that render
   ========================================================================== */

/* padding-top removed – layout now uses left sidebar, not a fixed top nav */
body {
    padding-top: 0;
}

/* ── Bootstrap bridge ───────────────────────────────────────────────
   The same technique used for Radzen: override the handful of primitives
   Bootstrap derives everything else from, and its utilities re-theme
   without a single per-component rule.

   The text colours are not cosmetic. Bootstrap ships --bs-secondary-color
   as rgba(33,37,41,.75) — a near-black — and never changes it, while
   .text-muted is "color: var(--bs-secondary-color) !important". Measured
   on the berth planner in dark mode, that put near-black text on a
   #1b2532 panel at a contrast ratio of 1.00: not dim, invisible. There
   are 339 uses of .text-muted across 75 components, so this was every
   caption, hint and empty-state message in the app disappearing the
   moment dark mode was switched on.

   Backgrounds are deliberately NOT bridged here. Panels and cards set
   their own surfaces a few rules below, and remapping --bs-body-bg as
   well would change things this file has no view on. */
:root {
    --bs-primary:        var(--pf-brand);
    --bs-primary-rgb:    21,94,148;
    --bs-link-color:     var(--pf-brand);
    --bs-link-hover-color: var(--pf-brand-hover);

    --bs-body-color:      var(--pf-text);
    --bs-emphasis-color:  var(--pf-text);
    --bs-secondary-color: var(--pf-text-muted);
    --bs-tertiary-color:  var(--pf-text-subtle);
    --bs-border-color:    var(--pf-border);

    /* Surfaces, after all. These were left at Bootstrap's defaults on the
       argument that panels set their own — but --bs-body-bg is #fff and a
       .table paints it into every cell, so in dark mode the grids came out
       as white slabs with near-white text on them, spilling past the
       panel's rounded corner. Mapping the surface fixes tables, modals and
       dropdowns in one place. */
    --bs-body-bg:         var(--pf-surface-0);
    --bs-secondary-bg:    var(--pf-surface-2);
    --bs-tertiary-bg:     var(--pf-surface-3);
}

/* A table paints no surface of its own. It sits on whatever panel or well
   carries it, which is the only way a grid can appear inside surfaces of
   different shades without one of them being wrong. */
.table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--pf-text);
    --bs-table-border-color: var(--pf-border);
    --bs-table-striped-bg: color-mix(in srgb, var(--pf-text) 4%, transparent);
    --bs-table-striped-color: var(--pf-text);
    --bs-table-hover-bg: color-mix(in srgb, var(--pf-brand) 10%, transparent);
    --bs-table-hover-color: var(--pf-text);
}

h1, h2, h3, h4, h5, h6 {
    color: var(--pf-brand);
}

/* The navy .card-header rule that used to sit here is gone. It had been
   dead for a while — the panel-system rule below matches
   .card-header:not(.pp-panel__header) at higher specificity and always
   won — and leaving it in place made every header read as navy when
   grepping the sheet, which is not what any page rendered. The one
   header it did still reach, the shipping list's turquoise band, sets
   its own background in .panel-header-turq later in this file. */

.card {
    border-color: color-mix(in srgb, var(--pf-brand) 12%, transparent);
    box-shadow: 0 1px 6px color-mix(in srgb, var(--pf-brand) 8%, transparent);
}

.badge.bg-primary  { background-color: var(--pf-brand) !important; }
.badge.bg-info     { background-color: var(--pf-brand-hover) !important; color: var(--pf-brand) !important; }

.form-control:focus, .form-select:focus {
    border-color: var(--pf-brand-hover);
    box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--pf-brand-hover) 30%, transparent);
}

/* Remove any conflicting margins */
.container, .container-fluid {
    margin-top: 0 !important;
    padding-top: 0 !important;
}

/* Ensure main content flows properly */
main {
    margin-top: 0;
    padding-top: 0;
}

/* Specific fix for your slotlist page */
.col-12 {
    margin-top: 0 !important;
}

/* Fix for fixed navbar */
.page-wrapper {
    padding-top: 76px; /* Height of navbar */
}

.main-content {
    min-height: calc(100vh - 76px);
}

/* Custom navbar styles */
.navbar-brand {
    font-weight: bold;
    font-size: 1.5rem;
}

.navbar-nav .nav-link {
    padding: 0.5rem 1rem;
    margin: 0 0.25rem;
    border-radius: 0.25rem;
    transition: all 0.3s ease;
}

    .navbar-nav .nav-link:hover {
        background-color: rgba(255,255,255,0.1);
    }

    .navbar-nav .nav-link.active {
        background-color: rgba(255,255,255,0.2);
        font-weight: bold;
    }

/* Dropdown styles */
.dropdown-menu {
    border: none;
    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
    border-radius: 0.5rem;
}

.dropdown-item {
    padding: 0.75rem 1rem;
    transition: all 0.2s ease;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

    .dropdown-item:hover {
        background-color: var(--pf-surface-1);
        color: var(--pf-brand);
    }

.dropdown-divider {
    margin: 0.5rem 0;
}

/* Mobile responsive */
@media (max-width: 991.98px) {
    .navbar-nav {
        text-align: center;
    }

    .nav-item {
        margin: 0.25rem 0;
    }

    .dropdown-menu {
        text-align: center;
        border: none;
        box-shadow: none;
    }
}

/* Target the grid root (Syncfusion adds .e-grid) plus your CssClass for max specificity */
.e-grid.grid-light-theme .e-gridheader,
.e-grid.grid-light-theme .e-gridheader .e-headercell,
.e-grid.grid-light-theme .e-gridheader .e-rowcell {
    background: linear-gradient(180deg, var(--pf-surface-1) 0%, var(--pf-surface-2) 100%) !important;
    color: var(--pf-text) !important;
    font-weight: 600 !important;
    border-bottom: 1px solid var(--pf-border) !important;
}

/* Header text specifically */
.e-grid.grid-light-theme .e-headercell .e-headertext {
    color: var(--pf-text) !important;
}

/* pager & footer matching theme */
.e-grid.grid-light-theme .e-gridpager,
.e-grid.grid-light-theme .e-gridfooter {
    background: linear-gradient(180deg, var(--pf-surface-1) 0%, var(--pf-surface-2) 100%) !important;
    border-top: 1px solid var(--pf-border) !important;
}

/* overall grid card look */
.e-grid.grid-light-theme .e-grid {
    border-radius: 0.5rem;
    border: 1px solid var(--pf-border) !important;
}

.pf-page-shell {
    margin-top: 0;
    padding-top: 20px;
    width: 100%;
    max-width: none;
}

.pf-page-breadcrumb {
    margin-bottom: 20px;
}

.container.mt-6,
.container.mt-8,
.container.mt-10,
.container-fluid[style*="margin-top"],
.container[style*="margin-top"] {
    width: 100% !important;
    max-width: none !important;
    margin-top: 0 !important;
    padding-top: 20px !important;
}

.container > .row.justify-content-center,
.container-fluid > .row.justify-content-center {
    width: 100%;
    margin-left: 0;
    margin-right: 0;
}

.card.shadow.p-0.mb-4.bg-body.border-1[class*="col-"],
.card.shadow.p-0.mb-12.bg-body.border-1[class*="col-"],
.card.shadow-sm.border-0[class*="col-"] {
    width: 100% !important;
    max-width: 100% !important;
    flex: 0 0 100% !important;
}

/* ════════════════════════════════════════════════════════════════════
   THE PANEL SYSTEM
   Three planes: page ground → panel → card well. Written once against
   the tokens, so choosing a different visual direction is a token swap
   and not a rewrite of these rules.

   The legacy class names are ALIASED rather than replaced. 61 razor
   files author .card-header and 14 author .pf-panel-header; 50 author
   "card shadow-sm border-0". Re-authoring all of them to get the new
   look would be a very large diff with a regression in every file that
   got missed, so instead the old selectors resolve to the new rules and
   pages inherit the band without being touched.
   ════════════════════════════════════════════════════════════════════ */

.pf-panel,
.pf-panel-card {
    background: var(--pf-panel-bg);
    border: 1px solid var(--pf-panel-border);
    border-radius: var(--pf-panel-radius);
    box-shadow: var(--pf-panel-shadow);
    overflow: hidden;
    min-width: 0;
}

/* Kept on the legacy class only: .pf-panel is used inside grids that
   own their own gap, and a stray bottom margin there breaks the row. */
.pf-panel-card {
    margin-bottom: 1.5rem;
}

/* A panel placed straight into a Bootstrap .row is still a row child,
   so it collects the row's gutter as its OWN horizontal padding — and a
   header band, drawn inside that padding, then stops 12px short of the
   panel's border on both sides. That is why the full-width panels had
   short headers while the ones nested in a .col were flush.

   The gutter belongs to columns, not to surfaces. Panels that sit
   directly in a row give it back; anything inside a real column is
   untouched, so the spacing between side-by-side panels is unchanged. */
.row > .pf-panel,
.row > .pf-panel-card,
.row > .card {
    padding-left: 0;
    padding-right: 0;
}

/* The header band. A tint of the family colour over the panel, capped
   by a 3px rule, titled in that colour — legible on both grounds, which
   a filled navy slab is not once --pf-brand turns pale in dark mode. */
.mud-card-header:not(.pp-panel__header),
.card-header:not(.pp-panel__header),
.pf-panel-header,
.pf-panel__header {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-height: 44px;

    /* Vertical padding, not a bare min-height. The old rule set
       "padding: 0 16px", so a header whose action group wrapped to a
       second line had its content jammed against the top and bottom
       edges. That is the "headers do not align in the available space"
       report, and it needs real padding rather than centring. */
    padding: .62rem 1rem;

    background: var(--pf-panel-head-bg);
    color: var(--pf-panel-head-fg);
    font-family: var(--pf-font-head);
    font-size: .78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    line-height: 1.2;
    border: 0;
    border-top: 3px solid var(--pf-fam);
    border-bottom: 1px solid var(--pf-border);
    border-radius: 0;
    box-shadow: none;
}

/* Family variants. They set one property; every rule above and below
   reads the band, the rule, the icon and the badge off it. */
.pf-panel__header--brand,   .pf-panel--brand   { --pf-fam: var(--pf-fam-brand); }
.pf-panel__header--danger,  .pf-panel--danger  { --pf-fam: var(--pf-fam-danger); }
.pf-panel__header--success, .pf-panel--success { --pf-fam: var(--pf-fam-success); }
.pf-panel__header--warning, .pf-panel--warning { --pf-fam: var(--pf-fam-warning); }
.pf-panel__header--info,    .pf-panel--info    { --pf-fam: var(--pf-fam-info); }
.pf-panel__header--slate,   .pf-panel--slate   { --pf-fam: var(--pf-fam-slate); }
.pf-panel__header--teal,    .pf-panel--teal    { --pf-fam: var(--pf-fam-teal); }

/* Alignment, for authored markup this sheet cannot restructure. The
   ops pages write a bare <div> title followed by a <div> of buttons.
   Without these the title is the element that shrinks and wraps while
   the action group holds its width. */
/* Images and icons are excluded. Several headers open with an <img> or an
   <i> rather than a title element, and telling that to grow stretched a
   20px ship icon across half the bar — which is what "the header is
   stretched" was. Only a real text container takes the free space. */
.card-header:not(.pp-panel__header) > :first-child:not(img):not(i):not(svg),
.pf-panel-header > :first-child:not(img):not(i):not(svg),
.pf-panel__header > :first-child:not(img):not(i):not(svg) {
    flex: 1 1 auto;
    min-width: 0;
}

.card-header:not(.pp-panel__header) > img,
.card-header:not(.pp-panel__header) > i,
.pf-panel-header > img,
.pf-panel-header > i,
.pf-panel__header > img,
.pf-panel__header > i {
    flex: 0 0 auto;
}

/* Shrinkable, not fixed. With "flex: 0 0 auto" the action group holds its
   max-content width forever, so its own flex-wrap never engages and the
   buttons run off the end of the panel — on a 375px screen that put the
   last button past the edge of an overflow:hidden panel, where it could
   not be reached at all. Allowing it to shrink lets the buttons wrap. */
.card-header:not(.pp-panel__header) > :last-child:not(:first-child),
.pf-panel-header > :last-child:not(:first-child),
.pf-panel__header > :last-child:not(:first-child) {
    margin-inline-start: auto;
    flex: 0 1 auto;
    min-width: 0;
}

/* Headings inside a band inherit it. Without this the global
   h1-h6 { color: var(--pf-brand) } paints them brand-blue on the tint
   — which is what turns the BerthSlotPieChart title unreadable. */
.card-header:not(.pp-panel__header) :is(h1, h2, h3, h4, h5, h6),
.pf-panel-header :is(h1, h2, h3, h4, h5, h6),
.pf-panel__header :is(h1, h2, h3, h4, h5, h6) {
    color: inherit;
    font-size: inherit;
    font-weight: inherit;
    letter-spacing: inherit;
    margin: 0;
}

.pf-panel-title,
.pf-panel__title {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    min-width: 0;
    flex: 1 1 auto;
    font-weight: 700;
}

.pf-panel-title span,
.pf-panel__title span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pf-panel__actions {
    margin-inline-start: auto;
    flex: 0 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .4rem;
}

/* Buttons sitting on the band. Bootstrap's outline variants are wired
   to --bs-primary, which has nothing to do with the panel's family. */
.card-header:not(.pp-panel__header) .btn-outline-primary,
.pf-panel-header .btn-outline-primary,
.pf-panel__header .btn-outline-primary {
    color: var(--pf-panel-head-fg);
    border-color: color-mix(in srgb, var(--pf-panel-head-fg) 40%, transparent);
}

.card-header:not(.pp-panel__header) .btn-outline-primary:hover,
.pf-panel-header .btn-outline-primary:hover,
.pf-panel__header .btn-outline-primary:hover {
    color: var(--pf-panel-head-fg);
    background: color-mix(in srgb, var(--pf-panel-head-fg) 12%, transparent);
    border-color: color-mix(in srgb, var(--pf-panel-head-fg) 60%, transparent);
}

.pf-panel-icon,
.pf-panel__icon,
.mud-card-header:not(.pp-panel__header) .mud-icon-root {
    height: 18px;
    width: auto;
    flex-shrink: 0;
    color: var(--pf-fam);
    filter: none;
}

.pf-panel-count-badge,
.pf-panel__badge {
    background: color-mix(in srgb, var(--pf-fam) 18%, transparent);
    color: var(--pf-panel-head-fg);
    font-weight: 700;
    font-size: 0.6875rem;
    letter-spacing: 0;
    text-transform: none;
    padding: 1px 9px;
    border-radius: var(--pf-radius-pill);
    line-height: 1.5;
    white-space: nowrap;
    flex: 0 0 auto;
}

.pf-panel-body,
.pf-panel__body {
    --pf-body-pad-x: .9rem;
    padding: .8rem var(--pf-body-pad-x);
}

.card-body {
    --pf-body-pad-x: var(--bs-card-spacer-x, 1rem);
}

/* ── One grid, everywhere ──────────────────────────────────────────
   Forty-two pages render a plain Bootstrap table and fifteen render a
   RadzenDataGrid. They are given the same header band, the same row
   rules and the same hover here, so which component a page happens to
   use stops being visible to the reader. */
.table > thead > tr > th {
    background: var(--pf-surface-2);
    color: var(--pf-brand);
    font-family: var(--pf-font-head);
    font-size: .68rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .04em;
    white-space: nowrap;
    padding: .5rem;
    border-bottom: 1px solid var(--pf-border);
}

.table > tbody > tr > td {
    border-bottom-color: var(--pf-border-subtle);
    vertical-align: middle;
}

/* The Radzen half of the same treatment. Its header text lives in a
   .rz-column-title inside the cell, which is why the bridged
   --rz-grid-header-font-* variables never reached it: they are declared
   on the th, and the child sets its own. Matched explicitly so a Radzen
   grid and a plain table put the same words in the same type. */
.rz-grid-table thead th,
.rz-grid-table thead th .rz-column-title,
.rz-datatable-thead > tr > th {
    font-family: var(--pf-font-head);
    font-size: .68rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--pf-brand);
}

.rz-grid-table td .rz-cell-data {
    font-size: .8125rem;
}

/* A grid runs edge to edge inside its panel, so the header band above it
   and the grid below start and end on the same pixel. Left inside the
   body's padding, the grid sat 32px narrower than the band over it —
   which is what "the header does not line up with the width of the grid"
   was. The negative margin cancels exactly the padding its own body
   declares, so it holds for both body flavours without either needing to
   know the other's value. */
.card-body > .table-responsive,
.pf-panel-body > .table-responsive,
.pf-panel__body > .table-responsive,
.card-body > .rz-datatable,
.card-body > .rz-data-grid,
.pf-panel-body > .rz-datatable,
.pf-panel-body > .rz-data-grid {
    margin-inline: calc(-1 * var(--pf-body-pad-x, 1rem));
    width: auto;
}

.card-body > .table-responsive:last-child,
.pf-panel-body > .table-responsive:last-child,
.pf-panel__body > .table-responsive:last-child {
    margin-bottom: calc(-1 * var(--pf-body-pad-y, .8rem));
}

/* ── The card well ────────────────────────────────────────────────
   The third plane. Anything that is a discrete reading — a KPI tile, a
   dial, a target bar, a TOPS row — sits in one of these so it reads as
   an object on the panel rather than as ink printed on it. */
.pf-card {
    background: var(--pf-card-bg);
    border: 1px solid var(--pf-card-border);
    border-radius: var(--pf-radius-sm);
    box-shadow: var(--pf-card-inset);
    min-width: 0;
}

/* Row form: a family rail down the left instead of a full border. */
.pf-card-row {
    background: var(--pf-card-bg);
    border: 1px solid var(--pf-card-border);
    border-left: 3px solid var(--pf-fam);
    border-radius: var(--pf-radius-sm);
    box-shadow: var(--pf-card-inset);
    min-width: 0;
}

.pf-chip-row {
    display: flex;
    flex-direction: column;
    gap: .35rem;
}

/* ── Section label inside a panel body ────────────────────────────
   Absorbs .pf-vessel-panel__section-title, which was the app's only
   intra-panel divider and is now the shared one. */
.pf-section-title,
.pf-vessel-panel__section-title {
    font-size: .72rem;
    font-weight: 700;
    color: var(--pf-fam);
    text-transform: uppercase;
    letter-spacing: .04em;
    display: flex;
    align-items: center;
    gap: .4rem;
    margin-bottom: .35rem;
}

.pf-section-title::after,
.pf-vessel-panel__section-title::after {
    content: "";
    flex: 1;
    height: 1px;
    background: color-mix(in srgb, var(--pf-fam) 20%, transparent);
}

/* ── Tab strip (Operations Dashboard, WP3) ────────────────────────
   Segmented control. Hand-rolled rather than RadzenTabs so the panes
   can be conditionally rendered and the Chart.js canvases inside them
   are created on show rather than disposed on every switch. */
.pf-tabs {
    display: inline-flex;
    flex-wrap: wrap;
    align-self: flex-start;
    gap: 2px;
    padding: 4px;
    background: var(--pf-surface-3);
    border-radius: var(--pf-radius-pill);
}

.pf-tab {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    border: 0;
    background: transparent;
    color: var(--pf-text-muted);
    font-family: var(--pf-font-head);
    font-size: .8125rem;
    font-weight: 600;
    white-space: nowrap;
    padding: .45rem .9rem;
    border-radius: var(--pf-radius-pill);
}

.pf-tab:hover {
    color: var(--pf-text);
}

.pf-tab[aria-selected="true"] {
    background: var(--pf-surface-0);
    color: var(--pf-brand);
    box-shadow: var(--pf-shadow-sm);
}

.pf-tab:focus-visible {
    outline: 2px solid var(--pf-focus-ring);
    outline-offset: 1px;
}

/* Canvas host for <PfChart> (WP2). Chart.js needs a laid-out parent
   with a real height; a percentage against an auto-height panel
   collapses to zero and the chart never draws. */
.pf-chart {
    position: relative;
    width: 100%;
    min-width: 0;
}

/* A header band must reach all three edges of its panel, always.

   Syncfusion's dashboard panels wrap our HeaderTemplate in their own
   .e-panel-header, which carries padding of 8px 18px — so the band
   rendered 36px narrower than the panel and sat 8px below its top,
   floating inside the panel instead of capping it.

   Qualified through the layout root because that is the depth
   Syncfusion writes its own rule at; a bare .e-panel-header is only
   (0,1,0) and loses. Our header owns the padding, the wrapper
   contributes none, and its fixed header height is released so the
   band can be its own height. */
.e-dashboardlayout .e-panel .e-panel-header,
.e-dashboardlayout.e-control .e-panel .e-panel-header {
    display: block;
    height: auto;
    /* Padding belongs to whichever element is actually the band. Where a
       real header is nested inside (the AIS board) this wrapper gives
       none and the child provides it; where the wrapper IS the header
       (the port dashboard) it needs its own, or the title sits flush
       against the panel edge and Syncfusion's fixed height clips it. */
    padding: .62rem 1rem;
    min-height: 44px;
}

.e-dashboardlayout .e-panel .e-panel-container .e-panel-header:has(> .ais-panel__header),
.e-dashboardlayout .e-panel .e-panel-header:has(> .ais-panel__header),
.e-dashboardlayout .e-panel .e-panel-header:has(> .pf-panel__header),
.e-dashboardlayout .e-panel .e-panel-header:has(> .pf-panel-header) {
    padding: 0;
    min-height: 0;
}

.e-dashboardlayout .e-panel .e-panel-header > * {
    width: 100%;
}

.pf-action-bar {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: 1rem;
}

.card-body > .pf-action-bar,
.card-body > .row.pb-0,
.card-body > .crud-actions,
.card-body > .d-flex.justify-content-between.align-items-center.mb-3 {
    margin-bottom: 5px !important;
}

.card-body .e-grid,
.card-body .table-responsive,
.card-body .list-group {
    margin-top: 5px;
}

.pf-loading-state,
.pf-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: var(--pf-text-subtle);
    padding: 2rem 1rem;
    gap: .5rem;
}

.pf-empty-state i {
    color: var(--pf-brand-hover);
}

.pf-loading-state .spinner-border {
    color: var(--pf-brand);
}

.pf-inline-actions {
    display: inline-flex;
    gap: .35rem;
    flex-wrap: wrap;
}

.pf-compact-badge {
    font-size: .75rem;
    font-weight: 600;
}

/* ── MOPS pilotage-duration chips (Corrections Register) ─────────────── */
.mops-hours-chip {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .15rem .55rem;
    border-radius: 999px;
    font-size: .78rem;
    font-weight: 700;
}

.mops-hours-chip--ok {
    color: #1b5e20;
    background: rgba(46, 125, 50, .12);
}

.mops-hours-chip--over {
    color: var(--pf-danger);
    background: rgba(198, 40, 40, .12);
}

body.pf-theme-dark .mops-hours-chip--ok {
    color: #86efac;
    background: rgba(46, 125, 50, .28);
}

body.pf-theme-dark .mops-hours-chip--over {
    color: #fca5a5;
    background: rgba(198, 40, 40, .28);
}

/* ── MOPS register: expandable slot rows ──────────────────────────────── */
.mops-slot-row {
    cursor: pointer;
    transition: background-color .12s;
}

.mops-slot-row:hover {
    background-color: color-mix(in srgb, var(--pf-brand) 5%, transparent);
}

body.pf-theme-dark .mops-slot-row:hover {
    background-color: color-mix(in srgb, var(--pf-brand-hover) 10%, transparent);
}

.mops-chevron {
    display: inline-block;
    transition: transform .15s ease;
}

.mops-chevron--open {
    transform: rotate(90deg);
}

/* The expanded-row panel holds a SECOND table of twelve columns, nested
   inside a cell of the outer one and — alone among the app's grids —
   wrapped in nothing that scrolls. A nested table's minimum content width
   propagates up through its cell into the outer table's column widths, so
   opening a row could push the whole register wider than its panel. It
   scrolls on its own now, and the outer grid keeps its width. */
.mops-movements-panel {
    padding: .6rem .75rem;
    background: var(--pf-surface-1);
    border-left: 3px solid var(--pf-brand-hover);
    overflow-x: auto;
    max-width: 100%;
}

body.pf-theme-dark .mops-movements-panel {
    background: color-mix(in srgb, var(--pf-brand-hover) 6%, transparent);
    border-left-color: #3b6d94;
}

/* ═══════════════════════════════════════════════════════════════════
   Global PortFlow 3D design system
   These classes are the canonical home for the 3D button + dialog
   styles used across VisualBerthPlanner, SelectedSlot, AgentVessels
   and the approval dialogs. New screens should reuse these directly.
   ═══════════════════════════════════════════════════════════════════ */

/* ── 3D action buttons ────────────────────────────────────────────── */
.pf-btn-3d {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .28rem;
    height: 34px;
    padding: 0 1.15rem;
    border: none;
    border-radius: 6px;
    font-size: .8rem;
    font-weight: 700;
    letter-spacing: .02em;
    cursor: pointer;
    color: var(--pf-text-inverse);
    text-shadow: 0 1px 2px rgba(0, 0, 0, .2);
    transition: transform .08s, box-shadow .08s, opacity .12s;
}

.pf-btn-3d:active:not(:disabled) {
    transform: translateY(2px);
}

.pf-btn-3d:disabled {
    opacity: .55;
    cursor: not-allowed;
}

.pf-btn-3d--save,
.pf-btn-3d--primary {
    background: linear-gradient(180deg, var(--pf-success) 0%, var(--pf-success) 55%, #15803d 100%);
    box-shadow: 0 4px 0 #166534, 0 2px 6px rgba(22, 163, 74, .35);
}

.pf-btn-3d--save:hover:not(:disabled),
.pf-btn-3d--primary:hover:not(:disabled) {
    background: linear-gradient(180deg, #34d399 0%, var(--pf-success) 55%, var(--pf-success) 100%);
    color: var(--pf-text-inverse);
}

.pf-btn-3d--save:active:not(:disabled),
.pf-btn-3d--primary:active:not(:disabled) {
    box-shadow: 0 2px 0 #166534;
}

.pf-btn-3d--cancel,
.pf-btn-3d--secondary {
    background: linear-gradient(180deg, #6b7280 0%, #4b5563 55%, #374151 100%);
    box-shadow: 0 4px 0 #1f2937, 0 2px 6px rgba(75, 85, 99, .3);
}

.pf-btn-3d--cancel:hover:not(:disabled),
.pf-btn-3d--secondary:hover:not(:disabled) {
    background: linear-gradient(180deg, #7b8290 0%, #5b6573 55%, #47515f 100%);
    color: var(--pf-text-inverse);
}

.pf-btn-3d--cancel:active:not(:disabled),
.pf-btn-3d--secondary:active:not(:disabled) {
    box-shadow: 0 2px 0 #1f2937;
}

.pf-btn-3d--reject,
.pf-btn-3d--danger {
    background: linear-gradient(180deg, var(--pf-danger) 0%, var(--pf-danger) 55%, #b91c1c 100%);
    box-shadow: 0 4px 0 #7f1d1d, 0 2px 6px rgba(220, 38, 38, .3);
}

.pf-btn-3d--reject:hover:not(:disabled),
.pf-btn-3d--danger:hover:not(:disabled) {
    background: linear-gradient(180deg, #f87171 0%, var(--pf-danger) 55%, var(--pf-danger) 100%);
    color: var(--pf-text-inverse);
}

.pf-btn-3d--reject:active:not(:disabled),
.pf-btn-3d--danger:active:not(:disabled) {
    box-shadow: 0 2px 0 #7f1d1d;
}

.pf-btn-3d--warn {
    background: linear-gradient(180deg, var(--pf-warning) 0%, var(--pf-warning) 55%, #b45309 100%);
    box-shadow: 0 4px 0 #78350f, 0 2px 6px rgba(217, 119, 6, .35);
}

.pf-btn-3d--warn:hover:not(:disabled) {
    background: linear-gradient(180deg, #fbbf24 0%, var(--pf-warning) 55%, var(--pf-warning) 100%);
    color: var(--pf-text-inverse);
}

.pf-btn-3d--warn:active:not(:disabled) {
    box-shadow: 0 2px 0 #78350f;
}

/* ── ShoreTensionDeployment: Deployment Status DDL text colour fix ── */
/* NOTE: site.css is not loaded by App.razor — this rule has no effect. */
/* The active fix is in app.css at the bottom of the file.              */

/* ── 3D dialog header / body / footer ─────────────────────────────── */
/* Apply .pf-dialog-standard as a CssClass on SfDialog. The wrapper class
   pierces Syncfusion's portal markup with descendant selectors so it
   works from a global stylesheet (no ::deep needed). */
.pf-dialog-standard .e-dlg-header-content {
    background: linear-gradient(180deg, #4a6b84 0%, #2c4d65 40%, #1a3550 70%, var(--pf-brand) 100%) !important;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.18),
        inset 0 -1px 0 rgba(0, 0, 0, 0.25),
        0 4px 10px rgba(0, 0, 0, 0.35) !important;
    color: var(--pf-text-inverse) !important;
}

.pf-dialog-standard .e-dlg-header-content .e-dlg-header,
.pf-dialog-standard .e-dlg-header-content * {
    color: var(--pf-text-inverse) !important;
}

.pf-dialog-standard .e-dlg-header-content .e-btn.e-dlg-closeicon-btn,
.pf-dialog-standard .e-dlg-header-content .e-dlg-closeicon-btn .e-icons {
    color: var(--pf-text-inverse) !important;
}

/* Dialog content area background — matches visual-planner-slot-dialog style */
.pf-dialog-standard .e-dlg-content {
    background: var(--pf-surface-0);
    padding: .85rem 1rem;
}

/* Footer area inside dialog content */
.pf-dialog-standard .e-dlg-footercontent {
    background: var(--pf-surface-0);
    border-top: 1px solid var(--pf-border);
    padding: .5rem 1rem;
}

/* Bordered body container — use as the inner wrapper inside <Content> */
.pf-dialog-body {
    background: var(--pf-surface-1);
    border: 1px solid var(--pf-border);
    border-radius: 8px;
    padding: .85rem 1rem;
    margin-bottom: .5rem;
}

.pf-dialog-footer {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: .5rem;
    padding-top: .5rem;
}

/* ── DarkSlateGray badge text — global standard ───────────────────── */
.pf-badge-darkslate {
    color: #2f4f4f !important;
}

.stu-status-ddl input.e-input,
  .stu-status-ddl .e-input,
  .stu-status-ddl span.e-input-value,
  .stu-status-ddl .e-dropdownlist {
      color: var(--pf-text) !important;
  }

/* ── Shared panel header styling (matches /operations/port-performance) ── */
.pp-panel__header {
    padding: 0.75rem 1rem;
    border-radius: 0.5rem 0.5rem 0 0;
    margin-bottom: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.panel-header-turq {
    background: linear-gradient(180deg, #99F6E4 0%, #5EEAD4 100%);
    border: 1px solid var(--pf-brand);
    border-bottom: 0;
    box-shadow: 0 2px 4px rgba(45, 212, 191, 0.25);
    color: #0F766E;
    font-weight: 600;
    font-size: 1rem;
}

/* Shipping List Display table styling */
.shipping-list-display.table {
    border-collapse: separate;
    border-spacing: 0;
}

.shipping-list-display td,
.shipping-list-display th {
    border-left: 1px solid var(--pf-border) !important;
    border-right: 1px solid var(--pf-border) !important;
    border-top: 0;
    border-bottom: 0;
}

.shipping-list-display th {
    text-align: center;
}

/* Compact day-group headers (TODAY / TOMORROW / DAY AFTER TOMORROW) */
.date-header-small {
    font-size: 0.9rem;
    padding: 0.5rem 0.75rem;
}

/* Mobile responsive tweaks for the Shipping List Display */
@media (max-width: 768px) {
    .shipping-list-display .card-header,
    .shipping-list-display .card-body {
        padding: 0.5rem;
    }

    .shipping-list-display .sld-table th,
    .shipping-list-display .sld-table td {
        font-size: .7rem;
    }
}

/* ═══════════════════════════════════════════════════════════════════
   PortFlow — Marine 3D Premium
   LIGHT = airy marine: sky-blue page (#f0f9ff), white appbar,
           marine-blue/seafoam accents.
   DARK  = deep ocean: navy page (#0c1a2a) + dark appbar.
   CRITICAL RULE: panels/cards keep the WHITE SMOKE surface (#f8fafc)
   in BOTH modes — content always sits on a light surface; only the
   shells (page background, appbar, drawer, headers) change.
   Dark overrides scope to body.pf-theme-dark (synced by
   ThemeControl.razor).

   PROTECTED — BERTH SLOT COLORS BUSINESS CRITICAL — DO NOT MODIFY:
   .slot-type-*, .slot-card, .permanent-slot, .opportunistic-slot,
   .priority-slot, .reserved-slot. No rule in this section may target
   them; panel overrides explicitly exclude .slot-card.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Base: Inter + theme-aware page shell ────────────────────────── */
body {
    font-family: var(--pf-font-sans);
    background-color: var(--pf-surface-1);
    color: var(--pf-text);
}

.mud-main-content {
    background: var(--pf-surface-1);
}

/* Smooth 200ms theme switch on the main surfaces.

   The header selectors are DELIBERATELY absent. Their background is now
   a color-mix() over a custom property, and a background-color
   transition across that never resolves in Chromium: measured 4 Sep
   2026, a header left in this list still reported the LIGHT tint two
   and a half seconds after the dark class went on, while the same
   element with transition:none reported the correct dark value
   immediately. Every .card-header in the app — 61 files — would render
   the light band in dark mode. A header that snaps while its panel
   fades is not perceptible; a header stuck in the wrong theme is. */
body,
.card,
.card-body,
.mud-card,
.mud-paper,
.mud-appbar,
.mud-table,
.mud-table-cell,
.mud-dialog,
.modal-content,
.table,
.sld-day-header {
    transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

/* .pf-topbar and .pf-sidebar are deliberately NOT in that list. Their fills come
   from a custom property, and a background-color transition over a var() that
   changed can sit on the old frame in Chromium until something forces a recalc —
   on the topbar that meant the ink flipped to the new theme while the bar kept
   the old one, so for a second every control in it was invisible. Same reason the
   panel headers are absent from it. */

/* Utility used by ShippingListDisplay MudCards */
.rounded-xl {
    border-radius: 16px !important;
    overflow: hidden;
}

/* ── PANEL CONTAINER RULE: white smoke in BOTH modes ──────────────
   v4: crisp 1px border + subtle shadow so panels don't "lose" their
   edges against the light page background. */
.mud-card,
.mud-paper:not(.e-schedule) {
    background: var(--pf-surface-0) !important;
    border-radius: 10px;
    border: 1px solid color-mix(in srgb, var(--pf-text-subtle) 80%, transparent);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

.card:not(.slot-card) {
    background-color: var(--pf-panel-bg);
    border-radius: var(--pf-panel-radius);
    border: 1px solid var(--pf-panel-border);
    box-shadow: var(--pf-panel-shadow);
    overflow: hidden;
    color: var(--pf-text);
}

/* Fifty razor files write "card shadow-sm border-0". Bootstrap's
   .border-0 is { border: 0 !important }, so those panels have no edge
   at all against the page — a second, quieter cause of the panels not
   reading as separate surfaces.

   Drawn as an OUTLINE, not a box-shadow. Those same files pair
   border-0 with shadow-sm, which Bootstrap also marks !important, so a
   box-shadow ring here is overwritten and the edge never appears.
   Nothing claims outline, and modern engines follow border-radius with
   it, so the ring lands where the border would have been. */
.card.border-0:not(.slot-card) {
    outline: 1px solid var(--pf-panel-border);
    outline-offset: -1px;
}

body.pf-theme-dark .mud-card,
body.pf-theme-dark .mud-paper:not(.e-schedule) {
    border: 1px solid rgba(51, 65, 85, 0.6);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

.modal-content,
.dropdown-menu {
    background-color: var(--pf-surface-0);
}

/* Dark mode: panels stay light, so content on them must stay DARK
   (MudBlazor's dark TextPrimary #f8fafc would be white-on-white) */
body.pf-theme-dark .mud-card,
body.pf-theme-dark .mud-paper:not(.e-schedule),
body.pf-theme-dark .card:not(.slot-card),
body.pf-theme-dark .modal-content,
body.pf-theme-dark .dropdown-menu,
body.pf-theme-dark .mud-dialog,
body.pf-theme-dark .mud-table,
body.pf-theme-dark .mud-table .mud-table-cell {
    color: var(--pf-text);
}

body.pf-theme-dark .mud-input input,
body.pf-theme-dark .mud-input textarea,
body.pf-theme-dark .mud-input .mud-input-slot,
body.pf-theme-dark .mud-select .mud-input {
    color: var(--pf-text);
}

/* ── Headings — Plus Jakarta Sans carries the page/panel identity ─── */
h1, h2, h3, h4, h5, h6 {
    color: var(--pf-text);
    font-family: var(--pf-font-head);
    font-weight: 650;
    letter-spacing: -0.01em;
}

/* On the dark ocean page shell, headings are light… */
body.pf-theme-dark h1,
body.pf-theme-dark h2,
body.pf-theme-dark h3,
body.pf-theme-dark h4,
body.pf-theme-dark h5,
body.pf-theme-dark h6 {
    color: var(--pf-text);
}

/* …but inside light panels they stay dark */
body.pf-theme-dark .card h1, body.pf-theme-dark .card h2,
body.pf-theme-dark .card h3, body.pf-theme-dark .card h4,
body.pf-theme-dark .card h5, body.pf-theme-dark .card h6,
body.pf-theme-dark .mud-card h1, body.pf-theme-dark .mud-card h2,
body.pf-theme-dark .mud-card h3, body.pf-theme-dark .mud-card h4,
body.pf-theme-dark .mud-card h5, body.pf-theme-dark .mud-card h6,
body.pf-theme-dark .mud-paper h1, body.pf-theme-dark .mud-paper h2,
body.pf-theme-dark .mud-paper h3, body.pf-theme-dark .mud-paper h4,
body.pf-theme-dark .mud-paper h5, body.pf-theme-dark .mud-paper h6,
body.pf-theme-dark .modal-content h1, body.pf-theme-dark .modal-content h2,
body.pf-theme-dark .modal-content h3, body.pf-theme-dark .modal-content h4,
body.pf-theme-dark .modal-content h5, body.pf-theme-dark .modal-content h6 {
    color: var(--pf-text);
}

/* ── Quay topbar: flat, quiet chrome. The navy identity is the sidebar's;
   the topbar is just the panel surface with a hairline seam. ────────── */
.mud-appbar,
.pf-layout .pf-topbar {
    background: var(--pf-chrome-bg);
    border-bottom: 1px solid var(--pf-border);
    box-shadow: none;
    padding: 8px 24px;
}

/* Controls on the flat topbar: theme-aware ink, no forced white. */
.pf-layout .pf-topbar .pf-topbar-toggle,
.pf-layout .pf-topbar .pf-topbar-right {
    color: var(--pf-text);
}

.pf-layout .pf-topbar .pf-topbar-right .text-white {
    color: var(--pf-text) !important;
}

.pf-layout .pf-topbar .btn-outline-light {
    color: var(--pf-text);
    border-color: var(--pf-border-strong);
}

.pf-layout .pf-topbar .btn-outline-light:hover {
    color: var(--pf-on-brand);
    background: var(--pf-brand);
    border-color: var(--pf-brand);
}

/* The toggle is a bare <button>: with only a colour set it kept the UA's own
   light button face, so in dark mode a light icon sat on a light box and read as
   an empty square. It needs the same chrome reset as .pf-topbar-toggle. */
.pf-theme-toggle {
    background: transparent;
    border: none;
    color: var(--pf-text) !important;
    padding: 0.3rem 0.5rem;
    border-radius: 4px;
    cursor: pointer;
    line-height: 1;
    font-size: 1.15rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.pf-theme-toggle:hover {
    background: color-mix(in srgb, var(--pf-text) 8%, transparent);
}

.pf-layout .pf-topbar .pf-topbar-toggle:hover {
    background: color-mix(in srgb, var(--pf-text) 8%, transparent);
}

/* The wordmark PNG is navy ink — reads fine unfiltered on the light topbar.
   On the dark topbar it needs to go light, same logic as any dark ink on a
   dark ground. */
body.pf-theme-dark .pf-topbar-brand img {
    filter: brightness(0) invert(1);
}

/* The profile link in the top bar. Was SideMenu's one remaining inline style. */
.pf-topbar-user {
    display: flex;
    align-items: center;
    gap: var(--pf-space-1);
    color: var(--pf-chrome-fg);
    text-decoration: none;
}

.pf-topbar-user:hover {
    color: var(--pf-chrome-fg);
    text-decoration: underline;
}

/* The sidebar's own background/foreground is set once, correctly, further down
   at .pf-layout .pf-sidebar (Quay: navy in both modes) — a higher-specificity
   body.pf-theme-dark override used to live here and repaint it back to
   --pf-surface-1 in dark mode specifically, which is why the sidebar went the
   wrong navy only when dark mode was on. Removed; nothing needs it. */

/* .slp-modal-header is gone: it dressed the Bootstrap modal headers in
   ShippingListPlanner, and C6 moved all six of those dialogs into PfDialog, which
   owns its own header and its own Danger tone. Nothing in the app writes the class
   any more. The scoped duplicate in ShippingListPlanner.razor.css went with it —
   along with the black-on-blue title bug the two copies disagreed about. */

/* ── MudTable: marine headers — light surface in BOTH modes ──────── */
.mud-table thead .mud-table-cell,
.mud-table .mud-table-head .mud-table-cell {
    background-color: var(--pf-surface-1);
    text-transform: uppercase;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--pf-brand);
    border-bottom: 2px solid var(--pf-border);
}

/* Full-height headers only on non-dense tables — dense shipping-list
   tables keep their locked compact layout */
.mud-table:not(.mud-table-dense) thead .mud-table-cell {
    height: 56px;
    padding: 18px;
}

.mud-table.mud-table-hover .mud-table-body .mud-table-row:hover {
    background-color: var(--pf-surface-1);
}

/* Dark palette would paint white-alpha stripes/hover on the light
   surface — pin them to marine tints instead */
body.pf-theme-dark .mud-table thead .mud-table-cell,
body.pf-theme-dark .mud-table .mud-table-head .mud-table-cell {
    background-color: var(--pf-surface-1);
    color: var(--pf-brand);
}

body.pf-theme-dark .mud-table.mud-table-hover .mud-table-body .mud-table-row:hover {
    background-color: var(--pf-surface-2);
}

body.pf-theme-dark .mud-table .mud-table-body .mud-table-row:nth-of-type(odd) {
    background-color: rgba(224, 242, 254, 0.5);
}

body.pf-theme-dark .table {
    color: var(--pf-text);
}

/* ── Dialogs: marine premium ─────────────────────────────────────── */
.mud-dialog {
    border-radius: 20px;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.18);
    overflow: hidden;
}

.mud-dialog .mud-dialog-title {
    min-height: 72px;
    padding: 24px 28px;
    display: flex;
    align-items: center;
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%);
    color: var(--pf-text-inverse);
    font-size: 1.25rem;
    font-weight: 600;
    border-radius: 20px 20px 0 0;
}

.mud-dialog .mud-dialog-title .mud-icon-root,
.mud-dialog .mud-dialog-title .mud-typography {
    color: var(--pf-text-inverse);
}

.mud-dialog .mud-dialog-content {
    padding: 28px;
}

body.pf-theme-dark .mud-dialog .mud-dialog-title {
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%);
}

/* Syncfusion dialogs join the same gradient system; their content
   stays on the light surface in both modes */
.pf-dialog-standard .e-dlg-header-content {
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%) !important;
    box-shadow: 0 4px 16px color-mix(in srgb, var(--pf-brand) 25%, transparent) !important;
}

body.pf-theme-dark .pf-dialog-standard .e-dlg-header-content {
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%) !important;
    box-shadow: 0 4px 16px color-mix(in srgb, var(--pf-brand) 40%, transparent) !important;
}

/* ── 3D Marine filter buttons ────────────────────────────────────── */
.btn-filter-3d {
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%);
    border: none;
    border-radius: 12px;
    padding: 12px 24px;
    color: var(--pf-text-inverse);
    font-weight: 600;
    box-shadow: 0 6px 20px color-mix(in srgb, var(--pf-brand) 25%, transparent);
    transition: transform 0.2s, box-shadow 0.2s;
}

.btn-filter-3d:hover {
    transform: translateY(-3px);
    color: var(--pf-text-inverse);
}

/* Shipping-list instances keep their compact padding (locked layout)
   but adopt the marine gradient. !important matches legacy rules. */
.shipping-list-display .btn-filter-3d,
.shipping-list-display .btn-filter-3d:focus {
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%) !important;
    border: none !important;
    border-radius: 12px !important;
    box-shadow:
        0 6px 20px color-mix(in srgb, var(--pf-brand) 25%, transparent),
        inset 0 1px 0 rgba(255, 255, 255, 0.25) !important;
    color: var(--pf-text-inverse) !important;
    font-weight: 600 !important;
    padding: 0.5rem 1rem !important;
    position: relative !important;
    top: 0 !important;
    transition: transform 0.2s, box-shadow 0.2s !important;
}

.shipping-list-display .btn-filter-3d.active {
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%) !important;
    box-shadow:
        0 2px 8px color-mix(in srgb, var(--pf-brand) 50%, transparent),
        inset 0 2px 4px rgba(0, 0, 0, 0.15) !important;
    top: 2px !important;
}

.shipping-list-display .btn-filter-3d:hover:not(.active) {
    transform: translateY(-3px) !important;
    box-shadow:
        0 10px 24px color-mix(in srgb, var(--pf-brand) 40%, transparent),
        inset 0 1px 0 rgba(255, 255, 255, 0.3) !important;
}

body.pf-theme-dark .btn-filter-3d,
body.pf-theme-dark .shipping-list-display .btn-filter-3d,
body.pf-theme-dark .shipping-list-display .btn-filter-3d:focus {
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%) !important;
    box-shadow:
        0 6px 20px color-mix(in srgb, var(--pf-brand) 40%, transparent),
        inset 0 1px 0 rgba(255, 255, 255, 0.12) !important;
    color: var(--pf-text-inverse) !important;
}

body.pf-theme-dark .shipping-list-display .btn-filter-3d.active {
    background: linear-gradient(135deg, var(--pf-brand) 0%, #155e75 100%) !important;
    box-shadow:
        0 2px 8px rgba(14, 116, 144, 0.5),
        inset 0 2px 4px rgba(0, 0, 0, 0.25) !important;
}

body.pf-theme-dark .shipping-list-display .btn-filter-3d:hover:not(.active) {
    box-shadow:
        0 10px 24px color-mix(in srgb, var(--pf-brand) 55%, transparent),
        inset 0 1px 0 rgba(255, 255, 255, 0.18) !important;
}

/* ── Forms: marine focus rings; inputs stay light in both modes ──── */
.form-control:focus,
.form-select:focus {
    border-color: var(--pf-brand);
    box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--pf-brand) 25%, transparent);
}

body.pf-theme-dark .form-control,
body.pf-theme-dark .form-select {
    background-color: var(--pf-surface-0);
    border-color: var(--pf-border);
    color: var(--pf-text);
}

/* The floating label is Bootstrap's own `rgba(var(--bs-body-color-rgb), .65)`,
   which stays near-black whatever the theme does. The rule above turns the input
   it sits inside to --pf-surface-0, so in dark mode the label is black ink on a
   near-black field — invisible, not merely low-contrast.

   Found on /Account/ForgotPassword in C1, but it is not an identity bug: it hits
   every .form-floating in the app. That is 14 identity pages and ContactUs, which
   is why the fix is here and not in the auth block. Login escaped it only because
   .pf-auth-body sets the colour itself. */
body.pf-theme-dark .form-floating > label {
    color: var(--pf-text-muted);
}

body.pf-theme-dark .form-floating > .form-control:focus ~ label,
body.pf-theme-dark .form-floating > .form-control:not(:placeholder-shown) ~ label {
    color: var(--pf-text-subtle);
}

body.pf-theme-dark .form-control:focus,
body.pf-theme-dark .form-select:focus {
    border-color: var(--pf-brand);
    box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--pf-brand) 30%, transparent);
}

/* ── Shipping List Display: theme companions (CSS only — the .razor
      structure and its 3 fixes are locked) ──────────────────────── */
.shipping-list-display .sld-banner {
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%);
    color: var(--pf-text-inverse);
}

body.pf-theme-dark .shipping-list-display .sld-banner {
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%);
}

/* Day headers sit on the light panel in both modes — marine tint */
.sld-day-header {
    background: var(--pf-surface-2);
    color: var(--pf-brand);
}

/* ── Syncfusion Schedule: PROTECTED grid ─────────────────────────
   No theme border/radius/shadow on .e-schedule — the Berthing
   Schedule grid (slot colors, grid lines) must stay untouched. The
   panel rule above already excludes it via :not(.e-schedule). Only
   the toolbar (not the grid) carries theme colors below. */

/* Light: marine gradient toolbar (overrides legacy navy in
   MainLayout.css — same !important, later in cascade) */
.e-schedule .e-schedule-toolbar-container,
.e-schedule .e-schedule-toolbar-container .e-toolbar,
.e-schedule .e-schedule-toolbar-container .e-toolbar-items,
.e-schedule .e-schedule-toolbar,
.e-schedule .e-schedule-toolbar.e-toolbar,
.e-schedule .e-schedule-toolbar .e-toolbar-items {
    background: linear-gradient(135deg, var(--pf-brand) 0%, var(--pf-brand) 100%) !important;
    border-color: var(--pf-brand) !important;
}

.e-schedule .e-schedule-toolbar-container {
    border-bottom: 3px solid var(--pf-brand) !important;
}

.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn:hover .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn:hover .e-icons,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn:hover .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn:hover .e-icons {
    color: #cffafe !important;
}

.e-schedule .e-schedule-toolbar-container .e-active-view .e-tbar-btn,
.e-schedule .e-schedule-toolbar-container .e-active-view .e-tbar-btn .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar .e-active-view .e-tbar-btn,
.e-schedule .e-schedule-toolbar .e-active-view .e-tbar-btn .e-tbar-btn-text {
    color: #a5f3fc !important;
}

/* Dark: deep navy toolbar with teal accent */
body.pf-theme-dark .e-schedule .e-schedule-toolbar-container,
body.pf-theme-dark .e-schedule .e-schedule-toolbar-container .e-toolbar,
body.pf-theme-dark .e-schedule .e-schedule-toolbar-container .e-toolbar-items,
body.pf-theme-dark .e-schedule .e-schedule-toolbar,
body.pf-theme-dark .e-schedule .e-schedule-toolbar.e-toolbar,
body.pf-theme-dark .e-schedule .e-schedule-toolbar .e-toolbar-items {
    background: var(--pf-surface-1) !important;
    border-color: var(--pf-border-strong) !important;
}

body.pf-theme-dark .e-schedule .e-schedule-toolbar-container {
    border-bottom: 3px solid var(--pf-brand) !important;
}

body.pf-theme-dark .e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn:hover .e-tbar-btn-text,
body.pf-theme-dark .e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn:hover .e-icons,
body.pf-theme-dark .e-schedule .e-schedule-toolbar-container .e-active-view .e-tbar-btn .e-tbar-btn-text {
    color: #22d3ee !important;
}

/* ═══════════════════════════════════════════════════════════════════
   Operations Performance Suite — KPI band scale, tiles, gauges, panels.
   Band colors are the single visual source of truth for PerformanceBand;
   components only ever apply the pf-band-* class, never a raw color.
   ═══════════════════════════════════════════════════════════════════ */

.pf-band-darkgreen { --pf-band-color: #1b5e20; --pf-band-bg: rgba(27,94,32,0.12); }
.pf-band-green     { --pf-band-color: #2e7d32; --pf-band-bg: rgba(46,125,50,0.12); }
.pf-band-orange    { --pf-band-color: #ef6c00; --pf-band-bg: rgba(239,108,0,0.14); }
.pf-band-red       { --pf-band-color: #c62828; --pf-band-bg: rgba(198,40,40,0.14); }
.pf-band-darkred   { --pf-band-color: #7f1d1d; --pf-band-bg: rgba(127,29,29,0.16); }
.pf-band-none      { --pf-band-color: #94a3b8; --pf-band-bg: color-mix(in srgb, var(--pf-text-subtle) 12%, transparent); }

body.pf-theme-dark .pf-band-darkgreen { --pf-band-color: #4ade80; --pf-band-bg: rgba(74,222,128,0.16); }
body.pf-theme-dark .pf-band-green     { --pf-band-color: #86efac; --pf-band-bg: rgba(134,239,172,0.14); }
body.pf-theme-dark .pf-band-orange    { --pf-band-color: #fb923c; --pf-band-bg: rgba(251,146,60,0.18); }
body.pf-theme-dark .pf-band-red       { --pf-band-color: #f87171; --pf-band-bg: rgba(248,113,113,0.18); }
body.pf-theme-dark .pf-band-darkred   { --pf-band-color: #fca5a5; --pf-band-bg: rgba(252,165,165,0.22); }
body.pf-theme-dark .pf-band-none      { --pf-band-color: #94a3b8; --pf-band-bg: color-mix(in srgb, var(--pf-text-subtle) 16%, transparent); }

/* ── Band chip / dot ─────────────────────────────────────────────── */
.pf-band-chip {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .2rem .6rem;
    border-radius: 999px;
    font-size: .78rem;
    font-weight: 600;
    color: var(--pf-band-color);
    background: var(--pf-band-bg);
    white-space: nowrap;
}

.pf-band-chip__dot {
    width: .55rem;
    height: .55rem;
    border-radius: 50%;
    background: var(--pf-band-color);
    flex-shrink: 0;
}

.pf-band-dot {
    display: inline-block;
    width: .65rem;
    height: .65rem;
    border-radius: 50%;
    background: var(--pf-band-color);
    box-shadow: 0 0 0 2px rgba(255,255,255,.6);
    flex-shrink: 0;
}

body.pf-theme-dark .pf-band-dot {
    box-shadow: 0 0 0 2px rgba(15,23,42,.7);
}

/* ── KPI tile (dashboard row 1) ──────────────────────────────────── */
/* A card well with the KPI's own band as its stripe. The stripe colour
   comes from --pf-band-color, set by the .pf-band-* class the component
   already emits, so the tile edge and the chip beside it can never
   disagree about the band. */
.pf-kpi-tile {
    background: var(--pf-card-bg);
    border: 1px solid var(--pf-card-border);
    border-left: 4px solid var(--pf-band-color, var(--pf-fam));
    border-radius: var(--pf-radius-sm);
    padding: .6rem .75rem;
    box-shadow: var(--pf-card-inset);
    height: 100%;
    display: flex;
    flex-direction: column;
    gap: .2rem;
    min-width: 0;
}

.pf-kpi-tile__label {
    font-family: var(--pf-font-head);
    font-size: .66rem;
    font-weight: 600;
    color: var(--pf-text-subtle);
    text-transform: uppercase;
    letter-spacing: .05em;
    line-height: 1.2;

    /* Two lines' worth of room, always. These labels run from "SWH" to
       "On-Time Vessel Service", and a row of tiles where the long ones
       ellipsize while the short ones sit alone looks broken; reserving
       the height keeps every value on the same baseline instead. */
    min-height: 2.4em;
    display: flex;
    align-items: flex-end;
}

.pf-kpi-tile__value {
    font-family: var(--pf-font-mono);
    font-size: 1.35rem;
    font-weight: 600;
    color: var(--pf-text);
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.pf-kpi-tile__value small {
    font-family: var(--pf-font-sans);
    font-size: .72rem;
    font-weight: 400;
    color: var(--pf-text-subtle);
    white-space: nowrap;
}

.pf-kpi-tile__target {
    font-size: .72rem;
    color: var(--pf-text-subtle);
}

.pf-kpi-tile__footer {
    margin-top: auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
}

/* No dark override for the tile. It reads --pf-card-bg / --pf-card-border
   / --pf-text, all of which already carry their dark values — and the
   override that used to sit here set surface-2, which is LIGHTER than
   the panel in dark mode and inverted the recessed reading. */

/* ── Vessel-in-port live panel ───────────────────────────────────── */
/* The vessel panel takes its family colour from the vessel's own
   overall band, so a ship in trouble is red-headed on the wall before
   anybody reads a number. --pf-band-color is set by the .pf-band-*
   class the component emits on this element. */
.pf-vessel-panel {
    --pf-fam: var(--pf-band-color, var(--pf-fam-brand));
    background: var(--pf-panel-bg);
    border: 1px solid var(--pf-panel-border);
    border-radius: var(--pf-panel-radius);
    box-shadow: var(--pf-panel-shadow);
    overflow: hidden;
    height: 100%;
    display: flex;
    flex-direction: column;
}

.pf-vessel-panel__header {
    padding: .62rem 1rem;
    background: var(--pf-panel-head-bg);
    color: var(--pf-panel-head-fg);
    border-top: 3px solid var(--pf-fam);
    border-bottom: 1px solid var(--pf-border);
    font-family: var(--pf-font-head);
    font-size: .78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    display: flex;
    align-items: center;
    gap: .5rem;
}

.pf-vessel-panel__title {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-width: 0;
}

.pf-vessel-panel__name {
    font-weight: 700;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pf-vessel-panel__meta {
    font-size: .75rem;
    color: var(--pf-text);
    padding: .35rem 1rem 0;
}

.pf-vessel-panel__owners {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem .9rem;
    padding: .3rem 1rem .1rem;
    font-size: .78rem;
    color: var(--pf-text-muted);
}

.pf-vessel-panel__owner-item {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pf-vessel-panel__owner-item i {
    color: var(--pf-brand);
    flex-shrink: 0;
}

.pf-vessel-panel__body {
    padding: .85rem 1rem 1rem;
    display: flex;
    flex-direction: column;
    gap: .85rem;
    flex: 1;
}

/* .pf-vessel-panel__section-title is defined with .pf-section-title in
   the panel system above — one rule for both, so the shared label and
   the vessel panel's own cannot drift apart. The duplicate that used to
   sit here came later in the file and silently won. */

.pf-kpi-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    padding: .3rem 0;
    font-size: .85rem;
    border-bottom: 1px dashed color-mix(in srgb, var(--pf-brand) 8%, transparent);
}

.pf-kpi-row:last-child {
    border-bottom: none;
}

.pf-kpi-row__label {
    color: #475569;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pf-kpi-row__value {
    font-weight: 600;
    color: var(--pf-brand);
    white-space: nowrap;
}

/* The vessel panel needs no dark override: it reads --pf-panel-* which
   already carry their dark values. The rule that used to sit here set
   surface-2, lighter than the panel plane, so in dark mode the vessel
   panels floated a shade above every other panel on the page. */

body.pf-theme-dark .pf-vessel-panel__meta {
    color: var(--pf-text-subtle);
}

body.pf-theme-dark .pf-vessel-panel__owners {
    color: var(--pf-text);
}

body.pf-theme-dark .pf-vessel-panel__owner-item i {
    color: var(--pf-brand-hover);
}

/* Section titles take --pf-fam, which resolves per mode already. */

body.pf-theme-dark .pf-kpi-row {
    border-bottom-color: color-mix(in srgb, var(--pf-brand-hover) 12%, transparent);
}

body.pf-theme-dark .pf-kpi-row__label {
    color: var(--pf-text-subtle);
}

body.pf-theme-dark .pf-kpi-row__value {
    color: var(--pf-text);
}

/* ── Target-vs-actual mini bar (SfLinearGauge wrapper) ───────────── */
.pf-target-bar {
    display: flex;
    flex-direction: column;
    gap: .2rem;
}

.pf-target-bar__labels {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    font-size: .75rem;
    color: var(--pf-text-subtle);
}

/* The label truncates first — the actual/target reading is the number someone is scanning for
   and must never be the half that gets clipped. */
.pf-target-bar__label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pf-target-bar__reading {
    flex: 0 0 auto;
    white-space: nowrap;
}

.pf-target-bar__track {
    position: relative;
    min-height: .5rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--pf-text-subtle) 25%, transparent);
    overflow: hidden;
}

.pf-target-bar__fill {
    height: 100%;
    border-radius: 999px;
    background: var(--pf-brand-hover);
    transition: width .3s ease;
}

.pf-target-bar__marker {
    position: absolute;
    top: -2px;
    bottom: -2px;
    width: 2px;
    background: var(--pf-brand);
}

body.pf-theme-dark .pf-target-bar__track {
    background: color-mix(in srgb, var(--pf-text-subtle) 18%, transparent);
}

body.pf-theme-dark .pf-target-bar__marker {
    background: var(--pf-surface-2);
}

/* ── Cargo progress gauge wrapper ─────────────────────────────────── */
.pf-cargo-gauge {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .25rem;
}

.pf-cargo-gauge__caption {
    font-size: .78rem;
    color: var(--pf-text-subtle);
    text-align: center;
}

body.pf-theme-dark .pf-cargo-gauge__caption {
    color: var(--pf-text-subtle);
}

/* ── Responsive grid for vessel panels / KPI tiles ───────────────── */
.pf-kpi-tile-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.pf-vessel-panel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
    gap: 1rem;
}

/* ── Agent vessels-live panels (2 per row) ───────────────────────── */
.pf-agent-panel-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

@media (max-width: 1100px) {
    .pf-agent-panel-grid {
        grid-template-columns: 1fr;
    }
}

.pf-agent-gauge-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: flex-start;
    gap: .75rem;
}

.pf-agent-card-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .75rem;
}

@media (max-width: 700px) {
    .pf-agent-card-grid {
        grid-template-columns: 1fr;
    }
}

.pf-agent-card {
    border: 1px solid color-mix(in srgb, var(--pf-text-subtle) 35%, transparent);
    border-radius: .5rem;
    background: var(--pf-surface-0);
    overflow: hidden;
}

.pf-agent-card__header {
    padding: .4rem .7rem;
    font-size: .8rem;
    font-weight: 600;
    color: var(--pf-text);
    background: linear-gradient(180deg, var(--pf-surface-2) 0%, var(--pf-surface-2) 100%);
    border-bottom: 1px solid color-mix(in srgb, var(--pf-brand) 10%, transparent);
}

.pf-agent-card__header i {
    margin-right: .35rem;
    color: var(--pf-brand);
}

.pf-agent-card__body {
    padding: .6rem .7rem;
}

body.pf-theme-dark .pf-agent-card {
    background: var(--pf-surface-2);
    border-color: color-mix(in srgb, var(--pf-text-subtle) 25%, transparent);
}

body.pf-theme-dark .pf-agent-card__header {
    background: linear-gradient(180deg, var(--pf-brand-active) 0%, var(--pf-brand-active) 100%);
    color: var(--pf-text);
    border-bottom-color: color-mix(in srgb, var(--pf-brand) 25%, transparent);
}

body.pf-theme-dark .pf-agent-card__header i {
    color: var(--pf-brand-hover);
}

.pf-agent-commodity-block {
    padding: .5rem 0;
}

.pf-agent-commodity-block + .pf-agent-commodity-block {
    border-top: 1px solid color-mix(in srgb, var(--pf-text-subtle) 30%, transparent);
    margin-top: .5rem;
}

.pf-agent-commodity-block__title {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: .85rem;
    font-weight: 600;
    color: var(--pf-brand);
    margin-bottom: .6rem;
}

body.pf-theme-dark .pf-agent-commodity-block__title {
    color: var(--pf-text);
}

/* ── KPI range gauge (SfCircularGauge wrapper) ───────────────────── */
.pf-range-gauge {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .2rem;
    max-width: 165px;
}

.pf-range-gauge__caption {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .15rem;
    text-align: center;
}

.pf-range-gauge__label {
    font-size: .74rem;
    font-weight: 600;
    color: var(--pf-text-muted);
    max-width: 160px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pf-range-gauge__target {
    font-size: .7rem;
    color: var(--pf-text-subtle);
}

.pf-range-gauge__empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .3rem;
    width: 150px;
    color: var(--pf-text-subtle);
    font-size: .74rem;
    border: 1px dashed color-mix(in srgb, var(--pf-text-subtle) 40%, transparent);
    border-radius: .5rem;
}

body.pf-theme-dark .pf-range-gauge__label {
    color: var(--pf-text);
}

body.pf-theme-dark .pf-range-gauge__target {
    color: var(--pf-text-subtle);
}

/* ── Vertical volume gauge wrapper ───────────────────────────────── */
.pf-volume-gauge {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .2rem;
}

.pf-volume-gauge__title {
    font-size: .74rem;
    font-weight: 600;
    color: var(--pf-text-muted);
}

.pf-volume-gauge__caption {
    font-size: .72rem;
    color: var(--pf-text-subtle);
    text-align: center;
}

.pf-volume-gauge__pct {
    font-weight: 700;
    color: var(--pf-brand);
}

body.pf-theme-dark .pf-volume-gauge__title {
    color: var(--pf-text);
}

body.pf-theme-dark .pf-volume-gauge__pct {
    color: var(--pf-brand-hover);
}

/* ==========================================================================
   FOLDED SHELL (Phase B2)
   --------------------------------------------------------------------------
   MainLayout.razor.css and SideMenu.razor.css. Their ::deep rules targeted
   descendants of .pf-layout, the element carrying the scope attribute, so
   they globalize as `.pf-layout X` and keep the specificity they had.
   Placed after the folded site.css so scoped-wins-over-global still holds.
   ========================================================================== */


/* --------------------------------------------------------------------------
   FOLDED FROM Components/Layout/MainLayout.razor.css
   the shell: topbar, sidebar, nav items, user panel, and the three collapse states
   -------------------------------------------------------------------------- */

.pf-layout {
    display: flex;
    min-height: 100vh;
    background: var(--pf-surface-1);
}

.pf-page-content {
    flex: 1;
    min-width: 0;
    padding: calc(56px + 24px) 28px 24px;
    transition: margin-left 0.28s ease;
}

.pf-layout .pf-topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 56px;
    background: var(--pf-chrome-bg);
    display: flex;
    align-items: center;
    padding: 0 1rem;
    gap: 0.75rem;
    z-index: 1050;
    box-shadow: 0 2px 8px color-mix(in srgb, var(--pf-nav-fg) 20%, transparent);
}

.pf-layout .pf-topbar-toggle {
    background: transparent;
    border: none;
    color: var(--pf-text);
    padding: 0.3rem 0.5rem;
    border-radius: 4px;
    cursor: pointer;
    line-height: 1;
    font-size: 1.4rem;
}

.pf-layout .pf-topbar-brand {
    display: flex;
    align-items: center;
    gap: 8px;
    text-decoration: none;
    flex: 1;
    overflow: hidden;
}

.pf-layout .pf-topbar-right {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--pf-text);
    font-size: 0.85rem;
    white-space: nowrap;
    font-weight: 600;
}

.pf-layout .pf-sidebar {
    width: 260px;
    position: fixed;
    left: 0;
    top: 56px;
    height: calc(100vh - 56px);
    background: var(--pf-nav-bg);
    color: var(--pf-nav-fg);
    display: flex;
    flex-direction: column;
    z-index: 1040;
    transition: transform 0.28s ease, width 0.28s ease;
    overflow: hidden;
    border-right: 1px solid color-mix(in srgb, var(--pf-nav-fg) 12%, transparent);
    box-shadow: 2px 0 16px color-mix(in srgb, var(--pf-nav-fg) 13%, transparent);
}

.pf-layout .pf-sidebar-body {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 6px 0;
}

.pf-layout .pf-nav-list,


.pf-layout .pf-nav-sub-list {
    list-style: none;
}

.pf-layout .pf-nav-list {
    padding: 0;
    margin: 0;
}

.pf-layout .pf-nav-section-label {
    padding: 14px 18px 4px;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: color-mix(in srgb, var(--pf-nav-fg) 55%, transparent);
    white-space: nowrap;
    overflow: hidden;
}

.pf-layout .pf-nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 14px;
    color: var(--pf-nav-fg) !important;
    text-decoration: none !important;
    border-radius: 6px;
    margin: 1px 6px;
    transition: background 0.15s ease;
    font-size: 0.88rem;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    width: calc(100% - 12px);
    box-sizing: border-box;
    background: transparent;
}

.pf-layout .pf-nav-item:hover {
    background: color-mix(in srgb, var(--pf-nav-fg) 9%, transparent);
    color: var(--pf-nav-fg) !important;
}

/* The active item takes the SAME ink as every other item. It used to use
   --pf-text-inverse, which is #06203a in dark mode — navy text on a navy
   sidebar, so the page you were actually on was the one you could not
   read. It is still obvious without a colour change: it carries the
   active background, a 3px marker down its left edge and heavier text. */
.pf-layout .pf-nav-item.active {
    background: var(--pf-nav-active-bg);
    color: var(--pf-nav-fg) !important;
    font-weight: 600;
    box-shadow: inset 3px 0 0 var(--pf-nav-active-marker);
}

.pf-layout .pf-nav-icon {
    flex-shrink: 0;
    width: 22px;
    text-align: center;
    font-size: 1rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.pf-layout .pf-nav-label {
    flex: 1;
    display: flex;
    align-items: center;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pf-layout .pf-nav-sub-list {
    padding: 2px 0;
    margin: 0 6px 2px;
    background: color-mix(in srgb, var(--pf-nav-fg) 7%, transparent);
    border-radius: 6px;
    overflow: hidden;
}

.pf-layout .pf-nav-sub-item {
    margin: 0 !important;
    width: 100% !important;
    border-radius: 0 !important;
    font-size: 0.84rem;
    padding: 8px 14px;
}

.pf-layout .pf-sidebar-footer {
    padding: 8px 0 6px;
    border-top: 1px solid color-mix(in srgb, var(--pf-nav-fg) 15%, transparent);
    flex-shrink: 0;
}

.pf-layout .pf-user-panel {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 14px 4px;
    color: var(--pf-nav-fg);
    overflow: hidden;
}

.pf-layout .pf-user-avatar {
    flex-shrink: 0;
    color: var(--pf-brand-hover);
    font-size: 1.5rem;
    line-height: 1;
}

.pf-layout .pf-user-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.pf-layout .pf-user-name {
    font-size: 0.84rem;
    font-weight: 600;
    color: var(--pf-nav-fg);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pf-layout .pf-user-role {
    font-size: 0.7rem;
    color: var(--pf-nav-fg) !important;
    white-space: nowrap;
}

.pf-layout .pf-sidebar-backdrop {
    position: fixed;
    top: 56px;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 1039;
}

@media (max-width: 991.98px) {
    .pf-page-content {
        margin-left: 0;
    }

    .pf-layout .pf-sidebar {
        transform: translateX(-100%);
    }

    .pf-layout .pf-sidebar.pf-sidebar--open {
        transform: translateX(0);
    }
}

@media (min-width: 992px) {
    .pf-page-content {
        margin-left: 260px;
    }

    body.pf-sidebar-mini .pf-page-content {
        margin-left: 64px;
    }

    .pf-layout .pf-sidebar {
        transform: translateX(0) !important;
    }

    .pf-layout .pf-sidebar.pf-sidebar--mini {
        width: 64px;
    }

    .pf-layout .pf-sidebar--mini .pf-nav-label,


    .pf-layout .pf-sidebar--mini .pf-nav-section-label,


    .pf-layout .pf-sidebar--mini .pf-user-info,


    .pf-layout .pf-sidebar--mini .pf-nav-sub-list {
        display: none !important;
    }

    .pf-layout .pf-sidebar--mini .pf-nav-item,


    .pf-layout .pf-sidebar--mini .pf-user-panel {
        justify-content: center;
    }
}

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }


/* --------------------------------------------------------------------------
   FOLDED FROM Components/Layout/SideMenu.razor.css
   the collapsible nav groups inside the sidebar
   -------------------------------------------------------------------------- */

/* ── Nav Group Header (collapsible section heading) ───────────────────── */

.pf-nav-group-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0.62rem 1rem 0.62rem 0.875rem;
    margin: 2px 0 0;
    background: color-mix(in srgb, var(--pf-nav-fg) 7%, transparent);
    border: none;
    border-top: 1px solid color-mix(in srgb, var(--pf-nav-fg) 10%, transparent);
    border-radius: 0;
    cursor: pointer;
    color: var(--pf-nav-fg);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    line-height: 1.3;
    transition: background 0.15s ease;
    white-space: nowrap;
    overflow: hidden;
}

.pf-nav-group-header:hover {
    background: color-mix(in srgb, var(--pf-nav-fg) 13%, transparent);
}

.pf-nav-group-header:focus-visible {
    outline: 2px solid var(--pf-nav-active-marker);
    outline-offset: -2px;
}

/* Group title — icon + label side-by-side */
.pf-nav-group-title {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Chevron icon */
.pf-nav-group-chevron {
    flex-shrink: 0;
    font-size: 0.72rem;
    color: color-mix(in srgb, var(--pf-nav-fg) 55%, transparent);
    transition: transform 0.2s ease;
    margin-left: 6px;
}

.pf-nav-group-chevron--collapsed {
    transform: rotate(-90deg);
}

/* ── Group body (children) ────────────────────────────────────────────── */

.pf-nav-group-body {
    overflow: hidden;
}

.pf-nav-group-body--collapsed {
    display: none;
}

.pf-nav-group-children {
    padding: 3px 0 4px;
    margin: 0;
    background: color-mix(in srgb, var(--pf-nav-fg) 3%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--pf-nav-fg) 7%, transparent);
}

/* ── Mini (collapsed) sidebar — hide group headers text, show icon only ── */
.pf-sidebar--mini .pf-nav-group-header {
    justify-content: center;
    padding: 0.62rem 0;
}

.pf-sidebar--mini .pf-nav-group-title .pf-nav-label,


.pf-sidebar--mini .pf-nav-group-chevron {
    display: none;
}

.pf-sidebar--mini .pf-nav-group-body {
    display: none;
}

/* ============================================================================
   SYNCFUSION DARK BRIDGE
   ----------------------------------------------------------------------------
   Syncfusion ships one compiled light theme (bootstrap5.css) with no CSS custom
   properties, so there is nothing to bridge the way Radzen's variables are
   bridged — its surfaces have to be named explicitly.

   Everything here is scoped to .pf-theme-dark, so light mode renders exactly as
   it does today and this can only affect a mode that was previously broken.
   Only Schedule and DashboardLayout are staying long-term, but the other
   selectors are included so dark mode works on the screens still waiting for
   their migration.

   Two things are deliberately NOT touched:
     - .e-appointment and its content. Slot colours are written as inline styles
       from SlotDisplayStyleHelper and are frozen; they are light fills with dark
       text by design and must read identically in both modes.
     - .e-schedule borders, radius and shadow. The schedule grid is protected.
   ============================================================================ */

body.pf-theme-dark .e-panel,
body.pf-theme-dark .e-card,
body.pf-theme-dark .e-dlg-container .e-dlg,
body.pf-theme-dark .e-popup.e-popup-open,
body.pf-theme-dark .e-grid,
body.pf-theme-dark .e-grid .e-gridcontent,
body.pf-theme-dark .e-grid .e-content,
body.pf-theme-dark .e-grid .e-table {
    background-color: var(--pf-surface-0);
    color: var(--pf-text);
}

body.pf-theme-dark .e-panel {
    border-color: var(--pf-border);
}

/* Syncfusion qualifies its panel fill through the layout root, which outranks a
   bare .e-panel override, so match that depth. */
body.pf-theme-dark .e-dashboardlayout .e-panel,
body.pf-theme-dark .e-dashboardlayout.e-control .e-panel {
    background-color: var(--pf-surface-0);
    color: var(--pf-text);
    border-color: var(--pf-border);
}

/* Syncfusion dashboard panels come in two shapes. On the AIS board the
   panel nests its own .ais-panel__header, so this wrapper must not paint
   a second band behind it. On the port dashboard the wrapper IS the
   header, and making it transparent left those panels with a bare label
   and no band at all. It carries the band by default and stands down
   only where a real header is nested inside it. */
/* Matched at Syncfusion's own depth. Its rule is
   ".e-dashboardlayout.e-control .e-panel .e-panel-container .e-panel-header"
   — four classes — and a shorter selector simply loses to it, which left
   these panels wearing Syncfusion's #f8f9fa in dark mode. */
.e-dashboardlayout.e-control .e-panel .e-panel-container .e-panel-header,
.e-dashboardlayout .e-panel .e-panel-container .e-panel-header,
.e-dashboardlayout .e-panel .e-panel-header,
.e-dashboardlayout.e-control .e-panel .e-panel-header {
    background: var(--pf-panel-head-bg);
    color: var(--pf-panel-head-fg);
    border-top: 3px solid var(--pf-fam);
    border-bottom: 1px solid var(--pf-border);
    font-family: var(--pf-font-head);
    font-size: .78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
}

.e-dashboardlayout .e-panel .e-panel-container .e-panel-header:has(> .ais-panel__header),
.e-dashboardlayout .e-panel .e-panel-container .e-panel-header:has(> .pf-panel__header),
.e-dashboardlayout .e-panel .e-panel-container .e-panel-header:has(> .pf-panel-header),
.e-dashboardlayout .e-panel .e-panel-header:has(> .ais-panel__header),
.e-dashboardlayout .e-panel .e-panel-header:has(> .pf-panel__header),
.e-dashboardlayout .e-panel .e-panel-header:has(> .pf-panel-header) {
    background: transparent;
    border: 0;
    padding: 0;
}

body.pf-theme-dark .e-dashboardlayout .e-panel .e-panel-container {
    background-color: transparent;
    color: var(--pf-text);
}

body.pf-theme-dark .e-panel-header,
body.pf-theme-dark .e-card .e-card-header,
body.pf-theme-dark .e-grid .e-gridheader,
body.pf-theme-dark .e-grid .e-headercell,
body.pf-theme-dark .e-grid .e-headercontent {
    background-color: var(--pf-surface-2);
    color: var(--pf-text);
    border-color: var(--pf-border);
}

body.pf-theme-dark .e-grid .e-rowcell,
body.pf-theme-dark .e-grid .e-headercelldiv,
body.pf-theme-dark .e-card .e-card-content,
body.pf-theme-dark .e-dlg .e-dlg-content {
    background-color: transparent;
    color: var(--pf-text);
    border-color: var(--pf-border);
}

body.pf-theme-dark .e-grid .e-row:nth-child(even) .e-rowcell {
    background-color: var(--pf-surface-1);
}

body.pf-theme-dark .e-grid .e-row:hover .e-rowcell {
    background-color: var(--pf-surface-2);
}

/* Inputs: Syncfusion paints these white and would leave dark text on white
   inside an otherwise dark form. */
body.pf-theme-dark .e-input-group,
body.pf-theme-dark .e-input-group.e-control-wrapper,
body.pf-theme-dark .e-ddl.e-input-group,
body.pf-theme-dark .e-float-input,
body.pf-theme-dark .e-multi-select-wrapper,
body.pf-theme-dark .e-input-group input.e-input,
body.pf-theme-dark .e-input-group textarea.e-input {
    background-color: var(--pf-surface-2);
    color: var(--pf-text);
    border-color: var(--pf-border);
}

body.pf-theme-dark .e-input-group input.e-input::placeholder,
body.pf-theme-dark .e-float-text {
    color: var(--pf-text-subtle);
}

/* Dropdown and popup lists float outside the component, so they need their own
   surface or they open as a white sheet over a dark page. */
body.pf-theme-dark .e-popup.e-ddl,
body.pf-theme-dark .e-dropdownbase,
body.pf-theme-dark .e-popup .e-list-item {
    background-color: var(--pf-surface-0);
    color: var(--pf-text);
}

body.pf-theme-dark .e-popup .e-list-item.e-hover,
body.pf-theme-dark .e-popup .e-list-item.e-active {
    background-color: var(--pf-surface-2);
    color: var(--pf-text);
}

/* Dialog chrome shares the one dialog look defined for Radzen. */
body.pf-theme-dark .e-dlg .e-dlg-header-content,
body.pf-theme-dark .e-dlg .e-footer-content {
    background-color: var(--pf-surface-2);
    color: var(--pf-text);
    border-color: var(--pf-border);
}

/* Schedule: surfaces only. No border, radius or shadow — the grid is protected —
   and nothing here reaches .e-appointment, whose fills are the frozen slot
   colours written inline from SlotDisplayStyleHelper. */
body.pf-theme-dark .e-schedule,
body.pf-theme-dark .e-schedule .e-table-container,
body.pf-theme-dark .e-schedule .e-content-wrap,
body.pf-theme-dark .e-schedule .e-work-cells,
body.pf-theme-dark .e-schedule .e-resource-cells,
body.pf-theme-dark .e-schedule .e-header-cells,
body.pf-theme-dark .e-schedule .e-date-header-wrap {
    background-color: var(--pf-surface-0);
    color: var(--pf-text);
}

body.pf-theme-dark .e-schedule .e-work-cells.e-alternate-cells {
    background-color: var(--pf-surface-1);
}

/* ============================================================================
   AUTH CARDS  (Phase B1 as .pf-login-*, widened in C1)
   ----------------------------------------------------------------------------
   Sign In, Request an Account and Pending Approval are the same object: a card
   on the page ground, a brand header with the mark reversed out of it, a body,
   a footer rule. Login solved it in B1; the other two hand-rolled it in inline
   styles against the OLD palette (#12304b navy, #78afd9 accent, #f0f4f8 ground)
   and so never followed the theme at all. The family is named pf-auth-* rather
   than pf-login-* now that three pages share it.

   The subtitle and links are not a straight token substitution: both were the
   old accent blue, and on the Night Watch brand header that pairing has almost
   no contrast. The subtitle is the header's own foreground held back to 78%,
   and the links take the brand colour because they sit on the card, not on the
   header.

   Interactivity, because it is not uniform and the difference matters:
   Account/Pages/_Imports.razor carries [ExcludeFromInteractiveRouting], so a
   page there posts rather than binding over a circuit unless it sets a render
   mode itself. Login and PendingApproval do not, and keep InputText /
   InputCheckbox. RegisterNewUser *does* -- @rendermode RenderMode.InteractiveServer
   on line 15 -- which is why it alone can carry a Radzen control.
   ============================================================================ */

.pf-auth-wrapper {
    min-height: calc(100vh - var(--pf-topbar-h));
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--pf-surface-1);
    padding: var(--pf-space-6) var(--pf-space-4);
}

/* Register and RegisterNewUser sit inside the app shell behind a breadcrumb,
   so they are not centred in the viewport the way Sign In is -- they scroll
   like a page. Same card, different ground. */
.pf-auth-page {
    padding: var(--pf-page-pad-y) var(--pf-page-pad-x);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--pf-space-5);
}

.pf-auth-page > .rz-breadcrumb {
    align-self: flex-start;
}

.pf-auth-card {
    width: 100%;
    max-width: 420px;
    border-radius: var(--pf-radius-lg);
    overflow: hidden;
    box-shadow: var(--pf-shadow-lg);
    background: var(--pf-surface-0);
    border: 1px solid var(--pf-border);
}

/* Sign In is one column of fields; the account request is four sections of
   them, and at 420px it reads as a receipt. */
.pf-auth-card--wide { max-width: 720px; }
.pf-auth-card--md   { max-width: 520px; }

.pf-auth-header {
    background: var(--pf-brand);
    color: var(--pf-on-brand);
    text-align: center;
    padding: var(--pf-space-8) var(--pf-space-6) var(--pf-space-6);
}

/* The heading rules colour every h1-h6, which leaves the title unreadable on the
   brand header. The header owns its own foreground.

   The card is in the selector for specificity, not for scoping. B1 wrote this as
   `.pf-auth-header h4` (0,1,1) and it fixed light mode only: the dark override is
   `body.pf-theme-dark h4` (0,1,2) and quietly outranked it, so the title sat in
   --pf-text on a cyan header for the whole of Phase B. Two classes beat one class
   and two elements. */
.pf-auth-card .pf-auth-header h1,
.pf-auth-card .pf-auth-header h2,
.pf-auth-card .pf-auth-header h3,
.pf-auth-card .pf-auth-header h4,
.pf-auth-card .pf-auth-header h5,
.pf-auth-card .pf-auth-header h6 {
    color: var(--pf-on-brand);
}

.pf-auth-logo {
    height: 48px;
    margin-bottom: var(--pf-space-3);
    filter: brightness(0) invert(1);
}

.pf-auth-sub {
    color: color-mix(in srgb, var(--pf-on-brand) 78%, transparent);
    font-size: var(--pf-fs-md);
    letter-spacing: var(--pf-tracking-wide);
}

/* PendingApproval's rule under the header. It was the old accent blue; the
   accent token is the one that carries "attention" in Night Watch. */
.pf-auth-accent {
    height: 4px;
    background: var(--pf-accent);
}

.pf-auth-body {
    padding: var(--pf-space-6);
}

.pf-auth-body .form-control,
.pf-auth-body .form-select,
.pf-auth-body .form-floating > label {
    color: var(--pf-text);
}

.pf-auth-body .form-control,
.pf-auth-body .form-select {
    background-color: var(--pf-surface-0);
    border-color: var(--pf-border);
}

/* Section rules inside the account request form. */
/* Two classes, for the same reason the header title needs them: the dark
   heading override is `body.pf-theme-dark h6` and outranks a single class. */
.pf-auth-body .pf-auth-section {
    color: var(--pf-brand);
    font-weight: var(--pf-fw-semibold);
    font-size: var(--pf-fs-lg);
    margin-bottom: var(--pf-space-3);
}

.pf-auth-body .pf-auth-section--muted { color: var(--pf-text-muted); }

/* Bootstrap's .alert-* variants are not themed anywhere in this sheet -- they
   arrive from the CDN with a light tint and dark ink, which on the Night Watch
   ground is a light box sitting inside a dark card. The auth pages get their own
   notice rather than a global .alert rule, because 192 alerts elsewhere in the
   app would change with it and that is not this work package's call. */
.pf-auth-notice {
    display: flex;
    gap: var(--pf-space-3);
    align-items: flex-start;
    padding: var(--pf-space-4);
    border-radius: var(--pf-radius);
    border: 1px solid color-mix(in srgb, var(--pf-info) 45%, transparent);
    background: color-mix(in srgb, var(--pf-info) 12%, transparent);
    color: var(--pf-text);
    font-size: var(--pf-fs-sm);
    line-height: var(--pf-lh-loose);
}

.pf-auth-notice > i {
    color: var(--pf-info);
    font-size: var(--pf-fs-xl);
    flex-shrink: 0;
    line-height: 1;
}

.pf-auth-notice--danger {
    border-color: color-mix(in srgb, var(--pf-danger) 45%, transparent);
    background: color-mix(in srgb, var(--pf-danger) 12%, transparent);
}

.pf-auth-notice--danger > i { color: var(--pf-danger); }

.pf-auth-copy {
    color: var(--pf-text-muted);
    font-size: var(--pf-fs-sm);
    line-height: var(--pf-lh-loose);
}

.pf-auth-foot-note {
    text-align: center;
    color: var(--pf-text-muted);
    font-size: var(--pf-fs-sm);
}

.pf-input:focus {
    border-color: var(--pf-focus-ring);
    box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--pf-focus-ring) 25%, transparent);
}

.pf-check:checked {
    background-color: var(--pf-brand);
    border-color: var(--pf-brand);
}

.pf-btn-primary {
    background: var(--pf-brand);
    color: var(--pf-on-brand);
    border: none;
    border-radius: var(--pf-radius);
    padding: var(--pf-space-3);
    font-size: var(--pf-fs-lg);
    font-weight: var(--pf-fw-semibold);
    cursor: pointer;
    transition: background var(--pf-dur) var(--pf-ease);
}

.pf-btn-primary:hover {
    background: var(--pf-brand-hover);
}

.pf-btn-primary:focus-visible {
    outline: 2px solid var(--pf-focus-ring);
    outline-offset: 2px;
}

.pf-btn-primary[disabled] {
    background: var(--pf-surface-3);
    color: var(--pf-text-subtle);
    cursor: not-allowed;
}

/* The quiet sibling -- "Email support", never the action the page is for. */
.pf-btn-quiet {
    background: transparent;
    color: var(--pf-text);
    border: 1px solid var(--pf-border-strong);
    border-radius: var(--pf-radius);
    padding: var(--pf-space-3);
    font-size: var(--pf-fs-md);
    font-weight: var(--pf-fw-medium);
    cursor: pointer;
    transition: background var(--pf-dur) var(--pf-ease);
}

.pf-btn-quiet:hover {
    background: var(--pf-surface-2);
    color: var(--pf-text);
}

.pf-link {
    color: var(--pf-brand);
    text-decoration: none;
    font-size: var(--pf-fs-md);
}

.pf-link:hover {
    color: var(--pf-brand-hover);
    text-decoration: underline;
}

.pf-auth-footer {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: var(--pf-space-2);
    margin-top: var(--pf-space-5);
    padding-top: var(--pf-space-4);
    border-top: 1px solid var(--pf-border);
}

/* PendingApproval's copyright strip. */
.pf-auth-footer-bar {
    background: var(--pf-surface-1);
    padding: var(--pf-space-3) var(--pf-space-6);
    border-top: 2px solid var(--pf-accent);
    text-align: center;
    color: var(--pf-text-muted);
    font-size: var(--pf-fs-xs);
}

.pf-divider {
    color: var(--pf-text-subtle);
    font-size: var(--pf-fs-xs);
}

/* ============================================================================
   KPI INDICATORS (Phase B4)
   ----------------------------------------------------------------------------
   The progress ring and the volume bar. Both were circular/linear gauge controls
   showing a single percentage with no axis, ticks or pointer — a charting control
   was only carrying styling there. Same call TargetActualBar already made.

   Colours arrive as the --pf-band-* tokens through inline custom properties set
   by the component, so light and dark follow without a second rule.
   ============================================================================ */

.pf-cargo-gauge__ring {
    position: relative;
    width: var(--pf-ring-size, 130px);
    aspect-ratio: 1;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: conic-gradient(var(--pf-ring-color, var(--pf-brand)) calc(var(--pf-ring-pct, 0) * 1%),
                               var(--pf-surface-2) 0);
}

.pf-cargo-gauge__ring::before {
    content: "";
    position: absolute;
    inset: 12%;
    border-radius: 50%;
    background: var(--pf-surface-0);
}

.pf-cargo-gauge__pct {
    position: relative;
    font-size: var(--pf-fs-xl);
    font-weight: var(--pf-fw-bold);
    color: var(--pf-text);
    font-variant-numeric: tabular-nums;
    letter-spacing: var(--pf-tracking-tight);
}

.pf-volume-gauge__track {
    position: relative;
    width: 18px;
    margin: 0 auto;
    border-radius: var(--pf-radius-pill);
    background: var(--pf-surface-2);
    overflow: hidden;
}

.pf-volume-gauge__fill {
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    height: calc(var(--pf-bar-pct, 0) * 1%);
    background: var(--pf-bar-color, var(--pf-brand));
    border-radius: var(--pf-radius-pill);
    transition: height var(--pf-dur) var(--pf-ease);
}

/* Quarter gridlines, so the bar can be read off without an axis. */
.pf-volume-gauge__tick {
    position: absolute;
    inset-inline: 0;
    height: 1px;
    background: color-mix(in srgb, var(--pf-text-subtle) 45%, transparent);
}

.pf-volume-gauge__marker {
    position: absolute;
    inset-inline: -4px;
    bottom: calc(var(--pf-bar-pct, 0) * 1%);
    height: 2px;
    background: var(--pf-text);
    transition: bottom var(--pf-dur) var(--pf-ease);
}

/* Hand-drawn instrument dial: a 270° arc, band segments as a slim outer ring,
   graduated ticks, a single target mark, and the reading as an HTML overlay
   (inherits type tokens, wraps sensibly, stays selectable — a gauge
   annotation does none of that). Replaced the Radzen radial gauge because its
   numeric tick labels collided with the centre reading at this size. */
.pf-range-gauge__dial {
    position: relative;
    display: grid;
    place-items: center;
    margin-inline: auto;
}

.pf-range-gauge__svg {
    width: 100%;
    height: 100%;
    overflow: visible;
    display: block;
}

.pf-range-gauge__track {
    fill: none;
    stroke: var(--pf-border);
    stroke-width: 8;
    stroke-linecap: butt;
}

.pf-range-gauge__band {
    fill: none;
    stroke-width: 3;
    opacity: .95;
}

.pf-range-gauge__ticks line {
    stroke: var(--pf-text-subtle);
    stroke-width: 1;
    opacity: .55;
}

.pf-range-gauge__ticks line.major {
    stroke-width: 1.5;
    opacity: .9;
}

.pf-range-gauge__value-arc {
    fill: none;
    stroke-width: 8;
    stroke-linecap: butt;
}

.pf-range-gauge__target-line {
    stroke: var(--pf-text);
    stroke-width: 2;
}

.pf-range-gauge__value-wrap {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    text-align: center;
    padding: 0 8px;
}

.pf-range-gauge__v {
    font-family: var(--pf-font-mono);
    font-size: var(--pf-fs-2xl);
    font-weight: var(--pf-fw-semibold);
    color: var(--pf-text);
    line-height: 1;
    letter-spacing: -0.01em;
}

.pf-range-gauge__u {
    font-size: var(--pf-fs-2xs);
    color: var(--pf-text-subtle);
    font-weight: 600;
    margin-top: 3px;
}

@media (prefers-reduced-motion: reduce) {
    .pf-volume-gauge__fill,
    .pf-volume-gauge__marker {
        transition: none;
    }
}

/* ============================================================================
   DIALOGS (Phase C2)
   ----------------------------------------------------------------------------
   The single definition of modal chrome, used by PfDialog. Before this the app
   had two systems — hand-rolled Bootstrap .modal markup and SfDialog — with
   headers in five different colours and no shared sizing, so the dialogs were
   the least consistent surface in the product.

   Radzen's own dialogs are themed by the --rz-dialog-* variables already bridged
   in the token section, so a DialogService dialog and a PfDialog land in the same
   place visually.
   ============================================================================ */

.pf-dialog-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--pf-z-dialog);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--pf-space-4);
    background: color-mix(in srgb, var(--pf-surface-sunken) 72%, transparent);
    backdrop-filter: blur(2px);
    overflow-y: auto;
    animation: pf-dialog-fade var(--pf-dur-fast) var(--pf-ease);
}

.pf-dialog {
    width: 100%;
    max-height: calc(100vh - var(--pf-space-8));
    display: flex;
    flex-direction: column;
    background: var(--pf-surface-0);
    color: var(--pf-text);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-lg);
    box-shadow: var(--pf-shadow-lg);
    overflow: hidden;
    animation: pf-dialog-rise var(--pf-dur) var(--pf-ease);
}

.pf-dialog:focus-visible {
    outline: 2px solid var(--pf-focus-ring);
    outline-offset: 2px;
}

.pf-dialog--sm { max-width: 380px; }
.pf-dialog--md { max-width: 520px; }
.pf-dialog--lg { max-width: 720px; }
.pf-dialog--xl { max-width: 960px; }

.pf-dialog__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-3);
    padding: var(--pf-space-3) var(--pf-space-4);
    background: var(--pf-brand);
    color: var(--pf-on-brand);
    flex: 0 0 auto;
}

.pf-dialog__header--muted   { background: var(--pf-surface-2); color: var(--pf-text); }
.pf-dialog__header--danger  { background: var(--pf-danger);  color: var(--pf-on-danger); }
.pf-dialog__header--warning { background: var(--pf-warning); color: var(--pf-on-warning); }
.pf-dialog__header--success { background: var(--pf-success); color: var(--pf-on-success); }

/* The title is an <h2>, so `color: inherit` at one class (0,1,0) loses to
   `body.pf-theme-dark h2` (0,1,2) and every dialog title in the app has been
   rendering in --pf-text on its tone-coloured header in dark mode. Same shape as
   the bug C1 found on the auth card header; see REDESIGN_PATTERNS.md. Three
   classes beat one class and two elements. */
.pf-dialog .pf-dialog__header .pf-dialog__title {
    display: flex;
    align-items: center;
    gap: var(--pf-space-2);
    margin: 0;
    font-size: var(--pf-fs-lg);
    font-weight: var(--pf-fw-semibold);
    letter-spacing: var(--pf-tracking-tight);
    color: inherit;
    flex: 1 1 auto;
    min-width: 0;
}

.pf-dialog__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: var(--pf-radius-sm);
    background: transparent;
    color: inherit;
    opacity: .75;
    cursor: pointer;
    transition: opacity var(--pf-dur-fast) var(--pf-ease),
                background-color var(--pf-dur-fast) var(--pf-ease);
}

.pf-dialog__close:hover {
    opacity: 1;
    background: color-mix(in srgb, currentColor 16%, transparent);
}

.pf-dialog__close:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 1px;
    opacity: 1;
}

.pf-dialog__body {
    padding: var(--pf-space-4);
    overflow-y: auto;
    flex: 1 1 auto;
}

/* Bootstrap's .text-muted is a fixed near-black (rgba(33,37,41,.75)) and is not
   themed, so on the dialog's dark surface it renders as invisible-on-dark. The
   override is scoped to the dialog rather than global on purpose: several panels
   in the app deliberately keep a white ground, and .text-muted is correct there. */
.pf-dialog .text-muted {
    color: var(--pf-text-muted) !important;
}

/* ── Dialog form surface ─────────────────────────────────────────────────────
   Dialog bodies are a flat panel colour, and both Bootstrap's .form-control and
   Radzen's inputs default to that same colour with a hairline border, so on the
   berthing-slot and bollard dialogs the controls were white on white — you could
   not see where a field began. The fix is two-sided: fields get their own ground
   and a visible border, and the content around them is grouped into tinted
   sections, so field and ground never resolve to the same value.

   Radzen inputs need !important here: the app bridges --rz-input-size-* but not
   --rz-input-background-color, so Radzen resolves its own --rz-white and wins on
   specificity from its stylesheet. Same treatment as the Radzen overrides in the
   BUTTON and GRID sections above. */
.pf-dialog__body .form-control,
.pf-dialog__body .form-select,
.pf-dialog__body textarea,
.pf-dialog__body input[type="text"],
.pf-dialog__body input[type="number"],
.pf-dialog__body input[type="search"],
.pf-dialog__body input[type="date"],
.pf-dialog__body input[type="time"],
.pf-dialog__body input[type="datetime-local"] {
    background-color: var(--pf-dlg-field-bg);
    border: 1px solid var(--pf-dlg-field-border);
    border-radius: var(--pf-radius-sm, 5px);
    box-shadow: var(--pf-dlg-field-glow);
    color: var(--pf-text);
}

.pf-dialog__body .rz-dropdown,
.pf-dialog__body .rz-numeric,
.pf-dialog__body .rz-textbox,
.pf-dialog__body .rz-textarea,
.pf-dialog__body .rz-datepicker,
.pf-dialog__body .rz-autocomplete,
.pf-dialog__body .rz-lookup,
.pf-dialog__body .rz-multiselect,
.pf-dialog__body .rz-selectbutton {
    background-color: var(--pf-dlg-field-bg) !important;
    border: 1px solid var(--pf-dlg-field-border) !important;
    border-radius: var(--pf-radius-sm, 5px);
    box-shadow: var(--pf-dlg-field-glow);
}

/* The inner <input> of a Radzen numeric/textbox sits on top of the wrapper and
   carries its own background, which would punch a white rectangle through the
   themed wrapper in dark mode. */
.pf-dialog__body .rz-numeric input,
.pf-dialog__body .rz-textbox input,
.pf-dialog__body .rz-datepicker input,
.pf-dialog__body .rz-autocomplete input,
.pf-dialog__body .rz-dropdown .rz-dropdown-label {
    background-color: transparent !important;
    border: 0 !important;
    color: var(--pf-text);
}

.pf-dialog__body .form-control:focus,
.pf-dialog__body .form-select:focus,
.pf-dialog__body textarea:focus {
    border-color: var(--pf-brand);
    box-shadow: 0 0 0 2px var(--pf-brand-subtle);
    outline: none;
}

.pf-dialog__body .rz-dropdown:not(.rz-state-disabled):hover,
.pf-dialog__body .rz-numeric:not(.rz-state-disabled):hover,
.pf-dialog__body .rz-textbox:not(.rz-state-disabled):hover {
    border-color: var(--pf-brand) !important;
}

/* Computed / read-only values keep the OPPOSITE cue to an editable field: they
   sit on the section tint with a dashed edge. Once fields have a ground of their
   own, "tinted" has to keep meaning "you cannot type here" or a readonly box
   reads as an empty input. */
.pf-dialog__body .form-control[readonly],
.pf-dialog__body input[readonly],
.pf-dialog__body .rz-dropdown.rz-state-disabled,
.pf-dialog__body .rz-numeric.rz-state-disabled,
.pf-dialog__body .rz-textbox.rz-state-disabled,
.pf-dialog__body .rz-datepicker.rz-state-disabled,
.pf-dialog__body .rz-lookup.rz-state-disabled,
.pf-dialog__body .rz-multiselect.rz-state-disabled {
    background-color: var(--pf-dlg-section-bg) !important;
    border-style: dashed !important;
    border-color: var(--pf-dlg-field-border) !important;
    color: var(--pf-text-muted);
}

/* ── Dialog sections ─────────────────────────────────────────────────────────
   Grouped, numbered bands inside a dialog body. Started life as the bollard
   dialog's .sbd-section; shared now so every dialog that needs the treatment
   gets the same one rather than a third vocabulary. */
.pf-dlg-section {
    border: 1px solid var(--pf-dlg-section-border);
    border-radius: var(--pf-radius-md, 8px);
    padding: var(--pf-space-2) .75rem .75rem;
    margin-bottom: var(--pf-space-2);
    background: var(--pf-dlg-section-bg);
}

/* Accent edges naming the section's role. */
.pf-dlg-section--given  { border-left: 3px solid var(--pf-border-strong); }
.pf-dlg-section--input  { border-left: 3px solid var(--pf-accent); }
.pf-dlg-section--result { border-left: 3px solid #2563eb; }
.pf-dlg-section--lines  { border-left: 3px solid #0f766e; }

.pf-dlg-section__head {
    display: flex;
    align-items: center;
    gap: .45rem;
    margin-bottom: .5rem;
}

.pf-dlg-section__num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
    background: var(--pf-text);
    color: var(--pf-surface-0);
    font-size: .7rem;
    font-weight: var(--pf-fw-bold);
    flex-shrink: 0;
}

.pf-dlg-section__title {
    font-weight: var(--pf-fw-bold);
    font-size: var(--pf-fs-sm);
    color: var(--pf-text);
    text-transform: uppercase;
    letter-spacing: .04em;
}

.pf-dlg-section__hint {
    font-size: .72rem;
    color: var(--pf-text-muted);
    font-style: italic;
    margin-left: auto;
    text-align: right;
}

.pf-dlg-label {
    display: block;
    font-size: .72rem;
    font-weight: var(--pf-fw-bold);
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--pf-text-muted);
    margin-bottom: .15rem;
}

/* ── Date picker popup: calendar band and time band ──────────────────────────
   Radzen paints the whole popup one flat colour, so the month grid and the
   hour/minute row ran together as a single sheet of white. Each is given the
   same tinted ground the dialog sections use, separated by the panel showing
   through between them, and the spinners keep the field ground so they still
   read as things you type into.

   Scoped to the popup and inline containers rather than to .rz-calendar so a
   RadzenScheduler or Gantt reusing calendar internals is not restyled. */
.rz-datepicker-popup-container .rz-calendar-view-container,
.rz-datepicker-inline-container .rz-calendar-view-container,
.rz-datepicker-popup-container .rz-timepicker,
.rz-datepicker-inline-container .rz-timepicker {
    background: var(--pf-dlg-section-bg);
    border: 1px solid var(--pf-dlg-section-border);
    border-radius: var(--pf-radius-md, 8px);
    margin: var(--pf-space-2, .5rem);
}

/* The band already carries its own top edge; Radzen's separator line would sit
   just above it as a second rule. */
.rz-datepicker-popup-container .rz-timepicker,
.rz-datepicker-inline-container .rz-timepicker {
    border-top: 1px solid var(--pf-dlg-section-border);
    padding-inline: .6rem;
    gap: .4rem;
}

/* "Time" names the band. It is decorative — the hour and minute spinners carry
   their own accessible names — so a pseudo-element is the right weight here,
   and it costs no change to Radzen-generated markup. */
.rz-datepicker-popup-container .rz-timepicker::before,
.rz-datepicker-inline-container .rz-timepicker::before {
    content: "Time";
    margin-inline-end: auto;
    font-size: .72rem;
    font-weight: var(--pf-fw-bold);
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--pf-text-muted);
}

.rz-datepicker-popup-container .rz-hour-picker,
.rz-datepicker-popup-container .rz-minute-picker,
.rz-datepicker-popup-container .rz-second-picker,
.rz-datepicker-inline-container .rz-hour-picker,
.rz-datepicker-inline-container .rz-minute-picker,
.rz-datepicker-inline-container .rz-second-picker {
    border: 1px solid var(--pf-dlg-field-border);
    border-radius: var(--pf-radius-sm, 5px);
    color: var(--pf-text);
}

/* Add-vessel wizard: the name-search hits. Capped in height so a full page of
   matches cannot push the dialog's own buttons off the screen. */
.avw-matches {
    max-height: 320px;
    overflow-y: auto;
    border: 1px solid var(--pf-dlg-section-border);
    border-radius: var(--pf-radius-md, 8px);
    background: var(--pf-dlg-section-bg);
}

.avw-matches table {
    margin-bottom: 0;
    color: var(--pf-text);
}

.avw-matches thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--pf-dlg-section-bg);
    font-size: .72rem;
    font-weight: var(--pf-fw-bold);
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--pf-text-muted);
    border-bottom: 1px solid var(--pf-dlg-section-border);
}

.avw-matches tbody td {
    font-size: var(--pf-fs-sm);
    border-color: var(--pf-border);
}

.pf-dlg-readonly {
    padding: .3rem .5rem;
    background: var(--pf-dlg-section-bg);
    border: 1px dashed var(--pf-dlg-field-border);
    border-radius: var(--pf-radius-sm, 5px);
    font-weight: var(--pf-fw-bold);
    color: var(--pf-text);
    min-height: 2rem;
}

.pf-dialog__footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--pf-space-2);
    padding: var(--pf-space-3) var(--pf-space-4);
    background: var(--pf-surface-1);
    border-top: 1px solid var(--pf-border);
    flex: 0 0 auto;
}

/* Set on <body> while any dialog is open, counted so stacked dialogs behave. */
body.pf-dialog-open {
    overflow: hidden;
}

@keyframes pf-dialog-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes pf-dialog-rise {
    from { opacity: 0; transform: translateY(8px) scale(.99); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .pf-dialog-backdrop,
    .pf-dialog {
        animation: none;
    }
}

@media (max-width: 575.98px) {
    .pf-dialog-backdrop { padding: 0; align-items: flex-end; }

    .pf-dialog {
        max-width: none;
        max-height: 92vh;
        border-radius: var(--pf-radius-lg) var(--pf-radius-lg) 0 0;
    }
}

/* ============================================================================
   CRUD CARD HEADER (Phase C4)
   ----------------------------------------------------------------------------
   The "Create/Update X" card header repeated across every add/edit form and
   list page in this work package as inline style="background-color:#12304b;"
   plus a white PNG icon inverted with filter:brightness(0) invert(1). One class
   for both, tokenized.
   ============================================================================ */

.pf-crud-header {
    display: flex;
    align-items: center;
}

/* Thirty-five components write "card-header text-white", from when these
   headers were a filled navy slab. They are a light tint now, so Bootstrap's
   .text-white — which is !important — was painting white text onto a
   near-white band and taking the title and its badge with it. Beaten on
   specificity here rather than by editing thirty-five files, any one of
   which would have been missed. */
.card-header:not(.pp-panel__header).text-white,
.card-header:not(.pp-panel__header) .text-white,
.card-header:not(.pp-panel__header) .text-white-50 {
    color: var(--pf-panel-head-fg) !important;
}

/* The artwork cannot take currentColor, so it is inverted only where the
   band is actually dark. */
.pf-crud-header__icon {
    filter: none;
    height: 20px;
}

:root.pf-theme-dark .pf-crud-header__icon {
    filter: brightness(0) invert(1);
}

/* Count chip sitting in a card header.
   It was rgba(255,255,255,.2) with white ink, written when these headers were a
   hardcoded navy. They are not: the global "Marine Headers Defined v4" rule
   paints every .card-header with a --pf-surface-2 gradient and --pf-text ink,
   both !important, so white-on-white made the chip invisible. It follows the
   header's real surface now. */
/* Reads the band's own family, like every other panel badge, so it stays
   legible whichever surface the header resolves to. */
.pf-crud-header__count,
.pf-list-header__count {
    background: color-mix(in srgb, var(--pf-fam) 20%, transparent);
    color: var(--pf-panel-head-fg) !important;
    font-weight: 700;
    white-space: nowrap;
}

/* A brand-coloured badge used inline in prose — role names, short labels.
   Unlayered: Bootstrap's .badge sets its own color and would win otherwise. */
.pf-brand-badge {
    background-color: var(--pf-brand);
    color: var(--pf-text-inverse);
}


/* ============================================================================
   DASHBOARD PANEL SHELLS (Phase C4)
   ----------------------------------------------------------------------------
   Folded from the <style> blocks of ShipperDashboard and
   TerminalOperatorSlotPlanner. Both are SfDashboardLayout pages (a justified
   Syncfusion retention) and both were carrying the same three shapes inline:
   a min-height for the layout host, a scrolling panel body, and a panel header
   that holds a selector beside its title. One definition now.
   ============================================================================ */

@layer pf-pages {

  #shipperDashboard          { min-height: calc(100vh - 220px); }
  #terminalOperatorDashboard { min-height: calc(100vh - 180px); }

  .shipper-dashboard-panel-body,
  .to-panel-body {
    height: 100%;
    overflow: auto;
    padding: .5rem;
  }

  .to-chart-panel           { height: 100%; padding: .2rem; }
  .to-chart-panel--graph    { overflow: hidden; }
  .to-chart-panel--legend   { overflow: auto; padding-right: .1rem; }

  .to-panel-header-with-selector {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .5rem;
  }

  .to-panel-header-with-selector span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}


/* ============================================================================
   SLOT LIST GRID (Phase C4)  —  CONTAINS FROZEN COLOURS
   ----------------------------------------------------------------------------
   Folded from the <style> blocks of ShipperSlotListPanel and
   TerminalOperatorSlotListPanel. The two were 224 and 211 lines that differed
   in exactly one declaration — their grid-template-columns — and in nothing
   else, so they are one definition here with a per-panel modifier for the
   column template.

   The slot-type backgrounds and borders below are the FROZEN business palette
   (REDESIGN_PATTERNS.md §1.4). They are written as --pf-slot-* tokens, which
   hold byte-identical values to the hexes they replace and are declared the
   same in light and dark, so nothing renders differently.

   Consequence, and it is deliberate: a typed slot row keeps its light
   background in dark mode, because that is what "never retune" means for this
   palette. Its ink is therefore pinned to --pf-slot-fg rather than --pf-text,
   so dark mode cannot put light text on a light row. The untyped row and the
   header do theme normally. Whether the slot grid should instead become a
   light island with dark chrome is a question for C7, where SlotCard.razor.css
   faces the identical one — do not answer it here, in a fold.
   ============================================================================ */

@layer pf-pages {

  .pf-slot-grid__header,
  .pf-slot-grid__row {
    display: grid;
    gap: .75rem;
    align-items: center;
  }

  .pf-slot-grid__header.pf-slot-grid--shipper,
  .pf-slot-grid__row.pf-slot-grid--shipper {
    grid-template-columns: 1.15fr .8fr 1fr .95fr .9fr 1fr .95fr .9fr .85fr 1.15fr;
  }

  .pf-slot-grid__header.pf-slot-grid--operator,
  .pf-slot-grid__row.pf-slot-grid--operator {
    grid-template-columns: 1.05fr .8fr 1.1fr 1fr .95fr 1fr 1fr .95fr .95fr 1.05fr;
  }

  .pf-slot-grid__header {
    padding: .75rem 1rem;
    margin-bottom: .5rem;
    border: 1px solid var(--pf-border);
    border-radius: .45rem;
    background: linear-gradient(180deg, var(--pf-surface-2) 0%, var(--pf-surface-3) 100%);
    color: var(--pf-text);
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .02em;
    text-transform: uppercase;
  }

  .pf-slot-grid__row {
    padding: .75rem 1rem;
    margin-bottom: .5rem;
    border: 1px solid var(--pf-border);
    border-radius: .45rem;
    background: var(--pf-surface-1);
    color: var(--pf-text);
    font-size: .85rem;
    box-shadow: 0 1px 4px rgba(18, 48, 75, 0.05);
  }

  /* ── FROZEN slot-type rows ── */
  .pf-slot-grid__row.permanent-slot {
    background-color: var(--pf-slot-permanent-bg);
    border-left: 4px solid var(--pf-slot-permanent-border);
  }

  .pf-slot-grid__row.opportunistic-slot {
    background-color: var(--pf-slot-opportunistic-bg);
    border-left: 4px solid var(--pf-slot-opportunistic-border);
  }

  .pf-slot-grid__row.priority-slot {
    background-color: var(--pf-slot-priority-bg);
    border-left: 4px solid var(--pf-slot-priority-border);
  }

  .pf-slot-grid__row.reserved-slot {
    background-color: var(--pf-slot-reserved-bg);
    border-left: 4px solid var(--pf-slot-reserved-border);
  }

  .pf-slot-grid__row.terminal-slot {
    background-color: var(--pf-slot-terminal-bg);
    border-left: 4px solid var(--pf-slot-terminal-border);
  }

  .pf-slot-grid__row.virtual-gap-slot {
    background: var(--pf-slot-virtualgap-bg);
    border-left: 4px solid var(--pf-slot-virtualgap-border);
    border-color: rgba(212, 177, 6, .32);
  }

  /* A typed row's background is frozen light in both themes, so its ink is
     pinned too — --pf-text would go pale in dark mode and vanish. */
  .pf-slot-grid__row.permanent-slot,
  .pf-slot-grid__row.opportunistic-slot,
  .pf-slot-grid__row.priority-slot,
  .pf-slot-grid__row.reserved-slot,
  .pf-slot-grid__row.terminal-slot,
  .pf-slot-grid__row.virtual-gap-slot {
    color: var(--pf-slot-fg);
  }

  /* The row's own children set colours of their own, so they need pinning too —
     inheritance alone does not reach them. */
  .pf-slot-grid__row.permanent-slot .pf-slot-grid__mobile-label,
  .pf-slot-grid__row.opportunistic-slot .pf-slot-grid__mobile-label,
  .pf-slot-grid__row.priority-slot .pf-slot-grid__mobile-label,
  .pf-slot-grid__row.reserved-slot .pf-slot-grid__mobile-label,
  .pf-slot-grid__row.terminal-slot .pf-slot-grid__mobile-label,
  .pf-slot-grid__row.virtual-gap-slot .pf-slot-grid__mobile-label {
    color: var(--pf-slot-fg);
  }

  .pf-slot-grid__cell {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .pf-slot-grid__cell--action {
    display: flex;
    justify-content: flex-end;
  }

  .pf-slot-grid__actions {
    display: inline-flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: .35rem;
  }

  .pf-slot-grid__mobile-label {
    display: none;
    color: var(--pf-text-muted);
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    margin-right: .35rem;
  }

  .pf-slot-grid__message {
    white-space: normal;
    color: #856404;
    font-size: .76rem;
    line-height: 1.25;
    margin-top: .15rem;
  }

  .pf-slot-grid__empty-state {
    color: var(--pf-text-subtle);
    font-weight: 600;
  }

  .slot-panel-header-controls {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
  }

  .slot-panel-header-controls__actions {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
  }

  .slot-panel-search-box {
    width: 210px;
  }

  /* ── FROZEN slot-type badges ── */
  .pf-slot-type-badge {
    display: inline-flex;
    align-items: center;
    padding: .2rem .45rem;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 700;
    border: 1px solid transparent;
    color: var(--pf-slot-fg);
  }

  .pf-slot-type-badge.permanent-slot {
    background-color: var(--pf-slot-permanent-hover);
    border-color: var(--pf-slot-permanent-border);
  }

  .pf-slot-type-badge.terminal-slot {
    background-color: var(--pf-slot-terminal-bg);
    border-color: var(--pf-slot-terminal-border);
  }

  .pf-slot-type-badge.opportunistic-slot {
    background-color: var(--pf-slot-opportunistic-hover);
    border-color: var(--pf-slot-opportunistic-border);
  }

  .pf-slot-type-badge.priority-slot {
    background-color: var(--pf-slot-priority-hover);
    border-color: var(--pf-slot-priority-border);
  }

  .pf-slot-type-badge.reserved-slot {
    background-color: var(--pf-slot-reserved-hover);
    border-color: var(--pf-slot-reserved-border);
  }

  .pf-slot-type-badge.virtual-gap-slot {
    background-color: var(--pf-slot-virtualgap-hover);
    border-color: var(--pf-slot-virtualgap-border);
  }

  /* ── Allocation deadline warning overrides ── */
  .pf-slot-grid__row.slot-row-warn-orange {
    border-left-width: 5px !important;
    border-left-color: #fd7e14 !important;
  }

  .pf-slot-grid__row.slot-row-warn-red {
    border-left-width: 5px !important;
    border-left-color: #dc3545 !important;
  }

  .slot-warn-inline {
    white-space: normal;
    font-size: .74rem;
    line-height: 1.2;
    margin-top: .15rem;
    font-weight: 600;
  }

  .slot-warn-inline--orange { color: #a85400; }
  .slot-warn-inline--red    { color: #842029; }

  /* The slot number heading repeated at the top of every slot dialog body. */
  .pf-dialog-slot-number { color: var(--pf-text); }

  @media (max-width: 1199.98px) {
    .slot-panel-header-controls,
    .slot-panel-header-controls__actions {
      width: 100%;
    }

    .slot-panel-search-box {
      width: 100%;
    }

    .pf-slot-grid__row.pf-slot-grid--shipper,
    .pf-slot-grid__row.pf-slot-grid--operator {
      grid-template-columns: 1fr;
      gap: .35rem;
    }

    .pf-slot-grid__cell {
      white-space: normal;
      overflow: visible;
      text-overflow: initial;
    }

    .pf-slot-grid__mobile-label {
      display: inline;
    }

    .pf-slot-grid__cell--action,
    .pf-slot-grid__actions {
      justify-content: flex-start;
    }
  }
}


/* ============================================================================
   AGENT VESSEL GRID + ETA PANEL (Phase C4)
   ----------------------------------------------------------------------------
   Folded from the <style> blocks of AgentsDashboard (170 lines) and
   AgentVesselsEtaPanel (238). The .agent-vessel-* grid was duplicated across
   both, near-identically: same seven-column layout, same underway/arrived/
   in-port row tinting, same badge. The base below is the AgentsDashboard copy;
   the ETA panel ran the same grid a shade tighter and with a different badge
   ink, so its four genuine deviations are scoped under .avp-card rather than
   flattened into the base — folding is not the place to decide which of two
   renderings is correct.

   One declaration was dropped as dead, not changed: the ETA panel's
   .agent-vessel-status-badge--in-port set a colour that its own base rule
   already overrode with !important, so it never applied.
   ============================================================================ */

@layer pf-pages {

  /* ── The vessel grid, shared ── */

  .agent-vessel-grid-header,
  .agent-vessel-grid-row {
    display: grid;
    grid-template-columns: 1.4fr 1fr .9fr 1.2fr 1fr .9fr 1.1fr;
    gap: .75rem;
    align-items: center;
  }

  .agent-vessel-grid-header {
    padding: .75rem 1rem;
    margin-bottom: .5rem;
    border: 1px solid var(--pf-border);
    border-radius: .45rem;
    background: linear-gradient(180deg, var(--pf-surface-2) 0%, var(--pf-surface-3) 100%);
    color: var(--pf-text);
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .02em;
    text-transform: uppercase;
  }

  .agent-vessel-grid-row {
    padding: .75rem 1rem;
    margin-bottom: .5rem;
    border: 1px solid var(--pf-border);
    border-radius: .45rem;
    background: var(--pf-surface-1);
    color: var(--pf-text);
    font-size: .85rem;
    box-shadow: 0 1px 4px rgba(18, 48, 75, 0.05);
  }

  /* Vessel movement state. Not the slot palette — these are the teal steps the
     agent screens use for underway / arrived / in port, and they are light in
     both themes, so the row ink is pinned alongside them. */
  .agent-vessel-grid-row--underway {
    background: #eefcfb;
    border-color: rgba(71, 145, 153, 0.18);
  }

  .agent-vessel-grid-row--arrived {
    background: #d6f2ef;
    border-color: rgba(50, 138, 146, 0.22);
  }

  .agent-vessel-grid-row--in-port {
    background: #b8e6e0;
    border-color: rgba(29, 112, 120, 0.3);
  }

  .agent-vessel-grid-row--underway,
  .agent-vessel-grid-row--arrived,
  .agent-vessel-grid-row--in-port {
    color: var(--pf-slot-fg);
  }

  .agent-vessel-grid-row--underway .agent-vessel-grid-mobile-label,
  .agent-vessel-grid-row--arrived .agent-vessel-grid-mobile-label,
  .agent-vessel-grid-row--in-port .agent-vessel-grid-mobile-label {
    color: var(--pf-slot-fg);
  }

  .agent-vessel-grid-cell {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .agent-vessel-grid-cell--action {
    display: flex;
    justify-content: flex-end;
  }

  .agent-vessel-grid-mobile-label {
    display: none;
    color: var(--pf-text-muted);
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    margin-right: .35rem;
  }


  /* ── AgentsDashboard only: the slot grid header and the vessel autocomplete ── */

  .agent-slot-grid-header {
    display: grid;
    grid-template-columns: 1fr .9fr 1.3fr 1fr 1.2fr 1.25fr 1fr 1.1fr .9fr 1.15fr 1.05fr 1.15fr;
    gap: .75rem;
    align-items: center;
    padding: .75rem 1rem;
    margin-bottom: .5rem;
    border: 1px solid var(--pf-border);
    border-radius: .45rem;
    background: linear-gradient(180deg, var(--pf-surface-2) 0%, var(--pf-surface-3) 100%);
    color: var(--pf-text);
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .02em;
    text-transform: uppercase;
  }

  .agent-vessel-autocomplete {
    position: absolute;
    top: calc(100% + .15rem);
    left: 0;
    right: 0;
    z-index: 1060;
    max-height: 240px;
    overflow-y: auto;
    background: var(--pf-surface-1);
    border: 1px solid var(--pf-border);
    border-radius: .45rem;
    box-shadow: 0 8px 24px rgba(18, 48, 75, 0.16);
  }

  .agent-vessel-autocomplete__item {
    display: block;
    width: 100%;
    padding: .55rem .75rem;
    border: 0;
    border-bottom: 1px solid var(--pf-border);
    background: var(--pf-surface-1);
    color: var(--pf-text);
    text-align: left;
    font-size: .85rem;
  }

  .agent-vessel-autocomplete__item:last-child {
    border-bottom: 0;
  }

  .agent-vessel-autocomplete__item:hover {
    background: var(--pf-surface-2);
  }

  /* ── AgentVesselsEtaPanel: card shell, pills, row buttons ── */

  .avp-card {
    border: 1px solid var(--pf-border);
    border-radius: 8px;
    box-shadow: 0 4px 14px rgba(18, 48, 75, 0.08);
    overflow: hidden;
    background: var(--pf-surface-1);
  }

  .avp-card-header {
    display: flex;
    align-items: center;
    padding: .65rem 1rem;
    background: linear-gradient(180deg, #4a6b84 0%, #2c4d65 40%, #1a3550 70%, #12304b 100%);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.18),
                inset 0 -1px 0 rgba(0,0,0,0.25),
                0 4px 10px rgba(0,0,0,0.25);
    color: #fff;
    font-weight: 700;
    letter-spacing: .02em;
  }

  .avp-card-header__icon {
    height: 20px;
    filter: brightness(0) invert(1);
  }

  .avp-card-header__title {
    font-size: .95rem;
  }

  .avp-card-body {
    background: var(--pf-surface-1);
  }

  /* The four places the ETA panel's copy of the grid genuinely differed. */
  .avp-card .agent-vessel-grid-header {
    padding: .65rem 1rem;
    border-radius: 6px;
    font-size: .76rem;
  }

  .avp-card .agent-vessel-grid-row {
    padding: .7rem 1rem;
    border-radius: 6px;
    transition: box-shadow .12s, transform .12s;
  }

  .avp-card .agent-vessel-grid-row:hover {
    box-shadow: 0 3px 10px rgba(18, 48, 75, 0.12);
  }

  .avp-card .agent-vessel-grid-cell--action {
    gap: .35rem;
  }

  .avp-card .agent-vessel-status-badge {
    color: #2f4f4f !important;
    font-weight: 700;
    letter-spacing: .02em;
  }

  .avp-pending-pill {
    display: inline-flex;
    align-items: center;
    padding: .12rem .5rem;
    font-size: .68rem;
    font-weight: 700;
    color: #2f4f4f;
    background: #fff3cd;
    border: 1px solid #f0c97a;
    border-radius: 50px;
    letter-spacing: .02em;
  }

  .avp-pending-pill--arrival {
    background: #d1fae5;
    border-color: #6ee7b7;
  }

  .avp-row-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 30px;
    padding: 0 .85rem;
    font-size: .76rem;
    font-weight: 700;
    letter-spacing: .02em;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    color: #fff;
    text-shadow: 0 1px 2px rgba(0,0,0,.2);
    transition: transform .08s, box-shadow .08s;
  }

  .avp-row-btn:active:not(:disabled) {
    transform: translateY(2px);
  }

  .avp-row-btn--eta {
    background: linear-gradient(180deg, #4a6b84 0%, #2c4d65 55%, #1a3550 100%);
    box-shadow: 0 3px 0 #0d253a, 0 1px 4px rgba(18,48,75,.30);
  }

  .avp-row-btn--eta:hover {
    background: linear-gradient(180deg, #5a7b94 0%, #3c5d75 55%, #2a4560 100%);
    color: #fff;
  }

  .avp-row-btn--eta:active {
    box-shadow: 0 1px 0 #0d253a;
  }

  .avp-row-btn--arrival {
    background: linear-gradient(180deg, #22c55e 0%, #16a34a 55%, #15803d 100%);
    box-shadow: 0 3px 0 #166534, 0 1px 4px rgba(22,163,74,.30);
  }

  .avp-row-btn--arrival:hover {
    background: linear-gradient(180deg, #34d399 0%, #22c55e 55%, #16a34a 100%);
    color: #fff;
  }

  .avp-row-btn--arrival:active {
    box-shadow: 0 1px 0 #166534;
  }

  .avp-row-btn--disabled {
    background: linear-gradient(180deg, #9ca3af 0%, #6b7280 55%, #4b5563 100%);
    box-shadow: 0 3px 0 #374151, 0 1px 4px rgba(75,85,99,.25);
    cursor: not-allowed;
    opacity: .85;
  }

  @media (max-width: 1199.98px) {
    .agent-vessel-grid-row,
    .avp-card .agent-vessel-grid-row {
      grid-template-columns: 1fr;
      gap: .35rem;
    }

    .agent-vessel-grid-cell {
      white-space: normal;
      overflow: visible;
      text-overflow: initial;
    }

    .agent-vessel-grid-mobile-label {
      display: inline;
    }

    .agent-vessel-grid-cell--action,
    .avp-card .agent-vessel-grid-cell--action {
      justify-content: flex-start;
    }
  }
}


/* ============================================================================
   VESSEL FORM + VESSELS-IN-PORT TABLE (Phase C4)
   ----------------------------------------------------------------------------
   Folded from VesselAddEdit and VesselsInPortComponent, the last two C4 files
   still carrying a <style> block. Both were hardcoded to the old marine palette
   — #12304b headers, #78afd9 accents, #fff grounds — so neither followed dark
   mode. Tokenized on the way in; the vessels-in-port header keeps a fixed white
   ink because it sits on the brand colour in both themes.
   ============================================================================ */

@layer pf-pages {

  .vessel-form-shell {
    max-width: none;
  }

  .vessel-form-card__body {
    background: var(--pf-surface-1);
  }

  .vessel-form .form-label {
    color: var(--pf-text);
  }


  .vip-wrapper {
    font-size: 0.75rem;
    height: 100%;
    overflow-y: auto;
  }

  .vip-empty {
    color: var(--pf-text-subtle);
    padding: 12px 8px;
    text-align: center;
    font-size: 0.78rem;
  }

  .vip-table {
    width: 100%;
    border-collapse: collapse;
  }

  /* The same header every other grid in the app now uses. This was a filled
     --pf-brand slab with inverse ink, which in dark mode is a bright blue
     band carrying near-black text — the loudest element on the page and the
     one least like the rest of it. */
  .vip-table thead tr {
    background: var(--pf-surface-2);
    color: var(--pf-brand);
    position: sticky;
    top: 0;
    z-index: 1;
  }

  .vip-table thead th {
    font-family: var(--pf-font-head);
    font-size: .68rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .04em;
    border-bottom: 1px solid var(--pf-border);
  }

  /* Body text is body text. It was inheriting the brand blue from the row
     above, which on a dark panel reads as disabled rather than as data. */
  .vip-table tbody td {
    color: var(--pf-text);
  }

  .vip-table th {
    padding: 4px 5px;
    font-weight: 600;
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    white-space: nowrap;
  }

  .vip-table tbody tr {
    border-bottom: 1px solid var(--pf-border);
    transition: background 0.15s;
  }

  .vip-table tbody tr:hover {
    background: var(--pf-surface-2);
  }

  .vip-table td {
    padding: 4px 5px;
    vertical-align: middle;
  }

  .vip-berth {
    color: var(--pf-brand);
    font-weight: 600;
    white-space: nowrap;
  }

  .vip-vessel {
    font-weight: 600;
    color: var(--pf-text);
    max-width: 90px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .vip-date {
    color: var(--pf-text-muted);
    font-variant-numeric: tabular-nums;
  }

  .vip-overdue {
    color: var(--pf-band-red);
    font-weight: 600;
  }

  /* Row-level list items that select on click. */
  .pf-clickable {
    cursor: pointer;
  }

  /* The location pin beside a single-port page's port name. Repeated across C4
     as inline style="color:#78afd9" on a <p> that also hardcoded #12304b —
     invisible in dark mode. The same idiom exists in the BerthingSlot and
     ShoreTension pages; those are C6/C7 and keep their inline styles until
     their own work packages open them. */
  .pf-port-pin {
    color: var(--pf-brand);
  }

  /* Plain list-card header icon: size only. Unlike .pf-crud-header__icon it does
     not invert here — an existing rule already inverts every img inside a
     .card-header in dark mode, and in light mode these headers are the default
     light surface where an inverted PNG would disappear. */
  .pf-list-header__icon {
    height: 20px;
  }

}


/* ============================================================================
   C4 RULES THAT COMPETE WITH BOOTSTRAP — DELIBERATELY UNLAYERED
   ----------------------------------------------------------------------------
   Bootstrap loads unlayered from a CDN (App.razor). An unlayered declaration
   beats a layered one whatever the specificity — REDESIGN_PATTERNS.md 1.3 —
   so anything here that sets a property Bootstrap also sets on the same element
   has to sit outside @layer pf-pages or it silently loses.

   Each of these is written on an element that also carries a Bootstrap class:
   the two badges alongside .badge (which sets its own color), and the vessel
   form checkbox against .form-check-input:checked. The layout-only rules for
   the same components stay in the layer; Bootstrap claims none of those names.
   ============================================================================ */

.agent-vessel-status-badge {
    color: var(--pf-slot-fg);
    border: 1px solid transparent;
}

.agent-vessel-status-badge--underway {
    background-color: #d8f5f2;
    border-color: #a8ddd7;
}

.agent-vessel-status-badge--arrived {
    background-color: #aee3db;
    border-color: #83cbc0;
}

.agent-vessel-status-badge--in-port {
    background-color: #6fc5b9;
    border-color: #4faea2;
}

.vessel-form .form-check-input:checked {
    background-color: var(--pf-brand);
    border-color: var(--pf-brand);
}

/* Bootstrap's .form-control sets its own min-height, so this competes too. */
.vessel-form textarea.form-control {
    min-height: 96px;
    resize: vertical;
}


/* ============================================================================
   SETUP CARD GRID (Phase C5)
   ----------------------------------------------------------------------------
   Replaces MainSetup's six SfCards. They carried an image, a title and footer
   buttons and no card behaviour, so by the "migrate for behaviour, not styling"
   rule they became plain markup rather than RadzenCard.

   Most of the <style> block they came with was Syncfusion sample boilerplate —
   .material3-dark, .fluent, .tailwind3 focus-ring selectors for themes this app
   has never used — and went with them. The six cards also all carried
   ID="SideCard", six duplicate DOM ids, which is what the sizing hung off; it is
   a class now.
   ============================================================================ */

@layer pf-pages {

  .pf-setup-card {
    margin-bottom: 1.5rem;
    overflow: hidden;
    border: 1px solid var(--pf-border);
    background: var(--pf-surface-2);
  }

  .pf-setup-card__image {
    width: 100%;
    height: 200px;
    object-fit: cover;
  }

  .pf-setup-card__body {
    display: flex;
    flex-direction: column;
    gap: .75rem;
  }

  .pf-setup-card__title {
    margin: 0;
    font-size: var(--pf-fs-sm, .875rem);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--pf-text);
  }

  .pf-setup-card__actions {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    margin-top: auto;
  }
}


/* ============================================================================
   HOME HERO + PORT CARDS (Phase C5)
   ----------------------------------------------------------------------------
   Home.razor's 265-line <style> block was almost entirely Syncfusion sample
   boilerplate — .material3-dark, .fluent, .tailwind3, .highcontrast focus rings
   for themes this app has never run — wrapped around sizing for an SfCarousel
   and two SfCards that no longer exist. What survived is here: the hero's
   dimensions and the port card's proportions.

   The hero was an SfCarousel on AnimationEffect.Fade with a 5s interval. Four
   stacked images on one crossfade keyframe reproduce that with no component and
   no JS. Deliberate loss: the indicator dots and previous/next arrows are gone.
   On a decorative marketing hero that is a fair trade for deleting a component;
   if manual control is wanted back, make the track a scroll-snap strip with
   anchor-link dots and drop the animation.
   ============================================================================ */

@layer pf-pages {

  .pf-hero {
    position: relative;
    width: 100%;
    height: clamp(240px, 38vh, 420px);
    overflow: hidden;
    background: var(--pf-surface-2);
  }

  .pf-hero__slides {
    position: absolute;
    inset: 0;
  }

  .pf-hero__slide {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    animation: pf-hero-fade 20s infinite;
  }

  /* Four slides, 20s loop: each is opaque for its own quarter and crossfades
     across roughly a second at each edge. */
  .pf-hero__slide:nth-child(1) { animation-delay:  0s; }
  .pf-hero__slide:nth-child(2) { animation-delay:  5s; }
  .pf-hero__slide:nth-child(3) { animation-delay: 10s; }
  .pf-hero__slide:nth-child(4) { animation-delay: 15s; }

  @media (prefers-reduced-motion: reduce) {
    .pf-hero__slide {
      animation: none;
    }
    /* Without the animation every slide would sit at opacity 0, so the first
       one is pinned visible and the rest stay hidden. */
    .pf-hero__slide:first-child {
      opacity: 1;
    }
  }

  .pf-port-card {
    display: flex;
    flex-direction: column;
    height: 440px;
    overflow: hidden;
    text-decoration: none;
    border: 1px solid var(--pf-border);
    background: var(--pf-surface-2);
    transition: box-shadow .15s ease, transform .15s ease;
  }

  .pf-port-card:hover {
    box-shadow: 0 6px 16px rgba(18, 48, 75, .18);
    transform: translateY(-2px);
  }

  .pf-port-card__image {
    flex: 1 1 auto;
    min-height: 240px;
    width: 100%;
    object-fit: cover;
  }

  .pf-port-card__body {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .6rem;
    text-align: center;
  }

  .pf-port-card__title {
    margin: 0;
    font-size: var(--pf-fs-md, 1rem);
    font-weight: 700;
    color: var(--pf-text);
  }
}

@keyframes pf-hero-fade {
  0%     { opacity: 0; }
  2%     { opacity: 1; }
  25%    { opacity: 1; }
  27%    { opacity: 0; }
  100%   { opacity: 0; }
}


/* ============================================================================
   USER MANAGER (Phase C5)
   ----------------------------------------------------------------------------
   Folded from UserManager.razor's 266-line <style> block.

   The original design was a hardcoded navy panel (#12304b) with white text, and
   white table rows with navy ink forced on top of it — a light island inside a
   dark one, built before there was a palette. Under Night Watch both halves come
   from tokens instead: the panel takes surface-2, the rows surface-1, and each
   states its own ink rather than inheriting across the boundary.

   Dropped as dead: ~30 lines of .user-editor-dialog / .user-delete-dialog rules
   that restyled SfDialog's .e-dlg-header-content. Both dialogs now render through
   PfDialog, which owns its own chrome, and the delete dialog's red header is its
   Danger tone rather than a hand-written #dc3545.

   The five action-icon hues are kept deliberately — they are how an operator
   tells Edit from Delete at a glance in a dense row — but mapped to the shared
   band tokens so they follow the theme.
   ============================================================================ */

@layer pf-pages {

  .user-manager-shell {
    width: 100%;
    max-width: none;
  }

  .user-manager-card-row,
  .user-manager-card-row > .col-12 {
    width: 100%;
  }

  .user-manager-card {
    background-color: var(--pf-surface-2);
    color: var(--pf-text);
    width: 100%;
  }

  .user-manager-card__header {
    border-bottom: 2px solid var(--pf-brand);
  }

  .user-manager-card__body {
    background-color: var(--pf-surface-2);
    color: var(--pf-text);
  }

  .user-manager-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
  }

  .user-manager-toolbar__main {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex: 1 1 480px;
    flex-wrap: wrap;
    min-width: 0;
  }

  .user-manager-toolbar__title { flex: 0 0 auto; }

  .user-manager-toolbar__search {
    flex: 1 1 320px;
    min-width: 220px;
    max-width: 420px;
  }

  .user-manager-toolbar__actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex: 0 0 auto;
    margin-left: auto;
  }

  .user-manager-table-wrap { width: 100%; }

  .user-manager-table {
    min-width: 980px;
    color: var(--pf-text);
  }

  .user-manager-sort-btn {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    width: 100%;
    justify-content: flex-start;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-weight: inherit;
  }

  .user-manager-sort-btn--center { justify-content: center; }

  .user-manager-sort-btn .bi { font-size: .85rem; }

  .users-grid-actions {
    display: inline-flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: .35rem;
  }

  .users-grid-actions__btn i {
    color: currentColor;
    font-size: 1rem;
  }

  @media (max-width: 991.98px) {
    .user-manager-shell {
      padding-left: .75rem;
      padding-right: .75rem;
    }

    .user-manager-toolbar__actions {
      width: 100%;
      justify-content: flex-start;
      margin-left: 0;
    }

    .user-manager-table { min-width: 860px; }
  }
}

/* ----------------------------------------------------------------------------
   UNLAYERED — these compete with Bootstrap on the same elements.
   .table sets cell background and border colour through its own --bs-table-*
   variables, .form-control and .input-group-text set background and colour, and
   .btn and .badge set colour. A layered rule loses all of those regardless of
   specificity (PATTERNS 1.3), which is how the C4 folds broke.
   -------------------------------------------------------------------------- */

.user-manager-search-group__icon,
.user-manager-search-group__clear {
    background: var(--pf-surface-1);
    border-color: var(--pf-border-strong);
    color: var(--pf-text);
}

.user-manager-search-group__clear:hover,
.user-manager-search-group__clear:focus {
    background: var(--pf-surface-3);
    color: var(--pf-text);
    border-color: var(--pf-brand);
}

.user-manager-search-group__input {
    background: var(--pf-surface-1);
    border-color: var(--pf-border-strong);
    color: var(--pf-text);
}

.user-manager-search-group__input::placeholder {
    color: var(--pf-text-subtle);
}

.user-manager-search-group__input:focus {
    background: var(--pf-surface-1);
    border-color: var(--pf-brand);
    box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--pf-brand) 22%, transparent);
    color: var(--pf-text);
}

.user-manager-toolbar-btn {
    color: var(--pf-text);
    border-color: var(--pf-border-strong);
}

.user-manager-toolbar-btn:hover,
.user-manager-toolbar-btn:focus {
    color: var(--pf-text);
    background-color: var(--pf-surface-3);
    border-color: var(--pf-brand);
}

/* Data rows sit on their own surface inside the panel, and state their ink. */
.user-manager-table > :not(caption) > * > * {
    background-color: var(--pf-surface-1);
    color: var(--pf-text);
    border-color: var(--pf-border);
    vertical-align: middle;
}

.user-manager-table__head > tr > th {
    background-color: var(--pf-surface-3) !important;
    color: var(--pf-text) !important;
    border-bottom-color: var(--pf-border-strong) !important;
    white-space: nowrap;
    font-weight: 600;
}

.user-manager-table tbody tr:hover > * {
    background-color: var(--pf-surface-2) !important;
    color: var(--pf-text) !important;
}

.user-manager-table tr.table-info > *,
.user-manager-table tr.table-info.fw-semibold > * {
    background-color: color-mix(in srgb, var(--pf-brand) 22%, transparent) !important;
    color: var(--pf-text) !important;
}

.user-manager-table tr.table-warning > * {
    background-color: var(--pf-band-orange-bg) !important;
    color: var(--pf-text) !important;
}

.user-manager-table .badge.bg-primary {
    background-color: var(--pf-brand) !important;
    color: var(--pf-text-inverse) !important;
}

.users-grid-actions__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2rem;
    color: var(--pf-text);
    border-color: var(--pf-border);
    background-color: transparent;
}

.users-grid-actions__btn:hover,
.users-grid-actions__btn:focus {
    color: var(--pf-text);
    background-color: var(--pf-surface-3);
    border-color: var(--pf-border-strong);
}

/* One hue per action so a dense row stays scannable. */
.users-grid-actions__btn--edit i   { color: var(--pf-brand); }
.users-grid-actions__btn--roles i  { color: #a78bfa; }
.users-grid-actions__btn--ports i  { color: var(--pf-band-green); }
.users-grid-actions__btn--reset i  { color: var(--pf-band-orange); }
.users-grid-actions__btn--delete i { color: var(--pf-band-red); }

.user-manager-card .form-check-input:checked {
    background-color: var(--pf-brand);
    border-color: var(--pf-brand);
}


/* ============================================================================
   SHIPPING LIST DISPLAY (Phase C5)
   ----------------------------------------------------------------------------
   Folded from ShippingListDisplay.razor. This file was left half-migrated in an
   earlier phase against a "Bootstrap gets dropped after C4" sweep that exists in
   neither tracker; there is no such phase, so it folds like any other.

   The .sld-flag yes/no dots and the day-group rules came from MudChip and
   MudTable when those were removed; they are unchanged apart from tokenizing.
   ============================================================================ */

@layer pf-pages {

  .sld-banner {
    background-color: var(--pf-brand);
    color: var(--pf-text-inverse);
    border-radius: .375rem;
  }

  .sld-table th,
  .sld-table td {
    font-size: .8rem;
    white-space: nowrap;
  }

  .sld-table thead th {
    font-weight: 600;
    font-size: .72rem;
    letter-spacing: .03em;
  }

  .sld-day-group {
    border-bottom: 1px solid var(--pf-border);
  }

  .sld-day-group:last-child {
    border-bottom: none;
  }

  .sld-label {
    font-size: .875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .6px;
  }

  .sld-value {
    font-size: 1.25rem;
    font-weight: 600;
  }

  /* Boolean clearance indicator — was a 20px MudChip. */
  .sld-flag {
    display: inline-block;
    width: 20px;
    height: 20px;
    border-radius: 999px;
  }

  .sld-flag--yes { background-color: var(--pf-band-green); }
  .sld-flag--no  { background-color: var(--pf-band-red); }

  .sld-day-header {
    background: var(--pf-surface-3);
    color: var(--pf-text);
    font-weight: 600;
    padding: .5rem .75rem;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
  }
}


/* ============================================================================
   SLOT STATUS STEPS (Phase C7)
   ----------------------------------------------------------------------------
   The slot lifecycle strip on the three slot templates. It was an SfStepper with
   ~20 lines of .e-stepper overrides per file — colouring the completed and
   in-progress indicators, and scaling the whole thing to 78% so it fitted a slot
   card. Those rules died with the component; this is their replacement.

   RadzenSteps renders a content panel per step and a numbered indicator. Neither
   is wanted: the steps are a read-only progress display whose icons live in each
   item's Template, so the panel is hidden and the number is replaced by the icon.
   Colours come from the bridged --rz-steps-* variables, so the strip follows the
   theme instead of being pinned to the old #78afd9.
   ============================================================================ */

@layer pf-components {

  .pf-slot-steps {
    font-size: .58rem;
    letter-spacing: .01em;
  }

  /* The Syncfusion stepper was scaled to 78% so all six steps fitted one line
     inside a slot card. Radzen's wraps instead, which costs a row of card
     height per slot, so the strip is held on one line and allowed to scroll. */
  .pf-slot-steps .rz-steps-list {
    flex-wrap: nowrap;
    gap: .15rem;
    overflow-x: auto;
    scrollbar-width: thin;
  }

  .pf-slot-steps .rz-steps-item {
    flex: 0 0 auto;
  }

  /* Read-only progress: no panel. Hiding the Previous/Next row is unlayered — see RADZEN
     OVERRIDES at the end of this file. */
  .pf-slot-steps .rz-steps-panels {
    display: none;
  }

  .pf-slot-steps .rz-steps-number {
    width: 22px;
    height: 22px;
    min-width: 22px;
    font-size: .65rem;
    line-height: 22px;
  }

  .pf-slot-steps .rz-steps-title {
    font-size: .58rem;
    white-space: nowrap;
  }

  /* The same strip inside the slot dialog is a different thing: there it is
     the width of the panel and it is the main thing being read, not a chip
     squeezed onto a card. The compact rules above kept every step at its
     content width, so all six huddled in the left corner of a wide dialog
     with the rest of the row empty. Here they share the width evenly. */
  .bpt-stepper-wrap {
    width: 100%;
  }

  .bpt-stepper-wrap .pf-slot-steps {
    font-size: .72rem;
  }

  /* Targeted at the bare <ul>, not .rz-steps-list. Radzen renders the list
     with no class at all, so the .rz-steps-list rules elsewhere in this file
     have never matched anything — the strip has been laid out by default
     inline-block flow the whole time, which is why the steps bunched at the
     left and the sixth wrapped onto its own line. */
  .bpt-stepper-wrap .pf-slot-steps ul {
    display: flex;
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: .25rem;
    width: 100%;
    margin: 0;
    padding-left: 0;
    list-style: none;
    overflow-x: visible;
  }

  .bpt-stepper-wrap .pf-slot-steps ul > li {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    justify-content: center;
  }

  .bpt-stepper-wrap .pf-slot-steps ul > li > * {
    width: 100%;
    justify-content: center;
  }

  /* Six labels sharing one row will not all fit at full length on a narrow
     dialog; they truncate rather than forcing a wrap that would put one step
     on a line of its own. */
  .bpt-stepper-wrap .pf-slot-steps .rz-steps-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .bpt-stepper-wrap .pf-slot-steps .rz-steps-number {
    width: 26px;
    height: 26px;
    min-width: 26px;
    font-size: .72rem;
    line-height: 26px;
  }

  .bpt-stepper-wrap .pf-slot-steps .rz-steps-title {
    font-size: .72rem;
  }

  /* Number ABOVE the label, not beside it. Radzen lays the link out as an
     inline-flex row, so with six steps sharing one dialog width the label was
     jammed against its own circle and read as part of the number. Stacking buys
     each label the full step width and costs one row of dialog height. */
  .bpt-stepper-wrap .pf-slot-steps .rz-menuitem-link {
    flex-direction: column;
    align-items: center;
    gap: .3rem;
    width: 100%;
    text-align: center;
  }

  .bpt-stepper-wrap .pf-slot-steps .rz-steps-title {
    margin-inline: 0;
    margin-block: 0;
    max-width: 100%;
  }

  /* A disabled step still has to read as reachable-later, not as absent. */
  .pf-slot-steps .rz-steps-item.rz-state-disabled {
    opacity: .55;
  }

  .pf-slot-steps .rz-steps-item.rz-state-disabled .rz-steps-number {
    cursor: default;
  }
}


/* ============================================================================
   WEATHER + ASTRONOMICAL PANELS (Phase C2)
   ----------------------------------------------------------------------------
   Folded from the <style> blocks of WeatherWidget, WeatherForecastPanel,
   WeatherForecastPage and AstronomicalSummaryBar — 306 lines between them.

   Two of these wrap a Chart.js <canvas>, and Chart.js is a justified retention
   (its windArrows plugin has no replacement). Unlike ScedulePerBerthComponent,
   though, almost none of this configures the retained component: it is the
   panels' own chrome, plus two or three rules sizing the chart wrapper. The
   class names are prefixed and used nowhere outside Pages/Shared, so unscoping
   them cannot collide.

   Chrome colours are tokenized so the panels follow the theme. Deliberately
   left literal: the temperature red (#e04e2a) and the error-state maroon
   (#842029), which are read as state rather than as decoration.
   ============================================================================ */

@layer pf-components {

  /* ---- WeatherWidget ---- */
    .ww-card {
        display: flex;
        flex-direction: column;
        height: 100%;
        font-size: 0.78rem;
    }

    @@keyframes ww-rotate { to { transform: rotate(360deg); } }
    .ww-spin { display: inline-block; animation: ww-rotate .9s linear infinite; }

    .ww-state {
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 14px;
        font-size: 0.78rem;
        text-align: center;
    }

    .ww-body {
        flex: 1;
        min-height: 0;
        padding: 4px 8px 2px;
        display: flex;
        flex-direction: column;
        gap: 4px;
        overflow: hidden;
    }

    /* Two-column row: data left, compass right */
    .ww-main-row {
        display: flex;
        align-items: center;
        gap: 6px;
        flex: 1;
        min-height: 0;
    }

    .ww-data-col {
        display: flex;
        flex-direction: column;
        gap: 4px;
        flex: 1;
        min-width: 0;
        justify-content: center;
    }

    .ww-compass-col {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1px;
        flex-shrink: 0;
    }

    .ww-temp-row {
        display: flex;
        align-items: center;
        gap: 5px;
    }

    .ww-icon-temp { font-size: 1.35rem; color: #e04e2a; }
    .ww-temp-val  { font-size: 1.35rem; font-weight: 700; color: var(--pf-text); line-height: 1; }

    .ww-wind-row    { display: flex; align-items: center; gap: 5px; }
    .ww-icon-wind   { font-size: 1.1rem; color: var(--pf-brand); }
    .ww-wind-detail { display: flex; flex-direction: column; gap: 0; }
    .ww-wind-speed  { font-size: 0.85rem; font-weight: 600; color: var(--pf-text); line-height: 1.2; }
    .ww-gusts       { font-size: 0.65rem; color: var(--pf-text-subtle); }
    .ww-unit        { font-size: 0.65rem; color: var(--pf-text-subtle); font-weight: 400; }

    .ww-dir-labels { display: flex; flex-direction: column; align-items: center; gap: 0; }
    .ww-bearing    { font-size: 1.05rem; font-weight: 700; color: var(--pf-text); line-height: 1.1; }
    .ww-degrees    { font-size: 0.65rem; color: var(--pf-text-subtle); }

    .ww-footer {
        padding: 2px 8px 3px;
        font-size: 0.62rem;
        color: var(--pf-text-subtle);
        border-top: 1px solid var(--pf-border);
        display: flex;
        justify-content: space-between;
        align-items: center;
        flex-shrink: 0;
    }

    .ww-beaufort-row { display: flex; align-items: center; gap: 5px; flex-shrink: 0; }
    .ww-icon-bft     { font-size: 0.85rem; color: var(--pf-text-subtle); }
    .ww-beaufort     { font-size: 0.68rem; color: var(--pf-text-muted); font-style: italic; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

  /* ---- WeatherForecastPanel ---- */
    .wfp-wrapper {
        display: flex;
        flex-direction: column;
        height: 100%;
        overflow: hidden;
    }

    .wfp-toolbar {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 0 0 8px;
        flex-shrink: 0;
    }

    .wfp-content {
        flex: 1;
        display: flex;
        flex-direction: column;
        min-height: 0;
        gap: 10px;
        overflow: hidden;
    }

    .wfp-chart-wrapper {
        position: relative;
        flex-shrink: 0;
        height: clamp(180px, 28vh, 320px);
        background: var(--pf-surface-0);
        border: 1px solid var(--pf-border);
        border-radius: 6px;
        padding: 10px;
        overflow: hidden;
    }

    .wfp-table-wrapper {
        flex: 1;
        min-height: 120px;
        overflow-y: auto;
        border: 1px solid var(--pf-border);
        border-radius: 6px;
    }

        .wfp-table-wrapper thead th {
            position: sticky;
            top: 0;
            z-index: 1;
        }

    .wfp-dir-badge {
        font-weight: 600;
        color: var(--pf-text);
        min-width: 2.4em;
        display: inline-block;
    }

    @@keyframes wfp-rotate { to { transform: rotate(360deg); } }
    .wfp-spin { display: inline-block; animation: wfp-rotate .9s linear infinite; }

  /* ---- WeatherForecastPage ---- */
    /* ── Full-page flex shell ───────────────────────────────────────── */
    .pf-forecast-wrapper {
        display: flex;
        flex-direction: column;
        height: calc(100vh - 160px);
        min-height: 500px;
        padding: 0 16px 16px;
    }

    .pf-forecast-header {
        flex-shrink: 0;
        padding-top: 16px;
        padding-bottom: 4px;
    }

    .pf-forecast-content {
        flex: 1;
        display: flex;
        flex-direction: column;
        min-height: 0;
        gap: 12px;
    }

    /* ── Chart panel ────────────────────────────────────────────────── */
    .forecast-chart-wrapper {
        position: relative;
        flex: 1 1 auto;
        min-height: 0;
        width: 100%;
        background: var(--pf-surface-0);
        border: 1px solid var(--pf-border);
        border-radius: 6px;
        padding: 12px;
        overflow: hidden;
    }

    .pf-forecast-content--chart-only .forecast-chart-wrapper {
        height: 100%;
    }

    .pf-forecast-content--with-grid .forecast-chart-wrapper {
        flex: 1 1 60%;
        min-height: 320px;
    }

    /* ── Table panel – fills whatever space the chart leaves ────────── */
    .forecast-table-wrapper {
        flex: 0 0 38%;
        min-height: 220px;
        overflow-y: auto;
        border: 1px solid var(--pf-border);
        border-radius: 6px;
    }

    .forecast-table-wrapper table {
        margin-bottom: 0;
    }

    .forecast-table-wrapper thead th {
        position: sticky;
        top: 0;
        z-index: 1;
    }

    .wind-dir-badge {
        display: inline-block;
        font-weight: 600;
        color: var(--pf-text);
        min-width: 2.4em;
    }

    /* ── Responsive breakpoints ─────────────────────────────────────── */
    @media (max-width: 991.98px) {
        .pf-forecast-wrapper {
            height: calc(100vh - 140px);
        }

        .forecast-chart-wrapper {
            min-height: 260px;
        }

        .pf-forecast-content--with-grid .forecast-chart-wrapper {
            min-height: 280px;
        }
    }

    @media (max-width: 600px) {
        .pf-forecast-wrapper {
            height: auto;
            min-height: calc(100vh - 120px);
        }

        .forecast-chart-wrapper {
            min-height: 260px;
        }

        .forecast-table-wrapper {
            flex-basis: auto;
            min-height: 260px;
        }
    }

    @@keyframes pf-rotate { to { transform: rotate(360deg); } }
    .pf-spin { display: inline-block; animation: pf-rotate .9s linear infinite; }

  /* ---- AstronomicalSummaryBar ---- */
    .astro-summary-bar {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        align-items: center;
        margin-bottom: 10px;
        padding: 10px 12px;
        border: 1px solid var(--pf-border);
        border-radius: 6px;
        background: var(--pf-surface-2);
        color: var(--pf-text);
        font-size: 0.88rem;
        font-weight: 600;
        box-shadow: 0 2px 6px rgba(18, 48, 75, 0.12);
    }

    .astro-summary-item {
        display: inline-flex;
        align-items: center;
        padding: 3px 8px;
        border-radius: 999px;
        background: color-mix(in srgb, var(--pf-brand) 16%, transparent);
        line-height: 1.2;
        white-space: nowrap;
    }

    .astro-summary-item--status {
        background: color-mix(in srgb, var(--pf-brand) 28%, transparent);
    }

    .astro-summary-bar--error {
        border-color: #842029;
        background: #842029;
        color: #fff;
    }

    @media (max-width: 600px) {
        .astro-summary-bar {
            font-size: 0.8rem;
            padding: 8px 10px;
        }

        .astro-summary-item {
            white-space: normal;
        }
    }
}


/* ============================================================================
   PORT LANDING (Phase B)
   ----------------------------------------------------------------------------
   The page chrome from Ngqura/Landing's <style> block. What stayed behind in the
   page configures the retained SfDashboardLayout; this is the rest.

   The psc-status-dialog rules are all overflow containment for a status
   description that arrives as author-entered HTML through MarkupString -- tables,
   <pre>, images, anything -- so they guard the dialog rather than style it. They
   survive the move to PfDialog unchanged. The three psc-header-* rules did not:
   PfDialog's Tone carries the header colour now.
   ============================================================================ */

@layer pf-pages {

    .pf-port-landing {
        margin-top: 0;
        padding-top: var(--pf-space-1);
    }

    .pf-port-landing__head {
        margin-top: var(--pf-space-1);
        margin-bottom: var(--pf-space-1);
        padding-top: 0;
    }

    .pf-dash-clickable {
        cursor: pointer;
    }

    .pf-dash-clickable:hover {
        background-color: var(--pf-brand-subtle);
    }

    .psc-description {
        font-size: var(--pf-fs-md);
    }

    .psc-status-dialog__meta dt,
    .psc-status-dialog__meta dd {
        overflow-wrap: anywhere;
        word-break: break-word;
    }

    .psc-status-dialog__description {
        max-width: 100%;
        overflow-x: auto;
        overflow-y: auto;
        white-space: normal;
        word-break: break-word;
        overflow-wrap: anywhere;
    }

    .psc-status-dialog__description * {
        max-width: 100%;
        white-space: normal;
        word-break: break-word;
        overflow-wrap: anywhere;
    }

    .psc-status-dialog__description table,
    .psc-status-dialog__description pre {
        display: block;
        overflow-x: auto;
        white-space: pre-wrap;
    }

    .psc-status-dialog__description img,
    .psc-status-dialog__description iframe {
        max-width: 100%;
        height: auto;
    }
}


/* ============================================================================
   VISUAL BERTH PLANNER (Phase C7)
   ----------------------------------------------------------------------------
   The live remainder of VisualScheduleComponent's stylesheet, plus the SAVE and
   CLOSE buttons that BerthingSlotComponent held a byte-identical second copy of.
   Both page copies are gone; this is the only definition, which also gives
   VesselSelectOrCreateDialog the styling it was using without defining.

   Everything here was written in the old navy palette and is tokenised on the way
   in. The 3D affordance on the buttons is deliberate and preserved -- the offset
   shadow, the 2px travel on :active -- only its colours now follow the theme.

   `.visual-planner-child-dialog { z-index: 12000 }` below is now confirmed DEAD, not merely
   unverified. VesselSelectOrCreateDialog does default its CssClass parameter to this name, but
   never applies it anywhere -- PfDialog has no CssClass/class parameter for it to land on, so
   the value is computed and never used. Exercised live: with a slot open on the planner and a
   vessel lookup opened inside it, both dialogs render as `.pf-dialog pf-dialog--xl` and
   `.pf-dialog pf-dialog--md` -- neither carries this class -- and the inner one still stacks
   correctly above the outer one anyway, because PfDialog gives every dialog the SAME z-index
   (see --pf-z-dialog) and later DOM siblings paint over earlier ones at a tied z-index; the two
   are markup siblings, not nested, so this falls out of paint order for free. Left in rather
   than removed: no evidence it's load-bearing anywhere else, but no proof either, and deleting
   an unused rule on reasoning alone is how the last one of these went unnoticed for this long. */

@layer pf-pages {

    /* See the note above: unverified, and one declaration is cheaper than a
       nested dialog rendering behind its parent. */
    .visual-planner-child-dialog {
        z-index: 12000;
    }

    /* Slot dialog header. Sits inside PfDialog's own brand header, so it takes
       that header's foreground rather than setting a colour of its own. */
    .vsp-dialog-header__slot-ref {
        display: inline-flex;
        align-items: center;
        gap: var(--pf-space-2);
        flex-shrink: 0;
    }

    .vsp-dialog-header__sep {
        color: color-mix(in srgb, currentColor 45%, transparent);
        flex-shrink: 0;
    }

    .vsp-dialog-header__icon {
        font-size: var(--pf-fs-sm);
        vertical-align: middle;
        flex-shrink: 0;
    }

    .vsp-dialog-header__slot-no {
        font-weight: var(--pf-fw-bold);
        white-space: nowrap;
    }

    .vsp-dialog-header__title {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .vsp-dialog-header__badges {
        display: inline-flex;
        align-items: center;
        gap: var(--pf-space-2);
        margin-left: auto;
        flex-shrink: 0;
    }

    .vsp-schedule-host {
        min-height: 340px;
        /* The schedule stays mounted across reloads (remounting it loses Syncfusion's
           rendered appointments), so the loading spinner overlays it instead. */
        position: relative;
    }

    .vsp-loading-overlay {
        position: absolute;
        inset: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        background: color-mix(in srgb, var(--pf-panel-bg, #fff) 70%, transparent);
        z-index: 5;
        pointer-events: none;
    }

    .vsp-selected-slot-panel {
        font-size: var(--pf-fs-md);
    }

    .vsp-shell .vsp-selected-slot-panel {
        box-shadow: var(--pf-shadow);
        border-radius: var(--pf-radius-lg);
    }

    .visual-planner-slot-dialog__body .vsp-selected-slot-surface {
        margin-bottom: 0;
    }

    /* Deleted-state banner, shown in place of the slot after a delete. */
    .vsp-deleted-state {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: var(--pf-space-10) var(--pf-space-6);
        text-align: center;
        gap: var(--pf-space-4);
    }

    .vsp-deleted-state__icon {
        font-size: 3.2rem;
        color: var(--pf-success);
        line-height: 1;
        filter: drop-shadow(0 2px 6px color-mix(in srgb, var(--pf-success) 30%, transparent));
    }

    .vsp-deleted-state__message {
        font-size: var(--pf-fs-lg);
        font-weight: var(--pf-fw-semibold);
        color: var(--pf-text);
        letter-spacing: 0.01em;
    }

    .vsp-deleted-state__slot-no {
        font-weight: var(--pf-fw-bold);
        color: var(--pf-brand);
        font-size: var(--pf-fs-xl);
    }

    .vsp-deleted-state__close-btn {
        margin-top: var(--pf-space-2);
        background: var(--pf-brand);
        color: var(--pf-on-brand);
        border: none;
        padding: var(--pf-space-2) var(--pf-space-6);
        border-radius: var(--pf-radius);
        font-weight: var(--pf-fw-semibold);
        font-size: var(--pf-fs-md);
        box-shadow: var(--pf-shadow-sm);
        transition: background var(--pf-dur-fast) var(--pf-ease);
    }

    .vsp-deleted-state__close-btn:hover {
        background: var(--pf-brand-hover);
        color: var(--pf-on-brand);
    }

    /* Dialog body/footer containers. Renamed from pf-dialog-body / -footer, which
       sat one character away from PfDialog's own pf-dialog__body / __footer. */
    .vsp-dialog-body {
        background: var(--pf-surface-2);
        border: 1px solid var(--pf-border);
        border-radius: var(--pf-radius-lg);
        padding: var(--pf-space-3) var(--pf-space-4);
        margin-bottom: var(--pf-space-2);
    }

    .vsp-dialog-footer {
        display: flex;
        justify-content: flex-end;
        align-items: center;
        gap: var(--pf-space-2);
        padding-top: var(--pf-space-2);
    }

    .vsp-shell .slot-card-banner--shore-tension {
        border-radius: var(--pf-radius);
        border: 1px solid var(--pf-border);
        background: var(--pf-brand-subtle);
        padding: var(--pf-space-2) var(--pf-space-3);
    }

    .vsp-shell .slot-card-banner__icon {
        width: 1.9rem;
        height: 1.9rem;
        border-radius: var(--pf-radius-pill);
        display: inline-flex;
        align-items: center;
        justify-content: center;
        background: var(--pf-brand-subtle);
        color: var(--pf-brand);
    }

    .vsp-popup-footer {
        display: flex;
        justify-content: flex-end;
        align-items: center;
        padding: var(--pf-space-2) var(--pf-space-2) var(--pf-space-1);
        border-top: 1px solid var(--pf-border);
        background: var(--pf-surface-1);
    }

    /* SAVE / CLOSE, the 3D action buttons. */
    .bsl-action-btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: .28rem;
        height: 34px;
        padding: 0 1.15rem;
        border-radius: var(--pf-radius);
        font-size: var(--pf-fs-sm);
        font-weight: var(--pf-fw-bold);
        letter-spacing: .02em;
        cursor: pointer;
        border: none;
        box-shadow: 0 4px 0 rgba(0, 0, 0, .22), 0 2px 6px rgba(0, 0, 0, .15);
        transition: transform .08s, box-shadow .08s, opacity .12s;
    }

    .bsl-action-btn:active:not(:disabled) {
        transform: translateY(2px);
        box-shadow: 0 2px 0 rgba(0, 0, 0, .22);
    }

    .bsl-action-btn:disabled {
        opacity: .38;
        cursor: default;
    }

    .bsl-action-btn--save {
        background: var(--pf-success);
        color: var(--pf-on-success);
        text-shadow: 0 1px 2px rgba(0, 0, 0, .2);
        box-shadow:
            0 4px 0 color-mix(in srgb, var(--pf-success) 60%, black),
            0 2px 6px color-mix(in srgb, var(--pf-success) 35%, transparent);
    }

    .bsl-action-btn--save:hover:not(:disabled) {
        background: color-mix(in srgb, var(--pf-success) 85%, white);
        color: var(--pf-on-success);
    }

    .bsl-action-btn--close {
        background: var(--pf-surface-3);
        color: var(--pf-text);
        text-shadow: none;
        box-shadow:
            0 4px 0 var(--pf-border-strong),
            0 2px 6px rgba(0, 0, 0, .18);
    }

    .bsl-action-btn--close:hover:not(:disabled) {
        background: var(--pf-surface-2);
        color: var(--pf-text);
    }

    /* SlotBollardDialog (Visual Berth Planner) */
    /* ── Assign Bollards dialog ──────────────────────────────────────────────
       Four numbered sections, each on its own tint, so it is obvious at a glance
       which fields the planner supplies and which the calculation fills in. */
    .sbd-vessel {
        padding: 0 0 var(--pf-space-2);
        border-bottom: 1px solid var(--pf-border);
        margin-bottom: var(--pf-space-3, 0.75rem);
    }

    .sbd-vessel__name {
        font-size: 1.05rem;
        font-weight: var(--pf-fw-bold);
        color: var(--pf-text);
        letter-spacing: .01em;
    }

    .sbd-vessel__meta {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        gap: .35rem;
        font-size: var(--pf-fs-sm);
        color: var(--pf-text-muted);
        margin-top: .15rem;
    }

    .sbd-dot { opacity: .5; }

    .sbd-tag {
        padding: .05rem .45rem;
        border-radius: 50px;
        font-size: .68rem;
        font-weight: var(--pf-fw-bold);
        letter-spacing: .04em;
    }

    .sbd-tag--alongside {
        background: #d1fae5;
        color: #065f46;
        border: 1px solid #6ee7b7;
    }

    /* Sections, labels and read-only boxes are the shared .pf-dlg-* set now
       (see DIALOGS above) — the bollard dialog was where they were designed,
       but the berthing-slot dialog needs the same treatment. */

    .sbd-help {
        font-size: .7rem;
        color: var(--pf-text-muted);
        margin-top: .12rem;
    }

    .sbd-help--warn { color: var(--pf-accent); font-weight: var(--pf-fw-bold); }

    .sbd-calc-btn {
        width: 100%;
        height: 32px;
        border: none;
        border-radius: 5px;
        background: linear-gradient(180deg, #f59e0b 0%, #d97706 55%, #b45309 100%);
        color: #fff;
        font-weight: var(--pf-fw-bold);
        font-size: var(--pf-fs-sm);
        box-shadow: 0 3px 0 #78350f;
    }

    .sbd-calc-btn:hover:not(:disabled) {
        background: linear-gradient(180deg, #fbbf24 0%, #e88c07 55%, #c46009 100%);
    }

    .sbd-calc-btn:active:not(:disabled) {
        transform: translateY(2px);
        box-shadow: 0 1px 0 #78350f;
    }

    .sbd-calc-btn:disabled { opacity: .45; }

    .sbd-mode {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        gap: .5rem;
        margin-bottom: .5rem;
    }

    .sbd-mode__hint {
        font-size: .72rem;
        color: var(--pf-text-muted);
    }

    .sbd-nofit { border-left: 4px solid var(--pf-danger); }

    /* ── Planning Workbench: schedule above, movement strip below ───────── */
    .pw-breadcrumb-row { margin-bottom: var(--pf-space-2); }

    .pw-toolbar {
        display: flex;
        align-items: center;
        justify-content: space-between;
        flex-wrap: wrap;
        gap: var(--pf-space-2);
        margin-bottom: var(--pf-space-2);
    }

    .pw-toolbar__left,
    .pw-toolbar__right {
        display: flex;
        align-items: center;
        gap: var(--pf-space-2);
    }

    .pw-port-label {
        font-size: var(--pf-fs-sm);
        font-weight: var(--pf-fw-bold);
        color: var(--pf-text-muted);
    }

    .pw-port-name {
        font-weight: var(--pf-fw-bold);
        color: var(--pf-text);
    }

    .pw-pane { margin-bottom: var(--pf-space-2); }

    /* ── Workbench dashboard panels ──────────────────────────────────────────
       Not scoped CSS: these style the inside of Syncfusion's own panel chrome,
       which this page does not author, so a scope attribute would never match. */
    .pwb-panel__header {
        display: flex;
        align-items: center;
        gap: .4rem;
        width: 100%;
        padding: .5rem .7rem;
        font-family: var(--pf-font-head);
        font-size: .78rem;
        font-weight: var(--pf-fw-bold);
        letter-spacing: .04em;
        text-transform: uppercase;
        color: var(--pf-panel-head-fg);
        background: var(--pf-panel-head-bg);
        border-bottom: 1px solid var(--pf-border);
    }

    .pwb-panel__title {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* The one surface a panel can be dragged by. Everything else inside a panel — a berthing slot
       tile, a grid row, a bollard marker — has its own drag of its own to do. */
    .pwb-panel__grip {
        display: inline-flex;
        align-items: center;
        padding: 0 .15rem;
        cursor: move;
        color: var(--pf-text-subtle);
    }

    .pwb-panel__grip:hover { color: var(--pf-text); }

    .pwb-panel__action {
        border: none;
        background: none;
        padding: .1rem .25rem;
        line-height: 1;
        color: var(--pf-text-subtle);
        cursor: pointer;
        border-radius: var(--pf-radius-sm, 4px);
    }

    .pwb-panel__action:hover {
        color: var(--pf-danger, #b42318);
        background: var(--pf-surface-2);
    }

    .pwb-panel__body {
        height: calc(100% - 38px);
        overflow: auto;
        padding: .5rem .6rem;
        --vbp-body-max: none;
    }

    .pwb-empty {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: .25rem;
        padding: 3rem 1rem;
        color: var(--pf-text-muted);
        border: 1px dashed var(--pf-border);
        border-radius: var(--pf-radius-md, 8px);
        background: var(--pf-surface-2);
    }

    .pwb-empty__icon { font-size: 1.8rem; opacity: .6; }

    .pwb-picker__row { padding: .25rem 0; }

    /* Editing the layout everybody else inherits must not look like editing your own. */
    .pwb-default-banner {
        display: flex;
        align-items: center;
        gap: .5rem;
        padding: .55rem .8rem;
        margin-bottom: var(--pf-space-2);
        border: 1px solid #d79b2b;
        border-left: 5px solid #d79b2b;
        border-radius: var(--pf-radius-md, 8px);
        background: #fff6e5;
        color: #5c3c00;
        font-size: var(--pf-fs-sm);
    }

    .pwb-dash--default-mode .pwb-panel__header {
        background: #fff1d6;
        color: #5c3c00;
        border-bottom-color: #d79b2b;
    }

    .pw-strip-toggle {
        display: flex;
        align-items: center;
        width: 100%;
        gap: .25rem;
        padding: .45rem .7rem;
        border: 1px solid var(--pf-border);
        border-radius: var(--pf-radius-md, 8px);
        background: var(--pf-surface-2);
        color: var(--pf-text);
        cursor: pointer;
    }

    .pw-strip-toggle:hover { background: var(--pf-surface-0); }

    .pw-strip-toggle__title {
        font-weight: var(--pf-fw-bold);
        font-size: var(--pf-fs-sm);
        text-transform: uppercase;
        letter-spacing: .03em;
    }

    .pw-strip-toggle__hint {
        margin-left: auto;
        font-size: .72rem;
        color: var(--pf-text-muted);
    }

    .pw-strip-body { padding-top: var(--pf-space-2); }

    /* The planner renders without its own page shell when embedded here. */
    .slp-embedded { padding: 0; }

    /* Approvals bell — same footprint as the neighbouring Refresh button. */
    .pw-notif-btn {
        position: relative;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        background: var(--pf-surface-0);
        color: var(--pf-brand);
        border: 1.5px solid var(--pf-border);
        border-radius: 7px;
        font-size: 0.82rem;
        padding: 0.36rem 0.85rem;
        transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
    }

    .pw-notif-btn:hover {
        background: color-mix(in srgb, var(--pf-brand) 10%, var(--pf-surface-0));
        border-color: var(--pf-brand-hover);
    }

    /* Lit up while something is waiting — same accent the banner below uses. */
    .pw-notif-btn--active {
        border-color: var(--pf-accent);
        color: var(--pf-accent);
    }

    .pw-notif-badge {
        position: absolute;
        top: -6px;
        right: -6px;
        min-width: 1.1rem;
        height: 1.1rem;
        padding: 0 .25rem;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        background: var(--pf-danger);
        color: var(--pf-on-danger);
        border-radius: 999px;
        font-size: .65rem;
        font-weight: var(--pf-fw-bold);
        line-height: 1;
    }

    /* Adaptive banner — takes up space only while approvals are actually pending. */
    .pw-notif-banner {
        display: flex;
        align-items: center;
        width: 100%;
        gap: var(--pf-space-2);
        padding: .5rem .9rem;
        margin-bottom: var(--pf-space-2);
        border: 1px solid var(--pf-border);
        border-left: 4px solid var(--pf-accent);
        border-radius: var(--pf-radius-md, 8px);
        background: color-mix(in srgb, var(--pf-accent) 12%, var(--pf-surface-2));
        color: var(--pf-text);
        font-size: var(--pf-fs-sm);
        font-weight: var(--pf-fw-bold);
        cursor: pointer;
        text-align: left;
    }

    .pw-notif-banner:hover {
        background: color-mix(in srgb, var(--pf-accent) 20%, var(--pf-surface-2));
    }

    /* Approvals overlay. PfDialog only renders ChildContent while Visible — that would tear
       PlannerNotificationsPanel's poll timer and event subscriptions down on every close and
       lose the live badge count, so this host renders its own backdrop + card and is toggled
       with [hidden] instead of being unmounted. */
    .pw-notif-host {
        position: fixed;
        inset: 0;
        z-index: 1050;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    .pw-notif-host__backdrop {
        position: absolute;
        inset: 0;
        background: rgba(0, 0, 0, 0.45);
    }

    .pw-notif-host__panel {
        position: relative;
        width: min(480px, 92vw);
        max-height: 85vh;
        display: flex;
        flex-direction: column;
        background: var(--pf-surface-0);
        border: 1px solid var(--pf-border);
        border-radius: var(--pf-radius-md, 8px);
        box-shadow: 0 12px 32px rgba(0, 0, 0, 0.28);
        overflow: hidden;
    }

    .pw-notif-host__header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: .6rem .9rem;
        border-bottom: 1px solid var(--pf-border);
        background: var(--pf-surface-2);
    }

    .pw-notif-host__title {
        font-weight: var(--pf-fw-bold);
        color: var(--pf-text);
    }

    .pw-notif-host__close {
        background: none;
        border: none;
        color: var(--pf-text-muted);
        padding: .2rem .4rem;
        cursor: pointer;
    }

    .pw-notif-host__close:hover { color: var(--pf-text); }

    .pw-notif-host__body {
        overflow-y: auto;
    }
}


/* ============================================================================
   BERTH PLANNING DASHBOARD (Phase C7)
   ----------------------------------------------------------------------------
   The live remainder of SlotList's stylesheet. Its other ~250 lines were
   Syncfusion Card demo boilerplate and .e-dialog overrides for an SfDialog that
   no longer exists; #berthPlanningDashboard stayed in the page because it sizes
   the retained SfDashboardLayout.

   The legend was written in the old navy (#12304b ink, #5b7083 meta,
   rgba(18,48,75,...) rules) and is tokenised here. Note SlotList.razor.css also
   carries scoped `.slot-summary-card .to-chart-card__*` overrides — those are a
   different, narrower selector and are left alone.
   ============================================================================ */

@layer pf-pages {

    .slot-list-panel-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--pf-space-3);
        flex-wrap: wrap;
    }

    .slot-list-panel-header__actions {
        display: flex;
        align-items: center;
        gap: var(--pf-space-2);
        flex-wrap: wrap;
    }

    .bpd-panel-body {
        height: 100%;
        overflow: auto;
        padding: var(--pf-space-2);
    }

    .bpd-panel-body--slots {
        padding: 0;
    }

    .bp-slot-list {
        height: 100%;
        overflow-y: auto;
        padding: var(--pf-space-4);
    }

    .bpd-chart-panel {
        height: 100%;
        padding: .2rem;
    }

    .bpd-chart-panel--legend {
        overflow: auto;
        padding-right: .1rem;
    }

    .to-chart-card {
        height: 100%;
        padding: .1rem;
        background: transparent;
    }

    .to-chart-card__legend {
        display: flex;
        flex-direction: column;
        gap: .55rem;
        max-height: 100%;
        overflow: auto;
        padding-right: .15rem;
    }

    .to-chart-card__legend-group {
        display: flex;
        flex-direction: column;
        gap: var(--pf-space-1);
    }

    .to-chart-card__summary {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        gap: var(--pf-space-2);
        align-items: center;
        padding: .35rem 0 .55rem;
        margin-bottom: .15rem;
        border-bottom: 1px solid var(--pf-border-strong);
    }

    .to-chart-card__summary-label {
        font-weight: var(--pf-fw-bold);
        color: var(--pf-text);
        text-transform: uppercase;
        font-size: var(--pf-fs-sm);
        line-height: var(--pf-lh-tight);
    }

    .to-chart-card__summary-count {
        font-weight: var(--pf-fw-bold);
        color: var(--pf-text);
        white-space: nowrap;
        font-size: var(--pf-fs-md);
    }

    .to-chart-card__legend-heading {
        font-weight: var(--pf-fw-bold);
        color: var(--pf-text);
        padding-bottom: .15rem;
        border-bottom: 1px solid var(--pf-border);
        line-height: var(--pf-lh-tight);
    }

    .to-chart-card__legend-heading-meta {
        font-weight: var(--pf-fw-medium);
        color: var(--pf-text-subtle);
        margin-left: var(--pf-space-1);
        font-size: var(--pf-fs-xs);
    }

    .to-chart-card__legend-row {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        gap: .35rem;
        align-items: center;
        font-size: var(--pf-fs-sm);
        color: var(--pf-text);
        line-height: 1.1;
    }

    .to-chart-card__legend-row--nested {
        padding-left: .35rem;
    }

    .to-chart-card__operator {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .to-chart-card__operator--indented::before {
        content: "↳";
        color: var(--pf-text-subtle);
        margin-right: .35rem;
    }

    .to-chart-card__count {
        font-weight: var(--pf-fw-bold);
        color: var(--pf-text);
        white-space: nowrap;
    }

    @media (max-width: 991.98px) {
        .slot-list-panel-header,
        .slot-list-panel-header__actions {
            width: 100%;
        }

        .slot-list-panel-header__actions .btn {
            flex: 1 1 auto;
        }
    }
}


/* ============================================================================
   PAGE GROUND
   ----------------------------------------------------------------------------
   <html> owns the page surface. Its background propagates to the canvas, so this
   is what fills the viewport behind everything.

   Deliberately NOT also declared on <body>: body's computed background and color
   freeze at their load-time values once the theme class is toggled at runtime
   (its var() substitutions stop being re-resolved, while <html> re-resolves them
   correctly). Painting the ground on <html> sidesteps it. Nothing is lost —
   .pf-layout covers body completely, so body's own background is never visible.
   Re-test this in B1 when site.css's transition/will-change rules on body are
   folded in; they are the most likely cause.

   Unlayered on purpose: it has to outrank Radzen's base sheet and site.css, both
   unlayered, and a layered rule always loses to an unlayered one. Once site.css
   is folded in, this moves into @layer pf-base.
   ============================================================================ */

html {
  background-color: var(--pf-surface-1);
  color: var(--pf-text);
}


/* ── Scheduler chrome ──────────────────────────────────────────────
   The date bar was a filled brand slab with a 2px brand-hover rule under
   it: the loudest band in the app, sitting directly above the quietest
   content in the app. It takes the same tinted treatment as every other
   panel header now, so the schedule reads as data with a label on it
   rather than a headline with a table underneath. */
.e-schedule .e-schedule-toolbar-container,
.e-schedule .e-schedule-toolbar-container .e-toolbar,
.e-schedule .e-schedule-toolbar,
.e-schedule .e-schedule-toolbar.e-toolbar,
.e-schedule .e-schedule-toolbar .e-toolbar-items,
.e-schedule .e-schedule-toolbar-container .e-toolbar-items {
    background: var(--pf-panel-head-bg) !important;
    background-color: var(--pf-panel-head-bg) !important;
    color: var(--pf-panel-head-fg) !important;
}

.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar .e-toolbar-item .e-tbar-btn .e-icons,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn .e-tbar-btn-text,
.e-schedule .e-schedule-toolbar-container .e-toolbar-item .e-tbar-btn .e-icons {
    background: transparent !important;
    background-color: transparent !important;
    color: var(--pf-panel-head-fg) !important;
    border-color: transparent !important;
}

/* The date row above the grid: quiet, but with ink that is actually read. */
.e-schedule .e-date-header-wrap table td,
.e-schedule .e-date-header-wrap .e-header-cells,
.e-schedule .e-header-row .e-header-cells {
    background: var(--pf-surface-2) !important;
    color: var(--pf-text) !important;
    border-color: var(--pf-border) !important;
    font-weight: 600 !important;
}

/* The berth column has to read as a column, not as the first cell of each
   row. It carries the labels the whole grid is indexed by, and at the same
   surface as the rows it disappeared into them. */
.e-schedule .e-resource-cells,
.e-schedule .e-resource-column-wrap .e-resource-cells,
.e-schedule .e-resource-left-td {
    background: var(--pf-surface-2) !important;
    color: var(--pf-text) !important;
    border-inline-end: 2px solid var(--pf-border-strong) !important;
}

.e-schedule .e-resource-cells .e-resource-text,
.e-schedule .e-resource-cells .e-text-ellipsis,
.e-schedule .e-resource-cells div {
    color: var(--pf-text) !important;
    font-weight: 650 !important;
}

/* Scoped <style> blocks inside the schedule components still carry the old navy
   literal at (0,4,0), and they render after this file, so an equal-specificity
   rule here loses on source order. The leading `body` takes this to (0,4,1) and
   makes the token authoritative for the berth labels wherever they are drawn. */
body .e-schedule .e-timeline-view .e-resource-left-td .e-resource-text,
body .e-schedule .e-timeline-view .e-resource-column-wrap .e-resource-text,
body .e-schedule .e-timeline-month-view .e-resource-left-td .e-resource-text {
    color: var(--pf-text) !important;
}


/* ============================================================================
   PLANNER NOTIFICATIONS / APPROVALS
   ----------------------------------------------------------------------------
   Global, not scoped to a page: PlannerNotificationsPanel is rendered by BOTH
   the Visual Berth Planner (as a panel) and the Planning Workbench (in its
   approvals dialog). A scoped sheet - even with ::deep - only matches inside
   the tree of the page that owns it, which would leave the Workbench copy
   completely unstyled.
   ========================================================================== */
.vbp-panel__header--notifications { --pf-fam: var(--pf-fam-warning); }

.vbp-panel__body--notifications {
    flex: 1;
    overflow-y: auto;
    padding: .65rem;
    /* A faint wash of the panel's own family rather than a fixed cream,
       so it stays a tint of the header in dark mode instead of a
       near-white block. */
    background: color-mix(in srgb, var(--pf-fam) 6%, var(--pf-panel-bg));
}

.vbp-notif-refresh {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    color: #ffffff;
    background: rgba(255,255,255,0.18);
    box-shadow: 0 2px 0 rgba(0,0,0,0.18);
    transition: background .12s, transform .07s;
}

.vbp-notif-refresh:hover:not(:disabled) {
    background: rgba(255,255,255,0.28);
}

.vbp-notif-refresh:active:not(:disabled) {
    transform: translateY(1px);
    box-shadow: 0 1px 0 rgba(0,0,0,0.18);
}

.vbp-notif-refresh:disabled {
    opacity: .55;
    cursor: default;
}

.vbp-notif-spin {
    animation: vbp-notif-spin 1s linear infinite;
}

@keyframes vbp-notif-spin {
    from { transform: rotate(0); }
    to { transform: rotate(360deg); }
}

.vbp-notif-list {
    display: flex;
    flex-direction: column;
    gap: .5rem;
}

.vbp-notif-card {
    background: #fff;
    border: 1px solid #e8d3a8;
    border-left: 3px solid #d97706;
    border-radius: 6px;
    padding: .55rem .65rem;
    box-shadow: 0 1px 3px rgba(120,53,15,0.08);
    transition: box-shadow .12s;
}

.vbp-notif-card:hover {
    box-shadow: 0 3px 8px rgba(120,53,15,0.14);
}

.vbp-notif-card--nomination {
    border-left-color: #2c4d65;
}

.vbp-notif-card--arrivalcapture {
    border-left-color: #16a34a;
}

.vbp-notif-card--arrivalcapture .vbp-notif-card__kind {
    color: #15803d;
}

.vbp-notif-card--etdupdate {
    border-left-color: #7c3aed;
}

.vbp-notif-card--etdupdate .vbp-notif-card__kind {
    color: #6d28d9;
}

.vbp-notif-card--pendingnomination {
    border-left-color: #0e7490;
}

.vbp-notif-card--pendingnomination .vbp-notif-card__kind {
    color: #0e7490;
}

.vbp-notif-card--operatorschedulechange {
    border-left-color: #b45309;
}

.vbp-notif-card--operatorschedulechange .vbp-notif-card__kind {
    color: #92400e;
}

.vbp-notif-card__head {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin-bottom: .35rem;
}

.vbp-notif-card__kind {
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: #92400e;
    flex: 1;
    min-width: 0;
}

.vbp-notif-card--nomination .vbp-notif-card__kind {
    color: #12304b;
}

.vbp-notif-card__slot {
    font-size: .72rem;
    font-weight: 700;
    color: #ffffff;
    background: #12304b;
    padding: .12rem .5rem;
    border-radius: 50px;
    white-space: nowrap;
}

.vbp-notif-card__body {
    display: flex;
    flex-direction: column;
    gap: .22rem;
    font-size: .76rem;
    color: #1f2933;
}

.vbp-notif-card__vessel {
    font-weight: 600;
    color: var(--pf-text);
}

.vbp-notif-card__berth {
    color: #6b7280;
    font-weight: 500;
    font-size: .72rem;
}

.vbp-notif-card__values {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    font-size: .73rem;
    color: #374151;
}

.vbp-notif-card__from {
    color: #6b7280;
}

.vbp-notif-card__to {
    color: #12304b;
    font-weight: 600;
}

.vbp-notif-card__reason {
    font-size: .72rem;
    color: #4b5563;
    font-style: italic;
    border-left: 2px solid #e5e7eb;
    padding-left: .4rem;
}

.vbp-notif-card__message {
    font-size: .74rem;
    color: #374151;
    line-height: 1.35;
    border-left: 2px solid #fcd34d;
    padding-left: .4rem;
}

.vbp-notif-card__stages {
    display: flex;
    gap: .3rem;
    flex-wrap: wrap;
}

.vbp-notif-stage {
    font-size: .65rem;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    padding: .08rem .45rem;
    border-radius: 50px;
    border: 1px solid transparent;
}

.vbp-notif-stage--op {
    background: #fef3c7;
    color: #92400e;
    border-color: #f0c97a;
}

.vbp-notif-stage--vts {
    background: #dbeafe;
    color: #1e3a8a;
    border-color: #93c5fd;
}

.vbp-notif-stage--done {
    background: #dcfce7;
    color: #166534;
    border-color: #86efac;
}

.vbp-notif-card__meta {
    display: flex;
    align-items: center;
    font-size: .68rem;
    color: #6b7280;
    margin-top: .15rem;
}

.vbp-notif-card__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .35rem .6rem;
    margin-top: .5rem;
    padding-top: .4rem;
    border-top: 1px dashed #e5e7eb;
}

.vbp-notif-stagegrp {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
}

.vbp-notif-stagegrp__label {
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: #6b7280;
}

.vbp-notif-card__hint {
    font-size: .7rem;
}

.vbp-notif-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 26px;
    padding: 0 .7rem;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    color: #fff;
    text-shadow: 0 1px 2px rgba(0,0,0,.2);
    transition: transform .07s, box-shadow .07s;
}

.vbp-notif-btn:active:not(:disabled) {
    transform: translateY(1px);
}

.vbp-notif-btn:disabled {
    opacity: .55;
    cursor: not-allowed;
}

.vbp-notif-btn--sm {
    height: 22px;
    padding: 0 .5rem;
    font-size: .62rem;
    gap: .25rem;
}

.vbp-notif-btn--approve {
    background: linear-gradient(180deg, #22c55e 0%, #16a34a 55%, #15803d 100%);
    box-shadow: 0 3px 0 #166534, 0 1px 3px rgba(22,163,74,.3);
}

.vbp-notif-btn--approve:hover:not(:disabled) {
    background: linear-gradient(180deg, #34d399 0%, #22c55e 55%, #16a34a 100%);
    color: #fff;
}

.vbp-notif-btn--approve:active:not(:disabled) {
    box-shadow: 0 1px 0 #166534;
}

.vbp-notif-btn--reject {
    background: linear-gradient(180deg, #ef4444 0%, #dc2626 55%, #b91c1c 100%);
    box-shadow: 0 3px 0 #7f1d1d, 0 1px 3px rgba(220,38,38,.3);
}

.vbp-notif-btn--reject:hover:not(:disabled) {
    background: linear-gradient(180deg, #f87171 0%, #ef4444 55%, #dc2626 100%);
    color: #fff;
}

.vbp-notif-btn--reject:active:not(:disabled) {
    box-shadow: 0 1px 0 #7f1d1d;
}

/* ============================================================================
   JOB CARDS — Terminal Operators
   Structural only. Every colour resolves from an existing token: no new palette,
   and the KPI band tokens are used only where a value carries KPI meaning.
   ============================================================================ */
@layer pf-pages {

    .pf-jobcard-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
        gap: 14px;
    }

    .pf-jobcard {
        display: flex;
        flex-direction: column;
    }

    .pf-jobcard__status {
        font-size: .72rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: .6px;
        opacity: .85;
    }

    .pf-jobcard__meta {
        display: flex;
        flex-wrap: wrap;
        gap: 4px 12px;
        font-size: .78rem;
        color: var(--pf-text-subtle);
        margin-bottom: 10px;
    }

    .pf-jobcard__counts {
        display: flex;
        flex-wrap: wrap;
        gap: 6px 16px;
        font-size: .8rem;
        color: var(--pf-text-muted);
        margin-bottom: 10px;
    }

    .pf-jobcard__progress { margin-bottom: 8px; }

    /* Shared by the board card, the detail panels and the wizard's allocation check. */
    .pf-jobcard__bar {
        height: 8px;
        border-radius: 4px;
        background: var(--pf-surface-3);
        overflow: hidden;
        margin: 4px 0;
    }

    .pf-jobcard__bar > i {
        display: block;
        height: 100%;
        background: var(--pf-chart-1);
    }

    .pf-jobcard__flag {
        font-size: .78rem;
        border-radius: 6px;
        padding: 5px 9px;
        margin-top: 6px;
    }

    .pf-jobcard__flag.warn {
        background: var(--pf-band-orange-bg);
        color: var(--pf-band-orange);
    }

    .pf-jobcard__flag.over {
        background: var(--pf-band-red-bg);
        color: var(--pf-band-red);
    }

    .pf-jobcard__flag.live {
        background: var(--pf-band-darkgreen-bg);
        color: var(--pf-band-darkgreen);
    }

    .pf-jobcard__actions {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 8px;
        padding: 9px 12px;
        border-top: 1px solid var(--pf-border);
    }

    /* ── Wizard ──────────────────────────────────────────────────────────── */

    .pf-wizard-context,
    .pf-wizard-review {
        display: flex;
        flex-wrap: wrap;
        gap: 8px 26px;
        padding: 10px 12px;
        border: 1px solid var(--pf-border);
        border-radius: 8px;
        background: var(--pf-card-bg);
        font-size: .85rem;
    }

    .pf-wizard-context .lbl,
    .pf-wizard-review .lbl {
        display: block;
        font-size: .7rem;
        text-transform: uppercase;
        letter-spacing: .5px;
        color: var(--pf-text-subtle);
    }

    /* The card sits on the TINTED surface and its controls on the plain one, never the other way
       round. Both were --pf-panel-bg (#ffffff in the light theme) and so were Radzen's inputs, which
       left a white field on a white card with nothing but a hairline between them — the dropdowns
       were genuinely hard to pick out from the card they sat on. The tokens invert together, so the
       same relationship holds in the dark theme. */
    .pf-wizard-line {
        border: 1px solid var(--pf-border);
        border-radius: 8px;
        padding: 12px;
        margin-bottom: 10px;
        background: var(--pf-card-bg);
    }

    /* The rules that give those controls their own background and border are NOT here. They fight
       Radzen for the same properties, so they must be unlayered — see RADZEN OVERRIDES at the end
       of this file. */

    .jc-slot-filter {
        display: flex;
        align-items: center;
        gap: 8px;
        font-size: .82rem;
        color: var(--pf-text-muted);
    }

    .pf-wizard-help {
        font-size: .8rem;
        color: var(--pf-text-muted);
        margin: 0 0 10px;
    }

    .pf-wizard-help--warn {
        color: var(--pf-band-orange);
        margin-top: 6px;
    }

    /* The sub-product picker and its "New" button share one cell. The row above them top-aligns,
       but inside this cell the button has to line up with the INPUT, not with the floating label
       that sits above it -- so the cell aligns to its own baseline instead of the row's. */
    .jc-subrow {
        display: flex;
        align-items: flex-start;
        gap: 8px;
    }

    .jc-subrow > .rz-form-field {
        flex: 1 1 auto;
        min-width: 0;
    }

    .jc-addsub {
        flex: 0 0 auto;
        white-space: nowrap;
    }

    /* See RADZEN OVERRIDES at the end of this file for the offset that lines this button up with
       the input rather than with the floating label above it. */

    /* The delete button ends a line whose other cells are labelled fields. Pushing it down by the
       label's height puts it on the controls' line rather than floating above them. */
    .jc-line-remove {
        display: flex;
        justify-content: flex-end;
        align-items: flex-start;
        padding-top: 4px;
    }

    /* A titled block of repeated lines -- hatches, gangs. Gives the heading something to belong to
       so it cannot be mistaken for a label on the first row beneath it. */
    .pf-wizard-group__title {
        font-weight: 600;
        font-size: .9rem;
        margin-bottom: 4px;
        color: var(--pf-text);
    }

    .jc-subproduct .pf-wizard-help {
        margin-bottom: 0;
    }

    /* Read aloud across a desk and copied onto paper, so it is deliberately large and monospaced —
       a 6 and an 8 have to be unmistakable at a glance. */
    .ops-pin-issue__code {
        font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
        font-size: 2.4rem;
        font-weight: 700;
        letter-spacing: .35em;
        text-align: center;
        padding: 14px 10px;
        border: 1px dashed var(--pf-border);
        border-radius: 8px;
        background: var(--pf-card-bg);
        color: var(--pf-text);
    }

    .pf-chip--ok {
        background: var(--pf-band-green, #1f7a4d);
        color: #fff;
    }

    .pf-chip--warn {
        background: var(--pf-band-orange);
        color: #fff;
    }

    .pf-wizard-alloc {
        border: 1px solid var(--pf-border);
        border-radius: 8px;
        padding: 10px 12px;
        background: var(--pf-card-bg);
    }

    .pf-wizard-implied {
        font-size: .8rem;
        color: var(--pf-text-muted);
        padding-bottom: 6px;
    }

    /* ── Detail board ────────────────────────────────────────────────────── */

    .pf-commodity-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
        gap: 12px;
    }

    .pf-commodity-card {
        border: 1px solid var(--pf-border);
        border-radius: 8px;
        padding: 11px 12px;
        background: var(--pf-card-bg);
    }

    .pf-commodity-card__head {
        display: flex;
        justify-content: space-between;
        align-items: baseline;
        gap: 8px;
    }

    .pf-commodity-card__dir {
        font-size: .68rem;
        font-weight: 700;
        letter-spacing: .6px;
        color: var(--pf-text-subtle);
    }

    .pf-commodity-card__grade {
        font-size: .78rem;
        color: var(--pf-text-subtle);
        margin-top: 2px;
    }

    .pf-commodity-card__figure {
        font-size: 1.35rem;
        font-weight: 700;
        letter-spacing: -.4px;
        margin: 6px 0 4px;
    }

    .pf-commodity-card__figure span {
        font-size: .8rem;
        font-weight: 400;
        color: var(--pf-text-subtle);
    }

    .pf-commodity-card__meta {
        display: flex;
        flex-wrap: wrap;
        gap: 3px 10px;
        font-size: .74rem;
        color: var(--pf-text-muted);
    }

    .pf-gang-chip {
        display: inline-block;
        min-width: 26px;
        text-align: center;
        border-radius: 999px;
        padding: 1px 8px;
        font-size: .74rem;
        font-weight: 700;
        background: var(--pf-surface-3);
        color: var(--pf-text);
    }

    .pf-plain-list {
        list-style: none;
        margin: 0;
        padding: 0;
    }

    .pf-plain-list li {
        display: flex;
        align-items: center;
        gap: 9px;
        padding: 6px 0;
        border-bottom: 1px solid var(--pf-border-subtle);
        font-size: .85rem;
    }

    .pf-plain-list li:last-child { border-bottom: 0; }

    /* Row actions sit hard right so the reading column stays the name, not a ragged button edge. */
    .pf-plain-list__actions {
        margin-left: auto;
        display: flex;
        gap: 2px;
        white-space: nowrap;
    }

    /* Edit and remove on a cargo card. Held at low opacity until the card is hovered: five cards
       side by side with two solid buttons each reads as a toolbar rather than as cargo. */
    .pf-commodity-card {
        position: relative;
    }

    .pf-commodity-card__actions {
        position: absolute;
        top: 4px;
        right: 4px;
        display: flex;
        gap: 0;
        opacity: 0;
        transition: opacity .12s ease-in-out;
    }

    .pf-commodity-card:hover .pf-commodity-card__actions,
    .pf-commodity-card:focus-within .pf-commodity-card__actions {
        opacity: 1;
    }

    /* Keyboard and touch never produce hover, so the buttons have to be there without it. */
    @media (hover: none) {
        .pf-commodity-card__actions { opacity: 1; }
    }

    /* Free text the planner left on the card. Reads as a note, not as another figure. */
    .pf-jobcard__notes {
        font-size: .84rem;
        color: var(--pf-text-muted);
        white-space: pre-wrap;
        border-left: 3px solid var(--pf-border);
        padding-left: 10px;
    }

    /* Every Radzen dialog body in the job card module. Gives the fields the same breathing room
       the wizard lines have without each dialog inventing its own spacing. */
    .pf-dialog-form {
        font-size: .88rem;
    }

    .pf-dialog-form hr {
        border-color: var(--pf-border);
        opacity: 1;
    }

    .pf-yes { color: var(--pf-band-green); }
    .pf-no  { color: var(--pf-band-orange); font-size: .78rem; }

    /* ── Last-updated stamp ──────────────────────────────────────────────── */

    .pf-last-updated {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        font-size: .78rem;
        color: var(--pf-text-subtle);
        white-space: nowrap;
    }

    .pf-last-updated__live {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        border-radius: 999px;
        padding: 1px 8px;
        font-weight: 600;
        background: var(--pf-band-darkgreen-bg);
        color: var(--pf-band-darkgreen);
    }

    /* AnchorageRegister and OperationsCapture carry a fixed navy card header with white ink.
       The subtle grey vanishes there, so the stamp inherits the header's own colour instead of
       the page's — cheaper and less invasive than repainting two headers to suit a stamp. */
    .pf-last-updated--ondark {
        color: rgba(255, 255, 255, .82);
    }

    .pf-last-updated--ondark .pf-last-updated__btn {
        border-color: rgba(255, 255, 255, .45);
        color: rgba(255, 255, 255, .9);
    }

    .pf-last-updated__btn {
        /* 44px is the touch minimum this sheet already sets elsewhere; this control is
           desktop-only and beside a text stamp, so it stays compact. */
        line-height: 1;
        padding: 2px 7px;
    }
}

/* ── Truck comparison panel ──────────────────────────────────────────────── */
@layer pf-pages {

    .pf-truck-tile {
        display: flex;
        flex-direction: column;
        gap: 2px;
        padding: 10px 12px;
        border: 1px solid var(--pf-border);
        border-radius: 8px;
        background: var(--pf-card-bg);
    }

    .pf-truck-tile__n {
        font-size: 1.3rem;
        font-weight: 700;
        letter-spacing: -.4px;
        line-height: 1.1;
    }

    .pf-truck-tile__l {
        font-size: .7rem;
        text-transform: uppercase;
        letter-spacing: .5px;
        color: var(--pf-text-subtle);
    }

    /* Neutral, not a warning colour. "Gate-to-gate is not being measured" is a statement of what
       the data does not contain, not an error — and colouring it red would train people to
       dismiss it. */
    .pf-truck-note {
        margin-top: 10px;
        padding: 9px 11px;
        border-radius: 7px;
        font-size: .82rem;
        background: var(--pf-band-none-bg);
        color: var(--pf-text-muted);
    }

    .pf-truck-chart { margin-top: 14px; }

    .pf-truck-chart__title {
        font-size: .78rem;
        text-transform: uppercase;
        letter-spacing: .6px;
        color: var(--pf-text-subtle);
        margin-bottom: 6px;
    }

    .pf-truck-detail { margin-top: 14px; }

    .pf-truck-detail > summary {
        cursor: pointer;
        font-size: .84rem;
        color: var(--pf-brand);
        /* A comfortable target even on a laptop trackpad. */
        padding: 6px 0;
    }
}

/* VesselAutoComplete.razor -- the RadzenAutoComplete replacement. Own classes, so this can stay
   layered; it doesn't compete with anything in Radzen's unlayered stylesheet. The input itself
   (.rz-textbox inside .pf-vessel-autocomplete__input) already gets its border and background
   from the app-wide Radzen input rule below -- nothing to repeat here. */
@layer pf-components {
    .pf-vessel-autocomplete {
        position: relative;
    }

    .pf-vessel-autocomplete__panel {
        position: absolute;
        inset-inline: 0;
        top: 100%;
        z-index: 20;
        margin: 4px 0 0;
        padding: 4px 0;
        max-height: 260px;
        overflow-y: auto;
        list-style: none;
        background-color: var(--pf-surface-0, var(--pf-panel-bg));
        border: 1px solid var(--pf-border-strong, var(--pf-border));
        border-radius: 6px;
        box-shadow: var(--pf-shadow-md, 0 4px 12px rgba(0, 0, 0, .15));
    }

    .pf-vessel-autocomplete__item {
        padding: 6px 12px;
        cursor: pointer;
        color: var(--pf-text);
    }

    .pf-vessel-autocomplete__item:hover,
    .pf-vessel-autocomplete__item--active {
        background-color: var(--pf-primary-lighter, var(--pf-panel-bg-hover, rgba(127, 127, 127, .15)));
    }
}


/* ============================================================================
   RADZEN OVERRIDES — DELIBERATELY UNLAYERED. DO NOT MOVE INTO @layer.
   ----------------------------------------------------------------------------
   Radzen's standard-base.css is entirely unlayered, and an unlayered declaration
   beats a layered one for the same property REGARDLESS of specificity. Anything
   below that competes with Radzen therefore has to live outside @layer, exactly
   like the token bridge at the top of this file.

   This is not theoretical. `.pf-jobcard-wizard .rz-steps-buttons { display:none }`
   sat inside @layer pf-pages and never once applied, because Radzen declares
   `.rz-steps-buttons{display:flex}` unlayered — so the wizard shipped with two
   identical Previous/Next pairs and grepping the deployed CSS "confirmed" a rule
   that was dead. Check overrides with getComputedStyle, not with grep.

   portflow.css loads after standard-base.css, so unlayered + source order is all
   that is needed here; no !important anywhere below.
   ============================================================================ */

/* Radzen renders its own Previous/Next pair below the step content and ignores
   ShowStepButtons="false" in 11.2.2. Ours sit directly beneath doing the same job,
   except ours honour CanAdvance and carry the final "Create draft" action, so
   Radzen's are the pair that goes. Hidden rather than removed: the component still
   uses them for keyboard order. */
.pf-jobcard-wizard .rz-steps-buttons,
.pf-slot-steps .rz-steps-buttons {
    display: none;
}

/* Make every plain Radzen input legible against whatever it sits on -- a card most of all,
   where a borderless, backgroundless control reads as part of the card rather than something
   you can type into.

   Inside a RadzenFormField the visible box is .rz-form-field-content, NOT .rz-dropdown
   or .rz-textbox — those are inner elements that carry no background of their own. An
   earlier attempt targeted the inner ones and so drew a border nobody could see.

   This used to be scoped to .pf-wizard-line/.pf-dialog-form; widened app-wide because the same
   invisible-against-the-card problem showed up everywhere a Radzen input sits directly on a
   card, not only inside those two containers, and RadzenFormField's box is the same class
   wherever it's used. RadzenDataGrid is deliberately excluded below: this app has no inline row
   editing (no EditTemplate anywhere) and the two grids with column filters both already sit
   inside a .pf-dialog-form covered here, but a future grid editor inheriting this by accident
   would draw a border mid-cell, so it's fenced off on purpose rather than by omission. */
.rz-form-field-content,
.rz-numeric,
.rz-textbox,
.rz-dropdown,
.rz-textarea,
.rz-datepicker,
.rz-autocomplete {
    background-color: var(--pf-panel-bg);
    border: 1px solid var(--pf-border-strong, var(--pf-border));
    border-radius: 6px;
}

.rz-data-grid .rz-form-field-content,
.rz-data-grid .rz-numeric,
.rz-data-grid .rz-textbox,
.rz-data-grid .rz-dropdown,
.rz-data-grid .rz-textarea,
.rz-data-grid .rz-datepicker,
.rz-data-grid .rz-autocomplete {
    background-color: initial;
    border: initial;
    border-radius: initial;
}

/* Bootstrap gives every .row > * a top margin of the gutter, but something in this stylesheet
   zeroes it for .col-12 -- so a row mixing .col-12 with .col-6 put half its cells 8px lower than
   the other half and the labels stopped lining up. Measured, not guessed: col-md-3 and col-md-4
   sat at y=251 while the two col-6 col-md-2 cells sat at y=259. Normalise inside the wizard lines
   and give the row an explicit gap so the cells still separate when they stack on a phone. */
.pf-wizard-line .row {
    row-gap: 8px;
}

.pf-wizard-line .row > * {
    margin-top: 0;
}

/* The floating label sits ON the field border, so it needs the field's background
   behind it or the border strikes through the text. */
.pf-wizard-line .rz-form-field .rz-form-field-label {
    background-color: transparent;
}

/* Line the "New" button up with the sub-product INPUT, not with the cell.

   RadzenFormField reserves space above the input for its floating label -- 0.625rem, the start
   value of --rz-form-field-margin-block -- so a button that top-aligns with the cell sits level
   with the label and reads as detached from the control it feeds. Matching the offset and the
   field's own height makes the button span exactly the same band as the input beside it.
   Unlayered because it sets height on .rz-button. */
.jc-subrow .jc-addsub.rz-button {
    align-self: flex-start;
    margin-top: 0.625rem;
    height: 34px;
}

/* Same offset for the delete button that ends each line. */
.pf-wizard-line .jc-line-remove {
    padding-top: 0.625rem;
}

.rz-form-field-content:hover,
.rz-numeric:hover,
.rz-textbox:hover,
.rz-dropdown:hover,
.rz-textarea:hover,
.rz-datepicker:hover,
.rz-autocomplete:hover {
    border-color: var(--pf-brand, var(--pf-border-strong));
}

/* Dialog rows carry the same mixed col-12/col-N pattern as the wizard lines, so they need the
   same gutter normalisation or half the fields sit 8px lower than the other half. */
.pf-dialog-form .row {
    row-gap: 8px;
}

.pf-dialog-form .row > * {
    margin-top: 0;
}


/* ============================================================================
   CIRCUIT-DROPPED NOTICE — UNLAYERED, and driven by Blazor, not by us.
   ----------------------------------------------------------------------------
   Blazor toggles classes on #components-reconnect-modal itself:
     components-reconnect-show     trying to reconnect
     components-reconnect-failed   attempts exhausted
     components-reconnect-rejected the server restarted; the circuit is gone
   It never sets a "hidden" class — the element is hidden by default and the
   framework reveals it, so the base rule below must be display:none.

   Unlayered on purpose: this has to win over anything, because the one moment
   it appears is the moment nothing else on the page works.
   ============================================================================ */
#components-reconnect-modal {
    display: none;
}

#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 2147483000;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(15, 23, 32, .55);
    backdrop-filter: blur(2px);
}

.pf-reconnect__card {
    max-width: 420px;
    width: 100%;
    border-radius: 10px;
    padding: 20px 22px;
    background: var(--pf-panel-bg, #ffffff);
    color: var(--pf-text, #131c27);
    border: 1px solid var(--pf-border, #dbe3ec);
    box-shadow: 0 18px 48px rgba(0, 0, 0, .28);
    font-size: .9rem;
}

.pf-reconnect__card p {
    margin: 6px 0 0;
    color: var(--pf-text-muted, #5b6b7d);
}

/* Only the state Blazor has switched on is shown. */
.pf-reconnect__show,
.pf-reconnect__failed,
.pf-reconnect__rejected {
    display: none;
}

.components-reconnect-show .pf-reconnect__show,
.components-reconnect-failed .pf-reconnect__failed,
.components-reconnect-rejected .pf-reconnect__rejected {
    display: block;
}

.components-reconnect-show .pf-reconnect__show {
    display: flex;
    align-items: center;
    gap: 14px;
}

.pf-reconnect__spinner {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 3px solid var(--pf-border, #dbe3ec);
    border-top-color: var(--pf-brand, #1f6feb);
    animation: pf-reconnect-spin .9s linear infinite;
}

@keyframes pf-reconnect-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .pf-reconnect__spinner { animation: none; }
}
