/* ═══════════════════════════════════════════════════════════
   MATrIX Command Center — Concept A: Clean Minimal
   Single CSS file for all admin pages (DRY)
   ═══════════════════════════════════════════════════════════ */

/* ── Font ───────────────────────────────────────────────── */
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&display=swap');

:root {
  /* STA-2686: declare the dark UI to the UA so native form-control popups
     (the <select> dropdown list, date/number spinners) and scrollbars render
     dark on Windows/Chrome instead of the light OS theme. Without this,
     Chromium draws native <select> popups light and ignores `option` colors. */
  color-scheme: dark;
  --bg-body:    #111827;
  --bg-sidebar: #111827;
  --bg-card:    #1f2937;
  --bg-input:   #1f2937;
  --border:     #1f2937;
  --border-light:#374151;
  --accent:     #f97316;
  --accent-dim: #c2410c;
  --text-primary:#ffffff;
  --text-body:   #e5e7eb;
  --text-muted:  #9ca3af;
  --text-dim:    #9ca3af;
  --text-faint:  #4b5563;
  --green:       #22c55e;
  --red:         #ef4444;
  --blue:        #3b82f6;
  --purple:      #a855f7;
  --amber:       #eab308;
  --radius-sm:   0.375rem;
  --radius:      0.5rem;
  --radius-lg:   0.75rem;
  --radius-xl:   1rem;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
body {
  font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  background: var(--bg-body);
  color: var(--text-body);
  height: 100vh;
  overflow: hidden;
  display: flex;
}

/* ── Grain overlay ──────────────────────────────────────── */
body::before {
  content: ''; position: fixed; inset: 0; z-index: 9999; pointer-events: none;
  opacity: 0.015;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ── Scrollbar ──────────────────────────────────────────── */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-light); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }

/* ── Layout shells ──────────────────────────────────────── */
.cc-sidebar {
  width: 15rem;
  height: 100vh;
  background: var(--bg-sidebar);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  position: fixed;
  top: 0; left: 0;
  z-index: 50;
}
.cc-main-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  margin-left: 15rem;
}
.cc-header {
  height: 4rem;
  background: var(--bg-sidebar);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 1.5rem;
  flex-shrink: 0;
}
.cc-content {
  flex: 1;
  overflow-y: auto;
  padding: 1.5rem;
}

/* ── Sidebar nav ────────────────────────────────────────── */
.cc-sidebar .logo-area {
  height: 4rem;
  display: flex;
  align-items: center;
  padding: 0 1.25rem;
  border-bottom: 1px solid var(--border);
  gap: 0.75rem;
}
.cc-sidebar .logo-mark {
  width: 2rem; height: 2rem;
  background: var(--accent);
  border-radius: var(--radius-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-weight: 700;
  font-size: 0.875rem;
}
/* STA-2320: frameless StartGuides arrow override. When .logo-mark contains
   the .logo-mark-arrow img, drop the accent box chrome and let the artwork
   fill the slot. Legacy text-fallback rules above are preserved intact so a
   missing-image scenario doesn't lose the visual placeholder entirely. */
.cc-sidebar .logo-mark:has(.logo-mark-arrow) {
  background: transparent;
  border-radius: 0;
}
.cc-sidebar .logo-mark-arrow {
  width: 100%; height: 100%;
  object-fit: contain;
}
.cc-sidebar .logo-text .brand { color: white; font-weight: 600; font-size: 0.875rem; letter-spacing: 0.05em; }
.cc-sidebar .logo-text .sub   { color: var(--text-dim); font-size: 0.625rem; text-transform: uppercase; letter-spacing: 0.15em; }

.cc-nav { flex: 1; overflow-y: auto; padding: 1rem 0.75rem; }
.cc-nav-section {
  color: var(--text-dim);
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  font-weight: 600;
  padding: 0 0.75rem;
  margin-bottom: 0.5rem;
  margin-top: 1.25rem;
}
.cc-nav-section:first-child { margin-top: 0; }

.cc-nav-link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius-lg);
  font-size: 0.875rem;
  color: var(--text-muted);
  text-decoration: none;
  transition: all 0.15s ease;
  position: relative;
  border: none;
  background: none;
  width: 100%;
  cursor: pointer;
  text-align: left;
}
.cc-nav-link:hover {
  color: white;
  background: rgba(255,255,255,0.04);
}
.cc-nav-link:hover::before {
  content: '';
  position: absolute;
  left: 0; top: 4px; bottom: 4px;
  width: 3px;
  background: var(--accent);
  border-radius: 0 4px 4px 0;
}
.cc-nav-link.active {
  color: white;
  background: rgba(249,115,22,0.08);
}
.cc-nav-link.active::before {
  content: '';
  position: absolute;
  left: 0; top: 4px; bottom: 4px;
  width: 3px;
  background: var(--accent);
  border-radius: 0 4px 4px 0;
}
.cc-nav-link .nav-icon {
  width: 1rem; height: 1rem;
  color: var(--text-dim);
  flex-shrink: 0;
}
.cc-nav-link.active .nav-icon { color: var(--accent); }
.cc-nav-link.disabled {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}
.cc-nav-link .nav-badge {
  margin-left: auto;
  font-size: 0.625rem;
  background: var(--bg-card);
  color: var(--text-dim);
  padding: 0.125rem 0.375rem;
  border-radius: 9999px;
}

.cc-sidebar .sidebar-footer {
  padding: 0.75rem 1rem;
  display: flex;
  align-items: center;
}

/* ── Header ─────────────────────────────────────────────── */
.cc-header .page-info h1 { color: white; font-size: 1.125rem; font-weight: 600; }
.cc-header .page-info p  { color: var(--text-dim); font-size: 0.75rem; }
.cc-header .header-actions { display: flex; align-items: center; gap: 0.75rem; }
/* STA-3407: logged-in identity next to the door-icon sign-out button,
   mirroring the frontend header's name span (text-gray-400 text-sm). */
.cc-header .header-user-email { color: var(--text-muted); font-size: 0.875rem; }
.cc-search {
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-lg);
  padding: 0.375rem 0.75rem 0.375rem 2.25rem;
  font-size: 0.875rem;
  color: var(--text-muted);
  width: 14rem;
  outline: none;
  transition: border-color 0.15s;
  font-family: inherit;
}
.cc-search:focus { border-color: rgba(249,115,22,0.5); box-shadow: 0 0 0 2px rgba(249,115,22,0.15); }
.cc-search::placeholder { color: var(--text-faint); }

/* ── Cards ──────────────────────────────────────────────── */
.card {
  background: var(--bg-card);
  border-radius: var(--radius-xl);
  border: 1px solid var(--border);
}
.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border);
}
.card-header h3 { color: white; font-size: 0.875rem; font-weight: 600; }
.card-body { padding: 1.25rem; }
.card-body-flush { padding: 0; }

/* ── Stat cards (KPI) ───────────────────────────────────── */
.stat-card {
  background: var(--bg-card);
  border-radius: var(--radius-xl);
  padding: 1.25rem;
  border: 1px solid var(--border);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.stat-card:hover { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(0,0,0,0.3); }
.stat-card .stat-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.75rem; }
.stat-card .stat-label { color: var(--text-dim); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; }
.stat-card .stat-icon {
  width: 2rem; height: 2rem;
  border-radius: var(--radius-lg);
  display: flex;
  align-items: center;
  justify-content: center;
}
.stat-card .stat-value { font-size: 1.5rem; font-weight: 700; color: white; }
.stat-card .stat-delta { font-size: 0.75rem; margin-top: 0.25rem; }

/* ── Tables ─────────────────────────────────────────────── */
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}
.data-table thead th {
  padding: 0.75rem 1rem;
  text-align: left;
  color: var(--text-dim);
  font-size: 0.75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.data-table tbody tr {
  border-bottom: 1px solid rgba(255,255,255,0.03);
  transition: background 0.1s;
}
.data-table tbody tr:hover { background: rgba(249,115,22,0.03); }
.data-table tbody td {
  padding: 0.75rem 1rem;
  color: var(--text-muted);
  vertical-align: middle;
}
.data-table tbody td:first-child { color: white; font-weight: 500; }
.data-table .cell-actions { display: flex; gap: 0.5rem; align-items: center; }
/* STA-3449: opt-in fixed layout (+ per-table colgroup) keeps column widths stable
   across search/filter reloads; no-search tables keep auto layout. */
.data-table--fixed { table-layout: fixed; }
/* STA-3449: truncate long free-text under fixed layout. A cell defaults to
   overflow:visible, so without this a long email/name paints over the next
   column. min-width:0 is what lets it shrink when the container is a flex item
   (the Users email drilldown button). Pair with a title="" for the full value. */
.data-table .cell-truncate {
  min-width: 0;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* STA-3449: badge groups wrap rather than truncate -- dropping a badge would hide
   a whole unit/role -- but one over-long badge still ellipsises inside its column.
   inline-block (not .badge's inline-flex) is what makes text-overflow apply, and
   vertical-align keeps the pill sitting where the inline-flex one did. */
.data-table .badge-truncate {
  display: inline-block;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}

/* ── Badges ─────────────────────────────────────────────── */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem 0.5rem;
  border-radius: 9999px;
  font-size: 0.6875rem;
  font-weight: 500;
  white-space: nowrap;
}
.badge-green  { background: rgba(34,197,94,0.1);  color: #4ade80; }
.badge-red    { background: rgba(239,68,68,0.1);  color: #f87171; }
.badge-blue   { background: rgba(59,130,246,0.1); color: #60a5fa; }
.badge-orange { background: rgba(249,115,22,0.1); color: #fb923c; }
.badge-purple { background: rgba(168,85,247,0.1); color: #c084fc; }
.badge-gray   { background: rgba(107,114,128,0.1);color: #9ca3af; }
.badge-amber, .badge-yellow { background: rgba(234,179,8,0.1);  color: #fbbf24; }

/* ── Buttons ────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  border-radius: var(--radius-lg);
  font-size: 0.875rem;
  font-weight: 500;
  border: none;
  cursor: pointer;
  transition: all 0.15s;
  text-decoration: none;
  font-family: inherit;
  line-height: 1.5;
}
.btn-primary {
  background: var(--accent);
  color: white;
}
.btn-primary:hover { background: #ea580c; }
.btn-secondary {
  background: var(--bg-card);
  color: var(--text-muted);
  border: 1px solid var(--border-light);
}
.btn-secondary:hover { color: white; border-color: var(--text-dim); }
.btn-ghost {
  background: transparent;
  color: var(--text-muted);
  padding: 0.375rem 0.5rem;
  /* STA-3407: .btn-ghost is used standalone (without .btn), so it needs its
     own border/cursor reset — otherwise the native button border shows and
     the header/sidebar icon buttons don't match the frontend's ghost look. */
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
}
.btn-ghost:hover { color: white; background: rgba(255,255,255,0.05); }
.btn-danger {
  background: rgba(239,68,68,0.1);
  color: #f87171;
  border: 1px solid rgba(239,68,68,0.2);
}
.btn-danger:hover { background: rgba(239,68,68,0.2); }
.btn-link {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 0.75rem;
  cursor: pointer;
  text-decoration: none;
  font-family: inherit;
}
.btn-link:hover { text-decoration: underline; }

.btn-sm { padding: 0.25rem 0.625rem; font-size: 0.75rem; }
.btn-icon { padding: 0.375rem; border-radius: var(--radius); }
/* UX-080: the native focus outline on `color-scheme: dark` (line ~14) is
   practically invisible (~1.07:1 contrast) on nav links/buttons. */
.cc-nav-link:focus-visible, .btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── Forms ──────────────────────────────────────────────── */
.form-group { margin-bottom: 1.25rem; }
/* UX-038: the kebab "Change Role"/"Add to Unit" actions land on
   /edit/#field-groups and #field-units (user_form.html's per-field
   id="field-{{ field.name }}" wrapper) with no visual indication of which
   field the jump landed on. */
.form-group:target { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 4px; }
.form-label {
  display: block;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-muted);
  margin-bottom: 0.375rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.form-input,
.form-select,
.form-textarea {
  width: 100%;
  padding: 0.625rem 0.875rem;
  background: var(--bg-body);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-lg);
  color: var(--text-body);
  font-size: 0.875rem;
  font-family: inherit;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.form-input:focus,
.form-select:focus,
.form-textarea:focus {
  border-color: rgba(249,115,22,0.5);
  box-shadow: 0 0 0 2px rgba(249,115,22,0.15);
}
.form-input::placeholder { color: var(--text-faint); }
.form-select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%236b7280' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  padding-right: 2.5rem;
}
.form-textarea { resize: vertical; min-height: 5rem; }
.form-check {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: var(--text-muted);
  cursor: pointer;
}
.form-check input[type="checkbox"] { accent-color: var(--accent); width: 1rem; height: 1rem; }
.form-hint { font-size: 0.75rem; color: var(--text-dim); margin-top: 0.25rem; }
.form-error { font-size: 0.75rem; color: var(--red); margin-top: 0.25rem; }
.form-row { display: grid; gap: 1rem; }
.form-row-2 { grid-template-columns: 1fr 1fr; }
.form-row-3 { grid-template-columns: 1fr 1fr 1fr; }
.form-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
  margin-top: 1.5rem;
}

/* Django form widget overrides — make Django-rendered inputs match */
.cc-form input[type="text"],
.cc-form input[type="email"],
.cc-form input[type="password"],
.cc-form input[type="url"],
.cc-form input[type="number"],
.cc-form input[type="date"],
.cc-form input[type="datetime-local"],
.cc-form select,
.cc-form textarea {
  width: 100%;
  padding: 0.625rem 0.875rem;
  background: var(--bg-body);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-lg);
  color: var(--text-body);
  font-size: 0.875rem;
  font-family: inherit;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.cc-form input:focus,
.cc-form select:focus,
.cc-form textarea:focus {
  border-color: rgba(249,115,22,0.5);
  box-shadow: 0 0 0 2px rgba(249,115,22,0.15);
}
.cc-form input[type="checkbox"] { accent-color: var(--accent); }

/* STA-3565: password field with an inline eye toggle. Shared by the Create User
   form and the set-password modal; behavior lives in password-controls.js.
   The padding rule names both consumers on purpose: the Django-rendered form is
   already covered by `.cc-form input[type=...]` above and the hand-written modal
   by `.form-input`, so it has to out-specify each. It is also deliberately
   type-agnostic, since the toggle swaps the input to type=text and a
   [type="password"] rule would drop the padding mid-interaction. */
.cc-password-field { position: relative; }
.cc-form .cc-password-field input,
.cc-password-field input.form-input { padding-right: 2.5rem; }
.cc-password-toggle {
  position: absolute;
  right: 0.625rem;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  padding: 0;
  background: none;
  border: 0;
  color: var(--text-dim);
  cursor: pointer;
}
.cc-password-toggle:hover { color: var(--text-body); }
.cc-password-toggle svg { width: 1.25rem; height: 1.25rem; }
.cc-hidden { display: none; }
.cc-form select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%236b7280' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  padding-right: 2.5rem;
}
.cc-form label {
  display: block;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-muted);
  margin-bottom: 0.375rem;
}
.cc-form .helptext {
  font-size: 0.75rem;
  color: var(--text-dim);
  margin-top: 0.25rem;
}
.cc-form .errorlist {
  list-style: none;
  padding: 0;
  margin: 0.25rem 0 0;
}
.cc-form .errorlist li {
  font-size: 0.75rem;
  color: var(--red);
}
/* Multi-select checkboxes (Django CheckboxSelectMultiple) */
.cc-form ul {
  list-style: none;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
}
.cc-form ul li {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.875rem;
  color: var(--text-muted);
}
.cc-form ul li label { margin-bottom: 0; display: inline; }

/* ── Impersonation bar (Plugin Management) — STA-2686 ───────
   The impersonation controls live outside any .cc-form, so the
   .cc-form rules above don't reach them. Style them here to match
   the Command Center palette (mirrors the .cc-form input/select
   pattern: var() palette, appearance:none + inline-SVG arrow,
   orange focus ring). Pairs with `color-scheme: dark` on :root,
   which darkens the native <select> popup. */
.impersonation-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  padding: 0.75rem 1.25rem;
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  margin-bottom: 1.5rem;
  min-height: 3rem;
}
.impersonation-controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
}
.impersonation-label {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
}
.impersonation-search-input,
.impersonation-user-select,
.impersonation-reason-select,
.impersonation-modal-select,
.impersonation-modal-input {
  padding: 0.5rem 0.875rem;
  background-color: var(--bg-body);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  color: var(--text-body);
  font-size: 0.875rem;
  font-family: inherit;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.impersonation-search-input::placeholder { color: var(--text-dim); }
.impersonation-search-input { width: 11rem; }
.impersonation-user-select { min-width: 15rem; cursor: pointer; }
.impersonation-reason-select { min-width: 11rem; cursor: pointer; }
.impersonation-modal-select,
.impersonation-modal-input { width: 100%; }
/* appearance:none + inline-SVG dropdown arrow, mirroring .cc-form select */
.impersonation-user-select,
.impersonation-reason-select,
.impersonation-modal-select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%236b7280' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  padding-right: 2.5rem;
}
.impersonation-user-select option,
.impersonation-reason-select option,
.impersonation-modal-select option {
  background: var(--bg-card);
  color: var(--text-body);
}
.impersonation-search-input:focus,
.impersonation-user-select:focus,
.impersonation-reason-select:focus,
.impersonation-modal-select:focus,
.impersonation-modal-input:focus {
  border-color: rgba(249, 115, 22, 0.5);
  box-shadow: 0 0 0 2px rgba(249, 115, 22, 0.15);
}
@media (max-width: 768px) {
  .impersonation-bar { flex-direction: column; align-items: stretch; }
  .impersonation-controls { width: 100%; flex-direction: column; align-items: stretch; }
  .impersonation-search-input,
  .impersonation-user-select,
  .impersonation-reason-select { width: 100%; min-width: 0; }
}

/* Impersonation active state + loading — ported from the removed
   styles.css (STA-2687); only admin.css reaches _impersonation_bar.html now.
   Hardcoded hex adapted to the var() palette. */
.impersonation-active {
  display: flex;
  align-items: center;
  gap: 0.9375rem;
  width: 100%;
}
.impersonation-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  background: var(--accent-dim);
  color: white;
  border-radius: 9999px;
  font-size: 0.875rem;
  font-weight: 500;
  animation: impersonation-pulse 2s ease-in-out infinite;
}
.impersonation-badge svg { flex-shrink: 0; }
@keyframes impersonation-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(249, 115, 22, 0.5); }
  50%      { box-shadow: 0 0 0 0.5rem rgba(249, 115, 22, 0); }
}
#impersonated-user-name { font-weight: 600; margin-left: 0.25rem; }
.btn-end-impersonation {
  padding: 0.5rem 1.25rem;
  background: var(--red);
  color: white;
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 500;
  transition: opacity 0.15s, transform 0.1s;
  margin-left: auto;
}
.btn-end-impersonation:hover:not(:disabled) { opacity: 0.9; transform: translateY(-1px); }
.btn-end-impersonation:active:not(:disabled) { transform: translateY(0); }
.btn-end-impersonation:disabled { opacity: 0.6; cursor: not-allowed; }
.impersonation-loading {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  color: var(--text-dim);
  font-size: 0.875rem;
}
.impersonation-spinner {
  width: 1.25rem;
  height: 1.25rem;
  border: 2px solid var(--border-light);
  border-top: 2px solid var(--accent);
  border-radius: 50%;
  animation: impersonation-spin 0.8s linear infinite;
}
@keyframes impersonation-spin {
  0%   { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
@media (max-width: 768px) {
  .impersonation-active { flex-direction: column; text-align: center; }
  .btn-end-impersonation { margin-left: 0; width: 100%; }
}

/* ── Plugin table (Command Center Plugins page) — STA-3131, STA-3138 ──
   _plugin_list.html renders these semantic classes but no stylesheet
   defines them (grep-verified: they appear only as JS selectors in
   plugin-management.js) — combined with the Tailwind CDN's preflight
   reset (loaded in plugin_management.html), the "View Plugin" button
   rendered as plain unstyled text. Class-selector rules here beat
   Tailwind's element-level preflight resets on specificity regardless
   of stylesheet load order, so no !important is needed. Sizing tokens
   mirror this file's .detail-grid / .stat-card conventions. */
.plugin-row-loading { opacity: 0.6; }
/* scoped to .plugin-name-cell: bare .plugin-icon is a public utility class
   inside .plugin-renderer-scope (plugin-renderer.css) for plugin-rendered
   content — an unscoped rule here would leak this sizing across that
   isolation boundary */
.plugin-name-cell .plugin-icon { width: 2.5rem; height: 2.5rem; flex-shrink: 0; }
.plugin-icon-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: var(--radius-lg);
}
.plugin-icon-placeholder {
  width: 2.5rem;
  height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-input);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-lg);
  color: var(--accent);
  font-size: 0.875rem;
  font-weight: 700;
}
.plugin-name-cell { display: flex; align-items: center; gap: 0.75rem; }

/* Checkbox-driven pill switch (native :checked — NOT the unused
   JS-class-driven .toggle/.toggle.on idiom below). performToggle()'s
   error path in plugin-management.js does `toggle.checked = !enabled`;
   only a :checked-keyed selector reacts to that. STA-3272: shared
   verbatim by the App Catalog "Live" column -- toggleAppVisibility() in
   app_list.html's inline script has the same checkbox.checked-flipping
   revert paths, so keep this checkbox-driven for both consumers. */
.plugin-toggle-switch {
  position: relative;
  display: inline-block;
  width: 2.75rem;
  height: 1.5rem;
  flex-shrink: 0;
  cursor: pointer;
}
.plugin-toggle-input { position: absolute; opacity: 0; width: 0; height: 0; }
.plugin-toggle-slider {
  position: absolute;
  inset: 0;
  background: var(--border-light);
  border-radius: 0.75rem;
  transition: background 0.2s;
}
.plugin-toggle-slider::after {
  content: '';
  position: absolute;
  top: 0.1875rem;
  left: 0.1875rem;
  width: 1.125rem;
  height: 1.125rem;
  background: white;
  border-radius: 50%;
  transition: transform 0.2s;
}
.plugin-toggle-input:checked + .plugin-toggle-slider { background: var(--accent); }
.plugin-toggle-input:checked + .plugin-toggle-slider::after { transform: translateX(1.25rem); }
.plugin-toggle-input:focus-visible + .plugin-toggle-slider { box-shadow: 0 0 0 2px rgba(249,115,22,0.4); }

.plugin-name { color: white; font-size: 0.9375rem; font-weight: 600; margin-bottom: 0.375rem; }
.plugin-author { font-size: 0.75rem; color: var(--text-dim); }
.plugin-table .plugin-version { white-space: nowrap; font-size: 0.75rem; color: var(--text-dim); }
.plugin-description {
  color: var(--text-muted);
  font-size: 0.8125rem;
  line-height: 1.5;
  max-width: 32rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.plugin-view-btn {
  padding: 0.5rem 0.875rem;
  background: var(--accent);
  color: white;
  border: none;
  border-radius: var(--radius-lg);
  font-size: 0.875rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s;
}
.plugin-view-btn:hover:not(:disabled) { background: #ea580c; }
.plugin-view-btn:disabled {
  background: var(--bg-input);
  color: var(--text-dim);
  cursor: not-allowed;
  border: 1px solid var(--border-light);
}

.plugin-table thead th { position: sticky; top: 0; background: var(--bg-card); z-index: 1; }
.card-body-flush.plugin-table-scroll { overflow-x: auto; overflow-y: auto; max-height: 28rem; }
.plugin-table { min-width: 50rem; }

.plugin-empty-state { text-align: center; padding: 3rem 1rem; color: var(--text-dim); }
.plugin-empty-icon { margin-bottom: 1rem; opacity: 0.3; }
.plugin-empty-title { color: white; font-size: 0.9375rem; font-weight: 600; margin-bottom: 0.375rem; }
.plugin-empty-message { font-size: 0.875rem; }

/* ── Toggle switch ──────────────────────────────────────── */
.toggle {
  width: 2.75rem;
  height: 1.5rem;
  background: var(--border-light);
  border-radius: 0.75rem;
  position: relative;
  cursor: pointer;
  transition: background 0.2s;
  flex-shrink: 0;
}
.toggle.on { background: var(--accent); }
.toggle::after {
  content: '';
  position: absolute;
  width: 1.125rem;
  height: 1.125rem;
  background: white;
  border-radius: 50%;
  top: 0.1875rem;
  left: 0.1875rem;
  transition: transform 0.2s;
}
.toggle.on::after { transform: translateX(1.25rem); }

/* ── Modal ──────────────────────────────────────────────── */
.modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.6);
  z-index: 100;
  align-items: center;
  justify-content: center;
}
.modal-overlay.open { display: flex; }
.modal-box {
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-xl);
  width: 100%;
  max-width: 28rem;
  overflow: hidden;
}
.modal-head {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.modal-head h3 { color: white; font-size: 1rem; font-weight: 600; }
.modal-body { padding: 1.25rem; }
.modal-foot {
  padding: 1rem 1.25rem;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
}

/* STA-3407: version-info panel rows — mirror the frontend popup's row
   rhythm (sidebar.js showVersionInfo: flex label/value rows, divider
   between rows, value right-aligned and break-all for the SHA). */
.version-row {
  display: flex;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
  font-size: 1rem;
}
.version-row:last-child { border-bottom: none; }
.version-row .version-label { color: var(--text-dim); }
.version-row .version-value { color: var(--text-body); text-align: right; word-break: break-all; }

/* Impersonation reason modal — ported from the removed styles.css (STA-2687).
   _impersonation_bar.html uses the .modal/.modal-content/.modal-header/
   .modal-footer names (toggled via inline display in impersonation.js),
   distinct from the .modal-overlay/.modal-box system above. Palette tokenized;
   .modal-body, .form-group, .btn-primary/.btn-secondary already live above. */
.modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10001;
}
.modal-content {
  background: var(--bg-card);
  border-radius: var(--radius-xl);
  width: 90%;
  max-width: 28rem;
  box-shadow: 0 0.5rem 2rem rgba(0, 0, 0, 0.5);
  overflow: hidden;
}
.impersonation-modal-content { border: 1px solid var(--border-light); }
.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 1.25rem;
  background: var(--bg-sidebar);
  border-bottom: 1px solid var(--border-light);
}
.modal-header h3 { margin: 0; color: white; font-size: 1.2em; font-weight: 500; }
.modal-close-btn {
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 1.5em;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  transition: color 0.15s;
}
.modal-close-btn:hover { color: white; }
.impersonation-modal-message { color: var(--text-body); margin: 0 0 1.25rem 0; font-size: 0.95em; }
.impersonation-modal-message strong { color: var(--accent); }
.modal-body .form-group label {
  display: block;
  color: var(--text-muted);
  font-size: 0.9em;
  margin-bottom: 0.375rem;
}
.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.625rem;
  padding: 1rem 1.25rem;
  background: var(--bg-sidebar);
  border-top: 1px solid var(--border-light);
}

/* ── Pagination ─────────────────────────────────────────── */
.pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--border);
  font-size: 0.75rem;
  color: var(--text-dim);
}
.pagination .page-links { display: flex; gap: 0.25rem; }
.pagination .page-link {
  padding: 0.25rem 0.625rem;
  border-radius: var(--radius);
  color: var(--text-dim);
  text-decoration: none;
  font-size: 0.75rem;
  border: 1px solid transparent;
}
.pagination .page-link:hover { color: white; background: rgba(255,255,255,0.05); }
.pagination .page-link.active {
  background: rgba(249,115,22,0.1);
  color: var(--accent);
  border-color: rgba(249,115,22,0.2);
}

/* ── Filter bar ─────────────────────────────────────────── */
.filter-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1.25rem;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.filter-bar .form-input,
.filter-bar .form-select { width: auto; padding: 0.375rem 0.75rem; font-size: 0.8125rem; }

/* ── Grid helpers ───────────────────────────────────────── */
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }
.grid-3-2 { display: grid; grid-template-columns: 2fr 1fr; gap: 1.5rem; }

/* ── Messages (Django messages framework) ───────────────── */
.messages-list { list-style: none; padding: 0; margin: 0 0 1rem; }
.messages-list li {
  padding: 0.75rem 1rem;
  border-radius: var(--radius-lg);
  font-size: 0.875rem;
  margin-bottom: 0.5rem;
}
.messages-list .success { background: rgba(34,197,94,0.1); color: #4ade80; border: 1px solid rgba(34,197,94,0.2); }
.messages-list .error   { background: rgba(239,68,68,0.1); color: #f87171; border: 1px solid rgba(239,68,68,0.2); }
.messages-list .warning { background: rgba(234,179,8,0.1); color: #fbbf24; border: 1px solid rgba(234,179,8,0.2); }
.messages-list .info    { background: rgba(59,130,246,0.1); color: #60a5fa; border: 1px solid rgba(59,130,246,0.2); }

/* ── Animations ─────────────────────────────────────────── */
@keyframes fadeSlide {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.fade-in { animation: fadeSlide 0.3s ease both; }
.stagger-1 { animation-delay: 0.05s; }
.stagger-2 { animation-delay: 0.1s; }
.stagger-3 { animation-delay: 0.15s; }
.stagger-4 { animation-delay: 0.2s; }

/* ── Tab navigation ─────────────────────────────────────── */
.tab-nav {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1.5rem;
}
.tab-nav a, .tab-nav button {
  padding: 0.625rem 1rem;
  font-size: 0.8125rem;
  color: var(--text-dim);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  background: none;
  border-top: none;
  border-left: none;
  border-right: none;
  font-family: inherit;
  transition: color 0.15s, border-color 0.15s;
}
.tab-nav a:hover, .tab-nav button:hover { color: var(--text-muted); }
.tab-nav a.active, .tab-nav button.active { color: var(--accent); border-bottom-color: var(--accent); }

/* ── Empty state ────────────────────────────────────────── */
.empty-state {
  text-align: center;
  padding: 3rem 1rem;
  color: var(--text-dim);
}
.empty-state .empty-icon { margin-bottom: 1rem; opacity: 0.3; }
.empty-state p { font-size: 0.875rem; }

/* ── Utility ────────────────────────────────────────────── */
.text-accent { color: var(--accent); }
.text-green  { color: var(--green); }
.text-red    { color: var(--red); }
.text-blue   { color: var(--blue); }
.text-muted  { color: var(--text-muted); }
.text-dim    { color: var(--text-dim); }
.text-sm     { font-size: 0.75rem; }
.text-xs     { font-size: 0.625rem; }
.font-mono   { font-family: ui-monospace, monospace; }
.mt-4   { margin-top: 1rem; }
.mt-6   { margin-top: 1.5rem; }
.mb-4   { margin-bottom: 1rem; }
.mb-6   { margin-bottom: 1.5rem; }
.gap-4  { gap: 1rem; }
.gap-6  { gap: 1.5rem; }
.flex   { display: flex; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.flex-1 { flex: 1; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); border: 0; }

/* ── Login page (standalone, no sidebar) ────────────────── */
.login-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: var(--bg-body);
}
.login-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 2.5rem;
  width: 100%;
  max-width: 24rem;
}

/* ── Analytics page ─────────────────────────────────────── */
/* STA-2324: tab bar is a card panel (ports /tmp/cc-mockup .tabs) holding the
   pill tab rows + an absolutely-positioned "Show all views" toggle. */
.analytics-tabbar {
  position: relative;
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-lg);
  padding: 0.8125rem 0.9375rem;
  margin-bottom: 1rem;
}
.analytics-tabs {
  display: flex;
  flex-direction: column;
  gap: 0.5625rem;
  padding-right: 11rem; /* clear the absolute toggle */
}
/* Each section = one pill row with an optional right-aligned group label. */
.analytics-tabs .tab-section { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem; }
.analytics-tabs .tab-section-label {
  flex: 0 0 6.875rem; text-align: right; padding-right: 0.625rem;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.625rem; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-faint);
}
/* Collapsed (default): one row of the 4 primary pills — no labels, no sections.
   Switch the column layout to a wrapping row so the flattened pills sit inline
   at natural width instead of stacking full-width. */
.analytics-tabs.analytics-collapsed { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.analytics-tabs.analytics-collapsed .tab-section { display: contents; }
.analytics-tabs.analytics-collapsed .tab-section-label { display: none; }
.analytics-tabs.analytics-collapsed .tablinks:not([data-primary]) { display: none; }
/* Pill tab buttons. */
.analytics-tabs .tablinks {
  font-size: 0.78125rem;
  font-weight: 550;
  color: var(--text-dim);
  background: var(--bg-body);
  border: 1px solid var(--border-light);
  padding: 0.4375rem 0.8125rem;
  border-radius: var(--radius);
  cursor: pointer;
  font-family: inherit;
  white-space: nowrap;
  transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.analytics-tabs .tablinks:hover { color: var(--text-body); border-color: #4a5a70; }
.analytics-tabs .tablinks.active {
  background: var(--accent); border-color: var(--accent); color: #1a1206; font-weight: 650;
}
.analytics-tabs .tablinks.hidden-tab { display: none; }
/* STA-2324 B1: on narrow screens the section label wraps to its own full row
   above its pills (ported from the matrix_usage.html inline <style>). */
@media (max-width: 700px) {
  .analytics-tabs .tab-section-label { flex-basis: 100%; }
}

/* STA-2324: "Show all views" toggle — absolute top-right of the tab card. */
.show-all-toggle {
  position: absolute; top: 0.8125rem; right: 0.9375rem;
  display: inline-flex; align-items: center; gap: 0.5rem; cursor: pointer;
}
.show-all-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.show-all-track {
  position: relative; width: 38px; height: 21px; border-radius: 20px;
  background: var(--bg-input); border: 1px solid var(--border-light); transition: background 0.15s, border-color 0.15s;
}
.show-all-thumb {
  position: absolute; top: 2px; left: 2px; width: 15px; height: 15px; border-radius: 50%;
  background: var(--text-dim); transition: transform 0.15s, background 0.15s;
}
.show-all-toggle input:checked + .show-all-track { background: rgba(249,115,22,0.14); border-color: rgba(249,115,22,0.5); }
.show-all-toggle input:checked + .show-all-track .show-all-thumb { transform: translateX(17px); background: var(--accent); }
.show-all-text { font-size: 0.75rem; color: var(--text-dim); font-weight: 550; }
.show-all-count {
  font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.625rem; color: var(--text-faint);
  background: var(--bg-input); border: 1px solid var(--border-light); padding: 0.0625rem 0.4375rem; border-radius: 20px; margin-left: 0.25rem;
}

/* STA-2324 / STA-3277: filter panel. One card; every widget is a uniform .field with
   a fixed-height .field-head (label + optional right-aligned actions) above one control
   box, laid out on a 12-col grid (not a ragged wrapping flex row) so the widgets share
   top edges and consistent widths. */
.filters-panel {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  align-items: start;
  gap: 0.875rem 1rem;
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-lg);
  padding: 0.875rem 1rem;
  margin-bottom: 1rem;
}
/* Sections are visibility wrappers (toggled per tab); transparent to layout so the
   .field inside becomes the grid item directly. */
.filters-panel .filter-section { display: contents; }
/* Narrow widgets span 2 of 12, the two multi-selects span 3, so a full filter row
   (2+2+2+3+3) lands on one line with the boxes aligned. min-width:0 lets a grid item
   shrink instead of overflowing. */
.filters-panel .field { grid-column: span 2; display: flex; flex-direction: column; gap: 0.375rem; min-width: 0; }
.filters-panel .field-wide { grid-column: span 3; }
/* Fixed-height header row (label left, optional actions right). A consistent header
   height is what keeps every control box top-aligned across the row. */
.filters-panel .field-head {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; min-height: 1.125rem;
}
.filters-panel .field-head label {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.625rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); white-space: nowrap;
}
/* One consistent style for every per-widget action (quick-range presets, license
   select-all/clear), anchored at the header's right edge instead of floating. */
.filters-panel .field-actions { display: flex; gap: 0.625rem; align-items: center; }
.filters-panel .field-action-btn {
  background: none; border: none; padding: 0; cursor: pointer; font-family: inherit;
  font-size: 0.6875rem; line-height: 1; color: var(--text-muted); white-space: nowrap;
}
.filters-panel .field-action-btn:hover { color: var(--accent); }
/* One control-box treatment for every widget: full-cell width, same height, padding,
   border, radius and background (date inputs, the native Top-N select, and select2). */
.filters-panel .field input[type="date"], .filters-panel .field > select {
  width: 100%; box-sizing: border-box; height: 2.375rem;
  background: var(--bg-input); border: 1px solid var(--border-light); color: var(--text-body);
  border-radius: var(--radius); padding: 0 0.6875rem; font-size: 0.8125rem; font-family: inherit; outline: none;
}
.filters-panel .field > select {
  padding-right: 2.25rem; cursor: pointer; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%236b7280' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.6875rem center;
}
.filters-panel .field input[type="date"]:focus, .filters-panel .field > select:focus { border-color: var(--accent); }
.filters-panel .field input[type="date"]::-webkit-calendar-picker-indicator { filter: invert(0.7); }
/* Bring the select2 boxes into the same system as the native controls (the global
   select2 theme uses a different radius/background); scoped to the panel so other
   select2 widgets elsewhere in the app are untouched. Multi-selects grow downward as
   chips are added; align-items:start keeps their top edge on the row line. */
.filters-panel .field .select2-container { width: 100% !important; }
.filters-panel .field .select2-container--default .select2-selection--single,
.filters-panel .field .select2-container--default .select2-selection--multiple {
  min-height: 2.375rem !important; border-radius: var(--radius) !important; background: var(--bg-input) !important;
}
.filters-apply {
  align-self: start; background: var(--accent); border: 1px solid var(--accent); color: #1a1206;
  font-weight: 650; font-size: 0.8125rem; border-radius: var(--radius); padding: 0.5625rem 1rem; cursor: pointer;
  font-family: inherit;
}
.filters-apply:hover { background: #ea580c; }

/* STA-3277: the panel's own last row: applied-filter chips on the left, the
   page-level Clear as a right-aligned ghost. Sits directly under the filter
   widgets with no divider (a slight negative margin snugs it up) so the panel
   reads as one continuous block. Spans the whole grid row; overrides the
   .filter-section display:contents above. */
.filters-panel .filters-footer {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.375rem 0.75rem;
  flex-wrap: wrap;
  /* Cancel most of the grid row-gap above and tuck into the panel's bottom
     padding so the row adds almost no height of its own. */
  margin-top: -0.625rem;
  margin-bottom: -0.375rem;
}
.filters-panel .filters-footer .btn {
  padding-top: 0.125rem;
  padding-bottom: 0.125rem;
  font-size: 0.6875rem;
  white-space: nowrap;
}

/* STA-3277: applied-filter chips. One bubble per applied value; the x removes it,
   the padlock marks it locked (survives Clear all, accent border), chip-inactive
   means held but not used by the current tab's charts. flex:1 keeps the chips on
   the left and pushes the Clear ghost to the row's right edge. */
.filter-chips { display: flex; flex-wrap: wrap; gap: 0.375rem; align-items: center; flex: 1; min-width: 0; }
.filter-chip {
  display: inline-flex; align-items: center; gap: 0.375rem; max-width: 18rem;
  background: var(--bg-input); border: 1px solid var(--border-light); border-radius: 20px;
  padding: 0.1875rem 0.5rem 0.1875rem 0.625rem;
  font-size: 0.6875rem; color: var(--text-body);
}
.filter-chip .chip-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.filter-chip.chip-locked { border-color: var(--accent); }
.filter-chip.chip-inactive { opacity: 0.45; }
.filter-chip .chip-btn {
  background: none; border: none; padding: 0; cursor: pointer; font-family: inherit;
  color: var(--text-muted); display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5rem; min-height: 1.5rem; border-radius: 0.25rem; line-height: 1;
}
.filter-chip .chip-btn:hover { color: var(--accent); }
.filter-chip .chip-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.filter-chip.chip-locked .chip-lock { color: var(--accent); }
.filter-chip .chip-x { font-size: 0.875rem; }

/* Narrow viewports: collapse the 12-col grid to two even columns so widgets stay
   aligned instead of squeezing. */
@media (max-width: 960px) {
  .filters-panel { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .filters-panel .field, .filters-panel .field-wide { grid-column: auto; }
}

.tabcontent { display: none; }
.tabcontent h3 { color: white; font-size: 1rem; font-weight: 600; margin-bottom: 0.25rem; }
.tabcontent .chart-description { font-size: 0.8125rem; color: var(--text-dim); margin-bottom: 1rem; }
/* STA-2324: unit caption in the panel header (e.g. "minutes / day"). */
.chart-unit { font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.6875rem;
  letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-faint); margin-left: 0.5rem; }
/* STA-2324: "Top N of {total}" caption on the two ranking charts. Empty until
   the chart's fetch resolves, so no leading separator when it has no text. */
.chart-count { font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.6875rem;
  letter-spacing: 0.05em; color: var(--accent); margin-left: 0.5rem; }
.chart-count:empty { margin-left: 0; }
.tabcontent canvas { max-width: 100%; border-radius: var(--radius-lg); }
/* STA-2324: fixed-height wrapper for the restyled charts (maintainAspectRatio:false). */
.chart-panel { position: relative; height: 392px; margin-top: 0.5rem; }
/* STA-2324: bound the At-Risk lists so a long roster scrolls instead of pushing
   the page. Inherits the global themed scrollbar; dark border + radius tokens. */
.atrisk-scroll { max-height: 22rem; overflow-y: auto; border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 0.25rem 0.75rem; }
.atrisk-scroll ul { margin: 0; }

.analytics-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}
.analytics-filters label {
  font-size: 0.75rem;
  color: var(--text-dim);
  font-weight: 500;
}
.analytics-filters input[type="date"] {
  padding: 0.375rem 0.75rem;
  background: var(--bg-body);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-lg);
  color: var(--text-body);
  font-size: 0.8125rem;
  font-family: inherit;
  outline: none;
}
.analytics-filters input[type="date"]:focus {
  border-color: rgba(249,115,22,0.5);
  box-shadow: 0 0 0 2px rgba(249,115,22,0.15);
}
.analytics-filters input[type="date"]::-webkit-calendar-picker-indicator { filter: invert(0.7); }

/* Select2 dark theme overrides */
.select2-container--default .select2-selection--multiple,
.select2-container--default .select2-selection--single {
  background: var(--bg-body) !important;
  border: 1px solid var(--border-light) !important;
  border-radius: var(--radius-lg) !important;
  min-height: 2.25rem !important;
  color: var(--text-body) !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice {
  background: var(--bg-card) !important;
  border: 1px solid var(--border-light) !important;
  color: var(--text-muted) !important;
  border-radius: var(--radius-sm) !important;
  font-size: 0.75rem !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
  color: var(--text-dim) !important;
}
.select2-container--default .select2-selection--multiple .select2-search__field {
  color: var(--text-body) !important;
}
.select2-container--default .select2-selection--multiple .select2-search__field::placeholder {
  color: var(--text-faint) !important;
}
.select2-dropdown {
  background: var(--bg-card) !important;
  border: 1px solid var(--border-light) !important;
  z-index: 9999 !important;
}
.select2-results__option {
  color: var(--text-muted) !important;
  font-size: 0.8125rem !important;
}
/* STA-2324: an already-selected result defaults to a light gray bg in select2 4.1 —
   override to dark so the chosen item isn't gray-on-light-gray. Above --highlighted
   so the orange hover still wins. */
.select2-results__option--selected,
.select2-container--default .select2-results__option[aria-selected="true"] {
  background: var(--bg-input) !important;
  color: var(--text-body) !important;
}
.select2-results__option--highlighted[aria-selected] {
  background: rgba(249,115,22,0.15) !important;
  color: white !important;
}
.select2-container--default .select2-search--dropdown .select2-search__field {
  background: var(--bg-body) !important;
  border: 1px solid var(--border-light) !important;
  color: var(--text-body) !important;
  border-radius: var(--radius-sm) !important;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
  color: var(--text-body) !important;
}
.select2-container--default .select2-selection--single .select2-selection__arrow b {
  border-color: var(--text-dim) transparent transparent transparent !important;
}

/* Analytics modals */
.custom-modal {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.6);
  z-index: 100;
  align-items: center;
  justify-content: center;
}
.custom-modal-content {
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-xl);
  padding: 1.5rem;
  max-width: 32rem;
  width: 90%;
  position: relative;
  color: var(--text-body);
}
.custom-modal-content h3 { color: white; }
.custom-modal-close {
  position: absolute;
  top: 0.75rem;
  right: 1rem;
  font-size: 1.25rem;
  cursor: pointer;
  color: var(--text-dim);
}
.custom-modal-close:hover { color: white; }
.modal-row {
  margin-bottom: 0.75rem;
}
.modal-row label {
  display: block;
  font-size: 0.75rem;
  color: var(--text-dim);
  margin-bottom: 0.25rem;
}
.modal-row input[type="date"] {
  padding: 0.375rem 0.75rem;
  background: var(--bg-body);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-lg);
  color: var(--text-body);
  font-size: 0.8125rem;
  font-family: inherit;
}

/* Chart.js tooltip dark theme (via canvas — handled by JS config) */
/* At-risk lists */
.tabcontent ul { list-style: none; padding: 0; }
.tabcontent ul li {
  padding: 0.375rem 0;
  font-size: 0.8125rem;
  color: var(--text-muted);
  border-bottom: 1px solid rgba(255,255,255,0.03);
}

/* ── Licensing sub-nav ──────────────────────────────────── */
.license-subnav {
  display: flex;
  gap: 0;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--border);
}
.license-subnav a {
  padding: 0.625rem 1rem;
  font-size: 0.8125rem;
  color: var(--text-dim);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  transition: color 0.15s, border-color 0.15s;
}
.license-subnav a:hover { color: var(--text-muted); }
.license-subnav a.active { color: var(--accent); border-bottom-color: var(--accent); }

/* ── Checkbox grid (license forms) ─────────────────────── */
.checkbox-grid ul,
.checkbox-grid > div {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.375rem;
}
.checkbox-grid li,
.checkbox-grid > div > div { margin: 0; }
.checkbox-grid li label,
.checkbox-grid > div > div label {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 0.875rem;
  color: var(--text-muted);
  margin-bottom: 0;
  cursor: pointer;
}
.checkbox-grid input[type="checkbox"] { accent-color: var(--accent); width: 1rem; height: 1rem; }
@media (max-width: 1200px) {
  .checkbox-grid ul,
  .checkbox-grid > div { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 900px) {
  .checkbox-grid ul,
  .checkbox-grid > div { grid-template-columns: repeat(2, 1fr); }
}

/* ── Flag grid (feature flags form) ────────────────────── */
.flag-grid { display: grid; grid-template-columns: 1fr; gap: 0.5rem; }
.flag-grid .flag-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: var(--text-muted);
}
.flag-grid .flag-item label {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin: 0;
  cursor: pointer;
}
.flag-grid .flag-hint { font-size: 0.75rem; color: var(--text-dim); }

/* ── Detail grid (license detail page) ─────────────────── */
.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
  gap: 1rem;
}
.detail-card {
  background: var(--bg-body);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.25rem;
}
.detail-card h4 {
  color: white;
  font-size: 0.8125rem;
  font-weight: 600;
  margin-bottom: 0.75rem;
}
.detail-card ul {
  list-style: none;
  padding: 0;
  margin: 0;
}
.detail-card ul li {
  font-size: 0.8125rem;
  color: var(--text-muted);
  padding: 0.25rem 0;
}
.detail-card .detail-empty { color: var(--text-dim); font-style: italic; }

/* ── 403 page ───────────────────────────────────────────── */
.error-page {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  min-height: 100vh;
  background: var(--bg-body);
  text-align: center;
  gap: 1rem;
}
.error-page h1 { font-size: 4rem; color: var(--accent); font-weight: 700; }
.error-page p  { color: var(--text-dim); font-size: 1rem; }

/* ── Content Upload ────────────────────────────────────── */
.upload-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
}
@media (max-width: 1024px) {
  .upload-layout { grid-template-columns: 1fr; }
}

.upload-dropzone {
  border: 2px dashed var(--border-light);
  border-radius: var(--radius-lg);
  padding: 3rem 2rem;
  text-align: center;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}
.upload-dropzone:hover,
.upload-dropzone.dragover {
  border-color: var(--accent);
  background: rgba(249, 115, 22, 0.05);
}
.dropzone-icon {
  width: 3rem; height: 3rem;
  color: var(--text-dim);
  margin: 0 auto 1rem;
  display: block;
}
.upload-dropzone.dragover .dropzone-icon { color: var(--accent); }
/* UX-051: visible indicator on the dropzone itself for an invalid (non-.zip)
   file drop, not just the far-below upload-result text. */
.upload-dropzone.dropzone-error {
  border-color: var(--red);
  background: rgba(239, 68, 68, 0.05);
}
.upload-dropzone.dropzone-error .dropzone-icon { color: var(--red); }
.dropzone-text {
  color: var(--text-muted);
  font-size: 0.9375rem;
}
.dropzone-browse {
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}
.dropzone-hint {
  color: var(--text-dim);
  font-size: 0.8125rem;
  margin-top: 0.5rem;
}

.upload-file-info {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem;
  background: var(--bg-body);
  border-radius: var(--radius);
  border: 1px solid var(--border-light);
}
.file-icon { color: var(--accent); flex-shrink: 0; }
.file-details { flex: 1; min-width: 0; }
.file-name {
  color: var(--text-primary);
  font-weight: 500;
  font-size: 0.9375rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.file-size { color: var(--text-dim); font-size: 0.8125rem; }

.upload-progress { margin-top: 1rem; }
.progress-bar {
  width: 100%; height: 6px;
  background: var(--bg-body);
  border-radius: 3px;
  overflow: hidden;
}
.progress-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
  transition: width 0.3s ease;
  width: 0%;
}
.progress-text {
  color: var(--text-muted);
  font-size: 0.8125rem;
  margin-top: 0.375rem;
}

.upload-result {
  margin-top: 1rem;
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  font-size: 0.875rem;
}
.upload-result-success {
  background: rgba(34, 197, 94, 0.1);
  color: var(--green);
  border: 1px solid rgba(34, 197, 94, 0.2);
}
.upload-result-error {
  background: rgba(239, 68, 68, 0.1);
  color: var(--red);
  border: 1px solid rgba(239, 68, 68, 0.2);
}

.info-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}
@media (max-width: 768px) {
  .info-grid { grid-template-columns: 1fr; }
}
.info-item { }
.info-label {
  color: var(--text-primary);
  font-weight: 600;
  font-size: 0.875rem;
  margin-bottom: 0.25rem;
}
.info-desc {
  color: var(--text-muted);
  font-size: 0.8125rem;
  line-height: 1.5;
}
.info-desc code {
  background: var(--bg-body);
  padding: 0.125rem 0.375rem;
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
  color: var(--accent);
}
.text-mono { font-family: 'SF Mono', 'Fira Code', monospace; font-size: 0.8125rem; }
.badge-purple { background: rgba(168, 85, 247, 0.15); color: var(--purple); }
.badge-blue { background: rgba(59, 130, 246, 0.15); color: var(--blue); }
