/*
 * TDI Web Command Center — custom app styles.
 * Loaded after tailwind.build.css so these rules (theme variables, animations,
 * small component classes not covered by a utility class) can rely on it.
 */

/* Color variables are bare "R G B" triplets (no rgb() wrapper, no commas) so Tailwind's
   rgb(var(--x) / <alpha-value>) pattern can apply opacity modifiers like bg-panel2/60. */
:root, .theme-dark {
  --color-white:255 255 255;
  --slate-200:226 232 240;
  --slate-300:203 213 225;
  --slate-400:148 163 184;
  --slate-500:100 116 139;
  --slate-600:71 85 105;
  --color-base:15 23 42;
  --color-panel:17 28 52;
  --color-panel2:11 21 38;
  --color-line:51 65 85;
  --color-sidebar:11 26 55;
  --color-navactive:27 42 74;
  --color-scrollbar:51 65 85;
}
.theme-light {
  --color-white:15 23 42;
  --slate-200:30 41 59;
  --slate-300:51 65 85;
  --slate-400:71 85 105;
  --slate-500:100 116 139;
  --slate-600:148 163 184;
  --color-base:241 245 249;
  --color-panel:255 255 255;
  --color-panel2:248 250 252;
  /* Darkened from the original 226 232 240 (1.23:1 against white — cards/table rows/
     form-input borders were nearly edgeless) to a value that reads as an actual boundary
     (~2:1) while staying a clean, subtle hairline rather than a heavy border. */
  --color-line:168 182 199;
  /* Was a distinct lavender (#E0E7FF) that clashed against the rest of the chrome (header
     is bg-panel2, panels are white) — matched to --color-panel2 so the sidebar reads as
     the same surface family as everything else instead of its own separate block of color. */
  --color-sidebar:248 250 252;
  /* A pale tint of the new #4392cb primary (was a plain lavender, #C7D2FE) so the active
     nav highlight visually matches the rebrand. */
  --color-navactive:227 239 247;
  --color-scrollbar:203 213 225;
  --color-primary:67 146 203;   /* #4392cb — the new primary, replacing #3b82f6 "electric" */
  /* A deepened shade of the primary reserved for SMALL TEXT (links, "View all" etc.) —
     #4392cb itself only measures 3.38:1 against white (fine for large text/buttons/icons,
     short of the 4.5:1 AA minimum for small body text). Buttons/borders/backgrounds keep
     using --color-primary as-is (the user's exact specified color); only text-electric
     reads from this instead. */
  --color-primary-text:46 109 164; /* #2e6da4 — 5.47:1 vs white */
  --color-rose:225 29 72;       /* #e11d48 — 4.70:1 vs white (was #f43f5e, 3.67:1) */
  --color-rose-dark:190 18 60;  /* #be123c — darker hover shade, mirrors the existing rose-600 hover already used for the Delete button */
  --color-amber:180 83 9;       /* #b45309 — 5.02:1 vs white (was #f59e0b, 2.15:1) */
  --color-emerald:4 120 87;     /* #047857 — 5.48:1 vs white (was #10b981, 2.54:1) */
  --color-teal:15 118 110;      /* #0f766e — 5.47:1 vs white (was #2dd4bf, 1.86:1) */
}

/* ===== Light Theme: redeclare the accent/status colors Tailwind compiled as hardcoded,
   non-theme-aware literals ===== */
/* `electric`/`rose`/`amber`/`emerald`/`teal` are all baked into the static
   tailwind.build.css as literal RGB values (no live Tailwind build in this project — see
   this file's own header comment) tuned to read well against Dark Theme's near-black
   panels. Measured live (WCAG contrast vs white): amber 2.15:1, emerald 2.54:1, teal
   1.86:1, rose 3.67:1, electric 3.68:1 — all below the 4.5:1 AA minimum for text, and
   these exact classes drive status pills, score badges, and buttons on every page. Since
   Tailwind can't be recompiled, these rules redeclare every compiled selector for each
   family (this file loads after tailwind.build.css, so same-specificity rules here win by
   cascade) — scoped to .theme-light only, so Dark Theme is completely unaffected. */
.theme-light .border-electric,
.theme-light .hover\:border-electric:hover,
.theme-light .focus\:border-electric:focus { border-color: rgb(var(--color-primary)); }
.theme-light .border-electric\/30 { border-color: rgb(var(--color-primary) / .3); }
.theme-light .border-electric\/40,
.theme-light .hover\:border-electric\/40:hover { border-color: rgb(var(--color-primary) / .4); }
.theme-light .bg-electric { background-color: rgb(var(--color-primary)); }
.theme-light .bg-electric\/5 { background-color: rgb(var(--color-primary) / .05); }
.theme-light .bg-electric\/10 { background-color: rgb(var(--color-primary) / .1); }
.theme-light .bg-electric\/15 { background-color: rgb(var(--color-primary) / .15); }
.theme-light .bg-electric\/25,
.theme-light .hover\:bg-electric\/25:hover { background-color: rgb(var(--color-primary) / .25); }
.theme-light .bg-electric\/\[0\.03\] { background-color: rgb(var(--color-primary) / .03); }
.theme-light .bg-electric\/\[0\.04\] { background-color: rgb(var(--color-primary) / .04); }
.theme-light .from-electric { --tw-gradient-from: #4392cb var(--tw-gradient-from-position); --tw-gradient-to: rgb(67 146 203 / 0) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); }
.theme-light .text-electric,
.theme-light .hover\:text-electric:hover { color: rgb(var(--color-primary-text)); }
.theme-light .accent-electric { accent-color: #4392cb; }
.theme-light .shadow-electric\/20 { --tw-shadow-color: rgb(var(--color-primary) / .2); }
.theme-light .shadow-electric\/30 { --tw-shadow-color: rgb(var(--color-primary) / .3); }
.theme-light .focus\:ring-electric\/40:focus { --tw-ring-color: rgb(var(--color-primary) / .4); }

.theme-light .border-rose,
.theme-light .focus\:border-rose:focus { border-color: rgb(var(--color-rose)); }
.theme-light .border-rose-500\/30 { border-color: rgb(var(--color-rose) / .3); }
.theme-light .border-rose-500\/40,
.theme-light .hover\:border-rose-500\/40:hover,
.theme-light .hover\:border-rose\/40:hover { border-color: rgb(var(--color-rose) / .4); }
.theme-light .hover\:border-rose-500:hover { border-color: rgb(var(--color-rose)); }
.theme-light .bg-rose { background-color: rgb(var(--color-rose)); }
.theme-light .bg-rose-500\/10 { background-color: rgb(var(--color-rose) / .1); }
.theme-light .bg-rose-500\/15,
.theme-light .bg-rose\/15 { background-color: rgb(var(--color-rose) / .15); }
.theme-light .hover\:bg-rose-600:hover { background-color: rgb(var(--color-rose-dark)); }
.theme-light .text-rose,
.theme-light .hover\:text-rose:hover { color: rgb(var(--color-rose)); }

.theme-light .border-amber-500\/30 { border-color: rgb(var(--color-amber) / .3); }
.theme-light .bg-amber { background-color: rgb(var(--color-amber)); }
.theme-light .bg-amber-500\/10 { background-color: rgb(var(--color-amber) / .1); }
.theme-light .bg-amber-500\/15,
.theme-light .bg-amber\/15 { background-color: rgb(var(--color-amber) / .15); }
.theme-light .text-amber,
.theme-light .hover\:text-amber:hover { color: rgb(var(--color-amber)); }
.theme-light .hover\:border-amber-500:hover { border-color: rgb(var(--color-amber)); }
.theme-light .hover\:border-amber\/40:hover { border-color: rgb(var(--color-amber) / .4); }

.theme-light .bg-emerald { background-color: rgb(var(--color-emerald)); }
.theme-light .bg-emerald-500\/15,
.theme-light .bg-emerald\/15 { background-color: rgb(var(--color-emerald) / .15); }
.theme-light .text-emerald,
.theme-light .hover\:text-emerald:hover { color: rgb(var(--color-emerald)); }
.theme-light .hover\:border-emerald-500:hover { border-color: rgb(var(--color-emerald)); }

.theme-light .bg-teal-500\/15 { background-color: rgb(var(--color-teal) / .15); }
.theme-light .bg-teal-500\/20 { background-color: rgb(var(--color-teal) / .2); }
.theme-light .text-teal-400 { color: rgb(var(--color-teal)); }
.theme-light .hover\:border-teal-400\/40:hover { border-color: rgb(var(--color-teal) / .4); }

/* text-slate-100 is compiled as a literal near-white (#f1f5f9) — meant as the "brightest"
   text shade against Dark Theme's near-black panels. It's used for: metric values with no
   documented good/bad threshold (speed-performance.js/sites.js bucketTextColor()'s default
   branch — Page Load Time, Redirect/Connect/Backend Duration, DOM timings, etc., rendered
   on white bg-panel2 chips), a dropdown-item hover state, and a session-device label — all
   "high emphasis text", the exact same role --color-white already plays app-wide (that's
   why text-white already flips to near-black in Light Theme). Reusing that variable here
   keeps it consistent instead of introducing a second near-white-text bug fix. */
.theme-light .text-slate-100 { color: rgb(var(--color-white)); }

/* bg-electric/bg-rose buttons set text-white explicitly for their label — but --color-white
   is deliberately near-black in Light Theme (so plain "brightest text" reads correctly on
   white panels), which also flips these button labels to unreadable dark-on-blue/dark-on-
   red. Buttons need their white label to stay actually white regardless of theme. */
.theme-light .bg-electric.text-white,
.theme-light .bg-rose.text-white,
.theme-light .bg-rose-500.text-white { color: #fff; }

/* Every bg-electric button's hover state hardcodes Tailwind's default blue-500 (#3b82f6) —
   the OLD "electric" color, unrelated to the new #4392cb primary — so hovering flashed a
   mismatched blue. Swap in a ~15% darker shade of the new primary instead, for a normal
   hover-darken instead of a hue jump. */
.theme-light .hover\:bg-blue-500:hover { background-color: rgb(57 124 173); }

/* hover:bg-panel2 (and its /40, /60 opacity variants) is the app's standard "highlight
   this interactive row/card" hover — used on every table row, the permission grid, and
   several dashboard cards. In Dark Theme that reads clearly (panel2 is darker than panel,
   so hovering toward it looks like a highlight against the near-black page). In Light
   Theme panel2 (248 250 252) is only a hair off white — the exact same hover is nearly
   invisible there. Darkening toward --color-line (already tuned as Light Theme's "reads
   as a real boundary" tone) instead of panel2 fixes every one of those call sites at
   once, app-wide, not just in Settings. */
.theme-light .hover\:bg-panel2:hover,
.theme-light .hover\:bg-panel2\/40:hover,
.theme-light .hover\:bg-panel2\/60:hover { background-color: rgb(var(--color-line) / .22); }

body { background: rgb(var(--color-base)); transition: background-color .15s ease; }

/* #appRoot (index.php) is a plain `min-h-screen` flex row, so with no explicit height of
   its own the sidebar stretches to match #mainContent's full scrollable height instead of
   the viewport — nav's own `overflow-y-auto` (sidebar.php) never actually kicks in, and
   anything placed after nav (e.g. the footer logo) ends up scrolled far below the fold.
   No Tailwind utility for this is in the prebuilt tailwind.build.css (no live build step
   in this project — see its own header comment), so it's defined here instead of adding
   an h-screen/sticky/top-0 class that would silently do nothing. */
#appSidebar { height: 100vh; position: sticky; top: 0; }

::-webkit-scrollbar { width:8px; height:8px; }
::-webkit-scrollbar-thumb { background: rgb(var(--color-scrollbar)); border-radius:4px; }
::-webkit-scrollbar-track { background:transparent; }

/* Sidebar nav */
.nav-item { border-left:2px solid transparent; }
.nav-item.active { background: rgb(var(--color-navactive)); color: rgb(var(--color-white)); border-left-color:#3B82F6; }
.theme-light .nav-item.active { border-left-color: rgb(var(--color-primary)); }

/* View switching — one <section class="view" data-view="..."> is shown at a time */
.view { display:none; }
.view.active { display:block; }

/* Misc small effects used across several pages */
.glow-scan { box-shadow: 0 0 0 1px rgba(59,130,246,.35), 0 0 24px -4px rgba(59,130,246,.55); }
.tick { background-image: repeating-linear-gradient(90deg, #1E293B 0 1px, transparent 1px 24px); }
.scan-bar-fill { transition: width .4s ease; }
.modal-backdrop { background: rgba(4,8,20,.72); backdrop-filter: blur(2px); }

/* Animations */
.fade-in { animation: fadein .18s ease-out; }
@keyframes fadein { from { opacity:0; transform:translateY(3px);} to {opacity:1; transform:translateY(0);} }

.modal-pop { animation: modalpop .28s cubic-bezier(0.16, 1, 0.3, 1); }
@keyframes modalpop { from { opacity:0; transform:scale(.94) translateY(6px);} to {opacity:1; transform:scale(1) translateY(0);} }

.spin { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Cursor halo ripple (login screen) and button click ripple (app) */
.cursor-ripple { position:absolute; top:0; left:0; width:16px; height:16px; margin-left:-8px; margin-top:-8px; border-radius:9999px; border:2px solid rgba(96,165,250,0.85); box-shadow:0 0 16px 2px rgba(59,130,246,0.35); pointer-events:none; animation: rippleburst .65s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
@keyframes rippleburst { from { width:16px; height:16px; margin-left:-8px; margin-top:-8px; opacity:0.9; } to { width:200px; height:200px; margin-left:-100px; margin-top:-100px; opacity:0; } }

.btn-ripple { position:absolute; border-radius:9999px; background:rgba(255,255,255,0.45); pointer-events:none; transform:scale(0); animation: btnrippleburst .5s ease-out forwards; }
@keyframes btnrippleburst { from { transform:scale(0); opacity:0.55; } to { transform:scale(1); opacity:0; } }

/* Task Board: compact overlapping assignee-initials avatar stack (ClickUp-style). Plain
   CSS rather than Tailwind utility classes, since the app's Tailwind build only includes
   the exact class strings already scanned from existing templates — negative-margin
   overlap and a per-user color palette were never in that scanned set. */
.avatar-stack .avatar-circle + .avatar-circle { margin-left:-4px; }
.avatar-circle { box-shadow:0 0 0 2px rgb(var(--color-panel)); }
.avatar-circle.avatar-removable:hover { z-index:1; }
.avatar-remove { position:absolute; top:-3px; right:-3px; width:13px; height:13px; border-radius:9999px; background:#f43f5e; color:#fff; font-size:9px; line-height:12px; text-align:center; border:1.5px solid rgb(var(--color-panel)); cursor:pointer; }
.avatar-remove:hover { background:#e11d48; }
/* A small, deterministic (hashed from user id) palette — the same person always gets the
   same color, rather than a genuinely new random color on every render. */
.avatar-c0 { background:#f43f5e; }
.avatar-c1 { background:#f59e0b; }
.avatar-c2 { background:#10b981; }
.avatar-c3 { background:#ec4899; }
.avatar-c4 { background:#14b8a6; }
.avatar-c5 { background:#f97316; }
.avatar-c6 { background:#6366f1; }
.avatar-c7 { background:#a855f7; }
/* "+" button appended to an assignee avatar stack — reveals the add-assignee <select>
   on click, replacing what used to be a permanently-visible dropdown under the stack. */
.avatar-add-btn { background:rgb(var(--color-panel2)); border:1.5px dashed rgb(var(--color-line)); color:rgb(var(--slate-400)); font-size:14px; line-height:1; cursor:pointer; }
.avatar-add-btn:hover { border-color:#3B82F6; color:#3B82F6; }
.theme-light .avatar-add-btn:hover { border-color: rgb(var(--color-primary)); color: rgb(var(--color-primary)); }

/* Task attachment remove (×) button. `bg-rose-500` (the solid, no-opacity utility) was
   never scanned into tailwind.build.css — only its /10, /15, /40 and hover: variants were
   — so this circle rendered with NO fill at all (just a white × floating over whatever's
   underneath) in both themes, and was effectively invisible against a light attachment
   thumbnail or the white Light Theme panel until hovered. Plain CSS gives it a real,
   theme-correct fill, mirroring the identical .avatar-remove pattern above. */
.attachment-delete-btn { background:#f43f5e; }
.attachment-delete-btn:hover { background:#e11d48; }
.theme-light .attachment-delete-btn { background: rgb(var(--color-rose)); }
.theme-light .attachment-delete-btn:hover { background: rgb(var(--color-rose-dark)); }

/* Task Detail modal: click-to-edit affordance for the title/description fields. In Light
   Theme, --color-panel2 (248 250 252) is nearly indistinguishable from the modal's own
   white --color-panel background, so this hover cue was practically invisible there — a
   light tint of the new primary reads as a clear, on-brand "this is editable" affordance
   instead. Dark Theme's panel/panel2 pair already has enough contrast, so it's untouched. */
.editable-field:hover { background:rgb(var(--color-panel2) / .6); }
.theme-light .editable-field:hover { background: rgb(var(--color-primary) / .08); }

/* Task Detail modal: the Status/Priority/Company/Assignees field grid's column gap.
   gap-x-12/gap-y-1 (Tailwind's spacing-scale gap utilities) were never in the compiled
   utility set — confirmed live: getComputedStyle returned "normal" (i.e. not applied at
   all), which is exactly why that spacing fix visually did nothing. Plain CSS avoids
   gambling on which spacing-scale step happens to already be compiled. */
.task-field-grid { column-gap:32px; row-gap:4px; }

/* Task Detail modal: fixed overall size (never grows/shrinks with task content — long
   content scrolls internally instead, per the ClickUp reference) and a two-pane body
   (main content + a fixed-width Activity rail) that stacks vertically on narrow screens.
   Plain CSS rather than Tailwind: a fixed-but-responsive size needs min()/media-query
   logic Tailwind's arbitrary-value syntax doesn't cleanly express, and this app's
   Tailwind build only ever includes the exact utility strings already scanned from
   existing templates anyway (see the avatar-stack note above). */
.task-modal-shell { width:min(1100px, 94vw); height:min(720px, 90vh); }
/* @mention autocomplete dropdown (task description + comment composer) and the rendered
   "@Name" chip itself — a wholly new floating component, so plain CSS rather than betting
   on an arbitrary utility class making it into the compiled Tailwind set (see the
   avatar-stack note above). z-index is deliberately far above any modal (z-50) since the
   dropdown is appended straight to <body>, outside the modal's own stacking context. */
.mention-dropdown { position:fixed; z-index:9999; background:rgb(var(--color-panel)); border:1px solid rgb(var(--color-line)); border-radius:8px; box-shadow:0 8px 24px -4px rgba(0,0,0,.45); max-height:180px; overflow-y:auto; padding:4px; }
/* Portfolio Health Score Trend chart hover tooltip — same fixed-position/append-to-body
   convention as .mention-dropdown above, since this is plain generated SVG rather than
   Tailwind-classed markup. pointer-events:none so it never itself becomes the mouseleave
   target that would fight with the hit-circle's own hover state. */
.trend-tooltip { position:fixed; z-index:9999; pointer-events:none; background:rgb(var(--color-panel)); border:1px solid rgb(var(--color-line)); border-radius:8px; box-shadow:0 8px 24px -4px rgba(0,0,0,.45); padding:8px 10px; font-size:11.5px; line-height:1.5; white-space:nowrap; }
.mention-dropdown-item { display:flex; align-items:center; gap:6px; padding:6px 8px; border-radius:6px; font-size:12.5px; color:rgb(var(--slate-300)); cursor:pointer; }
.mention-dropdown-item.active, .mention-dropdown-item:hover { background:rgb(var(--color-panel2)); color:rgb(var(--color-white)); }
.mention-chip { color:#60A5FA; font-weight:600; background:rgba(59,130,246,.12); border-radius:4px; padding:0 2px; }
/* #60A5FA (a light, low-saturation blue meant for dark panels) measures well under WCAG AA
   against Light Theme's white/near-white panels — swap in the new primary, which already
   clears AA there. */
.theme-light .mention-chip { color: rgb(var(--color-primary)); background: rgb(var(--color-primary) / .12); }
.task-modal-body { display:flex; min-height:0; }
.task-modal-right { width:320px; min-height:0; }
@media (max-width:720px) {
  .task-modal-shell { width:96vw; height:94vh; }
  .task-modal-body { flex-direction:column; }
  .task-modal-right { width:100%; height:45%; border-left:none; border-top:1px solid rgb(var(--color-line)); }
}

/* ===== Utility-class patches =====
   Every rule below is a Tailwind utility class that's used in a .php view or .js render
   function but was never scanned into the static tailwind.build.css (see this file's own
   header comment — there's no live Tailwind build in this project, so any class not
   present in a template at the time that file was generated silently does nothing, no
   error). Found via a full audit of every class="..." in public/views/ and
   public/assets/js/. Each one is written with the exact selector/value Tailwind v3 itself
   would output, so it's indistinguishable from (and safely replaced by) the real utility
   if the build is ever regenerated. Color-family classes (bg-rose-500/5 etc.) also get a
   .theme-light override, matching every other color utility already patched above. */
.-mx-1\.5 { margin-left:-.375rem; margin-right:-.375rem; }
.-mx-2\.5 { margin-left:-.625rem; margin-right:-.625rem; }
.border-l { border-left-width:1px; }
.ml-1 { margin-left:.25rem; }
.ml-1\.5 { margin-left:.375rem; }
.mr-1\.5 { margin-right:.375rem; }
.p-8 { padding:2rem; }
.p-0\.5 { padding:.125rem; }
.p-1\.5 { padding:.375rem; }
.pt-1\.5 { padding-top:.375rem; }
.mt-5 { margin-top:1.25rem; }
.h-5 { height:1.25rem; }
.w-5 { width:1.25rem; }
.text-3xl { font-size:1.875rem; line-height:2.25rem; }
.italic { font-style:italic; }
.cursor-help { cursor:help; }
.pl-2\.5 { padding-left:.625rem; }
.pr-1\.5 { padding-right:.375rem; }
.max-w-\[140px\] { max-width:140px; }
.sticky { position:sticky; }
.top-0 { top:0; }
.bottom-0 { bottom:0; }
.align-\[-2px\] { vertical-align:-2px; }
.max-h-\[200px\] { max-height:200px; }
.max-w-\[220px\] { max-width:220px; }
.min-w-\[820px\] { min-width:820px; }
.min-w-\[1480px\] { min-width:1480px; }
.min-w-\[1500px\] { min-width:1500px; }
.space-y-1>:not([hidden])~:not([hidden]) { --tw-space-y-reverse:0; margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse))); margin-bottom:calc(.25rem*var(--tw-space-y-reverse)); }
@media (min-width:640px) { .sm\:inline { display:inline; } }

.bg-rose-500\/5 { background-color:rgba(244,63,94,.05); }
.theme-light .bg-rose-500\/5 { background-color:rgb(var(--color-rose) / .05); }
.bg-amber-500\/5 { background-color:rgba(245,158,11,.05); }
.theme-light .bg-amber-500\/5 { background-color:rgb(var(--color-amber) / .05); }
.hover\:bg-rose-500\/25:hover { background-color:rgba(244,63,94,.25); }
.theme-light .hover\:bg-rose-500\/25:hover { background-color:rgb(var(--color-rose) / .25); }
.bg-panel2\/40 { background-color:rgb(var(--color-panel2) / .4); }
.bg-panel2\/30 { background-color:rgb(var(--color-panel2) / .3); }
.hover\:text-slate-100:hover { color:rgb(241 245 249); }
.theme-light .hover\:text-slate-100:hover { color:rgb(var(--color-white)); }

/* Settings > Bot Identification & Allowlisting card grid — real media queries (plain CSS,
   not a Tailwind utility) so the column count is exact regardless of the container's actual
   width: 3 per row on desktop, 2 on tablet, 1 on narrow/mobile. */
.bot-id-grid { display: grid; gap: .75rem; grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 1024px) { .bot-id-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) { .bot-id-grid { grid-template-columns: minmax(0, 1fr); } }

/* Settings > API Keys "New key" input — sized a bit past the largest compiled Tailwind
   width utility (w-72/18rem) so the field is roomier without jumping all the way to the
   next compiled size (w-[400px]), which was sized for unrelated, much wider elements. */
.api-key-input { width: 21rem; }

/* Add/Edit User > Client Access Scope's Websites/Clients checklists — a shorter box than
   the only compiled Tailwind max-h-[300px] (sized for the much-longer Permissions list),
   so two of these plus Permissions in one modal doesn't turn into a very long scroll. */
.scope-checklist { max-height: 11rem; }

/* Settings > Clients card — a 2-column grid (1 on narrow/mobile) instead of one row per
   Client stacked full-width, which either left a huge gap before right-aligned buttons or
   a long empty strip after a left-aligned compact group once that was fixed. Two columns
   reads as organized rather than each row floating alone in an oversized box. Same
   real-media-query pattern as .bot-id-grid above, not a compiled Tailwind utility. */
.client-grid { display: grid; gap: .75rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 640px) { .client-grid { grid-template-columns: minmax(0, 1fr); } }

/* Role Editor / Add User / Edit User permission grid (auth.js's permissionTreeHTML()) —
   a module's nested actions sit in one continuous-bordered group, not a separate short
   border fragment per row (which read as disconnected tick marks, not a real tree). A
   light background on the whole module+actions block, plus spacing between modules,
   makes each module's own cluster unmistakable at a glance. */
.permission-module-group { border-radius: 0.5rem; padding: 0.25rem; margin-bottom: 0.375rem; background: rgb(var(--color-panel2) / .35); }
.permission-action-group {
  margin: 0.25rem 0 0.25rem 1.5rem;
  padding: 0.375rem 0 0.375rem 0.875rem;
  border-left: 2px solid rgb(var(--color-line));
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

/* Settings > API Keys/Roles & Permissions/Clients rows previously had no hover feedback
   at all, unlike every other list row or card in the app (table rows, permission rows,
   Task cards). Pairs with each row's own hover:border-electric/40 (already compiled/
   theme-aware, same border highlight Task cards use) for a background tint — reused from
   --color-line rather than a new hardcoded color, since that variable is already tuned to
   read as "lighter" against Dark Theme's near-black panels and "darker" against Light
   Theme's near-white ones without needing two separate rules here. */
.settings-row-hover { transition: background-color .15s ease, border-color .15s ease; }
.settings-row-hover:hover { background-color: rgb(var(--color-line) / .14); }

/* Sidebar footer logo — the source PNG is dark-colored artwork, illegible straight
   against Dark Theme's near-black sidebar, so it's inverted to plain white there (no
   background card needed). In Light Theme the sidebar is already near-white
   (--color-sidebar), so the logo's own colors already read fine unmodified. */
#sidebarFooterLogo { padding: 6px 10px; }
#sidebarFooterLogo img { filter: brightness(0) invert(1); }
.theme-light #sidebarFooterLogo img { filter: none; }

/* Welcome Back modal — a frosted/translucent "glass" card (bg-panel/50 + backdrop-blur)
   tuned for Dark Theme, where panel is near-black and blends into the dark .modal-backdrop
   dimming behind every modal. In Light Theme, panel is white — the same translucency over
   that same dark backdrop produces a muddy grey haze instead of a clean card, and
   border-white/10 (a literal, non-theme-aware white hairline) all but disappears. A solid
   panel + the app's real border color reads correctly against the dark backdrop in both
   themes; the decorative glow blobs are dimmed slightly so they tint a solid light card
   instead of washing over it. */
.theme-light #modal-welcomeBack .modal-pop { background: rgb(var(--color-panel)); border-color: rgb(var(--color-line)); }
.theme-light #modal-welcomeBack .absolute.rounded-full { opacity: .4; }

/* Notification panel (header bell) — no precompiled Tailwind width between w-72 (288px,
   cramped for a title + message line) and w-96 (384px, too wide for a header dropdown),
   so a one-off custom width instead of reaching for an arbitrary-value class that isn't
   in tailwind.build.css. */
.notif-panel { width: 340px; }
.notif-row { border-bottom: 1px solid rgb(var(--color-line)); }
.notif-row:last-child { border-bottom: none; }

/* Website Health Report modal's Share Link section — pb-5 isn't in the precompiled
   Tailwind build (only directional-padding combos some other template already used got
   compiled), so this keeps its bottom gap identical to #siteReportContent's own p-5
   (which IS compiled, being the all-sides shorthand) instead of silently rendering as 0. */
#siteReportShareSection { padding-bottom: 1.25rem; }

/* GTmetrix Grade's 6-tier A–F color scale (A green, B light green, C yellow, D orange,
   E dark orange, F red — see gtmetrixGradeBucket() in sites.js). A and F reuse the app's
   existing text-emerald/text-rose (already correctly themed everywhere else); these four
   are the new middle tiers, none of which exist as precompiled Tailwind utilities in this
   project's static build (only its own named colors — electric/emerald/amber/rose — and
   whatever literal shades some other component already happened to use got compiled), so
   they're hand-written rather than guessing at an uncompiled class. Light-theme values
   step down ~1-2 shades for the same AA-contrast-on-white reason the existing
   --color-amber/--color-rose/--color-emerald overrides already use elsewhere in this file. */
.text-gradeLightgreen { color: #84cc16; }
.bg-gradeLightgreen\/15 { background-color: rgba(132, 204, 22, .15); }
.text-gradeYellow { color: #eab308; }
.bg-gradeYellow\/15 { background-color: rgba(234, 179, 8, .15); }
.text-gradeOrange { color: #f97316; }
.bg-gradeOrange\/15 { background-color: rgba(249, 115, 22, .15); }
.text-gradeDarkorange { color: #ea580c; }
.bg-gradeDarkorange\/15 { background-color: rgba(234, 88, 12, .15); }
.theme-light .text-gradeLightgreen { color: #4d7c0f; }
.theme-light .bg-gradeLightgreen\/15 { background-color: rgba(77, 124, 15, .12); }
.theme-light .text-gradeYellow { color: #a16207; }
.theme-light .bg-gradeYellow\/15 { background-color: rgba(161, 98, 7, .12); }
.theme-light .text-gradeOrange { color: #c2410c; }
.theme-light .bg-gradeOrange\/15 { background-color: rgba(194, 65, 12, .12); }
.theme-light .text-gradeDarkorange { color: #9a3412; }
.theme-light .bg-gradeDarkorange\/15 { background-color: rgba(154, 52, 18, .12); }
