/* ============================================================
   Offender Management System — PTS Solutions Theme
   Matches RMS web application design language
   ============================================================ */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
/* Material Icons (v4 / @material-ui/icons set) — the icon flavor PTS
   Settings and the rest of the Apps Suite ship with. Used app-wide
   for visual consistency. Every icon name OMS uses has been audited
   to ensure it exists in this older set; Symbols-only names
   (stylus_note, view_kanban, progress_activity, network_ping) have
   v4 equivalents. Don't add new Symbols-only icon names without
   first checking https://fonts.google.com/icons (toggle the
   "Material Icons" filter) — pick a name that exists in v4. */
@import url('https://fonts.googleapis.com/icon?family=Material+Icons');

/* Material Symbols Rounded kept as a fallback / explicit-opt-in font
   for any future piece that genuinely needs the Symbols set (none
   today). Use class="icon-symbols" instead of class="icon" to opt in. */
@font-face {
  font-family: 'Material Symbols Rounded';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url('/MaterialSymbolsRounded.ttf') format('truetype');
}
.icon { font-family: 'Material Symbols Rounded'; font-weight: normal; font-style: normal; font-size:1.2rem; line-height: 1; letter-spacing: normal; text-transform: none; display: inline-block; white-space: nowrap; word-wrap: normal; direction: ltr; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; font-feature-settings: 'liga'; -webkit-font-feature-settings: 'liga'; -moz-font-feature-settings: 'liga'; vertical-align: middle; }
/* Action-button icons render in the Material UI v4 filled style.
   Targets every .icon nested inside a <button>: .row-action,
   .oms-act, .ep-circle-btn, .btn, .tag-add-btn, .tag-delete,
   .modal-close, etc. The font-feature-settings reset is required
   because the default .icon rule turns on 'liga' which the older
   font doesn't define the same way. */
button .icon, .row-action .icon, a.btn .icon {
  font-family: 'Material Icons' !important;
  font-feature-settings: normal !important;
  -webkit-font-feature-settings: normal !important;
  -moz-font-feature-settings: normal !important;
}
/* Inline SVG icons drawn in the Material Symbols Rounded style.
   Size in 1em so the SVG inherits the parent .nav-icon font-size (1.5rem in
   topbar, 1.2rem in generic .icon contexts), exactly matching how the font
   glyphs scale. Inherits color via currentColor cascade. */
.nav-icon-svg { display: inline-block; vertical-align: middle; line-height: 1; }
.nav-icon-svg svg { width:1em; height:1em; display: block; color: inherit; }

/* ── CSS Variables ──────────────────────────────────────────── */
:root {
  /* Brand orange (topbar / nav strip) — locked, never overridden by user theme.
     Tuned to match the OMS logo (favicon.svg gradient #E64A19 → #BF360C). */
  --brand-primary:      #E64A19;
  --brand-primary-dark: #BF360C;
  /* Content accent — softer default, user-overridable via theme picker.
     davidnotes4 N5: prior #D84315 was too bold on long content pages. */
  --primary:          #E0703A;
  --primary-dark:     #C25A28;
  --primary-light:    #EE8060;
  --primary-hover:    #C63F17;
  --accent:           #FF5722;
  --bg-body:          #ECEFF1;
  --bg-content:       #FFFFFF;
  --bg-card:          #FFFFFF;
  --border-color:     #CFD8DC;
  --border-light:     #E0E0E0;
  --text-primary:     #212121;
  /* Floors raised from #546E7A / #90A4AE per the 33-theme WCAG-AA audit done
     on PRISM (PTS Support Console, 2026-05-16). Old values landed at ~2.5:1
     on white-ish surfaces — fail AA. New values clear 4.5:1 on every shipped
     light theme. Dark side is already above the corresponding floor from a
     prior bump (see :root.dark-mode block below). */
  --text-secondary:   #2D3340;
  --text-muted:       #525866;
  /* --text-on-primary is "text on brand CHROME" (topbar, login PIN header,
     nav drawer). The topbar is locked to --brand-primary orange and never
     themed — its text must stay white regardless of WCAG ratio. Body-content
     AA computation uses --text-on-brand / --text-on-accent instead. */
  --text-on-primary:  #FFFFFF;
  --text-on-accent:   #FFFFFF;
  --text-on-brand:    #FFFFFF;
  --accent-deep:      var(--primary-dark);
  --danger:           #D32F2F;
  --danger-light:     #FFEBEE;
  --success:          #2E7D32;
  --success-light:    #E8F5E9;
  --warning:          #F57F17;
  --warning-light:    #FFF8E1;
  --warning-deep:     #E65100;
  --info:             var(--primary);
  --info-light:       #FBE9E7;
  --info-blue:        #1565C0;
  --info-blue-light:  #E3F2FD;
  --accent-purple:    #7B1FA2;
  --accent-purple-light: #F3E5F5;
  --accent-pink:      #E91E63;
  --danger-deep:      #C62828;
  --danger-deeper:    #B71C1C;
  --shadow-sm:        0 1px 2px rgba(0,0,0,0.04), 0 2px 6px rgba(0,0,0,0.06);
  --shadow-md:        0 2px 4px rgba(0,0,0,0.04), 0 8px 20px rgba(0,0,0,0.08);
  --shadow-lg:        0 4px 8px rgba(0,0,0,0.06), 0 16px 40px rgba(0,0,0,0.12);
  --shadow-hover:     0 8px 24px rgba(0,0,0,0.12), 0 2px 6px rgba(0,0,0,0.06);
  --shadow-glow:      0 0 0 3px rgba(var(--theme-rgb,216,67,21),0.1);
  --radius:           0.625rem;  /* 10px @ 16px base */
  --radius-lg:        1rem;      /* 16px */
  --radius-pill:      3.125rem;  /* 50px */
  --radius-circle:    50%;
  --font:             'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --topbar-height:    3.875rem;  /* ~62px @ 16px base, ~54px @ 14px base */
  --transition-fast:  0.15s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-normal: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-med:   0.25s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-spring: 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  /* ── Z-index scale (unified) ─────────────────────────────── */
  --z-base:           1;
  --z-grid-header:    2;
  --z-fixed-bar:      100;
  --z-dropdown:       200;
  --z-mega-menu:      300;
  --z-topbar:         500;
  --z-modal-backdrop: 9999;
  --z-modal:          10000;
  --z-modal-nested:   10001;
  --z-toast:          10500;
  --z-datepicker:     10800;
  --z-session-banner: 99999;
}

/* ── Global focus visibility — keyboard accessibility ── */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(var(--theme-rgb,216,67,21),0.15);
}
body.dark-mode :focus-visible {
  outline-color: var(--primary-light);
  box-shadow: 0 0 0 4px rgba(var(--theme-rgb,255,87,34),0.25);
}

/* ── Shared utility classes — empty/loading states, icon sizes ── */
.empty-state,
.loading-state {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.4286rem 1rem;
  text-align: center;
  color: var(--text-muted);
  font-size: 0.85rem;
  font-style: italic;
}
.empty-state.compact,
.loading-state.compact { padding: 0.7143rem 0.5714rem; font-size: 0.78rem; }
.empty-state .icon,
.loading-state .icon { font-size: 1.6rem; opacity: 0.6; font-style: normal; }
.loading-state::before {
  content: '';
  width: 1rem;
  height: 1rem;
  border: 2px solid var(--border-color);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Icon size scale — use these instead of inline font-size on .icon spans */
.icon-xs { font-size: 0.7rem !important; }
.icon-sm { font-size: 0.85rem !important; }
.icon-md { font-size: 1rem !important; }
.icon-lg { font-size: 1.25rem !important; }
.icon-xl { font-size: 1.6rem !important; }

/* Icon-only buttons — consistent hover/focus */
.icon-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.3571rem;
  border-radius: var(--radius);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  transition: background var(--transition-fast), color var(--transition-fast);
}
.icon-btn:hover { background: rgba(var(--theme-rgb,216,67,21),0.10); color: var(--primary); }
.icon-btn:active { background: rgba(var(--theme-rgb,216,67,21),0.16); }
.icon-btn:disabled { opacity: 0.4; cursor: not-allowed; }
body.dark-mode .icon-btn:hover { background: rgba(var(--theme-rgb,255,87,34),0.18); color: var(--primary-light); }

/* ── Mobile-friendly modal sizing ── */
@media (max-width: 640px) {
  .modal,
  .modal-content,
  .modal-overlay > div,
  [role="dialog"] > div {
    max-width:95vw !important;
    width:95vw !important;
    max-height:90vh !important;
    margin:0.5714rem !important;
  }
  .modal-body { padding:0.8571rem !important; }
  .modal-footer { padding:0.7143rem 0.8571rem !important; }
}

/* ── Mobile-friendly form layout — let form groups stack instead of forcing horizontal scroll ── */
@media (max-width: 640px) {
  .fl-group,
  .fl-group.w2,
  .fl-group.w3 {
    min-width:100% !important;
    flex-basis:100% !important;
  }
  .ep-fields { gap:0.7143rem !important; }
  .ep-content,
  .ep-top { padding-left:0.8571rem !important; padding-right:0.8571rem !important; }
  .ep-tabs { padding-left:0.8571rem !important; padding-right:0.8571rem !important; }
  .ep-bottom { padding-left:0.8571rem !important; padding-right:0.8571rem !important; }
}

/* ── Theme transition (only active during toggle, not on page load) ── */
body.theme-transitioning,
body.theme-transitioning *,
body.theme-transitioning *::before,
body.theme-transitioning *::after {
  transition: background-color 0.15s ease, color 0.1s ease, border-color 0.15s ease, box-shadow 0.15s ease !important;
}

/* ── Reset ──────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin:0; padding:0; }
/* Fluid base font-size — scales every rem-based value across the app
   smoothly with viewport width. Locked to a sensible range so the app
   never gets too tiny on small laptops or absurdly large on 4K monitors.
     Viewport width  →  base font-size
       1024px (small laptop)    13.0px
       1366px (HD laptop)       13.4px
       1600px (HD+)             14.0px
       1920px (1080p)           14.8px
       2560px (1440p)           16.0px (capped)
       3840px (4K)              16.0px (capped)
   Every padding/width/font-size declared in rem follows this curve, so
   the entire UI scales proportionally without per-resolution tuning. */
/* davidnotes4: ~10% smaller than the previous clamp(13px, 0.25vw+10px, 16px)
   because users were dropping browser zoom to 90% to fit more on screen. */
html { font-size: clamp(11.7px, 0.225vw + 9px, 14.4px); height: 100%; -webkit-text-size-adjust: 100%; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; }
body {
  font-family: var(--font);
  background: linear-gradient(160deg, #E8EAF0 0%, #ECEFF1 40%, #F0F2F5 100%);
  color: var(--text-primary);
  line-height: 1.6;
  margin:0;
  height:100%;
  overflow: hidden;
  font-feature-settings: 'kern' 1, 'liga' 1;
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ── Login Page ─────────────────────────────────────────────── */
.login-bg {
  min-height:100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #1a1a2e url('/login-bg.jpg') center/cover no-repeat;
  position: relative;
  overflow: hidden;
}
.login-bg::before {
  content: '';
  position: absolute;
  inset:0;
  background: rgba(0,0,0,0.35);
}
.login-card {
  /* Match the PTS Settings login card exactly (PageLogin.js: width 450, maxWidth
     95%, Material Card → 4px radius + standard elevation shadow). OMS uses a fluid
     clamp root font-size, so px keeps it aligned with the fixed-px sibling apps. */
  width:min(450px, 95vw);
  border-radius: 4px;
  overflow: hidden;
  box-shadow: 0 11px 15px -7px rgba(0,0,0,0.2), 0 24px 38px 3px rgba(0,0,0,0.14), 0 9px 46px 8px rgba(0,0,0,0.12);
  z-index: 1;
}
.login-header {
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-dark));
  padding:2.2857rem 2.8571rem 1.7143rem;
  text-align: center;
}
/* Login + reset-password Sign In button — use the deeper brand orange,
   not the lighter --primary that the rest of the app's primary buttons
   use. The login page is the brand identity surface. */
.login-body .btn-primary,
.reset-page .btn-primary {
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-dark));
  border-color: var(--brand-primary);
}
.login-body .btn-primary:hover,
.reset-page .btn-primary:hover {
  background: linear-gradient(135deg, var(--brand-primary-dark), var(--brand-primary-dark));
}
body.dark-mode .login-body .btn-primary,
body.dark-mode .reset-page .btn-primary {
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-dark));
  border-color: var(--brand-primary);
}
.login-header h1 {
  color: #fff;
  font-size:2rem;
  font-weight: 700;
  letter-spacing: 1px;
}
.login-header .subtitle {
  color: rgba(255,255,255,0.8);
  font-size:0.85rem;
  margin-top:0.2857rem;
}
.login-body {
  background: #fff;
  padding:2rem 2.8571rem 2.5rem;
  position: relative; /* anchors the bottom-left version stamp */
}
/* ── PTS-parity login fields ───────────────────────────────────────────────────
   Outlined inputs with a floating label that lifts onto the border on focus/fill
   (the Material outlined TextField look of the sibling PTS Settings app), keeping
   OMS's orange accent. The input needs placeholder=" " so :placeholder-shown
   drives the float. */
.login-body .login-field { position: relative; margin-bottom:1.5rem; }
.login-body .login-field > input {
  width:100%;
  padding:0.9286rem 0.8571rem;
  border:1px solid var(--border-color);
  border-radius:6px;
  font-size:0.95rem;
  font-family: var(--font);
  background:#fff;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.login-body .login-field.pw-row > input { padding-right:2.5rem; }
/* Hide the browser-native password reveal/clear glyphs (Edge ::-ms-reveal) so the
   field shows ONLY OMS's own eye toggle — not a double eye. */
.login-body .login-field > input::-ms-reveal,
.login-body .login-field > input::-ms-clear { display:none; }
.login-body .login-field > input:focus {
  outline:none;
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px rgba(var(--theme-rgb,216,67,21),0.12);
}
.login-body .login-field > label {
  position:absolute;
  left:0.6429rem;
  top:50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  font-size:0.95rem;
  pointer-events:none;
  background:#fff;
  padding:0 0.2857rem;
  transition: top 0.15s ease, transform 0.15s ease, color 0.15s ease, font-size 0.15s ease;
}
.login-body .login-field > input:focus + label,
.login-body .login-field > input:not(:placeholder-shown) + label {
  top:0;
  transform: translateY(-50%) scale(0.82);
  color: var(--text-muted);
  font-weight:500;
}
/* Orange accent only while the field is focused (PTS: muted label, primary on focus). */
.login-body .login-field > input:focus + label { color: var(--brand-primary); }
.login-brand {
  text-align: center;
  margin-bottom:1.4286rem;
  color: var(--text-secondary);
  font-size:0.8rem;
  font-weight: 600;
  letter-spacing: 0.5px;
}
.login-body .form-group { margin-bottom:1.1429rem; }
.login-body input[type="text"],
.login-body input[type="password"],
.login-body input[type="email"] {
  width:100%;
  padding:0.7143rem 1rem;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  font-size:0.95rem;
  font-family: var(--font);
  transition: border-color 0.2s;
}
.login-body input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(var(--theme-rgb,216,67,21),0.15);
}
.login-body .pw-row {
  position: relative;
}
.login-body .pw-toggle {
  position: absolute;
  right:0.7143rem;
  top:50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-muted);
  font-size:1.1rem;
}
.login-body .forgot {
  display: block;
  text-align: right;
  font-size:0.8rem;
  color: var(--text-secondary);
  margin-top:0.2857rem;
}
.login-body .forgot:hover { color: var(--primary); }
.btn-login {
  display: block;
  width:14.2857rem;
  margin:1.4286rem auto 0;
  padding:0.7143rem;
  /* Match the .login-header hero gradient (deep brand orange), not the
     lighter app --primary used everywhere else. The login page is the
     brand identity surface. */
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-dark));
  color: #fff;
  border: none;
  /* Square button to match the PTS Settings login (its black square LOGIN);
     OMS keeps the orange fill. */
  border-radius: 6px;
  font-size:0.95rem;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  cursor: pointer;
  transition: filter 0.2s;
  box-shadow: 0 2px 8px rgba(var(--theme-rgb,216,67,21),0.3);
}
.btn-login:hover { background: linear-gradient(135deg, var(--brand-primary-dark), var(--brand-primary-dark)); }
.login-version {
  color: var(--text-muted);
  font-size:0.75rem;
  margin-top:1.1429rem;
}
.login-error {
  background: var(--danger-light);
  color: var(--danger);
  padding:0.5714rem 0.8571rem;
  border-radius: 8px;
  font-size:0.85rem;
  margin-bottom:0.8571rem;
  display: none;
}
.login-error.show { display: block; }

/* MFA section on login */
.mfa-section { display: none; margin-top:1.1429rem; }
.mfa-section.show { display: block; }
.mfa-section input {
  text-align: center;
  letter-spacing: 8px;
  font-size:1.3rem;
  font-weight: 600;
}

/* PIN login section */
.pin-divider { border-top:1px solid rgba(255,255,255,0.15); margin:1.1429rem 0 0.8571rem; }
.pin-avatar { width:3.4286rem; height:3.4286rem; border-radius:50%; background:rgba(255,255,255,0.18); margin:0 auto 0.4286rem; display:flex; align-items:center; justify-content:center; }
.pin-avatar .icon { font-size:1.5rem; color:rgba(255,255,255,0.9); }
.pin-user-info { text-align:center; margin-bottom:0.8571rem; }
.pin-display-name { font-weight:600; font-size:0.9286rem; color:var(--text-on-primary); }
.pin-device-info { font-size:0.7143rem; color:rgba(255,255,255,0.5); margin-top:2px; }
.pin-boxes { display:flex; justify-content:center; gap:0.5714rem; margin-bottom:0.8571rem; }
.pin-box { width:3.1429rem; height:3.7143rem; border:2px solid rgba(255,255,255,0.3); border-radius:10px; display:flex; align-items:center; justify-content:center; font-size:1.5rem; font-weight:700; color:var(--text-on-primary); cursor:pointer; transition:border-color 0.2s, transform 0.15s, background 0.2s; background:rgba(255,255,255,0.05); }
.pin-box.filled { border-color:var(--primary); background:rgba(216,65,21,0.12); }
.pin-lockout { text-align:center; padding:0.7143rem; background:rgba(244,67,54,0.15); border-radius:8px; margin-bottom:0.7143rem; }
.pin-lockout .icon { font-size:1.1rem; vertical-align:middle; color:#f44336; }
.pin-lockout-msg { font-size:0.8571rem; color:#f44336; }
.pin-switch { font-size:0.7857rem; color:rgba(255,255,255,0.6); text-decoration:none; }
.pin-switch:hover { color:rgba(255,255,255,0.9); }
@keyframes pinShake { 0%,100%{transform:translateX(0)} 20%{transform:translateX(-12px)} 40%{transform:translateX(10px)} 60%{transform:translateX(-8px)} 80%{transform:translateX(6px)} }

/* Forgot password view */
.forgot-icon-wrap { width:4rem; height:4rem; border-radius:50%; background:rgba(var(--theme-rgb,216,67,21),0.1); display:flex; align-items:center; justify-content:center; margin:0 auto 0.8571rem; }
.forgot-icon-wrap .icon { font-size:1.8rem; color:var(--primary); }
.forgot-title { font-size:1.05rem; font-weight:700; color:var(--text-primary); margin-bottom:0.4286rem; }
.forgot-desc { font-size:0.8571rem; color:var(--text-muted); line-height:1.4; }
.forgot-msg { margin-top:0.8571rem; font-size:0.8571rem; padding:0.7143rem 1rem; border-radius:8px; text-align:center; }
.forgot-msg.error { background:#FFEBEE; color:#C62828; }
.forgot-msg.success { background:#E8F5E9; color:#2E7D32; }
body.dark-mode .forgot-msg.error { background:#4a2020; color:#ff8a80; }
body.dark-mode .forgot-msg.success { background:#1b3a1b; color:#81C784; }
.forgot-back { font-size:0.8571rem; color:var(--text-secondary); text-decoration:none; display:inline-flex; align-items:center; gap:0.2857rem; }
.forgot-back:hover { color:var(--primary); }

/* Login button loading state */
.btn-login { position:relative; overflow:hidden; }
.btn-login.loading { pointer-events:none; color:transparent; }
.btn-login.loading::after { content:''; position:absolute; top:50%; left:50%; width:1.2857rem; height:1.2857rem; margin:-0.6429rem 0 0 -0.6429rem; border:2px solid rgba(255,255,255,0.3); border-top-color:#fff; border-radius:50%; animation:spin 0.6s linear infinite; }
/* Version stamp bottom-left, matching the PTS Settings login. */
.login-version { color:var(--text-muted); font-size:0.75rem; position:absolute; left:1em; bottom:0.5em; margin:0; line-height:1; }

/* ── Top Navigation Bar ─────────────────────────────────────── */
.topbar {
  height:var(--topbar-height);
  /* Topbar locked to brand orange — never themed (davidnotes4 N5).
     background-color + explicit background-image:none guarantees no
     gradient or image residue from any prior rule or browser-injected
     style (e.g. rocket-loader). */
  background-color: var(--brand-primary);
  background-image: none;
  display: flex;
  align-items: center;
  padding:0 0.5714rem;
  box-shadow: 0 2px 12px rgba(0,0,0,0.15);
  position: fixed;
  top:0; left:0; right:0;
  z-index: 1000;
}
/* Far-left PTS brand mark (RMS top-nav parity). The pts-logo.png is the colored
   mark; brightness(0)+invert(1) renders it solid white for the orange bar. */
.topbar-brand {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  padding:0 0.6rem 0 0.2rem;
  margin-right:0.4rem;
  text-decoration: none;
}
.topbar-logo {
  height:1.7rem;
  width: auto;
  filter: brightness(0) invert(1);
}
.topbar-nav {
  display: flex;
  align-items: center;
  gap:0.4286rem;
  /* flex: 0 1 auto + min-width:0 → the container sizes to its content
     but is allowed to shrink (with overflow-x:auto kicking in to
     scroll) when total content exceeds the available width.
     PREVIOUSLY: flex:1 made the container stretch the full available
     width, so its right edge butted against .topbar-right with no
     breathing room. Now there's a natural gap between the last nav
     item and the right cluster. */
  flex: 0 1 auto;
  min-width:0;
  margin-right: 1.5rem;
}
.topbar-nav a,
.topbar-nav .nav-dropdown {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding:0.5rem 1.2143rem;
  color: var(--text-on-primary);
  text-decoration: none;
  font-size:0.75rem;
  font-weight: 500;
  border-radius: 10px;
  transition: background 0.15s;
  cursor: pointer;
  position: relative;
  white-space: nowrap;
  user-select: none;
}
.topbar-nav a:hover,
.topbar-nav .nav-dropdown:hover {
  background: rgba(255,255,255,0.15);
  text-decoration: none;
}
/* Active nav item: a clear bottom-bar indicator + bold label (RMS-style), instead
   of the translucent pill box. inset box-shadow draws the bar without shifting
   layout; a faint wash keeps it grounded. */
.topbar-nav a.active {
  background: rgba(255,255,255,0.10);
  border-radius: 8px 8px 0 0;
  font-weight: 700;
  box-shadow: inset 0 -3px 0 0 #fff;
}
.topbar-nav .nav-icon {
  font-size:1.5rem;
  margin-bottom:2px;
  line-height: 1;
  font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
}
.topbar-right {
  display: flex;
  align-items: center;
  gap:1rem;
  margin-left:auto;
  position: relative;
  z-index: 1;
  flex-shrink: 0;
}
.topbar-right .meta-dropdown {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  font-size:0.7rem;
  color: #fff;
}
.topbar-right .meta-dropdown .meta-label {
  font-size:0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  opacity: 0.92;
}
.tb-select {
  display: inline-flex;
  align-items: center;
  gap:2px;
  background-color: rgba(255,255,255,0.15);
  color: #fff;
  border: 1px solid rgba(255,255,255,0.25);
  border-radius: 8px;
  padding:0.2143rem 0.3571rem 0.2143rem 0.6429rem;
  font-size:0.78rem;
  font-family: var(--font);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.tb-select:hover { background-color: rgba(255,255,255,0.25); }
.tb-select-arrow { font-size:1rem; opacity: 0.7; }
.tb-select-menu {
  position: fixed;
  min-width:11.4286rem;
  background-color: #2a2a3d;
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.4);
  z-index: 3000;
  padding:0.2857rem 0;
  max-height:20rem;
  overflow-y: auto;
}
.tb-select-menu .tb-opt {
  display: block;
  padding:0.5714rem 1rem;
  color: #e0e0e0;
  font-size:0.8rem;
  cursor: pointer;
  white-space: nowrap;
}
.tb-select-menu .tb-opt:hover { background-color: rgba(255,255,255,0.1); }

/* ── Topbar burger + slide-in nav drawer ─────────────────────────
   At narrow viewports (≤1100px) the primary nav collapses behind a
   hamburger button on the left. Drawer is fixed-position, slides in
   from the left, and contains the same nav items vertically. The
   right cluster (clearance, agency, alerts, bulletin, user) stays
   visible the whole time. */
.topbar-burger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  margin-right: 0.4rem;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.2);
  color: var(--text-on-primary);
  border-radius: 8px;
  cursor: pointer;
  flex-shrink: 0;
}
.topbar-burger:hover { background: rgba(255,255,255,0.22); }

/* davidnotes4 #26: Back + auto-refresh moved into topbar right cluster
   so they don't claim a row of their own on dense pages like greaseboard. */
.topbar-btn-mini { padding: 0 0.5rem !important; gap: 0 !important; }
.topbar-btn-mini .btn-icon { font-size: 1.1rem !important; }
@keyframes oms-spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }
#auto-refresh-btn:not(:hover) #auto-refresh-dot { animation: oms-spin 6s linear infinite; }
body.dark-mode .oms-back-pill { background: rgba(255, 255, 255, 0.12); border-color: rgba(255, 255, 255, 0.18); }
body.dark-mode .oms-back-pill:hover { background: var(--primary); }
.topbar-burger .icon { font-size: 1.4rem; line-height: 1; }
.nav-drawer-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.45);
  z-index: 1499;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease;
}
.nav-drawer-overlay.open { opacity: 1; pointer-events: auto; }
.nav-drawer {
  position: fixed;
  top: 0; left: 0; bottom: 0;
  width: 18rem;
  max-width: 85vw;
  background: linear-gradient(180deg, var(--primary-dark) 0%, #2a2a3d 100%);
  box-shadow: 4px 0 24px rgba(0,0,0,0.4);
  z-index: 1500;
  transform: translateX(-105%);
  transition: transform 0.22s ease;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.nav-drawer.open { transform: translateX(0); }
.nav-drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.9rem 1rem;
  border-bottom: 1px solid rgba(255,255,255,0.12);
  background: rgba(0,0,0,0.15);
}
.nav-drawer-title {
  color: var(--text-on-primary);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}
.nav-drawer-close {
  background: transparent;
  border: 0;
  color: var(--text-on-primary);
  width: 2rem;
  height: 2rem;
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.nav-drawer-close:hover { background: rgba(255,255,255,0.15); }
.nav-drawer-list {
  display: flex;
  flex-direction: column;
  padding: 0.4rem 0.5rem;
  overflow-y: auto;
  gap: 2px;
}
.nav-drawer-list a,
.nav-drawer-list .nav-dropdown {
  display: flex;
  flex-direction: row !important;
  align-items: center !important;
  gap: 0.75rem;
  padding: 0.7rem 0.85rem !important;
  color: var(--text-on-primary);
  text-decoration: none;
  font-size: 0.9rem !important;
  font-weight: 500;
  border-radius: 8px;
  white-space: nowrap;
  cursor: pointer;
}
.nav-drawer-list a:hover,
.nav-drawer-list .nav-dropdown:hover { background: rgba(255,255,255,0.12); }
.nav-drawer-list a.active { background: rgba(255,255,255,0.22); }
.nav-drawer-list .nav-icon { font-size: 1.3rem !important; margin: 0 !important; }
.nav-drawer-list a span:last-child,
.nav-drawer-list .nav-dropdown span:last-child { font-size: 0.9rem; }
body.nav-drawer-open { overflow: hidden; }

/* ── Topbar responsive scaling ──────────────────────────────────
   Everything stays visible at every viewport — nav labels, icons,
   right-cluster meta labels, the whole bar. As width shrinks the
   typography/padding progressively tightens. If after all the
   tightening it STILL doesn't fit, .topbar-nav scrolls horizontally
   (thin styled scrollbar) — but nothing is hidden, dropped, or
   collapsed at any breakpoint. */
/* overflow-x stays `auto` as a silent safety net (content is still reachable by
   trackpad/shift-wheel if the nav ever overflows at a width above the JS burger-
   collapse floor), but the visible scrollbar chrome is hidden in every engine so
   the thin bar never shows across the top nav. The measurement-based
   `body.nav-collapsed` burger (useNavCollapse) remains the primary overflow path. */
.topbar-nav { overflow-x: auto; overflow-y: hidden; scrollbar-width: none; -ms-overflow-style: none; }
.topbar-nav::-webkit-scrollbar { width: 0; height: 0; display: none; }
.topbar-nav a,
.topbar-nav .nav-dropdown { flex-shrink: 0; }

@media (max-width: 1440px) {
  .topbar-nav a,
  .topbar-nav .nav-dropdown { padding: 0.45rem 0.85rem; }
  .topbar-nav .nav-icon { font-size: 1.35rem; }
  .topbar-btn { padding: 0.3rem 0.5rem; font-size: 0.66rem; }
  .topbar-btn .btn-icon { font-size: 1.1rem; }
}
@media (max-width: 1280px) {
  .topbar-nav a,
  .topbar-nav .nav-dropdown { padding: 0.4rem 0.65rem; font-size: 0.7rem; }
  .topbar-nav .nav-icon { font-size: 1.2rem; }
  .topbar-right { gap: 0.55rem; }
  .topbar-right .meta-dropdown .meta-label { font-size: 0.55rem; }
  .tb-select { padding: 0.18rem 0.32rem 0.18rem 0.5rem; font-size: 0.72rem; }
  .topbar-btn { padding: 0.25rem 0.4rem; font-size: 0.62rem; }
  .topbar-btn .btn-icon { font-size: 1rem; }
  .topbar-user { padding: 0.25rem 0.45rem; font-size: 0.7rem; }
  .topbar-user .avatar { width: 1.6rem; height: 1.6rem; }
}
/* Drawer-collapse mode is driven by JS (see _adjustNavCollapse) which
   measures the actual gap between .topbar-nav and .topbar-right and
   toggles body.nav-collapsed when they'd come within ~24px. This is
   resolution-agnostic — the burger kicks in based on real content
   widths, not a hard-coded breakpoint. */
body.nav-collapsed .topbar-nav { display: none !important; }
body.nav-collapsed .topbar-burger { display: inline-flex; }
@media (max-width: 1100px) {
  .topbar-right { gap: 0.4rem; }
  .topbar-right .meta-dropdown .meta-label { font-size: 0.5rem; }
  .tb-select { padding: 0.15rem 0.28rem 0.15rem 0.42rem; font-size: 0.68rem; }
  .topbar-btn { padding: 0.22rem 0.32rem; font-size: 0.58rem; }
  .topbar-btn .btn-icon { font-size: 0.92rem; }
  .topbar-user { padding: 0.22rem 0.35rem; font-size: 0.66rem; }
  .topbar-user .avatar { width: 1.4rem; height: 1.4rem; }
}
@media (max-width: 960px) {
  .topbar-right { gap: 0.3rem; }
  .tb-select { padding: 0.12rem 0.25rem 0.12rem 0.36rem; font-size: 0.64rem; }
  .topbar-btn { padding: 0.2rem 0.28rem; font-size: 0.55rem; }
  .topbar-btn .btn-icon { font-size: 0.85rem; }
  .topbar-user { padding: 0.2rem 0.3rem; font-size: 0.62rem; }
  .topbar-user .avatar { width: 1.25rem; height: 1.25rem; }
}
.tb-select-menu .tb-opt.active { color: #fff; background-color: var(--primary); }
.topbar-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  color: var(--text-on-primary);
  font-size:0.7rem;
  cursor: pointer;
  padding:0.3571rem 0.6429rem;
  border-radius: 10px;
  transition: background 0.15s;
  position: relative;
}
.topbar-btn:hover { background: rgba(255,255,255,0.15); }
.topbar-btn .btn-icon { font-size:1.2rem; line-height: 1; }
.topbar-btn .badge {
  position: absolute;
  top:0; right:2px;
  background: var(--danger);
  color: #fff;
  font-size:0.62rem;
  font-weight: 700;
  border-radius: 50%;
  width:1.2143rem; height:1.2143rem;
  display: flex;
  align-items: center;
  justify-content: center;
}
.topbar-user {
  display: flex;
  align-items: center;
  gap:0.5rem;
  color: #fff;
  font-size:0.82rem;
  cursor: pointer;
  padding:0.3571rem 0.6429rem;
  border-radius: 10px;
}
.topbar-user:hover { background: rgba(255,255,255,0.15); }
.topbar-user .avatar {
  width:2.4286rem; height:2.4286rem;
  border-radius: var(--radius-circle);
  background: rgba(255,255,255,0.3);
  display: flex;
  align-items: center;
  justify-content: center;
}
/* ── User menu items ── */
.um-item {
  display: flex;
  align-items: center;
  gap:0.8571rem;
  padding:0.7143rem 1.4286rem;
  color: var(--text-primary);
  font-size:0.85rem;
  text-decoration: none;
  cursor: pointer;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.um-item > select { max-width: 9rem; min-width: 0; }
.um-item:hover { background: #f5f5f5; text-decoration: none; }
.um-icon { font-size:1.1rem; width:1.5714rem; text-align: center; color: var(--text-muted); }
.um-app-icon { display:inline-flex; align-items:center; justify-content:center; width:1.5714rem; height:1.5714rem; }
.um-app-icon img { width:1.4rem; height:1.4rem; object-fit:contain; border-radius:4px; }

/* ── Dropdown menus from topbar ─────────────────────────────── */
.dropdown-menu {
  position: fixed;
  background: #fff;
  border: 1px solid var(--border-light);
  border-radius: 12px;
  box-shadow: var(--shadow-md);
  min-width:12.8571rem;
  z-index: 1001;
  padding:0.2857rem 0;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
}
.dropdown-menu.show { pointer-events: auto; visibility: visible; opacity: 1; }
.dropdown-menu a {
  display: block;
  padding:0.5714rem 1.1429rem;
  color: var(--text-primary);
  font-size:0.85rem;
}
.dropdown-menu a:hover {
  background: var(--info-light);
  text-decoration: none;
}
.dropdown-menu .divider {
  height:1px;
  background: var(--border-light);
  margin:0.2857rem 0;
}

/* ── Mega menu (Search dropdown — matches RMS pattern) ── */
.mega-menu {
  position: fixed;
  top:var(--topbar-height);
  left:0; right:0;
  background: #fff;
  border-bottom: 1px solid var(--border-light);
  border-radius: 0 0 16px 16px;
  box-shadow: var(--shadow-sm);
  padding:1.1429rem 2rem 1.4286rem;
  z-index: 999;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
}
.mega-menu.show { pointer-events: auto; visibility: visible; opacity: 1; }
.mega-menu-grid {
  display: flex;
  gap:2.8571rem;
}
.mega-menu-col h3 {
  font-size:0.85rem;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom:0.5714rem;
  padding-bottom:0;
  border: none;
  letter-spacing: 0;
  text-transform: none;
}
.mega-menu-col a {
  display: flex;
  align-items: center;
  gap:0.5714rem;
  padding:0.2143rem 0;
  color: var(--text-secondary);
  font-size:0.82rem;
  border-radius: 0;
}
.mega-menu-col a:hover {
  color: var(--primary);
  text-decoration: none;
  background: none;
}
.mega-menu-col .menu-dot {
  width:0.5714rem; height:0.5714rem;
  border-radius: 50%;
  background: var(--border-color);
  flex-shrink: 0;
}
.mega-menu-col a:hover .menu-dot {
  background: var(--primary);
}
.mega-menu-col .menu-icon {
  font-size: 1.15rem;
  width: 1.4rem;
  flex-shrink: 0;
  color: var(--text-muted);
  text-align: center;
  transition: color 0.1s;
}
.mega-menu-col a:hover .menu-icon {
  color: var(--primary);
}

/* Multi-column layout — wider columns, larger labels,
   more vertical breathing room, section labels instead of h3 headers */
.mega-menu-2col, .mega-menu-3col, .mega-menu-4col, .mega-menu-7col { gap: 2rem; max-width: 100%; margin: 0; }
.mega-menu-2col .mega-menu-col, .mega-menu-3col .mega-menu-col, .mega-menu-4col .mega-menu-col, .mega-menu-7col .mega-menu-col { flex: 1; min-width: 0; }
.mega-menu-2col .mega-menu-col a, .mega-menu-3col .mega-menu-col a, .mega-menu-4col .mega-menu-col a, .mega-menu-7col .mega-menu-col a {
  padding: 0.45rem 0.6rem;
  font-size: 0.92rem;
  gap: 0.75rem;
  border-radius: 6px;
}
.mega-menu-2col .mega-menu-col a:hover, .mega-menu-3col .mega-menu-col a:hover, .mega-menu-4col .mega-menu-col a:hover, .mega-menu-7col .mega-menu-col a:hover {
  background: rgba(var(--theme-rgb,216,67,21),0.06);
  color: var(--primary);
}
body.dark-mode .mega-menu-2col .mega-menu-col a:hover, body.dark-mode .mega-menu-3col .mega-menu-col a:hover, body.dark-mode .mega-menu-4col .mega-menu-col a:hover, body.dark-mode .mega-menu-7col .mega-menu-col a:hover {
  background: rgba(var(--theme-rgb,216,67,21),0.18);
}
.mega-menu-7col .mega-menu-col a {
  font-size: 0.85rem;
  padding: 0.4rem 0.5rem;
  gap: 0.55rem;
}
.mega-menu-7col .menu-icon { font-size: 1.05rem; width: 1.2rem; }

/* Filter input row at the top of the mega menu — border only, no fill */
.mega-menu-filter-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.6rem 0.85rem;
  margin-bottom: 1rem;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  background: transparent;
}
.mega-menu-filter-row:focus-within { border-color: var(--border-color); box-shadow: none; }
.mega-menu-filter-icon { font-size: 1.15rem; color: var(--text-muted); flex-shrink: 0; }
.mega-menu-filter-input {
  flex: 1;
  border: none;
  background: transparent;
  outline: none;
  font-size: 1rem;
  color: var(--text-primary);
  min-height: 0;
  padding: 0;
  line-height: 1.4;
}
.mega-menu-filter-input::placeholder { color: var(--text-muted); }
.mega-menu-filter-input:focus,
.mega-menu-filter-input:focus-visible,
body.dark-mode .mega-menu-filter-input:focus,
body.dark-mode .mega-menu-filter-input:focus-visible {
  outline: none;
  border-color: transparent;
  box-shadow: none;
}
.mega-menu-filter-hint {
  font-size: 0.7rem;
  color: var(--text-muted);
  white-space: nowrap;
  flex-shrink: 0;
}
body.dark-mode .mega-menu-filter-row {
  background: transparent;
  border-color: var(--border-color);
}
body.dark-mode .mega-menu-filter-input { color: var(--text-primary); }
.menu-spacer {
  display: block;
  height: 0;
  border-top: 1px solid var(--border-light);
  margin: 0.7rem 0.65rem;
}
.menu-section-label {
  display: block;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.08rem;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 0.85rem 0.65rem 0.35rem;
  margin-top: 0.25rem;
  border-top: 1px solid var(--border-light);
}
.mega-menu-col > .menu-section-label:first-child {
  border-top: none;
  padding-top: 0.15rem;
  margin-top: 0;
}
body.dark-mode .menu-section-label { color: rgba(200, 200, 210, 0.55); }

/* ── Main Content Area ──────────────────────────────────────── */
@keyframes fadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
@keyframes heartbeat-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(0, 230, 64, 0.6); }
  50% { box-shadow: 0 0 0 5px rgba(0, 230, 64, 0); }
}
.main-content {
  margin-top:var(--topbar-height);
  padding:0;
  height:calc(100vh - var(--topbar-height));
  overflow: auto;
  /* Theme wash — subtle radial tint of the active accent. Anchored at
     top-left so the eye reads "themed" without the chrome looking dirty.
     Falls through to bg-body when no theme tint is applied (default). */
  background:
    radial-gradient(ellipse 60% 40% at 0% 0%, var(--theme-bg-wash, transparent), transparent 70%),
    var(--bg-body);
}
body.dark-mode .main-content {
  background:
    radial-gradient(ellipse 60% 40% at 0% 0%, var(--theme-bg-wash, transparent), transparent 70%),
    var(--bg-body);
}

/* ── Toolbar (action bar below topbar) ──────────────────────── */
.toolbar {
  background: #fff;
  border-bottom: 1px solid var(--border-light);
  padding:0.5714rem 1.1429rem;
  display: flex;
  align-items: center;
  gap:0.5714rem;
  flex-wrap: wrap;
  position: sticky;
  top:0;
  z-index: 50;
}
body.dark-mode .toolbar {
  background: var(--bg-card);
}
.toolbar .toolbar-group {
  display: flex;
  align-items: center;
  gap:0.2857rem;
}
.toolbar .toolbar-sep {
  width:1px;
  height:1.7143rem;
  background: var(--border-color);
  margin:0 0.5714rem;
}
.toolbar .toolbar-search {
  margin-left:auto;
  display: flex;
  align-items: center;
  gap:0.2857rem;
}
.toolbar .toolbar-search input {
  padding:0.3571rem 0.7143rem;
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  font-size:0.85rem;
  width:17.1429rem;
  font-family: var(--font);
}
.toolbar .toolbar-search input:focus {
  outline: none;
  border-color: var(--primary);
}

/* ── Buttons ────────────────────────────────────────────────── */
/* ── Canonical button system ────────────────────────────────────
   FOUR semantic buckets, ZERO outline variants. The button background
   color IS the verb signal — icon stays white because the bg already
   conveys semantics. No per-verb icon coloring.
     .btn         — default theme (Save/Print/Cancel/Open/View/etc.)
     .btn-edit    — modify existing (blue)
     .btn-delete  — destroy/remove (red)
     .btn-add     — create new (green)
     .btn-icon    — modifier: square icon-only
     .btn-sm/.btn-lg — modifier: size
     .btn-block   — modifier: full-width
   Excluded from this system (their own design lives elsewhere):
   mobile (.m-btn), webjail (.wj-*), topbar chrome, dashboard
   quick-action cards (.qa-btn), toggle pills (.tab-btn / range / period),
   date picker (.dp-*), tag chrome, grid row actions (.row-action-*). */
.btn,
.btn-edit, .btn-delete, .btn-add,
.btn-primary, .btn-secondary, .btn-info, .btn-warning, .btn-danger, .btn-success,
.btn-save, .btn-save2, .btn-close2, .btn-close3, .btn-cancel, .btn-hist, .btn-close,
.btn-back, .btn-next, .btn-submit, .btn-log, .btn-log-hours,
.btn-export, .btn-new-req, .btn-add-shift, .btn-ip-save, .btn-ip-cancel,
.dr-btn, .dr-btn-outline, .cc-add-btn, .ip-add-btn, .ps-btn,
.inv-btn, .fl-btn, .fd-btn, .add-row-btn, .remove-row-btn,
.sd-qv-btn-open, .sd-qv-btn-rebook, .sd-qv-btn-close,
.gb-qv-btn-open, .gb-qv-btn-print,
.sr-qv-btn-open, .sr-qv-btn-print, .sr-btn, .sr-btn-outline, .sr-btn-secondary,
.us-back-btn, .us-pill-btn {
  display: inline-flex;
  align-items: center;
  gap:0.2857rem;
  padding:0.4286rem 1rem;
  border: 1px solid var(--primary) !important;
  border-radius: 6px;
  background: transparent !important;
  color: var(--primary) !important;
  font-size:0.82rem;
  font-family: var(--font);
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
  white-space: nowrap;
  font-weight: 500;
}
/* Hover fills solid for clear feedback. */
.btn:hover { background: var(--primary) !important; border-color: var(--primary) !important; color: #fff !important; }
.btn:active { filter: brightness(0.92); }
.btn .icon { color: inherit !important; }

/* Native file-input "Choose File" button → canonical .btn (theme outline) look.
   This control is a UA shadow-tree button that no className can reach — the
   ::file-selector-button pseudo-element is the ONLY styling hook. Applied
   globally so EVERY <input type="file"> in the app matches the design system
   instead of rendering browser-default chrome. The standard and legacy -webkit-
   pseudos are written as SEPARATE rules: if a browser doesn't recognise one,
   selector-list grouping would drop the whole rule, so they must not share a
   selector list. */
input[type="file"]::file-selector-button {
  display: inline-block;
  padding: 0.3571rem 0.8571rem;
  margin: 0 0.7143rem 0 0;
  border: 1px solid var(--primary);
  border-radius: 6px;
  background: transparent;
  color: var(--primary);
  font-size: 0.8rem;
  font-family: var(--font);
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
input[type="file"]::file-selector-button:hover {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
input[type="file"]::-webkit-file-upload-button {
  display: inline-block;
  padding: 0.3571rem 0.8571rem;
  margin: 0 0.7143rem 0 0;
  border: 1px solid var(--primary);
  border-radius: 6px;
  background: transparent;
  color: var(--primary);
  font-size: 0.8rem;
  font-family: var(--font);
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
input[type="file"]::-webkit-file-upload-button:hover {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

/* Verb modifiers (.btn-edit / .btn-delete / .btn-add) all alias to
   .btn (theme color outline). Distinguishing them by color was over-
   engineering — the user's actual model is "theme color everywhere
   except inside colored chrome where white wins" (see chrome
   override block below). The classes are kept so existing markup
   stays valid; they just produce the canonical theme look. */
.btn-edit, .btn-delete, .btn-add {
  background: transparent !important;
  border-color: var(--primary) !important;
  color: var(--primary) !important;
}
.btn-edit:hover, .btn-delete:hover, .btn-add:hover {
  background: var(--primary) !important;
  border-color: var(--primary) !important;
  color: #fff !important;
}
.btn-edit .icon, .btn-delete .icon, .btn-add .icon { color: inherit !important; }

/* Chrome-context override — buttons inside a colored chrome surface
   (section header, panel header, entity-picker header) flip to white
   outlined so they read against the colored bg instead of clashing
   with theme color. Pages can opt their own colored containers in by
   adding the container's class to this selector list. */
.section-actions .btn, .ep-header .btn, .gb-panel-header .btn,
.section-actions button.btn-add, .section-actions button.btn-edit, .section-actions button.btn-delete {
  background: rgba(255,255,255,0.18) !important;
  border-color: rgba(255,255,255,0.4) !important;
  color: #fff !important;
}
.section-actions .btn:hover, .ep-header .btn:hover, .gb-panel-header .btn:hover {
  background: rgba(255,255,255,0.32) !important;
  border-color: #fff !important;
  color: #fff !important;
}
.section-actions .btn .icon, .ep-header .btn .icon, .gb-panel-header .btn .icon { color: #fff !important; }

/* Modifiers (orthogonal — apply on top of the four buckets above) */
.btn-icon { padding: 0.4286rem; min-width: 2rem; min-height: 2rem; justify-content: center; }
.btn-block { width: 100%; }

/* ── Aliases — every legacy / per-page custom class produces canonical
   output. HTML stays untouched until the Session 2 grep-and-replace.
   Old delete-family (btn-danger, .remove-row-btn) -> red.
   Old add-family (btn-success) -> green.
   Everything else -> default theme. */
.btn-danger, .remove-row-btn {
  background: transparent !important; border-color: var(--danger) !important; color: var(--danger) !important;
}
.btn-danger:hover, .remove-row-btn:hover {
  background: var(--danger) !important; border-color: var(--danger) !important; color: #fff !important;
}
.btn-danger .icon, .remove-row-btn .icon { color: inherit !important; }

.btn-success {
  background: transparent !important; border-color: #2E7D32 !important; color: #2E7D32 !important;
}
.btn-success:hover {
  background: #2E7D32 !important; border-color: #2E7D32 !important; color: #fff !important;
}
.btn-success .icon { color: inherit !important; }

.btn-primary, .btn-secondary, .btn-info, .btn-warning,
.btn-save, .btn-save2, .btn-close2, .btn-close3, .btn-cancel,
.btn-back, .btn-next, .btn-submit, .btn-log, .btn-log-hours,
.btn-export, .btn-new-req, .btn-add-shift, .btn-ip-save, .btn-ip-cancel,
.dr-btn, .dr-btn-outline, .cc-add-btn, .ip-add-btn, .ps-btn,
.inv-btn, .fl-btn, .fd-btn, .add-row-btn,
.sd-qv-btn-open, .sd-qv-btn-rebook, .sd-qv-btn-close,
.gb-qv-btn-open, .gb-qv-btn-print,
.sr-qv-btn-open, .sr-qv-btn-print, .sr-btn, .sr-btn-outline, .sr-btn-secondary,
.us-back-btn, .us-pill-btn {
  background: transparent !important;
  border-color: var(--primary) !important;
  color: var(--primary) !important;
}
.btn-primary:hover, .btn-secondary:hover, .btn-info:hover, .btn-warning:hover,
.btn-save:hover, .btn-save2:hover, .btn-close2:hover, .btn-close3:hover,
.btn-cancel:hover, .btn-back:hover, .btn-next:hover, .btn-submit:hover,
.btn-log:hover, .btn-log-hours:hover, .btn-export:hover, .btn-new-req:hover,
.btn-add-shift:hover, .btn-ip-save:hover, .btn-ip-cancel:hover,
.dr-btn:hover, .dr-btn-outline:hover, .cc-add-btn:hover, .ip-add-btn:hover,
.ps-btn:hover, .inv-btn:hover, .fl-btn:hover, .fd-btn:hover, .add-row-btn:hover,
.sd-qv-btn-open:hover, .sd-qv-btn-rebook:hover, .sd-qv-btn-close:hover,
.gb-qv-btn-open:hover, .gb-qv-btn-print:hover,
.sr-qv-btn-open:hover, .sr-qv-btn-print:hover, .sr-btn:hover,
.sr-btn-outline:hover, .sr-btn-secondary:hover, .us-back-btn:hover,
.us-pill-btn:hover {
  background: var(--primary) !important;
  border-color: var(--primary) !important;
  color: #fff !important;
}
.btn-primary .icon, .btn-secondary .icon, .btn-info .icon, .btn-warning .icon,
.btn-save .icon, .btn-save2 .icon, .btn-close2 .icon, .btn-close3 .icon,
.btn-cancel .icon, .btn-back .icon, .btn-next .icon, .btn-submit .icon,
.btn-log .icon, .btn-log-hours .icon, .btn-export .icon, .btn-new-req .icon,
.btn-add-shift .icon, .btn-ip-save .icon, .btn-ip-cancel .icon,
.dr-btn .icon, .dr-btn-outline .icon, .cc-add-btn .icon, .ip-add-btn .icon,
.ps-btn .icon, .inv-btn .icon, .fl-btn .icon, .fd-btn .icon, .add-row-btn .icon,
.sd-qv-btn-open .icon, .sd-qv-btn-rebook .icon, .sd-qv-btn-close .icon,
.gb-qv-btn-open .icon, .gb-qv-btn-print .icon,
.sr-qv-btn-open .icon, .sr-qv-btn-print .icon, .sr-btn .icon,
.sr-btn-outline .icon, .sr-btn-secondary .icon, .us-back-btn .icon,
.us-pill-btn .icon { color: inherit !important; }
/* NOT in canonical alias (they own their own visual identity):
   .col-menu-btn (three-dots in grid header — span widget, opacity-only)
   .gb-split-btn (composite split-button, has greaseboard.html styling)
   .seal-btn (booking-detail header chrome)
   .btn-tiny / .btn-icon-only / .icon-btn (size/icon modifiers, no fill)
   .sr-view-btn / .pi-info-btn / .widget-hide-btn / .watch-check-photo-btn
     (small icon widgets)
   Toggle pills (.tab-btn / .sub-tab-btn / .an-period-btn / .dr-period-btn /
     .bd-sched-range-btn / .sd-sched-range-btn / .cc-range-btn /
     .prop-quick-btn) — these have .active state UI, not action buttons. */
/* ── Theme-aware variants — replace inline style="background:#xxx" overrides ──
   Use .btn-secondary for cancel / dismiss / "this is not the primary action"
   buttons; .btn-success for confirm / accept / approve. Both swap correctly
   between light and dark mode without needing inline overrides per call site. */
/* Legacy .btn-secondary / .btn-success duplicate definitions retired —
   the canonical block above (with !important) now owns these classes. */
/* Circle-button (header action) secondary variant — for X close / muted glyphs.
   Sits at half-strength of the default circle background so it visually recedes
   behind the primary action buttons in the same row. */
.ep-circle-btn-secondary { background: var(--text-muted) !important; }
body.dark-mode .ep-circle-btn-secondary { background: #4A5568 !important; }

/* ── Delete buttons — prominent, separated, with icon ── */
.btn-delete {
  background: transparent;
  color: var(--danger);
  border: 2px solid var(--danger);
  border-radius: 8px;
  padding:0.2857rem 0.8571rem;
  font-size:0.75rem;
  font-weight: 600;
  font-family: var(--font);
  cursor: pointer;
  transition: background 0.15s, color 0.15s, box-shadow 0.15s, transform 0.15s;
  display: inline-flex;
  align-items: center;
  gap:0.2857rem;
}
.btn-delete:hover {
  background: var(--danger);
  color: #fff;
  box-shadow: 0 2px 8px rgba(211,47,47,0.35);
  transform: translateY(-1px);
}
.btn-delete .icon { font-size:1rem; }
/* Icons inside buttons are sized centrally — don't repeat font-size on every <span class="icon"> in markup */
.btn .icon { font-size: 1rem; }
.btn-sm .icon { font-size: 0.9rem; }
body.dark-mode .btn-delete { border-color: #ef5350; color: #ef5350; }
body.dark-mode .btn-delete:hover { background: #ef5350; color: #fff; }
/* Legacy duplicate .btn-success retired — canonical owns it (outlined). */
.btn-sm { padding:0.2857rem 0.7143rem; font-size:0.78rem; }
.btn-icon-only { padding:0.4286rem 0.5714rem; }

/* ── Row action circle buttons (edit, delete, clear, print) ── */
.row-action {
  display: inline-flex; align-items: center; justify-content: center;
  width:2.7rem; height:2.7rem; border-radius: 50%; border: none;
  cursor: pointer; transition: background-color .15s, color .15s;
  padding:0; font-family: var(--font); position: relative;
}
.row-action .icon { font-size:1.4rem; line-height: 1; }
/* No hover transform/shadow — variant bg-fill is feedback enough and is GPU-cheap */
.row-action-edit { background: #E3F2FD; color: #1565C0; }
.row-action-edit:hover { background: #1565C0; color: #fff; }
.row-action-delete { background: var(--danger-light); color: var(--danger); }
.row-action-delete:hover { background: var(--danger); color: #fff; }
.row-action-clear { background: var(--success-light); color: var(--success); }
.row-action-clear:hover { background: var(--success); color: #fff; }
.row-action-print { background: rgba(var(--theme-rgb,216,67,21),0.10); color: var(--primary); }
.row-action-print:hover { background: var(--primary); color: #fff; }
.row-action-view { background: rgba(var(--theme-rgb,216,67,21),0.10); color: var(--primary); }
.row-action-view:hover { background: var(--primary); color: #fff; }
.row-actions { display: inline-flex; gap:0.8571rem; align-items: center; }
body.dark-mode .row-action-edit { background: #E3F2FD !important; color: #1565C0 !important; }
body.dark-mode .row-action-edit:hover { background: #1565C0 !important; color: #fff !important; }
body.dark-mode .row-action-delete { background: #FFEBEE !important; color: #D32F2F !important; }
body.dark-mode .row-action-delete:hover { background: #D32F2F !important; color: #fff !important; }
body.dark-mode .row-action-clear { background: #E8F5E9 !important; color: #2E7D32 !important; }
body.dark-mode .row-action-clear:hover { background: #2E7D32 !important; color: #fff !important; }
body.dark-mode .row-action-print { background: rgba(var(--theme-rgb,216,67,21),0.18) !important; color: var(--primary) !important; }
body.dark-mode .row-action-print:hover { background: var(--primary) !important; color: #fff !important; }
body.dark-mode .row-action-view { background: rgba(var(--theme-rgb,216,67,21),0.18) !important; color: var(--primary) !important; }
body.dark-mode .row-action-view:hover { background: var(--primary) !important; color: #fff !important; }

/* ── Split panel layout (tree + grid like old exe) ──────────── */
.split-layout {
  display: flex;
  height:calc(100vh - var(--topbar-height) - 3.2143rem);
}
.split-tree {
  width:18.5714rem;
  min-width:14.2857rem;
  background: #fff;
  border-right: 1px solid var(--border-light);
  overflow-y: auto;
  flex-shrink: 0;
}
.split-grid {
  flex: 1;
  overflow: auto;
  background: var(--bg-body);
  padding:0;
}

/* ── Tree View ──────────────────────────────────────────────── */
.tree-header {
  padding:0.7143rem 0.8571rem;
  font-weight: 700;
  font-size:0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  background: var(--primary);
  color: #fff;
  border-bottom: none;
  display: flex;
  align-items: center;
  gap:0.4286rem;
}
.tree-search {
  padding:0.5714rem;
}
.tree-search input {
  width:100%;
  padding:0.4286rem 0.7143rem;
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  font-size:0.82rem;
  font-family: var(--font);
}
.tree-search input:focus { outline: none; border-color: var(--primary); }
.tree-list { padding:0.2857rem 0; }
.tree-item {
  padding:0.4286rem 0.8571rem 0.4286rem 1.1429rem;
  font-size:0.83rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap:0.4286rem;
  color: var(--text-primary);
  transition: background 0.1s;
}
.tree-item:hover { background: var(--info-light); }
.tree-item.active { background: var(--info-light); color: var(--primary); font-weight: 600; }
.tree-item .tree-icon { font-size:0.9rem; width:1.2857rem; text-align: center; }
.tree-group {
  padding:0.5714rem 0.8571rem 0.2857rem 0.8571rem;
  font-size:0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  font-weight: 600;
}
.tree-item .tree-count {
  margin-left:auto;
  font-size:0.72rem;
  color: var(--text-muted);
  background: #ECEFF1;
  padding:1px 0.5rem;
  border-radius: 10px;
}

/* ── Data Grid / Table ──────────────────────────────────────── */
.data-grid {
  width:max-content;
  min-width:100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--bg-content);
  font-size:0.83rem;
  border-radius: 12px;
  border: 1px solid var(--border-light);
  box-shadow: var(--shadow-sm);
}
/* Ensure grids with action columns don't clip buttons */
.tab-panel, .ep-content, [id^="grid-"], [id$="-grid"], .ps-grid-wrap { overflow-x: auto; }
.data-grid thead th {
  background: #F5F5F5;
  border-bottom: 2px solid var(--border-color);
  padding:0.7143rem 0.8571rem;
  text-align: center;
  font-weight: 700;
  color: var(--text-secondary);
}
/* Filter row seamlessly connects to header — no gaps.
   padding-left/right must match the parent grid's header th padding
   so inputs align with column text above. sr-grid uses 10px, data-grid uses less. */
.grid-filter-row th {
  background: var(--bg-body);
  border: none;
  border-bottom: 1px solid var(--border-light);
  padding:0.2143rem 0.2857rem;
  line-height: 1;
  font-size:0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  position: sticky;
  top:0;
  z-index: 2;
  white-space: nowrap;
  cursor: default;
  user-select: none;
}
/* ── Search-grid (sr-grid) sticky header fix ──────────────────────────────────
   Stick the ENTIRE thead (column-header row + quick-filter row) as one unit, the
   way .gb-grid thead does. Previously ONLY .grid-filter-row th was sticky (top:0),
   so on scroll the dark filter cells detached from the column header and floated
   over the data rows as "black pieces". Both header rows need a solid background so
   scrolling content never shows through the sticky header. */
.sr-grid thead { position: sticky; top: 0; z-index: 3; }
.sr-grid thead tr:first-child th { background: var(--bg-content); }
.sr-grid .grid-filter-row th { position: static; top: auto; z-index: auto; }

/* ── Bulk multi-select action bar (#sr-grid-bulk-bar / .ms-bulk-bar) ───────────
   Was unstyled (inline display:flex only), so the "N rows selected" count and the
   .btn-sm actions jammed together with no spacing or vertical padding. */
.ms-bulk-bar { display: flex; align-items: center; flex-wrap: wrap; gap:0.5rem; padding:0.4286rem 0.2857rem; }
.ms-bulk-count { font-weight: 600; margin-right:0.2857rem; white-space: nowrap; }
/* Filter Editor dialog — cross-column AND/OR builder reached from the
   three-dots "Filter Editor…" item. Quick-filter row is a plain text
   input only; advanced operators live here. */
#filter-editor-overlay .fe-logic {
  display:inline-block; min-width:3rem;
  padding:0.2857rem 0.7143rem; font-size:0.82rem; font-weight:700;
  background: var(--primary); color:#fff;
  border:1px solid var(--primary); border-radius:4px; cursor:pointer;
}
#filter-editor-overlay .fe-logic:hover { background: var(--primary-dark, var(--primary)); }
#filter-editor-overlay .fe-row { display:flex; gap:6px; align-items:center; margin-bottom:6px; }
#filter-editor-overlay .fe-row select,
#filter-editor-overlay .fe-row input[type="text"] {
  padding:0.2857rem 0.5714rem; font-size:0.82rem; line-height:1.3;
  border:1px solid var(--border-color); border-radius:4px;
  background-color: var(--bg-content, #fff); color: var(--text-primary);
}
#filter-editor-overlay .fe-row .fe-col { min-width:10rem; }
#filter-editor-overlay .fe-row .fe-op  { min-width:10rem; }
#filter-editor-overlay .fe-row .fe-val { display:inline-flex; gap:4px; flex:1; min-width:0; align-items:center; }
#filter-editor-overlay .fe-row .fe-val input { flex:1; min-width:0; }
#filter-editor-overlay .fe-remove {
  width:1.7143rem; height:1.7143rem; border:1px solid var(--border-color); border-radius:4px;
  background: var(--bg-content, #fff); color: var(--danger, #D32F2F); cursor:pointer; font-size:1rem; line-height:1;
  display:inline-flex; align-items:center; justify-content:center; flex-shrink:0;
}
#filter-editor-overlay .fe-remove:hover { background: rgba(211,47,47,0.08); }
body.dark-mode #filter-editor-overlay .fe-remove { background: var(--bg-content); border-color: var(--border-color); }
#filter-editor-overlay .fe-add {
  border:1px dashed var(--border-color); background:transparent; color: var(--primary);
  padding:0.2857rem 0.7143rem; border-radius:4px; cursor:pointer; font-size:0.78rem;
  margin-top:6px;
}
#filter-editor-overlay .fe-add:hover { background: rgba(var(--theme-rgb,216,67,21),0.08); border-color: var(--primary); }

/* Print List button — auto-injected by shared.js into accordion section
   headers and panel headers that contain a grid. */
.ep-print-list-btn, .gb-panel-header .ep-print-list-btn {
  display:inline-flex; align-items:center; justify-content:center;
  width:1.7143rem; height:1.7143rem;
  margin-left:0.5714rem;
  background:transparent; color:inherit;
  border:1px solid var(--border-color); border-radius:4px;
  cursor:pointer; padding:0;
  vertical-align:middle;
}
.ep-print-list-btn:hover { background: rgba(var(--theme-rgb,216,67,21),0.1); border-color: var(--primary); color: var(--primary); }
body.dark-mode .ep-print-list-btn { border-color: var(--border-color); }
body.dark-mode .ep-print-list-btn:hover { background: rgba(var(--theme-rgb,216,67,21),0.2); border-color: var(--primary); }

/* Group-by header rows — inserted by shared.js _applyGrouping() when a
   column menu "Group By This Column" action fires. Clicking a header
   toggles the members collapsed/expanded. */
tr.grid-group-header {
  background: #eceff1 !important;
  cursor: pointer;
  user-select: none;
}
tr.grid-group-header:hover { background: #cfd8dc !important; }
tr.grid-group-header td.grid-group-cell {
  padding: 0.5rem 0.7143rem;
  font-size: 0.78rem;
  color: var(--text-primary);
  border-bottom: 1px solid var(--border-color);
  border-top: 1px solid var(--border-color);
}
.grid-group-arrow { display:inline-block; min-width:1em; color: var(--primary); font-weight: 700; }
.grid-group-count { color: var(--text-muted); font-weight: 500; margin-left: 0.2857rem; }
body.dark-mode tr.grid-group-header { background: var(--bg-card) !important; }
body.dark-mode tr.grid-group-header:hover { background: var(--bg-card) !important; }

/* Text selection colours — browser default ::selection in dark mode uses a
   blue highlight that can swallow already-white text. Pin to the app primary
   on a translucent background so highlighted text stays readable. */
::selection { background: rgba(var(--theme-rgb,216,67,21),0.3); color: var(--text-primary); }
body.dark-mode ::selection { background: rgba(var(--theme-rgb,216,67,21),0.45); color: #fff; }
/* sr-grid headers use 10px padding — filter cells must match so inputs align with column text */
.sr-grid .grid-filter-row th { padding:0.2143rem 0.7143rem; }
.sr-grid-wrap.view-compact .sr-grid .grid-filter-row th { padding:2px 0.5714rem; }
/* Filter row inputs/selects adopt the theme — no inline styles so
   dark-mode toggle is instant. min-height: auto explicitly clears
   the global :where() form-field rule (which sets min-height to
   2.2857rem for height parity); these tiny filter inputs WANT to
   stay short so the filter bar doesn't take up half the column header. */
.grid-filter-row input[type="text"],
.grid-filter-row select {
  width:100%;
  height:1.4286rem;
  min-height: auto;
  padding:1px 0.3571rem;
  font-size:0.65rem;
  line-height: 1;
  border: 1px solid #BBDEFB;
  border-radius: 6px;
  box-sizing: border-box;
  outline: none;
  background-color: #fff;
  color: #212121;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.grid-filter-row input[type="text"]:focus,
.grid-filter-row select:focus {
  border-color: #1976D2;
  box-shadow: 0 0 0 2px rgba(25,118,210,0.15);
}
body.dark-mode .grid-filter-row input[type="text"],
body.dark-mode .grid-filter-row select {
  background-color: #141620;
  color: #e0e0f0;
  border-color: var(--border-light);
}
body.dark-mode .grid-filter-row input[type="text"]:focus,
body.dark-mode .grid-filter-row select:focus {
  border-color: #5c9ce6;
  box-shadow: 0 0 0 2px rgba(92,156,230,0.2);
}
.data-grid tbody tr:nth-child(even) { background-color: rgba(0,0,0,0.02); }
body.dark-mode .data-grid tbody tr:nth-child(even) { background-color: rgba(255,255,255,0.02); }
.data-grid thead th:first-child { border-radius: 10px 0 0 0; }
.data-grid thead th:last-child { border-radius: 0 10px 0 0; }
.col-resize-handle {
  position: absolute;
  right:0;
  top:0;
  bottom:0;
  width:0.3571rem;
  cursor: col-resize;
  background: transparent;
  z-index: 2;
  opacity: 0;
  transition: opacity 0.15s;
}
th:hover > .col-resize-handle,
.col-resize-handle:active {
  background: var(--primary);
  opacity: 0.5;
}
.col-menu-btn {
  opacity: 0 !important;
  transition: opacity 0.15s;
}
th:hover > .col-menu-btn {
  opacity: 0.6 !important;
}
.data-grid thead th:hover { background: #EEEEEE; }
body.dark-mode .data-grid thead th:hover { background: var(--bg-card); }
.data-grid thead th .sort-icon {
  font-size:0.65rem;
  margin-left:0.2857rem;
  opacity: 0.4;
}
.data-grid thead th.sorted .sort-icon { opacity: 1; color: var(--primary); }
.data-grid tbody tr {
  border-bottom: 1px solid var(--border-light);
  transition: background-color 0.12s ease, border-left 0.12s ease;
}
.data-grid tbody tr:hover { background: rgba(var(--theme-rgb,216,67,21),0.04); border-left: 3px solid var(--primary); }
.data-grid tbody tr.selected { background: rgba(var(--theme-rgb,216,67,21),0.08); }
.data-grid tbody tr.flagged { background: rgba(211,47,47,0.06); }
.data-grid tbody td {
  padding:0.5714rem 0.8571rem;
  text-align: center;
  vertical-align: middle;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width:17.8571rem;
}
.data-grid tbody td .mugshot-thumb {
  width:2.2857rem;
  height:2.2857rem;
  border-radius: 8px;
  object-fit: cover;
  vertical-align: middle;
}

/* ── Status Badges ──────────────────────────────────────────── */
.badge-status {
  display: inline-block;
  padding:0.2857rem 1rem;
  border-radius: 20px;
  font-size:0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.badge-active      { background: var(--success-light); color: var(--success); }
.badge-released    { background: var(--info-light);    color: var(--info); }
.badge-processing  { background: var(--warning-light); color: var(--warning); }
.badge-hold        { background: var(--danger-light);  color: var(--danger); }

/* ── Pill Badges ───────────────────────────────────────────── */
.badge { display: inline-flex; align-items: center; gap:0.2857rem; padding:2px 0.7143rem; border-radius: 20px; font-size:0.7rem; font-weight: 600; letter-spacing: 0.02em; }
.badge-active { background: rgba(76,175,80,0.12); color: #2E7D32; }
.badge-hold { background: rgba(244,67,54,0.12); color: #C62828; }
.badge-pending { background: rgba(255,152,0,0.12); color: #E65100; }
.badge-info { background: rgba(33,150,243,0.12); color: #1565C0; }

/* ── Cards ──────────────────────────────────────────────────── */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  border-radius: 12px;
  box-shadow: var(--shadow-md);
  transition: transform 0.15s ease, box-shadow 0.2s ease;
}
.card:hover { transform: translateY(-1px); box-shadow: var(--shadow-md); }
.card-header {
  padding:0.8571rem 1.1429rem;
  background: linear-gradient(135deg, var(--primary), var(--primary-dark));
  color: #fff;
  border-bottom: none;
  border-radius: 12px 12px 0 0;
  font-weight: 700;
  font-size:0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  display: flex;
  align-items: center;
  gap:0.5714rem;
}
.card-body { padding:1.1429rem; }
/* Cards whose body wraps a .data-grid (admin Activity tab — Who's Online /
   Most Active Users / Recent Changes; admin Telemetry tab; daily-reports)
   set inline padding:0 so the table can extend visually to the card edges.
   The result is the table kisses the colored card header and the right
   border. This single rule (scoped via :has() to card-bodies that directly
   contain a data-grid) gives consistent breathing room everywhere — !important
   needed to defeat the inline padding:0 across multiple pages. */
.card > .card-body:has(> .data-grid),
.card > .card-body:has(> table.data-grid) {
  padding: 0.4286rem 0.5714rem 0.4286rem 0.5714rem !important;
}
/* Defensive: any inline color:var(--text-muted/--text-secondary) inside an
   orange-background header (card / modal / quick-view) gets overridden so
   muted-gray text never renders on the orange bar. Uses attribute-selector
   matching so future regressions are caught without having to find each
   inline style individually. (Lesson #211 family — header-context contrast.) */
.card-header [style*="--text-muted"],
.card-header [style*="--text-secondary"],
.modal-header [style*="--text-muted"],
.modal-header [style*="--text-secondary"],
.gb-qv-header [style*="--text-muted"],
.gb-qv-header [style*="--text-secondary"],
.sd-qv-header [style*="--text-muted"],
.sd-qv-header [style*="--text-secondary"] {
  color: rgba(255,255,255,0.88) !important;
}

/* ── Forms ──────────────────────────────────────────────────── */
.form-group { margin-bottom:0.7143rem; }
.form-group label {
  display: flex;
  align-items: center;
  gap:0.2857rem;
  font-size:0.75rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom:0.2143rem;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
/* Field hint tooltip — hidden icon, tooltip on label hover */
.field-hint { display: none; }
label[data-hint] {
  cursor: help;
  position: relative;
}
label[data-hint]::after {
  content: attr(data-hint);
  position: absolute;
  bottom:calc(100% + 0.4286rem);
  left:0;
  background: #333;
  color: #fff;
  padding:0.4286rem 0.7143rem;
  border-radius: 6px;
  font-size:0.75rem;
  font-weight: 400;
  white-space: normal;
  width:max-content;
  max-width:18.5714rem;
  line-height: 1.4;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s;
  z-index: 1000;
  box-shadow: 0 4px 12px rgba(0,0,0,0.2);
  text-transform: none;
  letter-spacing: 0;
}
label[data-hint]::before {
  content: '';
  position: absolute;
  bottom:calc(100% + 2px);
  left:0.8571rem;
  border: 4px solid transparent;
  border-top-color: #333;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s;
  z-index: 1000;
}
label[data-hint]:hover::after,
label[data-hint]:hover::before { opacity: 1; }
body.dark-mode label[data-hint]::after { background: var(--text-secondary); color: var(--bg-content); }
body.dark-mode label[data-hint]::before { border-top-color: var(--text-secondary); }
/* Field-hint flip inside modals: the bubble normally renders ABOVE the label,
   but `.modal-body { overflow-y:auto }` (one axis auto forces the other to
   compute as auto -> a clip rect) cuts it off under the gradient `.modal-header`
   for FIRST-ROW labels. Flip just those below so they escape the top clip edge.
   Lower rows keep the default above-placement (legacy parity). */
.modal-body .form-row:first-child label[data-hint]::after,
.modal-body > .form-group:first-child label[data-hint]::after {
  bottom: auto;
  top: calc(100% + 0.4286rem);
}
.modal-body .form-row:first-child label[data-hint]::before,
.modal-body > .form-group:first-child label[data-hint]::before {
  bottom: auto;
  top: calc(100% + 2px);
  border-top-color: transparent;
  border-bottom-color: #333;
}
body.dark-mode .modal-body .form-row:first-child label[data-hint]::before,
body.dark-mode .modal-body > .form-group:first-child label[data-hint]::before {
  border-top-color: transparent;
  border-bottom-color: var(--text-secondary);
}
/* ── Global form field height parity (lesson #105 — final pass) ───
   Every <input>, <select>, and <textarea> in the app gets the same
   line-height and min-height so input vs select height never diverges.
   Wrapped in :where() so the selector has ZERO specificity — any
   per-page or per-class rule (.form-control, .fl-group input,
   .bi-inp, etc.) can still override it freely without !important.

   This catches every form field that doesn't go through .form-control
   or .fl-group: bulk-intake (.bi-inp), admin user editor, print
   template editor, and any future custom-class modal field. */
:where(input[type="text"], input[type="number"], input[type="email"],
       input[type="password"], input[type="date"], input[type="datetime-local"],
       input[type="time"], input[type="search"], input[type="tel"],
       input[type="url"], input:not([type]),
       select, textarea) {
  line-height: 1.3;
  min-height: 2.2857rem;
  box-sizing: border-box;
}
:where(textarea) { min-height: 4rem; line-height: 1.4; }

.form-control {
  width:100%;
  padding:0.5rem 0.7143rem;
  border: 1px solid var(--border-color);
  border-radius: 6px;
  font-size:0.84rem;
  font-family: var(--font);
  /* Explicit line-height + min-height so <input> and <select> render at the
     same vertical size. body inherits line-height:1.6, which <input> honors
     but <select> ignores in favor of an internal ~1.2 — that mismatch makes
     inputs look "fatter" than selects on larger displays. (Lesson #105) */
  line-height: 1.3;
  min-height:2.2857rem;
  box-sizing: border-box;
  transition: border-color 0.15s, box-shadow 0.15s;
  background-color: var(--bg-content);
  color: var(--text-primary);
}
textarea.form-control { min-height:4rem; line-height: 1.4; }
.form-control:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 2px rgba(var(--theme-rgb,216,67,21),0.15);
}
.form-control::placeholder { color: var(--text-muted); opacity: 0.7; }
.form-control[disabled],
.form-control[readonly] {
  background-color: #f0f0f0;
  color: var(--text-primary);
  cursor: not-allowed;
  border-style: dashed;
}
body.dark-mode .form-control[disabled],
body.dark-mode .form-control[readonly] {
  background-color: #15182050;
  color: var(--text-primary);
  cursor: not-allowed;
  border-style: dashed;
}
/* Zero-specificity catch-all for fields outside .form-control / .fl-group
   so disabled + readonly styling stays consistent across modals, admin
   pages, quick-add forms, and anywhere bespoke classes are used. Matches
   the pattern of the line-height/min-height rule from lesson #111. */
:where(input[disabled], input[readonly], select[disabled], select[readonly], textarea[disabled], textarea[readonly]) {
  background-color: #f0f0f0;
  color: var(--text-primary);
  cursor: not-allowed;
}
body.dark-mode :where(input[disabled], input[readonly], select[disabled], select[readonly], textarea[disabled], textarea[readonly]) {
  background-color: #15182050;
  color: var(--text-primary);
}
select.form-control,
select {
  cursor: pointer;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-color: var(--bg-content);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23333' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding:0.5rem 2rem 0.5rem 0.7143rem !important;
  border: 1px solid var(--border-color);
  border-radius: 6px;
  font-size:0.84rem;
  font-family: var(--font);
  color: var(--text-primary);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
/* base-select only for topbar dropdowns (scoped to avoid 989 option warnings on form selects) */
.topbar select {
  appearance: base-select;
}
.topbar select::picker-icon { display: none; }
.topbar select::picker(select) {
  border-radius: 10px;
  border: 1.5px solid var(--border-color);
  background-color: var(--bg-content);
  box-shadow: 0 8px 24px rgba(0,0,0,0.18);
  padding:0.2857rem;
}
.topbar select option {
  border-radius: 6px;
  padding:0.5714rem 0.8571rem;
  margin:2px 0;
  font-size:0.82rem;
  background-color: var(--bg-content);
  color: var(--text-primary);
}
.topbar select option:hover {
  border-radius: 6px;
  background-color: var(--primary-light);
  color: #fff;
}
select option:checked,
select.form-control option:checked {
  border-radius: 6px;
  background-color: var(--primary);
  color: #fff;
}
select.form-control:focus,
select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(var(--theme-rgb,216,67,21),0.12), 0 2px 8px rgba(var(--theme-rgb,216,67,21),0.08);
}
select.form-control:hover,
select:hover { border-color: var(--primary-light); }
textarea.form-control {
  resize: vertical;
  min-height:4rem;
  border-radius: 6px;
}

/* ── Custom checkboxes — visible in both light & dark mode ── */
input[type="checkbox"] {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  width:1.2857rem;
  height:1.2857rem;
  border: 2px solid var(--border-color);
  border-radius: 5px;
  background: var(--bg-content);
  cursor: pointer;
  position: relative;
  flex-shrink: 0;
  transition: background 0.15s, border-color 0.15s;
  vertical-align: middle;
}
input[type="checkbox"]:hover {
  border-color: var(--primary);
}
input[type="checkbox"]:checked {
  background: var(--primary);
  border-color: var(--primary);
}
input[type="checkbox"]:checked::after {
  content: '';
  position: absolute;
  left:0.3571rem;
  top:1px;
  width:0.3571rem;
  height:0.7143rem;
  border: solid #fff;
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(45deg);
}
input[type="checkbox"]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(var(--theme-rgb,216,67,21),0.2);
}
body.dark-mode input[type="checkbox"] {
  background: var(--bg-content);
  border-color: #4a4d60;
}
body.dark-mode input[type="checkbox"]:hover {
  border-color: var(--primary);
}
body.dark-mode input[type="checkbox"]:checked {
  background: var(--primary);
  border-color: var(--primary);
}
.form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap:0.7143rem;
}
/* ── Checkbox-only containers: compact, don't stretch ── */
.check-only,
.form-group.check-only,
.fl-group.check-only,
div.fl-group.check-only,
div.form-group.check-only {
  flex: 0 0 auto !important;
  min-width:auto !important;
  width:auto !important;
  max-width:max-content !important;
  grid-column: auto !important;
}
.form-inline {
  display: flex;
  align-items: center;
  gap:0.5714rem;
}

/* ── Tabs ────────────────────────────────────────────────────── */
.tabs {
  display: flex;
  border-bottom: 2px solid var(--border-light);
  background: #fff;
  padding:0 1.1429rem;
}
.tab-btn {
  padding:0.7143rem 1.2857rem;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  margin-bottom:-2px;
  font-family: var(--font);
  font-size:0.88rem;
  color: var(--text-secondary);
  cursor: pointer;
  transition: color 0.12s, background 0.12s, border-color 0.12s;
  white-space: nowrap;
  position: relative;
}
.tab-btn:hover { color: var(--text-primary); background: rgba(0,0,0,0.05); }
.tab-btn.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
  font-weight: 700;
  background: rgba(var(--theme-rgb,216,67,21),0.04);
}
body.dark-mode .tab-btn:hover { background: rgba(255,255,255,0.06); }
body.dark-mode .tab-btn.active { background: rgba(var(--theme-rgb,255,87,34),0.08); }
.tab-content { display: none; padding:1.1429rem; }
.tab-content.active { display: block; }

/* ── Modal / Dialog ─────────────────────────────────────────── */
.modal-overlay {
  display: none;
  position: fixed;
  inset:0;
  /* DO NOT add backdrop-filter — it forces the browser to re-blur the
     entire viewport behind the overlay on every repaint. Every keystroke
     inside the modal triggers a cursor repaint, which re-runs the blur,
     which made typing in modals feel laggy app-wide. The slightly-deeper
     rgba background below is the perf-friendly substitute. */
  background: rgba(15,15,25,0.72);
  z-index: 2000;
  align-items: center;
  justify-content: center;
}
.modal-overlay.show { display: flex; }
.modal-box {
  background: var(--bg-card);
  border-radius: 10px;
  box-shadow: 0 16px 48px rgba(0,0,0,0.2), 0 4px 16px rgba(0,0,0,0.1);
  max-height:85vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  animation: modalEnter 0.15s ease forwards;
}
.modal {
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 16px 48px rgba(0,0,0,0.2), 0 4px 16px rgba(0,0,0,0.1);
  width:90%;
  max-width:42.8571rem;
  max-height:85vh;
  overflow: visible;
  display: flex;
  flex-direction: column;
  animation: modalEnter 0.15s ease forwards;
}
@keyframes modalEnter { from { opacity:0; transform: translateY(8px); } to { opacity:1; transform: translateY(0); } }
.modal-header {
  padding:0.7143rem 1.1429rem;
  background: linear-gradient(135deg, var(--primary), var(--primary-dark));
  color: #fff;
  font-weight: 600;
  font-size:0.88rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-radius: 10px 10px 0 0;
}
/* Base .modal-close style applies anywhere — modal headers, slide panels,
   custom widgets. The white-on-colored variant inside .modal-header
   overrides via the higher-specificity rule below. Without this base
   rule, .modal-close used in non-.modal-header contexts (perms panel,
   custom drawers) fell through to browser default and looked broken. */
.modal-close,
[class~="modal-close"],
[class*="-modal-close"] {
  background: transparent;
  border: 1px solid var(--border-light);
  color: var(--text-primary);
  font-size:1.5rem;
  font-weight: 600;
  cursor: pointer;
  opacity: 0.85;
  line-height: 1;
  width: 2rem; height: 2rem;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s, transform 0.12s, opacity 0.12s, border-color 0.12s;
  padding: 0;
}
.modal-close:hover,
[class~="modal-close"]:hover,
[class*="-modal-close"]:hover { background: var(--border-light); opacity: 1; transform: scale(1.05); border-color: var(--text-muted); }
.modal-close:active,
[class~="modal-close"]:active,
[class*="-modal-close"]:active { transform: scale(0.95); }
body.dark-mode .modal-close,
body.dark-mode [class~="modal-close"],
body.dark-mode [class*="-modal-close"] { color: var(--text-primary); border-color: var(--border-color); }
body.dark-mode .modal-close:hover,
body.dark-mode [class~="modal-close"]:hover,
body.dark-mode [class*="-modal-close"]:hover { background: rgba(255,255,255,0.08); }

/* Inside a colored modal-header, the X needs to be white on translucent
   white to read against the orange/dark gradient. Matches canonical AND
   custom *-modal-header variants. */
.modal-header .modal-close,
[class~="modal-header"] [class~="modal-close"],
[class~="modal-header"] [class*="-modal-close"],
[class*="-modal-header"] [class~="modal-close"],
[class*="-modal-header"] [class*="-modal-close"] {
  background: rgba(255,255,255,0.12);
  border: none;
  color: #fff;
  opacity: 0.95;
}
.modal-header .modal-close:hover,
[class~="modal-header"] [class~="modal-close"]:hover,
[class~="modal-header"] [class*="-modal-close"]:hover,
[class*="-modal-header"] [class~="modal-close"]:hover,
[class*="-modal-header"] [class*="-modal-close"]:hover { background: rgba(255,255,255,0.28); opacity: 1; transform: scale(1.05); border-color: transparent; }
.modal-header .modal-close:active,
[class~="modal-header"] [class~="modal-close"]:active,
[class~="modal-header"] [class*="-modal-close"]:active,
[class*="-modal-header"] [class~="modal-close"]:active,
[class*="-modal-header"] [class*="-modal-close"]:active { transform: scale(0.95); }
.modal-body { padding:1rem 1.1429rem; overflow-y: auto; min-height: 0; flex: 1; }
.modal-footer {
  padding:0.7143rem 1.1429rem;
  border-top: 1px solid var(--border-light);
  display: flex;
  justify-content: flex-end;
  gap:0.5714rem;
}

/* ── Status Badges (reusable across all pages) ─────────────── */
.badge-status { display:inline-block; padding:1px 0.4286rem; border-radius:8px; font-size:0.7rem; font-weight:600; line-height:1.6; }
.badge-danger  { background:#FFEBEE; color:#C62828; }
.badge-warning { background:#FFF3E0; color:#E65100; }
.badge-success { background:#E8F5E9; color:#2E7D32; }
.badge-info    { background:#E3F2FD; color:#1565C0; }
.badge-purple  { background:#F3E5F5; color:#7B1FA2; }
body.dark-mode .badge-danger  { background:rgba(198,40,40,0.15); color:#EF5350; }
body.dark-mode .badge-warning { background:rgba(230,81,0,0.15); color:#FFB74D; }
body.dark-mode .badge-success { background:rgba(46,125,50,0.15); color:#81C784; }
body.dark-mode .badge-info    { background:rgba(21,101,192,0.15); color:#64B5F6; }
body.dark-mode .badge-purple  { background:rgba(123,31,162,0.15); color:#CE93D8; }

/* ── Alert / Callout Boxes ─────────────────────────────────── */
.alert { padding:0.5714rem 0.8571rem; border-radius:var(--radius); font-size:0.7857rem; font-weight:600; margin-bottom:0.7143rem; }
.alert-warning { background:#FFF3E0; color:#E65100; border:1px solid #FFB74D; }
.alert-danger  { background:#FFEBEE; color:#C62828; border:1px solid #EF9A9A; }
.alert-success { background:#E8F5E9; color:#2E7D32; border:1px solid #A5D6A7; }
.alert-info    { background:#E3F2FD; color:#1565C0; border:1px solid #90CAF9; }
body.dark-mode .alert-warning { background:rgba(255,152,0,0.12); color:#FFB74D; border-color:rgba(255,152,0,0.3); }
body.dark-mode .alert-danger  { background:rgba(244,67,54,0.12); color:#EF5350; border-color:rgba(244,67,54,0.3); }
body.dark-mode .alert-success { background:rgba(76,175,80,0.12); color:#81C784; border-color:rgba(76,175,80,0.3); }
body.dark-mode .alert-info    { background:rgba(33,150,243,0.12); color:#64B5F6; border-color:rgba(33,150,243,0.3); }

/* ── Empty states ──────────────────────────────────────────── */
.empty-state { padding:2.1429rem 1.4286rem; text-align:center; color:var(--text-muted); font-size:0.8571rem; }
.empty-state .icon { font-size:1.7143rem; display:block; margin-bottom:0.4286rem; opacity:0.4; }

/* ── Hover list rows (search results, pickers, dropdowns) ──── */
.hover-row { transition:background 0.12s; }
.hover-row:hover { background:var(--hover-bg, rgba(0,0,0,0.04)); }
body.dark-mode .hover-row:hover { background:rgba(255,255,255,0.06); }
.hover-row-select:not([data-selected="1"]) { transition:background 0.12s; }
.hover-row-select:not([data-selected="1"]):hover { background:var(--info-light, rgba(33,150,243,0.08)); }

/* ── Pagination ─────────────────────────────────────────────── */
.pagination {
  display: flex;
  align-items: center;
  gap:0.2857rem;
  padding:0.7143rem 1.1429rem;
  font-size:0.82rem;
  background: #fff;
  border-top: 1px solid var(--border-light);
}
.pagination button {
  padding:0.2857rem 0.7143rem;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  background: #fff;
  cursor: pointer;
  font-family: var(--font);
  font-size:0.82rem;
}
.pagination button:hover { background: #f5f5f5; }
.pagination button.active {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
.pagination .page-info { margin-left:auto; color: var(--text-muted); font-size:0.78rem; }

/* ── Toast / Notification ───────────────────────────────────── */
.toast-container {
  position: fixed;
  top:4rem;
  left:50%;
  transform: translateX(-50%);
  z-index: 3000;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap:0.5714rem;
  pointer-events: none;
}
.toast {
  padding:0.8571rem 1.4286rem 0.8571rem 1.1429rem;
  border-radius: 10px;
  color: #fff;
  font-size:0.88rem;
  font-weight: 500;
  box-shadow: 0 4px 20px rgba(0,0,0,0.25);
  animation: toastSlideDown 0.3s ease;
  min-width:22.8571rem;
  max-width:40rem;
  display: flex;
  align-items: center;
  gap:0.7143rem;
  pointer-events: auto;
  cursor: pointer;
}
.toast:hover { opacity: 0.9; }
@keyframes toastSlideDown { from { opacity:0;transform:translateY(-20px); } to { opacity:1;transform:translateY(0); } }
.toast-exit { animation: toastFadeOut 0.3s ease forwards; }
@keyframes toastFadeOut { from { opacity:1;transform:translateY(0); } to { opacity:0;transform:translateY(-10px); } }
.toast-success { background: var(--success); }
.toast-error   { background: var(--danger); }
.toast-warning { background: var(--warning); }
.toast-info    { background: var(--primary); }
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }

/* ── Session Timeout Warning ────────────────────────────────── */
.timeout-banner {
  display: none;
  position: fixed;
  bottom:0; left:0; right:0;
  background: var(--warning);
  color: #fff;
  padding:0.7143rem 1.4286rem;
  text-align: center;
  font-size:0.9rem;
  font-weight: 600;
  z-index: 3000;
}
.timeout-banner.show { display: block; }

/* ── Utility ────────────────────────────────────────────────── */
.text-center { text-align: center; }
.text-right  { text-align: right; }
.text-muted  { color: var(--text-muted); }
.text-danger { color: var(--danger); }
.text-success{ color: var(--success); }
.mt-1 { margin-top:0.5714rem; }
.mt-2 { margin-top:1.1429rem; }
.mb-1 { margin-bottom:0.5714rem; }
.mb-2 { margin-bottom:1.1429rem; }
.p-2  { padding:1.1429rem; }
.gap-1 { gap:0.5714rem; }
.flex  { display: flex; }
.flex-col { flex-direction: column; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.w-full { width:100%; }
.hidden { display: none !important; }

/* ── Skeleton Loading Placeholders ──────────────────────────── */
@keyframes skeleton-pulse {
  0%   { opacity: 0.15; }
  50%  { opacity: 0.3; }
  100% { opacity: 0.15; }
}
@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}
.skeleton {
  background: var(--text-muted);
  border-radius: 4px;
  height:1rem;
  animation: skeleton-pulse 1.2s ease-in-out infinite;
}
.skeleton-table {
  display: flex;
  flex-direction: column;
  gap:0.7143rem;
  padding:0.5714rem 0;
}
.skeleton-row {
  display: flex;
  gap:0.8571rem;
}
.skeleton-row .skeleton {
  flex-shrink: 0;
}

/* ── Home page ──────────────────────────────────────────────── */
.home-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height:calc(100vh - var(--topbar-height));
  color: var(--text-secondary);
}
.home-center h1 { font-size:1.4rem; margin-bottom:1.1429rem; font-weight: 400; }
.home-logo {
  width:11.4286rem;
  height:11.4286rem;
  background: linear-gradient(135deg, var(--primary), var(--primary-dark));
  border-radius: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size:3rem;
  font-weight: 700;
  box-shadow: var(--shadow-md);
}
.home-logo span { font-size:1.5rem; vertical-align: sub; }

/* ── Dark Mode ──────────────────────────────────────────────── */
body.dark-mode {
  /* Dark palette tuned to feel like a designed dark theme, not pure black.
     Reference: GitHub dark (#0d1117/#161b22), Material 3 dark (#1c1b1f/
     #2b2930), Slack dark (#1a1d21). Each surface step is ~6-8% lighter
     than the previous so cards/modals/inputs read as distinct tiers
     without resorting to inset shadows.
     Steps: body → content → card → input, each ~6-8% lighter. */
  --bg-body:         #16191F;
  --bg-content:      #1E222B;
  --bg-card:         #262B36;
  --bg-input:        #2F3441;
  --border-color:    #5A6175;
  --border-light:    #4A5165;
  /* Bumped for readability — prior #c8ccd8 / #9aa0b5 read as washed-out
     against the dark surfaces. New values give body text ~12:1 and muted
     text ~7.5:1 contrast on --bg-body, comfortably above WCAG AA-large
     and approaching AAA for sustained reading. */
  --text-primary:    #F5F6FA;
  --text-secondary:  #DDE2EC;
  --text-muted:      #B5BBCB;
  --info-light:      rgba(var(--theme-rgb,216,67,21),0.18);
  --success:         #66BB6A;
  --danger:          #ef5350;
  --warning:         #FFA726;
  --warning-deep:    var(--primary);
  --info-blue:       #5C9EE7;
  --info-blue-light: rgba(92,158,231,0.15);
  --accent-purple:   #BA68C8;
  --accent-purple-light: rgba(186,104,200,0.18);
  --accent-pink:     #F06292;
  --danger-deep:     #EF5350;
  --danger-deeper:   #E53935;
  --shadow-sm:       0 1px 3px rgba(0,0,0,0.55), 0 1px 2px rgba(0,0,0,0.4);
  --shadow-md:       0 4px 10px rgba(0,0,0,0.55), 0 2px 4px rgba(0,0,0,0.35);
  --shadow-lg:       0 10px 28px rgba(0,0,0,0.65), 0 4px 10px rgba(0,0,0,0.45);
  background: var(--bg-body);
  /* Subpixel-AA renders light-on-dark text with a soft bloom; grayscale
     AA + a lighter synthetic weight keeps glyphs crisp without looking
     thin. Applied only in dark mode — light mode keeps subpixel AA. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
/* Topbar in dark mode — brighter gradient, bolder text */
body.dark-mode .topbar { background-color: var(--brand-primary); background-image: none; box-shadow: 0 2px 16px rgba(0,0,0,0.4); }
body.dark-mode .topbar-nav a,
body.dark-mode .topbar-nav .nav-dropdown { color: #fff; font-weight: 600; text-shadow: 0 1px 2px rgba(0,0,0,0.3); }
body.dark-mode .topbar-nav .nav-icon { color: #fff; }
body.dark-mode .topbar-nav a:hover,
body.dark-mode .topbar-nav .nav-dropdown:hover { background: rgba(255,255,255,0.20); }
body.dark-mode .topbar-nav a.active { background: rgba(255,255,255,0.30); }
body.dark-mode .topbar-btn { color: #fff; }
body.dark-mode .topbar-user { color: #fff; }

/* ── Data grids — clearer rows, better alternating, visible borders ── */
body.dark-mode .data-grid { background: var(--bg-content); color: var(--text-primary); }
body.dark-mode .data-grid thead th { background: var(--bg-card); color: var(--text-secondary); border-color: var(--border-color); font-weight: 600; }
body.dark-mode .grid-filter-row th { background: var(--bg-body); border: none; border-bottom: 1px solid var(--border-light); }
body.dark-mode .data-grid tbody tr { border-color: var(--border-light); }
body.dark-mode .data-grid tbody tr:nth-child(even) { background-color: rgba(255,255,255,0.03); }
body.dark-mode .data-grid tbody tr:hover { background: rgba(var(--theme-rgb,255,112,67),0.12); }
body.dark-mode .data-grid tbody tr.selected { background: rgba(var(--theme-rgb,255,112,67),0.20); }
body.dark-mode .data-grid tbody tr.flagged { background: rgba(198,40,40,0.22); border-left: 3px solid #ef5350; }
body.dark-mode .data-grid tbody td { color: var(--text-primary); border-color: var(--border-light); }

/* ── Toolbars, tabs, cards — subtle elevation differences ── */
body.dark-mode .toolbar { background: var(--bg-content); border-color: var(--border-color); }
body.dark-mode .tabs { background: var(--bg-content); border-color: var(--border-color); }
body.dark-mode .tab-btn { color: var(--text-secondary); }
body.dark-mode .tab-btn:hover { color: var(--text-primary); }
body.dark-mode .tab-btn.active { color: var(--primary); border-bottom-color: var(--primary); }
body.dark-mode .card { background: var(--bg-card); border-color: var(--border-color); box-shadow: var(--shadow-sm); }
body.dark-mode .card-header { background: var(--primary); color: #fff; }

/* ── Forms — deeper input wells for contrast against card backgrounds ── */
body.dark-mode .form-control { background-color: var(--bg-input); color: var(--text-primary); border-color: var(--border-color); }
body.dark-mode .form-control:focus { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(var(--theme-rgb,216,67,21),0.25); }
body.dark-mode select.form-control,
body.dark-mode select { background-color: var(--bg-input); color: var(--text-primary); border-color: var(--border-color); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23f0f0f5' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; }

/* Searchable-combo inputs (built by shared.js to replace native <select>) — theme-aware arrow */
.searchable-combo-input { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23333' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; }
body.dark-mode .searchable-combo-input { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23f0f0f5' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); }
body.dark-mode select.form-control option,
body.dark-mode select option { background: var(--bg-card); color: var(--text-primary); }
body.dark-mode .code-filter-input { background-color: var(--bg-input); color: var(--text-primary); border-color: var(--border-color); }

/* Legacy dark-mode .btn / .btn-primary overrides retired — canonical
   button system above (with !important) now owns these in both modes.
   var(--primary) is theme-aware and works on both light + dark page bgs. */

/* ── Links & interactive text ── */
body.dark-mode a { color: var(--primary-light); }
body.dark-mode a:hover { color: #FFAB91; }
/* Detail-page tab anchors (.ep-tabs a) are NOT prose links — they're nav
   tabs styled like buttons. The global dark-mode anchor rules above
   paint them brand-orange, which then highlights brand-orange on hover.
   Active tab keeps the brand color (selection indicator); inactive +
   hover use the standard text colors. */
body.dark-mode .ep-tabs a { color: var(--text-muted); }
body.dark-mode .ep-tabs a:hover { color: var(--text-primary); }
body.dark-mode .ep-tabs a.active { color: var(--primary); }
.ep-tabs a { color: var(--text-muted); }
.ep-tabs a:hover { color: var(--text-primary); text-decoration: none; }
.ep-tabs a.active { color: var(--primary); }
/* Anchors that sit on a colored header/banner background must stay
   high-contrast (white) regardless of theme — the colored bg already
   provides the contrast. Without these overrides, the global
   body.dark-mode a rule above paints them in --primary-light which
   washes into anything that uses --primary as its background. */
body.dark-mode .widget-header a,
body.dark-mode .card-header a,
body.dark-mode .panel-header a,
body.dark-mode .modal-header a,
body.dark-mode .topbar a,
body.dark-mode .topbar-nav a,
body.dark-mode .topbar-right a {
  color: #fff;
}
body.dark-mode .widget-header a:hover,
body.dark-mode .card-header a:hover,
body.dark-mode .panel-header a:hover,
body.dark-mode .modal-header a:hover {
  color: #fff;
  text-decoration: underline;
}
body.dark-mode .topbar a:hover,
body.dark-mode .topbar-nav a:hover,
body.dark-mode .topbar-right a:hover {
  color: #fff;
  text-decoration: none;
}
/* ── Detail-page section & field spacing ───────────────────── */
/* Ensure fields never touch section edges or overlap backgrounds */
/* Ep-section base — visible grouping that wraps a set of related fields/widgets.
   Previously several detail pages (booking, person, property, subject, warrant)
   shipped these properties only via the dark-mode override in body.dark-mode
   .ep-section, so the grouping was invisible in light mode. The other 10
   detail pages duplicated the rule in inline <style> blocks. Centralized here
   so light and dark modes both render the boxed look. Per-page <style> blocks
   that set the same properties still win via cascade order, so no regression. */
.ep-section {
  background: var(--bg-content);
  border: 1px solid var(--border-light);
  border-top: 3px solid var(--theme-stripe, var(--primary));
  border-radius: 12px;
  margin-bottom: 1.1429rem;
  padding:1.1429rem 1.2857rem;
  overflow: visible;
}
.ep-section-body { padding:1.2857rem; }
.ep-fields { gap:1rem 0.8571rem; }

/* Detail-page header counter cards (Activities / Bookings / etc.).
   Lived as inline <style> in booking-detail before; centralized so
   every detail page using the same markup renders identical cards. */
.ep-counters { display:flex; gap:0.2857rem; flex-wrap:wrap; }
.ep-counter {
  text-align:center;
  padding:0.2857rem 0.5714rem;
  min-width:4.2857rem;
  border:1px solid var(--border-light);
  border-radius: var(--radius);
  background: var(--bg-body);
}
.ep-counter .ec-label { font-size:0.58rem; color: var(--primary); font-weight:600; text-transform:uppercase; line-height:1.2; }
.ep-counter .ec-value { font-size:0.95rem; font-weight:700; line-height:1.2; }
body.dark-mode .ep-counter { background: var(--bg-body); border-color: var(--border-light); }
.fl-row { gap:1rem 1.4286rem; }
.tab-content { padding:1.4286rem; }
.card-body { padding:1.4286rem; }
.form-row { gap:0.7143rem; }

/* ── Float-label form fields (.fl-group) — single source of truth ─
   Every detail page used to inline its own copy of these rules with
   subtle variations in padding/font-size/focus/disabled/dark-mode
   styling, plus an asymmetric 10px-top / 6px-bottom padding that broke
   input vs <select> height parity at 1080p+ (lesson #105). Centralized
   here so the whole app renders form fields identically.

   Layout pattern:
     <div class="fl-group">
       <label>Field Name</label>            ← absolutely positioned over the
       <input class="..." />                  input border, top:-7px
     </div>

   The asymmetric padding is required so the floating label doesn't
   overlap the input's text content. Explicit line-height + min-height
   force <input>, <select>, and <textarea> to render at the same
   vertical box dimensions regardless of inherited line-height. */
.fl-group {
  position: relative;
  flex: 1;
  min-width:8.5714rem;
  margin-top:0.2857rem;
}
.fl-group.w2   { min-width:14.2857rem; }
.fl-group.w3   { min-width:20rem; }
.fl-group.full { flex-basis:100%; min-width:100%; }
.fl-group.check-only {
  flex: 0 0 auto !important;
  min-width:auto !important;
  width:auto !important;
  max-width:max-content !important;
}
.fl-group input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),
.fl-group select,
.fl-group textarea {
  width:100%;
  padding:0.7143rem 0.7143rem 0.4286rem;
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  font-size:0.83rem;
  font-family: var(--font);
  line-height: 1.3;
  min-height:2.4286rem;
  box-sizing: border-box;
  background-color: var(--bg-content);
  color: var(--text-primary);
  transition: border-color 0.15s, box-shadow 0.15s;
}
.fl-group select {
  /* Symmetric vertical padding for selects since they don't have a
     floating label overlapping their text — keeps the dropdown arrow
     vertically centered with the value text. */
  padding:0.5714rem 2rem 0.5714rem 0.7143rem;
}
.fl-group textarea {
  min-height:4.5714rem;
  line-height: 1.4;
  resize: vertical;
}
.fl-group input:not([type="checkbox"]):not([type="radio"]):focus,
.fl-group select:focus,
.fl-group textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(var(--theme-rgb,216,67,21),0.15);
}
/* Picker chip — replaces a search input when a record has been selected.
   Sizes itself to match fl-group inputs so the floating label and any
   sibling controls (like the inline "+" add button) stay aligned. */
.picker-chip {
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  padding: 0.7143rem 0.7143rem 0.4286rem;
  border: 1px solid var(--border-color);
  border-radius: var(--radius);
  font-size: 0.83rem;
  font-family: var(--font);
  line-height: 1.3;
  min-height: 2.4286rem;
  box-sizing: border-box;
  background-color: var(--bg-content);
  color: var(--text-primary);
}
.picker-chip.shown { display: flex; }
.picker-chip .picker-chip-name { font-weight: 600; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.picker-chip .picker-chip-remove {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4286rem;
  height: 1.4286rem;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--danger);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}
.picker-chip .picker-chip-remove:hover { background: rgba(220,53,69,0.12); }
/* Search input gets hidden via JS (input.style.display='none') when its
   chip is shown, since CSS ~ sibling selector only works forward and
   the chip can sit either above or below the input across pages. */
.fl-group input:not([type="checkbox"]):not([type="radio"])[disabled],
.fl-group input:not([type="checkbox"]):not([type="radio"])[readonly],
.fl-group select[disabled],
.fl-group select[readonly],
.fl-group textarea[disabled],
.fl-group textarea[readonly] {
  background-color: #f0f0f0;
  color: var(--text-primary);
  cursor: not-allowed;
  border-style: dashed;
}
.fl-group label {
  position: absolute;
  top:-0.5rem;
  left:0.5714rem;
  font-size:0.65rem;
  line-height: 1;
  color: var(--text-muted);
  background: var(--bg-content);
  padding:0.1429rem 0.2857rem;
  font-weight: 500;
  pointer-events: none;
  white-space: nowrap;
  max-width: calc(100% - 1.5rem);
  overflow: hidden;
  text-overflow: ellipsis;
  z-index: 1;
}
.fl-group > label input[type="checkbox"] { pointer-events: auto; }

body.dark-mode .fl-group input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),
body.dark-mode .fl-group select,
body.dark-mode .fl-group textarea {
  background-color: var(--bg-input);
  color: var(--text-primary);
  border-color: #5e667f;
  /* Lifted-surface treatment: input fill is now LIGHTER than the modal
     card (was darker, which made fields sink and feel like voids).
     A soft outer micro-shadow + faint top hairline mimics a glassy
     raised tile — the same visual hierarchy that makes light mode
     satisfying (clean borders, fields that announce themselves). */
  box-shadow:
    0 1px 0 rgba(255,255,255,0.03) inset,
    0 1px 2px rgba(0,0,0,0.25);
}
body.dark-mode .fl-group input:not([type="checkbox"]):not([type="radio"]):focus,
body.dark-mode .fl-group select:focus,
body.dark-mode .fl-group textarea:focus {
  border-color: var(--primary);
  /* Tighter, brighter focus ring — keeps the lifted-tile look while
     still announcing focus clearly. */
  box-shadow:
    0 0 0 3px rgba(var(--theme-rgb,255,112,67),0.22),
    0 1px 0 rgba(255,255,255,0.03) inset;
}
body.dark-mode .fl-group input:not([type="checkbox"]):not([type="radio"])[disabled],
body.dark-mode .fl-group input:not([type="checkbox"]):not([type="radio"])[readonly],
body.dark-mode .fl-group select[disabled],
body.dark-mode .fl-group select[readonly],
body.dark-mode .fl-group textarea[disabled],
body.dark-mode .fl-group textarea[readonly] {
  background-color: #232735;
  color: var(--text-muted);
  cursor: not-allowed;
  border-style: dashed;
  box-shadow: none;
}
body.dark-mode .fl-group select option { background: var(--bg-card); color: var(--text-primary); }
body.dark-mode .fl-group label { color: var(--text-secondary); background: var(--bg-content); }

/* ── Detail page sections — dark mode ─────────────────────────── */
/* (.fl-group input/select/textarea/label dark mode is in the
   centralized .fl-group block above this section.) */
body.dark-mode .ep-section { background: var(--bg-content); border-color: var(--border-color); }
body.dark-mode .ep-section-header { background: var(--primary); color: #fff; }
/* .ep-badge stays orange in dark mode (matches modal-header, ep-
   section-header, card-header, gb-panel-header — every other section
   header in the app keeps its primary color in both themes). The
   coloured variants (.red, .green) get muted-on-dark equivalents
   so the warning/success signal remains readable. */
body.dark-mode .ep-badge.red { background: #b71c1c; }
body.dark-mode .ep-badge.green { background: #2E7D32; }
body.dark-mode .ep-fields, body.dark-mode .ep-checks { color: var(--text-primary); }
body.dark-mode .ep-header { border-color: var(--border-color); background: var(--bg-card); }

/* ── Codes page ── */
body.dark-mode .codes-sidebar { background: var(--bg-content); border-color: var(--border-color); }
body.dark-mode .cat-item { color: var(--text-primary); }
body.dark-mode .cat-item:hover { background: rgba(var(--theme-rgb,255,112,67),0.10); }
body.dark-mode .table-item { color: var(--text-secondary); }
body.dark-mode .table-item:hover { background: rgba(var(--theme-rgb,255,112,67),0.08); }
body.dark-mode .table-item.active { background: rgba(var(--theme-rgb,255,112,67),0.18); color: var(--primary); }
body.dark-mode .codes-grid thead th { background: var(--bg-card); color: var(--text-secondary); }
body.dark-mode .codes-grid tbody td { color: var(--text-primary); }
body.dark-mode .codes-grid tbody td input, body.dark-mode .codes-grid tbody td select { background-color: var(--bg-input); color: var(--text-primary); border-color: var(--border-color); }
body.dark-mode .codes-toolbar { border-color: var(--border-color); }
body.dark-mode .codes-footer { border-color: var(--border-color); }
body.dark-mode .row-actions button { background: var(--bg-card); color: var(--text-primary); border-color: #4e5470; }
body.dark-mode .row-actions button:hover { background: #383e58; }

/* ── Search & incident sections ── */
body.dark-mode .ep-section-body { color: var(--text-primary); }
body.dark-mode .ps-search-row input, body.dark-mode .ps-search-row select { background-color: var(--bg-input); color: var(--text-primary); border-color: var(--border-color); }
body.dark-mode .ps-grid thead th { background: var(--bg-card); }

/* ── Modals ── */
body.dark-mode .modal-overlay { background: rgba(0,0,0,0.75); }
body.dark-mode .modal-overlay .modal { background: var(--bg-card); color: var(--text-primary); border: 1px solid #646a86; box-shadow: 0 24px 48px rgba(0,0,0,0.7), 0 12px 24px rgba(0,0,0,0.5); }
body.dark-mode .modal-overlay .modal input, body.dark-mode .modal-overlay .modal select, body.dark-mode .modal-overlay .modal textarea { background-color: var(--bg-input); color: var(--text-primary); border-color: var(--border-color); }
body.dark-mode .modal-header { border-color: var(--border-color); }
body.dark-mode .modal-footer { border-color: var(--border-color); }

/* ── Context menus & pickers ── */
body.dark-mode #col-context-menu { background: var(--bg-card); border-color: var(--border-color); color: var(--text-primary); box-shadow: var(--shadow-md); }
body.dark-mode #col-show-picker { background: var(--bg-card); border-color: var(--border-color); color: var(--text-primary); box-shadow: var(--shadow-md); }
body.dark-mode #col-filter-input { background-color: var(--bg-input); color: var(--text-primary); border-color: var(--primary); }

/* ── Scrollbars ── */
body.dark-mode ::-webkit-scrollbar { width:0.5714rem; height:0.5714rem; }
body.dark-mode ::-webkit-scrollbar-track { background: var(--bg-content); }
body.dark-mode ::-webkit-scrollbar-thumb { background: #4a5068; border-radius: 4px; }
body.dark-mode ::-webkit-scrollbar-thumb:hover { background: #646a86; }

/* ── Toast notifications ── */
body.dark-mode .toast { box-shadow: var(--shadow-md); }

/* ── Stat cards & badges — brighter in dark mode ── */
body.dark-mode .stat-card { background: var(--bg-card); border-color: var(--border-color); }
body.dark-mode .stat-card:hover { border-color: var(--primary); }
body.dark-mode .qa-btn { background: var(--bg-card); border-color: var(--border-color); color: var(--text-primary); }
body.dark-mode .qa-btn:hover { background: var(--primary); color: #fff; border-color: var(--primary); }

/* ── Mega menu ── */
body.dark-mode .mega-menu { background: var(--bg-content); border-color: var(--border-color); box-shadow: var(--shadow-lg); }
body.dark-mode .mega-section-title { color: var(--primary-light); }
body.dark-mode .mega-link { color: var(--text-secondary); }
body.dark-mode .mega-link:hover { color: var(--primary); background: rgba(var(--theme-rgb,255,112,67),0.10); }
/* (duplicate dark-mode .btn-primary retired — canonical owns it) */
body.dark-mode .modal { background: var(--bg-card); }
body.dark-mode .modal-body { color: var(--text-primary); }
body.dark-mode .mega-menu-col h3 { color: var(--text-primary); }
body.dark-mode .mega-menu-col a { color: var(--text-secondary); }
body.dark-mode .mega-menu-col a:hover { color: var(--accent); }
body.dark-mode .dropdown-menu { background: var(--bg-content); border-color: var(--border-color); border-radius: 12px; box-shadow: var(--shadow-md); }
body.dark-mode .dropdown-menu a { color: var(--text-primary); }
body.dark-mode .dropdown-menu a:hover { background: var(--bg-card); }
body.dark-mode .split-tree { background: var(--bg-card); }
body.dark-mode .split-tree .tree-header { background: var(--primary); color: #fff; }
body.dark-mode .tree-item { color: var(--text-primary); border-color: var(--border-light); }
body.dark-mode .tree-item:hover { background: var(--bg-card); }
body.dark-mode .tree-item.active { background: var(--bg-card); color: var(--accent); }
body.dark-mode .tree-group { color: var(--text-muted); }
body.dark-mode .pagination { background: var(--bg-content); border-color: var(--border-color); }
body.dark-mode .pagination button { background: var(--bg-card); color: var(--text-primary); border-color: var(--border-color); }
body.dark-mode .pagination button:hover { background: #363b4e; }
body.dark-mode .pagination button.active { background: var(--primary); color: #fff; }
body.dark-mode .home-center { color: var(--text-secondary); }
body.dark-mode .um-item { color: var(--text-primary); }
body.dark-mode .um-item:hover { background: var(--bg-card); }
/* User dropdown panel */
body.dark-mode #user-dropdown { background: var(--bg-content) !important; border-color: var(--border-light); }
body.dark-mode #user-dropdown div { color: var(--text-primary); }
body.dark-mode #user-dropdown button { background: #262940; color: var(--text-primary); border-color: var(--border-light); }
body.dark-mode #user-dropdown button:hover { background: var(--border-light); }
/* Modal header stays orange, modal overlay darken */
body.dark-mode .modal-overlay { background: rgba(5,5,15,0.75); }
body.dark-mode .modal-header { background: var(--primary); color: #fff; }
/* Form labels */
body.dark-mode .form-group label { color: var(--text-secondary); }
/* Login page */
body.dark-mode .login-bg { background: #0a0a14 url('/login-bg.jpg') center/cover no-repeat; }
body.dark-mode .login-body { background: var(--bg-content); color: var(--text-primary); }
body.dark-mode .login-body input { background-color: var(--bg-body); color: var(--text-primary); border-color: var(--border-light); }
body.dark-mode .login-brand { color: var(--text-muted); }
body.dark-mode .login-error { background: #4a2020; color: #ff8a80; }
/* Badge readability */
body.dark-mode .badge-active { background: #1b4332; color: #6fcf97; }
body.dark-mode .badge-released { background: #1a2a4a; color: #64b5f6; }
body.dark-mode .badge-processing { background: #4a3a10; color: #ffd54f; }
body.dark-mode .badge-hold { background: #4a1a1a; color: #ef9a9a; }
/* Toast */
body.dark-mode .toast { box-shadow: 0 2px 8px rgba(0,0,0,0.5); }
/* Scrollbar — light mode */
::-webkit-scrollbar { width:0.5714rem; height:0.5714rem; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 10px; border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); border: 2px solid transparent; background-clip: content-box; }
/* Scrollbar — dark mode */
body.dark-mode ::-webkit-scrollbar { width:0.5714rem; height:0.5714rem; }
body.dark-mode ::-webkit-scrollbar-track { background: transparent; }
body.dark-mode ::-webkit-scrollbar-thumb { background: var(--border-light); border-radius: 10px; border: 2px solid transparent; background-clip: content-box; }
body.dark-mode ::-webkit-scrollbar-thumb:hover { background: #5a5d72; border: 2px solid transparent; background-clip: content-box; }
/* Password change modal inline styles override */
body.dark-mode .pw-modal input { background-color: var(--bg-body); color: var(--text-primary); }
/* Catch-all for any input/select/textarea not already covered.
   Background is transparent so inputs blend into their containing
   surface (which has its own color) — only the border + text color
   are styled. Form fields use .form-control which has its own
   raised dark fill (var(--bg-input) = var(--bg-input)) and overrides this. */
body.dark-mode input, body.dark-mode select, body.dark-mode textarea { background-color: transparent; color: var(--text-primary); border-color: var(--border-light); }
body.dark-mode input:focus, body.dark-mode select:focus, body.dark-mode textarea:focus { border-color: var(--primary); outline: none; }
body.dark-mode select option { background: var(--bg-content); color: var(--text-primary); }
/* Detail page sections */
body.dark-mode .ep-header { background: var(--bg-content); border-color: var(--primary); }
body.dark-mode .ep-top { background: var(--bg-content); border-color: var(--border-light); color: var(--text-secondary); }
body.dark-mode .ep-bottom { background: var(--bg-content); border-color: var(--border-light); }
body.dark-mode .ep-hinfo h2 { color: var(--text-primary); }
body.dark-mode .ep-meta span { color: var(--text-secondary); }
/* Legacy dark-mode .btn-save / .btn-close2 overrides retired —
   canonical alias block owns these in both modes. */
/* Greaseboard */
body.dark-mode .gb-panel { border-color: var(--border-light); }
body.dark-mode .gb-panel-header { background: linear-gradient(135deg, var(--primary), var(--primary-dark)); color: #fff; border-color: var(--primary); }
body.dark-mode .gb-panel-toolbar { background: var(--bg-body); border-color: var(--border-light); }
body.dark-mode .gb-grid-wrap { background: var(--bg-body); }
body.dark-mode .gb-tree-item { color: var(--text-secondary); border-color: var(--bg-card); }
body.dark-mode .gb-tree-item:hover { background: var(--bg-card); }
body.dark-mode .gb-tree-children { border-color: var(--bg-card); }
/* Analytics */
body.dark-mode .an-card { background: var(--bg-content); border-color: var(--border-light); }
body.dark-mode .an-card.highlight { border-color: var(--primary); background: rgba(var(--theme-rgb,216,67,21),0.12); }
body.dark-mode .an-panel { background: var(--bg-content); border-color: var(--border-light); }
body.dark-mode .an-panel h3 { color: var(--text-primary); }
body.dark-mode .bar-track, body.dark-mode .occ-track { background: var(--bg-body); }
body.dark-mode .trend-date { color: var(--text-muted); }
body.dark-mode .rpt-cat { border-color: var(--border-light); color: var(--text-primary); }
body.dark-mode .rpt-cat:hover { background: var(--bg-card); }
body.dark-mode .rpt-item { color: var(--primary); border-color: var(--border-light); }
body.dark-mode .rpt-item:hover { background: var(--bg-card); }
/* Search page */
body.dark-mode .sr-page { color: var(--text-primary); }
body.dark-mode .sr-header h1 { color: var(--text-primary); }
body.dark-mode .sr-controls { color: var(--text-primary); }
body.dark-mode .sr-type-select { background-color: var(--bg-body); color: var(--text-primary); border-color: var(--border-light); }
body.dark-mode .sr-search-input { background-color: var(--bg-body); color: var(--text-primary); border-color: var(--border-light); }
body.dark-mode .sr-grid { background: var(--bg-content); }
body.dark-mode .sr-footer { border-color: var(--border-light); color: var(--text-muted); }
body.dark-mode .sr-filters { background: var(--bg-body); border-color: var(--border-light); }
body.dark-mode .sr-filter-group label { color: var(--text-secondary); }
/* Narrative cards */
body.dark-mode .narr-card { border-color: var(--border-light); }
body.dark-mode .narr-card div[contenteditable] { background: var(--bg-body); color: var(--text-primary); border-color: var(--border-light); }
/* Search-select modal */
body.dark-mode #ss-results { border-color: var(--border-light); background: var(--bg-body); }
body.dark-mode #ss-results > div { border-color: var(--bg-card); color: var(--text-primary); }

/* ── Dark mode pill badges ─────────────────────────────────── */
body.dark-mode .badge-active { background: rgba(76,175,80,0.2); color: #81C784; }
body.dark-mode .badge-hold { background: rgba(244,67,54,0.2); color: #EF9A9A; }
body.dark-mode .badge-pending { background: rgba(255,152,0,0.2); color: #FFB74D; }
body.dark-mode .badge-info { background: rgba(33,150,243,0.2); color: #90CAF9; }

/* ── Skeleton Loading ──────────────────────────────────────── */
.skeleton {
  background: linear-gradient(90deg, var(--border-light) 25%, var(--bg-content) 50%, var(--border-light) 75%);
  background-size: 200% 100%;
  animation: skeleton-pulse 1.5s ease-in-out infinite;
  border-radius: 6px;
  min-height:1.1429rem;
}
@keyframes skeleton-pulse {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
.skeleton-row { display: flex; gap:0.8571rem; padding:0.7143rem 0; }
.skeleton-row .skeleton { flex: 1; height:1rem; }
.skeleton-table { padding:1.1429rem; }
.skeleton-table .skeleton-row:first-child .skeleton { height:1.2857rem; opacity: 0.7; }

/* ── Section Label ─────────────────────────────────────────── */
.section-label { font-size:0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); margin-bottom:0.5714rem; }

/* ── Responsive ─────────────────────────────────────────────── */
/* The fluid base font-size on <html> (clamp(13px, 0.25vw + 10px, 16px))
   already scales every rem-based padding, gap, width, font-size, etc.
   smoothly across all viewport widths. The media queries below only
   handle layout reflow at major breakpoints (collapsing multi-column
   grids, hiding optional sidebars, capping content width on ultrawide
   monitors). They are NOT for tweaking sizes — sizes scale on their own. */

/* ── Tablet (1024px and below) ─────────────────────────────── */
@media (max-width: 1024px) {
  .mega-menu-grid { flex-wrap: wrap; }
  .mega-menu-col { min-width:45%; }
  .fl-row { gap:0.5714rem 0.8571rem; }
  .fl-group { min-width:8.5714rem; }
  .an-cards { grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap:0.5714rem; }
  .an-row { grid-template-columns: 1fr; }
  .codes-wrap { flex-direction: column; height:auto !important; }
  .codes-sidebar { width:100% !important; border-right: none; border-bottom: 1px solid var(--border-light); max-height:14.2857rem; overflow-y: auto; }
}

/* No ultrawide content cap — .main-content fills the full viewport
   width at every resolution. Earlier revisions tried to cap at
   2400px to prevent "sprawl" on ultrawide monitors but the user
   prefers full-screen content. The fluid base font-size (clamp on
   <html>) keeps proportions sane at any width without needing a
   hard cap. */

/* ── Aspect-ratio specific tweaks ────────────────────────────
   Ultrawide aspect ratios (≥21:9) get extra horizontal breathing room
   on the topbar and content padding. Tall/portrait orientations get
   tighter vertical rhythm so more content fits. */
@media (min-aspect-ratio: 21/9) {
  .ep-content { padding-left: clamp(1rem, 4vw, 4rem); padding-right: clamp(1rem, 4vw, 4rem); }
}
@media (max-aspect-ratio: 4/3) and (min-width: 768px) {
  .ep-section { margin-bottom: 0.75rem; padding-top: 0.85rem; padding-bottom: 0.85rem; }
  .ep-fields { gap: 0.85rem 0.7rem; }
}

/* ── Tags ─────────────────────────────────────────────────────── */
.tag-pills { display:flex; flex-wrap:wrap; align-items:center; gap:0.2857rem; }
.tag-pill { display:inline-flex; align-items:center; gap:0.2857rem; padding:0.2143rem 0.7143rem; border-radius:14px; font-size:0.72rem; font-weight:600; color:#fff; cursor:default; }
.tag-pill .tag-type-label { opacity:0.8; text-transform:uppercase; font-size:0.6rem; font-weight:400; }
.tag-delete { background:none; border:none; color:rgba(255,255,255,0.7); cursor:pointer; padding:0; font-size:0.75rem; line-height:1; }
.tag-delete:hover { color:#fff; }
.tag-add-btn { display:inline-flex; align-items:center; gap:0.2143rem; padding:0.2143rem 0.7143rem; border-radius:14px; font-size:0.7rem; font-weight:600; color:var(--text-muted); border:1px dashed var(--border-light); background:none; cursor:pointer; }
.tag-add-btn:hover { border-color:var(--primary); color:var(--primary); }
.tag-add-form { display:inline-flex; gap:0.4286rem; align-items:center; margin-top:0.4286rem; flex-wrap:wrap; max-width:100%; }
.tag-add-form select, .tag-add-form input { font-size:0.78rem; padding:0.2857rem 0.5714rem; border:1px solid var(--border-light); border-radius:var(--radius); background-color:var(--bg-content); color:var(--text-primary); }
.tag-typeahead { position:relative; }
.tag-typeahead-list { position:absolute; top:100%; left:0; right:0; min-width:14.2857rem; background:var(--bg-content); border:1px solid var(--border-light); border-radius:var(--radius); max-height:11.4286rem; overflow-y:auto; z-index:var(--z-dropdown); box-shadow:0 4px 12px rgba(0,0,0,0.15); }
body.dark-mode .tag-typeahead-list { background:var(--bg-card); border-color:#3d3d5c; }
.tag-typeahead-item { padding:0.4286rem 0.7143rem; cursor:pointer; font-size:0.78rem; }
.tag-typeahead-item:hover { background:var(--bg-body); }
.tag-typeahead-item .tag-count { color:var(--text-muted); font-size:0.68rem; margin-left:0.2857rem; }

/* ── Standardized action buttons (window.actionBtn helper) ───────
   One canonical style per action variant so every page renders Edit /
   Delete / Save / Open / etc. identically. The helper picks the icon +
   label + variant; this CSS owns the visuals. */
.oms-act { display:inline-flex; align-items:center; gap:0.4rem; padding:0.4rem 0.75rem; border-radius:6px; border:1px solid var(--border-color); background:var(--bg-content); color:var(--text-primary); font-size:0.85rem; cursor:pointer; transition:background 0.1s, color 0.1s, border-color 0.1s; font-family:var(--font); line-height:1.2; white-space:nowrap; position:relative; }
.oms-act:hover { background:var(--primary); color:#fff; border-color:var(--primary); }
.oms-act:disabled { opacity:0.5; cursor:not-allowed; }
.oms-act:disabled:hover { background:var(--bg-content); color:var(--text-primary); border-color:var(--border-color); }
.oms-act .icon { font-size:1.05rem; line-height:1; }
.oms-act-compact { padding:0.4rem; gap:0; min-width:2rem; min-height:2rem; justify-content:center; }
.oms-act-compact .oms-act-label { display:none; }
.oms-act-primary { background:var(--primary); color:#fff; border-color:var(--primary); }
.oms-act-primary:hover { background:var(--primary-dark); border-color:var(--primary-dark); }
.oms-act-success { background:#2E7D32; color:#fff; border-color:#2E7D32; }
.oms-act-success:hover { background:#1B5E20; border-color:#1B5E20; }
.oms-act-danger { color:var(--danger); border-color:var(--danger); background:var(--bg-content); }
.oms-act-danger:hover { background:var(--danger); color:#fff; border-color:var(--danger); }
body.dark-mode .oms-act { background:var(--bg-content); border-color:var(--border-light); color:#dde0ec; }
body.dark-mode .oms-act:hover { background:var(--primary); color:#fff; border-color:var(--primary); }
body.dark-mode .oms-act-primary { background:var(--primary); color:#fff; border-color:var(--primary); }
body.dark-mode .oms-act-success { background:#2E7D32; color:#fff; border-color:#2E7D32; }
body.dark-mode .oms-act-danger { background:var(--bg-content); color:#ef5350; border-color:#ef5350; }
body.dark-mode .oms-act-danger:hover { background:#ef5350; color:#fff; border-color:#ef5350; }
/* Group of action buttons — consistent spacing */
.oms-act-row { display:inline-flex; gap:0.5rem; align-items:center; flex-wrap:wrap; }

/* ── Legacy .act-auto-* shells (DEPRECATED — runtime decorator retained
   for now but produces canonical .btn output via these aliases). Future
   cleanup will remove these once all plain <button> elements get
   explicit class assignments. */
.act-auto, .act-auto-primary, .act-auto-print, .act-auto-view,
.act-auto-neutral, .act-auto-edit, .act-auto-danger, .act-auto-success {
  display:inline-flex; align-items:center !important; justify-content:center !important;
  gap:0.4rem; padding:0.35rem 0.55rem !important; border:1px solid var(--primary) !important;
  background:var(--primary) !important; color:#fff !important; border-radius:6px !important;
  cursor:pointer; line-height:1; min-width:2rem; min-height:2rem; font-weight:500;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.act-auto.act-auto-text { padding:0.45rem 0.85rem !important; min-width:auto; }
.act-auto .icon { font-size:1.05rem !important; line-height:1; vertical-align:middle; color:#fff !important; }
.act-auto-primary:hover, .act-auto-print:hover, .act-auto-view:hover,
.act-auto-neutral:hover, .act-auto:hover {
  background:var(--primary-dark) !important; border-color:var(--primary-dark) !important; color:#fff !important;
}
.act-auto-edit { background:#1565C0 !important; border-color:#1565C0 !important; }
.act-auto-edit:hover { background:#0D47A1 !important; border-color:#0D47A1 !important; }
.act-auto-danger { background:var(--danger) !important; border-color:var(--danger) !important; }
.act-auto-danger:hover { background:#B71C1C !important; border-color:#B71C1C !important; }
.act-auto-success { background:#2E7D32 !important; border-color:#2E7D32 !important; }
.act-auto-success:hover { background:#1B5E20 !important; border-color:#1B5E20 !important; }

button[data-act-needs-icon]::before {
  font-family: 'Material Icons';
  font-weight: normal; font-style: normal;
  font-size: 1.05rem;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  font-feature-settings: 'liga';
  -webkit-font-feature-settings: 'liga';
  vertical-align: middle;
  margin-right: 0.4rem;
  display: inline-block;
  content: var(--act-icon, '');
}

.act-auto[aria-label] { position:relative; }
/* Hide the hover-tooltip for text-labelled buttons — the label is already visible */
.act-auto-text[aria-label]::after, .act-auto-text[aria-label]::before { content:none !important; display:none !important; }
.act-auto[aria-label]::after {
  content: attr(aria-label);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: rgba(40, 44, 60, 0.96);
  color: #fff;
  font-size: 0.7rem;
  font-weight: 500;
  padding: 0.3rem 0.6rem;
  border-radius: 4px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease 0.2s, transform 0.15s ease 0.2s;
  z-index: 10000;
  box-shadow: 0 2px 8px rgba(0,0,0,0.18);
}
.act-auto[aria-label]:hover::after,
.act-auto[aria-label]:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ── Entity-picker circle action buttons (.ep-circle-btn) ────────
   Round icon buttons in detail-page headers (Edit Subject, Print Badge,
   Submit AFIS, Transfer, etc.). Used to be defined inline in 15 detail
   pages; now centralized here. Hover shows the fast tooltip with the
   button's purpose (the always-visible label experiment overflowed
   neighbors when buttons were close together — reverted). */
.ep-circle-btn { width:3.4rem; height:3.4rem; border-radius:50%; border:none; cursor:pointer; display:inline-flex; align-items:center; justify-content:center; color:#fff; background:var(--primary); box-shadow:0 2px 6px rgba(0,0,0,0.15); position:relative; transition:background 0.15s; }
.ep-circle-btn:hover { background:var(--primary-dark); }
.ep-circle-btn:active { filter:brightness(0.92); }
.ep-circle-btn .icon { font-size:1.5rem; line-height:1; }
/* Delete variant — replaces inline `style="background:var(--danger);..."` */
.ep-circle-btn-delete { background:var(--danger) !important; box-shadow:0 2px 8px rgba(211,47,47,0.4); }
.ep-circle-btn-delete:hover { background:#B71C1C !important; }

/* ── Fast hover tooltip for icon-only action buttons ─────────────
   Browser-native title="..." takes ~1.5s to appear and looks like an OS
   tooltip. This shows a fast (200ms delay), styled bubble using
   aria-label content, matching the app's look. Suppresses the slow
   native tooltip via title-removal in JS, but aria-label preserves
   accessibility. Add the .has-tip class to any element to opt in.
   .row-action, .ep-circle-btn, and .oms-act-compact opt in by default. */
.row-action[aria-label]::after,
.ep-circle-btn[aria-label]::after,
.oms-act-compact[aria-label]::after,
.has-tip[aria-label]::after {
  content: attr(aria-label);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: rgba(40, 44, 60, 0.96);
  color: #fff;
  font-size: 0.7rem;
  font-weight: 500;
  padding: 0.3rem 0.6rem;
  border-radius: 4px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease 0.2s, transform 0.15s ease 0.2s;
  z-index: 10000;
  box-shadow: 0 2px 8px rgba(0,0,0,0.18);
}
.row-action[aria-label]::before,
.ep-circle-btn[aria-label]::before,
.oms-act-compact[aria-label]::before,
.has-tip[aria-label]::before {
  content: '';
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: rgba(40, 44, 60, 0.96);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease 0.2s;
  z-index: 10000;
}
.row-action[aria-label]:hover::after,
.row-action[aria-label]:focus-visible::after,
.ep-circle-btn[aria-label]:hover::after,
.ep-circle-btn[aria-label]:focus-visible::after,
.oms-act-compact[aria-label]:hover::after,
.oms-act-compact[aria-label]:focus-visible::after,
.has-tip[aria-label]:hover::after,
.has-tip[aria-label]:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.row-action[aria-label]:hover::before,
.row-action[aria-label]:focus-visible::before,
.ep-circle-btn[aria-label]:hover::before,
.ep-circle-btn[aria-label]:focus-visible::before,
.oms-act-compact[aria-label]:hover::before,
.oms-act-compact[aria-label]:focus-visible::before,
.has-tip[aria-label]:hover::before,
.has-tip[aria-label]:focus-visible::before {
  opacity: 1;
}

/* ── Portal tooltip (JS-driven) ─────────────────────────────────
   When <html> has .oms-portal-tips (set by shared.js on load),
   suppress every CSS pseudo-element tooltip. The JS portal renders
   one shared tooltip element directly on <body> with position:fixed
   so it's never clipped by an ancestor's overflow/transform/filter
   stacking context. */
html.oms-portal-tips .row-action[aria-label]::after,
html.oms-portal-tips .row-action[aria-label]::before,
html.oms-portal-tips .ep-circle-btn[aria-label]::after,
html.oms-portal-tips .ep-circle-btn[aria-label]::before,
html.oms-portal-tips .oms-act-compact[aria-label]::after,
html.oms-portal-tips .oms-act-compact[aria-label]::before,
html.oms-portal-tips .has-tip[aria-label]::after,
html.oms-portal-tips .has-tip[aria-label]::before,
html.oms-portal-tips .act-auto[aria-label]::after,
html.oms-portal-tips .act-auto[aria-label]::before,
html.oms-portal-tips [aria-label][data-oms-tip]::after,
html.oms-portal-tips [aria-label][data-oms-tip]::before {
  content: none !important;
  display: none !important;
}

.oms-portal-tip {
  position: fixed;
  top: 0; left: 0;
  background: rgba(40, 44, 60, 0.96);
  color: #fff;
  font-size: 0.7rem;
  font-weight: 500;
  padding: 0.3rem 0.6rem;
  border-radius: 4px;
  white-space: nowrap;
  pointer-events: none;
  z-index: 2147483647;       /* max safe int — above every modal/overlay */
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.12s ease, transform 0.12s ease;
  box-shadow: 0 2px 8px rgba(0,0,0,0.18);
  font-family: var(--font, system-ui, sans-serif);
  line-height: 1.2;
  visibility: hidden;
}
.oms-portal-tip.visible {
  opacity: 1;
  transform: translateY(0);
  visibility: visible;
}
.oms-portal-tip-arrow {
  position: absolute;
  bottom: -5px;
  width: 0;
  height: 0;
  border: 5px solid transparent;
  border-top-color: rgba(40, 44, 60, 0.96);
  pointer-events: none;
  transform: translateX(-5px);
}
.oms-portal-tip.below .oms-portal-tip-arrow {
  bottom: auto;
  top: -5px;
  border-top-color: transparent;
  border-bottom-color: rgba(40, 44, 60, 0.96);
}
.oms-portal-tip-label { display: inline; }

/* ── Tooltip stacking lift ────────────────────────────────────────
   Pseudo-element tooltips on .row-action / .ep-circle-btn /
   .oms-act-compact / .has-tip render above the button via
   bottom:calc(100% + 6px). In tables and other multi-row layouts,
   the next DOM row paints on top of the current row's overflow,
   covering the tooltip even though z-index:10000 is set on the
   pseudo. The pseudo's z-index only applies within its parent's
   stacking context — so we lift the parent button's stacking
   context above its siblings on hover/focus. The host classes already
   carry position:relative; .has-tip is included defensively in case
   it's applied to a static element. */
.has-tip { position: relative; }
.row-action:hover, .row-action:focus-visible,
.ep-circle-btn:hover, .ep-circle-btn:focus-visible,
.oms-act-compact:hover, .oms-act-compact:focus-visible,
.has-tip:hover, .has-tip:focus-visible {
  z-index: 10001;
}
/* Hide native title tooltip in favor of our styled one — only for opted-in
   buttons (so we don't break custom title-based tooltips elsewhere). The
   JS helper auto-removes title="" attribute from these buttons at load
   time, but defending against new HTML that hasn't run through it yet. */

/* ── Universal disabled button state ─────────────────────────────
   Many existing buttons across the app render disabled buttons that
   look identical to enabled ones — no opacity drop, hover still
   triggers, click still appears interactive. This rule forces an
   obviously-disabled appearance everywhere without per-page changes.
   Targets all common patterns: <button disabled>, .btn:disabled,
   .sr-btn:disabled, .row-action:disabled, .ep-circle-btn:disabled,
   .oms-act:disabled, .act-auto:disabled, .has-tip:disabled. */
button:disabled,
button[aria-disabled="true"],
.btn:disabled,
.sr-btn:disabled, .sr-btn-outline:disabled,
.row-action:disabled,
.ep-circle-btn:disabled,
.oms-act:disabled,
.act-auto:disabled,
.has-tip:disabled {
  opacity: 0.45 !important;
  cursor: not-allowed !important;
  filter: grayscale(0.4);
  pointer-events: none;
}
/* :hover on disabled should not "lift" or change colors */
button:disabled:hover,
.btn:disabled:hover,
.sr-btn:disabled:hover, .sr-btn-outline:disabled:hover,
.row-action:disabled:hover,
.ep-circle-btn:disabled:hover,
.oms-act:disabled:hover,
.act-auto:disabled:hover {
  transform: none !important;
  box-shadow: none !important;
  background: inherit !important;
  color: inherit !important;
  border-color: inherit !important;
}

/* ── Loading state for buttons ───────────────────────────────────
   Set data-loading="1" on any button to show a spinner overlay and
   freeze interaction while an async operation completes. The original
   button content is hidden via opacity:0 (preserves width to prevent
   layout jump). shared.js exposes window.btnLoading(btn, on) helper. */
button[data-loading="1"] {
  position: relative !important;
  pointer-events: none !important;
  cursor: progress !important;
}
button[data-loading="1"] > * { opacity: 0 !important; visibility: hidden; }
button[data-loading="1"]::after {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  width: 1.05rem; height: 1.05rem;
  margin: -0.525rem 0 0 -0.525rem;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: oms-spin 0.7s linear infinite;
  opacity: 0.85;
}
@keyframes oms-spin { to { transform: rotate(360deg); } }

/* ── Minimum touch target for action buttons (a11y) ──────────────
   WCAG 2.5.5 recommends 24px minimum, with 44px ideal. Many tiny
   icon buttons across the app are < 28px which is hard to hit on
   touch devices. Enforce 32px minimum on all our action button
   patterns. Buttons that genuinely need to be smaller can opt out
   with .btn-tiny. */
.row-action, .ep-circle-btn, .oms-act, .act-auto, .has-tip {
  min-width: 2rem; min-height: 2rem;
}
.btn-tiny { min-width: auto !important; min-height: auto !important; }

/* Mobile users are redirected to /mobile companion app — no responsive overrides needed */
#mobile-menu-btn { display: none; }

/* ── Watch interval check popup ───────────────────────────────────────── */
/* Forced popup — sits above every other modal (z-index 9999), dim background
   that captures clicks, no close button. Dismissable only by submitting an
   acknowledgement Note via the bottom button. */
.watch-check-modal { z-index: 9999 !important; background: rgba(0,0,0,0.62); }
.watch-check-modal-inner {
  max-width: 540px; width: 92%; padding: 0; border-radius: 14px;
  box-shadow: 0 12px 48px rgba(0,0,0,0.55), 0 2px 8px rgba(0,0,0,0.25);
  border-top: 6px solid var(--danger, #c62828);
  animation: watch-check-pop 0.18s ease-out;
}
@keyframes watch-check-pop { from { transform: scale(0.94); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.watch-check-header {
  display: flex; align-items: center; gap: 0.85rem;
  padding: 1rem 1.25rem 0.85rem; border-bottom: 1px solid var(--border, #eee);
}
.watch-check-icon {
  font-size: 2rem; color: var(--danger, #c62828);
  background: rgba(198, 40, 40, 0.1); border-radius: 50%;
  width: 2.5rem; height: 2.5rem; display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.watch-check-titles { flex: 1; min-width: 0; }
.watch-check-title {
  font-size: 1.05rem; font-weight: 700; color: var(--danger, #c62828);
  display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
}
.watch-check-subtitle { font-size: 0.85rem; color: var(--text-muted, #666); margin-top: 0.15rem; }
.watch-fanout-badge {
  background: var(--warning, #ed6c02); color: #fff;
  font-size: 0.65rem; font-weight: 700; padding: 0.1rem 0.5rem; border-radius: 4px;
  letter-spacing: 0.5px;
}
.watch-check-body { padding: 0.85rem 1.25rem; }
.watch-check-meta {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.5rem 1rem; margin-bottom: 0.75rem;
  font-size: 0.78rem;
}
.watch-check-meta > div {
  display: flex; flex-direction: column; gap: 0.1rem;
  padding: 0.4rem 0.6rem; background: rgba(0,0,0,0.03); border-radius: 6px;
}
.watch-check-meta strong {
  font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--text-muted, #666); font-weight: 600;
}
.watch-check-meta span { color: var(--text, #222); font-weight: 500; }
.watch-check-description {
  margin-bottom: 0.75rem; padding: 0.6rem 0.85rem;
  background: rgba(255, 193, 7, 0.1); border-left: 3px solid var(--warning, #ed6c02);
  border-radius: 4px; font-size: 0.85rem;
}
.watch-check-description strong {
  display: block; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--warning, #ed6c02); margin-bottom: 0.25rem;
}
.watch-image-required {
  margin-bottom: 0.75rem; padding: 0.5rem 0.85rem;
  background: rgba(33, 150, 243, 0.08); border-left: 3px solid var(--primary, #1976d2);
  border-radius: 4px; font-size: 0.78rem; color: var(--text, #222);
}
.watch-check-note-label {
  display: block; font-size: 0.78rem; font-weight: 600;
  margin: 0.25rem 0 0.4rem;
}
.watch-check-note {
  width: 100%; resize: vertical; min-height: 5.5rem; font-family: var(--font);
  font-size: 0.88rem; padding: 0.55rem 0.7rem;
}
.watch-check-error {
  color: var(--danger, #c62828); font-size: 0.78rem; margin-top: 0.4rem; min-height: 1rem;
}
.watch-check-footer {
  padding: 0.85rem 1.25rem 1rem; border-top: 1px solid var(--border, #eee);
  display: flex; justify-content: flex-end;
}
.watch-check-ack {
  background: var(--danger, #c62828); color: #fff; border-color: var(--danger, #c62828);
  font-weight: 600; min-width: 11rem;
}
.watch-check-ack:not(:disabled):hover { background: #b71c1c; border-color: #b71c1c; }
.watch-check-ack:disabled { opacity: 0.55; cursor: not-allowed; }

body.dark-mode .watch-check-meta > div { background: rgba(255,255,255,0.04); }
body.dark-mode .watch-check-meta span { color: var(--text-light, #e8e8ea); }
body.dark-mode .watch-check-description { background: rgba(255, 193, 7, 0.08); }

/* ── Watch popup photo capture / upload ──────────────────────────────── */
.watch-check-photo-block { margin: 0.5rem 0 0.6rem; }
.watch-check-photo-help {
  font-size: 0.72rem; color: var(--text-muted, #666); margin-bottom: 0.4rem;
}
.watch-check-photo-actions {
  display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
}
.watch-check-photo-btn {
  background: var(--primary, #1976d2); color: #fff; border-color: var(--primary, #1976d2);
  font-weight: 600; padding: 0.4rem 0.85rem;
}
.watch-check-photo-btn:hover { filter: brightness(1.05); }
.watch-check-photo-btn:disabled { opacity: 0.55; cursor: not-allowed; }
.watch-check-photo-status {
  font-size: 0.78rem; color: var(--text-muted, #666);
}
.watch-check-photo-thumbs {
  display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.5rem;
}
.watch-check-thumb {
  width: 5rem; max-width: 30%; border: 1px solid var(--border, #ddd);
  border-radius: 6px; overflow: hidden; background: rgba(0,0,0,0.04);
}
.watch-check-thumb img {
  width: 100%; height: 5rem; object-fit: cover; display: block;
}
.watch-check-thumb-name {
  font-size: 0.65rem; padding: 0.2rem 0.35rem; color: var(--text-muted, #666);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body.dark-mode .watch-check-thumb { background: rgba(255,255,255,0.04); border-color: rgba(255,255,255,0.1); }

/* Date-picker invalid state — applied by shared.js on blur when the
   typed value can't be parsed (e.g. user typed "311987" but failed
   format). Red border + subtle tint so the user notices, plus the
   value getter returns '' so any required-field check fails loudly. */
input.dp-invalid {
  border-color: var(--danger, #D32F2F) !important;
  background-color: rgba(211, 47, 47, 0.04) !important;
}
/* Future-date warning — amber accent. Date parsed cleanly but the value
   sits past today; we flag it without blocking the save (davidnotes3 #4). */
input.dp-future {
  border-color: var(--warning, #F57C00) !important;
  background-color: rgba(245, 124, 0, 0.06) !important;
}

/* ════════════════════════════════════════════════════════════════
   Theme propagation — coordinated tinting beyond just --primary so
   themes feel like themes, not accents (davidnotes4 N5 follow-up).
   Topbar is intentionally excluded (uses --brand-primary).
   ════════════════════════════════════════════════════════════════ */

/* Data-grid header strip picks up the theme stripe color. */
.data-grid thead th,
.sr-grid thead tr:first-child th {
  border-top: 3px solid var(--theme-stripe, var(--primary)) !important;
}

/* Section/panel banners and "title strip" rows pick up the theme. */
.audit-summary,
.changes-table thead th,
.search-results-summary {
  border-top: 2px solid var(--theme-stripe, var(--primary)) !important;
}

/* Hover state on grid rows — wash the theme tint instead of plain gray. */
.sr-grid tbody tr:hover:not(.sr-row-wanted):not(.ms-selected),
.data-grid tbody tr:hover {
  background: var(--theme-tint, rgba(var(--theme-rgb,216,67,21),0.06)) !important;
}

/* Selected/active row uses the stronger tint. */
.sr-grid tbody tr.sr-selected,
.sr-grid tbody tr.ms-selected,
.data-grid tbody tr.selected {
  background: var(--theme-tint-strong, rgba(var(--theme-rgb,216,67,21),0.14)) !important;
}

/* Themed focus rings — outer glow on form controls only. Buttons get NO
   custom focus-visible style: the canonical 1px primary border already
   reads as a focus indicator post-click, and any extra ring (outer halo
   OR inset) ends up stacked on top of that border, making the focused
   button look thicker/darker than its un-focused neighbors in the same
   button group. Browsers will still draw their default outline for true
   keyboard focus. */
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  box-shadow: 0 0 0 3px var(--theme-glow, rgba(var(--theme-rgb,216,67,21),0.25));
}

/* Sub-tab active pill picks up theme. */
.sub-tabs .btn.active {
  background: var(--primary) !important;
  color: #fff !important;
}

/* Modal header gets a subtle theme stripe. */
.modal-header,
.modal-box .modal-header {
  border-bottom: 2px solid var(--theme-stripe, var(--primary)) !important;
}

/* Counter cards (Activities / Bookings header counters). */
.ep-counter:hover {
  background: var(--theme-tint-strong, rgba(var(--theme-rgb,216,67,21),0.14));
  border-color: var(--primary);
}

/* ════════════════════════════════════════════════════════════════
   Dark-mode readability fixes — common inline-color patterns that
   don't respect CSS variables. Inline `color:#666` / `#888` etc. are
   used heavily in print stylesheets and ad-hoc spans; in dark mode
   they vanish into the bg. We can't touch every inline style, but
   the common patterns get a high-specificity dark override here so
   text stays readable.
   ════════════════════════════════════════════════════════════════ */
body.dark-mode [style*="color:#666"],
body.dark-mode [style*="color: #666"],
body.dark-mode [style*="color:#777"],
body.dark-mode [style*="color: #777"],
body.dark-mode [style*="color:#888"],
body.dark-mode [style*="color: #888"],
body.dark-mode [style*="color:#999"],
body.dark-mode [style*="color: #999"] {
  color: var(--text-secondary) !important;
}

/* Placeholder text — in dark mode the default 0.7 opacity reads as
   nearly invisible. Bump to a brighter base + higher opacity. */
body.dark-mode .form-control::placeholder,
body.dark-mode input::placeholder,
body.dark-mode textarea::placeholder {
  color: var(--text-muted) !important;
  opacity: 0.85;
}

/* Description / hint text under inputs is often <small> or class-less
   gray spans. The text-muted bump in :root vars handles var-driven
   ones; for inline `color:#aaa` etc., we'd need specific selectors.
   The high-frequency offenders above cover the rest. */
body.dark-mode small,
body.dark-mode .text-muted {
  color: var(--text-muted);
}

/* Disabled inputs in dark mode were #1a1a2e / #666 — too dim to read.
   Lift to readable. */
body.dark-mode input[disabled],
body.dark-mode select[disabled],
body.dark-mode textarea[disabled] {
  background-color: var(--bg-input) !important;
  color: var(--text-secondary) !important;
  opacity: 0.85;
}

/* ── Dashboard filter chips ────────────────────────────────────────
   Rendered by _renderDashFilterChips() from a per-user filter list
   (db/dashboard-filters.js). The active chip uses the filter's color
   for both background and outline; inactive chips are neutral. The
   "+" trailing chip opens the Manage Filters panel. */
.dash-filter-chip {
  background: transparent;
  border: 1px solid var(--border-color);
  color: var(--text-muted);
  padding: 0.3rem 0.85rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.12s;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  line-height: 1;
}
.dash-filter-chip:hover {
  border-color: var(--primary);
  color: var(--primary);
}
.dash-filter-chip.dash-filter-active {
  /* Inline style sets the per-filter color; defaults below are the
     fallback when no color is configured. */
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
.dash-filter-chip-add {
  border-style: dashed;
  font-weight: 700;
  padding: 0.3rem 0.6rem;
}
.dash-filter-fac-badge {
  font-size: 0.62rem;
  padding: 1px 5px;
  border-radius: 999px;
  background: rgba(255,255,255,0.25);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.dash-filter-chip:not(.dash-filter-active) .dash-filter-fac-badge {
  background: rgba(0,0,0,0.06);
  color: var(--text-muted);
}
body.dark-mode .dash-filter-chip:not(.dash-filter-active) .dash-filter-fac-badge {
  background: rgba(255,255,255,0.08);
}

/* Manage Filters modal — lives inside .modal-overlay so picks up the
   shared modal chrome. Each filter row is a card with reorder
   handles, a color picker, and the clause editor. */
.dfm-list { display: flex; flex-direction: column; gap: 0.6rem; max-height: 50vh; overflow-y: auto; padding-right: 0.4rem; }
.dfm-row { display: flex; flex-direction: column; gap: 0.4rem; padding: 0.7rem; border: 1px solid var(--border-color); border-radius: var(--radius); background: var(--bg-content); }
.dfm-row-head { display: flex; align-items: center; gap: 0.5rem; }
.dfm-handle { cursor: grab; color: var(--text-muted); font-size: 1.05rem; }
.dfm-handle:active { cursor: grabbing; }
.dfm-color-swatch { width: 1.4rem; height: 1.4rem; border-radius: 50%; border: 2px solid var(--border-color); cursor: pointer; flex-shrink: 0; }
.dfm-color-pick { display: flex; flex-wrap: wrap; gap: 4px; padding: 6px; background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius); }
.dfm-color-pick-cell { width: 1.2rem; height: 1.2rem; border-radius: 50%; cursor: pointer; border: 2px solid transparent; }
.dfm-color-pick-cell.selected { border-color: var(--text-primary); transform: scale(1.15); }
.dfm-row input.dfm-label { flex: 1; padding: 0.3rem 0.5rem; font-size: 0.85rem; font-weight: 600; }
.dfm-clause-list { display: flex; flex-direction: column; gap: 0.35rem; padding-left: 1rem; border-left: 2px solid var(--border-color); }
.dfm-clause { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; padding: 0.3rem 0.5rem; background: var(--bg-card); border-radius: var(--radius); }
.dfm-clause select { font-size: 0.78rem; padding: 0.2rem 0.4rem; }
.dfm-clause input.dfm-clause-vals { flex: 1; min-width: 8rem; padding: 0.25rem 0.4rem; font-size: 0.78rem; }
.dfm-clause-neg { font-size: 0.7rem; color: var(--text-muted); display: inline-flex; align-items: center; gap: 0.3rem; }
.dfm-row-actions { display: flex; gap: 0.4rem; justify-content: flex-end; padding-top: 0.3rem; border-top: 1px dashed var(--border-color); }

/* Empty-state cell for grid bodies — used when a search/filter returns
   zero rows. Centers the icon + label with comfortable vertical breathing
   room so it doesn't render as a thin sliver under the column headers.
   Was previously only declared on index.html, leaving search.html (and any
   other grid using class="widget-empty") with no styling at all. */
.widget-empty {
  padding: 3rem 1.5rem;
  text-align: center;
  color: var(--text-muted);
  font-size: 0.875rem;
  font-weight: 500;
  background: var(--bg-card);
}
.widget-empty .icon {
  display: block;
  font-size: 2.5rem;
  color: var(--text-muted);
  opacity: 0.55;
  margin: 0 auto 0.6rem;
}

/* ── Mugshot gallery tile + edit popover ────────────────────────────── */
.oms-mug-tile {
  position: relative;
  width: 120px;
  text-align: center;
  cursor: pointer;
  outline: none;
}
.oms-mug-tile img {
  width: 120px;
  height: 150px;
  object-fit: cover;
  border-radius: 4px;
  border: 2px solid var(--border-light);
  display: block;
  background: var(--bg-secondary);
}
.oms-mug-tile:hover img,
.oms-mug-tile:focus-visible img { box-shadow: 0 0 0 2px var(--primary-faint); }
.oms-mug-default-chip {
  position: absolute;
  top: 4px;
  left: 4px;
  background: var(--primary);
  color: #fff;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 6px;
  border-radius: 3px;
  z-index: 1;
}
.oms-mug-type {
  font-size: 0.7rem;
  color: var(--text);
  margin-top: 3px;
  font-weight: 600;
}
.oms-mug-type-empty { color: var(--text-muted); font-weight: 400; font-style: italic; }
.oms-mug-date { font-size: 0.65rem; color: var(--text-muted); }

.oms-mug-pop-host { position: fixed; top: 0; left: 0; }
.oms-mug-pop {
  width: 300px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.18);
  padding: 12px;
  font-size: 0.82rem;
}
.oms-mug-pop-row { margin-bottom: 10px; }
.oms-mug-pop-row label { display: block; font-weight: 600; margin-bottom: 4px; font-size: 0.78rem; }
.oms-mug-pop-row select { width: 100%; }
.oms-mug-pop-check { display: flex; align-items: center; gap: 6px; font-weight: 500; }
.oms-mug-pop-note { font-size: 0.7rem; color: var(--text-muted); margin-top: 4px; }
.oms-mug-pop-actions { display: flex; gap: 6px; justify-content: flex-end; }
.oms-mug-pop-actions [data-mug-delete] { margin-right: auto; }

/* ── Modal window controls (maximize / minimize / drag / resize) ──────────
   Wired by shared.js _omsInitModalWindow. Single-instance modal model
   preserved — overlay always present, no multi-modal. Lesson #250. */
/* Apply window-control styles to canonical AND every custom *-modal-header
   pattern. The injector adds .oms-mw-modal to the modal element regardless
   of class. The wildcard attribute selector picks up wa-, ir-, cm-, sh-,
   wj-, ba-, gb-modal-header etc. */
.modal-header,
[class~="modal-header"],
[class*="-modal-header"] { user-select: none; -webkit-user-select: none; }
.modal-header .modal-win-btn,
[class~="modal-header"] .modal-win-btn,
[class*="-modal-header"] .modal-win-btn {
  background: rgba(255,255,255,0.12);
  border: none;
  color: #fff;
  width: 2rem; height: 2rem;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0.95;
  transition: background 0.12s, transform 0.12s;
  padding: 0;
  flex: none;
}
.modal-header .modal-win-btn:hover,
[class~="modal-header"] .modal-win-btn:hover,
[class*="-modal-header"] .modal-win-btn:hover { background: rgba(255,255,255,0.28); transform: scale(1.05); }
.modal-header .modal-win-btn:active,
[class~="modal-header"] .modal-win-btn:active,
[class*="-modal-header"] .modal-win-btn:active { transform: scale(0.95); }
.modal-header .modal-win-btn .icon,
[class~="modal-header"] .modal-win-btn .icon,
[class*="-modal-header"] .modal-win-btn .icon { font-size: 1.05rem; line-height: 1; }
/* Push the actions group + close button cluster to the right edge of the
   header. Without margin-left:auto the header's space-between distributes
   the title, actions, and X evenly across the bar. */
.modal-header .modal-win-actions,
[class~="modal-header"] .modal-win-actions,
[class*="-modal-header"] .modal-win-actions { display: inline-flex; align-items: center; gap: 0.35rem; flex: none; margin-left: auto; margin-right: 0.35rem; }
/* Header is the drag handle. Cursor only when modal is draggable (not nested,
   not mobile). The `.modal-overlay--draggable` class is applied by JS. */
.modal-overlay--draggable > .oms-mw-modal > [class~="modal-header"],
.modal-overlay--draggable > .oms-mw-modal > [class*="-modal-header"],
.modal-overlay--draggable > .modal > .modal-header,
.modal-overlay--draggable > .modal-box > .modal-header { cursor: grab; }
.modal-overlay--draggable > .oms-mw-modal > [class~="modal-header"]:active,
.modal-overlay--draggable > .oms-mw-modal > [class*="-modal-header"]:active,
.modal-overlay--draggable > .modal > .modal-header:active,
.modal-overlay--draggable > .modal-box > .modal-header:active { cursor: grabbing; }
.modal-header .modal-win-btn,
.modal-header .modal-close,
.modal-header input,
.modal-header select,
.modal-header textarea,
.modal-header button:not(.modal-win-btn):not(.modal-close) { cursor: pointer; }

/* Floating: user has dragged or resized the modal. Overlay stops centering;
   modal is positioned absolutely within the overlay via inline left/top.
   .oms-mw-modal is added to every modal we manage (canonical or custom) so
   these rules apply to wa-modal, ir-modal, cm-modal, etc. without per-system
   CSS — see shared.js inject(). */
.modal-overlay--free { align-items: flex-start !important; justify-content: flex-start !important; }
.modal-overlay--free > .oms-mw-modal,
.modal-overlay--free > .modal,
.modal-overlay--free > .modal-box {
  position: absolute;
  margin: 0;
  animation: none;
}

/* Maximize */
.oms-mw-modal.modal--max,
.modal.modal--max,
.modal-box.modal--max {
  position: absolute !important;
  left: 1rem !important; top: 1rem !important;
  width: calc(100vw - 2rem) !important;
  height: calc(100vh - 2rem) !important;
  max-width: none !important;
  max-height: none !important;
}
.modal-overlay--free > .oms-mw-modal.modal--max,
.modal-overlay--free > .modal.modal--max,
.modal-overlay--free > .modal-box.modal--max { position: absolute !important; }

/* Minimize: collapses body + footer, modal docks to bottom-right as a chip. */
.oms-mw-modal.modal--min,
.modal.modal--min,
.modal-box.modal--min {
  position: fixed !important;
  left: auto !important;
  right: 1rem !important;
  bottom: 1rem !important;
  top: auto !important;
  width: 18rem !important;
  height: auto !important;
  max-width: 18rem !important;
  max-height: none !important;
  overflow: hidden !important;
  z-index: 2010;
}
.modal--min [class~="modal-body"],
.modal--min [class*="-modal-body"],
.modal--min [class~="modal-footer"],
.modal--min [class*="-modal-footer"],
.modal--min .modal-resize-grip { display: none !important; }
.modal--min [class~="modal-header"],
.modal--min [class*="-modal-header"] { border-radius: 10px; cursor: pointer; }
/* When minimized, the overlay backdrop must not block clicks elsewhere.
   !important needed to overrule custom-overlay backgrounds (.wa-overlay,
   .ir-overlay, etc.) defined in per-page <style> blocks loaded after
   shared.css. */
.modal-overlay--has-min { background: transparent !important; pointer-events: none !important; }
.modal-overlay--has-min > .modal--min { pointer-events: auto; }
/* Restore the backdrop only if there's a non-minimized modal still showing.
   This class is added by JS when min state toggles. */
.modal-overlay--restore-bg { background: rgba(15,15,25,0.72); pointer-events: auto; }

/* Custom resize grip — bottom-right corner. CSS `resize: both` requires
   overflow != visible, but our .modal uses overflow: visible for picker
   popovers. A custom handle sidesteps that. */
.modal-resize-grip {
  position: absolute;
  right: 0; bottom: 0;
  width: 16px; height: 16px;
  cursor: nwse-resize;
  background:
    linear-gradient(135deg, transparent 0 50%, var(--border-color) 50% 60%, transparent 60% 70%, var(--border-color) 70% 80%, transparent 80% 90%, var(--border-color) 90% 100%);
  border-bottom-right-radius: 10px;
  z-index: 2;
  opacity: 0.6;
}
.modal-resize-grip:hover { opacity: 1; }
.modal--min .modal-resize-grip,
.modal--max .modal-resize-grip { display: none; }

/* When floating, the modal is positioned inside the overlay; ensure modal
   keeps its own background so the see-through overlay (when minimized
   elsewhere) doesn't leak through. */
.modal-overlay--free > .modal { background: #fff; }
body.dark-mode .modal-overlay--free > .modal { background: var(--bg-card); }

/* Mobile: disable window controls; modals stay centered + full-bleed. */
@media (max-width: 767px) {
  .modal-header .modal-win-actions,
  [class~="modal-header"] .modal-win-actions,
  [class*="-modal-header"] .modal-win-actions { display: none; }
  .modal-resize-grip { display: none; }
  .modal-overlay--free { align-items: center; justify-content: center; }
  .modal-overlay--free > .modal,
  .modal-overlay--free > .modal-box { position: relative; left: auto !important; top: auto !important; width: 90% !important; height: auto !important; }
}
