/* ==========================================================================
   theme-overrides.css
   --------------------------------------------------------------------------
   Supplies dark-mode + utility rules that the precompiled style.css missed.
   Loaded AFTER style.css in views/layouts/main.php so it can backfill
   without fighting cascade order. Hand-written rather than rebuilt from
   Tailwind sources because we don't ship the Tailwind toolchain locally.

   Audit procedure (see scripts/lint_theme_classes.php):
     - Greps every distinct `dark:*` class in views/ and public/assets/js/
     - Compares to the compiled style.css
     - Any class that's referenced but uncompiled belongs here.

   Rule of thumb:
     - Colours that aren't in the brand palette (teal, sky, fuchsia, etc.)
       need an explicit rule here.
     - Opacity modifiers (/5 /10 /15 /20 /30 /40 /50 /60) only compile if
       Tailwind saw them in scanned source at build time; we add the ones
       the templates use.
     - Utility classes the build skipped (max-w-sm, min-w-9, etc.) live
       here too.

   The `&:is(.dark *)` selector matches Tailwind v4's class-based dark mode
   (the `dark` class is on <body> via Alpine's :class binding in main.php).
   ========================================================================== */

/* ── Layout utilities the build skipped ──────────────────────────────── */
.py-12 { padding-top: 3rem; padding-bottom: 3rem; }   /* 2FA status panel breathing room */
.max-w-sm  { max-width: 24rem; }
.max-w-lg  { max-width: 32rem; }
.max-w-xl  { max-width: 36rem; }
.max-w-2xl { max-width: 42rem; }
.min-w-9   { min-width: 2.25rem; }
.min-h-9   { min-height: 2.25rem; }
.max-w-3xl { max-width: 48rem; }
/* Fixed widths the build skipped. w-9 (2.25rem) squares off h-9 avatars/icon
   badges; w-64 (16rem) is the standard toolbar search-input width (users.php,
   mobile-manager, data-purge). Without these the elements collapsed to auto. */
.w-9  { width: 2.25rem; }
.w-14 { width: 3.5rem; }
.w-64 { width: 16rem; }
/* Responsive col-span the build skipped — without it a `lg:grid-cols-3` child
   that should span 2 columns collapses to 1, leaving a dead empty third column
   (device-detail alert history). Scoped to the lg breakpoint like Tailwind. */
@media (min-width: 1024px) {
  .lg\:col-span-2 { grid-column: span 2 / span 2; }
}
@media (min-width: 640px) {
  .sm\:col-span-2 { grid-column: span 2 / span 2; }
}
/* object-fit — needed for product-photo thumbnails (device detail, brand cards). */
.object-contain { object-fit: contain; }
.object-cover   { object-fit: cover; }
/* currentColor background — theme-reactive status dots inside coloured badges. */
.bg-current { background-color: currentColor; }
/* min-w-0 lets flex children shrink below content width — required for `truncate`
   to actually clip (device/session names). Was referenced but never compiled. */
.min-w-0  { min-width: 0; }
.max-h-48 { max-height: 12rem; }   /* data-purge confirm list scroll cap */
/* Arbitrary 10px font — used in 15+ places (badges, meta, ticket hashes) but
   the precompiled build never emitted it, so text silently rendered at the
   inherited (larger) size. This backfills it app-wide. */
.text-\[10px\] { font-size: 10px; }
.text-\[11px\] { font-size: 11px; }   /* alert-log meta (time, provider, ack, date headers) */

/* ── Teal palette (used by Default-FSE avatar on site-detail) ────────── */
.bg-teal-50   { background-color: #f0fdfa; }
.bg-teal-100  { background-color: #ccfbf1; }
.bg-teal-500  { background-color: #14b8a6; }
.bg-teal-600  { background-color: #0d9488; }
.text-teal-400 { color: #2dd4bf; }
.text-teal-500 { color: #14b8a6; }
.text-teal-600 { color: #0d9488; }
.text-teal-700 { color: #0f766e; }
.dark .dark\:bg-teal-900\/30 { background-color: rgb(19 78 74 / 0.30); }
.dark .dark\:bg-teal-900\/40 { background-color: rgb(19 78 74 / 0.40); }
.dark .dark\:text-teal-300 { color: #5eead4; }
.dark .dark\:text-teal-400 { color: #2dd4bf; }

/* ── Gray opacity variants we use for tinted panels ──────────────────── */
.bg-gray-50\/40 { background-color: rgb(249 250 251 / 0.40); }
.bg-gray-50\/60 { background-color: rgb(249 250 251 / 0.60); }
.bg-white\/60   { background-color: rgb(255 255 255 / 0.60); }
.bg-white\/95   { background-color: rgb(255 255 255 / 0.95); }
.dark .dark\:bg-gray-900\/95 { background-color: rgb(17 24 39 / 0.95); }
.dark .dark\:bg-gray-800\/30 { background-color: rgb(31 41 55 / 0.30); }
.dark .dark\:bg-gray-800\/40 { background-color: rgb(31 41 55 / 0.40); }
.dark .dark\:bg-gray-800\/50 { background-color: rgb(31 41 55 / 0.50); }
.dark .dark\:bg-gray-900\/60 { background-color: rgb(17 24 39 / 0.60); }
.dark .dark\:bg-gray-950     { background-color: #030712; }

/* ── Brand / status fills with light opacity (badges, soft pills) ────── */
.dark .dark\:bg-brand-500\/10 { background-color: rgb(245 158 11 / 0.10); }
.dark .dark\:bg-brand-900\/10 { background-color: rgb(120 53 15 / 0.10); }
.dark .dark\:bg-brand-900\/20 { background-color: rgb(120 53 15 / 0.20); }
.dark .dark\:bg-brand-900\/30 { background-color: rgb(120 53 15 / 0.30); }
.dark .dark\:bg-success-500\/10 { background-color: rgb(34 197 94 / 0.10); }
.dark .dark\:bg-success-900\/30 { background-color: rgb(20 83 45 / 0.30); }
.dark .dark\:bg-error-500\/10  { background-color: rgb(239 68 68 / 0.10); }
.dark .dark\:bg-error-500\/20  { background-color: rgb(239 68 68 / 0.20); }
.dark .dark\:bg-error-900\/20  { background-color: rgb(127 29 29 / 0.20); }
.dark .dark\:bg-warning-500\/10 { background-color: rgb(245 158 11 / 0.10); }

/* ── Blue + amber + green palette gaps used by status indicators ─────── */
.dark .dark\:bg-amber-900\/20 { background-color: rgb(120 53 15 / 0.20); }
.dark .dark\:bg-amber-900\/30 { background-color: rgb(120 53 15 / 0.30); }
.dark .dark\:bg-blue-500\/15  { background-color: rgb(59 130 246 / 0.15); }
.dark .dark\:bg-blue-900\/20  { background-color: rgb(30 58 138 / 0.20); }
.dark .dark\:bg-purple-500\/15 { background-color: rgb(168 85 247 / 0.15); }  /* acknowledged ticket status */
.dark .dark\:bg-blue-900\/30  { background-color: rgb(30 58 138 / 0.30); }
.dark .dark\:bg-green-900\/20 { background-color: rgb(20 83 45 / 0.20); }
.dark .dark\:bg-green-900\/30 { background-color: rgb(20 83 45 / 0.30); }

/* ── Border opacity variants ─────────────────────────────────────────── */
.dark .dark\:border-error-500\/30 { border-color: rgb(239 68 68 / 0.30); }
.dark .dark\:border-brand-500\/30 { border-color: rgb(245 158 11 / 0.30); }

/* ── Ring opacity variants (avatars, focus states) ───────────────────── */
.dark .dark\:ring-brand-500\/20   { --tw-ring-color: rgb(245 158 11 / 0.20); }
.dark .dark\:ring-brand-500\/30   { --tw-ring-color: rgb(245 158 11 / 0.30); }
.dark .dark\:ring-success-500\/20 { --tw-ring-color: rgb(34 197 94 / 0.20); }

/* ── Hover variants the build missed ─────────────────────────────────── */
.dark .dark\:hover\:bg-white\/\[0\.03\]:hover { background-color: rgb(255 255 255 / 0.03); }
.dark .dark\:hover\:bg-error-500\/20:hover    { background-color: rgb(239 68 68 / 0.20); }
.dark .dark\:hover\:bg-brand-500\/15:hover    { background-color: rgb(245 158 11 / 0.15); }

/* ── Stakeholder picker pills (used by stakeholderPicker.js) ─────────── */
.dark .dark\:bg-brand-900\/30 { background-color: rgb(120 53 15 / 0.30); }

/* ── Tailwind arbitrary-value classes the JIT skipped ───────────────── */
/* Used by modal cancel buttons throughout the app. Sub-percent opacity
   on white = barely-perceptible hover highlight in dark mode. */
.hover\:bg-white\/\[0\.03\]:hover { background-color: rgb(255 255 255 / 0.03); }
.dark .dark\:hover\:bg-white\/\[0\.03\]:hover { background-color: rgb(255 255 255 / 0.03); }

/* ── Modal overlay backdrops (bg-black with opacity) ────────────────── */
.bg-black\/50 { background-color: rgb(0 0 0 / 0.50); }
.bg-black\/60 { background-color: rgb(0 0 0 / 0.60); }

/* ── Danger (error) button fills — 2FA reset + confirm modal ─────────── */
.bg-error-600 { background-color: #dc2626; }
.hover\:bg-error-600:hover { background-color: #dc2626; }
.hover\:bg-error-50:hover  { background-color: #fef2f2; }

/* ── Soft tinted row backgrounds for tables and lists ────────────────── */
.bg-gray-50\/50 { background-color: rgb(249 250 251 / 0.50); }
.bg-gray-900\/60 { background-color: rgb(17 24 39 / 0.60); }

/* ── Status panel backgrounds (used by ticketDetail / monitoring) ───── */
.dark .dark\:bg-error-900\/30 { background-color: rgb(127 29 29 / 0.30); }
.dark .dark\:bg-gray-600 { background-color: #4b5563; }
.dark .dark\:bg-green-500\/15  { background-color: rgb(34 197 94 / 0.15); }
.dark .dark\:bg-orange-500\/15 { background-color: rgb(249 115 22 / 0.15); }
.dark .dark\:bg-purple-500\/15 { background-color: rgb(168 85 247 / 0.15); }
.dark .dark\:bg-purple-900\/30 { background-color: rgb(88 28 135 / 0.30); }
.dark .dark\:bg-red-900\/30    { background-color: rgb(127 29 29 / 0.30); }
.dark .dark\:bg-warning-900\/30 { background-color: rgb(120 53 15 / 0.30); }
.dark .dark\:bg-white          { background-color: #ffffff; }
.dark .dark\:bg-yellow-500\/15 { background-color: rgb(234 179 8 / 0.15); }
.dark .dark\:bg-yellow-900\/20 { background-color: rgb(113 63 18 / 0.20); }

/* ── Borders ─────────────────────────────────────────────────────────── */
.dark .dark\:border-blue-700      { border-color: #1d4ed8; }
.dark .dark\:border-brand-700     { border-color: #b45309; }
.dark .dark\:border-brand-900\/40 { border-color: rgb(120 53 15 / 0.40); }
.dark .dark\:border-error-800     { border-color: #991b1b; }
.dark .dark\:border-gray-600      { border-color: #4b5563; }
.dark .dark\:border-gray-700\/50  { border-color: rgb(55 65 81 / 0.50); }
.dark .dark\:border-red-900\/40   { border-color: rgb(127 29 29 / 0.40); }
.dark .dark\:border-success-500   { border-color: #22c55e; }
.dark .dark\:border-success-800   { border-color: #166534; }
.dark .dark\:border-success-900\/30 { border-color: rgb(20 83 45 / 0.30); }
.dark .dark\:border-warning-700   { border-color: #b45309; }
.dark .dark\:border-warning-800   { border-color: #92400e; }
.dark .dark\:border-yellow-800\/40 { border-color: rgb(133 77 14 / 0.40); }
.dark .dark\:border-yellow-900\/30 { border-color: rgb(113 63 18 / 0.30); }

/* ── Hover states ───────────────────────────────────────────────────── */
.dark .dark\:hover\:bg-gray-800\/30:hover { background-color: rgb(31 41 55 / 0.30); }
.dark .dark\:hover\:bg-gray-800\/60:hover { background-color: rgb(31 41 55 / 0.60); }
.dark .dark\:hover\:bg-white:hover         { background-color: #ffffff; }
.dark .dark\:hover\:border-brand-600:hover { border-color: #d97706; }
.dark .dark\:hover\:border-gray-700:hover  { border-color: #374151; }
.dark .dark\:hover\:border-red-700:hover   { border-color: #b91c1c; }
.dark .dark\:hover\:border-yellow-700:hover { border-color: #a16207; }
.dark .dark\:hover\:text-brand-300:hover   { color: #fcd34d; }
.dark .dark\:hover\:text-error-400:hover   { color: #f87171; }
.hover\:bg-brand-50\/10:hover { background-color: rgb(255 251 235 / 0.10); }
.hover\:bg-brand-50\/50:hover { background-color: rgb(255 251 235 / 0.50); }
.hover\:bg-gray-50\/50:hover  { background-color: rgb(249 250 251 / 0.50); }

/* ── Text colours ───────────────────────────────────────────────────── */
.dark .dark\:placeholder-gray-500::placeholder { color: #6b7280; }
.dark .dark\:text-blue-light-400 { color: #60a5fa; }
.dark .dark\:text-brand-300      { color: #fcd34d; }
.dark .dark\:text-brand-500      { color: #f59e0b; }
.dark .dark\:text-error-300      { color: #fca5a5; }
.dark .dark\:text-gray-600       { color: #4b5563; }
.dark .dark\:text-red-100        { color: #fee2e2; }
.dark .dark\:text-yellow-400     { color: #facc15; }
.text-white\/30 { color: rgb(255 255 255 / 0.30); }
.dark .dark\:text-amber-500   { color: #f59e0b; }
.dark .dark\:text-warning-500 { color: #f59e0b; }

/* ── Rings ──────────────────────────────────────────────────────────── */
.ring-brand-500\/10 { --tw-ring-color: rgb(245 158 11 / 0.10); }
.ring-brand-500\/20 { --tw-ring-color: rgb(245 158 11 / 0.20); }
.ring-brand-900\/30 { --tw-ring-color: rgb(120 53 15 / 0.30); }
.dark .dark\:ring-gray-900 { --tw-ring-color: #111827; }

/* ── Asset Care + QHSSE additions (migration 033 build) ─────────────── */

/* Indigo (in_progress ticket badges in asset registry) */
.dark .dark\:bg-indigo-900\/30 { background-color: rgb(49 46 129 / 0.30); }
.dark .dark\:text-indigo-400   { color: #818cf8; }

/* Lime (grade B band in inspection reports + history) */
.dark .dark\:bg-lime-900\/30   { background-color: rgb(54 83 20 / 0.30); }
.dark .dark\:text-lime-400     { color: #a3e635; }

/* Amber border dark variant (schedule upload progress) */
.dark .dark\:border-amber-800  { border-color: #92400e; }

/* Error hover backgrounds dark (reject action in schedule review) */
.dark .dark\:hover\:bg-error-900\/30:hover { background-color: rgb(127 29 29 / 0.30); }

/* Green hover dark (approve action) */
.dark .dark\:hover\:bg-green-900\/30:hover { background-color: rgb(20 83 45 / 0.30); }

/* Brand border + bg variants on the EPTW placeholder cards */
.dark .dark\:hover\:border-brand-700:hover { border-color: #b45309; }
.hover\:bg-brand-50\/40:hover  { background-color: rgb(255 251 235 / 0.40); }

/* ── Subtle white tints (used everywhere for dark-mode card surfaces) ─────
   These bracketed opacity classes are NOT picked up by the JIT during the
   original Tailwind build (see warning in CLAUDE.md §3a). Hand-write them. */
.dark .dark\:bg-white\/\[0\.03\]           { background-color: rgb(255 255 255 / 0.03); }
.dark .dark\:hover\:bg-white\/\[0\.03\]:hover { background-color: rgb(255 255 255 / 0.03); }
.dark .dark\:hover\:bg-white\/\[0\.05\]:hover { background-color: rgb(255 255 255 / 0.05); }

/* ── Larger stat/heading sizes the JIT skipped ───────────────────────────
   text-3xl/4xl are referenced by the dashboard KPIs + management pages but
   never made it into style.css, so they silently rendered at the inherited
   size. Backfill them here (see CLAUDE.md §3a). */
.text-3xl { font-size: 1.875rem; line-height: 2.25rem; }
.text-4xl { font-size: 2.25rem;  line-height: 2.5rem;  }

/* ── Sizing / object-fit / scroll-snap utilities the JIT skipped ──────────
   The precompiled style.css never emitted these fixed widths/heights,
   object-fit, or scroll-snap classes, so cards collapsed to content width
   and images/heights broke. Backfill the ones the dashboard widgets use. */
.w-52 { width: 13rem; }
.w-64 { width: 16rem; }
.w-72 { width: 18rem; }
.h-28 { height: 7rem; }
.h-36 { height: 9rem; }
.h-40 { height: 10rem; }
.h-\[70px\] { height: 70px; }
.h-2\.5 { height: 0.625rem; }
.w-2\.5 { width: 0.625rem; }
.max-h-full { max-height: 100%; }
.object-contain { object-fit: contain; }
.object-cover { object-fit: cover; }
.snap-x { scroll-snap-type: x mandatory; }
.snap-start { scroll-snap-align: start; }
.flex-shrink-0 { flex-shrink: 0; }
.shrink-0 { flex-shrink: 0; }
.min-w-0 { min-width: 0; }

/* ── gap utilities the JIT skipped (icon/text spacing everywhere) ─────────
   gap-1.5 / gap-2.5 / gap-3.5 are used throughout (dropdowns, alert strip,
   pills) but never compiled — icons and numbers clasped their neighbours. */
.gap-1\.5 { gap: 0.375rem; }
.gap-2\.5 { gap: 0.625rem; }
.gap-3\.5 { gap: 0.875rem; }

/* ── max-height scroll caps (System Dashboard) ────────────────────────────
   The precompiled build emitted NO max-h-* utilities at all — .max-h-48 above
   was already backfilled here for the data-purge list for the same reason.
   The System Dashboard's security / activity panels cap their scroll at these
   heights; without a rule the panels grow unbounded and the page stops being
   a single-glance cockpit. The lint does not catch these (it audits only
   dark:/opacity variants), so they were verified by hand against style.css. */
.max-h-72 { max-height: 18rem; }
.max-h-80 { max-height: 20rem; }
/* Arbitrary-value class: permitted here per CLAUDE.md §3a rule 3 (bracket
   syntax is exactly what the JIT misses). Caps the error-detail modal body so
   a long stack trace scrolls inside the modal instead of overflowing it. */
.max-h-\[60vh\] { max-height: 60vh; }

/* ── truncate + tracking-wide: referenced app-wide, never compiled ─────────
   Neither has ANY rule in style.css. The only text-overflow declaration in the
   whole build belongs to dropzone. So:
     .truncate      — referenced 76x (users, dashboard, notifications, settings,
                      site-performance, deviceDetail, maintenanceCal, brands…).
                      Long names/paths silently never clipped; they wrapped or
                      overflowed their container instead. Note the .min-w-0 rule
                      above was added "required for `truncate` to actually clip"
                      — that fix assumed a rule existed. It did not.
     .tracking-wide — referenced 122x. Letter-spacing was silently a no-op.
   The lint does not catch either (it audits only dark:/opacity variants), which
   is why both survived this long. Verified absent by grepping style.css. */
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tracking-wide { letter-spacing: 0.025em; }

/* ── Support + Help modules (2026-07-20) ─────────────────────────────────────
   Found by scripts/lint_ui_classes.php, which audits EVERY utility rather than
   only dark:/opacity variants. All 29 of these were referenced by the Support
   and Help pages and had no compiled rule, so the markup rendered with no
   spacing, no sticky rail and no hover affordance — the "sections clamped
   together" defect. The build only contains the utility VALUES the original
   template happened to use (space-y-5 and -6 exist; -2, -8, -10, -12 do not),
   so there is no pattern to intuit. Check, don't guess.
   ------------------------------------------------------------------------- */

/* Vertical rhythm. space-y-12 separates guide steps, which end in full-width
   screenshots and collided with the next heading without it. */
.space-y-2  > :not([hidden]) ~ :not([hidden]) { margin-top: 0.5rem; }
.space-y-2\.5 > :not([hidden]) ~ :not([hidden]) { margin-top: 0.625rem; }
.space-y-4  > :not([hidden]) ~ :not([hidden]) { margin-top: 1rem; }
.space-y-8  > :not([hidden]) ~ :not([hidden]) { margin-top: 2rem; }
.space-y-10 > :not([hidden]) ~ :not([hidden]) { margin-top: 2.5rem; }
.space-y-12 > :not([hidden]) ~ :not([hidden]) { margin-top: 3rem; }

.mt-12 { margin-top: 3rem; }
.ml-auto { margin-left: auto; }
.py-16 { padding-top: 4rem; padding-bottom: 4rem; }
.py-20 { padding-top: 5rem; padding-bottom: 5rem; }
.pl-10 { padding-left: 2.5rem; }
.pr-9  { padding-right: 2.25rem; }
.w-1\.5 { width: 0.375rem; }
.w-3\.5 { width: 0.875rem; }

/* Sizing used by the chat thread and search fields. */
.max-h-40      { max-height: 10rem; }
.min-h-\[44px\]  { min-height: 44px; }   /* composer: one comfortable text row */
.min-h-\[320px\] { min-height: 320px; }  /* thread keeps height while loading */
.min-w-\[240px\] { min-width: 240px; }
.min-w-\[760px\] { min-width: 760px; }   /* support table before it scrolls */
.max-w-\[78\%\]  { max-width: 78%; }     /* chat bubble never spans full width */

/* Guide page: reading column left, context rail right, rail follows scroll. */
@media (min-width: 1024px) {
  .lg\:gap-8   { gap: 2rem; }
  .lg\:sticky  { position: sticky; }
  .lg\:top-24  { top: 6rem; }
  .lg\:mt-0    { margin-top: 0; }
}
@media (min-width: 640px) {
  .sm\:max-w-md { max-width: 28rem; }
  .sm\:p-8      { padding: 2rem; }
  .sm\:px-8     { padding-left: 2rem; padding-right: 2rem; }
}
@media (min-width: 768px) {
  .md\:px-6 { padding-left: 1.5rem; padding-right: 1.5rem; }
}

/* Anchor offset so a step linked from the rail index is not hidden under the
   sticky header. */
.scroll-mt-24 { scroll-margin-top: 6rem; }

/* Interaction affordances. */
.hover\:text-brand-500:hover { color: #465fff; }
.group:hover .group-hover\:text-brand-500 { color: #465fff; }
.disabled\:opacity-60:disabled { opacity: 0.6; }

/* Four more found only after fixing a boundary bug in the checker: a substring
   test matched `.sm\:flex` inside `.sm\:flex-row`, so these read as compiled
   when they are not. `sm:flex` was why the Help list rows showed no category
   badge or reading time — `hidden` applied and nothing ever un-hid them. */
.rounded { border-radius: 0.25rem; }
.border-dashed { border-style: dashed; }
.w-4 { width: 1rem; }
@media (min-width: 640px) { .sm\:flex { display: flex; } }

/* Support list: the reference column was wrapping mid-token (SUP-\n000006). */
.whitespace-nowrap { white-space: nowrap; }
