/* ============================================================
   DavinaRadius — "Operator" theme
   Bootstrap 5.3 dark-mode customization
   ------------------------------------------------------------
   The --op-* tokens below are the palette. Every --bs-* token is
   mapped onto one of them, so a colour changes in one place and
   the whole admin UI follows, Bootstrap components included.

   Captive portals are not styled from here. They write their own
   <head> and load captive_portal.css, so nothing in this file
   ever reaches a customer-facing page.
   ============================================================ */

/* Import typography: Inter (UI) + JetBrains Mono (data/network values) */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');

/* ============================================================
   1. ROOT VARIABLES (light-mode baseline — mostly unused since
      the app is always dark, but required for Bootstrap compat)
   ============================================================ */
:root {
  /* ---- Palette. Everything else in this file points at these ----

     Each accent is declared twice, once as a hex and once as a bare rgb
     triple. CSS cannot pull the channels back out of a hex, so any tint
     built with rgba() has to read the triple; keeping them adjacent is
     what stops a solid and its tint drifting apart.

     The accents are pitched near full chroma and they are meant to be.
     Almost nothing renders them solid: badges, banners and glows all read
     them through a 0.12 to 0.18 alpha, so a token toned down for calm gets
     toned down a second time on the way to the screen and lands as grey.
     Restraint belongs in those alphas and in how rarely a colour appears,
     not in the token. ---- */
  --op-ground:        #0d1117;   /* page canvas */
  --op-surface:       #151c24;   /* cards, modals, sidebar */
  --op-surface-2:     #1b242e;   /* table headers, inputs, card headers */
  --op-surface-3:     #232e3a;   /* hover */
  --op-line:          #26313d;   /* every border and divider */
  --op-ink:           #e6edf3;   /* body text */
  --op-ink-2:         #b3c2d0;   /* secondary text, hints */
  --op-muted:         #7c8b9a;   /* labels, captions */
  --op-pppoe:         #00e2d6;   /* the anchor accent */
  --op-pppoe-rgb:     0, 226, 214;
  --op-pppoe-soft:    rgba(var(--op-pppoe-rgb), 0.15);
  --op-voucher:       #fa9e09;
  --op-voucher-rgb:   250, 158, 9;
  --op-voucher-soft:  rgba(var(--op-voucher-rgb), 0.16);
  --op-alarm:         #f54e4a;
  --op-alarm-rgb:     245, 78, 74;
  --op-alarm-soft:    rgba(var(--op-alarm-rgb), 0.12);
  --op-warn:          #fbb81e;
  --op-warn-rgb:      251, 184, 30;
  --op-warn-soft:     rgba(var(--op-warn-rgb), 0.12);
  --op-positive:      #31dc8f;
  --op-positive-rgb:  49, 220, 143;
  --op-positive-soft: rgba(var(--op-positive-rgb), 0.12);
  --op-info:          #21b4f7;
  --op-info-rgb:      33, 180, 247;
  --op-info-soft:     rgba(var(--op-info-rgb), 0.14);

  /* Everything that sits beside the live operational states rather than
     being one of them: a discontinued package, an account waiting on
     activation, a tier that is not billed like the rest. It is the only
     accent that never glows, because none of it is asking to be dealt with
     now, and the halo is what carries that difference. */
  --op-aside:         #9b6bff;
  --op-aside-rgb:     155, 107, 255;

  --op-ghost:         #495a68;   /* comparison lines, subordinate borders */
  --op-ghost-rgb:     73, 90, 104;
  --op-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 10px 30px rgba(0, 0, 0, 0.26);
  --op-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* ---- Semantic palette (light-mode baseline, rarely used: the
          app is always dark, but Bootstrap needs it defined) ---- */
  --bs-primary:        var(--op-pppoe);
  --bs-primary-hover:  #00bfb7;
  --bs-primary-rgb:    var(--op-pppoe-rgb);
  --bs-progress-bar-bg: var(--bs-primary);   /* Bootstrap doesn't derive this from --bs-primary itself */
  --bs-secondary:      var(--op-aside);
  --bs-secondary-rgb:  var(--op-aside-rgb);
  --bs-success:        var(--op-positive);
  --bs-success-rgb:    var(--op-positive-rgb);
  --bs-danger:         var(--op-alarm);
  --bs-danger-rgb:     var(--op-alarm-rgb);
  --bs-warning:        var(--op-warn);
  --bs-warning-rgb:    var(--op-warn-rgb);
  --bs-info:           var(--op-info);
  --bs-info-rgb:       var(--op-info-rgb);
  --bs-light:          #f0f4f8;
  --bs-dark:           var(--op-ground);

  /* Corners: one step softer than Bootstrap's default, which is what
     separates a panel from a box without becoming a pill. */
  --bs-border-radius:    0.5rem;
  --bs-border-radius-sm: 0.375rem;
  --bs-border-radius-lg: 0.75rem;
  --bs-border-radius-xl: 1rem;

  /* Shadows */
  --shadow-sm:  0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md:  0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.06);
  --shadow-lg:  0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.05);

  /* Transitions */
  --transition-default: all 0.2s ease;
}


/* ============================================================
   2. DARK MODE OVERRIDES — the theme the app actually runs in
   ============================================================ */
[data-bs-theme="dark"] {
  /* Backgrounds — layered depth */
  --bs-body-bg:          var(--op-ground);
  --bs-body-bg-rgb:      13, 17, 23;
  --bs-body-color:       var(--op-ink);
  --bs-body-color-rgb:   230, 237, 243;

  /* Surface layers */
  --surface-1: var(--op-surface);     /* Cards, modals, sidebar */
  --surface-2: var(--op-surface-2);   /* Table headers, input bg */
  --surface-3: var(--op-surface-3);   /* Hover states, subtle highlights */

  /* Semantic palette in dark context */
  --bs-primary:        var(--op-pppoe);
  --bs-primary-hover:  #00bfb7;
  --bs-primary-rgb:    var(--op-pppoe-rgb);
  --bs-progress-bar-bg: var(--bs-primary);
  --bs-secondary:      var(--op-aside);
  --bs-secondary-rgb:  var(--op-aside-rgb);
  --bs-success:        var(--op-positive);
  --bs-success-rgb:    var(--op-positive-rgb);
  --bs-danger:         var(--op-alarm);
  --bs-danger-rgb:     var(--op-alarm-rgb);
  --bs-warning:        var(--op-warn);
  --bs-warning-rgb:    var(--op-warn-rgb);
  --bs-info:           var(--op-info);
  --bs-info-rgb:       var(--op-info-rgb);

  /* Bootstrap internal dark-mode surface tokens */
  --bs-light:          var(--surface-2);
  --bs-dark:           var(--op-ink);
  --bs-gray:           var(--op-line);
  --bs-border-color:   var(--op-line);
  --bs-secondary-bg:   var(--surface-2);
  --bs-tertiary-bg:    var(--surface-1);
  --bs-secondary-color: var(--op-ink-2);
  --bs-tertiary-color:  var(--op-muted);

  /* Shadows — heavier in dark */
  --shadow-sm:  0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-md:  0 1px 2px rgba(0, 0, 0, 0.3), 0 6px 18px rgba(0, 0, 0, 0.22);
  --shadow-lg:  var(--op-shadow);

  /* Emphasis halos. They mark the focused or hovered thing; too faint and
     the interaction reads as not having registered at all. */
  --glow-primary:   0 0 8px rgba(var(--op-pppoe-rgb), 0.32);
  --glow-success:   0 0 8px rgba(var(--op-positive-rgb), 0.32);
  --glow-danger:    0 0 8px rgba(var(--op-alarm-rgb), 0.32);
  --glow-warning:   0 0 8px rgba(var(--op-warn-rgb), 0.32);
  --glow-info:      0 0 8px rgba(var(--op-info-rgb), 0.32);
}


.progress {
  --bs-progress-bar-bg: var(--bs-primary);
}


/* ============================================================
   3. BASE & TYPOGRAPHY
   ============================================================ */
body {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-feature-settings: "cv02", "cv03", "cv04", "cv11";
  -webkit-font-smoothing: antialiased;
  background-color: var(--bs-body-bg, #0d1117);
  color: var(--bs-body-color, #e6edf3);
}

/* Monospace for network data: IPs, MACs, session IDs, RADIUS values */
.font-mono,
.ip-address,
.mac-address,
.session-id,
code,
pre,
kbd,
samp {
  font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
  font-size: 0.85em;
  color: var(--bs-primary);
}

/* Inline code in dark mode */
[data-bs-theme="dark"] code {
  background-color: var(--surface-2);
  padding: 0.1em 0.35em;
  border-radius: 0.25rem;
  color: var(--bs-primary);
}

[data-bs-theme="dark"] pre {
  background-color: var(--surface-1);
  border: 1px solid var(--bs-border-color);
  border-radius: 0.5rem;
  padding: 1rem;
  color: var(--bs-body-color);
}

/* Links. :where() so this contributes no specificity beyond the theme
   attribute: it is the default for a bare <a>, not something a component
   has to fight. Without it the selector scores (0,2,1) on account of the
   :not(), which quietly outranks every "[data-bs-theme] .component" rule
   below and paints their anchors teal, up to and including teal text on a
   teal background where a component fills its own active state. */
[data-bs-theme="dark"] :where(a:not(.btn)) {
  color: var(--bs-primary);
}
[data-bs-theme="dark"] :where(a:not(.btn)):hover {
  color: var(--bs-primary-hover);
}


/* ============================================================
   4. CARDS
   ============================================================ */
.card {
  border-radius: var(--bs-border-radius-lg);
  transition: border-color 0.2s ease;
}

[data-bs-theme="dark"] .card {
  background-color: var(--surface-1);
  border: 1px solid var(--bs-border-color);
  box-shadow: var(--shadow-md);
}

[data-bs-theme="dark"] .card:hover {
  border-color: var(--op-ghost);
}

/* A header is the card's title, not a separate panel stacked on top of it.
   The filled bar and the rule under it were doing the job of a border the
   card already has, which is what made every card read as two boxes. */
.card-header,
[data-bs-theme="dark"] .card-header {
  background-color: transparent;
  border-bottom: 0;
  font-weight: 600;
  color: var(--bs-body-color);
  padding-bottom: 0.25rem;
}

.card-footer,
[data-bs-theme="dark"] .card-footer {
  background-color: transparent;
  border-top: 1px solid var(--bs-border-color);
}

/* Stat cards — colored top-border accent */
.card.stat-card {
  border-top: 3px solid var(--bs-primary);
  border-radius: 0.5rem;
}
.card.stat-card.stat-success  { border-top-color: var(--bs-success); }
.card.stat-card.stat-danger   { border-top-color: var(--bs-danger); }
.card.stat-card.stat-warning  { border-top-color: var(--bs-warning); }
.card.stat-card.stat-info     { border-top-color: var(--bs-info); }
.card.stat-card.stat-secondary { border-top-color: var(--bs-secondary); }

/* Auto-assign accent to dashboard stat figures */
[data-bs-theme="dark"] .card .display-6,
[data-bs-theme="dark"] .card .fs-2,
[data-bs-theme="dark"] .card .fs-3 {
  color: var(--bs-primary);
  font-family: 'JetBrains Mono', monospace;
  font-weight: 500;
}


/* ============================================================
   5. BUTTONS
   ============================================================ */
.btn {
  padding: 0.375rem 0.75rem;
  font-size: 0.875rem;
  font-weight: 500;
  border-radius: 0.375rem;
  transition: var(--transition-default);
}
.btn-sm  { padding: 0.25rem 0.5rem;  font-size: 0.8rem; }
.btn-lg  { padding: 0.5rem 1rem;     font-size: 1rem; }
.btn:active { transform: translateY(1px); }

/* Primary */
.btn-primary,
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-primary.active,
.btn-primary:focus-visible,
a.btn-primary,
a.btn-primary:hover {
  --bs-btn-color:        var(--op-ground);
  --bs-btn-hover-color:  var(--op-ground);
  --bs-btn-active-color: var(--op-ground);
  color: var(--op-ground) !important;
}

/* Bootstrap paints a disabled button from --bs-btn-disabled-bg, and its
   .btn:disabled rule outranks .btn-primary's plain `background`. Overriding
   only the enabled background therefore left every disabled primary button in
   the app sitting at Bootstrap's stock #0d6efd blue, which reads as an
   enabled button in some other product's palette. */
.btn-primary:disabled,
.btn-primary.disabled {
  --bs-btn-disabled-bg:           var(--op-surface-3);
  --bs-btn-disabled-border-color: var(--op-surface-3);
  --bs-btn-disabled-color:        var(--op-muted);
  background: var(--op-surface-3);
  color: var(--op-muted) !important;
  box-shadow: none;
  opacity: 1;
}

.btn-primary {
  background: var(--bs-primary);
  border: none;
  font-weight: 600;
}
.btn-primary:hover {
  background: var(--bs-primary-hover);
  box-shadow: var(--glow-primary);
}
.btn-primary:focus,
.btn-primary:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(var(--op-pppoe-rgb), 0.35);
}

/* Outline-primary */
[data-bs-theme="dark"] .btn-outline-primary {
  color: var(--bs-primary);
  border-color: var(--bs-primary);
}
[data-bs-theme="dark"] .btn-outline-primary:hover {
  background-color: rgba(var(--op-pppoe-rgb), 0.12);
  border-color: var(--bs-primary);
  color: var(--bs-primary);
  box-shadow: var(--glow-primary);
}
/* Secondary — neutral white, clearly subordinate to primary */
[data-bs-theme="dark"] .btn-secondary {
  --bs-btn-color:        var(--op-ground);
  --bs-btn-hover-color:  var(--op-ground);
  --bs-btn-active-color: var(--op-ground);
  background-color: var(--op-ink);
  border-color:     var(--op-ink);
  color:            var(--op-ground);
  font-weight:      500;
}
[data-bs-theme="dark"] .btn-secondary:hover {
  background-color: #ffffff;
  border-color:     #ffffff;
  color:            var(--op-ground);
  box-shadow:       0 0 8px rgba(230, 237, 243, 0.2);
}
[data-bs-theme="dark"] .btn-secondary:focus,
[data-bs-theme="dark"] .btn-secondary:focus-visible {
  outline:    none;
  box-shadow: 0 0 0 3px rgba(230, 237, 243, 0.25);
}

/* Outline-secondary — off-white border and text, fills on hover */
[data-bs-theme="dark"] .btn-outline-secondary {
  --bs-btn-color:        var(--op-ink);
  --bs-btn-hover-color:  var(--op-ground);
  --bs-btn-active-color: var(--op-ground);
  color:        var(--op-ink);
  border-color: var(--op-ghost);
}
[data-bs-theme="dark"] .btn-outline-secondary:hover {
  background-color: var(--op-ink);
  border-color:     var(--op-ink);
  color:            var(--op-ground);
  box-shadow:       0 0 8px rgba(230, 237, 243, 0.15);
}
[data-bs-theme="dark"] .btn-outline-secondary:focus,
[data-bs-theme="dark"] .btn-outline-secondary:focus-visible {
  outline:    none;
  box-shadow: 0 0 0 3px rgba(230, 237, 243, 0.2);
}
/* Active state for btn-group toggles (e.g. period filter Week/Month/Quarter/Year) */
[data-bs-theme="dark"] .btn-outline-secondary.active {
  background-color: var(--op-ink);
  border-color:     var(--op-ink);
  color:            var(--op-ground);
  font-weight:      600;
}

/* "← Back to X" links: the shared muted border reads too faint
   against the dark background — brighten just these to match the text
   color, without touching the outline-secondary buttons used elsewhere
   (filter toggles, cancel actions, etc). */
[data-bs-theme="dark"] .btn-outline-secondary:has(.bi-arrow-left) {
  border-color: var(--op-ink);
}

/* Success */
[data-bs-theme="dark"] .btn-success {
  background-color: var(--bs-success);
  border-color: var(--bs-success);
  color: var(--op-ground);
  font-weight: 600;
}
[data-bs-theme="dark"] .btn-success:hover {
  background-color: #4ea675;
  box-shadow: var(--glow-success);
}
[data-bs-theme="dark"] .btn-outline-success {
  color: var(--bs-success);
  border-color: var(--bs-success);
}
[data-bs-theme="dark"] .btn-outline-success:hover {
  background-color: rgba(var(--op-positive-rgb), 0.12);
  color: var(--bs-success);
  box-shadow: var(--glow-success);
}
/* Danger */
[data-bs-theme="dark"] .btn-danger {
  background-color: var(--bs-danger);
  border-color: var(--bs-danger);
  color: var(--op-ground);
  font-weight: 600;
}
[data-bs-theme="dark"] .btn-danger:hover {
  background-color: #c9584d;
  box-shadow: var(--glow-danger);
}
[data-bs-theme="dark"] .btn-outline-danger {
  color: var(--bs-danger);
  border-color: var(--bs-danger);
}
[data-bs-theme="dark"] .btn-outline-danger:hover {
  background-color: rgba(var(--op-alarm-rgb), 0.12);
  color: var(--bs-danger);
  box-shadow: var(--glow-danger);
}

/* Warning */
[data-bs-theme="dark"] .btn-warning {
  background-color: var(--bs-warning);
  border-color: var(--bs-warning);
  color: var(--op-ground);
  font-weight: 600;
}
[data-bs-theme="dark"] .btn-warning:hover {
  background-color: #c09a3c;
  box-shadow: var(--glow-warning);
}
[data-bs-theme="dark"] .btn-outline-warning {
  color: var(--bs-warning);
  border-color: var(--bs-warning);
}
[data-bs-theme="dark"] .btn-outline-warning:hover {
  background-color: rgba(var(--op-warn-rgb), 0.12);
  color: var(--bs-warning);
  box-shadow: var(--glow-warning);
}

/* Info */
[data-bs-theme="dark"] .btn-info {
  background-color: var(--bs-info);
  border-color: var(--bs-info);
  color: var(--op-ground);
  font-weight: 600;
}
[data-bs-theme="dark"] .btn-info:hover {
  background-color: #5c92ae;
  box-shadow: var(--glow-info);
}
[data-bs-theme="dark"] .btn-outline-info {
  color: var(--bs-info);
  border-color: var(--bs-info);
}
[data-bs-theme="dark"] .btn-outline-info:hover {
  background-color: rgba(var(--op-info-rgb), 0.12);
  color: var(--bs-info);
  box-shadow: var(--glow-info);
}

/* Dark button (used in sidebar network switcher) */
[data-bs-theme="dark"] .btn-dark {
  background-color: var(--surface-2);
  border: 2px solid var(--bs-primary);
  color: #ffffff;
  font-weight: 500;
}
[data-bs-theme="dark"] .btn-dark:hover {
  background-color: rgba(var(--op-pppoe-rgb), 0.08);
  border-color: var(--bs-primary);
  box-shadow: var(--glow-primary);
}

/* Global focus ring */
.btn:focus,
.btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(var(--op-pppoe-rgb), 0.3);
}


/* ============================================================
   6. FORMS
   ============================================================ */
[data-bs-theme="dark"] .form-control,
[data-bs-theme="dark"] .form-select {
  background-color: var(--surface-2);
  border: 1px solid var(--bs-border-color);
  color: var(--bs-body-color);
  border-radius: 0.375rem;
  transition: var(--transition-default);
}

[data-bs-theme="dark"] .form-control:focus,
[data-bs-theme="dark"] .form-select:focus {
  background-color: var(--surface-2);
  border-color: var(--bs-primary);
  color: var(--bs-body-color);
  outline: none;
  box-shadow: 0 0 0 3px rgba(var(--op-pppoe-rgb), 0.2), var(--glow-primary);
}

[data-bs-theme="dark"] .form-control::placeholder {
  color: var(--op-muted);
}

[data-bs-theme="dark"] .form-label {
  color: var(--op-ink-2);
  font-size: 0.8125rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* A label styles its own words, never a literal quoted inside it. The uppercase
   above was rewriting a zone called "New" into "Type NEW to confirm", against a
   comparison that still wanted "New", so the delete button could never enable. */
[data-bs-theme="dark"] .form-label code,
[data-bs-theme="dark"] .form-label kbd,
[data-bs-theme="dark"] .form-label samp {
  text-transform: none;
  letter-spacing: normal;
}

[data-bs-theme="dark"] .form-text {
  color: var(--op-ink-2) !important;
}

[data-bs-theme="dark"] .input-group-text {
  background-color: var(--surface-2);
  border-color: var(--bs-border-color);
  color: var(--bs-primary);
  font-size: 0.875rem;
  padding: 0.375rem 0.75rem;
}

[data-bs-theme="dark"] .form-check-input {
  background-color: var(--surface-2);
  border-color: var(--bs-border-color);
}
[data-bs-theme="dark"] .form-check-input:checked {
  background-color: var(--bs-primary);
  border-color: var(--bs-primary);
  box-shadow: var(--glow-primary);
}
[data-bs-theme="dark"] .form-check-input:focus {
  box-shadow: 0 0 0 3px rgba(var(--op-pppoe-rgb), 0.2);
}


/* ============================================================
   7. SIDEBAR
   ============================================================ */
.sidebar {
  transition: width 0.3s ease;
  background-color: var(--op-ground);
  border-right: 1px solid var(--op-line);
  flex-shrink: 0;
}

/* Desktop: fixed sidebar width */
@media (min-width: 992px) {
  .sidebar {
    width: 16rem !important;
  }
}

/* Mobile offcanvas: match sidebar width */
#sidebarOffcanvas {
  --bs-offcanvas-width: 280px;
}

/* Nav links */
.sidebar .nav-link {
  display: flex;
  align-items: center;
  padding: 0.4rem 1rem !important;
  transition: var(--transition-default);
  color: var(--op-ink);           /* white label text — readable at a glance */
  width: 100%;
  min-width: 0;
  border-left: 3px solid transparent;
  border-radius: 0 0.375rem 0.375rem 0;
  margin-bottom: 2px;
}

.sidebar .nav-link i {
  margin-right: 0.5rem;
  font-size: 1.2rem;
  color: var(--bs-primary); /* primary-colored icon always */
  flex-shrink: 0;
}

.sidebar .nav-link span {
  flex-grow: 1;
  min-width: 0;
}

.sidebar .nav-link:hover {
  background-color: rgba(var(--op-pppoe-rgb), 0.06);
  color: #ffffff;           /* text stays white, slightly brighter */
  border-left-color: rgba(var(--op-pppoe-rgb), 0.4);
}

.sidebar .nav-link:hover i {
  color: var(--bs-primary); /* icon already primary — keep it */
  filter: brightness(1.2);  /* subtle brightening on hover */
}

/* Active state — accent left-border bar, brightened text, primary icon */
.sidebar .nav-link.active {
  background-color: rgba(var(--op-pppoe-rgb), 0.1) !important;
  color: #ffffff !important;           /* white text on active */
  border-left-color: var(--bs-primary) !important;
  border-radius: 0 0.375rem 0.375rem 0;
}

.sidebar .nav-link.active i,
.sidebar .nav-link.active .text-primary-emphasis {
  color: var(--bs-primary) !important; /* icon stays primary */
  filter: none;
}

/* Sidebar nav item */
.sidebar .nav-item {
  width: 100%;
}

.sidebar .nav-pills {
  width: 100%;
  align-items: flex-start !important;
}

/* Network switcher toggle: persistent, subtle border so it reads as a
   bounded control at rest, not just during the transient focus ring. */
.sidebar-network-toggle {
  border: 1px solid var(--op-line);
  border-radius: 0.5rem;
  background-color: var(--surface-1);
}

.sidebar-network-toggle:hover {
  border-color: var(--bs-primary);
}

/* Create Network button */
.sidebar .btn-primary {
  padding: 0.5rem 1rem;
  border-radius: 0.5rem;
  width: 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: var(--transition-default);
  color: var(--op-ground);
  font-weight: 600;
}

.sidebar .btn-primary i {
  font-size: 1.2rem;
}

.sidebar .btn-primary:hover {
  box-shadow: var(--glow-primary);
}

/* Sidebar alignment */
.sidebar .d-flex.flex-column {
  align-items: flex-start !important;
}

.sidebar .dropdown {
  width: 100%;
}

.sidebar .nav-link,
.sidebar .dropdown-toggle,
.sidebar .dropdown > a,
.sidebar .dropdown > button {
  justify-content: flex-start !important;
  text-align: left !important;
  width: 100%;
}

/* Network switcher toggle keeps its icon/name on the left and chevron
   pinned right — higher specificity than the flex-start rule above. */
.sidebar .dropdown > .sidebar-network-toggle {
  justify-content: space-between !important;
}

/* Menu should match the toggle's width instead of Bootstrap's own
   content-based min-width. */
.sidebar .dropdown-menu {
  width: 100%;
}

/* Horizontal rule */
.sidebar hr {
  width: 100%;
  border: 0;
  border-top: 1px solid var(--op-line);
  margin: 0.35rem 0;
}

/* Section labels above each nav group */
.sidebar-section-label {
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .08em;
  color: rgba(255, 255, 255, .6);
}

/* Independent scroll region for the nav list — brand and network switcher
   stay pinned above it; everything else in the sidebar scrolls with it. */
.sidebar-scroll {
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* Mobile: the topbar isn't part of this flow, so let the shell size
   itself with the page instead of being clipped to the viewport. */
@media (max-width: 991.98px) {
  .app-shell {
    min-height: 100vh;
  }
}

/* Desktop app shell: topbar stays put; sidebar and main content each
   scroll independently within whatever height remains beneath it. */
@media (min-width: 992px) {
  .page-shell {
    display: flex;
    flex-direction: column;
    height: 100vh;
  }

  .app-shell-wrap {
    flex: 1 1 auto;
    min-height: 0;
  }

  .app-shell {
    height: 100%;
    overflow: hidden;
  }

  .app-shell .sidebar {
    height: 100%;
  }

  /* Bootstrap's offcanvas-lg breakpoint reset sets flex-grow:0 on
     .offcanvas-body so it shrinks to content — undo that so it fills
     the sidebar and .sidebar-scroll has a bounded height to scroll within. */
  .app-shell .sidebar .offcanvas-body {
    flex-grow: 1;
    height: 100%;
  }

  .app-shell .app-content {
    height: 100%;
    overflow-y: auto;
  }
}



/* ============================================================
   8. NAVBAR
   ============================================================ */
[data-bs-theme="dark"] .navbar {
  background-color: var(--op-ground) !important;
  border-bottom: 1px solid var(--bs-primary);  /* signal line */
  backdrop-filter: blur(8px);
  padding: 0.5rem 1rem;
}

[data-bs-theme="dark"] .navbar-brand {
  color: var(--bs-primary) !important;
  font-weight: 700;
  font-size: 1.1rem;
  letter-spacing: 0.02em;
}

[data-bs-theme="dark"] .navbar-nav .nav-link {
  color: var(--op-muted);
  transition: var(--transition-default);
}

[data-bs-theme="dark"] .navbar-nav .nav-link:hover {
  color: var(--bs-primary);
}


/* ============================================================
   9. TABLES
   ============================================================ */
[data-bs-theme="dark"] .table {
  color: var(--bs-body-color);
  border-color: var(--op-line);
}

[data-bs-theme="dark"] .table thead th {
  background-color: var(--surface-2);
  color: var(--bs-primary);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.07em;
  padding: 0.75rem;
  border-bottom: 1px solid var(--bs-border-color);
  border-top: none;
  font-family: 'JetBrains Mono', monospace;
}

[data-bs-theme="dark"] .table tbody tr {
  border-color: var(--op-line);
}

[data-bs-theme="dark"] .table-hover tbody tr:hover > * {
  background-color: var(--surface-3) !important;
  color: var(--bs-body-color);
}

[data-bs-theme="dark"] .table > :not(caption) > * > * {
  background-color: transparent;
}

[data-bs-theme="dark"] .table-striped > tbody > tr:nth-of-type(odd) > * {
  background-color: rgba(255, 255, 255, 0.02);
}


/* ============================================================
   10. BADGES
   ============================================================ */
.badge {
  padding: 0.3em 0.55em;
  font-weight: 500;
  font-size: 0.72rem;
  border-radius: 0.3rem;
  letter-spacing: 0.02em;
}

[data-bs-theme="dark"] .badge.bg-primary,
[data-bs-theme="dark"] .badge.text-bg-primary {
  background-color: rgba(var(--op-pppoe-rgb), 0.18) !important;
  color: var(--bs-primary) !important;
  border: 1px solid rgba(var(--op-pppoe-rgb), 0.42);
  box-shadow: var(--glow-primary);
}

[data-bs-theme="dark"] .badge.bg-success,
[data-bs-theme="dark"] .badge.text-bg-success {
  background-color: rgba(var(--op-positive-rgb), 0.18) !important;
  color: var(--bs-success) !important;
  border: 1px solid rgba(var(--op-positive-rgb), 0.42);
  box-shadow: var(--glow-success);
}

[data-bs-theme="dark"] .badge.bg-danger,
[data-bs-theme="dark"] .badge.text-bg-danger {
  background-color: rgba(var(--op-alarm-rgb), 0.18) !important;
  color: var(--bs-danger) !important;
  border: 1px solid rgba(var(--op-alarm-rgb), 0.42);
  box-shadow: var(--glow-danger);
}

[data-bs-theme="dark"] .badge.bg-warning,
[data-bs-theme="dark"] .badge.text-bg-warning {
  background-color: rgba(var(--op-warn-rgb), 0.18) !important;
  color: var(--bs-warning) !important;
  border: 1px solid rgba(var(--op-warn-rgb), 0.42);
  box-shadow: var(--glow-warning);
}

[data-bs-theme="dark"] .badge.bg-info,
[data-bs-theme="dark"] .badge.text-bg-info {
  background-color: rgba(var(--op-info-rgb), 0.18) !important;
  color: var(--bs-info) !important;
  border: 1px solid rgba(var(--op-info-rgb), 0.42);
  box-shadow: var(--glow-info);
}

/* bg-tier is the same badge under the name the customer pages already use. */
[data-bs-theme="dark"] .badge.bg-secondary,
[data-bs-theme="dark"] .badge.text-bg-secondary,
[data-bs-theme="dark"] .badge.bg-tier {
  background-color: rgba(var(--op-aside-rgb), 0.18) !important;
  color: var(--op-aside) !important;
  border: 1px solid rgba(var(--op-aside-rgb), 0.42);
}

[data-bs-theme="dark"] .badge.bg-dark,
[data-bs-theme="dark"] .badge.text-bg-dark {
  background-color: var(--surface-2) !important;
  color: var(--op-muted) !important;
  border: 1px solid var(--op-line);
}

/* Step-progress badges (zone card wizard step indicators) */
.badge-step-pending {
  background-color: #e9ecef;
  color: #495057;
  border: 1px solid #ced4da;
}
[data-bs-theme="dark"] .badge-step-pending {
  background-color: var(--surface-2) !important;
  color: var(--bs-body-color) !important;
  border: 1px solid var(--bs-border-color) !important;
}


/* ============================================================
   11. MODALS
   ============================================================ */
[data-bs-theme="dark"] .modal-content {
  background-color: var(--surface-1);
  border: 1px solid var(--op-line);
  border-radius: 0.75rem;
  box-shadow: var(--shadow-lg), 0 0 30px rgba(0, 0, 0, 0.5);
}

[data-bs-theme="dark"] .modal-header {
  background-color: var(--surface-2);
  border-bottom: 1px solid var(--op-line);
  border-radius: 0.75rem 0.75rem 0 0;
  padding: 1rem 1.25rem;
}

[data-bs-theme="dark"] .modal-title {
  color: var(--bs-primary);
  font-weight: 600;
}

[data-bs-theme="dark"] .modal-footer {
  background-color: var(--surface-2);
  border-top: 1px solid var(--op-line);
  border-radius: 0 0 0.75rem 0.75rem;
}

[data-bs-theme="dark"] .modal-body {
  color: var(--bs-body-color);
}

[data-bs-theme="dark"] .btn-close {
  filter: invert(1) grayscale(1) brightness(0.8);
}
[data-bs-theme="dark"] .btn-close:hover {
  filter: invert(1) grayscale(1) brightness(1);
  box-shadow: none;
}


/* ============================================================
   12. DROPDOWNS
   ============================================================ */
[data-bs-theme="dark"] .dropdown-menu {
  background-color: var(--surface-1);
  border: 1px solid var(--op-line);
  border-radius: 0.5rem;
  box-shadow: var(--shadow-lg);
  max-height: 80vh;
  overflow-y: auto;
}

[data-bs-theme="dark"] .dropdown-item {
  color: var(--op-ink);
  transition: var(--transition-default);
  border-radius: 0.25rem;
  margin: 1px 4px;
  width: calc(100% - 8px);
}

[data-bs-theme="dark"] .dropdown-item:hover {
  background-color: rgba(var(--op-pppoe-rgb), 0.08);
  color: var(--bs-primary);
}

[data-bs-theme="dark"] .dropdown-item.active,
[data-bs-theme="dark"] .dropdown-item:active {
  background-color: rgba(var(--op-pppoe-rgb), 0.18) !important;
  color: var(--bs-primary) !important;
}

[data-bs-theme="dark"] .dropdown-divider {
  border-color: var(--op-line);
}

[data-bs-theme="dark"] .dropdown-header {
  color: var(--op-muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-family: 'JetBrains Mono', monospace;
}



/* ============================================================
   13. NAV TABS
   ============================================================ */
[data-bs-theme="dark"] .nav-tabs {
  border-bottom: 1px solid var(--op-line);
}

[data-bs-theme="dark"] .nav-tabs .nav-link {
  color: var(--op-ink-2);
  border: none;
  padding: 0.5rem 1rem;
  border-radius: 0.375rem 0.375rem 0 0;
  transition: var(--transition-default);
  border-bottom: 2px solid transparent;
}

[data-bs-theme="dark"] .nav-tabs .nav-link:hover {
  color: var(--bs-primary);
  background-color: rgba(var(--op-pppoe-rgb), 0.05);
  border-bottom-color: rgba(var(--op-pppoe-rgb), 0.4);
}

[data-bs-theme="dark"] .nav-tabs .nav-link.active {
  background-color: transparent;
  color: var(--bs-primary) !important;
  border-bottom: 2px solid var(--bs-primary) !important;
  font-weight: 600;
}


/* ============================================================
   14. LIST GROUPS
   ============================================================ */
[data-bs-theme="dark"] .list-group-item {
  background-color: var(--surface-1);
  border-color: var(--op-line);
  color: var(--bs-body-color);
  transition: var(--transition-default);
}

[data-bs-theme="dark"] .list-group-item:hover {
  background-color: var(--surface-2);
  color: var(--bs-body-color);
}

[data-bs-theme="dark"] .list-group-item.active {
  background-color: rgba(var(--op-pppoe-rgb), 0.12);
  border-color: var(--bs-primary);
  color: var(--bs-primary);
}


/* ============================================================
   15. ALERTS
   ============================================================ */
[data-bs-theme="dark"] .alert {
  border-radius: 0.5rem;
  border-left-width: 3px;
  font-size: 0.875rem;
}

[data-bs-theme="dark"] .alert-primary {
  background-color: rgba(var(--op-pppoe-rgb), 0.08);
  border-color: var(--bs-primary);
  color: var(--bs-primary);
}

[data-bs-theme="dark"] .alert-success {
  background-color: rgba(var(--op-positive-rgb), 0.08);
  border-color: var(--bs-success);
  color: var(--bs-success);
}

[data-bs-theme="dark"] .alert-danger {
  background-color: rgba(var(--op-alarm-rgb), 0.08);
  border-color: var(--bs-danger);
  color: var(--bs-danger);
}

[data-bs-theme="dark"] .alert-warning {
  background-color: rgba(var(--op-warn-rgb), 0.08);
  border-color: var(--bs-warning);
  color: var(--bs-warning);
}

[data-bs-theme="dark"] .alert-info {
  background-color: rgba(var(--op-info-rgb), 0.08);
  border-color: var(--bs-info);
  color: var(--bs-info);
}


/* ============================================================
   16. PAGINATION
   ============================================================ */
[data-bs-theme="dark"] .page-link {
  background-color: var(--surface-1);
  border-color: var(--op-line);
  color: var(--op-muted);
  transition: var(--transition-default);
}

[data-bs-theme="dark"] .page-link:hover {
  background-color: var(--surface-2);
  border-color: var(--bs-primary);
  color: var(--bs-primary);
}

[data-bs-theme="dark"] .page-item.active .page-link {
  background-color: var(--bs-primary);
  border-color: var(--bs-primary);
  color: var(--op-ground);
  font-weight: 600;
  box-shadow: var(--glow-primary);
}

[data-bs-theme="dark"] .page-item.disabled .page-link {
  background-color: var(--surface-1);
  border-color: var(--op-line);
  color: var(--op-muted);
}


/* ============================================================
   17. TEXT UTILITIES — dark mode fixes
   ============================================================ */
[data-bs-theme="dark"] .text-muted,
[data-bs-theme="dark"] .form-text {
  color: var(--op-ink-2) !important;
}

[data-bs-theme="dark"] .text-primary   { color: var(--bs-primary) !important; }
[data-bs-theme="dark"] .text-success   { color: var(--bs-success) !important; }
[data-bs-theme="dark"] .text-danger    { color: var(--bs-danger) !important; }
[data-bs-theme="dark"] .text-warning   { color: var(--bs-warning) !important; }
[data-bs-theme="dark"] .text-info      { color: var(--bs-info) !important; }
[data-bs-theme="dark"] .text-secondary { color: var(--op-aside) !important; }

[data-bs-theme="dark"] .text-primary-emphasis { color: var(--bs-primary) !important; }

/* Specific dynamic content */
[data-bs-theme="dark"] #recipient-count,
[data-bs-theme="dark"] #messageDetailsContent,
[data-bs-theme="dark"] #promo-preview,
[data-bs-theme="dark"] #char-count,
[data-bs-theme="dark"] #preview-text,
[data-bs-theme="dark"] #promo-char-count,
[data-bs-theme="dark"] #message-preview {
  color: var(--op-ink-2) !important;
}

[data-bs-theme="dark"] .text-body {
  color: var(--bs-body-color) !important;
}


/* ============================================================
   18. BACKGROUNDS
   ============================================================ */
[data-bs-theme="dark"] .bg-light {
  background-color: var(--surface-2) !important;
  color: var(--bs-body-color) !important;
}

[data-bs-theme="dark"] .bg-dark {
  background-color: var(--op-ground) !important;
}

[data-bs-theme="dark"] .bg-primary {
  background-color: var(--bs-primary) !important;
  color: var(--op-ground) !important;
}

[data-bs-theme="dark"] .border.p-3.bg-light {
  background-color: var(--surface-2) !important;
  border-color: var(--op-line) !important;
}

[data-bs-theme="dark"] .card.border-info .card-body {
  background-color: var(--surface-1) !important;
  color: var(--bs-body-color) !important;
}


/* ============================================================
   19. BORDERS & DIVIDERS
   ============================================================ */
[data-bs-theme="dark"] .border,
[data-bs-theme="dark"] .border-top,
[data-bs-theme="dark"] .border-bottom,
[data-bs-theme="dark"] .border-start,
[data-bs-theme="dark"] .border-end {
  border-color: var(--op-line) !important;
}

[data-bs-theme="dark"] .border-primary { border-color: var(--bs-primary) !important; }
[data-bs-theme="dark"] .border-success { border-color: var(--bs-success) !important; }
[data-bs-theme="dark"] .border-danger  { border-color: var(--bs-danger) !important; }
[data-bs-theme="dark"] .border-warning { border-color: var(--bs-warning) !important; }
[data-bs-theme="dark"] .border-info    { border-color: var(--bs-info) !important; }

hr {
  border-color: var(--op-line);
  opacity: 1;
}


/* ============================================================
   20. SPINNERS / LOADING
   ============================================================ */
[data-bs-theme="dark"] .spinner-border {
  color: var(--bs-primary);
}


/* ============================================================
   21. TOOLTIPS & POPOVERS
   ============================================================ */
[data-bs-theme="dark"] .tooltip .tooltip-inner {
  background-color: var(--surface-2);
  color: var(--bs-body-color);
  border: 1px solid var(--op-line);
  font-size: 0.8rem;
}

[data-bs-theme="dark"] .popover {
  background-color: var(--surface-1);
  border: 1px solid var(--op-line);
}

[data-bs-theme="dark"] .popover-header {
  background-color: var(--surface-2);
  border-bottom-color: var(--op-line);
  color: var(--bs-primary);
}

[data-bs-theme="dark"] .popover-body {
  color: var(--bs-body-color);
}


/* ============================================================
   22. LAYOUT UTILITIES
   ============================================================ */
.container-fluid {
  padding-left: 0;
  padding-right: 0;
  overflow-x: hidden;
}


.col.py-3 {
  padding-left: 0.5rem;
  padding-right: 0.5rem;
}

@media (min-width: 576px) {
  .col.py-3 {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
  }
}

.responsive-container {
  padding: 1rem;
}
@media (min-width: 576px) { .responsive-container { padding: 1.5rem; } }
@media (min-width: 768px) { .responsive-container { padding: 2rem; } }

.text-responsive { font-size: 0.875rem; }
@media (min-width: 576px) { .text-responsive { font-size: 1rem; } }

.card-responsive { margin: 0.5rem 0; padding: 1rem; }
@media (min-width: 576px) { .card-responsive { margin: 1rem; padding: 1.5rem; } }


/* ============================================================
   23. SCROLLBAR
   ============================================================ */
[data-bs-theme="dark"] ::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
[data-bs-theme="dark"] ::-webkit-scrollbar-track {
  background: var(--op-ground);
}
[data-bs-theme="dark"] ::-webkit-scrollbar-thumb {
  background: var(--op-line);
  border-radius: 3px;
}
[data-bs-theme="dark"] ::-webkit-scrollbar-thumb:hover {
  background: var(--bs-primary);
}


/* ============================================================
   24. SMS / MODAL SPECIFIC PATCHES (preserve existing fixes)
   ============================================================ */
[data-bs-theme="dark"] #sendMessageModal .form-text,
[data-bs-theme="dark"] #sendMessageModal .text-muted,
[data-bs-theme="dark"] #sendMessageModal #char-count,
[data-bs-theme="dark"] #sendMessageModal #preview-text {
  color: var(--op-ink-2) !important;
}

[data-bs-theme="dark"] #voucherConfigModal .form-text,
[data-bs-theme="dark"] #voucherConfigModal .text-muted,
[data-bs-theme="dark"] #voucherConfigModal #promo-char-count,
[data-bs-theme="dark"] #voucherConfigModal #promo-preview {
  color: var(--op-ink-2) !important;
}


/* ============================================================
   25. VOUCHER TYPE PILLS
   ============================================================ */
ul.nav.voucher-type-pills {
  --bs-nav-pills-link-active-bg: var(--bs-primary);
  --bs-nav-pills-link-active-color: var(--op-ground);
}
ul.nav.voucher-type-pills .nav-link.active:hover {
  color: var(--op-ground) !important;
}

/* The count rides inside the pill, so it has to be drawn in the pill's own
   ink rather than a fixed white. The active pill is a bright teal fill with
   dark text on it, and white-on-teal is where the number disappeared. The
   flat background is the fallback for browsers without color-mix. */
ul.nav.voucher-type-pills .nav-link .badge {
  color: inherit;
  background: transparent;
  background: color-mix(in srgb, currentColor 16%, transparent);
  border: 1px solid color-mix(in srgb, currentColor 40%, transparent);
  font-weight: 600;
}




/* ============================================================
   26. DEMO BAR
   ============================================================ */
/* Sits between the topbar and the app shell on demo tenancies only. It has
   to read as a frame around the product rather than as another dismissible
   alert inside it, so it spans the full width, carries no close button, and
   borrows the voucher amber rather than any colour the app itself uses for
   state. */
.demo-bar {
  background: linear-gradient(
    90deg,
    rgba(var(--op-voucher-rgb), 0.22),
    rgba(var(--op-voucher-rgb), 0.10)
  );
  border-bottom: 1px solid rgba(var(--op-voucher-rgb), 0.45);
  color: var(--op-ink);
}

.demo-bar .badge {
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.demo-bar .btn-outline-light {
  --bs-btn-color: var(--op-ink);
  --bs-btn-border-color: rgba(var(--op-voucher-rgb), 0.55);
  --bs-btn-hover-bg: rgba(var(--op-voucher-rgb), 0.25);
  --bs-btn-hover-border-color: var(--op-voucher);
  --bs-btn-hover-color: var(--op-ink);
}
