/* ===========================================================================
   sui.css · Syphnosys UI — the single authored stylesheet
   ---------------------------------------------------------------------------
   Replaces app.css + custom.css. Third-party code is NOT merged in: Bootstrap,
   Bootstrap Icons and Tom Select stay untouched in css/vendor/ and fonts/.

   Load order on every page:
     1. css/vendor/bootstrap.min.css
     2. fonts/icons/bootstrap-icons.min.css
     3. css/vendor/tom-select.bootstrap5.min.css
     4. css/sui.css            <- this file, last

   STRUCTURE — two halves, in their original cascade order:

     PART A · base layer      (was app.css)     sections 0-18
     PART B · skin + shell    (was custom.css)  sections 0-15 + unnumbered blocks

   Part B still overrides Part A for ~40 selectors. That is deliberate: this
   merge preserves the exact cascade the two files produced, so it renders
   byte-identically to what it replaces. Collapsing those 40 pairs into single
   rules is a follow-up pass, done one component at a time with a screenshot
   diff after each.

   Already removed as dead (verified: no `class="top-nav"` in any view, in any
   panel): the .top-nav blocks from both files, their responsive and dark-mode
   variants, and the .sui-notif-count rule that targeted the old navbar bell.

   Conventions kept from custom.css:
     · every new class is prefixed  .sui-*
     · every new variable is prefixed  --sui-*
     · component rules are scoped under `.sui-app` on <body>
   =========================================================================== */

/* ===========================================================================
   PART A · base layer                  (was app.css)
   =========================================================================== */

/* =============================================================
   AdminKit · catchy + minimal
   Loaded after bootstrap.min.css on every page.
   ============================================================= */

/* ------------------------------------------------------------- */
/* 0. Fonts · Inter (18pt optical-size — designed for UI text)   */
/*    8 TTF files in public/fonts/inter/ wired below — Regular   */
/*    / Medium / SemiBold / Bold with matching italics.          */
/* ------------------------------------------------------------- */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/inter/Inter_18pt-Regular.ttf') format('truetype');
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/inter/Inter_18pt-Italic.ttf') format('truetype');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/inter/Inter_18pt-Medium.ttf') format('truetype');
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/inter/Inter_18pt-MediumItalic.ttf') format('truetype');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/inter/Inter_18pt-SemiBold.ttf') format('truetype');
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/inter/Inter_18pt-SemiBoldItalic.ttf') format('truetype');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/inter/Inter_18pt-Bold.ttf') format('truetype');
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/inter/Inter_18pt-BoldItalic.ttf') format('truetype');
}

/* ------------------------------------------------------------- */
/* 1. Tokens                                                     */
/* ------------------------------------------------------------- */
:root {
  --brand: #4f46e5;
  --brand-2: #7c3aed;
  --brand-soft: rgba(79, 70, 229, .12);
  --brand-ring: rgba(79, 70, 229, .18);
  --brand-press: #4338ca;

  --bg: #f6f7fb;
  --surface: #ffffff;
  --surface-alt: #fafbfc;
  --text: #0f172a;
  --muted: #64748b;
  --muted-soft: #94a3b8;

  --border: #e2e8f0;
  --border-soft: #f1f5f9;
  --hover-row: #f8fafc;

  --sidebar-bg: #0f172a;
  --sidebar-fg: #cbd5e1;

  --code-bg: #0f172a;
  --code-fg: #e2e8f0;

  --radius: .55rem;
  --radius-lg: .9rem;

  --ease: cubic-bezier(.4, 0, .2, 1);
  --t-fast: .12s;
  --t-base: .18s;

  --ring: 0 0 0 3px var(--brand-ring);
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, .04);
  --shadow: 0 4px 14px rgba(15, 23, 42, .06);
  --shadow-lg: 0 20px 50px rgba(15, 23, 42, .12);

  --bs-font-sans-serif: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', Arial, sans-serif;
  --bs-font-monospace: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --bs-body-font-family: var(--bs-font-sans-serif);
}

/* ------------------------------------------------------------- */
/* 2. Base                                                       */
/* ------------------------------------------------------------- */
* { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
html, body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', Arial, sans-serif;
  font-feature-settings: 'ss01', 'ss02', 'ss03', 'kern';
  text-rendering: optimizeLegibility;
  letter-spacing: -.005em;
}
body {
  background: var(--bg);
  color: var(--text);
}

a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-press); }
code { color: inherit; background: transparent; padding: 0; font-size: .9em; }

::selection { background: var(--brand-soft); color: var(--text); }

/* Focus ring (uniform) */
*:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 4px; }
.btn:focus-visible { outline: 0; box-shadow: var(--ring); }

/* Skip link */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 8px;
  background: var(--brand);
  color: #fff;
  padding: .5rem 1rem;
  border-radius: var(--radius);
  z-index: 9999;
  font-weight: 600;
}
.skip-link:focus { left: 8px; outline: 2px solid #fff; outline-offset: 2px; color: #fff; }

/* ------------------------------------------------------------- */
/* 3. Layout utilities · content shell                            */
/* ------------------------------------------------------------- */
/* Brand logo size tokens — replace inline style="max-height:Npx" in views. */
.brand-logo    { max-height: 28px; width: auto; }
.brand-logo-md { max-height: 36px; width: auto; }

/* Table cell width utilities — used for "label : value" tables on detail pages. */
.col-label      { width: 140px; min-width: 140px; }
.col-label-sm   { width: 5rem;  min-width: 5rem;  }

/* Code/log preview pane — fixed-height scroll box for tail output. */
.log-tail { max-height: 340px; overflow: auto; }

/* Audit/activity "When" column — fixed width to keep timestamps tidy. */
.col-when { width: 7rem; min-width: 7rem; }

.content { padding: 1.5rem; min-height: calc(100vh - 56px - 60px); }

/* ------------------------------------------------------------- */
/* 4. Cards                                                      */
/* ------------------------------------------------------------- */
.card {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: none;
  transition: box-shadow var(--t-base) var(--ease), transform var(--t-base) var(--ease), border-color var(--t-base) var(--ease);
}
.card-header { background: transparent; border-bottom: 1px solid var(--border-soft); padding: .9rem 1.1rem; font-weight: 600; }
.card-footer { background: transparent; border-top: 1px solid var(--border-soft); padding: .9rem 1.1rem; }

/* Dashboard KPI card — coloured-soft background that matches its icon hue. */
/* Hover gives a noticeable lift + colour-matched glow + icon pop.         */
.stat-card {
  display: block;
  height: 100%;
  padding: 1.1rem 1.15rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--surface);
  position: relative;
  overflow: hidden;
  transition:
    transform .25s var(--ease),
    box-shadow .25s var(--ease),
    border-color .25s var(--ease),
    background-color .25s var(--ease);
}
/* Decorative diagonal sheen on the card — invisible at rest, slides across */
/* on hover. Pure CSS, no JS.                                              */
.stat-card::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(120deg, transparent 30%, rgba(255, 255, 255, .35) 50%, transparent 70%);
  transform: translateX(-100%);
  transition: transform .6s var(--ease);
  pointer-events: none;
}
a.stat-card { color: inherit; text-decoration: none; }
a.stat-card:hover,
a.stat-card:focus-visible {
  transform: translateY(-1px);
  color: inherit;
}
/* Sheen sweep disabled for the minor-hover treatment — too flashy for the  */
/* light-gray look.                                                         */

/* All stat-card variants share a soft light-gray background — calm,       */
/* neutral, so the data does the talking.                                  */
.stat-card-primary,
.stat-card-warning,
.stat-card-danger,
.stat-card-success,
.stat-card-info {
  background: linear-gradient(135deg, #e2e8f0 0%, #f1f5f9 100%);
  border-color: var(--border-soft);
  color: var(--text);
}

/* Stat icon on the light surface — keep the existing solid colour set on  */
/* the <span> via bg-primary / bg-warning utilities; just ensure the glyph */
/* stays readable.                                                         */

/* Hover: minor — barely-there bg shift + small neutral shadow.            */
a.stat-card-primary:hover, a.stat-card-warning:hover,
a.stat-card-danger:hover,  a.stat-card-success:hover,
a.stat-card-info:hover {
  background: linear-gradient(135deg, #cbd5e1 0%, #e2e8f0 100%);
  border-color: var(--border);
  box-shadow: var(--shadow-sm);
  color: var(--text);
}

a.stat-card:active { transform: translateY(0); transition-duration: .08s; }

/* Dark mode — keep the same brand gradient (already reads well on dark).  */
body.dark-mode .stat-card::after {
  background: linear-gradient(120deg, transparent 30%, rgba(255, 255, 255, .08) 50%, transparent 70%);
}

.stat-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
  transition: transform .25s var(--ease), box-shadow .25s var(--ease);
  position: relative;
  z-index: 1;
}
a.stat-card:hover .stat-icon {
  transform: scale(1.03);
}
.stat-icon-md { width: 40px; height: 40px; }
.stat-icon-sm { width: 36px; height: 36px; font-size: .9rem; }

/* Make sure the number/label text stay above the sliding sheen pseudo-el. */
.stat-card > * { position: relative; z-index: 1; }

/* Status / severity pills on bug rows — slightly smaller than .badge default. */
.badge-status { font-size: .72rem; padding: .3em .6em; }

/* AI-assist side panel — distinguishes itself from regular cards with a   */
/* dashed border and soft surface so users notice it is AI-generated UI.    */
.ai-panel {
  background: var(--surface-alt);
  border: 1px dashed var(--border);
  border-radius: var(--radius-lg);
  padding: 1rem;
}
.ai-btn {
  background: linear-gradient(135deg, var(--brand-2), var(--brand));
  border: 0;
  color: #fff;
  font-weight: 500;
}
.ai-btn:hover,
.ai-btn:focus { color: #fff; opacity: .95; box-shadow: 0 4px 12px rgba(124, 58, 237, .25); }
.ai-btn:active { color: #fff; opacity: 1; }

/* Attachment thumbnail square — used on bug view + apps form icon preview. */
.attachment-thumb {
  width: 100px;
  height: 100px;
  object-fit: cover;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface-alt);
}

/* Gujarati script textareas — distinct font so the user can tell the EN    */
/* and GU summary fields apart visually.                                     */
textarea.gujarati { font-family: 'Noto Sans Gujarati', 'Inter', sans-serif; }
.gujarati { font-family: 'Noto Sans Gujarati', 'Inter', sans-serif; }

/* Preserve newlines + wrap — used by bug raw description / steps / summary */
/* fields when rendering free-text the user typed in a textarea.            */
.text-prewrap { white-space: pre-wrap; word-wrap: break-word; }

/* Bug attachment thumbnail grid cell — fixed-width caption under the thumb */
.attachment-cell { width: 120px; }
.attachment-cell .attachment-name { font-size: .8rem; max-width: 120px; }
.attachment-cell .attachment-size { font-size: .7rem; color: var(--muted); }

/* App icon thumbnail — fixed 36×36 square used in the apps list rows. */
.app-icon-sm { width: 36px; height: 36px; object-fit: cover; }

/* Thin progress bar — used inline in tables and on the SLA sidebar card. */
.progress-thin { height: .45rem; }

/* Bug-view timeline — single item is a left-border line + content gutter. */
.timeline-item {
  border-left: 2px solid var(--border-soft);
  padding-left: 1rem;
  margin-bottom: 1rem;
}
.timeline-item:last-child { margin-bottom: 0; }
.timeline-item .timeline-meta { font-size: .8rem; color: var(--muted); }

/* ------------------------------------------------------------- */
/* 5. Buttons                                                    */
/* ------------------------------------------------------------- */
.btn {
  --bs-btn-padding-y: .5rem;
  --bs-btn-padding-x: .9rem;
  --bs-btn-font-size: .9rem;
  --bs-btn-font-weight: 500;
  --bs-btn-border-radius: var(--radius);
  /* Bootstrap 5.0.2 does NOT consume --bs-btn-* vars (those are 5.3+ only), so
     apply them explicitly here. Every variant (.btn-sm, .btn-icon, …) then only
     overrides the vars and this base rule makes them take effect. */
  padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x);
  font-size: var(--bs-btn-font-size);
  font-weight: var(--bs-btn-font-weight);
  border-radius: var(--bs-btn-border-radius);
  letter-spacing: -.005em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease),
              transform .06s var(--ease);
}
.btn:active { transform: translateY(0.5px); }
.btn i { line-height: 1; }

/* Smaller variant — overrides the vars; the base .btn rule applies them. */
.btn-sm { --bs-btn-padding-y: .45rem; --bs-btn-padding-x: 1rem; --bs-btn-font-size: .85rem; --bs-btn-border-radius: .4rem; }

.btn-primary {
  --bs-btn-bg: var(--brand);
  --bs-btn-border-color: var(--brand);
  --bs-btn-hover-bg: var(--brand-press);
  --bs-btn-hover-border-color: var(--brand-press);
  --bs-btn-active-bg: var(--brand-press);
  --bs-btn-active-border-color: var(--brand-press);
  --bs-btn-disabled-bg: #c7d2fe;
  --bs-btn-disabled-border-color: #c7d2fe;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 1px 2px rgba(79, 70, 229, .25);
}
.btn-primary:hover { box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 4px 10px rgba(79, 70, 229, .3); }

.btn-light {
  --bs-btn-bg: #f1f5f9;
  --bs-btn-border-color: #f1f5f9;
  --bs-btn-color: var(--text);
  --bs-btn-hover-bg: #e2e8f0;
  --bs-btn-hover-border-color: #e2e8f0;
  --bs-btn-hover-color: var(--text);
  --bs-btn-active-bg: #cbd5e1;
}

/* The outline variants were retired — every button in the suite is now solid.
   Their rules were `--bs-btn-*` declarations, which this Bootstrap (5.0.2) does
   not read anyway, so nothing is lost by dropping them. The one exception was
   the outline-secondary focus treatment below, which carried real properties;
   it now applies to `.btn-secondary`, the class those buttons were renamed to,
   so all 211 secondary buttons share one focus style. */
.btn-secondary:focus-visible,
.btn-secondary.focus {
  border-color: var(--brand);
  box-shadow: var(--ring);
  color: var(--brand-press);
}

/* Solid tone-colored buttons: brand-consistent palette + inset highlight
   + colored ambient shadow that intensifies on hover. Matches the
   .btn-primary treatment so all tones feel like one family. */
.btn-danger {
  --bs-btn-bg: #dc2626;
  --bs-btn-border-color: #dc2626;
  --bs-btn-hover-bg: #b91c1c;
  --bs-btn-hover-border-color: #b91c1c;
  --bs-btn-active-bg: #b91c1c;
  --bs-btn-disabled-bg: #fca5a5;
  --bs-btn-disabled-border-color: #fca5a5;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 1px 2px rgba(220, 38, 38, .25);
}
.btn-danger:hover { box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 4px 10px rgba(220, 38, 38, .3); }

.btn-warning {
  --bs-btn-bg: #f59e0b;
  --bs-btn-border-color: #f59e0b;
  --bs-btn-color: #fff;
  --bs-btn-hover-bg: #d97706;
  --bs-btn-hover-border-color: #d97706;
  --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: #d97706;
  --bs-btn-active-color: #fff;
  --bs-btn-disabled-bg: #fde68a;
  --bs-btn-disabled-border-color: #fde68a;
  --bs-btn-disabled-color: #fff;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 1px 2px rgba(245, 158, 11, .25);
}
.btn-warning:hover { box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 4px 10px rgba(245, 158, 11, .3); }

.btn-success {
  --bs-btn-bg: #16a34a;
  --bs-btn-border-color: #16a34a;
  --bs-btn-hover-bg: #15803d;
  --bs-btn-hover-border-color: #15803d;
  --bs-btn-active-bg: #15803d;
  --bs-btn-disabled-bg: #86efac;
  --bs-btn-disabled-border-color: #86efac;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 1px 2px rgba(22, 163, 74, .25);
}
.btn-success:hover { box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 4px 10px rgba(22, 163, 74, .3); }

.btn-info {
  --bs-btn-bg: #0284c7;
  --bs-btn-border-color: #0284c7;
  --bs-btn-color: #fff;
  --bs-btn-hover-bg: #0369a1;
  --bs-btn-hover-border-color: #0369a1;
  --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: #0369a1;
  --bs-btn-active-color: #fff;
  --bs-btn-disabled-bg: #7dd3fc;
  --bs-btn-disabled-border-color: #7dd3fc;
  --bs-btn-disabled-color: #fff;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 1px 2px rgba(2, 132, 199, .25);
}
.btn-info:hover { box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset, 0 4px 10px rgba(2, 132, 199, .3); }


/* Square icon-only button — no text label, clean centered glyph. */
.btn-icon {
  --bs-btn-padding-x: 0;
  --bs-btn-padding-y: 0;
  width: 2.25rem;
  height: 2.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.btn-icon.btn-sm { width: 2rem; height: 2rem; font-size: .85rem; }
.btn-icon i.bi { line-height: 1; }

.btn-group .btn { border-radius: 0; }
.btn-group > .btn:first-child { border-top-left-radius: var(--bs-btn-border-radius); border-bottom-left-radius: var(--bs-btn-border-radius); }
.btn-group > .btn:last-child { border-top-right-radius: var(--bs-btn-border-radius); border-bottom-right-radius: var(--bs-btn-border-radius); }

/* Equal-width group — every button in the group takes the same width */
.btn-group-equal { display: inline-flex; }
.btn-group-equal > .btn { flex: 1 1 0; min-width: 100px; }

/* Icon-only buttons */
.btn > i.bi:only-child { display: inline-flex; align-items: center; justify-content: center; }

/* ------------------------------------------------------------- */
/* 6. Forms                                                      */
/* ------------------------------------------------------------- */
.form-label {
  font-size: .82rem;
  font-weight: 500;
  color: var(--text);
  margin-bottom: .35rem;
}

.form-text { font-size: .78rem; color: var(--muted); margin-top: .35rem; }

.form-control,
.form-select {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: .5rem .85rem;
  font-size: .9rem;
  line-height: 1.5;
  color: var(--text);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
  box-shadow: none;
}
.form-control::placeholder { color: var(--muted-soft); }
.form-control:hover,
.form-select:hover { border-color: #cbd5e1; }
.form-control:focus,
.form-select:focus {
  border-color: var(--brand);
  box-shadow: var(--ring);
  outline: none;
}
.form-control:disabled,
.form-select:disabled,
.form-control[readonly] {
  background-color: var(--surface-alt);
  color: var(--muted);
  cursor: not-allowed;
  border-color: var(--border-soft);
}

.form-control-sm, .form-select-sm { padding: .45rem .75rem; font-size: .85rem; border-radius: .4rem; }

textarea.form-control { padding: .65rem .85rem; resize: vertical; min-height: 6rem; }

.form-control.is-invalid,
.form-select.is-invalid {
  border-color: #dc2626;
  background-image: none;
  padding-right: .85rem;
}
.form-control.is-invalid:focus,
.form-select.is-invalid:focus { box-shadow: 0 0 0 3px rgba(220, 38, 38, .18); }
.invalid-feedback { font-size: .78rem; color: #dc2626; }

.form-control.is-valid,
.form-select.is-valid { border-color: #16a34a; background-image: none; padding-right: .85rem; }
.form-control.is-valid:focus { box-shadow: 0 0 0 3px rgba(22, 163, 74, .18); }
.valid-feedback { font-size: .78rem; color: #16a34a; }

/* Selects — custom caret + native option tint */
.form-select {
  /* default chevron */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%2364748b' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
  background-position: right .85rem center;
  background-size: 12px;
  padding-right: 2.5rem;
  /* tints the OS-native option highlight in Chrome / Edge / Safari */
  accent-color: var(--brand);
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}
.form-select:hover { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%234f46e5' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round' d='M2 4l4 4 4-4'/%3E%3C/svg%3E"); }
.form-select:focus { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%234f46e5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M2 4l4 4 4-4'/%3E%3C/svg%3E"); }
.form-select[multiple],
.form-select[size]:not([size="1"]) {
  background-image: none;
  padding-right: .85rem;
  cursor: default;
}

/* Native <option> — limited but honoured by most browsers */
.form-select option,
.form-select optgroup {
  font-family: inherit;
  font-size: .9rem;
  background-color: var(--surface);
  color: var(--text);
  padding: .5rem .75rem;
}
.form-select option:hover { background-color: var(--surface-alt); }
.form-select option:checked,
.form-select option:focus,
.form-select option[selected] {
  background: linear-gradient(0deg, var(--brand-soft), var(--brand-soft)), var(--surface);
  background-color: var(--brand-soft);
  color: var(--brand-press);
  font-weight: 500;
}
.form-select option:disabled { color: var(--muted-soft); }
.form-select optgroup {
  font-weight: 600;
  color: var(--muted);
  font-size: .72rem;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.form-select-sm { background-position: right .65rem center; background-size: 10px; padding-right: 2rem; }

/* Color & date inputs keep native look but match height */
input[type="color"].form-control { padding: .25rem; width: 3rem; cursor: pointer; }
input[type="file"].form-control { padding: .35rem .55rem; }
input[type="file"].form-control::file-selector-button {
  background: var(--surface-alt);
  border: 0;
  border-right: 1px solid var(--border);
  color: var(--text);
  font-weight: 500;
  margin: -.35rem .85rem -.35rem -.55rem;
  padding: .55rem .85rem;
  border-radius: 0;
}

/* Number inputs — hide the chunky native spinner arrows for a cleaner
   admin look. Users can still type freely; arrow keys still increment. */
input[type="number"].form-control { -moz-appearance: textfield; }
input[type="number"].form-control::-webkit-outer-spin-button,
input[type="number"].form-control::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Search inputs — restyle the native clear (X) so it matches the
   muted-soft palette instead of the OS-default heavy gray. */
input[type="search"].form-control::-webkit-search-cancel-button {
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  margin-left: .3rem;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%2394a3b8' d='M11.5 4.5L4.5 11.5M4.5 4.5L11.5 11.5' stroke='%2394a3b8' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat center / contain;
  cursor: pointer;
  opacity: .7;
  transition: opacity var(--t-fast) var(--ease);
}
input[type="search"].form-control::-webkit-search-cancel-button:hover { opacity: 1; }

/* Date / time inputs — make the native calendar/clock indicator subtle
   in rest, lift on hover (Chromium/Edge only — Firefox/Safari ignore). */
input[type="date"].form-control::-webkit-calendar-picker-indicator,
input[type="time"].form-control::-webkit-calendar-picker-indicator,
input[type="datetime-local"].form-control::-webkit-calendar-picker-indicator,
input[type="month"].form-control::-webkit-calendar-picker-indicator,
input[type="week"].form-control::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: .55;
  transition: opacity var(--t-fast) var(--ease);
  filter: invert(0); /* light-mode default; flipped under body.dark-mode in §17 */
}
input[type="date"].form-control:hover::-webkit-calendar-picker-indicator,
input[type="time"].form-control:hover::-webkit-calendar-picker-indicator,
input[type="datetime-local"].form-control:hover::-webkit-calendar-picker-indicator { opacity: .95; }

/* Input groups — feel like one unit */
.input-group { position: relative; }
.input-group-text {
  background-color: var(--surface);
  border-color: var(--border);
  color: var(--muted);
  font-size: .85rem;
}
.input-group:focus-within > .form-control,
.input-group:focus-within > .form-select,
.input-group:focus-within > .input-group-text,
.input-group:focus-within > .btn { border-color: var(--brand); }
.input-group:focus-within { box-shadow: var(--ring); border-radius: var(--radius); }
.input-group:focus-within > .form-control:focus,
.input-group:focus-within > .form-select:focus { box-shadow: none; }

/* Checkboxes & radios */
.form-check-input {
  border: 1.5px solid #cbd5e1;
  width: 1.1em;
  height: 1.1em;
  margin-top: .2em;
  transition: background-color var(--t-fast), border-color var(--t-fast), box-shadow var(--t-fast);
}
.form-check-input:hover { border-color: var(--brand); }
.form-check-input:checked {
  background-color: var(--brand);
  border-color: var(--brand);
}
.form-check-input:focus { box-shadow: var(--ring); border-color: var(--brand); }
.form-check-input[type="radio"]:checked { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='2' fill='%23fff'/%3E%3C/svg%3E"); }
.form-check-label { font-size: .9rem; color: var(--text); cursor: pointer; }

/* Only inside .form-check do we pull the input left into the label gutter */
.form-check { padding-left: 1.7em; min-height: 1.4rem; }
.form-check .form-check-input { margin-left: -1.7em; }

/* ------------------------------------------------------------- */
/* 7. Tables                                                     */
/* ------------------------------------------------------------- */
.table {
  --bs-table-bg: transparent;
  --bs-table-border-color: var(--border-soft);
  --bs-table-hover-bg: var(--hover-row);
  margin-bottom: 0;
  color: var(--text);
  font-size: .9rem;
}
.table > :not(caption) > * > * {
  padding: 1rem 1.25rem;
  border-bottom-width: 1px;
  vertical-align: middle;
}
.table thead th {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--surface-alt) !important;
  border-bottom: 1px solid var(--border) !important;
  border-top: 0 !important;
  padding-top: .85rem;
  padding-bottom: .85rem;
  white-space: nowrap;
}
.table > tbody > tr {
  transition: background var(--t-fast) var(--ease);
  line-height: 1.55;
}
.table > tbody > tr > * { font-size: inherit; }
/* Every text node inside a cell — sub-labels, links, codes, divs — picks up
   the cell font-size. Hierarchy comes from color (.text-secondary) and
   weight (.fw-semibold), not size. */
.table > tbody > tr > * .small,
.table > tbody > tr > * small,
.table > tbody > tr > * .fs-6,
.table > tbody > tr > * div,
.table > tbody > tr > * a,
.table > tbody > tr > * span:not(.badge):not(.method):not(.stat-icon):not(.file-icon):not(.user-avatar-circle) {
  font-size: inherit;
}
.table > tbody > tr > * code { font-size: inherit; }

.table tbody tr:hover { background: var(--hover-row); }
.table tbody tr:last-child > td { border-bottom: 0; }
.table.thead-light thead th,
.table .bg-light { background: var(--surface-alt) !important; }
.table th, .table td { border-color: var(--border-soft); }

/* Density variants */
.table-sm { font-size: .82rem; }
.table-sm > :not(caption) > * > * { padding: .65rem .85rem; }

/* table-responsive — keep card corners rounded */
.card > .table-responsive,
.card > .table-responsive > .table { border-radius: inherit; }
.card > .table-responsive { overflow: hidden auto; }
.table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-responsive::-webkit-scrollbar { height: 8px; }
.table-responsive::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }

/* Tighter horizontal padding on small screens so 5+ columns don't get   */
/* clipped on a 360-px viewport.                                          */
@media (max-width: 575.98px) {
  .table > :not(caption) > * > * { padding: .75rem .85rem; }
  .table thead th { padding-top: .65rem; padding-bottom: .65rem; }
  .table { font-size: .82rem; }
}

/* DataTables controls — top length/search bar + bottom info/pagination. */
.dataTables_wrapper {
  padding: 0;
}
.dataTables_wrapper .row:first-child,
.dataTables_wrapper .row:last-child {
  padding: .85rem 1.25rem;
  margin: 0;
  align-items: center;
}
.dataTables_wrapper .row:first-child { border-bottom: 1px solid var(--border-soft); }
.dataTables_wrapper .row:last-child  { border-top:    1px solid var(--border-soft); }
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter,
.dataTables_wrapper .dataTables_info { font-size: .82rem; color: var(--muted); }
.dataTables_wrapper .dataTables_length label,
.dataTables_wrapper .dataTables_filter label { margin-bottom: 0; display: inline-flex; align-items: center; gap: .5rem; }
.dataTables_wrapper .dataTables_length select { width: auto; padding: .3rem 1.85rem .3rem .6rem; }
.dataTables_wrapper .dataTables_filter input { width: 14rem; max-width: 100%; }
@media (max-width: 575.98px) {
  .dataTables_wrapper .row:first-child > div,
  .dataTables_wrapper .row:last-child  > div { text-align: left !important; padding-bottom: .35rem; }
  .dataTables_wrapper .dataTables_filter input { width: 100%; }
}

/* Pagination — Bootstrap default look + tighter spacing on table footers.
   Page items render as squares (min-width = height) so single-digit pages and
   the « ‹ › » chevrons all sit in equal-sized boxes. Multi-digit pages widen
   horizontally as needed but keep the same height. */
.pagination { margin-bottom: 0; gap: .4rem; }
.page-link {
  border-radius: var(--radius);
  border-color: var(--border);
  color: var(--text);
  min-width: 2.25rem;
  height: 2.25rem;
  padding: 0 .5rem;
  font-size: .85rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.page-link:hover { background: var(--surface-alt); color: var(--brand-press); border-color: var(--border); }
.page-item.active .page-link { background: var(--brand); border-color: var(--brand); color: #fff; }
.page-link .bi { font-size: 1em; line-height: 1; }

/* ------------------------------------------------------------- */
/* 7b. Charts & sparklines                                       */
/* Wrappers that give a Chart.js canvas explicit height so        */
/* `responsive: true, maintainAspectRatio: false` works.          */
/* ------------------------------------------------------------- */
.chart-wrap    { position: relative; height: 240px; }
.chart-wrap-sm { position: relative; height: 180px; }
.chart-wrap-lg { position: relative; height: 340px; }
@media (max-width: 575.98px) {
  .chart-wrap    { height: 200px; }
  .chart-wrap-lg { height: 260px; }
}

/* Inline CSS-only mini bar chart (e.g. 7-day request volume on
   endpoint detail page). Bars set their own height inline. */
.spark {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 60px;
  width: 100%;
}
.spark > span,
.spark > div {
  flex: 1 1 0;
  min-width: 2px;
  background: var(--brand);
  opacity: .8;
  border-radius: 2px;
  transition: opacity var(--t-fast) var(--ease);
}
.spark > span:hover,
.spark > div:hover { opacity: 1; }

/* ------------------------------------------------------------- */
/* 8. Badges                                                     */
/* ------------------------------------------------------------- */
.badge {
  font-weight: 600;
  letter-spacing: .01em;
  border-radius: .375rem;
  padding: .3em .55em;
  font-size: .72rem;
  line-height: 1.2;
  vertical-align: middle;
}

/* DEV / PROD mode badge — letter-spaced for that "STATUS" feel.
   Size inherits from base .badge (0.72rem); add `.badge-mode` for the spacing. */
.badge-mode { letter-spacing: .05em; }

.bg-success-subtle { background-color: #dcfce7 !important; }
.bg-warning-subtle { background-color: #fef3c7 !important; }
.bg-danger-subtle  { background-color: #fee2e2 !important; }
.bg-info-subtle    { background-color: #dbeafe !important; }
.bg-primary-subtle { background-color: #ede9fe !important; }
.bg-secondary-subtle { background-color: #f1f5f9 !important; }

/* Solid colored dot — used for state indicators (health probe OK/fail,
   live activity). Combine with bg-X (success/danger/etc.) for color. */
.badge-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  padding: 0;
  border-radius: 50%;
  vertical-align: middle;
  flex-shrink: 0;
}

/* ------------------------------------------------------------- */
/* 9. Nav · tabs · pills                                          */
/* ------------------------------------------------------------- */
.nav-tabs {
  --bs-nav-tabs-border-color: var(--border);
  --bs-nav-tabs-border-radius: 0;
  border-bottom-width: 1px;
}
.nav-tabs .nav-link {
  color: var(--muted);
  font-weight: 500;
  font-size: .9rem;
  border: 0;
  padding: .65rem .9rem;
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
}
.nav-tabs .nav-link:hover { color: var(--text); border-bottom-color: var(--border); background: transparent; }
.nav-tabs .nav-link.active { color: var(--brand); border-bottom-color: var(--brand); background: transparent; }

.nav-pills {
  --bs-nav-pills-border-radius: var(--radius);
  --bs-nav-pills-link-active-bg: var(--brand);
  gap: 4px;
}
.nav-pills .nav-link { color: var(--text); font-weight: 500; font-size: .9rem; padding: .5rem .8rem; }
.nav-pills .nav-link:hover { background: var(--surface-alt); color: var(--text); }
.nav-pills .nav-link.active { color: #fff; }
/* Panel tab pills (grant editors, modules, effective): active tab keeps the
   normal text colour — only a soft tint + weight marks it, no white-on-fill. */
.panel-tabs .nav-link { color: var(--text); }
.panel-tabs .nav-link.active { background: var(--brand-soft); color: var(--text); font-weight: 600; }

/* ------------------------------------------------------------- */
/* 10. Modal · offcanvas · toast                                  */
/* ------------------------------------------------------------- */
.modal-content { border: 0; border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); }
.modal-header { border-bottom-color: var(--border-soft); padding: 1.1rem 1.25rem; }
.modal-footer { border-top-color: var(--border-soft); padding: 1rem 1.25rem; gap: .35rem; }
.modal-title { font-size: 1.05rem; font-weight: 600; }
.modal-backdrop.show { opacity: .55; }

.offcanvas { border: 0 !important; }
.offcanvas-header { border-bottom: 1px solid var(--border-soft); }

.toast { border-radius: var(--radius); box-shadow: var(--shadow); }

/* ------------------------------------------------------------- */
/* 11. Alerts                                                    */
/* Admin-Bootstrap pattern: leading icon at top-left of each      */
/* alert, body content flows with extra left padding. Absolute    */
/* positioning so it works for simple text AND structured alerts  */
/* (alert-heading, <pre>, multi-line content).                    */
/* ------------------------------------------------------------- */
.alert {
  border: 0;
  border-radius: var(--radius);
  padding: .85rem 1rem .85rem 2.65rem;
  font-size: .9rem;
  position: relative;
}
.alert::before {
  position: absolute;
  left: 1rem;
  top: .95rem;
  font-family: 'bootstrap-icons' !important;
  font-style: normal;
  font-weight: normal;
  font-size: 1.05rem;
  line-height: 1;
  display: inline-block;
}
.alert-info    { background: #eff6ff; color: #1e3a8a; }
.alert-warning { background: #fffbeb; color: #78350f; }
.alert-danger  { background: #fef2f2; color: #991b1b; }
.alert-success { background: #f0fdf4; color: #166534; }
.alert-light   { background: var(--surface-alt); color: var(--text); }

.alert-info::before    { content: '\f430'; } /* bi-info-circle-fill */
.alert-warning::before { content: '\f33a'; } /* bi-exclamation-triangle-fill */
.alert-danger::before  { content: '\f622'; } /* bi-x-circle-fill */
.alert-success::before { content: '\f26a'; } /* bi-check-circle-fill */
.alert-light::before   { content: '\f431'; } /* bi-info-circle (outlined for muted look) */

/* The custom .alert padding above sets right padding to 1rem, which clobbers
   Bootstrap's .alert-dismissible padding-right:3rem — so the absolute close
   button overlaps long text. Re-reserve room on the right for the X button. */
.alert-dismissible { padding-right: 2.75rem; }
.alert-dismissible .btn-close { padding: .9rem 1rem; }

/* Opt-out of the leading ::before marker for a specific alert (pass
   'icon' => false to the alert partial). Drops the icon + its reserved gap. */
.alert.alert-no-icon { padding-left: 1rem; }
.alert.alert-no-icon::before { content: none; }

/* ------------------------------------------------------------- */
/* 12. Common utilities                                          */
/* ------------------------------------------------------------- */
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .85rem; }

/* Micro text — sub-meta lines beneath primary content (slug under name,
   actor · time under action label, timestamps, secondary tier labels). */
.text-micro { font-size: .72rem; }

/* Flexbox child that needs to truncate — Bootstrap has no utility for this.
   Pair with .text-truncate on a descendant to clamp text inside a flex row. */
.min-w-0 { min-width: 0; }

/* In-card section subhead — smaller, less-prominent than .section-title.
   Used inside framework widgets, server panels, etc. for secondary groupings. */
.subhead {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-weight: 600;
}

/* Mini section header used inside form cards (Admin-Bootstrap input.html). */
.section-title {
  font-size: .75rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
  margin-bottom: 1rem;
}

/* Reset uppercase + letter-spacing inherited from a parent (.section-title
   etc.) for an inline span. Used on SdkAuth info "(secret)" sub-label. */
.normal-case {
  text-transform: none;
  letter-spacing: 0;
}

/* ----- JS-hook classes (no styling — markers for app.js / inline JS) -----
   .dash-live           — dashboard live in-flight cells (poller updates text)
   .ep-live             — Endpoints index live in-flight cells (same poller)
   .repo-copy-label     — Gradle-user form copy-button label span (swaps to "Copied")
   These intentionally have no CSS rule. JS toggles their visibility via
   .d-none / textContent updates. Don't add styling — that's their contract.
   --------------------------------------------------------------------- */

.snippet {
  background: var(--code-bg);
  color: var(--code-fg);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .82rem;
  line-height: 1.6;
  position: relative;
  overflow: auto;
}
.snippet .copy { position: absolute; top: .5rem; right: .5rem; }

/* Transparent <pre> for command-output dumps (no bg, no padding) —
   used in dummy_data result alerts. */
.pre-output {
  white-space: pre-wrap;
  font-size: .78rem;
  max-height: 420px;
  overflow: auto;
  background: transparent;
  border: 0;
  padding: 0;
}

/* Inline-detail <pre> for audit JSON / context blobs — subtle bg, padded,
   sits inside a card row. */
.pre-details {
  white-space: pre-wrap;
  max-width: 100%;
  background: var(--surface-alt);
  padding: .5rem;
  border-radius: .35rem;
}

.meta-row {
  padding: .85rem 0;
  border-bottom: 1px solid var(--border-soft);
  display: grid;
  grid-template-columns: 180px 1fr;
  gap: 1rem;
}
.meta-row:last-child { border-bottom: 0; }
.meta-row .label { color: var(--muted); font-size: .85rem; }
@media (max-width: 767.98px) { .meta-row { grid-template-columns: 1fr; gap: .25rem; } }

/* Initials circle — used by the topbar user dropdown (trigger + menu header) */
.user-avatar-circle {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: -.02em;
  flex-shrink: 0;
}
.user-avatar-circle.user-avatar-lg {
  width: 44px;
  height: 44px;
  font-size: 1rem;
}

/* HTTP method tags */
.method {
  font-weight: 700;
  font-size: .7rem;
  letter-spacing: .04em;
  padding: .25rem .55rem;
  border-radius: 4px;
  display: inline-block;
}
.m-get   { background: #dcfce7; color: #166534; }
.m-post  { background: #dbeafe; color: #1e40af; }
.m-put   { background: #fef3c7; color: #92400e; }
.m-patch { background: #ede9fe; color: #5b21b6; }
.m-del, .m-delete { background: #fee2e2; color: #991b1b; }
.m-head  { background: #ede9fe; color: #5b21b6; }

/* File icon — used on Repository artifact detail header. */
.file-icon { width: 40px; height: 40px; border-radius: 10px; display: inline-flex; align-items: center; justify-content: center; font-size: 1.1rem; }
.file-icon-lg { width: 64px; height: 64px; border-radius: 14px; font-size: 1.6rem; display: inline-flex; align-items: center; justify-content: center; }

/* ------------------------------------------------------------- */
/* 13. Auth / error chrome                                       */
/* ------------------------------------------------------------- */
.auth-bg {
  min-height: 100vh;
  background:
    radial-gradient(circle at 20% 10%, rgba(255, 255, 255, .12) 0, transparent 30%),
    radial-gradient(circle at 80% 80%, rgba(255, 255, 255, .08) 0, transparent 40%),
    linear-gradient(135deg, var(--brand) 0%, var(--brand-2) 100%);
  display: flex; align-items: center; justify-content: center;
  padding: 2rem 1rem;
}
.auth-bg-soft {
  min-height: 100vh;
  background: var(--bg);
  display: flex; align-items: center; justify-content: center;
  padding: 2rem 1rem;
}
.auth-card {
  max-width: 460px;
  width: 100%;
  border: 0;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.error-code {
  font-size: clamp(5rem, 18vw, 11rem);
  font-weight: 800;
  line-height: 1;
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.error-code.error-500 {
  background: linear-gradient(135deg, #dc2626, #f59e0b);
  -webkit-background-clip: text; background-clip: text;
}

/* ------------------------------------------------------------- */
/* 14. Responsive                                                */
/* ------------------------------------------------------------- */
@media (max-width: 991.98px) {
  .content { padding: 1rem; }

}
@media (max-width: 575.98px) {
  .content { padding: .85rem .75rem; }
  .meta-row { padding-top: 1rem; padding-bottom: 1rem; }
  /* Smaller hero on small screens                                     */
  h4.fw-bold, h5.fw-bold { font-size: 1.1rem; }
}

/* ------------------------------------------------------------- */
/* 15. Motion · print                                             */
/* ------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

@media print {
  .btn, .pagination, .form-control, .form-select { display: none !important; }
  .content { padding: 0; }
  .card { box-shadow: none; border: 1px solid var(--border) !important; break-inside: avoid; }
  a[href]::after { content: " (" attr(href) ")"; font-size: .8em; color: #444; }
}

/* ------------------------------------------------------------- */
/* 16. Scrollbars                                                */
/* Thin styled scrollbars applied globally (Webkit + Firefox).    */
/* Per-component rules in §3 (.sidebar) and §7 (.table-responsive)*/
/* keep their tighter widths via higher selector specificity.     */
/* ------------------------------------------------------------- */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--muted-soft) transparent;
}
*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
*::-webkit-scrollbar-track {
  background: transparent;
}
*::-webkit-scrollbar-thumb {
  background-color: var(--muted-soft);
  border-radius: 8px;
  /* 2px transparent border creates a visual gutter so the thumb
     doesn't touch the track edges — looks more refined. */
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover {
  background-color: var(--muted);
}
*::-webkit-scrollbar-corner {
  background: transparent;
}

/* ------------------------------------------------------------- */
/* 17. Dark mode                                                 */
/* Activated by `<html data-bs-theme="dark">` + `body.dark-mode`.*/
/* The data-bs-theme attribute auto-darkens Bootstrap's own      */
/* tokens (dropdowns, modals, tables, btn-close, etc.). The      */
/* `body.dark-mode` rules below override our custom design tokens*/
/* and the few hardcoded utility colors that don't go through BS.*/
/* ------------------------------------------------------------- */
body.dark-mode {
  --bg: #0b1220;
  --surface: #131c2c;
  --surface-alt: #1a2336;
  --text: #e2e8f0;
  --muted: #94a3b8;
  --muted-soft: #64748b;

  --border: #1f2a3d;
  --border-soft: #1a2336;
  --hover-row: #1a2336;

  /* sidebar — keep it dark but slightly lighter than bg so it has presence */
  --sidebar-bg: #0a0f1c;
  --sidebar-fg: #cbd5e1;

  --code-bg: #050b18;
  --code-fg: #e2e8f0;

  --brand-soft: rgba(129, 140, 248, .18);
  --brand-ring: rgba(129, 140, 248, .35);

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .35);
  --shadow:    0 4px 14px rgba(0, 0, 0, .45);
  --shadow-lg: 0 20px 50px rgba(0, 0, 0, .55);
}

/* Cards / inputs pick up via tokens, but the explicit white/light bgs need help. */
body.dark-mode .card { background: var(--surface); }
body.dark-mode .card-header,
body.dark-mode .card-footer { border-color: var(--border-soft); background: transparent; }

body.dark-mode .form-control,
body.dark-mode .form-select {
  background-color: var(--surface);
  border-color: var(--border);
  color: var(--text);
}
body.dark-mode .form-control::placeholder { color: var(--muted-soft); }
body.dark-mode .form-control:hover,
body.dark-mode .form-select:hover { border-color: #334155; }
body.dark-mode .form-control:disabled,
body.dark-mode .form-control[readonly],
body.dark-mode .form-select:disabled { background-color: var(--surface-alt); color: var(--muted); }
body.dark-mode .input-group-text {
  background-color: var(--surface-alt);
  border-color: var(--border);
  color: var(--muted);
}
body.dark-mode input[type="file"].form-control::file-selector-button {
  background: var(--surface-alt);
  border-right-color: var(--border);
  color: var(--text);
}

/* Select chevron — recolor for dark contrast */
body.dark-mode .form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%2394a3b8' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
}

/* Checkboxes — bump the unchecked border so they read on dark */
body.dark-mode .form-check-input { border-color: #475569; }

/* btn-light → dark-tinted neutral */
body.dark-mode .btn-light {
  --bs-btn-bg: var(--surface-alt);
  --bs-btn-border-color: var(--surface-alt);
  --bs-btn-color: var(--text);
  --bs-btn-hover-bg: #233048;
  --bs-btn-hover-border-color: #233048;
  --bs-btn-hover-color: var(--text);
  --bs-btn-active-bg: #2c3a55;
}
body.dark-mode .btn-primary { --bs-btn-disabled-bg: #3730a3; --bs-btn-disabled-border-color: #3730a3; }

/* Table — header/border tokens flow through, but bg-light cells need help */
body.dark-mode .table thead.bg-light,
body.dark-mode .table thead th.bg-light,
body.dark-mode .table .bg-light { background-color: var(--surface-alt) !important; }
body.dark-mode .table-responsive::-webkit-scrollbar-thumb { background: #334155; }

/* Subtle badge backgrounds — re-derive with dark palette */
body.dark-mode .bg-success-subtle   { background-color: rgba(34, 197, 94, .15) !important; }
body.dark-mode .bg-warning-subtle   { background-color: rgba(234, 179, 8, .15) !important; }
body.dark-mode .bg-danger-subtle    { background-color: rgba(239, 68, 68, .15) !important; }
body.dark-mode .bg-info-subtle      { background-color: rgba(59, 130, 246, .18) !important; }
body.dark-mode .bg-primary-subtle   { background-color: rgba(129, 140, 248, .18) !important; }
body.dark-mode .bg-secondary-subtle { background-color: rgba(148, 163, 184, .15) !important; }
body.dark-mode .bg-light-subtle     { background-color: var(--surface-alt) !important; }

/* Text-X colors on dark — slightly lighter so subtle bg+text combos stay readable */
body.dark-mode .text-success { color: #4ade80 !important; }
body.dark-mode .text-warning { color: #fbbf24 !important; }
body.dark-mode .text-danger  { color: #f87171 !important; }
body.dark-mode .text-info    { color: #60a5fa !important; }
body.dark-mode .text-primary { color: #a5b4fc !important; }
body.dark-mode .text-secondary { color: var(--muted) !important; }

/* Bare bg-light utility (used for code blocks, table thead, etc.) */
body.dark-mode .bg-light { background-color: var(--surface-alt) !important; }

/* Alerts — re-derive with dark, muted backgrounds */
body.dark-mode .alert-info    { background: rgba(59, 130, 246, .12); color: #93c5fd; }
body.dark-mode .alert-warning { background: rgba(234, 179, 8, .12);  color: #fcd34d; }
body.dark-mode .alert-danger  { background: rgba(239, 68, 68, .12);  color: #fca5a5; }
body.dark-mode .alert-success { background: rgba(34, 197, 94, .12);  color: #86efac; }
body.dark-mode .alert-light   { background: var(--surface-alt); color: var(--text); }

/* HTTP method tags + reason tags */
body.dark-mode .m-get   { background: rgba(34, 197, 94, .18); color: #86efac; }
body.dark-mode .m-post  { background: rgba(59, 130, 246, .18); color: #93c5fd; }
body.dark-mode .m-put   { background: rgba(234, 179, 8, .18); color: #fcd34d; }
body.dark-mode .m-patch,
body.dark-mode .m-head  { background: rgba(167, 139, 250, .18); color: #c4b5fd; }
body.dark-mode .m-del,
body.dark-mode .m-delete { background: rgba(239, 68, 68, .18); color: #fca5a5; }

/* Confirm-modal modal & dropdowns — BS5 auto-handles via data-bs-theme,
   but the dropdown shadow needs to read on dark backgrounds */
body.dark-mode .dropdown-menu { box-shadow: var(--shadow); }
body.dark-mode .modal-content { box-shadow: var(--shadow-lg); }

/* Code element on dark — lift contrast */
body.dark-mode code { color: #fca5a5; }

/* Auth-bg-soft (used by 404 page when on dark) — flip to dark surface */
body.dark-mode .auth-bg-soft { background: var(--bg); }


/* Progress bars stay visible on dark surface */
body.dark-mode .progress { background-color: var(--surface-alt); }

/* Pagination — BS5 handles dark via data-bs-theme; just nudge active */
body.dark-mode .page-link { background-color: var(--surface); border-color: var(--border); color: var(--text); }
body.dark-mode .page-link:hover { background-color: var(--surface-alt); color: var(--text); }
body.dark-mode .page-item.active .page-link { background-color: var(--brand); border-color: var(--brand); color: #fff; }
body.dark-mode .page-item.disabled .page-link { background-color: var(--surface); color: var(--muted-soft); }

/* Global scrollbars in dark mode — darker thumb on dark page bg */
body.dark-mode { scrollbar-color: #334155 transparent; }
body.dark-mode *::-webkit-scrollbar-thumb { background-color: #334155; }
body.dark-mode *::-webkit-scrollbar-thumb:hover { background-color: #475569; }

/* Native date/time picker icons render as black SVG by default — flip to
   white on dark backgrounds so they stay visible. */
body.dark-mode input[type="date"].form-control::-webkit-calendar-picker-indicator,
body.dark-mode input[type="time"].form-control::-webkit-calendar-picker-indicator,
body.dark-mode input[type="datetime-local"].form-control::-webkit-calendar-picker-indicator,
body.dark-mode input[type="month"].form-control::-webkit-calendar-picker-indicator,
body.dark-mode input[type="week"].form-control::-webkit-calendar-picker-indicator {
  filter: invert(1) brightness(.85);
}

/* Search clear-X in dark mode — slate-400 instead of muted-soft */
body.dark-mode input[type="search"].form-control::-webkit-search-cancel-button {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%2394a3b8' d='M11.5 4.5L4.5 11.5M4.5 4.5L11.5 11.5' stroke='%23cbd5e1' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------- */
/* 18. Toast stack                                                */
/* Lightweight, CSP-friendly feedback for small "Copied" /        */
/* "Saved" confirmations — replaces window.alert().               */
/* Injected by app.js into <body> on first window.toast() call.   */
/* ------------------------------------------------------------- */
.toast-stack {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 1080;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  pointer-events: none;
}
.toast-item {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding: .55rem .9rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  font-size: .85rem;
  font-weight: 500;
  min-width: 12rem;
  max-width: 22rem;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--t-base) var(--ease), transform var(--t-base) var(--ease);
  pointer-events: auto;
}
.toast-item.show { opacity: 1; transform: translateY(0); }
.toast-item i { font-size: 1rem; line-height: 1; flex-shrink: 0; }
.toast-primary i { color: var(--brand); }
.toast-success i { color: #16a34a; }
.toast-warning i { color: #f59e0b; }
.toast-danger  i { color: #dc2626; }
body.dark-mode .toast-item { background: var(--surface); color: var(--text); border-color: var(--border); }

/* Play · Tom Select combobox → Bootstrap .form-select parity (downloads / reviews). */
.ts-wrapper.single .ts-control {
    min-height: calc(1.5em + 1rem + 2px);
    padding: 0.5rem 2.25rem 0.5rem 0.85rem;
    font-size: 0.9rem;
    font-weight: 400;
    line-height: 1.5;
    color: var(--bs-body-color, #212529);
    background-color: var(--bs-body-bg, #fff);
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    background-size: 16px 12px;
    border: var(--bs-border-width, 1px) solid var(--bs-border-color, #dee2e6);
    border-radius: var(--bs-border-radius, 0.375rem);
    box-shadow: none;
}
.ts-wrapper.single .ts-control:after { display: none !important; }
.ts-wrapper.single.input-active .ts-control { background: var(--bs-body-bg, #fff); }
.ts-wrapper.focus .ts-control,
.ts-wrapper .ts-control:focus-within {
    border-color: #86b7fe;
    box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
    outline: 0;
}
.ts-wrapper.disabled .ts-control { background-color: var(--bs-secondary-bg, #e9ecef); }
.ts-dropdown {
    margin-top: 0.125rem;
    padding: 0.25rem 0;
    font-size: 0.9rem;
    color: var(--bs-body-color, #212529);
    background-color: var(--bs-body-bg, #fff);
    border: var(--bs-border-width, 1px) solid var(--bs-border-color, #dee2e6);
    border-radius: var(--bs-border-radius, 0.375rem);
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
.ts-dropdown .ts-dropdown-content { padding: 0; }
.ts-dropdown .option {
    padding: 0.60rem 0.75rem !important;
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--bs-body-color, #212529);
}
.ts-dropdown .option > div { padding: 0 !important; }
.ts-dropdown .option img { width: 18px; height: 18px; }
.ts-dropdown .option:hover,
.ts-dropdown .option.active { background-color: var(--bs-tertiary-bg, #f8f9fa); color: var(--bs-body-color, #212529); }
.ts-dropdown .option.selected { background-color: var(--bs-secondary-bg, #e9ecef); }
.ts-dropdown .no-results,
.ts-dropdown .optgroup-header { padding: 0.375rem 0.75rem; color: var(--bs-secondary-color, #6c757d); }


/* ===========================================================================
   PART B · skin + console shell        (was custom.css)
   Everything below overrides or extends PART A above.
   =========================================================================== */
/* ===========================================================================
   custom.css  ·  Syphnosys UI — "Editorial Slate" redesign (Direction 1b)
   ---------------------------------------------------------------------------
   Loaded AFTER app.css. Scoped under the `.sui-app` root class on <body>, so
   it reskins the existing Bootstrap markup app-wide by re-pointing the theme
   tokens and overriding a handful of structural component rules. app.css is
   never modified — remove the <link> to fully revert.

   Conventions:
     · every NEW class is prefixed  .sui-*
     · every NEW variable is prefixed  --sui-*
     · the app's existing theme tokens (--brand/--bg/--border/…) are re-pointed
       *scoped to .sui-app* so base components reskin without editing app.css
     · typography stays Inter (self-hosted); code/mono keeps the app mono stack
   =========================================================================== */

/* ------------------------------------------------------------------ */
/* 0. Tokens — re-point the theme + define the sui palette (scoped)    */
/* ------------------------------------------------------------------ */
.sui-app {
  /* sui palette */
  --sui-bg:          #fbfbfc;
  --sui-surface:     #ffffff;
  --sui-surface-alt: #f4f5f7;
  --sui-ink:         #12151c;   /* primary action + heading ink        */
  --sui-ink-press:   #23262e;
  --sui-text:        #12151c;
  --sui-nav-fg:      #4b5563;   /* sidebar menu item (non-active)      */
  --sui-muted:       #7a828e;
  --sui-muted-soft:  #9aa1ac;
  --sui-border:      #e7e9ee;
  --sui-border-soft: #eef0f3;
  --sui-input-border: #d3d7de;  /* form-control / select / ts-control resting border */
  --sui-hover:       #f7f8fa;
  --sui-accent:      #2563eb;   /* links / focus                       */
  --sui-accent-press:#1d4ed8;
  --sui-success:     #16a34a;
  --sui-danger:      #e11d48;
  --sui-warning:     #b45309;
  --sui-info:        #0d9bc4;
  --sui-pink:        #ff2d78;   /* logo                                */
  --sui-cyan:        #12b5e5;   /* logo                                */
  --sui-r-sm:        6px;
  --sui-r:           8px;
  --sui-r-lg:        10px;
  --sui-r-xl:        14px;
  --sui-shadow-sm:   0 1px 2px rgba(16, 24, 40, .05);
  --sui-shadow:      0 1px 2px rgba(16, 24, 40, .06), 0 12px 30px -18px rgba(16, 24, 40, .30);

  /* re-point the app/Bootstrap theme tokens so base rules follow suit */
  --brand:        var(--sui-accent);
  --brand-2:      var(--sui-cyan);
  --brand-soft:   rgba(37, 99, 235, .10);
  --brand-ring:   rgba(37, 99, 235, .22);
  --brand-press:  var(--sui-accent-press);
  --bg:           var(--sui-bg);
  --surface:      var(--sui-surface);
  --surface-alt:  var(--sui-surface-alt);
  --text:         var(--sui-text);
  --muted:        var(--sui-muted);
  --muted-soft:   var(--sui-muted-soft);
  --border:       var(--sui-border);
  --border-soft:  var(--sui-border-soft);
  --hover-row:    var(--sui-hover);
  --radius:       var(--sui-r);
  --radius-lg:    var(--sui-r-lg);

  --bs-primary:      var(--sui-accent);
  --bs-link-color:   var(--sui-accent);
  --bs-link-hover-color: var(--sui-accent-press);
  --bs-body-bg:      var(--sui-bg);
  --bs-body-color:   var(--sui-text);
}

/* ------------------------------------------------------------------ */
/* 1. Base                                                            */
/* ------------------------------------------------------------------ */
.sui-app { background: var(--sui-bg); color: var(--sui-text); }
.sui-app a { color: var(--sui-accent); }
.sui-app a:hover { color: var(--sui-accent-press); }
.sui-app .text-primary { color: var(--sui-accent) !important; }
.sui-app .text-secondary { color: var(--sui-muted) !important; }
.sui-app .content { padding: 1.4rem 1.6rem 3rem; }
/* Constrain page width like the design's 1160px column */
.sui-app .content > .sui-wrap,
.sui-app .content { }
.sui-mono { font-family: var(--bs-font-monospace); }
/* ------------------------------------------------------------------ */
/* 3. Buttons — primary → ink                                         */
/* ------------------------------------------------------------------ */
.sui-app .btn { letter-spacing: 0; font-weight: 600; }
.sui-app .btn-primary {
  --bs-btn-bg: var(--sui-ink); --bs-btn-border-color: var(--sui-ink);
  --bs-btn-hover-bg: var(--sui-ink-press); --bs-btn-hover-border-color: var(--sui-ink-press);
  --bs-btn-active-bg: var(--sui-ink-press); --bs-btn-active-border-color: var(--sui-ink-press);
  --bs-btn-disabled-bg: var(--sui-muted-soft); --bs-btn-disabled-border-color: var(--sui-muted-soft);
  /* Text is --sui-surface (white in light, dark in dark) so it always contrasts
     the ink button — which itself inverts to a light button in dark mode. */
  --bs-btn-color: var(--sui-surface); --bs-btn-hover-color: var(--sui-surface); --bs-btn-active-color: var(--sui-surface);
  background: var(--sui-ink); border-color: var(--sui-ink); color: var(--sui-surface);
  box-shadow: none;
}
.sui-app .btn-primary:hover,
.sui-app .btn-primary:focus { background: var(--sui-ink-press); border-color: var(--sui-ink-press); color: var(--sui-surface); box-shadow: none; }
.sui-app .btn-secondary {
  --bs-btn-color: var(--sui-text);
  background: var(--sui-surface); border: 1px solid var(--sui-input-border); color: var(--sui-text);
}
.sui-app .btn-secondary:hover { background: var(--sui-surface-alt); border-color: var(--sui-muted-soft); color: var(--sui-text); }

/* ------------------------------------------------------------------ */
/* 4. Cards                                                           */
/* ------------------------------------------------------------------ */
.sui-app .card { border: 1px solid var(--sui-border); border-radius: var(--sui-r-lg); box-shadow: var(--sui-shadow-sm); }
.sui-app .card-header { border-bottom: 1px solid var(--sui-border); background: transparent; font-weight: 600; }
.sui-app .card-header h6 { font-weight: 700; }

/* ------------------------------------------------------------------ */
/* 5. Stat tiles — clean bordered tile, no icon, big tabular number    */
/* ------------------------------------------------------------------ */
.sui-app .stat-card,
.sui-app .stat-card-primary, .sui-app .stat-card-warning,
.sui-app .stat-card-danger,  .sui-app .stat-card-success, .sui-app .stat-card-info {
  background: var(--sui-surface) !important;
  border: 1px solid var(--sui-border); border-radius: var(--sui-r-lg);
  padding: .9rem 1.05rem; box-shadow: none;
}
.sui-app .stat-card::after { display: none; }
.sui-app .stat-card .stat-icon { display: none; }
.sui-app .stat-card .text-secondary.small:first-child {
  text-transform: uppercase; letter-spacing: .5px; font-weight: 700;
  font-size: .66rem; color: var(--sui-muted-soft);
}
.sui-app .stat-card .h4 {
  font-size: 1.65rem; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--sui-text); margin-top: .1rem;
}
.sui-app a.stat-card:hover {
  border-color: var(--sui-input-border); box-shadow: var(--sui-shadow-sm);
  background: var(--sui-surface) !important; transform: none;
}

/* sui native tile grid (for bespoke dashboard rows) */
.sui-tiles { display: grid; grid-template-columns: repeat(4, 1fr); border: 1px solid var(--sui-border); border-radius: var(--sui-r-lg); overflow: hidden; background: var(--sui-surface); }
.sui-tile { padding: 14px 16px; border-right: 1px solid var(--sui-border-soft); }
.sui-tile:last-child { border-right: 0; }
.sui-tile-label { font-size: 10.5px; color: var(--sui-muted-soft); font-weight: 700; letter-spacing: .4px; text-transform: uppercase; }
.sui-tile-num { font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.3; color: var(--sui-text); }
.sui-tile-num.is-good { color: var(--sui-success); }
.sui-tile-num.is-bad  { color: var(--sui-danger); }
.sui-tile-sub { font-size: 11px; color: var(--sui-muted-soft); }

/* ------------------------------------------------------------------ */
/* 6. Tables — borderless, dense, uppercase micro headers             */
/* ------------------------------------------------------------------ */
.sui-app .table { --bs-table-bg: transparent; margin-bottom: 0; }
.sui-app .table > thead th,
.sui-app .table thead.bg-light th {
  background: transparent !important; border-bottom: 1px solid var(--sui-border);
  text-transform: uppercase; letter-spacing: .5px; font-size: .66rem; font-weight: 700;
  color: var(--sui-muted-soft); padding-top: .6rem; padding-bottom: .6rem; white-space: nowrap;
}
.sui-app .table > tbody > tr > td { border-color: var(--sui-border-soft); font-size: .86rem; vertical-align: middle; }
.sui-app .table > tbody > tr:last-child > td { border-bottom: 0; }
.sui-app .table > tbody > tr:hover { background: var(--sui-hover); }
.sui-app .table code { color: var(--sui-text); }

/* status dot */
.sui-dot { display: inline-flex; align-items: center; gap: .35rem; font-size: .78rem; font-weight: 600; }
.sui-dot::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.sui-dot.is-active { color: var(--sui-success); }
.sui-dot.is-off    { color: var(--sui-muted-soft); }

/* ------------------------------------------------------------------ */
/* 7. Forms                                                           */
/* ------------------------------------------------------------------ */
.sui-app .form-label { font-weight: 600; font-size: .78rem; color: #4a515c; }
.sui-app .form-control, .sui-app .form-select { border-color: var(--sui-input-border); border-radius: var(--sui-r); color: var(--sui-text); }
.sui-app .form-control::placeholder { color: var(--sui-muted-soft); }
.sui-app .form-control:focus, .sui-app .form-select:focus { border-color: var(--sui-accent); box-shadow: 0 0 0 3px var(--brand-ring); }

/* ------------------------------------------------------------------ */
/* 8. Badges & pills (body content)                                   */
/* ------------------------------------------------------------------ */
.sui-app .badge { font-weight: 600; border-radius: var(--sui-r-sm); }
.sui-badge { display: inline-flex; align-items: center; gap: .3rem; font-size: .7rem; font-weight: 700; letter-spacing: .3px; text-transform: uppercase; padding: .28em .6em; border-radius: var(--sui-r-sm); border: 1px solid currentColor; background: transparent; }
.sui-badge.is-super  { color: var(--sui-danger); }
.sui-badge.is-admin  { color: var(--sui-accent); }
.sui-badge.is-muted  { color: var(--sui-muted); }

/* ------------------------------------------------------------------ */
/* 9. Alerts                                                          */
/* ------------------------------------------------------------------ */
.sui-app .alert { border-radius: var(--sui-r-lg); border: 1px solid transparent; font-size: .9rem; }
.sui-app .alert-success { background: #ecfdf3; border-color: #b7ecc9; color: #0f6b3a; }
.sui-app .alert-danger  { background: #fef2f2; border-color: #fecdd3; color: #9f1239; }
.sui-app .alert-warning { background: #fffbeb; border-color: #fde68a; color: #92600b; }
.sui-app .alert-info    { background: #eff6ff; border-color: #bfdbfe; color: #1e40af; }

/* ------------------------------------------------------------------ */
/* 10. Dropdowns · pagination · modals                                */
/* ------------------------------------------------------------------ */
.sui-app .dropdown-menu { border: 1px solid var(--sui-border); border-radius: var(--sui-r-lg); box-shadow: var(--sui-shadow); }
.sui-app .page-link { color: var(--sui-text); border-color: var(--sui-border); }
.sui-app .page-item.active .page-link { background: var(--sui-ink); border-color: var(--sui-ink); color: #fff; }
.sui-app .modal-content { border: 1px solid var(--sui-border); border-radius: var(--sui-r-xl); box-shadow: var(--sui-shadow); }

/* ------------------------------------------------------------------ */
/* 11. Page header (shared partial)                                   */
/* ------------------------------------------------------------------ */
.sui-page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; margin-bottom: 1.1rem; }
.sui-page-head h1, .sui-page-head .h1 { font-size: 1.45rem; font-weight: 700; letter-spacing: -.02em; margin: 0; }
.sui-page-head p { font-size: .82rem; color: var(--sui-muted); margin: .2rem 0 0; }

/* ------------------------------------------------------------------ */
/* 12. Auth screens (login / forgot / reset / 2fa)                    */
/* ------------------------------------------------------------------ */
.sui-auth { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 40px 16px; background: var(--sui-bg); }
.sui-auth-card { width: 100%; max-width: 400px; background: var(--sui-surface); border: 1px solid var(--sui-border); border-radius: var(--sui-r-xl); padding: 34px; box-shadow: var(--sui-shadow); }
.sui-auth-head { display: flex; flex-direction: column; align-items: center; text-align: center; margin-bottom: 22px; }
.sui-auth-logo { width: 30px; height: 30px; margin-bottom: 12px; }
.sui-auth-title { font-size: 1.4rem; font-weight: 700; letter-spacing: -.02em; color: var(--sui-text); }
.sui-auth-sub { font-size: .8rem; color: var(--sui-muted); margin-top: 4px; }
.sui-auth-foot { border-top: 1px solid var(--sui-border-soft); padding-top: 14px; margin-top: 16px; text-align: center; font-size: .74rem; color: var(--sui-muted-soft); }
/* nowrap + shrink-to-fit so all 6 cells stay on one row even in the 400px auth card */
.sui-otp { display: flex; gap: 8px; justify-content: center; flex-wrap: nowrap; }
.sui-otp-cell { flex: 0 1 44px; width: 44px; min-width: 0; height: 52px; text-align: center; font-size: 22px; font-weight: 700; color: var(--sui-text); border: 1.5px solid var(--sui-input-border); border-radius: 9px; background: var(--sui-surface); font-family: inherit; padding: 0; }
.sui-otp-cell:focus { border-color: var(--sui-ink); outline: none; box-shadow: none; }
.sui-otp-cell.is-filled { border-color: var(--sui-ink); }
/* setup-URI paste block on 2FA enroll */
.sui-uri { font-family: var(--bs-font-monospace); font-size: .68rem; color: var(--sui-muted); word-break: break-all; background: var(--sui-hover); border: 1px solid var(--sui-border-soft); border-radius: 7px; padding: 8px 10px; line-height: 1.5; }
/* reskin the existing standalone auth markup (.auth-bg-soft / .auth-card) */
.sui-app .auth-bg-soft { background: var(--sui-bg); min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 16px; }
.sui-app .auth-card { max-width: 400px; width: 100%; border: 1px solid var(--sui-border); border-radius: var(--sui-r-xl); box-shadow: var(--sui-shadow); }
/* Auth headings track the design's 21px title (Bootstrap h3 is too large here) */
.sui-app .auth-card h3 { font-size: 1.35rem; letter-spacing: -.02em; }
.sui-app .input-group-text { background: var(--sui-surface); border-color: var(--sui-input-border); color: var(--sui-muted-soft); }
.sui-auth-logo { width: 30px; height: 30px; }

/* ------------------------------------------------------------------ */
/* 13. Access-control hub — vertical "access pipeline" flow            */
/*    A single card whose rows are the six ordered steps, linked by a  */
/*    connector rail so "top to bottom, each builds on the last" reads */
/*    literally. Row = [rail(number) | body(title+desc) | side(count + */
/*    open)]. New .sui-flow-* classes; reuses the --sui-* tokens.       */
/* ------------------------------------------------------------------ */
.sui-flow { background: var(--sui-surface); border: 1px solid var(--sui-border); border-radius: var(--sui-r-lg); box-shadow: var(--sui-shadow-sm); overflow: hidden; }
.sui-flow-step { display: grid; grid-template-columns: 56px 1fr auto; align-items: center; padding: 16px 18px 16px 0; }
.sui-flow-step + .sui-flow-step { border-top: 1px solid var(--sui-border-soft); }
.sui-flow-step:hover { background: var(--sui-hover); }
/* Rail: centered number badge with a 2px connector line threading each
   step to the next; trimmed to a half-line at the first/last rows. */
.sui-flow-rail { align-self: stretch; display: flex; justify-content: center; position: relative; }
.sui-flow-rail::before { content: ''; position: absolute; left: 50%; top: -16px; bottom: -16px; width: 2px; transform: translateX(-50%); background: var(--sui-border); }
.sui-flow-step:first-child .sui-flow-rail::before { top: 14px; }
.sui-flow-step:last-child  .sui-flow-rail::before { bottom: auto; height: 14px; }
.sui-flow-n { width: 26px; height: 26px; margin-top: 1px; border-radius: 8px; background: var(--sui-ink); color: var(--sui-surface); font-size: 12px; font-weight: 700; display: flex; align-items: center; justify-content: center; position: relative; z-index: 1; }
.sui-flow-body { min-width: 0; padding-right: 16px; }
.sui-flow-title { font-size: .92rem; font-weight: 700; color: var(--sui-text); }
.sui-flow-desc { font-size: .8rem; color: var(--sui-muted); line-height: 1.5; margin-top: 2px; }
.sui-flow-side { display: flex; align-items: center; gap: 18px; }
.sui-flow-count { text-align: right; }
.sui-flow-count b { display: block; font-size: 1.15rem; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; color: var(--sui-text); }
.sui-flow-count span { font-size: 10px; font-weight: 600; letter-spacing: .4px; text-transform: uppercase; color: var(--sui-muted-soft); }
.sui-flow-go { display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: 0 13px; border: 1px solid var(--sui-input-border); border-radius: var(--sui-r); background: var(--sui-surface); color: var(--sui-text); font-size: 12.5px; font-weight: 600; white-space: nowrap; }
.sui-flow-step:hover .sui-flow-go { border-color: var(--sui-ink); color: var(--sui-ink); }

/* Inline callout note — info / warn / success / danger (design's colored boxes) */
.sui-note { display: flex; gap: .6rem; border-radius: var(--sui-r-lg); padding: .7rem .85rem; font-size: .82rem; line-height: 1.5; border: 1px solid transparent; margin-bottom: 1rem; }
.sui-note .sui-note-ico { flex: none; margin-top: 1px; }
.sui-note.is-info    { background: #eff6ff; border-color: #bfdbfe; color: #1e40af; }
.sui-note.is-warn    { background: #fffbeb; border-color: #fde68a; color: #92600b; }
.sui-note.is-success { background: #ecfdf3; border-color: #b7ecc9; color: #0f6b3a; }
.sui-note.is-danger  { background: #fef2f2; border-color: #fecdd3; color: #9f1239; }
.sui-note b { color: inherit; }
.sui-note code { font-family: var(--bs-font-monospace); }
/* Validation summary bullets inside a note (design uses "·" markers) */
.sui-note-list { list-style: none; padding: 0; margin: .3rem 0 0; }
.sui-note-list li { position: relative; padding-left: .75rem; }
.sui-note-list li::before { content: '·'; position: absolute; left: 0; font-weight: 700; }

/* Per-field validation state — red 1.5px border + inline message under the field */
.sui-app .form-control.is-invalid,
.sui-app .form-select.is-invalid { border-color: #f43f5e; border-width: 1.5px; background-image: none; padding-right: .85rem; }
.sui-field-err { font-size: .7rem; color: var(--sui-danger); margin-top: 4px; }
/* Design constrains single-column forms rather than letting them span the page */
.sui-form-narrow { max-width: 520px; }
.sui-form-wide   { max-width: 560px; }

/* Read-only/locked field (design shows a padlock inside a muted field) */
.sui-locked {
  border: 1px solid var(--sui-border-soft); background: var(--sui-hover); border-radius: var(--sui-r);
  padding: .5rem .7rem; font-family: var(--bs-font-monospace); font-size: .8rem; color: var(--sui-muted-soft);
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
}
/* Mono record-id chip beside an edit-screen title */
.sui-id-chip { font-family: var(--bs-font-monospace); font-size: .7rem; font-weight: 400; color: var(--sui-muted-soft); margin-left: .4rem; }

/* 46px tinted status circle used on confirmation / dead-end auth cards */
.sui-ico-circle {
  width: 46px; height: 46px; border-radius: 50%; display: flex;
  align-items: center; justify-content: center; margin: 0 auto 16px; font-size: 1.25rem;
}
.sui-ico-circle.is-success { background: #ecfdf3; color: var(--sui-success); }
.sui-ico-circle.is-danger  { background: #fef2f2; color: var(--sui-danger); }
.sui-ico-circle.is-info    { background: #eff6ff; color: var(--sui-accent); }

/* Danger zone card (design 43) — rose border + rose heading */
.sui-app .sui-danger-zone { border-color: #fecdd3; }
.sui-app .sui-danger-zone .card-header { border-bottom-color: #fecdd3; }
.sui-app .sui-danger-zone .card-header h6 { color: #9f1239; }
.sui-app .sui-danger-zone .card-body p { color: var(--sui-muted); }

/* Destructive-confirm modal: icon tile + tinted footer (design 71) */
.sui-modal-ico {
  width: 38px; height: 38px; border-radius: 9px; flex: none;
  display: flex; align-items: center; justify-content: center; font-size: 1rem;
}
.sui-modal-ico.is-danger { background: color-mix(in srgb, var(--sui-danger) 14%, transparent);  color: var(--sui-danger); }
.sui-modal-ico.is-warn   { background: color-mix(in srgb, var(--sui-warning) 16%, transparent); color: var(--sui-warning); }
.sui-app .sui-modal-foot { background: var(--surface-alt); border-top: 1px solid var(--sui-border-soft); }

/* Rich empty state (icon tile + heading + copy + CTA) */
.sui-empty { text-align: center; padding: 2.5rem 1.25rem; }
.sui-empty-ico {
  width: 48px; height: 48px; border-radius: 12px; background: #f0f9ff; color: var(--sui-info);
  display: flex; align-items: center; justify-content: center; margin: 0 auto .85rem; font-size: 1.35rem;
}
.sui-empty h6 { font-weight: 700; margin-bottom: .35rem; }
.sui-empty p { font-size: .82rem; color: var(--sui-muted); max-width: 30rem; margin: 0 auto 1rem; line-height: 1.55; }

/* 4-segment password strength meter (design: 3px bars, 4px gap) */
.sui-meter { display: flex; gap: 4px; }
.sui-meter span { flex: 1; height: 3px; border-radius: 2px; background: var(--sui-border); transition: background .15s var(--ease, ease); }
.sui-meter span.on { background: var(--sui-success); }
.sui-meter.lvl-1 span.on { background: var(--sui-danger); }
.sui-meter.lvl-2 span.on { background: var(--sui-warning); }

/* Key-value detail rows (profile, audit detail) */
.sui-kv { display: grid; grid-template-columns: 140px 1fr; padding: 9px 0; border-bottom: 1px solid var(--sui-border-soft); font-size: .82rem; }
.sui-kv:last-child { border-bottom: 0; }
.sui-kv > .k { color: var(--sui-muted-soft); }
.sui-kv > .v { color: var(--sui-text); }
.sui-kv > .v.mono { font-family: var(--bs-font-monospace); font-size: .78rem; color: #4a515c; }

/* Current-session row highlight on the sessions table */
.sui-app tr.sui-row-current > td,
.sui-app .sui-row-current { background: #f0fdf4 !important; }

/* ------------------------------------------------------------------ */
/* 13a. 404 page + notifications dropdown                             */
/* ------------------------------------------------------------------ */
.sui-404 { font-size: 4.5rem; font-weight: 700; letter-spacing: -2px; color: var(--sui-ink); line-height: 1; }

/* Dropdown panel */
.sui-app .sui-notif-menu { width: 340px; max-width: 92vw; padding: 0; border: 1px solid var(--sui-border); border-radius: 12px; box-shadow: 0 20px 44px -18px rgba(0, 0, 0, .35); overflow: hidden; }
.sui-notif-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 15px; border-bottom: 1px solid var(--sui-border-soft); }
.sui-notif-head b { font-size: .82rem; font-weight: 700; color: var(--sui-text); }
.sui-notif-head a { font-size: .72rem; font-weight: 500; }
.sui-notif-item { display: flex; gap: 10px; padding: 12px 15px; border-bottom: 1px solid #f4f5f7; text-decoration: none; }
.sui-notif-item:last-of-type { border-bottom: 0; }
.sui-notif-item.is-unread { background: #f7fbff; }
.sui-notif-item:hover { background: var(--sui-hover); }
.sui-notif-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--sui-accent); flex: none; margin-top: 5px; }
.sui-notif-item.is-read .sui-notif-dot { background: transparent; }
.sui-notif-title { font-size: .78rem; color: var(--sui-text); font-weight: 500; }
.sui-notif-meta { font-size: .68rem; color: var(--sui-muted-soft); margin-top: 2px; }
.sui-notif-empty { padding: 22px 15px; text-align: center; font-size: .78rem; color: var(--sui-muted-soft); }
.sui-notif-foot { display: block; text-align: center; padding: 11px; font-size: .75rem; font-weight: 600; border-top: 1px solid var(--sui-border-soft); background: #fbfbfc; }
/* Pin the panel to the navbar's right edge (design 70) rather than under the
   toggle. The <li> goes position:static so the menu's containing block becomes
   the sticky .top-nav; Popper is off via data-bs-display="static" on the toggle.
   Desktop only — the collapsed navbar keeps the normal anchored dropdown. */
@media (min-width: 992px) {
  .sui-app .sui-notif-menu { position: absolute; top: 100%; right: 22px; left: auto; margin-top: 0; }
}

/* ------------------------------------------------------------------ */
/* 13b. Refinements — status dots · outlined action icons · ink bars   */
/* ------------------------------------------------------------------ */
/* Status pills from active_badge() → understated dot + label. Targeted
   at the exact class pairs the helper emits so count/other subtle
   badges (e.g. ".bg-secondary-subtle.text-dark") are left untouched. */
.sui-app .badge.bg-success-subtle.text-success,
.sui-app .badge.bg-secondary-subtle.text-secondary {
  background: transparent !important; padding: 0; font-weight: 600; font-size: .8rem;
  display: inline-flex; align-items: center; gap: .38rem; border-radius: 0;
}
.sui-app .badge.bg-success-subtle.text-success::before,
.sui-app .badge.bg-secondary-subtle.text-secondary::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none;
}
.sui-app .badge.bg-success-subtle.text-success   { color: var(--sui-success) !important; }
.sui-app .badge.bg-secondary-subtle.text-secondary { color: var(--sui-muted-soft) !important; }

/* Row action buttons → neutral outlined squares; delete/enable tinted. */
.sui-app .btn-icon {
  background: var(--sui-surface); border: 1px solid var(--sui-border);
  color: var(--sui-muted); box-shadow: none; border-radius: var(--sui-r-sm);
}
.sui-app .btn-icon:hover { background: var(--sui-surface-alt); border-color: var(--sui-input-border); color: var(--sui-text); }
.sui-app .btn-icon.btn-danger  { border-color: #fecdd3; color: var(--sui-danger); background: var(--sui-surface); }
.sui-app .btn-icon.btn-danger:hover  { background: #fef2f2; border-color: #fca5b4; color: var(--sui-danger); }
.sui-app .btn-icon.btn-success { border-color: #bbf7d0; color: var(--sui-success); background: var(--sui-surface); }
.sui-app .btn-icon.btn-success:hover { background: #ecfdf3; border-color: #86efac; color: var(--sui-success); }

/* Dashboard "Top actions" bars → ink; failure actions → red. */
.sui-app .progress-bar.bg-primary { background-color: var(--sui-ink) !important; }
.sui-app .progress-bar.sui-bar-bad { background-color: var(--sui-danger) !important; }

/* ------------------------------------------------------------------ */
/* 14. Responsive                                                     */
/* ------------------------------------------------------------------ */
@media (max-width: 991.98px) {
  .sui-tiles { grid-template-columns: repeat(2, 1fr); }
  .sui-tile:nth-child(2n) { border-right: 0; }
}
@media (max-width: 575.98px) {
  .sui-tiles { grid-template-columns: 1fr; }
  .sui-tile { border-right: 0; border-bottom: 1px solid var(--sui-border-soft); }
  /* stack the pipeline row's count + Open button so a narrow viewport doesn't
     crush the middle column */
  .sui-flow-side { flex-direction: column; align-items: flex-end; gap: 8px; }
}

/* ------------------------------------------------------------------ */
/* 15. Tom Select — searchable / scrollable selects                    */
/* Long <select> lists (> 8 options) are upgraded in layout_footer.php  */
/* to a type-to-filter dropdown. Restyle the vendor widget to match the */
/* sui form-control look, and cap the list at ~10 rows before scroll.   */
/* ------------------------------------------------------------------ */
/* The control (closed state) mirrors .form-control / .form-select */
.sui-app .ts-wrapper { font-size: .9rem; }
.sui-app .ts-control {
  background: var(--sui-surface);
  border: 1px solid var(--sui-input-border);
  border-radius: var(--sui-r);
  color: var(--sui-text);
  min-height: 42px;
  padding: .45rem 2.25rem .45rem .85rem;
  box-shadow: none;
}
.sui-app .ts-wrapper.single .ts-control {
  /* native-select style caret on the right */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%237a828e' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .85rem center;
  background-size: 12px;
}
.sui-app .ts-control:hover { border-color: var(--sui-muted-soft); }
.sui-app .ts-wrapper.focus .ts-control {
  border-color: var(--sui-accent);
  box-shadow: 0 0 0 3px var(--brand-ring);
}
.sui-app .ts-control input,
.sui-app .ts-control .item { color: var(--sui-text); font-family: inherit; }
.sui-app .ts-control input::placeholder { color: var(--sui-muted-soft); }

/* Dropdown panel */
.sui-app .ts-dropdown {
  background: var(--sui-surface);
  border: 1px solid var(--sui-border);
  border-radius: var(--sui-r-lg);
  box-shadow: var(--sui-shadow);
  margin-top: 6px;
  overflow: hidden;
  padding: 6px;
  /* Widen past the (often narrow) control so long codes like
     "session.revoked.ua_mismatch" read on one line instead of wrapping. */
  min-width: 240px;
}
/* ~10 rows tall, then scroll (each option ≈ 40px) */
.sui-app .ts-dropdown .ts-dropdown-content {
  max-height: 400px;
  overflow-y: auto;
}
.sui-app .ts-dropdown .option {
  display: flex;
  align-items: center;    /* vertically center the label regardless of padding */
  height: 38px;
  padding: 0 .7rem !important;  /* override the vendor's vertical padding for an exact 38px row */
  border-radius: var(--sui-r-sm);
  color: var(--sui-text);
  font-size: .875rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sui-app .ts-dropdown .option:hover,
.sui-app .ts-dropdown .option.active {
  background: var(--sui-hover);
  color: var(--sui-text);
}
.sui-app .ts-dropdown .option.selected {
  color: var(--sui-accent);
  font-weight: 600;
  background: transparent;
}
.sui-app .ts-dropdown .no-results {
  padding: 1rem .7rem;
  text-align: center;
  color: var(--sui-muted-soft);
  font-size: .82rem;
}
.sui-app .ts-dropdown .ts-dropdown-content::-webkit-scrollbar { width: 10px; }
.sui-app .ts-dropdown .ts-dropdown-content::-webkit-scrollbar-thumb {
  background: var(--sui-input-border); border-radius: 6px; border: 3px solid var(--sui-surface);
}

/* NOTE on validation: no rule is needed here. Tom Select copies the original
   select's className onto its wrapper, so the wrapper ends up carrying BOTH
   `form-select` and `is-invalid` — and the existing `.sui-app .form-select.is-invalid`
   rule then paints the rose border on it. Verified in the DOM: the wrapper has
   `ts-wrapper form-select is-invalid single …` and a 1px rose border, while the
   inner `.ts-control` has no border at all.
   That class copying is also why several `.sui-app .ts-control` rules below are
   weaker than they look: vendor selectors of the form `.ts-wrapper.form-select
   .ts-control` score (0,3,0) and outrank them at (0,2,0). Worth an audit before
   relying on any measurement in that block. */

/* Disabled — without this the vendor skin's `--bs-secondary-bg` shows through,
   which is not a colour this theme defines. Match `.form-control:disabled`. */
.sui-app .ts-wrapper.disabled .ts-control {
  background: var(--sui-surface-alt);
  color: var(--sui-muted-soft);
  border-color: var(--sui-border-soft);
  cursor: not-allowed;
}

/* Multi-select chips — nothing uses these yet, but Tom Select supports multi and
   the suite has obvious candidates (collaborators, phase tags, app assignment).
   Styled now so the first one built matches the rest of the product instead of
   inheriting the vendor's Bootstrap 5 look. */
.sui-app .ts-wrapper.multi .ts-control .item {
  background: var(--sui-surface-alt);
  border: 1px solid var(--sui-border);
  border-radius: var(--sui-r-sm);
  color: var(--sui-text);
  padding: 2px 7px;
  font-size: .78rem;
}
.sui-app .ts-wrapper.multi .ts-control .item .remove {
  color: var(--sui-muted-soft);
  border-left-color: var(--sui-border);
}
.sui-app .ts-wrapper.multi .ts-control .item.active {
  background: color-mix(in srgb, var(--sui-accent) 12%, transparent);
  border-color: color-mix(in srgb, var(--sui-accent) 30%, transparent);
  color: var(--sui-accent);
}

/* Dark mode — follow app.css dark tokens so the widget doesn't glow white */
body.dark-mode .sui-app .ts-control,
body.dark-mode .ts-control {
  background: var(--surface); border-color: #334155; color: var(--text);
}
body.dark-mode .sui-app .ts-dropdown,
body.dark-mode .ts-dropdown {
  background: var(--surface); border-color: var(--border);
}
body.dark-mode .ts-dropdown .option { color: var(--text); }
body.dark-mode .ts-dropdown .option:hover,
body.dark-mode .ts-dropdown .option.active { background: var(--surface-alt); }

/* ===========================================================================
   CONSOLE SHELL — Phase 1 redesign (sidebar + slim topbar).
   Presentational only; reuses the --sui-* tokens above. The old .top-nav rules
   are now dead. Dark theme is opt-in via html[data-theme="dark"].
   =========================================================================== */
.sui-app { overflow: hidden; }
.sui-shell {
  --sbw: 248px;
  display: grid;
  grid-template-columns: var(--sbw) 1fr;
  grid-template-rows: 56px 1fr;
  grid-template-areas: "brand top" "side main";
  height: 100vh;
}
html[data-collapsed="1"] .sui-shell { --sbw: 66px; }

/* Brand cell */
.sui-brand {
  grid-area: brand; display: flex; align-items: center; gap: 9px; padding: 0 16px;
  background: var(--surface); border-right: 1px solid var(--border); border-bottom: 1px solid var(--border);
  color: var(--sui-ink); font-weight: 700; letter-spacing: -.02em; text-decoration: none;
  overflow: hidden; white-space: nowrap;
}
.sui-logo { width: 24px; height: 24px; flex: none; }
html[data-collapsed="1"] .sui-brand-name { display: none; }

/* Topbar */
.sui-top {
  grid-area: top; display: flex; align-items: center; gap: 7px; padding: 0 14px;
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.sui-top-spacer { flex: 1; }
.sui-icon-btn {
  width: 36px; height: 36px; display: inline-grid; place-items: center; border-radius: 8px;
  color: var(--sui-muted); border: none; background: none; cursor: pointer; font-size: 16px;
}
.sui-icon-btn:hover { background: var(--sui-hover); color: var(--sui-text); }
.sui-search {
  display: flex; align-items: center; gap: 9px; height: 36px; padding: 0 12px;
  min-width: 170px; max-width: 340px; flex: 1;
  background: var(--sui-surface-alt); border: 1px solid var(--border); border-radius: 8px;
  color: var(--sui-muted); font-size: 13px; cursor: pointer;
}
.sui-search:hover { border-color: var(--sui-muted-soft); }
.sui-search-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sui-kbd {
  margin-left: auto; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11px;
  color: var(--sui-muted-soft); border: 1px solid var(--border); border-radius: 5px; padding: 1px 6px; background: var(--surface);
}

/* Notification bell (shared partial): show icon + badge, hide the text label. */
.sui-top-bell { list-style: none; margin: 0; padding: 0; display: flex; }
.sui-top-bell .nav-link { position: relative; width: 36px; height: 36px; display: grid; place-items: center; border-radius: 8px; color: var(--sui-muted); font-size: 0; }
.sui-top-bell .nav-link:hover, .sui-top-bell .nav-link.active { background: var(--sui-hover); color: var(--sui-text); }
.sui-top-bell .nav-link i { font-size: 17px; margin: 0 !important; }
.sui-top-bell .sui-notif-count { position: absolute; top: 2px; right: 1px; font-size: 10px !important; padding: 1px 5px; line-height: 1.25; }

/* Theme toggle icon swap */
.sui-theme-light { display: none; }
html[data-theme="dark"] .sui-theme-dark { display: none; }
html[data-theme="dark"] .sui-theme-light { display: inline; }

/* User menu button */
.sui-user-btn { display: flex; align-items: center; gap: 8px; height: 36px; padding: 0 8px 0 6px; border-radius: 8px; color: var(--sui-text); border: none; background: none; cursor: pointer; }
.sui-user-btn:hover { background: var(--sui-hover); }
.sui-avatar { width: 28px; height: 28px; border-radius: 50%; background: linear-gradient(135deg, var(--sui-pink), var(--sui-accent)); color: #fff; display: grid; place-items: center; font-size: 11px; font-weight: 650; flex: none; }
.sui-user-name { font-weight: 560; font-size: 13.5px; }
.sui-role { font-size: 10.5px !important; font-weight: 650 !important; text-transform: capitalize; padding: 2px 7px !important; }
.sui-user-caret { font-size: 12px; color: var(--sui-muted); }

/* Dropdown menus (restyle Bootstrap) */
.sui-menu { border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--sui-shadow); padding: 6px; min-width: 224px; background: var(--surface); margin-top: 6px; }
.sui-menu .dropdown-item { display: flex; align-items: center; gap: 10px; border-radius: 8px; padding: 8px 10px; font-size: 13px; font-weight: 500; color: var(--sui-text); }
.sui-menu .dropdown-item:hover, .sui-menu .dropdown-item:focus { background: var(--sui-hover); color: var(--sui-text); }
.sui-menu .dropdown-item i { color: var(--sui-muted); font-size: 15px; width: 17px; text-align: center; }
.sui-menu .dropdown-divider { border-color: var(--sui-border-soft); margin: 5px 2px; }
.sui-menu-label { font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--sui-muted-soft); padding: 8px 10px 6px; }
.sui-signout { color: var(--sui-danger) !important; }
.sui-signout:hover { background: color-mix(in srgb, var(--sui-danger) 12%, transparent) !important; }
.sui-signout i { color: var(--sui-danger) !important; }

/* User menu header */
.sui-umenu { min-width: 252px; }
.sui-umenu-head { display: flex; align-items: center; gap: 10px; padding: 8px 10px 10px; }
.sui-umenu-head .sui-avatar { width: 36px; height: 36px; font-size: 13px; }
.sui-umenu-id { display: flex; flex-direction: column; min-width: 0; }
.sui-umenu-name { font-weight: 650; color: var(--sui-ink); font-size: 13.5px; }
.sui-umenu-mail { font-size: 12px; color: var(--sui-muted); overflow: hidden; text-overflow: ellipsis; }

/* Panel switcher */
.sui-pmenu { min-width: 300px; }
.sui-pgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; padding: 2px; }
.sui-pcard { display: flex; align-items: center; gap: 9px; padding: 9px; border-radius: 9px; border: 1px solid var(--sui-border-soft); color: var(--sui-text); text-decoration: none; }
.sui-pcard:hover { background: var(--sui-hover); border-color: var(--sui-muted-soft); }
.sui-pcard.is-current { background: var(--sui-hover); }
.sui-pcard-ico { width: 30px; height: 30px; border-radius: 8px; display: grid; place-items: center; font-weight: 700; font-size: 13px; flex: none; background: color-mix(in srgb, var(--sui-accent) 14%, transparent); color: var(--sui-accent); }
.sui-pcard-meta { display: flex; flex-direction: column; min-width: 0; }
.sui-pcard-name { font-weight: 600; color: var(--sui-ink); font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sui-pcard-role { font-size: 11px; color: var(--sui-muted); text-transform: capitalize; }
.sui-here { font-size: 9.5px; font-weight: 700; text-transform: uppercase; color: var(--sui-accent); background: color-mix(in srgb, var(--sui-accent) 14%, transparent); padding: 0 5px; border-radius: 5px; margin-left: 4px; }

/* Sidebar */
.sui-side { grid-area: side; background: var(--surface); border-right: 1px solid var(--border); overflow: hidden; }
.sui-side-body { overflow-y: auto; padding: 12px 12px 20px; display: flex; flex-direction: column; height: 100%; }
.sui-nav-group { margin-top: 14px; }
.sui-nav-group:first-child { margin-top: 2px; }
.sui-nav-label { padding: 6px 10px 4px; font-size: 10.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--sui-muted-soft); }
html[data-collapsed="1"] .sui-nav-label { height: 8px; opacity: 0; padding: 0; overflow: hidden; }
.sui-nav-item { display: flex; align-items: center; gap: 11px; padding: 8px 10px; border-radius: 8px; color: var(--sui-text); font-weight: 520; text-decoration: none; white-space: nowrap; position: relative; }
.sui-nav-item:hover { background: var(--sui-hover); }
.sui-nav-item i { color: var(--sui-muted); font-size: 16px; width: 18px; text-align: center; flex: none; }
.sui-nav-item.active { background: color-mix(in srgb, var(--sui-accent) 10%, transparent); color: var(--sui-accent); font-weight: 600; }
.sui-nav-item.active i { color: var(--sui-accent); }
.sui-nav-item.active::before { content: ""; position: absolute; left: -12px; top: 7px; bottom: 7px; width: 3px; border-radius: 0 3px 3px 0; background: var(--sui-accent); }
/* Sidebar menu color/size. Scoped with `.sui-side` (0,2,0) so it beats the
   global `.sui-app a` link color (0,1,1) that otherwise paints every item blue.
   Non-active: muted-slate, 14px/500. Active: dark-ink bold on a neutral gray
   pill (no accent) — monochrome, so the current page reads by weight+fill. */
.sui-side .sui-nav-item { color: var(--sui-nav-fg); font-size: 15px; font-weight: 500; }
.sui-side .sui-nav-item.active { color: var(--sui-ink); font-weight: 600; background: color-mix(in srgb, var(--sui-ink) 8%, transparent); }
.sui-side .sui-nav-item.active i { color: var(--sui-ink); }
.sui-side .sui-nav-item.active::before { background: var(--sui-ink); }
/* Hover: darken slate→ink (a clean affordance) and, crucially, override the
   global `.sui-app a:hover` blue-link color that otherwise leaks in on hover. */
.sui-side .sui-nav-item:hover { color: var(--sui-ink); }
.sui-side .sui-nav-item:hover i { color: var(--sui-ink); }
/* Pill tabs (Modules / Users-edit / Security-hub / Access-workspace / grant
   selectors) share the sidebar's active treatment: dark-ink bold on a neutral
   gray pill — instead of the default blue-tinted pill. */
.sui-app .panel-tabs .nav-link.active,
.sui-app .nav-pills .nav-link.active {
  background: color-mix(in srgb, var(--sui-ink) 8%, transparent);
  color: var(--sui-ink);
  font-weight: 600;
}
.sui-app .panel-tabs .nav-link.active i { color: var(--sui-ink); }
/* Tab hover — same light-gray pill + ink text as the sidebar hover (one step
   lighter than the active pill), so tabs and sidebar behave identically. */
.sui-app .panel-tabs .nav-link:hover,
.sui-app .nav-pills .nav-link:not(.active):hover { background: var(--sui-hover); color: var(--sui-ink); }
html[data-collapsed="1"] .sui-nav-item { justify-content: center; padding: 9px; }
html[data-collapsed="1"] .sui-nav-item span { display: none; }
.sui-side-foot { margin-top: auto; padding: 10px; font-size: 11.5px; color: var(--sui-muted-soft); display: flex; align-items: center; gap: 8px; }
html[data-collapsed="1"] .sui-side-foot span { display: none; }

/* Main content area */
.sui-app .sui-main.content { grid-area: main; overflow-y: auto; padding: 22px 26px 40px; background: var(--sui-bg); }
.sui-foot { padding: 22px 0 4px; color: var(--sui-muted-soft); border-top: none; }

/* Keep the sidebar filling its grid cell at >=lg (override Bootstrap offcanvas width) */
@media (min-width: 992px) {
  .sui-side.offcanvas-lg { width: auto; transform: none; visibility: visible; position: static; border-right: 1px solid var(--border); background: var(--surface); }
}
/* Mobile: collapse to a single column; the sidebar becomes the off-canvas drawer */
@media (max-width: 991.98px) {
  /* minmax(0, 1fr) — NOT 1fr — so the column can shrink below its content's
     min-width and let inner .table-responsive containers scroll, instead of the
     topbar's min-content forcing the whole shell (and every page) wider than the
     viewport and dragging the page into a horizontal scroll. */
  .sui-shell { grid-template-columns: minmax(0, 1fr); grid-template-rows: 56px 1fr; grid-template-areas: "top" "main"; }
  .sui-brand { display: none; }
  .sui-app .sui-main.content { padding: 16px; }
  /* Mobile off-canvas drawer. This Bootstrap build ships only base `.offcanvas`
     + `.offcanvas-start/end` — NOT the responsive `.offcanvas-lg` variant the
     markup uses — so below lg the sidebar gets no fixed/overlay/slide styling
     and falls back to a static 400px block. Supply the drawer behaviour here so
     it doesn't depend on the missing `.offcanvas-lg` rules; the JS still just
     toggles `.show`. Keeps the sidebar out of grid flow (fixed) too. */
  .sui-side.offcanvas-lg {
    position: fixed; top: 0; left: 0; bottom: 0; height: 100%;
    z-index: 1050; width: 258px; max-width: 82vw;
    transform: translateX(-100%); visibility: hidden;
    transition: transform .3s ease-in-out, visibility .3s;
    border-right: 1px solid var(--border); background: var(--surface);
  }
  .sui-side.offcanvas-lg.show,
  .sui-side.offcanvas-lg.showing { transform: none; visibility: visible; }
  .sui-side.offcanvas-lg.hiding { transform: translateX(-100%); }
}
/* Off-canvas backdrop — also absent from this Bootstrap build. The JS appends
   `.offcanvas-backdrop` to <body>; give it the dimming overlay so the open
   drawer reads as a modal layer above the page (below the drawer's z-index). */
.offcanvas-backdrop { position: fixed; inset: 0; z-index: 1040; width: 100vw; height: 100vh; background-color: #000; }
.offcanvas-backdrop.fade { opacity: 0; transition: opacity .15s linear; }
.offcanvas-backdrop.show { opacity: .5; }

/* Modals-on-top guarantee: keep every Bootstrap modal + its backdrop above the
   app chrome AND above the offcanvas drawers (z-index 1050), so a confirm dialog
   can never render behind the shell or a drawer. (The shell has no transform/
   filter ancestor, so the position:fixed modal is never trapped or clipped.) */
.sui-app .modal { z-index: 1080; }
.sui-app .modal-backdrop { z-index: 1075; }
/* Tokenize the modal panel so it follows the theme (Bootstrap's .modal-content
   hardcodes a white background → unreadable in dark, like the offcanvas). */
.sui-app .modal-content { background-color: var(--surface); color: var(--sui-text); border-color: var(--border); }
.sui-app .modal-header, .sui-app .modal-footer { border-color: var(--sui-border-soft); }
/* Tom Select dropdown opened inside a modal must clear the modal's stacking. */
.sui-app .modal .ts-dropdown { z-index: 1090; }

/* Phone (≤575px): let the topbar controls fit a narrow viewport. The user name
   is already hidden <md; drop the role badge to just avatar+caret, let the
   search box shrink to fit, and tighten spacing. */
@media (max-width: 575.98px) {
  .sui-top { gap: 4px; padding: 0 10px; }
  .sui-search { min-width: 0; }
  .sui-search .sui-kbd { display: none; }
  .sui-role { display: none; }
}

/* ---- Dark theme (opt-in via toggle; re-points the --sui-* tokens) ---- */
html[data-theme="dark"] .sui-app {
  --sui-bg: #0d0f13; --sui-surface: #14171d; --sui-surface-alt: #1a1e26;
  --sui-ink: #f3f5f8; --sui-ink-press: #e7eaef; --sui-text: #dfe3ea;
  --sui-nav-fg: #aeb6c2;
  --sui-muted: #98a0ac; --sui-muted-soft: #6f7783;
  --sui-border: #262b34; --sui-border-soft: #20242c; --sui-hover: #1b2029; --sui-input-border: #334155;
  --sui-accent: #5b8cf8; --sui-accent-press: #7aa3fa;
  --sui-success: #37cd82; --sui-danger: #fb5b78; --sui-warning: #e0a54b; --sui-info: #3cc3e0;
  --sui-shadow-sm: 0 1px 2px rgba(0,0,0,.4);
  --sui-shadow: 0 1px 2px rgba(0,0,0,.4), 0 14px 34px -18px rgba(0,0,0,.7);
  color-scheme: dark;
}

/* ===========================================================================
   PHASE 2 — list/form component shells (data_table, list_toolbar, form_field,
   form_actions) + toast close. Reuses the --sui-* tokens; both themes covered.
   =========================================================================== */

/* data_table — count badge + header rhythm */
.sui-app .sui-count {
  background: var(--sui-surface-alt); color: var(--sui-muted); border: 1px solid var(--sui-border-soft);
  font-weight: 650; font-size: 11.5px; padding: 3px 9px; border-radius: 20px;
  font-variant-numeric: tabular-nums;
}
.sui-app .sui-data-card > .card-header { padding-top: .8rem; padding-bottom: .8rem; }

/* Filter / search toolbar */
.sui-app .sui-toolbar { padding: 11px 14px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.sui-app .sui-toolbar-controls { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; flex: 1; min-width: 0; }
.sui-app .sui-toolbar-actions { display: flex; gap: 8px; margin-left: auto; }
.sui-app .sui-toolbar .form-control, .sui-app .sui-toolbar .form-select { height: 34px; }

/* Sticky form action bar (pins to the bottom of the scroll area on long forms) */
.sui-app .sui-formbar {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; align-items: center; gap: 10px;
  margin-top: 1.4rem; padding: .85rem 0 .15rem;
  background: var(--surface); border-top: 1px solid var(--sui-border-soft);
}
.sui-app .sui-formbar-left  { display: flex; align-items: center; gap: 8px; }
.sui-app .sui-formbar-right { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.sui-app .sui-formbar-left:empty { display: none; }

/* Toast dismiss button (dismissible error/warning toasts) */
.toast-close {
  border: none; background: none; color: var(--sui-muted-soft); padding: 0 0 0 6px;
  display: inline-flex; align-items: center; cursor: pointer; font-size: 15px; line-height: 1;
}
.toast-close:hover { color: var(--sui-text); }

/* Phase 3 — audit slide-over drawer width */
.sui-app .sui-drawer.offcanvas-end { --bs-offcanvas-width: min(480px, 92vw); }

/* Tokenize the offcanvas panel bg + text so it follows the theme. Bootstrap's
   base `.offcanvas` hardcodes a white background, which left the audit detail
   drawer white-with-light-text (unreadable) in dark mode. */
.sui-app .offcanvas { background-color: var(--surface); color: var(--sui-text); }

/* Audit detail "Changes" before→after table (friendlier than raw diff JSON). */
.sui-app .sui-diff { width: 100%; border-collapse: collapse; }
.sui-app .sui-diff th { text-align: left; font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; color: var(--sui-muted); font-weight: 700; padding: .35rem .5rem; border-bottom: 1px solid var(--sui-border); }
.sui-app .sui-diff td { padding: .35rem .5rem; border-bottom: 1px solid var(--sui-border-soft); vertical-align: top; font-size: .8rem; color: var(--sui-text); word-break: break-word; }
.sui-app .sui-diff .sui-diff-field { font-weight: 600; color: var(--sui-ink); white-space: nowrap; }
.sui-app .sui-diff .sui-diff-from { color: var(--sui-muted); text-decoration: line-through; }
.sui-app .sui-diff .sui-diff-to { color: var(--sui-text); font-weight: 500; }

/* ===========================================================================
   Audit filter — search-first sticky command bar + active chips + inline
   advanced panel. Uses the --sui-* tokens so both themes follow automatically.
   =========================================================================== */
/* Collapsible "Activity overview" (KPI) card via <details>. */
.sui-app .sui-ov { overflow: hidden; }
.sui-app .sui-ov > .sui-ov-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; cursor: pointer; list-style: none; }
.sui-app .sui-ov > .sui-ov-head::-webkit-details-marker { display: none; }
.sui-app .sui-ov-chev { color: var(--sui-muted); transition: transform .2s; flex: none; }
.sui-app .sui-ov[open] .sui-ov-chev { transform: rotate(180deg); }

/* Sticky filter block (sticks to the top of the scrolling main content). */
.sui-app .sui-audit-filters { position: sticky; top: 0; z-index: 6; background: var(--sui-bg); padding-top: 6px; margin-bottom: 14px; }
.sui-app .sui-cmdbar { display: flex; align-items: center; gap: 10px; padding: 9px 10px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--sui-r-lg); box-shadow: var(--sui-shadow-sm, 0 1px 2px rgba(16,20,30,.05)); }
.sui-app .sui-search-field { flex: 1; display: flex; align-items: center; gap: 9px; min-width: 0; height: 40px; padding: 0 12px; background: var(--sui-surface-alt); border: 1px solid var(--border); border-radius: 9px; color: var(--sui-muted); }
.sui-app .sui-search-field input { flex: 1; min-width: 0; height: 100%; border: 0; background: none; outline: none; color: var(--sui-text); font: inherit; font-size: 14px; }
.sui-app .sui-search-field input::placeholder { color: var(--sui-muted-soft); }

.sui-app .sui-seg { display: inline-flex; gap: 2px; padding: 3px; background: var(--sui-surface-alt); border: 1px solid var(--border); border-radius: 9px; }
.sui-app .sui-seg button { border: 0; background: none; color: var(--sui-muted); font: inherit; font-size: 12.5px; font-weight: 600; padding: 6px 11px; border-radius: 6px; cursor: pointer; white-space: nowrap; }
.sui-app .sui-seg button:hover { color: var(--sui-text); }
.sui-app .sui-seg button.on { background: var(--surface); color: var(--sui-ink); box-shadow: var(--sui-shadow-sm, 0 1px 2px rgba(16,20,30,.08)); }

.sui-app .sui-fbtn { display: inline-flex; align-items: center; gap: 8px; height: 40px; padding: 0 13px; border: 1px solid var(--border); background: var(--surface); color: var(--sui-text); border-radius: 9px; font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; white-space: nowrap; }
.sui-app .sui-fbtn:hover { background: var(--sui-hover); }
.sui-app .sui-fbtn .sui-fcount { display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px; background: var(--sui-accent); color: #fff; font-size: 11px; font-weight: 700; border-radius: 999px; }
.sui-app .sui-fbtn .chev { color: var(--sui-muted); font-size: 12px; transition: transform .2s; }
.sui-app .sui-audit-filters[data-adv="true"] .sui-fbtn .chev { transform: rotate(180deg); }
.sui-app .sui-cmd-apply { flex: none; }

.sui-app .sui-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 11px 2px 0; }
.sui-app .sui-chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 6px 4px 11px; background: color-mix(in srgb, var(--sui-ink) 8%, transparent); color: var(--sui-ink); border-radius: 999px; font-size: 12.5px; font-weight: 600; text-decoration: none; }
.sui-app .sui-chip:hover { background: color-mix(in srgb, var(--sui-ink) 14%, transparent); color: var(--sui-ink); }
.sui-app .sui-chip .k { color: var(--sui-muted); font-weight: 600; }
.sui-app .sui-chip .x { display: grid; place-items: center; width: 17px; height: 17px; border-radius: 999px; font-size: 12px; opacity: .75; }
.sui-app .sui-chip:hover .x { opacity: 1; background: color-mix(in srgb, var(--sui-ink) 16%, transparent); }
.sui-app .sui-clearall { border: 0; background: none; color: var(--sui-muted); font-size: 12.5px; font-weight: 600; text-decoration: underline; padding: 4px 6px; }
.sui-app .sui-clearall:hover { color: var(--sui-danger); }

.sui-app .sui-adv { display: none; margin-top: 12px; padding: 16px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--sui-r-lg); box-shadow: var(--sui-shadow-sm, 0 1px 2px rgba(16,20,30,.05)); }
.sui-app .sui-audit-filters[data-adv="true"] .sui-adv { display: block; }
.sui-app .sui-adv-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 13px; }
.sui-app .sui-field label { display: block; font-size: 11.5px; font-weight: 600; color: var(--sui-muted); margin-bottom: 5px; }
.sui-app .sui-adv-foot { display: flex; justify-content: flex-end; gap: 9px; margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--sui-border-soft); }

/* Uniform 38px control height (matching the dropdown option rows) with
   vertically-centered text across every control in the advanced grid —
   Tom Select controls, date and text inputs alike. */
.sui-app .sui-adv .ts-control { min-height: 38px; height: 38px; padding-top: 0; padding-bottom: 0; align-items: center; }
.sui-app .sui-adv .ts-control .item,
.sui-app .sui-adv .ts-control > input { line-height: 38px; }
.sui-app .sui-adv .form-control,
.sui-app .sui-adv .form-control-sm { height: 38px; padding-top: 0; padding-bottom: 0; font-size: .9rem; line-height: 36px; }

/* Every small single-select (`form-select-sm` / `form-control-sm`) enhanced by
   Tom Select sits its value below centre: the skin's
   `.ts-wrapper.form-select-sm.has-items .ts-control` zeroes padding-bottom
   (meant for its multi-chip layout) while `.ts-wrapper.single .ts-control`
   keeps 0.5rem on top. Mirror the top padding on the bottom (specificity 0,5,0
   beats the 0,4,0 skin rule) so the label centres vertically; `min-height`
   absorbs it, so the control height is unchanged. Applies wherever such a
   select appears — filter modal, user-access role picker, etc. */
.sui-app .ts-wrapper.form-select-sm.single .ts-control,
.sui-app .ts-wrapper.form-control-sm.single .ts-control { padding-bottom: .5rem; align-items: center; }

/* dropdown_input plugin — a search box pinned to the top of the option list. */
.sui-app .ts-dropdown .dropdown-input-wrap { padding: 0 2px 6px; }
.sui-app .ts-dropdown .dropdown-input { width: 100%; height: 38px; padding: 0 11px; border: 1px solid var(--border); border-radius: var(--sui-r-sm); background: var(--sui-surface-alt); color: var(--sui-text); font: inherit; font-size: .9rem; outline: none; }
.sui-app .ts-dropdown .dropdown-input:focus { border-color: var(--sui-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--sui-accent) 16%, transparent); }
.sui-app .ts-dropdown .dropdown-input::placeholder { color: var(--sui-muted-soft); }

@media (max-width: 991.98px) {
  .sui-app .sui-cmdbar { flex-wrap: wrap; }
  .sui-app .sui-search-field { flex-basis: 100%; order: -1; }
  .sui-app .sui-adv-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 575.98px) {
  .sui-app .sui-seg { flex: 1; justify-content: space-between; }
  .sui-app .sui-adv-grid { grid-template-columns: 1fr; }
}

/* ===========================================================================
   Generic list filter bar (filter_bar partial) — search + a "Filters" button
   that opens a Bootstrap modal of advanced controls + active-filter chips.
   Reuses the cmdbar/chip/adv-grid/field visual language via a neutral
   `.sui-filters` container so any list page can use it (Bugs apps/versions/bugs).
   Deliberately NOT sticky / no z-index: the advanced modal lives inside this
   form, so a stacking context here would trap the fixed modal under its backdrop.
   =========================================================================== */
.sui-app .sui-filters { margin-bottom: 14px; }

/* ===========================================================================
   Detail-page primitives — hero header, meta bar, lifecycle stepper, comment
   timeline, severity breakdown. Presentational; reuse the --sui-* tokens so both
   themes follow. Used by the Bugs app/version/bug detail pages.
   =========================================================================== */
/* Hero header (replaces page_header on detail pages) */
.sui-app .sui-hero { position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: var(--sui-r-xl); padding: 20px 22px; box-shadow: var(--sui-shadow-sm); overflow: hidden; margin-bottom: 16px; }
.sui-app .sui-hero.is-striped::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--stripe, var(--sui-accent)); }
.sui-app .sui-hero-top { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.sui-app .sui-hero-ico { width: 52px; height: 52px; border-radius: 13px; flex: none; display: grid; place-items: center; font-size: 22px; background: color-mix(in srgb, var(--sui-accent) 12%, transparent); color: var(--sui-accent); overflow: hidden; }
.sui-app .sui-hero-ico img { width: 100%; height: 100%; object-fit: cover; }
.sui-app .sui-hero-id { flex: 1; min-width: 0; }
.sui-app .sui-eyebrow { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--sui-muted-soft); }
.sui-app .sui-hero-title { font-size: 1.5rem; font-weight: 750; letter-spacing: -.02em; margin: 3px 0 0; line-height: 1.2; }
.sui-app .sui-hero-code { font-family: var(--bs-font-monospace); font-size: 13px; color: var(--sui-muted); }
.sui-app .sui-hero-actions { display: flex; gap: 8px; flex-wrap: wrap; align-self: flex-start; }

/* Meta bar — key facts row under the hero title */
.sui-app .sui-metabar { display: flex; flex-wrap: wrap; gap: 22px; margin-top: 16px; padding-top: 15px; border-top: 1px solid var(--sui-border-soft); }
.sui-app .sui-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sui-app .sui-meta .k { font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--sui-muted-soft); }
.sui-app .sui-meta .v { font-size: 13.5px; font-weight: 600; color: var(--sui-text); display: flex; align-items: center; gap: 7px; }
.sui-app .sui-ava { width: 22px; height: 22px; border-radius: 50%; flex: none; display: grid; place-items: center; font-size: 10px; font-weight: 700; color: #fff; }
.sui-app .sui-ava.is-lg { width: 30px; height: 30px; font-size: 12px; }

/* Soft/line status pill keyed off --c */
.sui-app .sui-pill { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 999px; border: 1px solid transparent; white-space: nowrap; }
.sui-app .sui-pill .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.sui-app .sui-pill.is-soft { background: color-mix(in srgb, var(--c) 14%, transparent); color: var(--c); border-color: color-mix(in srgb, var(--c) 26%, transparent); }
.sui-app .sui-pill.is-line { background: transparent; color: var(--c); border-color: color-mix(in srgb, var(--c) 45%, transparent); }

/* Lifecycle stepper */
/* padding-top + explicit overflow-y:hidden gives the current step's glow ring
   room so it is not clipped at the top edge (overflow-x:auto alone clips both axes). */
.sui-app .sui-stepper { display: flex; align-items: center; margin-top: 18px; overflow-x: auto; overflow-y: hidden; padding: 10px 2px 4px; }
.sui-app .sui-step { display: flex; align-items: flex-start; flex: 0 0 auto; }
.sui-app .sui-step .node { display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 82px; text-align: center; }
.sui-app .sui-step .bead { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 700; background: var(--sui-surface-alt); color: var(--sui-muted-soft); border: 2px solid var(--border); }
.sui-app .sui-step .lbl { font-size: 11px; font-weight: 600; color: var(--sui-muted-soft); }
/* Bar sits at the bead's vertical centre (bead is 26px tall → centre at 13px);
   align-items:flex-start pins it there regardless of how tall the label is. */
.sui-app .sui-step .bar { width: 34px; height: 2px; background: var(--border); flex: none; margin-top: 12px; }
.sui-app .sui-step.is-done .bead { background: var(--sui-success); border-color: var(--sui-success); color: #fff; }
.sui-app .sui-step.is-done .lbl { color: var(--sui-text); }
.sui-app .sui-step.is-done .bar, .sui-app .sui-step.is-cur .bar { background: var(--sui-success); }
.sui-app .sui-step.is-cur .bead { background: var(--sui-accent); border-color: var(--sui-accent); color: #fff; box-shadow: 0 0 0 4px color-mix(in srgb, var(--sui-accent) 18%, transparent); }
.sui-app .sui-step.is-cur .lbl { color: var(--sui-accent); font-weight: 700; }
.sui-app .sui-step.is-rej .bead { background: var(--sui-danger); border-color: var(--sui-danger); color: #fff; box-shadow: 0 0 0 4px color-mix(in srgb, var(--sui-danger) 18%, transparent); }
.sui-app .sui-step.is-rej .lbl { color: var(--sui-danger); font-weight: 700; }

/* Comment / activity timeline */
.sui-app .sui-tl-item { display: flex; gap: 12px; padding: 0 0 18px; position: relative; }
.sui-app .sui-tl-item:not(:last-child)::before { content: ""; position: absolute; left: 15px; top: 32px; bottom: 0; width: 2px; background: var(--sui-border-soft); }
.sui-app .sui-tl-ava { width: 32px; height: 32px; border-radius: 50%; flex: none; display: grid; place-items: center; font-size: 13px; font-weight: 700; color: #fff; z-index: 1; }
.sui-app .sui-tl-body { flex: 1; min-width: 0; }
.sui-app .sui-tl-meta { font-size: 12.5px; color: var(--sui-muted); margin-bottom: 3px; }
.sui-app .sui-tl-meta b { color: var(--sui-text); font-weight: 700; }
.sui-app .sui-tl-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--sui-surface-alt); border: 1px solid var(--sui-border-soft); border-radius: var(--sui-r); padding: 6px 11px; font-size: 12.5px; }

/* Steps / Expected / Actual boxes */
.sui-app .sui-sbs { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; margin-top: 6px; }
@media (max-width: 640px) { .sui-app .sui-sbs { grid-template-columns: 1fr; } }
.sui-app .sui-sbs-box { background: var(--sui-surface-alt); border: 1px solid var(--sui-border-soft); border-radius: var(--sui-r); padding: 12px 13px; }
.sui-app .sui-blk { font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--sui-muted-soft); margin: 0 0 6px; }

/* Severity breakdown mini-bars */
.sui-app .sui-breakdown { display: flex; flex-direction: column; gap: 9px; }
.sui-app .sui-bd-row { display: flex; align-items: center; gap: 10px; font-size: 13px; }
.sui-app .sui-bd-bar { flex: 1; height: 7px; border-radius: 4px; background: var(--sui-surface-alt); overflow: hidden; }
.sui-app .sui-bd-bar > span { display: block; height: 100%; border-radius: 4px; }
.sui-app .sui-bd-n { font-variant-numeric: tabular-nums; font-weight: 700; min-width: 20px; text-align: right; }

/* Severity stripe marker for table rows */
.sui-app .sui-sev { display: inline-block; width: 3px; height: 15px; border-radius: 2px; vertical-align: middle; margin-right: 6px; }

/* ------------------------------------------------------------------ */
/* Missing Bootstrap display utilities                                 */
/* ------------------------------------------------------------------ */
/* The bundled bootstrap.min.css ships no `.d-inline-grid` and no
   responsive `.d-*-inline-grid` variant, so the topbar's
   `d-none d-lg-inline-grid` collapse button was hidden at EVERY width —
   `.d-none` applied and nothing ever un-hid it. Supply the variant the
   markup asks for, scoped to the shell so it cannot leak elsewhere.
   (Same class of gap as the missing `.offcanvas-lg` rules above.) */
@media (min-width: 992px) {
  .sui-app .d-lg-inline-grid { display: inline-grid !important; }
}

/* ------------------------------------------------------------------ */
/* Dark mode: rescue `.text-dark` on backgrounds we darken             */
/* ------------------------------------------------------------------ */
/* app.css already flips `.bg-light` and every `.bg-*-subtle` to a dark
   surface for the dark theme, and lightens .text-success/.warning/
   .danger/.info/.primary/.secondary to match — but it never handles
   `.text-dark`. So the ~60 `bg-light text-dark` / `bg-*-subtle text-dark`
   badges across the panels rendered near-black on a dark surface, i.e.
   invisible. Lighten the text wherever the background was darkened.

   Deliberately NOT matched: solid semantic backgrounds such as
   `.badge.bg-warning.text-dark` — app.css leaves those amber in dark mode,
   so their dark text is correct and must stay dark. */
html[data-theme="dark"] .sui-app .bg-light.text-dark,
html[data-theme="dark"] .sui-app [class*="-subtle"].text-dark {
  color: var(--sui-text) !important;
}

/* ------------------------------------------------------------------ */
/* Topbar entity search                                                */
/* ------------------------------------------------------------------ */
/* For panels whose old top-nav carried a real inline search box (Projects
   posts to /projects/search). Same metrics as the `.sui-search` ⌘K palette
   button so the topbar rhythm is unchanged, but it is an actual GET input.
   The min-width:0 at phone widths matters: a non-shrinkable control here is
   what pushed the whole shell into ~122px of horizontal overflow before. */
.sui-topsearch {
  display: flex; align-items: center; gap: 9px; height: 36px; padding: 0 12px;
  min-width: 170px; max-width: 340px; flex: 1; margin: 0;
  background: var(--sui-surface-alt); border: 1px solid var(--border); border-radius: 8px;
  color: var(--sui-muted);
}
.sui-topsearch:focus-within { border-color: var(--sui-muted-soft); }
.sui-topsearch input {
  flex: 1; min-width: 0; height: 100%; border: 0; background: none; outline: none;
  color: var(--sui-text); font: inherit; font-size: 13px;
}
.sui-topsearch input::placeholder { color: var(--sui-muted-soft); }
@media (max-width: 575.98px) { .sui-topsearch { min-width: 0; } }

/* ------------------------------------------------------------------ */
/* Sidebar nav count badge                                             */
/* ------------------------------------------------------------------ */
/* For nav items that carried a live count in the old top-nav (Play's
   "Updates" unseen-event pill). Pushed to the trailing edge; it is a
   <span>, so the existing collapsed rule
   `html[data-collapsed="1"] .sui-nav-item span{display:none}` hides it
   along with the label when the sidebar is collapsed. */
.sui-side .sui-nav-badge {
  margin-left: auto; font-size: 10.5px; font-weight: 700; line-height: 1;
  padding: 3px 6px; border-radius: 999px; flex: none;
  background: var(--sui-danger); color: #fff;
}
.sui-side .sui-nav-item.active .sui-nav-badge { background: var(--sui-danger); color: #fff; }

/* ------------------------------------------------------------------ */
/* Topbar context switcher + status pill (Finance)                     */
/* ------------------------------------------------------------------ */
/* Finance scopes every page by an "active company" and shows a live cash
   (silak) balance. Both lived in the old top-nav; in the shell they belong
   in the topbar, styled to sit alongside .sui-user-btn without competing
   with it. Both are hidden below md so the topbar can still shrink. */
.sui-ctxbtn {
  display: flex; align-items: center; gap: 7px; height: 36px; padding: 0 10px;
  border-radius: 8px; color: var(--sui-text); cursor: pointer;
  border: 1px solid var(--sui-border); background: var(--sui-surface-alt);
  font-size: 13px; font-weight: 560; max-width: 210px;
}
.sui-ctxbtn:hover { border-color: var(--sui-muted-soft); }
.sui-ctxbtn i { color: var(--sui-muted); font-size: 14px; flex: none; }
.sui-ctxbtn .sui-ctx-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sui-ctxbtn .sui-ctx-caret { font-size: 11px; color: var(--sui-muted); margin-left: auto; flex: none; }

/* Status pill (silak). Tone comes from .is-ok / .is-bad / .is-off. */
.sui-statpill {
  display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 11px;
  border-radius: 999px; font-size: 12.5px; font-weight: 620; text-decoration: none;
  border: 1px solid transparent; white-space: nowrap;
}
.sui-statpill.is-ok  { color: var(--sui-success); background: color-mix(in srgb, var(--sui-success) 12%, transparent); border-color: color-mix(in srgb, var(--sui-success) 26%, transparent); }
.sui-statpill.is-bad { color: var(--sui-danger);  background: color-mix(in srgb, var(--sui-danger) 12%, transparent);  border-color: color-mix(in srgb, var(--sui-danger) 26%, transparent); }
.sui-statpill.is-off { color: var(--sui-muted);   background: var(--sui-surface-alt); border-color: var(--sui-border); }
.sui-app a.sui-statpill:hover { color: inherit; filter: brightness(.96); }

/* ------------------------------------------------------------------ */
/* Solid buttons rendered as <a> — beat the .sui-app link colour       */
/* ------------------------------------------------------------------ */
/* `.sui-app a{color:var(--sui-accent)}` (0,1,1) outranks Bootstrap's own
   `.btn-success{color:#fff}` (0,1,0), so an ANCHOR styled as a solid button
   came out with link-blue text on a coloured fill — e.g. Finance's
   "Record income" / "Record expense". It only shows up once a panel gains
   `class="sui-app"`, and Accounts/Bugs happen to use <button> everywhere,
   which is why it went unnoticed until the Finance port.
   Restated at (0,2,0) / (0,3,0) so the button's own colour wins, using the
   exact values this Bootstrap build declares. `.btn-primary` is handled
   separately above (it is themed to --sui-ink). */
/* `:not(.btn-icon)` is essential: row-action icon buttons reuse the SAME
   semantic classes but are styled as OUTLINED squares on a surface bg (see
   `.sui-app .btn-icon` above). Without the exclusion these rules repaint their
   ink — `btn-icon btn-secondary` became white-on-white (invisible) and
   btn-info/btn-warning lost their muted ink. */
.sui-app .btn-success:not(.btn-icon),
.sui-app .btn-danger:not(.btn-icon),
.sui-app .btn-dark:not(.btn-icon)    { color: #fff; }
.sui-app .btn-warning:not(.btn-icon),
.sui-app .btn-info:not(.btn-icon),
.sui-app .btn-light:not(.btn-icon)   { color: #000; }
.sui-app .btn-success:not(.btn-icon):hover, .sui-app .btn-success:not(.btn-icon):focus,
.sui-app .btn-danger:not(.btn-icon):hover,  .sui-app .btn-danger:not(.btn-icon):focus,
.sui-app .btn-dark:not(.btn-icon):hover,    .sui-app .btn-dark:not(.btn-icon):focus    { color: #fff; }
.sui-app .btn-warning:not(.btn-icon):hover, .sui-app .btn-warning:not(.btn-icon):focus,
.sui-app .btn-info:not(.btn-icon):hover,    .sui-app .btn-info:not(.btn-icon):focus,
.sui-app .btn-light:not(.btn-icon):hover,   .sui-app .btn-light:not(.btn-icon):focus   { color: #000; }
/* `.btn-secondary` is NOT a solid semantic button in this theme: §3 re-themes it
   to a SURFACE button (white fill, ink text, input-grey border). Restating
   Bootstrap's `#fff` ink for it — as the lists above used to — therefore painted
   white on white and made every plain `btn-secondary` unreadable, most visibly
   the shared page_header "Back" <a>, which is invisible on every list/form/view
   page the moment the user arrives with a referrer. It still needs the anchor
   override (that is what this whole block is for), just with its OWN ink. */
.sui-app .btn-secondary:not(.btn-icon),
.sui-app .btn-secondary:not(.btn-icon):hover,
.sui-app .btn-secondary:not(.btn-icon):focus { color: var(--sui-text); }

/* ------------------------------------------------------------------ */
/* Filter-modal control sizing                                         */
/* ------------------------------------------------------------------ */
/* The 38px normalisation above is scoped to `.sui-adv` — the ORIGINAL
   inline advanced panel (only /audit ever used it). `filter_bar` renders its
   controls inside a modal as a bare `.sui-adv-grid`, with no `.sui-adv`
   ancestor, so native selects (~31px at -sm) and Tom Select controls (~38px)
   sat at different heights in every filter modal. Mirror the same rules onto
   the grid itself so both containers agree. */
.sui-app .sui-adv-grid .ts-control { min-height: 38px; height: 38px; padding-top: 0; padding-bottom: 0; align-items: center; }
.sui-app .sui-adv-grid .ts-control .item,
.sui-app .sui-adv-grid .ts-control > input { line-height: 38px; }
.sui-app .sui-adv-grid .form-control,
.sui-app .sui-adv-grid .form-control-sm,
.sui-app .sui-adv-grid .form-select,
.sui-app .sui-adv-grid .form-select-sm { height: 38px; padding-top: 0; padding-bottom: 0; font-size: .9rem; }

/* ------------------------------------------------------------------ */
/* List groups — tokenise the hardcoded white                          */
/* ------------------------------------------------------------------ */
/* Bootstrap hardcodes `.list-group-item{background-color:#fff}` (same trap as
   `.offcanvas` and `.modal-content` above), and nothing ever re-pointed it, so
   in dark mode every list-group row rendered as a white band — visible on
   Play's dashboard, and equally on Bugs (15 uses) and Projects (29). Tokenise
   background, text and border so the rows follow the surface they sit on.
   `.list-group-flush` rows sit directly on a card, so keep them transparent
   and let the card's own surface show through. */
.sui-app .list-group-item {
  background-color: var(--surface);
  color: var(--sui-text);
  border-color: var(--sui-border);
}
.sui-app .list-group-flush > .list-group-item { background-color: transparent; }
.sui-app .list-group-item-action:hover,
.sui-app .list-group-item-action:focus { background-color: var(--sui-hover); color: var(--sui-text); }

/* ------------------------------------------------------------------ */
/* Dark-mode contrast fix · shared                                     */
/* ------------------------------------------------------------------ */
/* Bootstrap's `.bg-dark` is #212529. Against the light surface that is a
   15.4:1 pill and reads perfectly; against the DARK surface it is 1.11:1 —
   the fill and the background are the same colour to the eye, so the pill
   vanishes and the label reads as bare text rather than a status chip. The
   white label was never the problem (15.4:1 either way), which is why this is
   easy to miss: nothing looks broken, the status just stops looking like one.

   Slate-500 restores it: 3.6:1 against the surface (clears the 3:1 WCAG
   non-text target) with 4.8:1 for the white label on top. Light mode is left
   exactly as it was.

   SHARED, not panel-specific: three panels render a `bg-dark` badge —
   Bugs via bug_status_color() ('closed', 'on_hold') and Analytics + Apps via
   $platformTone / $storeTone ('ios'). It lived in the Bugs block for a year
   while the same badge was unreadable on the other two.

   `.badge.bg-dark` and not `.bg-dark` — the Stale KPI tile uses `bg-dark` on a
   `.stat-icon`, where a dark circle on a dark card is the intended look.
   !important because Bootstrap's background utilities carry it themselves.

   `body.dark-mode.sui-app`, NOT `body.dark-mode .sui-app` — .sui-app is on
   <body> itself, so the descendant form silently matches nothing. */
body.dark-mode.sui-app .badge.bg-dark {
  background-color: #64748b !important;
  color: #fff;
}
