/* TW LogistiQ — Apple-inspired theme, light + dark */

:root {
  /* Light (default) */
  --bg:         #f5f5f7;
  --bg-card:    #ffffff;
  --bg-sidebar: #fbfbfd;
  --border:    rgba(0,0,0,0.08);
  --border-2:  rgba(0,0,0,0.04);
  --text:       #1d1d1f;
  --text-2:     #6e6e73;
  --text-3:     #86868b;
  --accent:     #0071e3;
  --accent-hover:#0077ed;
  --success:    #30d158;
  --warning:    #ff9500;
  --danger:     #ff3b30;
  --fill:       #f5f5f7;
  --fill-hover: #ebebed;
  --radius:     10px;
  --radius-lg:  14px;
  --shadow-sm:  0 1px 2px rgba(0,0,0,0.04);
  --shadow:     0 4px 14px rgba(0,0,0,0.06);
  --shadow-lg:  0 20px 40px rgba(0,0,0,0.08);
  /* Amendment 12 Oct 2026: the record drawer's surface, its easing and the
     pill radius (ported from the TruCore slide-over, without its purple). */
  --bg-elevated: #ffffff;
  --ease-out:   cubic-bezier(0.22, 1, 0.36, 1);
  --r-pill:     999px;
}

html[data-theme="dark"] {
  --bg:         #000000;
  --bg-card:    #1c1c1e;
  --bg-sidebar: #161617;
  --border:    rgba(255,255,255,0.10);
  --border-2:  rgba(255,255,255,0.06);
  --text:       #f5f5f7;
  --text-2:     #a1a1a6;
  --text-3:     #86868b;
  --accent:     #0a84ff;       /* Apple dark-mode blue */
  --accent-hover:#409cff;
  --success:    #32d74b;
  --warning:    #ff9f0a;
  --danger:     #ff453a;
  --fill:       #2c2c2e;
  --fill-hover: #3a3a3c;
  --shadow-sm:  0 1px 2px rgba(0,0,0,0.3);
  --shadow:     0 4px 14px rgba(0,0,0,0.4);
  --shadow-lg:  0 20px 40px rgba(0,0,0,0.5);
  --bg-elevated: #1c1c1e;
  --ease-out:   cubic-bezier(0.22, 1, 0.36, 1);
  --r-pill:     999px;
}

html[data-theme="dark"] body { background: var(--bg); color: var(--text); }
html[data-theme="dark"] .bg-slate-50 { background: var(--fill) !important; }
html[data-theme="dark"] .bg-slate-100 { background: var(--fill) !important; }
html[data-theme="dark"] .bg-white  { background: var(--bg-card) !important; }
html[data-theme="dark"] .bg-emerald-50 { background: rgba(50,215,75,0.12) !important; }
html[data-theme="dark"] .bg-blue-100 { background: rgba(10,132,255,0.12) !important; }
html[data-theme="dark"] .bg-indigo-100 { background: rgba(94,92,230,0.15) !important; }
html[data-theme="dark"] .bg-amber-100, html[data-theme="dark"] .bg-amber-50 { background: rgba(255,159,10,0.12) !important; }
html[data-theme="dark"] .bg-teal-100 { background: rgba(10,132,255,0.12) !important; }
html[data-theme="dark"] .bg-emerald-100 { background: rgba(50,215,75,0.12) !important; }
html[data-theme="dark"] .text-emerald-600, html[data-theme="dark"] .text-emerald-700 { color: var(--success) !important; }
html[data-theme="dark"] .text-red-600, html[data-theme="dark"] .text-red-700, html[data-theme="dark"] .text-red-900 { color: var(--danger) !important; }
html[data-theme="dark"] .text-amber-600, html[data-theme="dark"] .text-amber-700, html[data-theme="dark"] .text-amber-900 { color: var(--warning) !important; }
html[data-theme="dark"] .text-blue-600, html[data-theme="dark"] .text-blue-700, html[data-theme="dark"] .text-blue-900 { color: var(--accent) !important; }
html[data-theme="dark"] .text-indigo-700, html[data-theme="dark"] .text-indigo-900 { color: #a78bfa !important; }
html[data-theme="dark"] .border-red-200 { border-color: rgba(255,69,58,0.35) !important; }
html[data-theme="dark"] .border-amber-200, html[data-theme="dark"] .border-amber-300 { border-color: rgba(255,159,10,0.35) !important; }
html[data-theme="dark"] .bg-red-50 { background: rgba(255,69,58,0.12) !important; }
html[data-theme="dark"] header.h-16 { background: rgba(28,28,30,0.7) !important; }

html, body { height: 100%; }
body {
  /* Primary font is Chakra Petch — the same face used in the TW LogistiQ
     logo wordmark + MOVE SMARTER tagline. Loaded via Google Fonts <link>
     in every page's <head>; system fonts fall back if the network blocks. */
  font-family: 'Chakra Petch', -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
               "Helvetica Neue", "Segoe UI", Roboto, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: -0.01em;
  color: var(--text);
  background: var(--bg);
}

/* --- Tailwind override layer (via utility-like overrides for existing classes) --- */
.bg-slate-50 { background: var(--bg) !important; }
.bg-white    { background: var(--bg-card) !important; }
.border-slate-200, .border-slate-100 { border-color: var(--border) !important; }
.divide-slate-100 > * + * { border-color: var(--border-2) !important; }
.text-slate-900 { color: var(--text) !important; }
.text-slate-700 { color: var(--text) !important; }
.text-slate-600 { color: var(--text-2) !important; }
.text-slate-500 { color: var(--text-2) !important; }
.text-slate-400 { color: var(--text-3) !important; }
.text-slate-300 { color: var(--text-3) !important; }

/* Teal (old brand) → Apple blue */
.text-teal-700, .text-teal-600, .text-teal-800, .text-teal-900 { color: var(--accent) !important; }
.bg-teal-700, .bg-teal-800 { background: var(--accent) !important; }
.bg-teal-700:hover, .hover\:bg-teal-800:hover { background: var(--accent-hover) !important; }
.border-teal-700, .border-teal-500, .border-teal-600 { border-color: var(--accent) !important; }
.bg-teal-50, .bg-teal-100 { background: rgba(0, 113, 227, 0.08) !important; }
.focus\:ring-teal-500:focus { --tw-ring-color: rgba(0, 113, 227, 0.35) !important; }
.focus\:border-teal-500:focus { border-color: var(--accent) !important; }

/* Rounded corners softer, Apple style */
.rounded-xl { border-radius: var(--radius-lg) !important; }
.rounded-lg { border-radius: var(--radius) !important; }

/* Shadows — softer, more diffuse */
.shadow-sm { box-shadow: var(--shadow-sm) !important; }
.shadow    { box-shadow: var(--shadow) !important; }
.shadow-md { box-shadow: var(--shadow) !important; }
.shadow-lg { box-shadow: var(--shadow-lg) !important; }
.shadow-2xl{ box-shadow: 0 30px 60px rgba(0,0,0,0.12) !important; }

/* Inputs — Apple feel */
input[type=text], input[type=email], input[type=password], input[type=number],
input[type=date], input[type=time], input[type=search], input[type=tel],
input[type=url], input[type=datetime-local], input[type=month], input[type=week],
input[type=color], select, select[multiple], textarea {
  background: var(--bg-card) !important;
  color: var(--text) !important;
  border: 1px solid var(--border) !important;
  border-radius: var(--radius) !important;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  transition: border-color 0.15s, box-shadow 0.15s !important;
}
input::placeholder, textarea::placeholder {
  color: var(--text-2, #94a3b8);
  opacity: 1;
}
input:focus, select:focus, textarea:focus {
  outline: none !important;
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 4px rgba(0, 113, 227, 0.15) !important;
}
/* 1.44.0 (3b): a required field left empty, or rejected by the server, carries a red outline app wide. */
/* :not(#tw-never) lifts this above the !important theme rules for inputs (0,3,1) without touching them. */
:is(input,select,textarea)[aria-invalid="true"]:not(#tw-never), :is(input,select,textarea).is-invalid:not(#tw-never) {
  border-color: var(--danger) !important;
  box-shadow: 0 0 0 1px var(--danger) !important;
  outline: none;
}
/* The browser focuses the first invalid field, so the focus accent must not hide the red. */
:is(input,select,textarea)[aria-invalid="true"]:focus:not(#tw-never), :is(input,select,textarea).is-invalid:focus:not(#tw-never) {
  border-color: var(--danger) !important;
  box-shadow: 0 0 0 1px var(--danger) !important;
}
:is(.field,.twp-field,.pw2-f,.iw2-f,label):has(> [aria-invalid="true"]) > span:first-child { color: var(--danger); }
input:disabled, select:disabled, textarea:disabled {
  background: var(--fill, #f1f5f9) !important;
  color: var(--text-3, #64748b) !important;
  cursor: not-allowed;
}
input[type=checkbox], input[type=radio] {
  accent-color: var(--accent);
}
html[data-theme="dark"] input[type=text],
html[data-theme="dark"] input[type=email],
html[data-theme="dark"] input[type=password],
html[data-theme="dark"] input[type=number],
html[data-theme="dark"] input[type=date],
html[data-theme="dark"] input[type=time],
html[data-theme="dark"] input[type=search],
html[data-theme="dark"] input[type=tel],
html[data-theme="dark"] input[type=url],
html[data-theme="dark"] input[type=datetime-local],
html[data-theme="dark"] input[type=month],
html[data-theme="dark"] input[type=week],
html[data-theme="dark"] input[type=color],
html[data-theme="dark"] select,
html[data-theme="dark"] select[multiple],
html[data-theme="dark"] textarea {
  background: var(--bg-card) !important;
  color: var(--text) !important;
  border-color: var(--border) !important;
}

/* Buttons — primary (.bg-teal-700) */
button.bg-teal-700, a.bg-teal-700, .bg-teal-700 {
  font-weight: 500 !important;
  letter-spacing: -0.01em !important;
  transition: all 0.15s ease !important;
}
button.bg-teal-700:hover, a.bg-teal-700:hover, .bg-teal-700:hover {
  transform: translateY(-1px);
}

/* Body surface gradients */
.bg-gradient-to-br.from-teal-800,
.bg-gradient-to-br.from-teal-800.via-teal-900 {
  background: linear-gradient(135deg, #0071e3 0%, #0b4a9e 100%) !important;
}

/* Status pills */
.pill {
  display: inline-flex; align-items: center;
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: -0.005em;
}
.pill-green  { background: rgba(48,209,88,0.15);  color: #1d8c3a; }
.pill-red    { background: rgba(255,59,48,0.12);  color: #c62617; }
.pill-amber  { background: rgba(255,149,0,0.15);  color: #9c5a00; }
.pill-blue   { background: rgba(0,113,227,0.12);  color: #0058b0; }
.pill-slate  { background: rgba(0,0,0,0.06);      color: var(--text-2); }
.pill-purple { background: rgba(168,85,247,0.14); color: #6b21a8; }
.pill-cyan   { background: rgba(6,182,212,0.14);  color: #0e7490; }
.pill-grey   { background: rgba(100,116,139,0.14); color: #475569; }

/* Tables */
table thead { background: var(--fill) !important; }
table thead th {
  font-weight: 600 !important;
  color: var(--text-2) !important;
  letter-spacing: 0.02em !important;
  font-size: 0.68rem !important;
}
tbody tr:hover { background-color: var(--fill) !important; }

/* Sidebar — light Apple look */
.sidebar {
  background: var(--bg-sidebar) !important;
  color: var(--text) !important;
  border-right: 1px solid var(--border);
}
.sidebar .brand-title { color: var(--text) !important; }
.sidebar .brand-sub   { color: var(--text-3) !important; }
.sidebar .section-heading {
  color: var(--text-3) !important;
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 14px 20px 4px;
}
.sidebar .nav-item {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 20px; margin: 1px 8px;
  border-radius: 8px;
  color: var(--text);
  font-size: 14px; font-weight: 500;
  text-decoration: none;
  transition: background 0.1s;
}
.sidebar .nav-item:hover { background: var(--fill); }
.sidebar .nav-item.active {
  background: rgba(0,113,227,0.1);
  color: var(--accent);
}
.sidebar .nav-item.active svg { color: var(--accent); }
.sidebar .nav-item svg { color: var(--text-2); width: 18px; height: 18px; flex-shrink: 0; }
.sidebar .user-block {
  padding: 14px 20px; border-top: 1px solid var(--border);
  font-size: 13px;
}
.sidebar .user-email { color: var(--text); font-weight: 500; }
.sidebar .user-role { color: var(--text-3); font-size: 12px; }
.sidebar .logout-link { color: var(--accent); font-size: 13px; margin-top: 6px; display:inline-block; }

/* ===========================================================
   Minimized, categorized nav — a pinned launchpad above a set
   of collapsible accordion categories. Collapsed at rest with
   the active category expanded, so the rail stays short and
   calm instead of a long flat list. On-theme via the shared
   CSS variables (light + dark); the LED active-item treatment
   further down is deliberately left untouched.
   =========================================================== */

/* Hairline under the pinned launchpad (Demo / Dashboard / Overview). */
.sidebar .nav-pinned-sep {
  height: 1px;
  margin: 8px 16px;
  background: var(--border);
}

/* One category = quiet header button + collapsible body. */
.sidebar .nav-cat { margin-bottom: 4px; }

.sidebar .nav-cat-head {
  display: flex; align-items: center; gap: 10px;
  width: calc(100% - 16px);
  margin: 1px 8px;
  padding: 9px 12px;
  border: 0; background: none; cursor: pointer;
  border-radius: 8px;
  font-family: inherit;
  font-size: 12px; font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--text-2);
  transition: background 0.15s ease, color 0.15s ease, box-shadow 0.2s ease;
}
.sidebar .nav-cat-head .nav-cat-label { flex: 1 1 auto; text-align: left; }
.sidebar .nav-cat-icon {
  display: inline-flex; flex-shrink: 0;
  color: var(--text-3);
  transition: color 0.15s ease;
}
.sidebar .nav-cat-icon svg { width: 17px; height: 17px; }
.sidebar .nav-cat-caret {
  display: inline-flex; flex-shrink: 0; margin-left: auto;
  color: var(--text-3);
  transition: transform 0.22s ease;
}
.sidebar .nav-cat-caret svg { width: 13px; height: 13px; }

/* Hover — a soft fill + full-strength label. */
.sidebar .nav-cat-head:hover { background: var(--fill); color: var(--text); }

/* Open — label brightens, leading icon takes the accent, caret rotates down. */
.sidebar .nav-cat.is-open > .nav-cat-head { color: var(--text); }
.sidebar .nav-cat.is-open > .nav-cat-head .nav-cat-icon { color: var(--accent); }
.sidebar .nav-cat.is-open > .nav-cat-head .nav-cat-caret { transform: rotate(90deg); }

/* Active category (contains the current route) — subtle inset cyan cue so the
   folded rail still signals where you are, even with the body collapsed. */
.sidebar .nav-cat.is-active-cat > .nav-cat-head {
  box-shadow: inset 2px 0 0 var(--led-cyan);
}

/* Collapsible body — animating grid-template-rows 0fr -> 1fr gives a smooth
   height transition with no JS measuring and no max-height jank. The inner
   wrapper does the clipping (overflow:hidden + min-height:0). */
.sidebar .nav-cat-body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar .nav-cat.is-open > .nav-cat-body { grid-template-rows: 1fr; }
.sidebar .nav-cat-body-inner {
  overflow: hidden;
  min-height: 0;
}
/* Breathing room lives on the OPEN body only. Padding on the collapsed inner
   would leak through the 0fr track (padding is exempt from min-height:0), so a
   folded category would keep a ~6px sliver. Applying it only when open keeps a
   collapsed category truly flat (0px) and the rail calm. */
.sidebar .nav-cat.is-open > .nav-cat-body .nav-cat-body-inner { padding: 2px 0 4px; }

/* Respect prefers-reduced-motion — no accordion glide, no caret spin. */
@media (prefers-reduced-motion: reduce) {
  .sidebar .nav-cat-body,
  .sidebar .nav-cat-caret { transition: none; }
}

/* Boot guard — renderShell mounts the sidebar with .tw-anim-boot so the
   initially-open (active/stored) category snaps straight to its expanded
   height, no glide. The scroll-memory restore in app.js then lands on
   settled layout and lifts this class one frame later, re-arming the
   accordion transition for real clicks only. Prevents the open-on-load
   scroll jump. */
.sidebar.tw-anim-boot .nav-cat-body,
.sidebar.tw-anim-boot .nav-cat-caret { transition: none !important; }

.sidebar::-webkit-scrollbar { width: 6px; }
.sidebar::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 3px; }

/* Top bar
   Note: `position: relative` + `z-index: 100` are deliberate — they
   establish a stacking context for the header subtree so that
   absolutely-positioned descendants (the .tw-notif-panel notification
   dropdown + the .tw-wa-panel WhatsApp dropdown) paint ABOVE the
   dashboard content below. Without this, the .quick-chip tiles on
   the dashboard (which use `isolation: isolate` for their LED glow)
   render on top of the dropdown because they come after the header
   in document order. Brent flagged this on 2026-05-19:
   "Notifications are getting lost behind the text in the home
   dashboard". */
header.h-16 {
  position: relative;
  z-index: 100;
  background: rgba(255,255,255,0.8) !important;
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--border) !important;
}
header.h-16 h1 {
  font-size: 22px !important;
  font-weight: 600 !important;
  letter-spacing: -0.02em !important;
}

/* Headings throughout */
h2 { letter-spacing: -0.02em; }
h3 { letter-spacing: -0.01em; }
.font-bold { font-weight: 600 !important; }
.font-black { font-weight: 700 !important; }

/* Brand mark */
.brand-mark {
  width: 34px; height: 34px;
  border-radius: 10px;
  background: linear-gradient(135deg, #0071e3 0%, #00a3ff 100%);
  color: white;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.02em;
  box-shadow: 0 2px 8px rgba(0,113,227,0.3);
}

/* =========================================================
   Theme-aware logo swap
   ---------------------------------------------------------
   Render BOTH the light + dark horizontal logo variants in
   any logo location, marked with `.tw-logo-light` and
   `.tw-logo-dark`. This rule shows the one matching the
   current `html[data-theme]` and hides the other.

   - Light variant SVG: slate-blue + muted teal — designed
     for off-white backdrops (used in light mode).
   - Dark variant SVG: white wordmark + cyan Q — designed for
     dark backdrops (used in dark mode).

   Both apps (office portal + driver PWA) load this file and
   set html[data-theme] on first paint, so the swap is flicker-
   free regardless of stored preference vs system preference.
   ========================================================= */
.tw-logo-light { display: inline-block; }
.tw-logo-dark  { display: none; }
html[data-theme="dark"] .tw-logo-light { display: none; }
html[data-theme="dark"] .tw-logo-dark  { display: inline-block; }

/* Phone frame for driver PWA */
.phone-frame {
  width: 390px; height: 820px;
  background: #1d1d1f;
  border-radius: 48px;
  padding: 14px;
  box-shadow: 0 40px 80px -20px rgba(0,0,0,0.35), 0 0 0 2px rgba(255,255,255,0.05) inset;
}
.phone-screen {
  width: 100%; height: 100%;
  background: var(--bg);
  border-radius: 36px;
  overflow: hidden;
  display: flex; flex-direction: column;
  position: relative;
}
.phone-screen::before {
  content: '';
  position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 120px; height: 30px;
  background: #1d1d1f;
  border-bottom-left-radius: 18px;
  border-bottom-right-radius: 18px;
  z-index: 10;
}

/* Xero/integrations brand colors */
.xero-blue { color: #13b5ea; }
.bg-xero   { background: #13b5ea; }
.bg-xero-soft { background: rgba(19,181,234,0.08); }

/* 1.55.0 lane SCREEN: the "Module strip" switch, drawn as the theme toggle. */
.tw-ql-toggle {
  width: 48px; height: 26px; padding: 0;
  border-radius: 999px;
  background: var(--fill);
  border: 1px solid var(--border);
  position: relative;
  cursor: pointer;
  transition: background 0.2s;
  flex-shrink: 0;
}
.tw-ql-toggle:hover { background: var(--fill-hover); }
.tw-ql-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tw-ql-toggle-knob {
  position: absolute; top: 2px; left: 2px;
  width: 20px; height: 20px; border-radius: 50%;
  background: white; box-shadow: 0 2px 4px rgba(0,0,0,0.2);
  display: flex; align-items: center; justify-content: center;
  transition: left 0.2s ease; color: #6e6e73;
}
.tw-ql-toggle-knob svg { width: 12px; height: 12px; }
.tw-ql-toggle[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); }
.tw-ql-toggle[aria-pressed="true"] .tw-ql-toggle-knob { left: 24px; color: var(--accent); }
@media (max-width: 700px) { header .tw-ql-toggle { display: none; } }
@media (prefers-reduced-motion: reduce) { .tw-ql-toggle, .tw-ql-toggle-knob { transition: none; } }

/* Theme toggle — iOS-style switch */
.theme-toggle {
  width: 48px; height: 26px;
  border-radius: 999px;
  background: var(--fill);
  border: 1px solid var(--border);
  position: relative;
  cursor: pointer;
  transition: background 0.2s;
  flex-shrink: 0;
}
.theme-toggle:hover { background: var(--fill-hover); }
.theme-toggle-knob {
  position: absolute;
  top: 2px; left: 2px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: white;
  box-shadow: 0 2px 4px rgba(0,0,0,0.2);
  display: flex; align-items: center; justify-content: center;
  transition: left 0.2s ease, background 0.2s;
  color: #ff9500;
}
.theme-toggle-knob svg { width: 12px; height: 12px; }
.theme-toggle-knob .moon-icon { display: none; }
html[data-theme="dark"] .theme-toggle-knob {
  left: 24px;
  background: #1c1c1e;
  color: #a1a1a6;
}
html[data-theme="dark"] .theme-toggle-knob .sun-icon { display: none; }
html[data-theme="dark"] .theme-toggle-knob .moon-icon { display: block; }
html[data-theme="dark"] .theme-toggle { background: var(--accent); border-color: var(--accent); }

/* =========================================================
   GLOBAL FORM CONTROL FIX
   Fixes white input/select/textarea boxes in dark mode
   and invisible low-contrast fields in light mode.
   Applies across Booking, Clients, Vehicles, Drivers, Trips.
   ========================================================= */

input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
select,
textarea {
  background: var(--bg-card) !important;
  color: var(--text) !important;
  border: 1px solid var(--border) !important;
  border-radius: 10px !important;
  outline: none !important;
}

input:not([type="checkbox"]):not([type="radio"]):not([type="file"])::placeholder,
textarea::placeholder {
  color: var(--text-3) !important;
  opacity: 1 !important;
}

input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus,
select:focus,
textarea:focus {
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.18) !important;
}

select option {
  background: var(--bg-card) !important;
  color: var(--text) !important;
}

/* Date/time picker icons in dark mode */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
  filter: invert(1);
}

/* Number input spinner visibility */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  opacity: 0.8;
}

/* Light mode override */
[data-theme="light"] input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
[data-theme="light"] select,
[data-theme="light"] textarea,
html.light input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
html.light select,
html.light textarea,
body.light input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
body.light select,
body.light textarea {
  background: #ffffff !important;
  color: #111827 !important;
  border-color: #d1d5db !important;
}

[data-theme="light"] input::placeholder,
[data-theme="light"] textarea::placeholder,
html.light input::placeholder,
html.light textarea::placeholder,
body.light input::placeholder,
body.light textarea::placeholder {
  color: #6b7280 !important;
}

[data-theme="light"] select option,
html.light select option,
body.light select option {
  background: #ffffff !important;
  color: #111827 !important;
}

[data-theme="light"] input[type="date"]::-webkit-calendar-picker-indicator,
[data-theme="light"] input[type="time"]::-webkit-calendar-picker-indicator,
[data-theme="light"] input[type="datetime-local"]::-webkit-calendar-picker-indicator,
html.light input[type="date"]::-webkit-calendar-picker-indicator,
html.light input[type="time"]::-webkit-calendar-picker-indicator,
html.light input[type="datetime-local"]::-webkit-calendar-picker-indicator,
body.light input[type="date"]::-webkit-calendar-picker-indicator,
body.light input[type="time"]::-webkit-calendar-picker-indicator,
body.light input[type="datetime-local"]::-webkit-calendar-picker-indicator {
  filter: none;
}

/* =========================================================
   MODULE STRIP: rail tabs (1.19.4, Brent 20 Oct 2026, option 1)
   "Same stroke icons as the left rail, one quiet colour, the active
   page marked with the LED dot. Pages sit in their rail groups with
   thin dividers. Edge arrows and a soft fade replace the scrollbar."
   Replaces the coloured emoji pills and the 10px gradient scrollbar
   (Brent 2026-05-20). The track scrolls; its scrollbar is hidden.
   ========================================================= */
/* 1.55.0 lane SCREEN (Brent, 3 Nov 2026): the strip is hidden by default
   (html.tw-ql-hidden, nav[hidden]); it is a flex row of the main column, so
   the content below takes its 40px back with no blank band. */
html.tw-ql-hidden #ql-bar, #ql-bar[hidden] { display: none !important; }
#ql-bar {
  flex-shrink: 0;
  position: relative;
  display: flex;
  align-items: stretch;
  padding: 0 16px;
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}
#ql-track {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  gap: 2px;
  align-items: center;
  white-space: nowrap;
  min-height: 40px;
  padding: 0 4px;
  overflow-x: auto;
  overflow-y: hidden;
  /* No CSS smooth scrolling: the first jump to the active tab is instant;
     the arrows ask for a smooth step themselves (and not under reduced
     motion). */
  overscroll-behavior-x: contain;
  /* A tab reached by keyboard stops clear of the edge fades and arrows. */
  scroll-padding-inline: 40px;
  scrollbar-width: none;
  -ms-overflow-style: none;
  /* Soft edge fade, switched on per edge by .has-prev / .has-next. */
  --ql-fade-l: 0px;
  --ql-fade-r: 0px;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--ql-fade-l), #000 calc(100% - var(--ql-fade-r)), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 var(--ql-fade-l), #000 calc(100% - var(--ql-fade-r)), transparent 100%);
}
#ql-track::-webkit-scrollbar { display: none; height: 0; }
#ql-bar.has-prev #ql-track { --ql-fade-l: 36px; }
#ql-bar.has-next #ql-track { --ql-fade-r: 36px; }

/* Group label and the thin divider between groups, as the rail groups them. */
.ql-group {
  flex-shrink: 0;
  padding: 0 6px 0 4px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-2);
  user-select: none;
}
.ql-sep {
  flex-shrink: 0;
  width: 1px;
  height: 18px;
  margin: 0 8px;
  background: var(--border);
}

/* One tab: the rail row's own icon and label, one quiet colour. */
.ql-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  height: 30px;
  padding: 0 10px;
  border-radius: 8px;
  border: 1px solid transparent;
  color: var(--text-2);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: -0.01em;
  text-decoration: none;
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}
.ql-ico { display: inline-flex; width: 16px; height: 16px; color: var(--text-3); transition: color 0.15s ease; }
.ql-ico svg { width: 16px; height: 16px; }
.ql-label { line-height: 1; }
.ql-tab:hover { color: var(--text); background: rgba(0, 113, 227, 0.06); }
.ql-tab:hover .ql-ico { color: var(--text-2); }
.ql-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.ql-tab.is-active {
  color: var(--text);
  font-weight: 600;
  background: rgba(0, 113, 227, 0.08);
  border-color: rgba(0, 212, 255, 0.45);
}
.ql-tab.is-active .ql-ico { color: var(--accent); }
/* The rail's status LED, centred under the active tab. */
.ql-tab.is-active::after {
  content: '';
  position: absolute;
  left: 50%; bottom: 2px;
  transform: translateX(-50%);
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--led-cyan, #00d4ff);
  box-shadow: 0 0 8px var(--led-cyan, #00d4ff), 0 0 2px #fff inset;
}

/* Edge arrows: the rail's caret, the left one mirrored. They float over the
   fade zones, so the tabs do not shift when one appears or goes. */
.ql-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--bg-card);
  color: var(--text-2);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.ql-arrow[hidden] { display: none; }
.ql-arrow--prev { left: 8px; }
.ql-arrow--next { right: 8px; }
.ql-arrow svg { width: 14px; height: 14px; }
.ql-arrow--prev svg { transform: scaleX(-1); }
.ql-arrow:hover { color: var(--accent); border-color: rgba(0, 212, 255, 0.55); }
.ql-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Phones: icons only (the label stays for screen readers and the tip). */
@media (max-width: 720px) {
  .ql-group { display: none; }
  .ql-sep { margin: 0 4px; }
  .ql-tab { padding: 0 9px; }
  .ql-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}

/* Back button */
#back-btn { white-space: nowrap; }
#back-btn:hover { background: var(--bg) !important; }

/* =========================================================
   ELECTRIC-BLUE LED HIGHLIGHT — sidebar modules + dashboard
   module tiles. Soft cyan→electric-blue glow behind each
   item, with a gentle pulse staggered per item. Active item
   gets a brighter glow plus a small "status LED" dot on the
   left edge.

   prefers-reduced-motion: animation is frozen — the static
   glow remains so the highlight is still visible, just not
   pulsing.
   ========================================================= */
:root {
  /* The LogistiQ lead-chevron tokens (rail marker, row markers, drawer
     tab marker). Light cut = the brand mark's own gradient stops. */
  --tw-tri-hi:    #7fd6e0;
  --tw-tri-mid:   #2f8b99;
  --tw-tri-lo:    #155560;
  --tw-tri-edge:  #a8ebf2;
  --tw-tri-glow:  rgba(0, 170, 210, 0.45);
  --led-cyan:     #00d4ff;
  --led-blue:     #0066ff;
  --led-glow-min: 0.20;
  --led-glow-max: 0.45;
  --led-glow-hover: 0.60;
  --led-glow-active: 0.80;
}

@keyframes tw-led-pulse {
  0%, 100% { opacity: var(--led-glow-min); transform: translate(-50%, -50%) scale(1); }
  50%      { opacity: var(--led-glow-max); transform: translate(-50%, -50%) scale(1.05); }
}

/* Sidebar items get the LED glow behind them. The .nav-item
   rule above sets up the rounded rect; we layer a ::before
   pseudo behind it. position:relative is added so absolute
   positioning resolves against the item, not the sidebar. */
.sidebar .nav-item {
  position: relative;
  isolation: isolate; /* keeps ::before's blur behind item only */
}
.sidebar .nav-item::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width:  calc(100% - 6px);
  height: calc(100% - 4px);
  background: radial-gradient(ellipse at center,
              var(--led-cyan) 0%,
              var(--led-blue) 55%,
              transparent 85%);
  filter: blur(14px);
  opacity: var(--led-glow-min);
  z-index: -1;
  pointer-events: none;
  border-radius: 12px;
  animation: tw-led-pulse 4.8s ease-in-out infinite;
  animation-delay: var(--led-delay, 0s);
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.sidebar .nav-item:hover::before {
  opacity: var(--led-glow-hover);
}
.sidebar .nav-item.active {
  /* override the existing pale blue fill — let the LED do the work */
  background: rgba(0, 113, 227, 0.08);
  border: 1px solid rgba(0, 212, 255, 0.55);
  padding: 7px 19px; /* compensate for 1px border so layout doesn't shift */
}
.sidebar .nav-item.active::before {
  opacity: var(--led-glow-active);
  animation-duration: 3.2s;
}
.sidebar .nav-item.active::after {
  /* Tiny status-LED dot pinned to the left edge of active items. */
  content: '';
  position: absolute;
  left: -2px; top: 50%;
  transform: translateY(-50%);
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--led-cyan);
  box-shadow: 0 0 8px var(--led-cyan), 0 0 2px #fff inset;
  z-index: 1;
}

/* Dashboard module tiles (.quick-chip) — same LED treatment so the
   homepage "modules" feel match the sidebar modules. */
.quick-chip {
  isolation: isolate;
}
.quick-chip::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width:  calc(100% + 8px);
  height: calc(100% + 8px);
  background: radial-gradient(ellipse at center,
              var(--led-cyan) 0%,
              var(--led-blue) 55%,
              transparent 85%);
  filter: blur(18px);
  opacity: var(--led-glow-min);
  z-index: -1;
  pointer-events: none;
  border-radius: 18px;
  animation: tw-led-pulse 5.4s ease-in-out infinite;
  animation-delay: var(--led-delay, 0s);
  transition: opacity 0.25s ease;
}
.quick-chip:hover::before {
  opacity: var(--led-glow-hover);
}

/* Dark mode tweak — the LED reads stronger against dark navy
   so we ease the resting opacity down slightly to keep it
   from screaming. */
html[data-theme="dark"] {
  --led-glow-min: 0.14;
  --led-glow-max: 0.36;
  /* Dark cut: brighter so the chevron reads on near-black. */
  --tw-tri-hi:    #a8ebf2;
  --tw-tri-mid:   #3fb6c6;
  --tw-tri-lo:    #1d7f8d;
  --tw-tri-edge:  #d2f8fc;
  --tw-tri-glow:  rgba(0, 212, 255, 0.55);
}
html[data-theme="dark"] .sidebar .nav-item.active {
  background: rgba(10, 132, 255, 0.10);
  border-color: rgba(0, 212, 255, 0.45);
}

/* Respect prefers-reduced-motion — freeze the pulse but keep
   the static glow visible. Active items still get their
   brighter glow + LED dot. */
@media (prefers-reduced-motion: reduce) {
  .sidebar .nav-item::before,
  .quick-chip::before {
    animation: none !important;
    opacity: var(--led-glow-min);
  }
  .sidebar .nav-item.active::before {
    opacity: var(--led-glow-active);
  }
}

/* =========================================================
   NOTIFICATIONS BELL — topbar trigger + dropdown panel
   ========================================================= */
.tw-bell-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.tw-bell-btn:hover {
  background: var(--fill);
  color: var(--accent);
}
.tw-bell-btn[aria-expanded="true"] {
  background: var(--fill);
  color: var(--accent);
}
.tw-bell-btn.has-unread {
  color: var(--accent);
}
.tw-bell-btn svg {
  width: 22px; height: 22px;
  transition: transform 0.15s ease;
}
.tw-bell-btn:hover svg { transform: rotate(-8deg); }
.tw-bell-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.30);
}

.tw-bell-badge {
  position: absolute;
  top: 4px; right: 4px;
  min-width: 16px; height: 16px;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--danger);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  border-radius: 999px;
  line-height: 1;
  box-shadow: 0 0 0 2px var(--bg-card, #fff);
  letter-spacing: -0.02em;
}
.tw-bell-badge[data-count="0"] { display: none; }

.tw-notif-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 380px;
  max-width: calc(100vw - 32px);
  max-height: 480px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  /* Sits inside the header stacking context (header.h-16 has
     z-index: 100); a high local z-index keeps the dropdown above any
     sibling within the header (avatar, theme toggle popovers, etc.).
     Combined with the header's z-index 100, this puts the panel well
     above the dashboard quick-chip tiles which create their own
     stacking contexts via `isolation: isolate`. */
  z-index: 1100;
}
/* Keep the `hidden` attribute authoritative over the bare `.tw-notif-panel`
   display:flex above. Tailwind's Preflight hides [hidden] via a :where()
   rule (0 specificity), tying the bare class and losing on source order since
   app.css loads after tailwind.css. This class+attribute selector (0,0,2,0)
   wins the tie, so the panels stay hidden until JS clears `hidden`. */
.tw-notif-panel[hidden], .tw-wa-panel[hidden] { display: none; }
.tw-notif-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
}
.tw-notif-head-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}
.tw-notif-mark-all {
  background: none;
  border: 0;
  color: var(--accent);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  padding: 4px 6px;
  border-radius: 6px;
  transition: background 0.15s;
}
.tw-notif-mark-all:hover:not(:disabled) { background: rgba(0, 113, 227, 0.08); }
.tw-notif-mark-all:disabled { color: var(--text-3); cursor: default; }
.tw-notif-list {
  list-style: none;
  margin: 0;
  padding: 4px 0;
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 80px;
  max-height: 360px;
}
.tw-notif-list::-webkit-scrollbar { width: 6px; }
.tw-notif-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.tw-notif-list li { margin: 0; }
.tw-notif-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 16px;
  text-decoration: none;
  color: var(--text);
  transition: background 0.12s ease;
  position: relative;
}
.tw-notif-item:hover { background: var(--fill); }
.tw-notif-icon {
  flex-shrink: 0;
  width: 32px; height: 32px;
  border-radius: 9px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tw-notif-icon svg { width: 16px; height: 16px; }
.tw-notif-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.tw-notif-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tw-notif-text {
  font-size: 12px;
  color: var(--text-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: 1px;
  line-height: 1.35;
}
.tw-notif-time {
  font-size: 11px;
  color: var(--text-3);
  margin-top: 3px;
}
.tw-notif-unread-dot {
  flex-shrink: 0;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--danger);
  margin-top: 6px;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.tw-notif-item.is-unread .tw-notif-unread-dot { opacity: 1; }
.tw-notif-item.is-unread .tw-notif-title { color: var(--text); }

.tw-notif-loading,
.tw-notif-error,
.tw-notif-empty {
  padding: 24px 16px;
  text-align: center;
  color: var(--text-2);
  font-size: 13px;
  list-style: none;
}
.tw-notif-empty-icon {
  width: 36px; height: 36px;
  margin: 0 auto 8px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: rgba(48, 209, 88, 0.14);
  color: var(--success);
}
.tw-notif-empty-icon svg { width: 18px; height: 18px; }
.tw-notif-empty-title { font-weight: 600; color: var(--text); }
.tw-notif-empty-sub { font-size: 12px; color: var(--text-3); margin-top: 2px; }
.tw-notif-error { color: var(--danger); }

.tw-notif-foot {
  display: block;
  text-align: center;
  padding: 10px 12px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  font-weight: 500;
  color: var(--accent);
  text-decoration: none;
  transition: background 0.12s ease;
}
.tw-notif-foot:hover { background: var(--fill); }

/* =========================================================
   WHATSAPP SHORTCUT — topbar icon + dropdown (peer of bell)
   ========================================================= */

/* The WhatsApp button reuses .tw-bell-btn for sizing / hover / focus
   so the two icons share a visual rhythm. The .tw-wa-* selectors only
   override the bits that differ — badge colour, panel paddings, etc. */
.tw-wa-btn svg { width: 22px; height: 22px; }
.tw-wa-btn:hover svg { transform: none; } /* skip the bell-wiggle */

/* Green unread badge — distinct from the bell's red, matches the
   WhatsApp brand greens without using the protected Meta logo. */
.tw-wa-badge {
  background: var(--success, #25D366);
  color: #fff;
}

/* WhatsApp panel inherits .tw-notif-panel; we only tweak overflow so
   the avatar circles don't get clipped at the rounded corners. */
.tw-wa-panel { overflow: hidden; }

/* "+ New chat" chip in the panel header. */
.tw-wa-new-chat {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px 10px 5px 8px;
  background: var(--accent);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  border-radius: 999px;
  text-decoration: none;
  transition: filter 0.12s ease;
}
.tw-wa-new-chat:hover { filter: brightness(1.08); }
.tw-wa-new-chat svg   { width: 12px; height: 12px; }

/* Chat-bubble glyph beside the panel title. */
.tw-wa-head-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  color: var(--success, #25D366);
  margin-right: 6px;
  vertical-align: -3px;
}
.tw-wa-head-icon svg { width: 16px; height: 16px; }

/* Conversation rows — slightly denser than the notif rows. */
.tw-wa-list { padding: 4px 0; }
.tw-wa-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
}
.tw-wa-avatar {
  flex-shrink: 0;
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.tw-wa-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.tw-wa-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tw-wa-preview {
  font-size: 12px;
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tw-wa-right {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  min-width: 36px;
}
.tw-wa-time {
  font-size: 11px;
  color: var(--text-3);
}
.tw-wa-unread-chip {
  min-width: 18px;
  height: 18px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--success, #25D366);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

/* Bold the row's title + preview when it has unread messages. */
.tw-wa-row.is-unread .tw-wa-title,
.tw-wa-row.is-unread .tw-wa-preview { color: var(--text); font-weight: 600; }

/* Empty-state CTA button. */
.tw-wa-empty-icon {
  background: rgba(37, 211, 102, 0.16) !important;
  color: var(--success, #25D366) !important;
}
.tw-wa-cta {
  display: inline-block;
  margin-top: 10px;
  padding: 6px 14px;
  background: var(--accent);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  border-radius: 999px;
  text-decoration: none;
}
.tw-wa-cta:hover { filter: brightness(1.08); }

/* Respect prefers-reduced-motion — kill the bell-wiggle transition
   on the WhatsApp icon and any animated transitions on its rows. */
@media (prefers-reduced-motion: reduce) {
  .tw-wa-btn svg,
  .tw-wa-row,
  .tw-wa-new-chat,
  .tw-wa-cta { transition: none !important; }
}


/* ===========================================================
   NAV RAIL v1 — "Rail + Context" (Option A, approved by Brent
   2026-07-16). Replaces the seven competing accordion headers
   at rest with a slim icon rail of modules plus ONE contextual
   panel showing only the active module's pages. Every href,
   sub-item and `requires` gate carries over untouched: a NAV
   section simply BECOMES a rail module, so nothing is re-homed
   and nobody relearns where a page lives. Mirrors the PalmStat
   nav-v2 pattern so the two products feel like one family.

   Escape hatch: ?nav=classic restores the accordion above and
   persists for the session (see twNavMode() in app.js).

   Motion: the active marker (.nav-rail-tri) GLIDES between the
   icons, the newly selected icon pops, and the incoming panel
   slides in with its rows staggered. All of it is suppressed
   on first paint by .tw-anim-boot and switched off entirely
   under prefers-reduced-motion.
   =========================================================== */

.sidebar.nav-rail-mode {
  flex-direction: row !important;
  overflow: hidden !important;
  width: 260px !important;
  flex-shrink: 0;
}

/* ---- the rail ---- */
.sidebar.nav-rail-mode .nav-rail {
  width: 56px; flex: 0 0 56px;
  display: flex; flex-direction: column; align-items: center;
  padding: 10px 0;
  border-right: 1px solid var(--border);
  position: relative; z-index: 2;
}
/* Brand mark: the faithful three-chevron LogistiQ trio, bare (no tile).
   position: relative is load-bearing, the .nav-rail-tip hover label is
   absolutely positioned against this element. The trio paints 100x62 in
   a 0 0 100 100 viewBox, so at 38px square the artwork reads ~38x24
   with symmetric breathing room above and below. */
.sidebar.nav-rail-mode .nav-rail-mark {
  position: relative;
  width: 38px; height: 38px;
  display: flex; align-items: center; justify-content: center;
  text-decoration: none; flex-shrink: 0; margin-bottom: 10px;
  transition: transform 0.18s ease;
}
.sidebar.nav-rail-mode .nav-rail-mark .nav-rail-mark-svg {
  width: 38px; height: 38px;
  display: block; overflow: visible;
}
.sidebar.nav-rail-mode .nav-rail-mark:hover {
  transform: translateY(-1px) scale(1.06);
}

/* The track owns the sliding pill, so the buttons measure their
   offsetTop against it (position: relative = offsetParent). */
.sidebar.nav-rail-mode .nav-rail-track {
  position: relative;
  width: 100%; flex: 1 1 auto;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
}

/* The marker that glides (14 Oct 2026, Brent's General 1): the lead,
   cyan chevron of the TW LogistiQ mark, pointing at the active module.
   It replaced the rounded pill and keeps the pill's motion exactly: JS
   parks it with translateY(offsetTop) and the same spring curve carries
   it between modules. The box is the full 40px row height but only 12px
   wide at the rail's left edge, so the triangle sits INSIDE the 56px rail
   and never under the icon. Colours: the --tw-tri-* brand tokens. */
.sidebar.nav-rail-mode .nav-rail-tri {
  position: absolute; top: 0; left: 3px;
  width: 12px; height: 40px;
  display: flex; align-items: center;
  opacity: 0; pointer-events: none;
  transition: transform 0.38s cubic-bezier(0.34, 1.28, 0.44, 1), opacity 0.2s ease;
}
.sidebar.nav-rail-mode .nav-rail-tri-svg {
  display: block; width: 10px; height: 15px; overflow: visible;
  transform-origin: 0 50%;
  filter: drop-shadow(0 0 3px var(--tw-tri-glow));
  animation: twRailTriBreathe 3.2s ease-in-out infinite;
}
@keyframes twRailTriBreathe {
  0%, 100% { filter: drop-shadow(0 0 2px var(--tw-tri-glow)); }
  50%      { filter: drop-shadow(0 0 5px var(--tw-tri-glow)); }
}
/* One flare as it lands on a newly chosen module (JS replays .did-land). */
@keyframes twRailTriLand {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.35) translateX(1px); }
  100% { transform: scale(1); }
}
.sidebar.nav-rail-mode .nav-rail-tri.did-land .nav-rail-tri-svg {
  animation: twRailTriLand 0.34s cubic-bezier(0.34, 1.3, 0.44, 1), twRailTriBreathe 3.2s ease-in-out 0.34s infinite;
}

.sidebar.nav-rail-mode .nav-rail-btn {
  position: relative;
  width: 40px; height: 40px; flex: 0 0 40px;
  border: 0; background: none; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3); border-radius: 12px;
  transition: color 0.18s ease, background 0.18s ease;
}
.sidebar.nav-rail-mode .nav-rail-btn .nav-rail-ico {
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.22s cubic-bezier(0.34, 1.4, 0.44, 1);
}
.sidebar.nav-rail-mode .nav-rail-btn svg { width: 19px; height: 19px; color: currentColor; }
.sidebar.nav-rail-mode .nav-rail-btn:hover { color: var(--text); background: var(--fill); }
.sidebar.nav-rail-mode .nav-rail-btn:hover .nav-rail-ico { transform: scale(1.12); }
.sidebar.nav-rail-mode .nav-rail-btn.is-on { color: var(--accent); background: none; }

/* Icon pop on the newly selected module — the class is stamped
   by JS after a forced reflow so it replays on every switch. */
@keyframes twRailPop {
  0%   { transform: scale(1); }
  42%  { transform: scale(1.26); }
  100% { transform: scale(1); }
}
.sidebar.nav-rail-mode .nav-rail-btn.did-pop .nav-rail-ico {
  animation: twRailPop 0.34s cubic-bezier(0.34, 1.3, 0.44, 1);
}

/* Small LogistiQ triangle = "your current page lives in this module",
   shown only while you are browsing a DIFFERENT module's panel. It was a
   cyan dot until 14 Oct 2026. Inside the 40px button, bottom right. */
.sidebar.nav-rail-mode .nav-rail-btn.has-active::after {
  content: ''; position: absolute; right: 5px; bottom: 5px;
  width: 6px; height: 8px; border-radius: 0;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  background: linear-gradient(180deg, var(--tw-tri-hi) 0%, var(--tw-tri-mid) 50%, var(--tw-tri-lo) 100%);
}
.sidebar.nav-rail-mode .nav-rail-btn.has-active.is-on::after { display: none; }

/* Hover label — the week-one training wheels for the icons. */
.sidebar.nav-rail-mode .nav-rail-tip {
  position: absolute; left: calc(100% + 4px); top: 50%;
  transform: translateY(-50%) translateX(-4px);
  white-space: nowrap; pointer-events: none;
  background: var(--text); color: var(--bg-card);
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.2px;
  padding: 4px 9px; border-radius: 7px;
  opacity: 0; z-index: 5;
  box-shadow: 0 4px 14px rgba(0,0,0,0.22);
  transition: opacity 0.16s ease, transform 0.16s ease;
}
.sidebar.nav-rail-mode .nav-rail-btn:hover .nav-rail-tip,
.sidebar.nav-rail-mode .nav-rail-btn:focus-visible .nav-rail-tip,
.sidebar.nav-rail-mode .nav-rail-mark:hover .nav-rail-tip {
  opacity: 1; transform: translateY(-50%) translateX(0);
}

/* Back to landing sits at the foot of the rail. Neutralise the
   generic .sidebar .logout-link type styling it inherits (the
   label is delivered by the hover tip, not inline text). */
.sidebar.nav-rail-mode .nav-rail-back {
  margin-top: 6px; flex: 0 0 40px;
  color: var(--text-3) !important; font-size: 0 !important;
}
.sidebar.nav-rail-mode .nav-rail-back .nav-rail-tip { font-size: 11.5px !important; }
.sidebar.nav-rail-mode .nav-rail-back:hover { color: var(--danger) !important; }

/* ---- the contextual panel ---- */
.sidebar.nav-rail-mode .nav-ctx {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; overflow: hidden;
}
.sidebar.nav-rail-mode .nav-ctx-brand {
  padding: 14px 14px 12px; border-bottom: 1px solid var(--border); flex: 0 0 auto;
}
.sidebar.nav-rail-mode .nav-ctx-brand .tw-sidebar-logo { max-width: 100%; height: auto; }
.sidebar.nav-rail-mode .nav-ctx-panels {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 8px 0 10px;
}
.sidebar.nav-rail-mode .nav-ctx-panel { display: none; }
.sidebar.nav-rail-mode .nav-ctx-panel[hidden] { display: none; }
.sidebar.nav-rail-mode .nav-ctx-panel.is-on { display: block; }
.sidebar.nav-rail-mode .nav-ctx-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; padding: 4px 14px 8px;
}
.sidebar.nav-rail-mode .nav-ctx-name {
  font-size: 12.5px; font-weight: 700; color: var(--text);
  letter-spacing: 0.02em; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sidebar.nav-rail-mode .nav-ctx-count {
  font-size: 10.5px; color: var(--text-3); flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
/* Roomier rows: the panel is narrower than the old w-64 rail. */
.sidebar.nav-rail-mode .nav-item {
  padding: 7px 10px; margin: 1px 6px; font-size: 13.5px; gap: 10px;
}
.sidebar.nav-rail-mode .nav-item svg { width: 17px; height: 17px; }
.sidebar.nav-rail-mode .user-block { padding: 12px 14px; flex: 0 0 auto; }

/* Panel swap: the incoming module slides in from the rail side
   and its rows cascade, so switching reads as movement rather
   than a hard cut. --row is stamped per row in renderShell. */
@keyframes twNavPanelIn {
  from { opacity: 0; transform: translateX(-10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes twNavRowIn {
  from { opacity: 0; transform: translateX(-8px); }
  to   { opacity: 1; transform: none; }
}
.sidebar.nav-rail-mode .nav-ctx-panel.is-on {
  animation: twNavPanelIn 0.26s cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
.sidebar.nav-rail-mode .nav-ctx-panel.is-on .nav-item {
  animation: twNavRowIn 0.3s cubic-bezier(0.2, 0.7, 0.3, 1) both;
  animation-delay: calc(var(--row, 0) * 22ms);
}

/* ---- rail-mode row markers and sub-row motion (14 Oct 2026) ----
   The active row's marker is a small LogistiQ triangle (span.nav-tri,
   drawn only in rail mode) instead of the 4px LED dot, which sat at
   left:-2px and was half clipped by the panel column (overflow-y:auto
   clips x too). The triangle sits inside the row's own left padding:
   3px in on a parent row (padding 10px), 16px in on a sub-row (padding
   30px). The classic accordion keeps its dot: every rule here is scoped
   to .nav-rail-mode. */
.sidebar.nav-rail-mode .nav-item.active::after { content: none; display: none; }
.sidebar.nav-rail-mode .nav-item--tri .nav-tri {
  position: absolute; left: 3px; top: 50%;
  width: 5px; height: 8px; margin-top: -4px;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  background: linear-gradient(180deg, var(--tw-tri-hi) 0%, var(--tw-tri-mid) 50%, var(--tw-tri-lo) 100%);
  pointer-events: none; z-index: 1;
  animation: twNavTriIn 0.32s cubic-bezier(0.34, 1.4, 0.44, 1) both;
  animation-delay: calc(var(--row, 0) * 22ms + 120ms);
}
.sidebar.nav-rail-mode .nav-subitem.nav-item--tri .nav-tri {
  left: 16px; width: 6px; height: 9px; margin-top: -4.5px;
}
@keyframes twNavTriIn {
  from { opacity: 0; transform: translateX(-4px) scale(0.4); }
  to   { opacity: 1; transform: none; }
}

/* Sub-rows: a quick staggered reveal when their module's panel opens
   (after the parent row lands), and a staggered ripple, icon nudge plus
   an LED flash, whenever their parent row is hovered or focused, in the
   same family as the rail's staggered LED pulse. --sub is each sub-row's
   place under its parent, stamped by renderShell. */
@keyframes twNavSubIn {
  0%   { opacity: 0; transform: translateX(-12px); }
  65%  { opacity: 1; transform: translateX(2px); }
  100% { opacity: 1; transform: none; }
}
.sidebar.nav-rail-mode .nav-ctx-panel.is-on .nav-subitem {
  animation-name: twNavSubIn;
  animation-duration: 0.34s;
  animation-delay: calc(var(--row, 0) * 22ms + 40ms + var(--sub, 0) * 26ms);
}
@keyframes twNavSubNudge {
  0%   { transform: none; }
  45%  { transform: translateX(3px) scale(1.12); }
  100% { transform: none; }
}
@keyframes twNavSubLed {
  0%   { opacity: var(--led-glow-min); transform: translate(-50%, -50%) scale(1); }
  40%  { opacity: var(--led-glow-hover); transform: translate(-50%, -50%) scale(1.04); }
  100% { opacity: var(--led-glow-min); transform: translate(-50%, -50%) scale(1); }
}
.sidebar.nav-rail-mode .nav-tri-group > .nav-item:not(.nav-subitem):hover ~ .nav-subitem svg,
.sidebar.nav-rail-mode .nav-tri-group > .nav-item:not(.nav-subitem):focus-visible ~ .nav-subitem svg {
  animation: twNavSubNudge 0.38s cubic-bezier(0.34, 1.4, 0.44, 1) both;
  animation-delay: calc(var(--sub, 0) * 40ms);
}
.sidebar.nav-rail-mode .nav-tri-group > .nav-item:not(.nav-subitem):hover ~ .nav-subitem::before,
.sidebar.nav-rail-mode .nav-tri-group > .nav-item:not(.nav-subitem):focus-visible ~ .nav-subitem::before {
  animation: twNavSubLed 0.55s ease-out both;
  animation-delay: calc(var(--sub, 0) * 40ms);
}

/* First paint must be still: the boot guard is lifted one frame
   after the scroll restore lands (see app.js), exactly as it is
   for the accordion. */
.sidebar.tw-anim-boot.nav-rail-mode .nav-rail-tri,
.sidebar.tw-anim-boot.nav-rail-mode .nav-rail-tri-svg,
.sidebar.tw-anim-boot.nav-rail-mode .nav-tri,
.sidebar.tw-anim-boot.nav-rail-mode .nav-subitem svg,
.sidebar.tw-anim-boot.nav-rail-mode .nav-subitem::before,
.sidebar.tw-anim-boot.nav-rail-mode .nav-ctx-panel.is-on,
.sidebar.tw-anim-boot.nav-rail-mode .nav-ctx-panel.is-on .nav-item,
.sidebar.tw-anim-boot.nav-rail-mode .nav-rail-btn .nav-rail-ico {
  animation: none !important;
  transition: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .sidebar.nav-rail-mode .nav-rail-tri,
  .sidebar.nav-rail-mode .nav-rail-mark,
  .sidebar.nav-rail-mode .nav-rail-btn,
  .sidebar.nav-rail-mode .nav-rail-btn .nav-rail-ico,
  .sidebar.nav-rail-mode .nav-rail-tip { transition: none; }
  .sidebar.nav-rail-mode .nav-ctx-panel.is-on,
  .sidebar.nav-rail-mode .nav-ctx-panel.is-on .nav-item,
  .sidebar.nav-rail-mode .nav-rail-btn.did-pop .nav-rail-ico { animation: none; }
  /* The markers stay, still: only their motion goes. */
  .sidebar.nav-rail-mode .nav-rail-tri-svg,
  .sidebar.nav-rail-mode .nav-rail-tri.did-land .nav-rail-tri-svg,
  .sidebar.nav-rail-mode .nav-tri,
  .sidebar.nav-rail-mode .nav-tri-group > .nav-item:not(.nav-subitem):hover ~ .nav-subitem svg,
  .sidebar.nav-rail-mode .nav-tri-group > .nav-item:not(.nav-subitem):focus-visible ~ .nav-subitem svg,
  .sidebar.nav-rail-mode .nav-tri-group > .nav-item:not(.nav-subitem):hover ~ .nav-subitem::before,
  .sidebar.nav-rail-mode .nav-tri-group > .nav-item:not(.nav-subitem):focus-visible ~ .nav-subitem::before { animation: none !important; }
}

/* Theme-logo swap, specificity fix (found during the rail build, 2026-07-16).
   `.tw-sidebar-logo { display: block }` is declared in the shell's inline
   <style> (app.js), which the browser applies AFTER this file and which TIES
   on specificity with `.tw-logo-dark { display: none }` above. Source order
   therefore won and BOTH logos rendered in the light theme; dark only looked
   right because its rule carries an extra attribute selector. Raise the
   specificity so the swap wins in both directions, including when no
   data-theme has been stamped yet. */
html:not([data-theme="dark"]) img.tw-logo-dark  { display: none !important; }
html[data-theme="dark"]       img.tw-logo-light { display: none !important; }

/* ===========================================================
   COMMAND PALETTE (Ctrl/Cmd + K) — Option D, layered on top of
   the rail nav without touching it (approved 2026-07-16).
   Fuzzy search across every page the signed-in user is
   entitled to, built from the SAME NAV array the rail uses, so
   the two can never drift apart. Keyboard-first: the input
   keeps focus and the highlighted row is announced via
   aria-activedescendant (standard combobox pattern), so there
   is no focus trap to fight.
   =========================================================== */

/* The `hidden` attribute is zero-specificity in the Tailwind
   preflight (`[hidden]:where(...)`), so a class-level display
   would beat it. Guard it explicitly — same lesson as the
   notification and WhatsApp panels. */
.tw-cmdk[hidden] { display: none !important; }

.tw-cmdk {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: flex-start; justify-content: center;
  padding: 12vh 16px 16px;
}
.tw-cmdk-backdrop {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  animation: twCmdkFade 0.16s ease both;
}
html[data-theme="dark"] .tw-cmdk-backdrop { background: rgba(0, 0, 0, 0.62); }

.tw-cmdk-dialog {
  position: relative;
  width: 100%; max-width: 620px;
  display: flex; flex-direction: column;
  max-height: 74vh;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.28), 0 0 0 1px rgba(0, 212, 255, 0.10);
  overflow: hidden;
  animation: twCmdkRise 0.2s cubic-bezier(0.2, 0.8, 0.3, 1) both;
}
html[data-theme="dark"] .tw-cmdk-dialog {
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(0, 212, 255, 0.16);
}

/* ---- search field ---- */
.tw-cmdk-head {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 14px; flex: 0 0 auto;
  border-bottom: 1px solid var(--border);
}
.tw-cmdk-head > svg { width: 18px; height: 18px; color: var(--text-3); flex-shrink: 0; }
.tw-cmdk-input {
  flex: 1 1 auto; min-width: 0;
  border: 0; outline: 0; background: none;
  color: var(--text); font-size: 15px; font-family: inherit;
}
.tw-cmdk-input::placeholder { color: var(--text-3); }

/* ---- results ---- */
.tw-cmdk-list {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  margin: 0; padding: 6px; list-style: none;
}
.tw-cmdk-group {
  font-size: 10px; font-weight: 700; letter-spacing: 1.6px; text-transform: uppercase;
  color: var(--text-3); padding: 10px 10px 5px;
}
.tw-cmdk-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 9px; cursor: pointer;
  color: var(--text); font-size: 13.5px;
  border: 1px solid transparent;
}
.tw-cmdk-row > svg { width: 16px; height: 16px; color: var(--text-3); flex-shrink: 0; }
.tw-cmdk-row .tw-cmdk-label { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tw-cmdk-row .tw-cmdk-where {
  font-size: 11px; color: var(--text-3); flex-shrink: 0;
  max-width: 45%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tw-cmdk-row mark { background: none; color: var(--accent); font-weight: 700; }
.tw-cmdk-row.is-active {
  background: rgba(0, 113, 227, 0.10);
  border-color: rgba(0, 212, 255, 0.45);
  color: var(--accent);
}
.tw-cmdk-row.is-active > svg { color: var(--accent); }
.tw-cmdk-row.is-active .tw-cmdk-where { color: var(--accent); opacity: 0.75; }
.tw-cmdk-row.is-current .tw-cmdk-label::after {
  content: 'current'; margin-left: 8px;
  font-size: 9.5px; letter-spacing: 1px; text-transform: uppercase;
  color: var(--text-3); font-weight: 700;
}
.tw-cmdk-empty { padding: 26px 14px; text-align: center; color: var(--text-3); font-size: 13px; }

/* ---- footer hints ---- */
.tw-cmdk-foot {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 9px 14px; flex: 0 0 auto;
  border-top: 1px solid var(--border);
  font-size: 11px; color: var(--text-3);
}
.tw-cmdk-foot .tw-cmdk-count { margin-left: auto; font-variant-numeric: tabular-nums; }
.tw-cmdk-kbd {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px;
  border: 1px solid var(--border); border-bottom-width: 2px;
  border-radius: 5px; background: var(--fill);
  font-family: ui-monospace, "Cascadia Mono", "Segoe UI Mono", Menlo, monospace;
  font-size: 10px; color: var(--text-2);
}

/* ---- the discoverable trigger in the topbar ---- */
.tw-cmdk-trigger {
  display: inline-flex; align-items: center; gap: 8px;
  height: 36px; padding: 0 8px 0 10px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-card); color: var(--text-3);
  font-size: 12.5px; font-family: inherit; cursor: pointer;
  transition: color 0.16s ease, border-color 0.16s ease, background 0.16s ease;
}
.tw-cmdk-trigger:hover { color: var(--text); border-color: rgba(0, 212, 255, 0.55); }
.tw-cmdk-trigger > svg { width: 15px; height: 15px; flex-shrink: 0; }
.tw-cmdk-trigger-label { white-space: nowrap; }
@media (max-width: 900px) {
  .tw-cmdk-trigger-label, .tw-cmdk-trigger .tw-cmdk-kbd { display: none; }
  .tw-cmdk-trigger { padding: 0 9px; }
}
@media (max-width: 700px) {
  .tw-cmdk { padding-top: 8vh; }
  .tw-cmdk-dialog { max-height: 82vh; }
}

@keyframes twCmdkFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes twCmdkRise {
  from { opacity: 0; transform: translateY(-10px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .tw-cmdk-backdrop, .tw-cmdk-dialog { animation: none; }
  .tw-cmdk-trigger { transition: none; }
}

/* 1.40.0 SHELL item 11: the keyboard icon beside the WhatsApp button and the
   shortcuts screen (the cmdk dialog as a panel: Back top left, the page
   search, and the shortcut list beside it, stacked on a phone). */
.tw-cmdk-icon { display: inline-flex; align-items: center; justify-content: center; }
.tw-cmdk-icon > svg { width: 22px; height: 22px; }
.tw-cmdk-icon:focus-visible, .tw-cmdk-back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tw-cmdk-panel { max-width: 920px; max-height: 80vh; }
.tw-cmdk-top {
  display: flex; align-items: center; gap: 12px; flex: 0 0 auto;
  padding: 10px 14px; border-bottom: 1px solid var(--border);
}
.tw-cmdk-back {
  display: inline-flex; align-items: center; gap: 4px;
  height: 32px; padding: 0 10px 0 6px;
  border: 1px solid var(--border); border-radius: 9px;
  background: var(--bg-card); color: var(--text-2);
  font: inherit; font-size: 12.5px; cursor: pointer;
}
.tw-cmdk-back:hover { color: var(--text); border-color: rgba(0, 212, 255, 0.55); }
.tw-cmdk-back > svg { width: 16px; height: 16px; }
.tw-cmdk-title { margin: 0; font-size: 14px; font-weight: 700; color: var(--text); }
.tw-cmdk-cols { display: flex; flex: 1 1 auto; min-height: 0; }
.tw-cmdk-cols > .tw-cmdk-list { flex: 1 1 55%; min-width: 0; }
.tw-cmdk-keys {
  flex: 1 1 45%; min-width: 0; overflow-y: auto;
  padding: 6px 10px 10px; border-left: 1px solid var(--border);
}
.tw-cmdk-keylist { list-style: none; margin: 0; padding: 0; }
.tw-cmdk-key {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 7px 4px; border-bottom: 1px solid var(--border);
  font-size: 12.5px; color: var(--text-2); line-height: 1.4;
}
.tw-cmdk-key:last-child { border-bottom: 0; }
.tw-cmdk-key-keys { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 3px; flex-wrap: wrap; min-width: 112px; }
.tw-cmdk-key-what { flex: 1 1 auto; min-width: 0; color: var(--text); }
.tw-cmdk-plus, .tw-cmdk-or { font-size: 10px; color: var(--text-3); padding: 0 2px; }
@media (max-width: 700px) {
  .tw-cmdk { padding: 8px; }
  .tw-cmdk-panel { max-height: calc(100vh - 16px); }
  .tw-cmdk-cols { flex-direction: column; overflow-y: auto; }
  .tw-cmdk-cols > .tw-cmdk-list { flex: 0 0 auto; max-height: 40vh; }
  .tw-cmdk-keys { border-left: 0; border-top: 1px solid var(--border); overflow: visible; }
  .tw-cmdk-key-keys { min-width: 88px; }
}

/* =================================================================
   Notification bell, server-rendered partial (K3)
   resources/views/partials/_notifications-bell.blade.php

   The bell itself reuses .tw-bell-btn / .tw-notif-panel / .tw-notif-item
   above, so only the few things the partial adds live here: the wrapper it
   hangs off, and the flat colour disc it uses in place of the per-kind SVG
   the JS shell paints. The disc takes its colour inline from the
   notification's own icon_color, which is why there is no palette here.
   ================================================================= */
.tw-nbell { position: relative; display: inline-flex; }

/* Colour disc standing in for an icon. Same box as .tw-notif-icon so rows
   line up whichever bell rendered them. */
.tw-nbell-dot { position: relative; }
.tw-nbell-dot::after {
  content: "";
  width: 10px; height: 10px;
  border-radius: 50%;
  background: currentColor;
}

/* An unread row is the one the approver still owes an answer on, so it gets
   a left edge rather than only the dot on the right. */
.tw-nbell .tw-notif-item.is-unread { box-shadow: inset 2px 0 0 var(--accent, #0a84ff); }

@media (prefers-reduced-motion: reduce) {
  .tw-nbell .tw-notif-item { transition: none; }
}

/* =================================================================
   RECORD DRAWER (amendment 12 Oct 2026, item 8 chrome, lane shell)

   One right-hand drawer for the whole office shell, the TruCore
   procurement slide-over ported to LogistiQ tokens: a body-level scrim
   (z 180) and drawer (z 190), min(560px, 94vw) wide and the full width
   under 768px, sliding in over 260ms and out over 200ms on --ease-out,
   instant under reduced motion. Modals (the document viewer) sit above
   it. The body is a server fragment; the classes from .tw-dr-head down
   are shared chrome a fragment may use. window.twDrawer in app.js.
   ================================================================= */
.tw-sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}

.tw-scrim {
  position: fixed; inset: 0; z-index: 180;
  background: rgba(11, 15, 42, 0.32);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  opacity: 0;
  transition: opacity 220ms var(--ease-out);
}
html[data-theme="dark"] .tw-scrim { background: rgba(0, 0, 0, 0.55); }
.tw-scrim.on { opacity: 1; }

.tw-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 190;
  width: min(560px, 94vw);
  display: flex; flex-direction: column;
  background: var(--bg-elevated);
  color: var(--text);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  font-size: 0.875rem;
  outline: none;
  transform: translateX(103%);
  transition: transform 200ms var(--ease-out);
}
.tw-drawer.on {
  transform: translateX(0);
  transition-duration: 260ms;
}
/* Tailwind's [hidden] reset has no specificity: keep both gone at rest. */
.tw-scrim[hidden], .tw-drawer[hidden] { display: none; }
/* Never inherit a page entrance animation. */
.tw-scrim, .tw-drawer { animation: none !important; }

.tw-drawer-x {
  position: absolute; top: 14px; right: 16px; z-index: 2;
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 8px;
  background: transparent; color: var(--text-2);
  cursor: pointer;
}
.tw-drawer-x:hover { background: var(--fill); color: var(--text); }
.tw-drawer-x[hidden] { display: none; }

.tw-drawer-body {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Saving: a thin LED bar along the top edge. */
.tw-drawer.is-saving::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 2px; z-index: 3;
  background: linear-gradient(90deg, var(--led-cyan), var(--led-blue), var(--led-cyan));
  background-size: 200% 100%;
  animation: twDrawerSaving 1.2s linear infinite;
}
@keyframes twDrawerSaving { from { background-position: 100% 0; } to { background-position: -100% 0; } }

/* Loading and error states. */
.tw-drawer-state {
  flex: 1 1 auto;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 16px;
  padding: 56px 24px;
  text-align: center;
}
.tw-drawer-state--loading { justify-content: flex-start; padding-top: 72px; }
.tw-drawer-loading-mark .tw-pulse-svg { width: 72px; height: 43px; display: block; }
/* 1.40.0 SHELL item 1: the drawer shows the page loader's animated triangle
   pulse (tw-transitions.css .tw-loader-tri, which also stills it under
   reduced motion) from the moment it opens until the fragment lands. */
.tw-drawer-loading-mark .tw-loader-svg { width: 96px; height: 57px; display: block; overflow: visible; margin: 0 auto; }
html[data-theme="light"] .tw-drawer-loading-mark .tw-loader-svg polygon:first-child { fill: #2aa7bb; }
.tw-drawer-skel {
  width: 100%; max-width: 440px;
  display: flex; flex-direction: column; gap: 12px;
  margin-top: 12px;
}
.tw-drawer-skel span {
  display: block; height: 12px;
  border-radius: 6px;
  background: var(--fill);
}
.tw-drawer-skel span:nth-child(1) { width: 46%; height: 18px; }
.tw-drawer-skel span:nth-child(2) { width: 82%; }
.tw-drawer-skel span:nth-child(3) { width: 64%; }
.tw-drawer-skel span:nth-child(4) { width: 90%; }
.tw-drawer-skel span:nth-child(5) { width: 38%; }
.tw-drawer-state-title {
  margin: 0;
  font-size: 1rem; font-weight: 700; line-height: 1.4;
  color: var(--text);
  max-width: 400px;
}
.tw-drawer-state-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.tw-drawer-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 40px; padding: 0 18px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-card); color: var(--text);
  font: inherit; font-size: 0.875rem; font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}
.tw-drawer-btn:hover { border-color: rgba(0, 212, 255, 0.55); }
.tw-drawer-btn--primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.tw-drawer-btn--primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.tw-drawer-alert {
  margin: 12px 20px 0;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid rgba(255, 59, 48, 0.35);
  background: rgba(255, 59, 48, 0.08);
  color: var(--danger);
  font-size: 0.875rem; font-weight: 600;
}

/* Shared chrome for a drawer fragment: header, scrolling body, sticky foot. */
.tw-dr-head {
  flex: 0 0 auto;
  display: flex; flex-direction: column; gap: 6px;
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--border);
}
.tw-dr-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.tw-dr-iconbtn {
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 8px;
  background: transparent; color: var(--text-2);
  text-decoration: none; cursor: pointer;
}
.tw-dr-iconbtn:hover { background: var(--fill); color: var(--text); }
.tw-dr-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 16px 20px 34px; }
.tw-dr-foot {
  flex: 0 0 auto;
  display: flex; justify-content: flex-end; gap: 10px;
  padding: 12px 20px;
  border-top: 1px solid var(--border);
  background: var(--bg-elevated);
}

.tw-drawer :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* A row that opens the drawer says so, and shows where the keyboard is. */
[data-drawer-url] { cursor: pointer; }
[data-drawer-url]:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* The help mascot sits bottom right, where the drawer's foot is. */
html.tw-drawer-open #tru-we-widget { display: none; }

@media (max-width: 767.98px) {
  .tw-drawer { width: 100vw; border-left: 0; }
  .tw-drawer-x, .tw-dr-iconbtn { width: 44px; height: 44px; }
  .tw-drawer-x { top: 8px; right: 8px; }
  .tw-drawer-btn { min-height: 44px; }
}

@media (prefers-reduced-motion: reduce) {
  .tw-scrim, .tw-drawer, .tw-drawer.on { transition: none; }
  .tw-drawer.is-saving::before { animation: none; }
}

/* =================================================================
   BULK SELECTION BAR (amendment 12 Oct 2026, lane shell)

   window.twBulk.attach(table, {noun, actions}). A floating bar, bottom
   centre, with the count, the actions and Clear. A disabled action says
   why on hover, on keyboard focus and on a tap.
   ================================================================= */
.tw-bulk-bar {
  position: fixed; left: 50%; bottom: 24px; z-index: 170;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 12px;
  max-width: calc(100vw - 32px);
  padding: 8px 8px 8px 18px;
  background: var(--bg-elevated);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-lg), 0 0 0 1px rgba(0, 212, 255, 0.22), 0 0 24px rgba(0, 212, 255, 0.12);
  font-size: 0.875rem;
  animation: twBulkIn 200ms var(--ease-out) both;
}
.tw-bulk-bar[hidden] { display: none; }
@keyframes twBulkIn {
  from { opacity: 0; transform: translate(-50%, 12px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
.tw-bulk-count { font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
.tw-bulk-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.tw-bulk-btn {
  position: relative;
  min-height: 36px; padding: 0 16px;
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--bg-card); color: var(--text);
  font: inherit; font-size: 0.875rem; font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.tw-bulk-btn:hover { border-color: rgba(0, 212, 255, 0.55); }
.tw-bulk-btn--primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.tw-bulk-btn--primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.tw-bulk-btn[aria-disabled="true"],
.tw-bulk-btn--primary[aria-disabled="true"] {
  background: var(--bg-card); border-color: var(--border); color: var(--text-3);
  cursor: not-allowed;
}
.tw-bulk-btn[data-reason]:hover::after,
.tw-bulk-btn[data-reason]:focus-visible::after,
.tw-bulk-btn[data-reason].is-telling::after {
  content: attr(data-reason);
  position: absolute; left: 50%; bottom: calc(100% + 10px);
  transform: translateX(-50%);
  width: max-content; max-width: 260px;
  padding: 8px 10px;
  border-radius: 8px;
  background: var(--text); color: var(--bg-card);
  font-size: 0.875rem; font-weight: 500; line-height: 1.35;
  white-space: normal; text-align: left;
  box-shadow: var(--shadow);
  pointer-events: none;
}
.tw-bulk-clear {
  min-height: 36px; padding: 0 14px;
  border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--text-2);
  font: inherit; font-size: 0.875rem; font-weight: 600;
  cursor: pointer;
}
.tw-bulk-clear:hover { color: var(--text); background: var(--fill); }
.tw-bulk-bar :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

tr.is-bulk-selected > td { background: rgba(0, 113, 227, 0.06); }
html[data-theme="dark"] tr.is-bulk-selected > td { background: rgba(10, 132, 255, 0.14); }

@media (max-width: 767.98px) {
  .tw-bulk-bar {
    bottom: 12px;
    border-radius: 16px;
    flex-wrap: wrap; justify-content: center;
    padding: 10px 12px;
  }
  .tw-bulk-btn, .tw-bulk-clear { min-height: 44px; }
  /* Lift the help mascot above the bar while a selection is open. */
  html.tw-bulk-open #tru-we-widget { bottom: 132px; }
}

@media (prefers-reduced-motion: reduce) {
  .tw-bulk-bar { animation: none; }
}

/* ===========================================================
   DRAWER TAB STRIP + DOCUMENTS WELL (SHELL, 14 Oct 2026)
   <x-drawer.tabs> and <x-drawer.documents>, shared by every
   module drawer (clients, vehicles, drivers, suppliers, routes,
   bookings, trips, quotations, invoices, procurement), so they
   live here and every drawer is pixel-identical. Tokens only:
   both themes follow --bg-elevated / --border / --text-2 /
   --accent and the --tw-tri-* chevron tokens.
   =========================================================== */

/* The strip: small icon-over-label buttons in one sideways-scrolling
   row, stuck to the top of the drawer under the head while the body
   scrolls. Edge masks fade the clipped ends; no scrollbar. */
.twp-tabs {
  position: sticky; top: 0; z-index: 4;
  display: flex; flex-wrap: nowrap; gap: 2px;
  padding: 6px 14px 0;
  background: var(--bg-elevated, var(--bg-card));
  border-bottom: 1px solid var(--border);
  overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: 24px;
  /* 1.31.1 (Brent, 27 Oct 2026): a visible horizontal scroll bar, so tabs past the edge can be reached. */
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
  padding-bottom: 4px;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
}
.twp-tabs::-webkit-scrollbar { height: 6px; }
.twp-tabs::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.twp-tabs::-webkit-scrollbar-track { background: transparent; }
.twp-tabs[hidden] { display: none; }

.twp-tab {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-width: 64px; min-height: 48px;
  padding: 6px 10px 9px;
  border: 0; border-radius: 10px 10px 0 0;
  background: transparent;
  color: var(--text-2);
  font: inherit; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.02em; line-height: 1.1;
  white-space: nowrap;
  cursor: pointer;
  scroll-snap-align: center;
  scroll-margin-inline: 24px;
  transition: color 0.16s ease, background 0.16s ease;
}
.twp-tab:hover { color: var(--text); background: var(--fill); }
.twp-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.twp-tab:disabled,
.twp-tab[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; background: transparent; }
.twp-tab-ic { display: inline-flex; line-height: 0; }
.twp .twp-tab-ic svg,
.twp-tab-ic svg { width: 16px; height: 16px; stroke-width: 1.6; }
.twp-tab-l { display: block; }
.twp-tab-n {
  position: absolute; top: 3px; right: 6px;
  min-width: 15px; height: 15px; padding: 0 4px;
  border-radius: var(--r-pill, 999px);
  background: var(--fill); color: var(--text-2);
  font-size: 0.6rem; font-weight: 700; line-height: 15px; text-align: center;
  font-variant-numeric: tabular-nums;
}
.twp-tab.is-on { color: var(--accent); }
.twp-tab.is-on .twp-tab-n { background: var(--accent); color: var(--twp-on-accent, #fff); }
/* The active tab's marker: the same small LogistiQ triangle as the
   nav, turned to point up at the tab from the strip's bottom edge,
   plus an accent underline. Inside the tab's own box. */
.twp-tab.is-on::before {
  content: ''; position: absolute; left: 10px; right: 10px; bottom: 0;
  height: 2px; border-radius: 2px 2px 0 0; background: var(--accent);
}
.twp-tab.is-on::after {
  content: ''; position: absolute; left: 50%; bottom: 2px;
  width: 9px; height: 6px; margin-left: -4.5px;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
  background: linear-gradient(90deg, var(--tw-tri-hi) 0%, var(--tw-tri-mid) 50%, var(--tw-tri-lo) 100%);
  animation: twTabTriIn 0.26s cubic-bezier(0.34, 1.4, 0.44, 1) both;
}
@keyframes twTabTriIn {
  from { opacity: 0; transform: translateY(3px) scale(0.5); }
  to   { opacity: 1; transform: none; }
}

/* A body swap (data-drawer-swap) in flight: the old body dims, no
   skeleton, so changing tab never flashes. */
.tw-drawer-body.is-swapping .twp-body { opacity: 0.55; transition: opacity 0.12s ease; pointer-events: none; }

/* ---- the documents well ---- */
.twp-dw .twp-dw-h { margin-top: 14px; }
.twp-dw > .twp-note { margin: 0 0 8px; }
.twp-dw-doc,
.twp-dw-type { flex-wrap: wrap; align-items: flex-start; }
.twp-dw-doc > .twp-doc-main,
.twp-dw-type > .twp-doc-main { flex: 1 1 0; min-width: 0; }
.twp-dw-doc.is-expired,
.twp-dw-doc.is-rejected { border-left-color: var(--danger); }
.twp-dw-doc.is-under_review { border-left-color: var(--warning); }
.twp-dw-type.is-missing { border-left-color: var(--border); }
.twp-dw-review { color: var(--text-2); }
.twp-dw-req { color: var(--danger); font-weight: 700; }
.twp-dw-manage {
  flex: 1 0 100%;
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px;
  padding-left: 28px;
}
.twp-dw-inline { margin: 0; }
.twp-dw-more { flex: 0 1 auto; }
.twp-dw-more > summary { list-style: none; }
.twp-dw-more > summary::-webkit-details-marker { display: none; }
.twp-dw-more[open] { flex: 1 0 100%; }
.twp-dw-more[open] > summary { margin-bottom: 6px; }
.twp-dw-btn { min-height: 34px; padding: 0 12px; font-size: 0.8rem; gap: 6px; }
.twp-dw-btn svg { width: 16px; height: 16px; }
.twp-dw-form {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px;
  margin: 8px 0 2px;
}
.twp-dw-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 160px; }
.twp-dw-field input[type="text"],
.twp-dw-field input[type="date"],
.twp-dw-field input[type="file"] {
  width: 100%; min-height: 36px;
  padding: 6px 8px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg-card); color: var(--text);
  font: inherit; font-size: 0.8rem;
}
.twp-dw-field input[type="file"] { padding: 5px 6px; }
.twp-dw-file { flex-basis: 220px; }
.twp-dw-hint { margin: 0; flex: 1 0 100%; font-size: 0.75rem; color: var(--text-2); }
.twp-dw-other { margin-top: 12px; }
.twp-dw-other > .twp-dw-form { padding: 4px 12px 12px; }

@media (max-width: 767.98px) {
  .twp-tabs { padding: 4px 8px 4px; }
  .twp-tab { min-height: 52px; min-width: 68px; }
  .twp-dw-btn,
  .twp-dw-field input[type="text"],
  .twp-dw-field input[type="date"],
  .twp-dw-field input[type="file"] { min-height: 44px; }
  .twp-dw-manage { padding-left: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .twp-tab { transition: none; }
  .twp-tab.is-on::after { animation: none; }
  .tw-drawer-body.is-swapping .twp-body { transition: none; }
}

/* =================================================================
   1.19.2 (Brent, 19 Oct 2026): hide the page menu, keep the rail.
   The sidebar narrows to the 56px rail; the page gets the width back.
   Phones keep their drawer as it is.
   ================================================================= */
.sidebar.nav-rail-mode .nav-ctx-head { display: flex; align-items: center; gap: 8px; }
.sidebar.nav-rail-mode .nav-ctx-hide {
  margin-left: auto; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 8px; border: 0; background: none;
  color: var(--muted, #8a8f98); cursor: pointer; flex: 0 0 auto;
}
.sidebar.nav-rail-mode .nav-ctx-hide svg { width: 16px; height: 16px; }
.sidebar.nav-rail-mode .nav-ctx-hide:hover,
.sidebar.nav-rail-mode .nav-ctx-hide:focus-visible { color: var(--text); background: var(--fill); outline: none; }
.sidebar.nav-rail-mode .nav-rail-ctxtoggle { margin-top: auto; }
.sidebar.nav-rail-mode .nav-rail-ctxtoggle .nav-rail-ico-show { display: none; }
.sidebar.nav-rail-mode.is-ctx-hidden .nav-rail-ctxtoggle .nav-rail-ico-show { display: inline-flex; }
.sidebar.nav-rail-mode.is-ctx-hidden .nav-rail-ctxtoggle .nav-rail-ico-hide { display: none; }
@media (min-width: 701px) {
  .sidebar.nav-rail-mode { transition: width 0.22s ease; }
  .sidebar.nav-rail-mode.is-ctx-hidden { width: 56px !important; }
  .sidebar.nav-rail-mode.is-ctx-hidden .nav-ctx { display: none; }
}
@media (max-width: 700px) {
  .sidebar.nav-rail-mode .nav-ctx-hide,
  .sidebar.nav-rail-mode .nav-rail-ctxtoggle { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar.nav-rail-mode { transition: none; }
}

/* =================================================================
   1.19.5 (Brent, 20 Oct 2026, option E "LED, tamed"): the active page
   row keeps the LogistiQ look (fill, border, triangle, steady glow), but
   only the page row. A parent row whose page is the active one renders
   plain, so exactly one row is lit, and the glow no longer pulses on the
   active row. Top-level pages without sub-rows (Dashboard) keep their
   own active look. Rail mode only; the classic accordion is unchanged.
   ================================================================= */
.sidebar.nav-rail-mode .nav-tri-group:has(.nav-subitem.active) > .nav-item.active:not(.nav-subitem) {
  background: none;
  border-color: transparent;
  color: var(--text);
}
.sidebar.nav-rail-mode .nav-tri-group:has(.nav-subitem.active) > .nav-item.active:not(.nav-subitem) svg { color: var(--text-2); }
.sidebar.nav-rail-mode .nav-tri-group:has(.nav-subitem.active) > .nav-item.active:not(.nav-subitem)::before { opacity: var(--led-glow-min); animation: none; }
.sidebar.nav-rail-mode .nav-tri-group:has(.nav-subitem.active) > .nav-item.active:not(.nav-subitem) .nav-tri { display: none; }
.sidebar.nav-rail-mode .nav-tri-group:has(.nav-subitem.active) > .nav-item.active:not(.nav-subitem):hover { background: var(--fill); }
.sidebar.nav-rail-mode .nav-item.active::before { animation: none; opacity: var(--led-glow-active); }

/* 1.19.6 (Brent, 20 Oct 2026): full screen button in the top bar.
   One icon at a time: expand when off, collapse when on. */
.tw-fs-btn .tw-fs-ico { width: 20px; height: 20px; color: var(--text-2); }
.tw-fs-btn:hover .tw-fs-ico, .tw-fs-btn:focus-visible .tw-fs-ico { color: var(--text); }
.tw-fs-btn:hover { background: var(--fill-hover); }
.tw-fs-btn[aria-pressed="true"] { background: var(--fill); }
.tw-fs-btn[aria-pressed="true"] .tw-fs-ico { color: var(--accent); }
.tw-fs-btn .tw-fs-exit { display: none; }
.tw-fs-btn[aria-pressed="true"] .tw-fs-enter { display: none; }
.tw-fs-btn[aria-pressed="true"] .tw-fs-exit { display: block; }
.tw-fs-btn[hidden] { display: none; }
@media (max-width: 699px) { .tw-fs-btn { display: none; } }
@media (prefers-reduced-motion: reduce) { .tw-fs-btn, .tw-fs-btn .tw-fs-ico { transition: none; } }

/* 1.19.7: full screen remembered across pages; while it waits for the
   first click or key press to come back, the button shows a small dot. */
.tw-fs-btn.is-fs-pending { position: relative; color: var(--accent); }
.tw-fs-btn.is-fs-pending::after { content: ""; position: absolute; top: 6px; right: 6px; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
/* =================================================================
   1.19.8 (Brent, 20 Oct 2026, on option E): "the blue led to be less
   bright and also ensure the text is electric white", application wide.
   The LED glow drops by about 40% everywhere it is drawn (sidebar rows,
   dashboard module tiles, the module strip), the active border and the
   status dot are softer, and on the dark theme the active row and the
   active strip tab read in electric white. The light theme keeps its
   blue active text, since white would not read on its pale fill.
   ================================================================= */
:root {
  --led-glow-min: 0.12;
  --led-glow-max: 0.26;
  --led-glow-hover: 0.36;
  --led-glow-active: 0.45;
}
html[data-theme="dark"] {
  --led-glow-min: 0.08;
  --led-glow-max: 0.20;
}
.sidebar .nav-item.active { border-color: rgba(0, 212, 255, 0.30); }
html[data-theme="dark"] .sidebar .nav-item.active { border-color: rgba(0, 212, 255, 0.28); }
.sidebar .nav-item.active::after { box-shadow: 0 0 4px rgba(0, 212, 255, 0.55); }
.ql-tab.is-active { border-color: rgba(0, 212, 255, 0.28); }
.ql-tab.is-active::after { box-shadow: 0 0 4px rgba(0, 212, 255, 0.55); }
html[data-theme="dark"] .sidebar .nav-item.active,
html[data-theme="dark"] .ql-tab.is-active {
  color: #ffffff; /* electric white */
  text-shadow: 0 0 6px rgba(190, 235, 255, 0.35);
}

/* 1.19.9: full screen holds the app in a frame so it survives module changes. */
#tw-fs-host { position: fixed; inset: 0; z-index: 2147483000; background: #000000; }
#tw-fs-host iframe { display: block; width: 100%; height: 100%; border: 0; background: #000000; }
html.tw-fs-hosting, html.tw-fs-hosting body { overflow: hidden; }

/* 1.20.0 lane SHELL (item 11): the page inside the full screen frame is
   pinned to the frame: no page scroll, shell exactly the frame's height, and
   the main column may shrink beside the page menu so the top bar is never
   pushed or clipped. */
html.tw-fs-framed, html.tw-fs-framed body { height: 100%; overflow: hidden; }
html.tw-fs-framed .flex.h-screen { height: 100%; }
.tw-main-col { min-width: 0; }
.tw-main-col > header.h-16 { min-width: 0; }
.tw-main-col > header.h-16 > div:first-child { min-width: 0; flex: 1 1 auto; }
.tw-main-col > header.h-16 > div:last-child { flex: 0 0 auto; }

/* 1.20.1 lane FSSCROLL: in the full screen frame the shell gets a bounded
   height (100% of an auto height #app resolved to auto, so the shell grew to
   the page's full length and the hidden body overflow clipped it: no scroll).
   main#content stays the one scroller, both ways, with min-height 0 down the
   flex chain. */
html.tw-fs-framed #app { height: 100%; }
html.tw-fs-framed .flex.h-screen { height: 100vh; height: 100dvh; max-height: 100%; }
html.tw-fs-framed .tw-main-col { min-height: 0; }
html.tw-fs-framed main#content { min-height: 0; overflow-y: auto; overflow-x: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
/* end FSSCROLL */
