/* IT Asset Inventory — styles */

:root {
  --bg:        #f5f6f8;
  --surface:   #ffffff;
  --ink:       #1a1d23;
  --ink-soft:  #4a5160;
  --muted:     #7b8494;
  --line:      #e3e6ec;
  --line-2:    #d7dbe3;
  /* House accent, shared across the Desk apps. Change these four values to
     rebrand; everything below refers to them rather than to a literal hex. */
  --app-accent:       #1d4ed8;
  --app-accent-hover: #1e40af;
  --app-accent-light: #5aa9ef;
  --app-gold:         #d8b35c;
  --primary:   var(--app-accent);
  --primary-h: var(--app-accent-hover);
  --danger:    #c0392b;
  --danger-h:  #9a2d22;
  --ok:        #1d8a5f;
  --warn:      #c98200;
  --radius:    6px;
  --shadow-sm: 0 1px 2px rgba(12,18,32,0.05);
  --shadow:    0 2px 6px rgba(12,18,32,0.07), 0 1px 2px rgba(12,18,32,0.05);
  --font-sans: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.45;
}
a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }
code { font-family: var(--font-mono); font-size: 0.92em; }

/* ══════════════════════════════════════════════════════════════════════
   Sidebar navigation (always visible, collapsible)
   ══════════════════════════════════════════════════════════════════════ */

:root {
  --sb-width: 240px;
  --sb-collapsed-width: 60px;
  --sb-bg: #14181f;
  --sb-bg-dark: #0f1319;
  --sb-fg: #c9d0db;
  --sb-fg-dim: #8892a2;
  --sb-fg-strong: #ffffff;
  --sb-border: #0a0d12;
  --sb-hover: #222733;
  --sb-active-bg: rgba(90, 169, 239, 0.16);
  --sb-active-border: var(--app-accent-light);
  --sb-accent: var(--app-accent-light);
  --sb-transition: 220ms cubic-bezier(0.4, 0, 0.2, 1);
}

.sidebar {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: var(--sb-width);
  background: var(--sb-bg);
  color: var(--sb-fg);
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--sb-border);
  z-index: 50;
  transition: width var(--sb-transition);
  overflow: hidden;
}
html.sb-collapsed .sidebar { width: var(--sb-collapsed-width); }

/* Header (brand + toggle) */
.sb-header {
  padding: 12px 12px 12px 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  border-bottom: 1px solid var(--sb-border);
  min-height: 62px;
}
.sb-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
  color: var(--sb-fg-strong);
  text-decoration: none;
  font-weight: 600;
}
.sb-brand:hover { text-decoration: none; }
.sb-logo {
  width: 36px;
  height: 36px;
  border-radius: 6px;
  object-fit: contain;
  background: rgba(255, 255, 255, 0.08);
  flex-shrink: 0;
}
.sb-logo-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.5px;
}
.sb-brand-text {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
  min-width: 0;
  transition: opacity var(--sb-transition);
}
.sb-brand-title {
  font-weight: 600;
  font-size: 14px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 195px;
}
.sb-brand-subtitle {
  font-size: 11px;
  color: var(--sb-fg-dim);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sb-toggle {
  background: transparent;
  border: 1px solid transparent;
  color: var(--sb-fg);
  cursor: pointer;
  padding: 6px;
  border-radius: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background 0.15s, transform var(--sb-transition);
  position: relative;
  z-index: 2;
}
.sb-toggle:hover {
  background: var(--sb-hover);
  color: var(--sb-fg-strong);
}
html.sb-collapsed .sb-toggle-icon {
  transform: rotate(180deg);
}
.sb-toggle-icon {
  transition: transform var(--sb-transition);
}

/* Nav body */
.sb-nav {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 10px 0 16px;
  /* thin scrollbar */
  scrollbar-width: thin;
  scrollbar-color: #2a313d transparent;
}
.sb-nav::-webkit-scrollbar { width: 6px; }
.sb-nav::-webkit-scrollbar-thumb { background: #2a313d; border-radius: 3px; }
.sb-nav::-webkit-scrollbar-track { background: transparent; }

.sb-section-head {
  padding: 14px 20px 6px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--sb-fg-dim);
  white-space: nowrap;
  overflow: hidden;
}
.sb-section-head span {
  transition: opacity var(--sb-transition);
}

.sb-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 20px;
  color: var(--sb-fg);
  text-decoration: none;
  font-size: 14px;
  border-left: 3px solid transparent;
  white-space: nowrap;
  overflow: hidden;
  transition: background 0.12s ease;
}
.sb-item:hover {
  background: var(--sb-hover);
  color: var(--sb-fg-strong);
  text-decoration: none;
}
.sb-item.active {
  background: var(--sb-active-bg);
  border-left-color: var(--sb-active-border);
  color: var(--sb-fg-strong);
  font-weight: 500;
}
.sb-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  stroke-width: 2;
}
.sb-label {
  transition: opacity var(--sb-transition);
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Footer (user + signout) */
.sb-footer {
  border-top: 1px solid var(--sb-border);
  padding: 8px 0;
  background: var(--sb-bg-dark);
}
.sb-user, .sb-signout {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 20px;
  color: var(--sb-fg);
  text-decoration: none;
  font-size: 14px;
  white-space: nowrap;
  overflow: hidden;
}
.sb-user:hover, .sb-signout:hover {
  background: var(--sb-hover);
  color: var(--sb-fg-strong);
  text-decoration: none;
}
.sb-user-text {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
  min-width: 0;
  transition: opacity var(--sb-transition);
}
.sb-user-name {
  font-weight: 600;
  font-size: 13px;
  color: var(--sb-fg-strong);
  overflow: hidden;
  text-overflow: ellipsis;
}
.sb-user-role {
  font-size: 10px;
  color: var(--sb-fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-top: 2px;
}

/* Collapsed state — hide text, keep icons */
html.sb-collapsed .sb-brand-text,
html.sb-collapsed .sb-section-head span,
html.sb-collapsed .sb-label,
html.sb-collapsed .sb-user-text {
  opacity: 0;
  pointer-events: none;
}
html.sb-collapsed .sb-section-head {
  padding: 10px 0 4px;
  text-align: center;
}
html.sb-collapsed .sb-section-head::after {
  content: "";
  display: block;
  width: 24px;
  height: 1px;
  background: rgba(255, 255, 255, 0.1);
  margin: 0 auto;
}
html.sb-collapsed .sb-item,
html.sb-collapsed .sb-user,
html.sb-collapsed .sb-signout {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
}
html.sb-collapsed .sb-header {
  padding: 12px 6px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
html.sb-collapsed .sb-brand {
  flex: 0 0 auto;
  width: 100%;
  justify-content: center;
  gap: 0;
}
html.sb-collapsed .sb-brand-text {
  width: 0;
  overflow: hidden;
}
html.sb-collapsed .sb-toggle {
  margin: 0 auto;
}

/* App shell — everything non-sidebar lives here */
.app-shell {
  margin-left: var(--sb-width);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  transition: margin-left var(--sb-transition);
}
html.sb-collapsed .app-shell {
  margin-left: var(--sb-collapsed-width);
}
.app-shell > main.container {
  flex: 1;
}

/* Footer row: prefs button + signout button side-by-side */
.sb-footer-row {
  display: flex;
  gap: 0;
}
.sb-footer-row > * { flex: 1; min-width: 0; }
.sb-prefs-btn {
  background: transparent;
  border: none;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 20px;
  color: var(--sb-fg);
  font-size: 14px;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  font-family: inherit;
}
.sb-prefs-btn:hover {
  background: var(--sb-hover);
  color: var(--sb-fg-strong);
}

/* When collapsed, stack the prefs button over signout (they don't fit side-by-side) */
html.sb-collapsed .sb-footer-row {
  flex-direction: column;
}

/* Preferences popup */
.sb-prefs-popup {
  position: absolute;
  bottom: 100%;
  left: 10px;
  right: 10px;
  margin-bottom: 6px;
  background: #1a1f2a;
  border: 1px solid #2a313d;
  border-radius: 8px;
  padding: 14px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.4);
  z-index: 60;
}
.sb-prefs-popup[hidden] { display: none; }
.sb-prefs-title {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--sb-fg-dim);
  margin-bottom: 10px;
}
.sb-prefs-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  color: var(--sb-fg);
  font-size: 13px;
  cursor: pointer;
  line-height: 1.4;
}
.sb-prefs-row input[type="checkbox"] {
  margin-top: 3px;
  cursor: pointer;
  flex-shrink: 0;
}
.sb-prefs-text { display: flex; flex-direction: column; gap: 2px; }
.sb-prefs-label {
  color: var(--sb-fg-strong);
  font-weight: 500;
}
.sb-prefs-hint {
  color: var(--sb-fg-dim);
  font-size: 11px;
}
.sb-footer { position: relative; } /* anchor for popup positioning */

/* Hover-expand: only active when both collapsed AND preference enabled */
html.sb-collapsed.sb-hover-expand .sidebar:hover {
  width: var(--sb-width);
  box-shadow: 4px 0 24px rgba(0, 0, 0, 0.35);
}
/* Re-enable all labels during hover-expand */
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-brand-text,
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-section-head span,
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-label,
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-user-text {
  opacity: 1;
  pointer-events: auto;
}
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-brand {
  display: flex;
}
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-header {
  padding: 12px 12px 12px 16px;
  justify-content: flex-start;
}
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-toggle {
  margin: 0;
}
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-section-head {
  padding: 14px 20px 6px;
  text-align: left;
}
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-section-head::after {
  display: none;
}
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-item,
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-user,
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-signout,
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-prefs-btn {
  justify-content: flex-start;
  padding-left: 20px;
  padding-right: 20px;
}
html.sb-collapsed.sb-hover-expand .sidebar:hover .sb-footer-row {
  flex-direction: row;
}
/* Content area doesn't shift during hover-expand — sidebar overlays on top */
html.sb-collapsed.sb-hover-expand .app-shell {
  margin-left: var(--sb-collapsed-width);
}

/* Mobile: sidebar becomes slide-in overlay */
@media (max-width: 768px) {
  .sidebar {
    transform: translateX(-100%);
    transition: transform var(--sb-transition);
    width: var(--sb-width) !important;
  }
  html.sb-mobile-open .sidebar {
    transform: translateX(0);
    box-shadow: 4px 0 24px rgba(0,0,0,0.4);
  }
  html.sb-mobile-open::before {
    content: "";
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.5);
    z-index: 49;
  }
  .app-shell {
    margin-left: 0 !important;
  }
}

/* ── Flash ──────────────────────────────────────────────────────────── */
.flash {
  padding: 10px 16px; margin: 0;
  border-bottom: 1px solid var(--line);
  font-weight: 500;
}
.flash-success { background: #e7f5ee; color: #0d6e47; border-color: #bde4cf; }
.flash-error   { background: #fbe8e6; color: #8a2318; border-color: #f0c2bc; }

/* ── Layout ─────────────────────────────────────────────────────────── */
/* width: 100% is load-bearing. .app-shell is a flex column, so .container is
   a flex item; on the cross axis a flex item sizes to its CONTENT unless it
   stretches, and align-self resolves to auto here. Without an explicit width
   the container collapses to its content — which on the settings hub meant a
   537px grid in a 1860px shell, and one column instead of four. */
.container { max-width: 1200px; margin: 0 auto; padding: 24px; width: 100%; }

.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 12px 20px; flex-wrap: wrap;
  margin-bottom: 16px;
}
.page-head h1 { margin: 0; font-size: 22px; min-width: 0; }
.page-head .crumb {
  font-size: 12px;
  color: var(--muted);
  margin-bottom: 6px;
}
.page-head .crumb a,
.page-head .crumb a:link,
.page-head .crumb a:visited {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: #475569;
  background-color: #f1f5f9;
  border: 1px solid #e2e8f0;
  text-decoration: none;
  padding: 3px 10px 3px 8px;
  border-radius: 4px;
  font-weight: 500;
  transition: all 0.08s;
}
.page-head .crumb a:hover {
  background-color: #e2e8f0;
  border-color: #cbd5e1;
  color: #0f172a;
  text-decoration: none;
}
.page-actions { display: flex; gap: 8px; }

.foot {
  text-align: center;
  background: var(--app-accent);
  color: rgba(255, 255, 255, 0.78);
  font-size: 12px;
  padding: 14px 20px;
  border-radius: var(--radius);
  /* Inset like WiFiDesk's. Theirs is inset because the footer sits inside
     .container (max-width 1400px, auto margins); NetDesk's lives in
     .app-shell, outside any container, so it needs its own constraint —
     otherwise a 16px margin leaves it spanning the whole viewport. */
  max-width: 1400px;
  margin: 24px auto 32px;
  width: calc(100% - 32px);
}

/* ── Settings hub + generic section pages ───────────────────────────────────
   Card grid for the Settings landing, matching AssetDesk and WiFiDesk. Cards
   are links, not containers-with-buttons: the whole tile is the target. ───── */
.sec-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 14px;
}
.sec-card {
  display: block;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 18px 18px 16px;
  text-decoration: none;
  color: inherit;
  transition: border-color .12s, box-shadow .12s, transform .12s;
}
.sec-card:hover {
  border-color: var(--app-accent);
  box-shadow: var(--shadow);
  text-decoration: none;
  transform: translateY(-1px);
}
.sec-icon {
  width: 34px; height: 34px;
  border-radius: 8px;
  background: rgba(29, 78, 216, .10);
  color: var(--app-accent);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 12px;
}
.sec-name { font-size: 15px; font-weight: 600; margin: 0 0 4px; }
.sec-blurb { font-size: 13px; color: var(--muted); margin: 0; line-height: 1.5; }

/* Two columns at NetDesk's 1200px page width gives each field ~570px, which
   is enough for the label, the control and its help line. One column below
   720px — the width where two genuinely stop working. */
.set-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px 24px;
  align-items: start;
}
@media (max-width: 720px) { .set-grid { grid-template-columns: 1fr; } }

/* A textarea at half width is worse than one at full width, so multiline
   fields take the whole row. */
.set-row-wide { grid-column: 1 / -1; }

.set-row { padding: 0; min-width: 0; }
/* The row borders were there to separate full-width rows. In a grid they draw
   lines across the gaps, so spacing does the separating instead. */
.set-row-err {
  background: #fff7f7;
  border-radius: var(--radius);
  margin: -8px -10px;
  padding: 8px 10px;
}
.set-row > label { font-size: 13px; font-weight: 500; color: var(--ink-soft); }
.set-row input[type=text], .set-row input[type=number], .set-row textarea,
.set-row select { margin-top: 5px; }
.set-check { display: flex !important; flex-direction: row !important;
             align-items: center; gap: 9px; cursor: pointer; }
.set-check input { width: auto; margin: 0; }
.set-help { font-size: 12px; color: var(--muted); margin-top: 5px; }
.set-err  { font-size: 12px; color: var(--danger); margin-top: 5px; font-weight: 500; }
/* The actions bar now sits outside the cards, below the last one, because a
   grouped section is several cards under one form. */
.set-actions {
  margin: 4px 0 24px;
  display: flex; gap: 10px; align-items: center;
}

/* Login notices. The card itself is styled in the Auth block above. */
.auth-note {
  padding: 10px 12px; border-radius: var(--radius);
  font-size: 13px; font-weight: 500; margin: 0 0 14px; text-align: left;
}
.auth-note-warn { color: #854d0e; background: #fef9c3; }
.auth-note-err  { color: #991b1b; background: #fee2e2; }

/* ── Cards & grid ───────────────────────────────────────────────────── */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 16px;
  box-shadow: var(--shadow-sm);
}
.card h2 { margin: 0 0 12px 0; font-size: 15px; letter-spacing: 0.2px; }

.cards { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); margin-bottom: 16px; }
.stat .stat-label { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.6px; }
.stat .stat-value { font-size: 28px; font-weight: 700; margin-top: 2px; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 800px) { .grid-2 { grid-template-columns: 1fr; } }

/* ── Tables ─────────────────────────────────────────────────────────── */
.table { width: 100%; border-collapse: collapse; }
.table th, .table td {
  padding: 9px 10px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
.table th {
  font-weight: 600; font-size: 12px;
  text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--ink-soft); background: #fafbfc;
}
.table tbody tr:hover { background: #f8f9fb; }
.table td.right, .table th.right { text-align: right; }
.muted { color: var(--muted); }

/* Empty-state action links (e.g. "No X yet. Add one.") — styled as subtle
   buttons so they don't look like raw hyperlinks. */
td.muted a,
td.muted a:link,
td.muted a:visited {
  display: inline-block;
  padding: 2px 10px;
  margin-left: 4px;
  background-color: #eff6ff;
  border: 1px solid #bfdbfe;
  border-radius: 4px;
  color: #1e40af;
  text-decoration: none;
  font-weight: 500;
  transition: all 0.08s;
}
td.muted a:hover {
  background-color: #dbeafe;
  border-color: #93c5fd;
  text-decoration: none;
}

/* ── Status chips ───────────────────────────────────────────────────── */
.status {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.3px;
  border: 1px solid transparent;
}
.status.st-active     { background: #e7f5ee; color: #0d6e47; border-color: #bde4cf; }
.status.st-in-storage { background: #fff6dc; color: #7a5900; border-color: #f0df9e; }
.status.st-retired    { background: #eef0f4; color: #4a5160; border-color: #d7dbe3; }
.status.st-disposed   { background: #fbe8e6; color: #8a2318; border-color: #f0c2bc; }
.status.st-needs-verification { background: #e8effd; color: #1e40af; border-color: #bed0f5; }
.status.st-missing    { background: #fbe8e6; color: #8a2318; border-color: #f0c2bc; font-weight: 700 !important; }

/* ── Forms ──────────────────────────────────────────────────────────── */
.form-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(2, 1fr);
}
.form-grid .span-2 { grid-column: span 2; }
@media (max-width: 700px) {
  .form-grid { grid-template-columns: 1fr; }
  .form-grid .span-2 { grid-column: span 1; }
}
label { display: flex; flex-direction: column; gap: 5px; font-size: 13px; color: var(--ink-soft); font-weight: 500; }
input[type=text], input[type=email], input[type=password], input[type=date], input[type=file],
select, textarea {
  width: 100%;
  padding: 8px 10px;
  font: inherit;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  transition: border-color 0.15s, box-shadow 0.15s;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(43,95,217,0.15);
}
textarea { resize: vertical; font-family: var(--font-sans); }
.hint { color: var(--muted); font-size: 12px; font-weight: 400; }

/* Subtle inline link inside hint text — matches hint color, no chip.
   Underlines on hover to signal clickability without shouting. */
.hint a,
.hint a:link,
.hint a:visited {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: #cbd5e1;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.hint a:hover {
  color: var(--text, #0f172a);
  text-decoration-color: currentColor;
}

.filters {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  padding: 12px 16px;
}
.filters input[type=text] { flex: 1 1 260px; }
.filters select { flex: 0 0 auto; }

.form-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 6px; }

/* ── Buttons ────────────────────────────────────────────────────────── */
.btn {
  display: inline-block;
  padding: 7px 14px;
  font: inherit; font-weight: 500;
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.btn:hover { background: #f1f3f7; text-decoration: none; }
.btn-primary {
  background: var(--primary); color: #fff; border-color: var(--primary);
}
.btn-primary:hover { background: var(--primary-h); border-color: var(--primary-h); color: #fff; }
.btn-danger {
  background: var(--danger); color: #fff; border-color: var(--danger);
}
.btn-danger:hover { background: var(--danger-h); border-color: var(--danger-h); color: #fff; }
.btn-ghost { background: transparent; }
.btn-block { width: 100%; }

/* ── Detail grid ────────────────────────────────────────────────────── */
.detail-grid {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px 24px;
}
.detail-grid .span-2 { grid-column: span 2; }
.detail-grid dt {
  color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px;
  margin: 0 0 2px 0;
}
.detail-grid dd { margin: 0; font-size: 14px; }

/* ── Auth ───────────────────────────────────────────────────────────────────
   Layout follows WiFiDesk: the brand sits inside the card as a coloured strip
   rather than a banner floating above it, so the whole thing reads as one
   object and the branding stays on screen on a phone. overflow:hidden is what
   lets the strip meet the card edges — no negative margins to keep in sync
   with the padding. ───────────────────────────────────────────────────────── */
.auth-wrap {
  padding: 56px 20px 20px;
  display: flex; align-items: flex-start; justify-content: center;
}
.auth-card {
  width: 100%; max-width: 400px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--shadow);
}
.auth-brand {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  background: var(--app-accent);
  padding: 26px 20px 22px;
}
.auth-logo {
  width: 54px; height: 54px; object-fit: contain; border-radius: 50%;
  background: rgba(255, 255, 255, .14); padding: 4px;
}
.auth-logo-placeholder {
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 22px; font-weight: 700;
}
.auth-brand-title { font-size: 22px; font-weight: 700; }
.auth-brand-sub { font-size: 13px; color: rgba(255, 255, 255, .82); }
.auth-body { padding: 26px 28px 28px; }
.auth-card h1 { margin: 0 0 4px; font-size: 19px; }
.auth-card .auth-sub { color: var(--muted); font-size: 13px; margin: 0 0 20px; }
.auth-field { margin-bottom: 14px; }

/* Confirm-link page: the facts being agreed to, laid out so they are read
   rather than skimmed past. */
.link-facts { margin: 0 0 18px; }
.link-facts dt {
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); margin-top: 12px;
}
.link-facts dt:first-child { margin-top: 0; }
.link-facts dd {
  margin: 3px 0 0; font-size: 14px; color: var(--ink);
  overflow-wrap: anywhere;
}
.link-facts dd .badge { margin-left: 6px; vertical-align: middle; }

/* Entra SSO: the divider and button are styled now so the markup can land
   whole when the route exists, rather than being retrofitted later. */
.sso-divider {
  display: flex; align-items: center; gap: 12px;
  margin: 20px 0 4px;
  color: var(--muted); font-size: 11px;
  text-transform: uppercase; letter-spacing: .07em;
}
.sso-divider::before, .sso-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}
.btn-microsoft {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; padding: 11px 16px;
  border: 1px solid var(--line-2); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
  font-size: 14px; font-weight: 600; text-decoration: none;
}
.btn-microsoft:hover {
  background: #f1f3f7; border-color: var(--muted); text-decoration: none;
}
.ms-logo {
  display: grid; grid-template-columns: 9px 9px; grid-template-rows: 9px 9px;
  gap: 2px; flex-shrink: 0;
}
.ms-logo span { display: block; width: 9px; height: 9px; }
.ms-q1 { background: #f25022; }
.ms-q2 { background: #7fba00; }
.ms-q3 { background: #00a4ef; }
.ms-q4 { background: #ffb900; }

/* Logged-out pages (login, etc.) have no sidebar — don't reserve space for one.
   Also remove the flex-stretch so the footer sits naturally below the login
   card instead of being pinned to the viewport bottom with a huge empty gap. */
body.no-sidebar .app-shell {
  margin-left: 0 !important;
  min-height: 0;
}
body.no-sidebar .app-shell > main.container {
  flex: 0 0 auto;
}
body.no-sidebar .foot {
  padding: 16px 0;
}

/* ── Misc ───────────────────────────────────────────────────────────── */
.chips { list-style: none; padding: 0; margin: 8px 0 14px; display: flex; gap: 6px; flex-wrap: wrap; }
.chips li code {
  display: inline-block; padding: 3px 8px; background: #f1f3f7;
  border: 1px solid var(--line-2); border-radius: 4px;
}
.err-list { color: var(--danger); font-family: var(--font-mono); font-size: 12px; }

/* ── Phase 2 additions ─────────────────────────────────────────────── */
.u-link {
  font-weight: 600; color: #fff; text-decoration: none;
  padding: 4px 8px; border-radius: 4px;
}
.u-link:hover { background: #222733; text-decoration: none; }

/* Generic pager (used on audit page etc.) */
.pager {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
  margin: 12px 0 4px;
}

/* Pager bar — wraps the per-page dropdown + hybrid pagination on the assets list */
.pager-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  margin: 14px 0 4px;
  flex-wrap: wrap;
}
.pager-bar .pager {
  /* Override generic .pager: right-aligned, tight spacing for numbered pager */
  justify-content: flex-end;
  gap: 2px;
  margin: 0;
}
.pager-perpage {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
}
.pager-perpage select {
  padding: 4px 8px;
  font-size: 13px;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 4px;
  background: #fff;
}

.page-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 34px;
  padding: 0 10px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink, #0f172a);
  background: #fff;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 4px;
  text-decoration: none;
  transition: background-color 0.08s, border-color 0.08s;
}
.page-btn:hover {
  background: #f8fafc;
  border-color: #cbd5e1;
  text-decoration: none;
}
.page-btn.page-current {
  background: var(--primary, #2563eb);
  border-color: var(--primary, #2563eb);
  color: #fff;
  cursor: default;
}
.page-btn.page-current:hover {
  background: var(--primary, #2563eb);
}
.page-btn.disabled {
  color: #cbd5e1;
  background: #f8fafc;
  cursor: not-allowed;
  pointer-events: none;
}
.page-ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 34px;
  color: #94a3b8;
  user-select: none;
}

/* Keyboard shortcut hint below the pager */
.pager-hint {
  margin: 8px 0 0 0;
  text-align: right;
  font-size: 11px;
}
.pager-hint kbd {
  display: inline-block;
  padding: 1px 6px;
  margin: 0 1px;
  font-family: var(--mono, ui-monospace, "SF Mono", Consolas, monospace);
  font-size: 11px;
  color: #475569;
  background: #f8fafc;
  border: 1px solid #cbd5e1;
  border-bottom-width: 2px;
  border-radius: 3px;
  line-height: 1;
}

/* ── Overview dashboard (reports/overview) ─────────────────────────── */

.overview-header {
  background: linear-gradient(135deg, #4c1d95, #6d28d9);
  color: #fff;
  padding: 16px 20px;
  border-radius: 10px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: 16px;
  margin-bottom: 18px;
}
.overview-title h1 {
  color: #fff;
  margin: 0;
  font-size: 22px;
}
.overview-title .crumb {
  font-size: 12px;
  margin-bottom: 6px;
}
.overview-title .crumb a,
.overview-title .crumb a:link,
.overview-title .crumb a:visited {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: #f5f3ff;
  background-color: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.18);
  text-decoration: none;
  padding: 3px 10px 3px 8px;
  border-radius: 4px;
  font-weight: 500;
  transition: all 0.08s;
}
.overview-title .crumb a:hover {
  background-color: rgba(255, 255, 255, 0.22);
  border-color: rgba(255, 255, 255, 0.32);
  color: #ffffff;
  text-decoration: none;
}

.overview-slicers {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-end;
}
.slicer {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.slicer span {
  font-size: 11px;
  color: #ddd6fe;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.slicer select {
  padding: 6px 10px;
  font-size: 13px;
  min-width: 160px;
  border: 1px solid rgba(255,255,255,0.3);
  border-radius: 4px;
  background: rgba(255,255,255,0.95);
  color: #0f172a;
}
.overview-header .btn-ghost {
  background: rgba(255,255,255,0.15);
  color: #fff;
  border: 1px solid rgba(255,255,255,0.25);
}
.overview-header .btn-ghost:hover {
  background: rgba(255,255,255,0.25);
}

.kpi-row {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 10px;
  margin-bottom: 16px;
}
.kpi-card {
  background: #fff;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 8px;
  padding: 12px 14px;
}
/* Clickable KPI tile — used when the KPI can drill into a filtered list.
   Keeps the same visual resting state as a regular .kpi-card but adds a
   hover affordance: border tints, shadow lifts, and the KPI label briefly
   gains an arrow glyph. Uses <a> as the root so the whole tile is a
   single tap/click target (better than just linking the number). */
.kpi-card-clickable {
  display: block;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: border-color 0.12s, box-shadow 0.12s, transform 0.12s;
  position: relative;
}
.kpi-card-clickable:hover {
  border-color: #93c5fd;
  box-shadow: 0 2px 8px rgba(37, 99, 235, 0.12);
  text-decoration: none;
}
.kpi-card-clickable::after {
  content: "→";
  position: absolute;
  top: 10px;
  right: 12px;
  color: var(--muted, #94a3b8);
  font-size: 14px;
  font-weight: 400;
  opacity: 0.5;
  transition: opacity 0.12s, transform 0.12s;
}
.kpi-card-clickable:hover::after {
  opacity: 1;
  color: #2563eb;
  transform: translateX(2px);
}
.kpi-label {
  font-size: 11px;
  color: var(--muted, #64748b);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 500;
  margin-bottom: 6px;
}
.kpi-value {
  font-size: 26px;
  font-weight: 700;
  color: #0f172a;
  line-height: 1.1;
}
.kpi-sub {
  font-size: 11px;
  color: var(--muted, #64748b);
  margin-top: 4px;
}

@media (max-width: 1100px) {
  .kpi-row { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 640px) {
  .kpi-row { grid-template-columns: repeat(2, 1fr); }
}

.chart-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-bottom: 12px;
}
.chart-card { padding: 14px; }
.chart-card h3 {
  margin: 0 0 10px 0;
  font-size: 14px;
  font-weight: 600;
  color: #0f172a;
}
.chart-wrap {
  position: relative;
  height: 260px;
}

@media (max-width: 900px) {
  .chart-row { grid-template-columns: 1fr; }
  .chart-wrap { height: 240px; }
}

/* Featured report card — slightly more prominent */
.report-card-featured {
  border: 2px solid #6d28d9;
  background: linear-gradient(135deg, #faf5ff, #f5f3ff);
}
.report-card-featured h2 { color: #6d28d9; }

.inline-form { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.inline-form input[type=password] {
  padding: 4px 8px !important;
  font-size: 12px;
}

.inline-check {
  display: inline-flex; flex-direction: row !important; align-items: center;
  gap: 4px; font-size: 11px; color: var(--ink-soft); font-weight: 500;
  white-space: nowrap;
}
.inline-check input[type=checkbox] { margin: 0; }

.checkbox-row {
  flex-direction: row !important; align-items: center; gap: 10px;
  flex-wrap: wrap;
}
.checkbox-row input[type=checkbox] {
  width: auto; margin: 0;
}
.checkbox-row > span {
  font-weight: 500; color: var(--ink);
}
.checkbox-row .hint { flex-basis: 100%; }

/* ── Tabs (vendors page) ───────────────────────────────────────────── */
.tabs {
  display: flex; gap: 2px; margin-bottom: 12px;
  border-bottom: 1px solid var(--line-2);
}
.tabs .tab {
  padding: 8px 14px;
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  font-weight: 500; font-size: 13px;
  margin-bottom: -1px;
}
.tabs .tab:hover { color: var(--ink); text-decoration: none; }
.tabs .tab.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
}

/* ── Dashboard sections ────────────────────────────────────────────── */
.section-title {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--muted);
  margin: 24px 0 10px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--line-2);
}
.section-title:first-of-type { margin-top: 8px; }

.stat-sub { font-size: 14px; color: var(--muted); font-weight: 500; }
.stat-warn { color: var(--warn); }

/* Stat card tints — applied to the whole card to draw attention when
   there's something worth attending to. Subtle, not alarming. */
.stat.stat-tint-warn {
  background: #fffbeb;
  border-color: #fde68a;
}
.stat.stat-tint-warn .stat-value { color: #b45309; }

.stat.stat-tint-danger {
  background: #fef2f2;
  border-color: #fecaca;
}
.stat.stat-tint-danger .stat-value { color: #b91c1c; }

.stat.stat-tint-ok {
  background: #f0fdf4;
  border-color: #bbf7d0;
}
.stat.stat-tint-ok .stat-value { color: #15803d; }

.seat-bar {
  margin-top: 8px;
  height: 6px;
  background: #eef0f4;
  border-radius: 999px;
  overflow: hidden;
}
.seat-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--primary), #5a8ef0);
  transition: width 0.3s, background 0.3s;
}
/* Conditional colour based on utilisation — green < 80, amber 80-95, red >= 95 */
.seat-bar-fill.seat-warn {
  background: linear-gradient(90deg, #d97706, #f59e0b);
}
.seat-bar-fill.seat-danger {
  background: linear-gradient(90deg, #b91c1c, #ef4444);
}
.seat-bar-fill.seat-ok {
  background: linear-gradient(90deg, #15803d, #22c55e);
}

/* ── Phase 4 additions ─────────────────────────────────────────────── */

/* Stat card color tints for each status */
.stat.stat-needs-verification {
  background: #e8effd; border-color: #bed0f5;
}
.stat.stat-needs-verification .stat-label { color: #1e40af; }
.stat.stat-needs-verification .stat-value { color: #1e40af; }

.stat.stat-missing {
  background: #fbe8e6; border-color: #f0c2bc;
}
.stat.stat-missing .stat-label { color: #8a2318; }
.stat.stat-missing .stat-value { color: #8a2318; }

.stat.stat-in-storage {
  background: #fff6dc; border-color: #f0df9e;
}
.stat.stat-in-storage .stat-label { color: #7a5900; }

.stat.stat-active {
  background: #e7f5ee; border-color: #bde4cf;
}
.stat.stat-active .stat-label { color: #0d6e47; }

/* Verification progress card */
.progress-card { padding: 14px 18px; margin-bottom: 16px; }
.progress-header {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 10px;
}
.progress-stats { color: var(--ink-soft); font-size: 13px; }
.progress-stats strong { color: var(--ink); }
.progress-bar {
  height: 10px; background: #eef0f4; border-radius: 999px; overflow: hidden;
}
.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #10b981, #34d399);
  transition: width 0.4s;
}
.progress-hint { margin-top: 8px; font-size: 13px; }

/* Total row in entity value table */
.total-row td {
  border-top: 2px solid var(--line-2);
  background: #fafbfc;
}

/* Asset list — sort links */
.sort-link {
  color: inherit; text-decoration: none;
  display: inline-block; white-space: nowrap;
}
.sort-link:hover { color: var(--primary); text-decoration: none; }
.sort-link.active { color: var(--primary); }
.sort-arrow { font-size: 10px; margin-left: 2px; }

/* Bulk toolbar */
.bulk-toolbar {
  background: #1e40af;
  color: #fff;
  padding: 10px 16px;
  border-radius: var(--radius);
  margin-bottom: 12px;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.bulk-toolbar .bulk-count { flex-shrink: 0; }
.bulk-toolbar .bulk-actions {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.bulk-toolbar select, .bulk-toolbar input[type=text] {
  padding: 4px 8px; font-size: 13px;
}
.bulk-toolbar .divider {
  width: 1px; height: 24px; background: rgba(255,255,255,0.3);
  margin: 0 4px;
}

/* Quick action bar on asset detail */
.quick-action-bar {
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin-bottom: 16px;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.quick-action-form {
  padding: 16px;
  border-left: 3px solid var(--primary);
  margin-bottom: 16px;
}
.quick-action-form h3 { margin: 0 0 12px; font-size: 14px; }

/* Section head (between card h2 and add-note button) */
.section-head {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 12px;
}

/* History timeline — scrollable when it gets long */
.timeline-scroll {
  max-height: 480px;
  overflow-y: auto;
  padding-right: 8px;
  /* Subtle visual cue that content is scrollable */
  background:
    linear-gradient(to bottom, #fff, transparent 4%),
    linear-gradient(to top, #fff, transparent 4%);
  background-attachment: local, local;
}
.timeline-scroll::-webkit-scrollbar        { width: 8px; }
.timeline-scroll::-webkit-scrollbar-track  { background: transparent; }
.timeline-scroll::-webkit-scrollbar-thumb  { background: var(--line-2); border-radius: 4px; }
.timeline-scroll::-webkit-scrollbar-thumb:hover { background: var(--muted); }

.timeline {
  list-style: none; padding: 0; margin: 0;
  border-left: 2px solid var(--line-2);
  margin-left: 6px;
}
.timeline-item {
  position: relative;
  padding: 14px 0 14px 20px;
  display: flex;
  gap: 18px;
  align-items: flex-start;
}
.timeline-item::before {
  content: '';
  position: absolute;
  left: -6px; top: 20px;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--muted);
  border: 2px solid #fff;
}
.timeline-verification::before { background: var(--ok); }
.timeline-status_change::before { background: var(--primary); }
.timeline-assignment_change::before { background: #b45309; }
.timeline-movement::before { background: #6b21a8; }
.timeline-note::before { background: var(--muted); }

/* The event date becomes the visual anchor — left column, big, bold */
.timeline-event-date {
  flex: 0 0 110px;
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  padding-top: 1px;
  letter-spacing: 0.3px;
}

.timeline-body {
  flex: 1;
  min-width: 0;
}
.timeline-head {
  display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
  margin-bottom: 4px;
}
.timeline-type {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
  background: #eef0f4; color: var(--ink-soft);
  padding: 2px 7px; border-radius: 4px; font-weight: 600;
}
.timeline-verification .timeline-type { background: #e7f5ee; color: #0d6e47; }
.timeline-status_change .timeline-type { background: #e8effd; color: #1e40af; }
.timeline-assignment_change .timeline-type { background: #fef3c7; color: #92400e; }
.timeline-movement .timeline-type { background: #f3e8ff; color: #6b21a8; }
.timeline-transition { font-size: 14px; color: var(--ink); }
.timeline-desc { margin-top: 4px; font-size: 13px; color: var(--ink); }
.timeline-meta { margin-top: 6px; font-size: 11px; }
.timeline-meta .logged-at { color: var(--muted); opacity: 0.75; }

.tiny { font-size: 11px; }

/* ── Phase 5 additions ─────────────────────────────────────────────── */
.pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  vertical-align: middle;
  margin-left: 6px;
}
.pill-cross   { background: #f3e8ff; color: #6b21a8; }
.pill-inactive { background: #eef0f4; color: var(--muted); }
.pill-primary { background: #dbeafe; color: #1e40af; }

/* Alias list on person detail page */
.alias-list {
  list-style: none;
  padding: 0;
  margin: 12px 0 0;
}
.alias-list li {
  padding: 6px 0;
  border-top: 1px solid var(--border);
}
.alias-list li:first-child { border-top: none; }
.alias-list code {
  background: #f8fafc;
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 13px;
}

/* Small button variant for inline actions */
.btn-small {
  padding: 3px 10px;
  font-size: 12px;
}

.muted-row td { color: var(--muted); }
.req { color: var(--danger); }
.inline-check { display: flex; align-items: center; gap: 8px; }
.inline-check input { width: auto; margin: 0; }

/* Phase 7: compact multi-column filter grid */
.filters-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  align-items: start;
}
.filters-grid .span-2 { grid-column: span 2; }
.filters-grid input,
.filters-grid select {
  width: 100%;
  margin: 0;
}
.filters-grid .filter-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  grid-column: span 4;
}
@media (max-width: 900px) {
  .filters-grid { grid-template-columns: repeat(2, 1fr); }
  .filters-grid .span-2 { grid-column: span 2; }
  .filters-grid .filter-actions { grid-column: span 2; }
}

.dupe-group {
  border-left: 3px solid var(--warn, #d97706);
  padding: 10px 14px;
  margin: 14px 0;
  background: #fffbeb;
  border-radius: 6px;
}
.dupe-group h3 {
  margin: 0 0 8px 0;
  font-size: 14px;
}
.btn.tiny {
  padding: 3px 8px;
  font-size: 11px;
}

.reports-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 14px;
  margin-top: 16px;
}
.report-card {
  display: block;
  text-decoration: none;
  color: inherit;
  transition: transform 0.08s, box-shadow 0.08s;
}
.report-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
  text-decoration: none;
}
.report-card h2 {
  margin-top: 0;
  margin-bottom: 6px;
  font-size: 16px;
}
.report-card p { margin: 0; font-size: 13px; }

/* Clickable table rows (dashboard drill-downs) */
.table-clickable tbody tr[onclick] {
  cursor: pointer;
  transition: background-color 0.08s;
}
.table-clickable tbody tr[onclick]:hover {
  background-color: #f1f5f9;
}
.table-clickable tbody tr[onclick]:active {
  background-color: #e2e8f0;
}
.table-clickable tbody tr.total-row {
  cursor: default;
}
.table-clickable tbody tr.total-row:hover {
  background: inherit;
}

/* Clickable stat cards */
.stat-link {
  display: block;
  text-decoration: none;
  color: inherit;
  transition: transform 0.08s, box-shadow 0.08s;
}
.stat-link:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
  text-decoration: none;
}

/* Scrollable table container — sticks the header while scrolling the rows */
.table-scroll {
  max-height: 60vh;
  overflow-y: auto;
  border-radius: 6px;
}
.table-scroll table { margin: 0; }
.table-scroll thead th {
  position: sticky;
  top: 0;
  background: var(--panel-bg, #f8fafc);
  z-index: 1;
  box-shadow: inset 0 -1px 0 var(--line, #e5e7eb);
}
/* Taller variant for list/working views like Assets where you want to see
   many rows at once. Keeps filters + bulk toolbar + pagination visible. */
.table-scroll.table-scroll-tall {
  max-height: 65vh;
}

/* Count pill — button-styled badge for asset counts on the right */
.count-pill {
  display: inline-block;
  min-width: 2.5em;
  padding: 3px 10px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.count-pill.count-zero {
  color: var(--muted, #94a3b8);
  background: transparent;
  border: 1px dashed var(--line, #e5e7eb);
  border-radius: 4px;
}

/* Bolder table headers for clearer visual hierarchy */
.table thead th {
  font-weight: 700;
  color: #0f172a;
}

/* Entity pill — consistent coloured badge for entity codes.
   Colour is deterministic based on the code, so BBTC always looks
   the same everywhere it appears. */
.entity-pill {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  font-family: var(--mono, ui-monospace, "SF Mono", Consolas, monospace);
  letter-spacing: 0.02em;
  line-height: 1.6;
  vertical-align: middle;
  white-space: nowrap;
  border: 1px solid transparent;
}
/* Ten distinct, readable hues. Each has a light background + dark text
   + subtle border. Assignment is by hash(code) % 10. */
.entity-pill.epc-0 { background: #dbeafe; color: #1e40af; border-color: #bfdbfe; }
.entity-pill.epc-1 { background: #dcfce7; color: #166534; border-color: #bbf7d0; }
.entity-pill.epc-2 { background: #fef3c7; color: #854d0e; border-color: #fde68a; }
.entity-pill.epc-3 { background: #f3e8ff; color: #6b21a8; border-color: #e9d5ff; }
.entity-pill.epc-4 { background: #ffe4e6; color: #9f1239; border-color: #fecdd3; }
.entity-pill.epc-5 { background: #cffafe; color: #155e75; border-color: #a5f3fc; }
.entity-pill.epc-6 { background: #ecfccb; color: #3f6212; border-color: #d9f99d; }
.entity-pill.epc-7 { background: #fed7aa; color: #9a3412; border-color: #fdba74; }
.entity-pill.epc-8 { background: #e0e7ff; color: #3730a3; border-color: #c7d2fe; }
.entity-pill.epc-9 { background: #fce7f3; color: #9d174d; border-color: #fbcfe8; }
.entity-pill.epc-unknown { background: #f1f5f9; color: #475569; border-color: #e2e8f0; }

/* Tag link — for asset tags / software tags / identifiers in lists.
   Rendered as a dark monospace identifier, NOT as a blue hyperlink.
   The hover state reveals it's clickable (background + subtle colour shift). */
a.tag-link,
a.tag-link:link,
a.tag-link:visited {
  text-decoration: none;
  color: #334155;                 /* slate-700 — dark, reads as data not link */
  font-family: var(--mono, ui-monospace, "SF Mono", Consolas, monospace);
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 4px;
  background-color: #f1f5f9;       /* slate-100 — subtle chip background */
  border: 1px solid transparent;
  transition: all 0.08s;
  white-space: nowrap;
}
a.tag-link:hover {
  color: #1e40af;                  /* blue-800 — shifts on hover to signal link */
  background-color: #eff6ff;       /* blue-50 */
  border-color: #bfdbfe;           /* blue-200 */
  text-decoration: none;
}

/* Name link — for human names (people, etc.) in lists.
   Same chip-style affordance as tag-link but without monospace. */
a.name-link,
a.name-link:link,
a.name-link:visited {
  text-decoration: none;
  color: #334155;
  font-weight: 500;
  padding: 2px 8px;
  border-radius: 4px;
  background-color: #f1f5f9;
  border: 1px solid transparent;
  transition: all 0.08s;
  display: inline-block;
}
a.name-link:hover {
  color: #1e40af;
  background-color: #eff6ff;
  border-color: #bfdbfe;
  text-decoration: none;
}

/* Card footer — for "See all X →" links at the bottom of dashboard widgets. */
.card-footer-link {
  display: flex;
  justify-content: flex-end;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line, #e5e7eb);
}
.card-footer-link a,
.card-footer-link a:link,
.card-footer-link a:visited {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  text-decoration: none;
  font-size: 13px;
  font-weight: 500;
  color: var(--accent, #2563eb);
  padding: 6px 12px;
  border-radius: 6px;
  background-color: #f1f5f9;
  border: 1px solid #e2e8f0;
  transition: all 0.1s;
}
.card-footer-link a:hover {
  background-color: #eff6ff;
  border-color: #bfdbfe;
  color: #1d4ed8;
  text-decoration: none;
}
.card-footer-link a::after {
  content: "→";
  transition: transform 0.1s;
}
.card-footer-link a:hover::after {
  transform: translateX(2px);
}

/* Category icon — small emoji prefix, consistent spacing */
.category-icon {
  display: inline-block;
  margin-right: 6px;
  font-size: 14px;
  width: 1.2em;
  text-align: center;
  opacity: 0.9;
}

/* Icon picker for category form */
.icon-picker {
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 8px;
  padding: 12px 14px 14px;
  margin: 0;
  background: #fafbfc;
}
.icon-picker legend {
  padding: 0 6px;
  font-weight: 600;
  font-size: 14px;
  color: var(--text, #111);
}
.icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
  gap: 6px;
  margin: 8px 0;
}
.icon-chip {
  appearance: none;
  border: 1px solid var(--border, #d1d5db);
  background: #fff;
  border-radius: 6px;
  height: 44px;
  font-size: 20px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: border-color 100ms ease, background 100ms ease, transform 100ms ease;
}
.icon-chip:hover {
  border-color: #94a3b8;
  background: #f1f5f9;
}
.icon-chip.selected {
  border-color: #2563eb;
  background: #dbeafe;
  box-shadow: 0 0 0 1px #2563eb inset;
}
.icon-auto-label {
  font-size: 11px;
  font-weight: 600;
  color: #475569;
  letter-spacing: 0.02em;
}
.icon-chip.selected .icon-auto-label {
  color: #1d4ed8;
}

/* Duplicates page — sticky jump nav + collapsible section heads */
.dupe-jump-nav {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  gap: 8px;
  padding: 10px 14px;
  margin: 12px 0;
  background: #fff;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
  flex-wrap: wrap;
  align-items: center;
}
.dupe-jump-nav a {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 10px;
  border-radius: 6px;
  text-decoration: none;
  color: #334155;
  font-size: 13px;
  font-weight: 500;
  border: 1px solid transparent;
  transition: background 100ms ease, border-color 100ms ease;
}
.dupe-jump-nav a:hover {
  background: #f1f5f9;
  border-color: #cbd5e1;
}
.dupe-jump-nav a .count {
  color: #64748b;
  font-weight: 400;
  font-size: 12px;
}
.dupe-section-head {
  display: flex;
  align-items: center;
  margin: 0;
}
.dupe-section-head h2 {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
}
.dupe-toggle {
  background: transparent;
  border: 1px solid var(--border, #d1d5db);
  border-radius: 6px;
  width: 28px;
  height: 28px;
  padding: 0;
  cursor: pointer;
  font-size: 12px;
  color: #475569;
  line-height: 1;
  flex-shrink: 0;
  transition: background 100ms ease;
}
.dupe-toggle:hover {
  background: #f1f5f9;
}
.dupe-section-body {
  margin-top: 10px;
}


/* ── Branding: login page logo + settings-page logo preview ──────── */
.auth-logo {
  display: block;
  margin: 0 auto 12px;
  max-height: 64px;
  max-width: 200px;
  object-fit: contain;
}
.org-subtitle {
  font-size: 14px;
  margin: -8px 0 12px;
  font-weight: 500;
}
.logo-preview {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: #f8fafc;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  margin-bottom: 8px;
}
.logo-preview img {
  max-height: 40px;
  max-width: 120px;
  object-fit: contain;
}

/* Overview dashboard: supplementary panels */
.card-head-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}
.card-head-row h3 {
  margin: 0;
}
.chart-card-wide {
  width: 100%;
}
.table-compact th, .table-compact td {
  padding: 6px 10px;
  font-size: 13px;
}
.table-compact td.num, .table-compact th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Filter banner — shown when a list is filtered via deep-link from elsewhere */
.filter-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  border-radius: 6px;
  margin-bottom: 16px;
  font-size: 14px;
  color: #1e3a8a;
}
.btn-sm { padding: 4px 10px; font-size: 12px; }

/* table.td.num — right-aligned numeric cell (we prefer this name over .right
   for numeric data since it also enables tabular numerals via typography) */
.table td.num, .table th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Days-left urgency badges (overview warranty panel) */
.days-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  min-width: 32px;
  text-align: center;
}
.days-badge.badge-red   { background: #fee2e2; color: #991b1b; border: 1px solid #fca5a5; }
.days-badge.badge-amber { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
.days-badge.badge-green { background: #dcfce7; color: #166534; border: 1px solid #86efac; }

/* Location panel: highlight unassigned+unlocated as an audit-hygiene gap */
.loc-warn { color: #b45309; font-weight: 600; }

/* ══════════════════════════════════════════════════════════════════════════
   Mobile polish (added in v0.10.0 — mobile responsiveness audit)
   ──────────────────────────────────────────────────────────────────────────
   Philosophy: the app is a desktop-first admin tool, but occasionally gets
   used on a phone for spot-checks and quick edits. These rules keep the
   core workflows usable on narrow viewports without redesigning the UI.

   Hamburger top bar: The left-hand sidebar is hidden off-canvas on mobile
   (see existing rule at max-width: 768px further up this file). A dedicated
   `.mobile-topbar` shows only on mobile and contains a hamburger that opens
   the sidebar as a drawer.

   Tables: `.table-scroll` was vertical-only. On mobile we need horizontal
   scrolling too, with a subtle shadow to hint more content exists.

   Breakpoints used (consistent with rest of file):
     - 768px: mobile (phone, portrait tablet)
     - 640px: small mobile (single-column KPIs etc., already defined above)
   ────────────────────────────────────────────────────────────────────── */

/* Mobile topbar — hidden by default (desktop), shown at the mobile breakpoint */
.mobile-topbar {
  display: none;
}

.mt-hamburger {
  background: transparent;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 6px;
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  color: #1f2937;
  cursor: pointer;
  flex-shrink: 0;
}
.mt-hamburger:hover, .mt-hamburger:focus {
  background: #f1f5f9;
  outline: none;
}
.mt-brand {
  display: inline-flex; align-items: center; gap: 10px;
  color: #0f172a; text-decoration: none;
  min-width: 0;                /* allow text ellipsis inside */
  flex: 1 1 auto;
}
.mt-brand:hover { text-decoration: none; }
.mt-logo {
  width: 30px; height: 30px;
  border-radius: 6px;
  object-fit: contain;
  flex-shrink: 0;
}
.mt-logo-placeholder {
  background: var(--primary, #2b5fd9);
  color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 14px;
}
.mt-brand-text {
  display: flex; flex-direction: column;
  min-width: 0; line-height: 1.15;
}
.mt-brand-org {
  font-weight: 600; font-size: 14px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mt-brand-app {
  font-size: 11px; color: #64748b;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Horizontal scroll for wide tables on narrow screens. We apply it to the
   existing `.table-scroll` wrapper so list pages automatically benefit.
   `-webkit-overflow-scrolling: touch` keeps iOS momentum scrolling.
   The thin shadow on the right edge hints that more content exists. */
.table-scroll {
  -webkit-overflow-scrolling: touch;
}

@media (max-width: 768px) {
  /* Show the mobile topbar */
  .mobile-topbar {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    background: #fff;
    border-bottom: 1px solid var(--line, #e5e7eb);
    position: sticky; top: 0;
    z-index: 40;                /* below the open sidebar (50) + scrim (49) */
  }

  /* Hide the desktop-only sidebar toggle button (the `‹` chevron). On mobile
     the hamburger on the topbar is the control; tapping outside the drawer
     or a nav link also closes it. */
  .sidebar .sb-toggle { display: none; }

  /* Mobile sidebar layering — existing rule already flips transform on
     .sb-mobile-open; bump z-index so it sits above the topbar. */
  .sidebar { z-index: 50; }

  /* Container padding — 24px wastes ~12% of viewport on narrow phones */
  .container { padding: 14px; }

  /* Page head — stack h1 above actions, let long titles wrap */
  .page-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
  .page-head h1 { font-size: 19px; word-break: break-word; }
  .page-actions { flex-wrap: wrap; }

  /* Horizontal scroll for tables; keep the existing vertical limit but
     let the thead remain sticky as rows scroll up. */
  .table-scroll {
    overflow-x: auto;
    max-height: none;            /* let the whole page scroll on mobile */
  }
  .table-scroll.table-scroll-tall {
    max-height: none;
  }
  .table { min-width: 600px; }   /* force horizontal scroll rather than cramped columns */
  .table th, .table td {
    padding: 8px 8px;
    font-size: 13px;
  }

  /* Filters bar — let inputs grow to full width one per row when needed */
  .filters { padding: 10px 12px; }
  .filters input[type=text],
  .filters select {
    flex: 1 1 100%;
    min-width: 0;
  }

  /* Flash — don't overrun the edges */
  .flash { padding: 10px 14px; font-size: 14px; }

  /* Cards — drop the per-card min width so the grid doesn't overflow */
  .cards { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }

  /* Buttons inside page-actions — ensure tap targets are >= 40px */
  .page-actions .btn { min-height: 40px; }
}

/* Very narrow screens — stack filter selects one per row cleanly */
@media (max-width: 480px) {
  .container { padding: 10px; }
  .page-head h1 { font-size: 17px; }
  .cards { grid-template-columns: 1fr 1fr; }
  .stat .stat-value { font-size: 22px; }
}

/* ── Data completeness wizard (/reports/completeness, v0.11.0) ───────── */
.gap {
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 6px;
  margin-bottom: 8px;
  background: #fff;
}
.gap > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  cursor: pointer;
  list-style: none;
  font-weight: 500;
}
.gap > summary::-webkit-details-marker { display: none; }
.gap > summary::before {
  content: "▸";
  font-size: 10px;
  color: #94a3b8;
  margin-right: 6px;
  transition: transform 0.08s;
  display: inline-block;
}
.gap[open] > summary::before { transform: rotate(90deg); }
.gap:hover { border-color: #d1d5db; }
.gap-label { flex: 1 1 auto; }
.gap-count {
  background: #fef3c7;
  color: #92400e;
  border: 1px solid #fcd34d;
  flex-shrink: 0;
}
.gap-body {
  padding: 0 14px 12px 14px;
  border-top: 1px solid var(--line, #e5e7eb);
}
.gap-clean {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--line, #e5e7eb);
  font-size: 13px;
  color: #475569;
}
.clean-pill {
  display: inline-block;
  margin: 2px 4px 2px 0;
  padding: 2px 8px;
  background: #ecfdf5;
  color: #065f46;
  border: 1px solid #a7f3d0;
  border-radius: 10px;
  font-size: 12px;
}
.ent-tag {
  display: inline-block;
  padding: 2px 7px;
  background: #f1f5f9;
  color: #334155;
  border: 1px solid #e2e8f0;
  border-radius: 4px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.col-actions { white-space: nowrap; text-align: right; }

/* Tiny info text in stat tiles */
.stat .tiny { font-size: 11px; margin-top: 2px; }

/* ── Asset photos gallery (v0.12.0) ────────────────────────────────────── */
.photo-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 10px;
  margin-top: 10px;
}
.photo-tile {
  position: relative;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 6px;
  overflow: hidden;
  background: #f8fafc;
  aspect-ratio: 1 / 1;
  display: flex;
  flex-direction: column;
}
.photo-tile > a {
  flex: 1 1 auto;
  display: block;
  overflow: hidden;
}
.photo-tile img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.12s;
}
.photo-tile:hover img { transform: scale(1.03); }
.photo-tile-meta {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 4px 6px;
  background: rgba(15, 23, 42, 0.72);
  color: #fff;
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.photo-tile-delete {
  position: absolute;
  top: 4px; right: 4px;
  margin: 0;
}
.btn-x {
  width: 24px; height: 24px;
  border: 0;
  border-radius: 50%;
  background: rgba(15, 23, 42, 0.72);
  color: #fff;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.btn-x:hover { background: #b91c1c; }

@media (max-width: 480px) {
  .photo-gallery { grid-template-columns: repeat(2, 1fr); gap: 8px; }
}

/* ──────────────────────────────────────────────────────────────────────────
   Responsive refinements (v1.8.0 — mobile/tablet polish)
   ──────────────────────────────────────────────────────────────────────────
   Goals:
   - Dark mobile topbar that matches the sidebar's dark theme (and RiskMap's
     style), instead of the previous white topbar
   - Single "AssetDesk" text on mobile (drop the long org name on small screens)
   - Stack content rows vertically on narrow screens so cards don't overflow
   - Sensible grid breakpoints across phone-landscape, foldable, tablet, desktop
   - Verification progress card stops overflowing on phones
   - Better card density on tablets (2-up instead of cramped 4-up)

   Breakpoints used:
   - ≤ 480px   phone portrait
   - 481-768px phone landscape, foldable closed, small tablet portrait
   - 769-1024px tablet portrait, foldable inner
   - 1025-1280px tablet landscape
   - > 1280px  desktop

   These complement the existing rules above; nothing here removes prior styling,
   it only adjusts and adds new behaviour.
   ────────────────────────────────────────────────────────────────────── */

/* ── Mobile topbar: dark theme (match sidebar + RiskMap) ─────────────────── */
@media (max-width: 768px) {
  .mobile-topbar {
    background: var(--sb-bg, #14181f) !important;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
    color: var(--sb-fg, #c9d0db);
  }
  .mt-hamburger {
    background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.15);
    color: var(--sb-fg-strong, #ffffff);
  }
  .mt-hamburger:hover,
  .mt-hamburger:focus {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.25);
    outline: none;
  }
  .mt-brand {
    color: var(--sb-fg-strong, #ffffff);
  }
  .mt-logo {
    background: rgba(255, 255, 255, 0.08);
  }
  .mt-logo-placeholder {
    background: var(--primary, #2b5fd9);
    color: #fff;
  }
  .mt-brand-org {
    color: var(--sb-fg-strong, #ffffff);
    font-weight: 600;
  }
  .mt-brand-app {
    color: var(--sb-fg-dim, #8892a2);
  }
}

/* On phone portrait, drop the long org name and show only "AssetDesk". The
   org name is still in the title bar and on the desktop sidebar; here we
   need the space for the actual product name to be readable. */
@media (max-width: 480px) {
  .mt-brand-org {
    /* When both .mt-brand-org and .mt-brand-app are present, hide the org line. */
    display: none;
  }
  .mt-brand-app {
    font-size: 15px !important;
    color: var(--sb-fg-strong, #ffffff) !important;
    font-weight: 600;
  }
  /* If there's only one element (mt-brand-org without app), keep that visible. */
  .mt-brand-text:not(:has(.mt-brand-app)) .mt-brand-org {
    display: inline;
    font-size: 15px;
    color: var(--sb-fg-strong, #ffffff);
  }
}

/* ── Verification progress card: stack contents on narrow screens ─────────── */
@media (max-width: 640px) {
  .progress-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }
  .progress-stats {
    font-size: 12px;
  }
  /* The "see N assets needing verification" link can wrap on small screens
     instead of forcing horizontal scroll. */
  .card-footer-link {
    word-wrap: break-word;
    white-space: normal;
  }
  .card-footer-link a {
    display: inline-block;
    word-break: break-word;
  }
}

/* ── Cards grid: sensible breakpoints across all viewport sizes ──────────── */
/* The base rule already uses auto-fit + minmax(160px, 1fr) which works for
   most widths. We override for specific viewport ranges where the auto-fit
   produces awkward layouts (e.g. 3-up at 700px = cramped 200px columns). */

/* Phone portrait: stack to a single column */
@media (max-width: 480px) {
  .cards {
    grid-template-columns: 1fr !important;
  }
}

/* Phone landscape / foldable closed / small tablet portrait: 2-up */
@media (min-width: 481px) and (max-width: 768px) {
  .cards {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Tablet portrait / foldable inner: 3-up keeps cards comfortable */
@media (min-width: 769px) and (max-width: 1024px) {
  .cards {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ── 2-col content grid (e.g. "By entity" + "By category" on dashboard) ──── */
/* The existing rule at line 534 stacks at ≤800px. We want it to stack on all
   phone-sized devices but allow side-by-side from tablet up. */
@media (min-width: 769px) and (max-width: 1024px) {
  .grid-2 {
    grid-template-columns: 1fr;  /* stack on tablet portrait — tables need width */
  }
}
@media (min-width: 1025px) {
  .grid-2 {
    grid-template-columns: 1fr 1fr;
  }
}

/* ── Page-head: action buttons take full width on small phones ─────────── */
@media (max-width: 480px) {
  .page-actions {
    width: 100%;
  }
  .page-actions .btn {
    flex: 1 1 auto;
    text-align: center;
    justify-content: center;
  }
}

/* ── Container padding: tweak for tablet sizes too ─────────────────────── */
@media (min-width: 769px) and (max-width: 1024px) {
  .container {
    padding: 18px;  /* between mobile's 14px and desktop's 24px */
  }
}

/* ── Tables: increase the min-width threshold for tablets so columns fit ─ */
/* Tablets are wide enough to show full tables without horizontal scroll.
   Only force min-width on actual phones. */
@media (min-width: 769px) {
  .table {
    min-width: 0;  /* no forced overflow on tablet up */
  }
}

/* ── Sidebar slide-in on tablet portrait too (not just phone) ──────────── */
/* The existing rule fires at ≤768px. Tablet portrait (up to ~820px on iPad)
   would benefit too — sidebar takes too much screen on portrait. */
@media (max-width: 1024px) and (orientation: portrait) {
  .sidebar {
    transform: translateX(-100%);
    transition: transform var(--sb-transition);
    width: var(--sb-width) !important;
  }
  html.sb-mobile-open .sidebar {
    transform: translateX(0);
    box-shadow: 4px 0 24px rgba(0,0,0,0.4);
  }
  html.sb-mobile-open::before {
    content: "";
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.5);
    z-index: 49;
  }
  .app-shell {
    margin-left: 0 !important;
  }
  .mobile-topbar {
    display: flex !important;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    position: sticky; top: 0;
    z-index: 40;
  }
}

/* ──────────────────────────────────────────────────────────────────────────
   Responsive refinements v2 — fixes from Batch 1 testing
   ──────────────────────────────────────────────────────────────────────────
   Three issues found:
   1. .page-actions on phone portrait: the two buttons share row width and
      overflow when both are ~150px+. Stack them vertically instead.
   2. .card-footer-link a is inline-flex which doesn't wrap. Switch to
      inline-block on phone portrait so the link can wrap if too long.
   3. Tighten the page-head action button styles for narrow widths.
   ────────────────────────────────────────────────────────────────────── */

@media (max-width: 480px) {
  /* Stack page-action buttons vertically on phone portrait. They were
     overflowing the viewport when laid out side-by-side because
     `flex: 1 1 auto` honours natural content width, and both buttons
     together exceeded the screen. Stacking + full-width is the cleanest
     mobile pattern (and matches how RiskMap presents primary actions). */
  .page-actions {
    flex-direction: column;
    width: 100%;
    align-items: stretch;
  }
  .page-actions .btn {
    flex: 0 0 auto;        /* don't grow/shrink; fill the column width */
    width: 100%;
    text-align: center;
    justify-content: center;
  }

  /* Card-footer-link: convert from inline-flex to inline-block so the
     link text can wrap when too long for the viewport. Without this the
     "See N assets needing verification" link would overflow horizontally.
     Also drop the `justify-content: flex-end` on the parent so the link
     stays left-aligned and can use the full available width. */
  .card-footer-link {
    justify-content: flex-start;
  }
  .card-footer-link a,
  .card-footer-link a:link,
  .card-footer-link a:visited {
    display: inline-block;
    max-width: 100%;
    white-space: normal;
    word-wrap: break-word;
    line-height: 1.4;
  }
  /* The ::after arrow is positioned via inline-flex; in inline-block
     mode just append it inline. */
  .card-footer-link a::after {
    margin-left: 4px;
  }
}

/* ──────────────────────────────────────────────────────────────────────────
   Responsive refinements v3 — fix dashboard lower-section overflows
   ──────────────────────────────────────────────────────────────────────────
   Issues found during Batch 1 testing:
   1. Card <h2> headings with inline subtitles (e.g. "Hardware warranty
      expiring in the next 60 days · 14 already expired") clip when the
      heading alone is too wide for the viewport.
   2. Inline link rows ("Last backup: 12.0 hours ago · manage backups")
      clip when the link extends past the card width.
   3. Card padding eats too much horizontal space on phones.
   ────────────────────────────────────────────────────────────────────── */

@media (max-width: 480px) {
  /* Card headings: allow wrapping. The h2 default doesn't wrap nicely
     when it has inline child <span> elements. */
  .card h2 {
    white-space: normal;
    word-break: break-word;
    line-height: 1.3;
  }
  /* Inline subtitle spans inside h2: drop down to a new line on narrow
     screens rather than fighting for horizontal space. */
  .card h2 .muted.tiny {
    display: block;
    margin-top: 4px;
    font-size: 11px;
  }

  /* Card content paragraphs with inline content + links: allow wrap.
     Targets the database-backup status line. */
  .card > p {
    word-wrap: break-word;
  }
  /* Backup status line: stack the status and the "manage backups" link
     when there's no room. The bullet separator looks slightly odd on
     a new line but still functions as a separator. */
  .card > p > a {
    white-space: normal;
    word-break: break-word;
  }

  /* Card body padding: reduce on phones to give content more room */
  .card {
    padding: 12px 14px;
  }
}

/* ──────────────────────────────────────────────────────────────────────────
   Responsive refinements v4 — fix landscape horizontal overflow
   ──────────────────────────────────────────────────────────────────────────
   Root cause: dashboard tables aren't wrapped in .table-scroll, so the
   600px min-width on tables pushes the body wider than the viewport,
   causing horizontal scroll on landscape (and clipped content right edge
   on portrait).

   Two fixes:
   1. Stop-gap: prevent body horizontal scroll on phones. If a child
      element overflows, it gets clipped instead of pushing the body
      width. This is defence-in-depth — visible side-effect would be
      content cut off, but we'd see that and know to fix it.
   2. Proper fix is to wrap tables in .table-scroll containers in the
      dashboard template — that's a template change, not CSS.

   Also stronger selector for the v3 fixes that didn't apply.
   ────────────────────────────────────────────────────────────────────── */

/* Stop-gap: prevent body horizontal scroll at all phone widths */
@media (max-width: 768px) {
  html, body {
    overflow-x: hidden;
    max-width: 100vw;
  }
  /* Tables inside cards without .table-scroll wrapper: contain them
     within the card so they don't push body width. */
  .card {
    overflow-x: hidden;
  }
  /* But the card with .table-scroll inside should keep horizontal
     scroll for the table — don't clip the scrollable child. */
  .card .table-scroll {
    overflow-x: auto;
  }
}

/* Stronger selectors for v3 fixes that didn't apply */
@media (max-width: 480px) {
  /* The h2 inside card sometimes has white-space: nowrap from a parent.
     Force wrap. Using !important since some inline styles override. */
  .card h2,
  section.card h2 {
    white-space: normal !important;
    word-break: break-word !important;
    overflow-wrap: break-word;
    hyphens: auto;
    line-height: 1.3;
  }

  /* The database backup status line has inline child elements. Force
     the paragraph itself to wrap, and crucially allow the inline <a>
     to break onto a new line. */
  .card > p {
    white-space: normal !important;
    word-wrap: break-word;
    overflow-wrap: break-word;
  }
  .card > p > a {
    display: inline;
    white-space: normal !important;
  }
}

/* ──────────────────────────────────────────────────────────────────────────
   Responsive refinements v5 — actually fix the horizontal scroll
   ──────────────────────────────────────────────────────────────────────────
   The body { overflow-x: hidden } from v4 didn't stop horizontal scroll on
   iOS Safari. Root cause: .table { min-width: 600px } at <=768px forces
   tables wider than the viewport, and Safari honours that even with body
   overflow-x: hidden — children with intrinsic min-width can still extend
   the visible scroll area.

   Real fix: kill the 600px min-width on .table at phone widths. Tables
   become squashed but visible. This is the right trade-off for the
   dashboard's small summary tables (3-5 columns max). Long-column tables
   like /assets list will need to be wrapped in .table-scroll explicitly
   (template change, comes next).

   Rules later in the file win, so this overrides line 1941.
   ────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {
  /* Drop the min-width on tables; let columns compress as needed */
  .table {
    min-width: 0 !important;
    width: 100%;
    table-layout: auto;
  }
  /* Tables explicitly wrapped in .table-scroll keep horizontal scroll */
  .table-scroll .table {
    min-width: 600px !important;
  }
  /* Table cells: tighter padding, allow text wrap rather than nowrap */
  .table th, .table td {
    padding: 6px 6px !important;
    font-size: 12px !important;
    white-space: normal !important;
    word-break: break-word;
  }
}

/* ──────────────────────────────────────────────────────────────────────────
   Responsive — shared list-table → cards  (v1.8.0+ mobile completion)
   ──────────────────────────────────────────────────────────────────────────
   The list pages (assets, software, people, vendors, …) are wide multi-column
   tables. Horizontally scrolling them on a phone (≈60px/column at the global
   600px min-width) is painful, so at ≤768px we transform each row into a
   stacked "card": the first cell becomes the card title and every other column
   becomes a label:value pair. Empty cells are hidden so cards stay tight.

   Labels come from each column's <th>, attached as data-label by the shim in
   /static/js/list-cards.js (column-agnostic — any list page works with no
   per-cell tagging, just add class="table list-table" to the table). The shim
   also sets .cell-tag / .cell-check / .cell-empty / .cell-fullspan; the assets
   template hard-codes the same hints as a no-JS fallback, so both selectors are
   kept below and it degrades gracefully.

   Bulk-select checkboxes + the bulk toolbar are desktop power-features and are
   hidden on mobile — bulk edits aren't a phone task, and dropping them keeps
   each card clean.

   Scoped to .list-table so the dashboard's small summary tables (which scroll
   horizontally per the global rules) are unaffected. Tablets (769–1024px) keep
   the normal table — they have the width for it.
   ────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {
  /* Neutralise the global `.table-scroll .table { min-width:600px }` for THIS
     table — we're stacking, not scrolling. */
  .table-scroll .list-table,
  .list-table.table { min-width: 0 !important; }

  /* Header row not needed — labels move inline via data-label */
  .list-table thead { display: none; }

  /* Bulk-select column hidden (no bulk ops on mobile) */
  .list-table .cell-check { display: none !important; }

  /* Row → card */
  .list-table,
  .list-table tbody,
  .list-table tr,
  .list-table td { display: block; width: 100%; }

  .list-table tr {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-sm);
    padding: 10px 12px;
    margin-bottom: 10px;
  }
  /* Kill the desktop row-hover tint on touch cards */
  .list-table tbody tr:hover { background: var(--surface); }

  /* Generic label:value cell.
     Label hugs the left (::before with margin-right:auto); the value — even
     when it's several elements, e.g. multiple gap badges or an icon + name —
     groups on the right and wraps as a unit. (Using justify-content:flex-end
     instead of space-between is what keeps multi-element values together
     rather than spread across the row.) */
  .list-table td {
    border-bottom: 1px solid var(--line) !important;
    padding: 6px 0 !important;
    font-size: 13px !important;
    white-space: normal !important;
    word-break: break-word;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: baseline;
    gap: 4px 10px;
    text-align: right;
  }
  .list-table td:last-child { border-bottom: 0 !important; }

  /* Inline label, pulled from the column header text */
  .list-table td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 auto;
    margin-right: auto;   /* push the label to the left edge */
    text-align: left;
    color: var(--muted);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
  }

  /* Hide cells that rendered empty (no serial, no RAM, unassigned, …).
     :empty catches truly-empty cells; .cell-empty is set by the shim for
     cells that are whitespace-only. */
  .list-table td:empty,
  .list-table td.cell-empty { display: none !important; }

  /* Asset tag = card title: full width, prominent, no label */
  .list-table td.cell-tag {
    display: block;
    text-align: left;
    padding-bottom: 8px !important;
    margin-bottom: 2px;
  }
  .list-table td.cell-tag::before { content: none; }
  .list-table td.cell-tag .tag-link { font-size: 15px; font-weight: 600; }

  /* Status chip stays on one line */
  .list-table td .status { white-space: nowrap; }

  /* Empty-state row (colspan) spans the full card, centred, no label.
     [colspan] catches the literal attribute; .cell-fullspan is set by the shim. */
  .list-table td[colspan],
  .list-table td.cell-fullspan {
    text-align: center;
    color: var(--muted);
    padding: 16px 0 !important;
  }
  .list-table td[colspan]::before,
  .list-table td.cell-fullspan::before { content: none; }

  /* Bulk toolbar has no purpose without row selection */
  #bulk-toolbar { display: none !important; }

  /* Keyboard pager hint is meaningless on touch */
  .pager-hint { display: none; }
}

/* Filter banners (vendor / stale): stack text above the Clear button on phones */
@media (max-width: 480px) {
  .filter-banner {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
  .filter-banner .btn { width: 100%; text-align: center; }

  /* Filters form: single column for comfortable tap targets */
  .filters-grid { grid-template-columns: 1fr; }
  .filters-grid .span-2,
  .filters-grid .filter-actions { grid-column: span 1; }
  .filters-grid .filter-actions .btn {
    flex: 1 1 auto;
    text-align: center;
    min-height: 40px;
  }
}

/* Pager: centre + stack the per-page selector and numbered pager on phones */
@media (max-width: 560px) {
  .pager-bar { justify-content: center; }
  .pager-bar .pager {
    justify-content: center;
    width: 100%;
    flex-wrap: wrap;
  }
  .pager-perpage { justify-content: center; width: 100%; }
}

/* ── list-table cards: count cells (vendors HW/SW, etc.) ──────────────────── */
/* On desktop the .count-pill is a small boxed button (bordered when clickable,
   dashed when zero). In a card row, pushed to the right, that box reads as a
   cramped/"shrunken" widget. In card mode strip the chrome and show the count
   as a plain right-aligned value — links stay primary-coloured and tappable. */
@media (max-width: 768px) {
  .list-table td .count-pill {
    min-width: 0;
    padding: 0;
    border: 0;
    background: none;
    border-radius: 0;
    font-size: 14px;
    text-align: right;
  }
  .list-table td a.count-pill { color: var(--primary); }
  .list-table td a.count-pill:hover { background: none; text-decoration: underline; }
  .list-table td .count-pill.count-zero { color: var(--muted); }
}

/* ── list-table cards: seat-utilization progress bar (license usage) ──────── */
@media (max-width: 768px) {
  /* The utilization bar must span the card cell, not collapse to content
     width inside the flex row — give it its own full-width line. */
  .list-table td .seat-util-bar {
    flex: 1 1 100%;
    width: 100%;
    min-width: 140px;
  }
  /* SKU/code titles read better slightly larger than the .tiny default. */
  .list-table td.cell-tag code { font-size: 13px; }
}

/* ── list-table cards: rich multi-line cells ─────────────────────────────── */
/* Cells with a <br> or block-level content (a stacked device list, "code +
   name" pairs, person + email, …) don't fit the single-line label:value flex
   row. The shim tags them .cell-block; lay them out as the label on its own
   line with the value flowing full-width beneath, left-aligned. */
@media (max-width: 768px) {
  .list-table td.cell-block {
    display: block;
    text-align: left;
  }
  .list-table td.cell-block::before {
    display: block;
    margin: 0 0 3px 0;
  }
}

/* ── list-table cards: interactive form cells (e.g. Users admin actions) ──── */
@media (max-width: 768px) {
  /* Password-reset form: full-width input, with the force-change toggle and
     the Reset button wrapping onto the line beneath it. */
  .list-table td.cell-block form:has(input[type="password"]) {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    width: 100%;
    margin-top: 4px;
  }
  .list-table td.cell-block form input[type="password"] {
    flex: 1 1 100%;
    width: auto;
  }
  /* Touch-friendly buttons inside any card form cell (reset/unlink/unlock/delete). */
  .list-table td.cell-block form .btn { min-height: 36px; }
}

/* ── Forms: prevent layout blow-out on narrow screens ────────────────────── */
/* A <select> with a long option, or a long unbreakable <code> URL in a hint,
   can force a .form-grid track wider than the viewport (grid/flex items default
   to min-width:auto), which clips the whole page on the right. Letting items
   shrink and long hint text wrap fixes it — applies at all widths. */
.form-grid > *,
.form-grid input,
.form-grid select,
.form-grid textarea { min-width: 0; }
.form-grid .inline-check { flex-wrap: wrap; }
.hint { overflow-wrap: break-word; }

/* ── v1.8.10: detail pages, sync-history cards, settings overflow ─────────
   Three mobile fixes:
   1. .detail-grid is a 2-column dt/dd grid that never collapsed on phones,
      so its right column was clipped (Software / Person detail pages).
      Stack it to a single column.
   2. THE settings overflow culprit: a long no-space token in a .hint —
      the Entra redirect URI <code>https://…/auth/entra/callback</code> and
      tenant-ID GUIDs — forced the .form-grid track wider than the viewport,
      clipping the whole page. overflow-wrap:break-word (added earlier) does
      NOT help here because it doesn't change the min-content size that a
      grid/flex track is sized from; overflow-wrap:anywhere DOES. Apply it
      to code + hints on mobile so the track can shrink and the URL wraps.
   3. Belt-and-suspenders: clip horizontal overflow at the scroll ancestors
      and let form action buttons wrap, so no future stray wide element can
      push the page sideways. Scroll tables (.table-scroll) and <pre> keep
      their own internal scroll, so this clip doesn't trap their content. */
@media (max-width: 768px) {
  .detail-grid { grid-template-columns: 1fr; }
  .detail-grid .span-2 { grid-column: span 1; }
  .detail-grid > * { min-width: 0; }

  code { overflow-wrap: anywhere; word-break: break-all; }
  .hint { overflow-wrap: anywhere; }

  /* Carded list-table cells (and their card titles) can hold long
     unbreakable tokens — backup filenames like asset_inventory.db.…gz,
     tenant GUIDs, tags. word-break:break-word / overflow-wrap:anywhere do
     NOT break these (no legal break point at '.'/'-', and they only break
     against an available width that the block cell is itself defining —
     circular, so the longest token wins). break-all breaks between any two
     characters unconditionally and lowers min-content, forcing the cell to
     fit its container. Filenames wrap onto 2 lines; acceptable on mobile. */
  .list-table td, .list-table .cell-tag { overflow-wrap: anywhere; word-break: break-all; }
  /* Keep the carded table itself bounded to its card — a display:block
     table/tbody/tr otherwise takes its content width and runs off-screen. */
  .list-table, .list-table tbody, .list-table tr, .list-table td { max-width: 100%; box-sizing: border-box; }

  /* The real Settings-overflow culprit: an .inline-check is a flex row
     (checkbox + label text + a block .hint). Flex items default to
     min-width:auto and refuse to shrink below their content's min-content,
     so the long hint ("Will only enable if tenant ID…") claimed ~700px and
     dragged the whole page wide. flex-wrap alone doesn't help — the wrapped
     item still demands full min-content. Force every flex child to shrink,
     and let the hint take its own full-width line. */
  .inline-check { flex-wrap: wrap; }
  .inline-check > * { min-width: 0; }
  .inline-check .hint { flex: 1 1 100%; }

  .app-shell, .app-shell > main.container { overflow-x: hidden; }
  /* .app-shell is a COLUMN flexbox, so min-width on main.container governs
     the height axis, not width — that's why the earlier min-width:0 never
     capped it and the cards ran off-screen. The width axis is the cross
     axis; cap it directly with max-width:100% (overriding the desktop
     max-width:1200px). Now the container = the app-shell width = viewport,
     and every card/table inside fits. THIS is the actual fix. */
  .app-shell > main.container { min-width: 0; max-width: 100%; }
  .form-actions { flex-wrap: wrap; }
  pre { max-width: 100%; }
}


/* ── Signature pad (ported from StaffDesk v1.12.3) ───────────────────── */
.sig-field { display:block; margin:.6rem 0; }
.sig-label { display:block; font-size:.9rem; color:var(--muted); margin-bottom:4px; }
.sigpad { display:block; max-width:100%; }
.sigpad canvas {
  border:1px solid #c4c9d0; border-radius:6px; background:#fff;
  touch-action:none; cursor:crosshair; display:block;
  width:100%; max-width:360px; height:auto; aspect-ratio:32 / 11;
}
.sigpad .sig-clear { margin-top:6px; }

/* ═══════════════════════════════════════════════════════════════════════
   NetDesk — compatibility + additions
   ────────────────────────────────────────────────────────────────────────
   APPEND THIS BLOCK to the end of AssetDesk's app.css (copied verbatim).
   It defines the legacy class names the existing NOC page templates rely on
   — these were declared inline in the old base.html, which was the ONLY
   stylesheet, so they are exactly the classes the pages can use. As each page
   is migrated to AssetDesk idioms (.container/.table/.status/.form-grid/
   .flash-success|error) these legacy rules become unused and can be dropped.

   Deliberate divergences from the old NOC styles (flagged, not accidental):
     • Dropped the old @media(prefers-color-scheme:dark) block. AssetDesk's
       identity is light content + dark sidebar; a full dark mode would clash.
     • .btn / .btn-primary / .btn-danger / .btn-sm / .card / .muted now come
       from AssetDesk (intentional — that IS the shared look). Not redefined.
     • .section-title resolves to AssetDesk's small-uppercase label, NOT the
       old bold 17px header. Pages using it as a header will be normalised
       during their migration pass.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Legacy page wrapper + title (pages that only fill {% block content %}) ─ */
.page { max-width: 1200px; margin: 0 auto; padding: 24px; }
.page-title { font-size: 22px; font-weight: 700; margin: 0 0 18px 0; letter-spacing: -.01em; }

/* ── Legacy bare-<table> styling ───────────────────────────────────────────
   AssetDesk styles the `.table` class; the NOC pages use bare <table>. These
   rules cover bare tables only — `.table` rules are more specific and win for
   migrated pages, so no conflict. */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--line); vertical-align: middle; }
th { color: var(--ink-soft); font-weight: 600; font-size: 12px; letter-spacing: .04em; text-transform: uppercase; background: #fafbfc; }
tbody tr:hover td { background: #f8f9fb; }
tr:last-child td { border-bottom: none; }

/* ── Legacy forms (.form-row grid). Inputs already inherit AssetDesk's global
   input styling for borders/focus, so we only need the row layout. ───────── */
.form-row { display: grid; grid-template-columns: 180px 1fr; gap: 10px; align-items: center; margin: 10px 0; }
.form-label { color: var(--ink-soft); font-weight: 600; font-size: 13px; }
.form-input { width: 100%; }
.form-hint { color: var(--muted); font-size: 12px; margin-top: 3px; }
@media (max-width: 640px) { .form-row { grid-template-columns: 1fr; } }

/* ── Legacy badges (.badge-*). AssetDesk uses .status/.pill/.entity-pill; the
   NOC pages use .badge-ok/warn/bad/muted. ──────────────────────────────────*/
.badge { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 11px; font-weight: 700; letter-spacing: .04em; }
.badge-ok    { background: #dcfce7; color: #166534; }
.badge-warn  { background: #fef9c3; color: #854d0e; }
.badge-bad   { background: #fee2e2; color: #991b1b; }
.badge-muted { background: #f1f5f9; color: #475569; }

/* ── Legacy flash variants. AssetDesk's .flash provides the layout; it only
   defines success/error, so add NOC's ok/err/warn colour set. ──────────────*/
.flash-ok   { background: #e7f5ee; color: #0d6e47; border-color: #bde4cf; }
.flash-err  { background: #fbe8e6; color: #8a2318; border-color: #f0c2bc; }
.flash-warn { background: #fef9c3; color: #854d0e; border-color: #fde68a; }

/* ── Legacy role chips (if shown in any page body) ─────────────────────────*/
.role-admin    { background: #7c3aed; color: #fff; }
.role-operator { background: #0369a1; color: #fff; }
.role-viewer   { background: #374151; color: #e5e7eb; }

/* ── Misc legacy utilities ─────────────────────────────────────────────────*/
.nowrap  { white-space: nowrap; }
.divider { border: none; border-top: 1px solid var(--line); margin: 20px 0; }

/* ── NetDesk: --card alias ──────────────────────────────────────────────────
   The original NOC templates (and JS-generated HTML in device_detail) reference
   var(--card) for surface backgrounds. AssetDesk's app.css defines --surface,
   not --card, so without this alias those backgrounds fall back to transparent
   (breaking sticky headers + info tiles). Map --card to --surface globally. */
:root { --card: var(--surface); }

/* ── Sidebar header ─────────────────────────────────────────────────────────
   The sidebar header carries the app accent; the nav below it stays dark.
   Ported from WiFiDesk (its app.css:663). Reading --app-accent rather than a
   literal is the point: the same rule gives NetDesk blue, AssetDesk indigo and
   WiFiDesk teal.

   The border override matters too — --sb-border (#0a0d12) was picked to read
   against a near-black header and vanishes against a mid-blue one. */
.sb-header {
  background: var(--app-accent);
  border-bottom-color: rgba(0, 0, 0, .22);
}

/* ── Suite wordmark: gold prefix, white suffix ──────────────────────────────
   Shared treatment across WiFiDesk / AssetDesk / NetDesk. The app's own accent
   goes on the band behind it, not in the letters. ─────────────────────────── */
.sb-brand-title, .mt-brand-app { font-weight: 700; }
.wm-pre  { color: var(--app-gold); }
.wm-post { color: #ffffff; }

/* NetDesk subtitle: org name, wrap long names instead of truncating */
.sb-brand-subtitle {
  font-size: 10px !important;
  letter-spacing: -0.1px;
  white-space: normal !important;
  line-height: 1.3;
  overflow: visible !important;
  text-overflow: clip !important;
}
