/* SSSS UI Phase 3a — design tokens.
 * Mirror current implicit values; not changing them in Phase 3.
 * Phase 9 (visual modernization) is the only place these values should be revised.
 */
:root {
  /* Brand */
  --ssss-orange: #ffa328;

  /* Text colors */
  --ssss-text-dark: #000;
  --ssss-danger-red: red;

  /* Borders */
  --ssss-border-dark: #000;

  /* Typography */
  --ssss-font-base: 14px;
  --ssss-font-table: 14px;
  --ssss-font-section-title: 22px;

  /* Form-row geometry */
  --ssss-form-label-width: 20%;
  --ssss-form-input-width: 70%;
  --ssss-form-row-gap: 25px;

  /* Modal */
  --ssss-modal-max-height: 640px;
}

/* ----- Utility classes — Phase 3b -----
 * Namespaced ssss-* to avoid collision with Bootstrap 4 utilities.
 * Each class mirrors a specific high-frequency inline pattern; Phase 3c/3d
 * substitute the inline patterns with these.
 */

.ssss-text-brand        { color: var(--ssss-orange); }
.ssss-text-black        { color: var(--ssss-text-dark); }

.ssss-required-mark     { color: var(--ssss-danger-red); margin-left: 5px; }

.ssss-border-dark       { border: 1px solid var(--ssss-border-dark); }

.ssss-table-100         { width: 100%; font-size: var(--ssss-font-table); }

/* Phase 4.3 (2026-07-20) — row-hover feedback for DataTables list pages.
 *
 * The per-page `background-color: #FFA500` full-row hover was deleted because a
 * solid orange row masked every semantic status colour underneath it (offline
 * red, SOS bands, PTW expiry, …). Bootstrap's own .table-hover then takes over,
 * but its default is too weak to read on our striped tables: an odd row goes
 * rgb(242,242,242) -> rgb(236,236,236), a 6/255 (2.4%) delta that operators
 * scanning a wide table cannot see — and losing row tracking on a wide operator
 * table is a worse regression than the one we just fixed.
 *
 * So raise only the hover TINT, site-wide, in one place. It stays a
 * semi-transparent overlay (Bootstrap paints it as an inset box-shadow on each
 * cell), so semantic row colours still show through — that is the whole point.
 * Value matches the hover already shipped in ai_camera_mgt.php's history table.
 *
 * NOTE on the mechanism (Bootstrap v5.3.3 — the version actually served):
 *
 *   .table > :not(caption) > * > *   box-shadow: inset 0 0 0 9999px
 *       var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))
 *   .table-hover   > tbody > tr:hover            > *   sets --bs-table-bg-state
 *   .table-striped > tbody > tr:nth-of-type(odd) > *   sets --bs-table-bg-type
 *
 * Two consequences worth knowing before touching this:
 *   1. The box-shadow lives on `.table`, not `.table-hover` — a table needs
 *      BOTH classes or it gets no hover at all.
 *   2. hover writes `bg-state`, stripes write `bg-type`, and `bg-state` is the
 *      first fallback — so hover beats stripe by the variable chain, not by
 *      source order. That is why raising --bs-table-hover-bg here is enough.
 *
 * The only vendored Bootstrap files are css/bootstrap.min.css and
 * js/bootstrap.bundle.min.js, both v5.3.3, pinned by
 * tests/unit/BootstrapVersionTest.php. The unminified/rtl/grid/reboot/utilities
 * builds used to sit beside them, still on v5.2.0-beta1 from before the 5.3.3
 * upgrade — nothing loaded them, but two people in a row read one and drew
 * wrong conclusions about how tables paint, so they were deleted.
 */
.table-hover > tbody > tr:hover > * { --bs-table-hover-bg: rgba(13, 110, 253, .15); }

.ssss-form-row-label    {
  display: inline-block;
  width: var(--ssss-form-label-width);
  vertical-align: middle;
  margin-right: 10px;
  margin-bottom: var(--ssss-form-row-gap);
}
.ssss-form-row-input    {
  display: inline-block;
  width: var(--ssss-form-input-width);
  margin-bottom: var(--ssss-form-row-gap);
}

.ssss-modal-body-tall   { max-height: var(--ssss-modal-max-height); }

.ssss-section-title     {
  margin-left: 7px;
  font-size: var(--ssss-font-section-title);
}

.ssss-divider-orange    { border-right: 2px solid var(--ssss-orange); }

/* Phase 7g — WCAG 2.5.5 / Apple HIG 44×44 minimum tap target. */
.ssss-tap-44 {
  min-width: 44px;
  min-height: 44px;
  padding: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  box-sizing: border-box;
}

/* Bump dropdown-item taps to 44px without altering visual paint padding. */
.navbar .dropdown-menu .dropdown-item {
  min-height: 44px;
  display: flex;
  align-items: center;
}

/* Hamburger toggler and inline menu-hide button — original SVGs are 12×12. */
#navMenu .navbar-toggler,
#navShowMenu .navbar-text > div,
#navMenu .navbar-text > div {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Phase 7b — page intro paragraph (one-sentence what-does-this-page-do hint). */
.ssss-page-intro {
  margin: 0.5rem 0 1rem 0;
  padding: 0.5rem 0.75rem;
  background-color: #fafafa;
  border-left: 3px solid var(--ssss-orange);
  color: #333;
  font-size: 0.95rem;
  line-height: 1.4;
}

/* Phase 7c — glossary chip (clickable `?` next to a domain term).
   Phase 3 (2026-07-13): read as an intentional info badge, not a broken
   superscript render — <sup> wrapper dropped (helper/nav.php), text-top lift +
   cursor:help, hover tokenized (--ssss-orange-600, was raw #e8951f). */
.ssss-glossary-chip {
  display: inline-block;
  width: 15px;
  height: 15px;
  margin-left: 3px;
  border-radius: 50%;
  background-color: var(--ssss-orange-500);
  color: #fff !important;
  text-align: center;
  text-decoration: none;
  font-size: 10px;
  font-weight: bold;
  line-height: 15px;
  vertical-align: text-top;
  cursor: help;
}
.ssss-glossary-chip:hover { background-color: var(--ssss-orange-600); text-decoration: none; }

/* NAV-4 (2026-07-16) — page-level「相關頁面」chip row (spec §4.4).
   A light「下一步去邊」hint under .ssss-page-intro. Outline pills so they read
   as secondary cross-navigation, distinct from primary buttons; tokenized on
   the brand orange. Emitted by related_pages() in helper/nav.php. */
.ssss-related-pages {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0 0 1rem 0;
}
.ssss-related-label {
  font-size: 0.85rem;
  color: #6b7280;
}
.ssss-related-chip {
  display: inline-block;
  padding: 2px 10px;
  border: 1px solid var(--ssss-orange-500);
  border-radius: 12px;
  background-color: #fff;
  color: var(--ssss-orange-600);
  font-size: 0.85rem;
  line-height: 1.5;
  text-decoration: none;
  white-space: nowrap;
}
.ssss-related-chip:hover,
.ssss-related-chip:focus {
  background-color: var(--ssss-orange-500);
  color: #fff !important;
  text-decoration: none;
}

/* Phase 8a — mobile guard banner.
   z-index 1040: above navbar fixed-top (1030), below modal-backdrop (1050) +
   modal (1055) so Bootstrap modals' bottom-aligned action buttons (Save/
   Cancel/Confirm in modal-footer) stay clickable when modal-content scrolls
   to bottom on mobile. Original 9999 covered modal-footer — see PR following
   8a code review. App doesn't use Bootstrap offcanvas (also defaults to 1040),
   so no collision. */
#ssss-mobile-guard {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1040;
    background: #222;
    color: #fff;
    border-top: 3px solid var(--ssss-orange, #ffa328);
    padding: 12px 16px;
    box-shadow: 0 -2px 8px rgba(0,0,0,0.3);
    font-size: 14px;
}
#ssss-mobile-guard .ssss-mobile-guard-inner {
    max-width: 100%;
    margin: 0 auto;
}
#ssss-mobile-guard strong {
    display: block;
    margin-bottom: 4px;
}
#ssss-mobile-guard p {
    margin: 0 0 8px 0;
}
@media (max-width: 767.98px) {
    #ssss-mobile-guard { display: block; }
}
.ssss-mobile-continued #ssss-mobile-guard { display: none !important; }

/* ==========================================================================
 * W300 polish — friendly_id cell + mobile card view
 * ==========================================================================
 * Desktop: cname column renders 2-line (primary name + secondary dev_code).
 * IMEI column renders mono small + copy button.
 *
 * Mobile (<768px): DataTable hidden, parallel mobile-card list shown.
 * Tier classes defined for lifecycle states (normal / stale / offline).
 * Alarm tier classes (--critical / --high / --acked) defined as empty
 * placeholders here; a follow-up iteration populates them after PR #136
 * (W300 PR-C alarm path) merges.
 */

/* ---- Desktop cname / imei cell rendering ---- */
.ssss-w300-id-primary       { font-weight: 600; color: #111827; }
.ssss-w300-id-secondary     { font-size: 11px; color: #6b7280; letter-spacing: 0.4px; margin-top: 2px; }
.ssss-w300-imei             { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; color: #9ca3af; }
.ssss-w300-imei-copy        {
    background: transparent; border: none;
    color: #9ca3af; padding: 4px 6px;
    cursor: pointer; min-height: 32px; min-width: 32px;
    margin-left: 4px;
}
.ssss-w300-imei-copy:hover  { color: #374151; }

/* ---- Mobile card container ---- */
.ssss-w300-mobile-cards     { display: none; padding: 12px 0; }

.ssss-w300-card {
    background: #fff; border-radius: 12px;
    margin-bottom: 12px; overflow: hidden;
    box-shadow: 0 1px 2px rgba(0,0,0,0.06);
    border-left: 4px solid #e5e7eb;
}
/* Tier accents — same tokens as the desktop table rows (Phase 4.1). */
.ssss-w300-card--normal     { border-left-color: var(--ssss-tier-normal-accent); }
.ssss-w300-card--stale      { border-left-color: var(--ssss-tier-stale-accent); }
.ssss-w300-card--offline    {
    border-left-color: var(--ssss-tier-offline-accent);
    background: var(--ssss-tier-offline-surface);
}
.ssss-w300-card--offline .ssss-w300-card-vitals { opacity: 0.55; }

.ssss-w300-card--critical   { border-left-color: var(--ssss-tier-critical-accent); }
.ssss-w300-card--high       { border-left-color: var(--ssss-tier-high-accent); }
.ssss-w300-card--acked      { border-left-color: var(--ssss-tier-acked-accent); }

.ssss-w300-card-top {
    display: flex; align-items: flex-start; justify-content: space-between;
    padding: 12px 14px 6px 14px;
}
.ssss-w300-card-lastseen    {
    text-align: right; font-size: 12px; color: #6b7280; white-space: nowrap;
}
.ssss-w300-card-lastseen--stale     { color: #ea580c; font-weight: 600; }
.ssss-w300-card-lastseen--offline   { color: #6b7280; font-style: italic; }

.ssss-w300-card-vitals {
    display: flex; flex-wrap: wrap; gap: 6px;
    padding: 8px 14px 10px 14px;
}
.ssss-vital-pill {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 5px 10px;
    background: #f9fafb; border: 1px solid #e5e7eb;
    border-radius: 999px; font-size: 12px; color: #374151;
}
.ssss-vital-pill .v         { font-weight: 600; color: #111827; }
.ssss-vital-pill .u         { font-size: 10px; color: #9ca3af; }

.ssss-w300-card-imei {
    padding: 8px 14px 10px 14px;
    border-top: 1px solid #f3f4f6;
    display: flex; align-items: center; justify-content: space-between;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 11px; color: #9ca3af;
}

/* ---- Responsive toggle ---- */
@media (max-width: 767.98px) {
    .ssss-w300-desktop-table        { display: none !important; }
    .ssss-w300-desktop-table + .dataTables_wrapper,
    .dataTables_wrapper:has(.ssss-w300-desktop-table) { display: none !important; }
    .ssss-w300-mobile-cards         { display: block; }
}

/* =====================================================================
   PHASE 9 — DESIGN FOUNDATION (Track 0)  [APPEND-ONLY — do not edit
   the :root block at lines 5-28; these EXTEND it, never replace it.]
   Namespace: --ssss-*  · loaded after bootstrap.min.css (pageHead.php:6-7)
   ===================================================================== */
:root {
  /* ---- BRAND (re-expressed from the existing --ssss-orange:#ffa328) -- */
  --ssss-orange-500: #ffa328;            /* == existing --ssss-orange     */
  --ssss-orange-600: #e08c1c;            /* hover/active, ~10% darker      */
  --ssss-orange-400: #ffb757;            /* lighter tint for dark surfaces */
  --ssss-orange-700: #c2780f;            /* pressed                        */
  /* On-orange text: orange is a mid-tone -> DARK text clears 4.5:1.
     #1a1205 on #ffa328 = 9.29:1 ;  #000 on #ffa328 = 10.52:1 ;
     white on #ffa328 = 2.00:1 (NEVER put white text on orange).         */
  --ssss-on-orange: #1a1205;

  /* ---- SEMANTIC COLOR ROLES (status; light-context defaults) -------- */
  --ssss-success: #1e7d46;
  --ssss-warning: #9a6b00;
  --ssss-danger:  #c62828;               /* legacy --ssss-danger-red:red kept */
  --ssss-info:    #1565a0;
  --ssss-critical:    #6a0000;           /* black-rain / T8+ typhoon — beyond danger */
  --ssss-on-critical: #ffffff;

  /* LIVE BLINKING SAFETY ALARM (confined-space gas readouts). A deliberately
     BRIGHTER pair than the static --ssss-danger/warning above: these paint a
     cell that is actively pulsing because a gas reading crossed its threshold,
     so attention-grab is the whole job (same philosophy as --ssss-tier-critical
     for W300 SOS). Values are the pre-4.1 ones EXACTLY (#ff4242 / pure yellow)
     — this slice only tokenises a trained life-safety look, it does not restyle
     it. Two levels, matching the sensor warn-limit / danger-limit thresholds:
        gas value > warning-limit  -> alarm-warn  (yellow, blinking)
        gas value > danger-limit   -> alarm-danger (red,    blinking)
     NOTE: --ssss-alarm-danger #ff4242 sits 3 units from --ssss-tier-critical-fill
     #ff4d4d; a future owner-reviewed pass could merge the two "bright blinking
     critical" reds, but that is a visible change and out of scope here. */
  --ssss-alarm-danger: #ff4242;
  --ssss-alarm-warn:   #ffff00;          /* == the `yellow` keyword it replaces */
  /* Life-safety insurance: the LIVE gas-cell consumption sites (the JS
     rowCallback .css() calls in confined_spaces_*.php) write these WITH a
     literal fallback — var(--ssss-alarm-danger, #ff4242) — UNLIKE every other
     --ssss-* token in this file. Rationale: a blank badge is cosmetic, but a
     confined-space gas-alarm cell that fails to paint is a safety alarm that
     vanishes; the fallback keeps the cell red/yellow even if this file failed
     to load or a token got deleted. Do NOT "tidy away" those fallbacks.
     The static legend swatches deliberately DON'T carry the fallback — they are
     a reference key, not a live alarm, so a bare var() is correct there (and an
     inline-style hex fallback would trip the no-new-inline-hex-style tripwire). */

  /* Command-center pill BACKGROUND tints (Phase 4.1d). The command-center keeps
     its own deliberate Untitled-UI palette — its --cc-danger/-dot/-warn/-ok
     tokens stay defined (grandfathered) in command_center_mgt.php's <style>.
     Only these three BG-tint tokens are hoisted HERE, because a raw-hex custom
     property outside css/ssss.css trips the no-raw-hex-token tripwire, and the
     pills need a named tint to pair with the (already-tokenised) --cc-* text
     colour. Values are the pre-4.1d pill backgrounds EXACTLY — zero visual
     change; owner opted to preserve the CC look, not unify it to --ssss-*. */
  --cc-danger-bg: #fee4e2;
  --cc-warn-bg:   #fef0c7;
  --cc-ok-bg:     #d1fadf;

  /* SUBTLE status tints (Phase 4.1e). Pale backgrounds behind dark text —
     e.g. PTW risk-level cells (高/中/低危險性), expired-qual chips, alarm rows.
     Distinct from the CC pill tints above (CC keeps its own Untitled-UI look).
     Canonical value per role = the app's most-used tint; ALL 18 converted
     sites were already exactly this value, so the conversion is byte-identical
     everywhere. The near-duplicate tints are deliberately NOT folded in and
     keep their own contexts: js/common.js toast success #d1e7dd (that palette
     is one centralised definition, not scattered duplication) and the
     iot-status STALE tint #fde8e8 (staleness is its own concept, not danger). */
  --ssss-danger-subtle:  #f8d7da;
  --ssss-warning-subtle: #fff3cd;
  --ssss-success-subtle: #d4edda;
  /* Info-panel tint + its subtle BORDER companion (Phase 4.1f). Closes the
     #hhdPurpose info box (hhd_asset / hhd_map), a coupled bg+border web panel —
     a subtle background needs its border tokenised too, else converting only the
     bg leaves a raw hex on the same line. Values are the pre-4.1f ones exactly
     — zero visual change. Toast info stays #cfe2ff (centralised, out of scope),
     so --ssss-info-subtle canonical = the scattered #hhdPurpose value #eef4ff.
     NB the mobile-plant 24h-escalation banner deliberately keeps LITERAL hexes
     (#fff3cd/#ffeeba) — it is EMAIL HTML, where var() does not resolve, so no
     --ssss-warning-subtle-border token exists (it would only have served that
     one email site).                                                          */
  --ssss-info-subtle:        #eef4ff;
  --ssss-info-subtle-border: #cfe0ff;
  /* Body text on a permanently-dark surface (the landing page is dark in BOTH
     themes, so this cannot live in the dark-mode block). css/welcome.css has
     referenced this since Phase 9 but nobody ever defined it — every use
     carries `, #ececec`, so the fallback has silently been doing the work.
     Defined here at exactly that value: no visual change, token now real. */
  --ssss-text-on-dark: #ececec;
  --ssss-focus:   #ffa328;               /* focus ring uses brand orange   */

  /* RGB helpers (comma-separated) — Bootstrap 5.3 reads rgba(var(--bs-*-rgb),a)
     for tints/subtle bgs; these MUST match the hex tokens just above + the
     surface tokens below (one source of truth, no new colors introduced). */
  --ssss-success-rgb:     30, 125, 70;   /* == #1e7d46 */
  --ssss-warning-rgb:     154, 107, 0;   /* == #9a6b00 */
  --ssss-danger-rgb:      198, 40, 40;   /* == #c62828 */
  --ssss-info-rgb:        21, 101, 160;  /* == #1565a0 */
  --ssss-surface-0-rgb:   255, 255, 255; /* == #ffffff (body-bg)  */
  --ssss-on-surface-rgb:  22, 24, 28;    /* == #16181c (body-color) */

  /* ---- ALARM ESCALATION TIERS (W300 worker / R110 hrwatch) ----------
     One tier == one token, consumed by BOTH the desktop table-row fill
     and the mobile card left-accent. Before Phase 4.1 these were two
     hard-coded sets that disagreed for the same tier (the mobile ones
     were literally commented "placeholders"), so an operator switching
     from desktop to phone saw a different colour for the same alarm.
     Desktop values win as canonical: worker_status_mgt + hrwatch_status_mgt
     already share them, and operators are trained on that look.
       -fill   = large tinted area behind row text
       -accent = 4px card border / legend chip (small area -> saturated)
     NOT a general-purpose palette: these encode a tier ORDER, so do not
     reuse them for plain error/warning text (that is --ssss-danger etc). */
  --ssss-tier-critical-fill:   #ff4d4d;
  --ssss-tier-critical-flash:  #ff8080;  /* 50% keyframe of the pulse    */
  --ssss-tier-critical-accent: #dc2626;
  --ssss-on-tier-critical:     #ffffff;

  --ssss-tier-high-fill:       #fb923c;
  --ssss-tier-high-accent:     #ea580c;
  --ssss-on-tier-high:         #ffffff;

  --ssss-tier-acked-fill:      #fde68a;
  --ssss-tier-acked-accent:    #ca8a04;

  /* stale: red-family on the two W300/R110 desktop tables; the mobile card
     used to say amber #f59e0b. Accent is a DESATURATED brick so a 4px stale
     border never reads as loud as the #dc2626 critical border next to it.
     status_mgt.php also hard-codes #f7a2a2 but that tint means "row has a
     live alert", NOT staleness — same hex, different concept, so it is
     deliberately NOT folded in here.
     Consumers of --stale-accent are the THREE pages that build
     .ssss-w300-card--<tier>: worker_status_mgt, device_mgt, iot_status_mgt
     (via js/ssss-ui.js) — changing this token moves all three.            */
  --ssss-tier-stale-fill:      #f7a2a2;
  --ssss-tier-stale-accent:    #b85c5c;
  --ssss-on-tier-stale:        #5c1a1a;

  /* offline has THREE roles: the row tint (hrwatch only — worker_status
     deliberately leaves offline rows untinted), the mobile card panel
     background, and the border/text accent shared by both.              */
  --ssss-tier-offline-accent:  #6b7280;
  --ssss-tier-offline-fill:    #e5e7eb;  /* desktop row tint            */
  --ssss-tier-offline-surface: #fafafa;  /* mobile card panel bg        */
  --ssss-tier-normal-accent:   #16a34a;

  /* ---- TYPE SCALE (base 16px; existing 14px tokens UNCHANGED) -------- */
  --ssss-fs-100: 0.75rem;   /* 12px  caption/meta            */
  --ssss-fs-200: 0.875rem;  /* 14px  == legacy body (compat) */
  --ssss-fs-300: 1rem;      /* 16px  NEW base body           */
  --ssss-fs-400: 1.25rem;   /* 20px  sub-heading             */
  --ssss-fs-500: 1.5rem;    /* 24px  section title           */
  --ssss-fs-600: 2rem;      /* 32px  page/hero h2            */
  --ssss-fs-700: 2.75rem;   /* 44px  landing hero h1         */
  --ssss-lh-tight: 1.2;
  --ssss-lh-base:  1.5;
  --ssss-fw-regular: 400;
  --ssss-fw-medium:  500;
  --ssss-fw-bold:    700;

  /* ---- SPACING SCALE (4px base grid) -------------------------------- */
  --ssss-space-0: 0;
  --ssss-space-1: 0.25rem;  /* 4px  */
  --ssss-space-2: 0.5rem;   /* 8px  */
  --ssss-space-3: 0.75rem;  /* 12px */
  --ssss-space-4: 1rem;     /* 16px */
  --ssss-space-5: 1.5rem;   /* 24px */
  --ssss-space-6: 2rem;     /* 32px */
  --ssss-space-7: 3rem;     /* 48px */
  --ssss-space-8: 4rem;     /* 64px */

  /* ---- RADIUS SCALE ------------------------------------------------- */
  --ssss-radius-xs: 4px;
  --ssss-radius-sm: 8px;
  --ssss-radius-md: 12px;   /* login card / panels                       */
  --ssss-radius-lg: 16px;
  --ssss-radius-pill: 999px;

  /* ---- ELEVATION / SHADOW RAMP (light context) ---------------------- */
  --ssss-elev-0: none;
  --ssss-elev-1: 0 1px 2px rgba(16,18,22,0.08), 0 1px 1px rgba(16,18,22,0.04);
  --ssss-elev-2: 0 2px 6px rgba(16,18,22,0.10), 0 1px 2px rgba(16,18,22,0.06);
  --ssss-elev-3: 0 8px 24px rgba(16,18,22,0.14), 0 2px 6px rgba(16,18,22,0.08);
  --ssss-elev-4: 0 16px 48px rgba(16,18,22,0.20), 0 4px 12px rgba(16,18,22,0.12);

  /* ---- MOTION TOKENS ------------------------------------------------ */
  --ssss-dur-instant: 80ms;
  --ssss-dur-fast:    160ms;
  --ssss-dur-base:    240ms;
  --ssss-dur-slow:    400ms;
  --ssss-ease-standard:   cubic-bezier(0.2, 0, 0, 1);     /* enter/move   */
  --ssss-ease-decelerate: cubic-bezier(0, 0, 0, 1);       /* incoming     */
  --ssss-ease-accelerate: cubic-bezier(0.3, 0, 1, 1);     /* outgoing     */
  --ssss-ease-emphasized: cubic-bezier(0.2, 0, 0, 1.05);  /* hero accent  */

  /* ---- SURFACE RAMP — LIGHT (dashboards/ops stay light) ------------- */
  --ssss-surface-0: #ffffff;   /* base page                    */
  --ssss-surface-1: #fafafa;   /* == legacy intro tint          */
  --ssss-surface-2: #f1f2f4;   /* raised card                   */
  --ssss-surface-3: #e7e9ec;   /* raised+                       */
  --ssss-on-surface:        #16181c;   /* body text  (17.8:1 on #fff)   */
  --ssss-on-surface-muted:  #565b62;   /* muted text (6.84:1 on #fff)   */
  --ssss-border:            #d4d7dc;
  --ssss-border-strong:     #b4b8bf;

  /* ---- GLASS TUNABLES (read by .ssss-glass; overridden in dark) ----- */
  --ssss-glass-bg:        rgba(255,255,255,0.62);  /* light fallback tint */
  --ssss-glass-bg-solid:  #f4f5f7;                 /* @supports-none / RT  */
  --ssss-glass-border:    rgba(255,255,255,0.55);
  --ssss-glass-blur:      14px;                    /* <=20px per perf budget */
  --ssss-glass-saturate:  140%;
  --ssss-glass-shadow:    var(--ssss-elev-3);
  --ssss-glass-text:      var(--ssss-on-surface);
}

/* ---- SURFACE RAMP — DARK + glass re-tint (public surfaces only) -----
   Applied only when an ancestor carries data-bs-theme="dark"
   (Track A sets it on the login + landing surfaces ONLY).              */
[data-bs-theme="dark"] {
  --ssss-surface-0: #0e1116;   /* near-black page base                  */
  --ssss-surface-1: #151a21;   /* elevated                              */
  --ssss-surface-2: #1c222b;   /* card                                  */
  --ssss-surface-3: #242c37;   /* raised+ (glass reads against this)    */
  --ssss-on-surface:        #f3f5f7;   /* 17.3:1 on surface-0           */
  --ssss-on-surface-muted:  #b3bac3;   /* 9.66:1 on surface-0           */
  --ssss-border:            #2a323d;
  --ssss-border-strong:     #3a4452;

  /* brand reads brighter on dark; on-orange text stays dark            */
  --ssss-orange-500: #ffb142;          /* lifted for dark legibility    */
  --ssss-on-orange:  #1a1205;          /* 10.26:1 on #ffb142            */

  /* status roles re-tuned for AA on dark surface-0                     */
  --ssss-success: #4cc98a;
  --ssss-warning: #ffce6a;
  --ssss-danger:  #ff6b6b;
  --ssss-info:    #5fb1ef;

  /* glass on dark: low-alpha light film over the elevated dark ramp    */
  --ssss-glass-bg:       rgba(36,44,55,0.55);   /* tint over surface-3  */
  --ssss-glass-bg-solid: #1c222b;               /* solid fallback       */
  --ssss-glass-border:   rgba(255,255,255,0.14);
  --ssss-glass-shadow:   0 16px 48px rgba(0,0,0,0.55);
  --ssss-glass-text:     var(--ssss-on-surface);
}

/* =====================================================================
   .ssss-glass — frosted panel for SMALL CHROME ONLY
   (login card #divLogin/#divCommunity, landing nav).
   NEVER place over <video>, data tables, or map tiles (perf constraint).
   ===================================================================== */
.ssss-glass {
  position: relative;
  background-color: var(--ssss-glass-bg-solid);   /* solid base first... */
  border: 1px solid var(--ssss-glass-border);
  border-radius: var(--ssss-radius-md);
  box-shadow: var(--ssss-glass-shadow);
  color: var(--ssss-glass-text);
  font-size: var(--ssss-fs-300);
  line-height: var(--ssss-lh-base);
}

/* Enable translucency ONLY where backdrop-filter is truly supported.    */
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .ssss-glass {
    background-color: var(--ssss-glass-bg);       /* ...upgrade to film  */
    -webkit-backdrop-filter: blur(var(--ssss-glass-blur))
                             saturate(var(--ssss-glass-saturate));
            backdrop-filter: blur(var(--ssss-glass-blur))
                             saturate(var(--ssss-glass-saturate));
  }
}

/* A11y: reduce transparency -> revert to solid panel, drop the blur.    */
@media (prefers-reduced-transparency: reduce) {
  .ssss-glass {
    background-color: var(--ssss-glass-bg-solid);
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
  }
}

/* A11y: reduced-motion collapses token durations to ~0.                 */
@media (prefers-reduced-motion: reduce) {
  :root {
    --ssss-dur-instant: 0.01ms;
    --ssss-dur-fast:    0.01ms;
    --ssss-dur-base:    0.01ms;
    --ssss-dur-slow:    0.01ms;
  }
  .ssss-glass { transition: none !important; }
}

/* Visible keyboard focus ring (:focus-visible). Brand-orange ring.      */
.ssss-glass :focus-visible,
.ssss-focus-ring:focus-visible {
  outline: 3px solid var(--ssss-focus);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px rgba(255,163,40,0.30);
}

/* 44px tap targets inside glass chrome (WCAG 2.5.5).                    */
.ssss-glass .btn,
.ssss-glass button,
.ssss-glass [role="button"] {
  min-height: 44px;
}

/* Low-FX escape hatch toggled by Track A's perf detector.               */
body.is-lowfx .ssss-glass {
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  background-color: var(--ssss-glass-bg-solid);
}

/* Brand-primary remap — neutralize Bootstrap blue, adopt --ssss-orange.
   --bs-btn-* variable theming is present in the vendored Bootstrap v5.3.3
   (re-verified 2026-07-20 against css/bootstrap.min.css, the served file).
   Was originally written against 5.2.0-beta1; the 5.3.3 upgrade (8cccf7c)
   kept these variables, so the remap carried over unchanged. */
:root {
  --bs-primary: var(--ssss-orange-500);
  --bs-primary-rgb: 255, 163, 40;

  /* ---- Bridge extension (GATE 0 / T6) — additive, dormant ------------
     Map Bootstrap 5.3's remaining theme-color + surface variables onto the
     existing --ssss-* tokens so vendored components inherit the brand
     palette with ZERO page edits. No new hex literals here: every value
     points at a token already defined in the append-only :root blocks
     above. 5.3 also reads rgba(var(--bs-*-rgb),a) for subtle bgs/tints, so
     the matching --bs-*-rgb come from the --ssss-*-rgb helpers. */
  --bs-success:        var(--ssss-success);
  --bs-success-rgb:    var(--ssss-success-rgb);
  --bs-danger:         var(--ssss-danger);
  --bs-danger-rgb:     var(--ssss-danger-rgb);
  --bs-warning:        var(--ssss-warning);
  --bs-warning-rgb:    var(--ssss-warning-rgb);
  --bs-info:           var(--ssss-info);
  --bs-info-rgb:       var(--ssss-info-rgb);

  --bs-body-bg:        var(--ssss-surface-0);
  --bs-body-bg-rgb:    var(--ssss-surface-0-rgb);
  --bs-body-color:     var(--ssss-on-surface);
  --bs-body-color-rgb: var(--ssss-on-surface-rgb);
  --bs-border-color:   var(--ssss-border);
}
.btn-primary {
  --bs-btn-bg: var(--ssss-orange-500);
  --bs-btn-border-color: var(--ssss-orange-500);
  --bs-btn-color: var(--ssss-on-orange);          /* dark text on orange */
  --bs-btn-hover-bg: var(--ssss-orange-600);
  --bs-btn-hover-border-color: var(--ssss-orange-600);
  --bs-btn-hover-color: var(--ssss-on-orange);
  --bs-btn-active-bg: var(--ssss-orange-700);
  --bs-btn-active-border-color: var(--ssss-orange-700);
  --bs-btn-active-color: var(--ssss-on-orange);
  --bs-btn-focus-shadow-rgb: 255, 163, 40;
}

/* Brand the DataTables/Bootstrap pagination ACTIVE cell too (the .btn remap
   above only covered --bs-btn-*). v5.3.3 exposes --bs-pagination-* and
   `.active>.page-link,.page-link.active` reads them (re-verified 2026-07-20
   against css/bootstrap.min.css — the older note cited bootstrap.css, a stale
   5.2.0-beta1 build that has since been deleted). NB: default active-color is
   #fff which FAILS on orange (~2:1) — dark on-orange clears AA (~9.3:1). */
.pagination {
  --bs-pagination-active-bg: var(--ssss-orange-500);
  --bs-pagination-active-border-color: var(--ssss-orange-500);
  --bs-pagination-active-color: var(--ssss-on-orange);
}

/* Path B only: minimal Bootstrap-chrome dark bridge for 5.2.0-beta1.
   Scoped to [data-bs-theme="dark"] -> zero effect on light pages.       */
[data-bs-theme="dark"] body {
  background-color: var(--ssss-surface-0);
  color: var(--ssss-on-surface);
}
[data-bs-theme="dark"] .form-control {
  background-color: var(--ssss-surface-2);
  border-color: var(--ssss-border);
  color: var(--ssss-on-surface);
}
[data-bs-theme="dark"] .form-control::placeholder { color: var(--ssss-on-surface-muted); }
[data-bs-theme="dark"] .modal-content {
  background-color: var(--ssss-surface-2);
  color: var(--ssss-on-surface);
  border-color: var(--ssss-border);
}
[data-bs-theme="dark"] .alert-warning {
  background-color: #3a2f12;
  border-color: #5a4a1c;
  color: var(--ssss-warning);
}
[data-bs-theme="dark"] .alert-warning .ssss-text-black { color: var(--ssss-on-surface); }

/* IoT usage guide */
.iotguide-pill{border:1px solid #ccc;margin:0 4px 4px 0;background:#fff}
.iotguide-pill.active{background:#e87b00;color:#fff;border-color:#e87b00}
.iotguide-pane{display:none}
.iotguide-pane.active{display:block}

/* =====================================================================
   Weather-safety widget (homepage step 1) — dormant until pageMaster
   wires it (Task 9). Tokens only, no new raw hex outside the
   --ssss-critical / --ssss-on-critical definitions above.
   ===================================================================== */
.ssss-weather              { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; }
.ssss-weather--stale       { color: var(--ssss-warning); font-style: italic; }
.ssss-weather-badge        { font-size: 11px; }
.ssss-badge-critical       { background-color: var(--ssss-critical); color: var(--ssss-on-critical); }
/* 5.1 SOS auto-popup — critical framing via token (header uses .bg-danger). */
.ssss-sos-popup-content    { border: 3px solid var(--ssss-danger); }
.ssss-weather-banner       { padding: 6px 12px; text-align: center; font-weight: bold; }
.ssss-weather-banner a     { color: var(--ssss-on-critical); text-decoration: underline; }
.iotguide-steps{line-height:1.8}

/* =====================================================================
   IoT connection-status pills — SINGLE SOURCE (A5 / visual S1).
   Previously duplicated in per-page <style> on device_mgt / iot_status;
   promoting here also styles the CCTV pill that had no local CSS (F4).
   Phase 4.1b DID the semantic-token remap this block was waiting for (the
   old note here deferred it to "S3, owner-reviewed" — owner signed off
   2026-07-21). The pill carries white text, so every background must clear
   4.5:1 against white. Measured, old -> new:
       online   #198754 4.53:1 (only just)  -> #1e7d46 5.15:1
       stale    #fd7e14 2.57:1 **FAILS**    -> #9a6b00 4.69:1
       offline  #dc3545 4.53:1 (only just)  -> #c62828 5.62:1
   So the remap fixes one real AA failure (stale) and gives the other two
   headroom instead of sitting on the line. Neutral mute/never greys are
   4.1b scope and deliberately untouched.
   ===================================================================== */
.iot-pill         { display:inline-block; padding:1px 10px; border-radius:12px; font-weight:bold; font-size:12px; color:white; }
.iot-pill-online  { background-color:var(--ssss-success); }
.iot-pill-stale   { background-color:var(--ssss-warning); }
.iot-pill-offline { background-color:var(--ssss-danger); }
.iot-pill-mute    { background-color:#9ca3af; }
.iot-pill-never   { background-color:#e9ecef; color:#6b7280; font-style:italic; }

/* Command-center hero-map popup: alarm text (A6) — tokenised so cc.js needs no
   inline hex style (ci-tripwire #1). */
.cc-alarm-text    { color: var(--ssss-danger); font-weight: 500; }

/* ===== ssss-count-strip — build-once fleet summary line (usability wave 1).
   One slim line of live whole-set counts (總數/在線/警報/在線率…), the CMSV6-
   footer pattern the owner asked for. Rendered by js/ssss/count_strip.js;
   labels are passed in by each page (LangHelper), so this component itself
   carries no strings. Tones map to the semantic tokens only — no new hex. */
.ssss-count-strip { display:flex; flex-wrap:wrap; align-items:baseline; gap:6px 18px; margin:4px 0 10px; font-size:13.5px; }
.ssss-count-strip .cs-item { display:inline-flex; align-items:baseline; gap:6px; color:#5f636a; }
.ssss-count-strip .cs-n { font-size:1.3rem; font-weight:700; font-variant-numeric:tabular-nums; line-height:1; color:var(--ssss-text-dark); }
.ssss-count-strip [data-tone="ok"]     .cs-n { color: var(--ssss-success); }
.ssss-count-strip [data-tone="danger"] .cs-n { color: var(--ssss-danger); }
.ssss-count-strip [data-tone="warn"]   .cs-n { color: var(--ssss-warning); }
.ssss-count-strip [data-tone="muted"]  .cs-n { color: #6c757d; }
.ssss-count-strip .cs-item[role="button"] { cursor:pointer; }
.ssss-count-strip .cs-item[role="button"]:hover .cs-l,
.ssss-count-strip .cs-item[role="button"]:focus-visible .cs-l { text-decoration:underline; }

/* ===== ssss-badge — semantic status pills (usability wave 1, component D).
   Status/severity encoded in FORM as well as text, on the semantic tokens
   only. Generic: any page's status column can map its codes onto these. */
.ssss-badge { display:inline-block; padding:.25em .65em; font-size:85%; font-weight:700; border-radius:.375rem; color:#fff; white-space:nowrap; }
.ssss-badge-ok     { background: var(--ssss-success); }
.ssss-badge-danger { background: var(--ssss-danger); }
.ssss-badge-warn   { background: var(--ssss-warning); }
.ssss-badge-muted  { background: #6c757d; }

/* shell variant of the count strip: slimmer, quiet ground, sits under the nav */
.ssss-shell-strip { margin:0; padding:4px 16px 3px; gap:4px 16px; font-size:12px; background:#fafafa; border-bottom:1px solid #e5e5e5; }
.ssss-shell-strip .cs-n { font-size:1.02rem; }

/* =====================================================================
   前端實用化 wave 2 — 組件 C: inline evidence (js/ssss/evidence.js).
   Tiles/strip render INSIDE DataTable cells; the lightbox + wall cards
   are page-level. Semantic colours ride the 4.1b tokens above.
   ===================================================================== */
.ssss-ev-strip  { display:inline-flex; align-items:center; gap:4px; vertical-align:middle; }
.ssss-ev-tile   { height:42px; width:60px; object-fit:cover; border-radius:4px; border:1px solid #cfcfcf; cursor:zoom-in; background:#f3f4f6; }
.ssss-ev-tile:hover, .ssss-ev-card:hover { outline:2px solid var(--ssss-info); outline-offset:1px; }
.ssss-ev-tile--video { display:inline-flex; align-items:center; justify-content:center; background:#1f2937; color:#fff; font-size:15px; cursor:pointer; }
.ssss-ev-more   { display:inline-flex; align-items:center; justify-content:center; height:42px; min-width:34px; padding:0 6px; border-radius:4px; border:1px dashed #9ca3af; background:#f9fafb; color:#374151; font-size:12px; font-weight:bold; cursor:pointer; }

/* alert type badge with severity tint (嚴重度色); neutral grey for unmapped codes */
.ssss-ev-badge  { display:inline-block; padding:1px 8px; border-radius:10px; font-size:12px; font-weight:bold; background:#e5e7eb; color:#374151; white-space:nowrap; }
.ssss-ev-badge--danger { background:var(--ssss-danger);  color:#fff; }
.ssss-ev-badge--warn   { background:var(--ssss-warning); color:#fff; }
.ssss-ev-badge--info   { background:var(--ssss-info);    color:#fff; }

/* lightbox (#ssssEvModal) */
.ssss-ev-lightbox { display:flex; align-items:center; gap:8px; }
.ssss-ev-stage    { flex:1; text-align:center; min-height:200px; }
.ssss-ev-stage img,
.ssss-ev-stage video { max-width:100%; max-height:78vh; object-fit:contain; }
.ssss-ev-nav      { border:none; background:transparent; font-size:38px; line-height:1; padding:0 10px; cursor:pointer; color:inherit; }
.ssss-ev-nav:disabled { opacity:.25; cursor:default; }

/* evidence wall (ai_camera event log / aicam-detail history) */
.ssss-ev-wall { display:grid; grid-template-columns:repeat(auto-fill, minmax(170px, 1fr)); gap:10px; padding:4px 0; }
.ssss-ev-card { border:1px solid #cfcfcf; border-radius:8px; overflow:hidden; cursor:zoom-in; background:#fff; }
.ssss-ev-card-thumb { width:100%; aspect-ratio:16/10; object-fit:cover; display:block; background:#f3f4f6; }
.ssss-ev-card-thumb--video { display:flex; align-items:center; justify-content:center; color:#fff; font-size:28px; background:#1f2937; }
.ssss-ev-card-meta  { padding:6px 8px; font-size:12px; line-height:1.5; }
.ssss-ev-card-meta .ssss-ev-dt { color:#6b7280; }

/* alert_mgt count strip — click-to-filter chips over the alert grid */
.ssss-alert-strip { display:flex; flex-wrap:wrap; gap:8px; margin:0 0 8px 5px; }
.ssss-alert-chip  { display:inline-flex; align-items:baseline; gap:6px; border:1px solid #cfcfcf; border-radius:8px; background:#fff; padding:4px 12px; font-size:13px; cursor:pointer; }
.ssss-alert-chip b { font-size:18px; }
.ssss-alert-chip.is-active { outline:2px solid var(--ssss-info); }
.ssss-alert-chip--danger  b { color:var(--ssss-danger); }
.ssss-alert-chip--success b { color:var(--ssss-success); }

/* =====================================================================
   Designed focus ring (owner 拍板 2026-08-17: option C 雙層圈).
   #463 made the icon-only controls keyboard-reachable but left focus on
   the browser default. This is the site-wide designed state: an info-blue
   outline (same hue as the hover language) offset 2px, with a white halo
   filling the gap so the ring reads on ANY ground — map tiles, the dark
   command-center chrome, photo thumbnails. :focus-visible only, so mouse
   clicks never flash a ring. Scoped to interactive elements — a bare
   :focus-visible would also ring modal dialogs (tabindex="-1" containers
   receive scripted focus on open).
   ===================================================================== */
a:focus-visible, button:focus-visible, [role="button"]:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible,
summary:focus-visible, [tabindex="0"]:focus-visible {
	/* !important is deliberate: Bootstrap ships `.navbar-toggler:focus { outline:0 }`
	   and several component :focus rules that out-specificity a bare
	   element:focus-visible — an a11y ring that some controls can suppress is
	   not a ring. Keyboard-only (:focus-visible), so mouse clicks never flash. */
	outline: 3px solid var(--ssss-info) !important;
	outline-offset: 2px !important;
	box-shadow: 0 0 0 2px #fff !important;
}
