/*
 * Blivos theme — the visual layer that sits on top of AdminLTE 4 + Bootstrap 5.
 *
 * Loaded after adminlte.css, so every rule here wins by order rather than by
 * !important. AdminLTE keeps doing the structural work (the CSS grid layout, the
 * push-menu behaviour, the treeview) and its own JS keeps working untouched —
 * this file only re-points the colours, spacing, radii and shadows at a single
 * set of design tokens.
 *
 * Nothing here changes markup semantics: class names AdminLTE's JavaScript looks
 * for (.app-sidebar, .sidebar-menu, .nav-link, .menu-open, .sidebar-overlay …)
 * are restyled, never renamed.
 *
 * Sections
 *   1. Design tokens
 *   2. Bootstrap re-mapping
 *   3. Base & typography
 *   4. Layout shell
 *   5. Sidebar
 *   6. Topbar
 *   7. Cards
 *   8. Buttons
 *   9. Forms
 *  10. Tables
 *  11. Badges, alerts, dropdowns, modals, pagination
 *  12. Dashboard widgets
 *  13. Loading & empty states
 *  14. Responsive
 */

/* ── 1. Design tokens ─────────────────────────────────────────────────────── */

:root,
:root[data-bs-theme="light"] {
  /*
   * The accent is #FF4B2B. `-strong` is the darkened step used for text, links
   * and hover states: at 4.6:1 on white it stays readable at small sizes, which
   * the raw accent (3.3:1) does not.
   */
  --bl-primary: #ff4b2b;
  --bl-primary-strong: #d93a1a;
  --bl-primary-rgb: 255, 75, 43;
  --bl-primary-soft: rgba(255, 75, 43, .1);

  --bl-success: #28c76f;
  --bl-warning: #ff9f43;
  --bl-danger: #ea5455;
  --bl-info: #00cfe8;

  --bl-canvas: #f6f7fb;
  --bl-surface: #ffffff;
  --bl-surface-soft: #f9fafc;

  --bl-text: #2f3349;
  --bl-muted: #7a7f95;
  --bl-nav: #6b7280;

  --bl-line: rgba(47, 51, 73, .07);
  --bl-line-strong: rgba(47, 51, 73, .12);

  --bl-radius-sm: 8px;
  --bl-radius: 12px;
  --bl-radius-lg: 16px;

  --bl-shadow-xs: 0 1px 3px rgba(47, 51, 73, .04);
  --bl-shadow: 0 4px 20px rgba(47, 51, 73, .05);
  --bl-shadow-md: 0 8px 28px rgba(47, 51, 73, .09);
  --bl-shadow-lg: 0 16px 44px rgba(47, 51, 73, .14);

  --bl-ease: .18s cubic-bezier(.4, 0, .2, 1);

  /*
   * AdminLTE reads this for the grid column and the off-canvas offset.
   * 290px rather than the usual ~250: a third-level label like
   * "Fast & Slow Moving Product" loses 24px to the sub-menu indent and needed
   * 171px of text where 246px only gave it 137px. Anything longer still wraps
   * rather than clipping — see the .nav-link p rule in section 5.
   */
  --lte-sidebar-width: 290px;
}

/*
 * Dark mode is a token swap, not a second stylesheet: every component below
 * reads these variables, so the whole UI follows the toggle in the topbar.
 */
:root[data-bs-theme="dark"] {
  /* Lifted a step so the accent still clears 4.5:1 against the dark surface. */
  --bl-primary: #ff6b4f;
  --bl-primary-strong: #ff4b2b;
  --bl-primary-rgb: 255, 107, 79;
  --bl-primary-soft: rgba(255, 107, 79, .16);

  --bl-canvas: #21232f;
  --bl-surface: #2b2c3e;
  --bl-surface-soft: #32334a;

  --bl-text: #e4e5ec;
  --bl-muted: #a1a4bb;
  --bl-nav: #b3b6cc;

  --bl-line: rgba(255, 255, 255, .07);
  --bl-line-strong: rgba(255, 255, 255, .13);

  --bl-shadow-xs: 0 1px 3px rgba(0, 0, 0, .2);
  --bl-shadow: 0 4px 20px rgba(0, 0, 0, .22);
  --bl-shadow-md: 0 8px 28px rgba(0, 0, 0, .3);
  --bl-shadow-lg: 0 16px 44px rgba(0, 0, 0, .4);
}

/* ── 2. Bootstrap re-mapping ──────────────────────────────────────────────── */

:root,
:root[data-bs-theme="light"],
:root[data-bs-theme="dark"] {
  --bs-primary: var(--bl-primary);
  --bs-primary-rgb: var(--bl-primary-rgb);
  --bs-primary-bg-subtle: var(--bl-primary-soft);
  --bs-primary-border-subtle: rgba(var(--bl-primary-rgb), .3);
  --bs-primary-text-emphasis: var(--bl-primary-strong);

  --bs-success: var(--bl-success);
  --bs-success-rgb: 40, 199, 111;
  --bs-warning: var(--bl-warning);
  --bs-warning-rgb: 255, 159, 67;
  --bs-danger: var(--bl-danger);
  --bs-danger-rgb: 234, 84, 85;
  --bs-info: var(--bl-info);
  --bs-info-rgb: 0, 207, 232;

  --bs-body-bg: var(--bl-canvas);
  --bs-body-color: var(--bl-text);
  --bs-secondary-color: var(--bl-muted);
  --bs-tertiary-bg: var(--bl-surface-soft);
  --bs-border-color: var(--bl-line-strong);
  --bs-emphasis-color: var(--bl-text);

  --bs-link-color: var(--bl-primary-strong);
  --bs-link-hover-color: var(--bl-primary);
  --bs-link-color-rgb: var(--bl-primary-rgb);
  --bs-link-hover-color-rgb: var(--bl-primary-rgb);

  --bs-border-radius: var(--bl-radius-sm);
  --bs-border-radius-sm: 6px;
  --bs-border-radius-lg: var(--bl-radius);
  --bs-border-radius-xl: var(--bl-radius-lg);

  /*
   * Inter first for anyone who has it installed, then the platform's own modern
   * UI face. No webfont is fetched: the app's CSP allows styles and fonts from
   * itself and jsDelivr only, and a blocked font request would fall back mid-
   * paint anyway.
   */
  --bs-font-sans-serif: "Inter", "Inter var", "Segoe UI Variable Text", "Segoe UI",
    system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --bs-body-font-size: .9375rem;
  --bs-body-font-weight: 400;
  --bs-body-line-height: 1.55;
}

/* ── 3. Base & typography ─────────────────────────────────────────────────── */

body {
  background-color: var(--bl-canvas);
  color: var(--bl-text);
  font-family: var(--bs-font-sans-serif);
  font-size: var(--bs-body-font-size);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Weights stay moderate — 600 is the heaviest the design uses. */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  color: var(--bl-text);
  font-weight: 600;
  letter-spacing: -.01em;
}

code, kbd, samp, pre {
  font-family: "JetBrains Mono", "Cascadia Mono", "Consolas", ui-monospace, monospace;
  font-size: .8125em;
}

code {
  color: var(--bl-primary-strong);
  background: var(--bl-primary-soft);
  padding: .1rem .35rem;
  border-radius: 5px;
}

.text-secondary { color: var(--bl-muted) !important; }

::selection {
  background: rgba(var(--bl-primary-rgb), .22);
}

:focus-visible {
  outline: 2px solid var(--bl-primary);
  outline-offset: 2px;
}

/* A light, unobtrusive scrollbar in every scroll container of the shell. */
.app-main,
.sidebar-wrapper,
.table-responsive,
.dropdown-menu {
  scrollbar-width: thin;
  scrollbar-color: var(--bl-line-strong) transparent;
}

.app-main::-webkit-scrollbar,
.sidebar-wrapper::-webkit-scrollbar,
.table-responsive::-webkit-scrollbar { width: 8px; height: 8px; }

.app-main::-webkit-scrollbar-thumb,
.sidebar-wrapper::-webkit-scrollbar-thumb,
.table-responsive::-webkit-scrollbar-thumb {
  background: var(--bl-line-strong);
  border-radius: 99px;
}

/*
 * Petunjuk kecil "bisa digeser" untuk tabel lebar di layar sempit. Banyak
 * orang tidak menyadari sebuah tabel bisa digeser ke samping sampai mereka
 * mencobanya secara tidak sengaja — di HP, tanpa scrollbar yang selalu
 * terlihat seperti di desktop, itu sama saja dengan tidak ada jalan sama
 * sekali. Kelas `is-bisa-digeser` dipasang oleh blivos-ui.js
 * (tandaiTabelBisaDigeser) hanya kalau isi tabelnya SUNGGUH lebih lebar
 * dari wadahnya, jadi petunjuk ini tidak pernah muncul untuk tabel yang
 * sudah muat penuh. Dibatasi ke layar sempit supaya tata letak desktop
 * (yang scrollbar-nya sudah terlihat sendiri) tidak ikut berubah.
 */
@media (max-width: 767.98px) {
  .table-responsive.is-bisa-digeser {
    position: relative;
    padding-top: 1.625rem;
  }
  .table-responsive.is-bisa-digeser::before {
    content: "↔ Geser tabel ke samping untuk lihat kolom lainnya";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    padding-bottom: .375rem;
    font-size: .6875rem;
    color: var(--bl-muted);
    text-align: center;
  }
}

/* ── 4. Layout shell ──────────────────────────────────────────────────────── */

/*
 * Fixed topbar, on every breakpoint.
 *
 * `position: sticky` cannot do it here: .app-header is a CSS grid item, so its
 * sticky constraint rectangle is its own grid area — one row tall — and it has
 * nowhere to travel. Pinning the shell to the viewport instead makes .app-main
 * the scroll container, which leaves the header and the sidebar genuinely
 * stationary without taking either out of the grid.
 */
.app-wrapper {
  height: 100vh;
  height: 100dvh; /* dodges the mobile URL-bar jump where supported */
  background: var(--bl-canvas);
}

body.layout-fixed { overflow: hidden; }

.app-main {
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--bl-canvas);
  scroll-behavior: smooth;
  /* Gulungan yang sudah mentok tidak diteruskan ke luar. Itu yang memberi
     tarik-untuk-muat-ulang di bawah ruang bersih untuk bekerja: tanpa ini,
     tarikan di puncak halaman diambil alih pantulan bawaan peramban. */
  overscroll-behavior-y: contain;
}

/* ── Tarik untuk muat ulang ───────────────────────────────────────────────
   Lingkaran yang menunggu di luar tepi atas layar dan turun mengikuti jari.
   Seluruh elemennya dibuat blivos-ui.js — tidak ada satu pun layout yang perlu
   mencetaknya, dan di perangkat bertetikus ia bahkan tidak pernah dibuat. */
.bl-tarik {
  position: fixed;
  top: -44px;
  left: 0;
  right: 0;
  z-index: 1040;
  display: flex;
  justify-content: center;
  /* Ia melayang di atas topbar; tanpa ini ia akan menelan sentuhan yang
     ditujukan ke tombol di bawahnya. */
  pointer-events: none;
}

.bl-tarik-bulat {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  color: var(--bl-primary);
  background: var(--bl-surface);
  border: 1px solid var(--bl-line);
  box-shadow: 0 8px 20px -8px rgba(47, 51, 73, .45);
  transform: translateY(var(--bl-tarik, 0px));
  transition: transform .3s cubic-bezier(.22, 1, .36, 1);
}

/* Selama jarinya masih menempel, lingkarannya harus mengikuti TANPA transisi —
   transisi di sini akan membuatnya tertinggal di belakang jari. Transisi baru
   dipasang kembali saat dilepas, dan itulah yang menariknya pulang. */
.bl-tarik.is-tarik .bl-tarik-bulat { transition: none; }

.bl-tarik-bulat i { font-size: 1rem; transition: transform .2s ease; }
.bl-tarik.is-siap .bl-tarik-bulat { color: var(--bl-primary-strong); border-color: var(--bl-primary); }
.bl-tarik.is-siap .bl-tarik-bulat i { transform: rotate(180deg); }
.bl-tarik.is-muat .bl-tarik-bulat i { animation: bl-tarik-putar .8s linear infinite; }

@keyframes bl-tarik-putar { to { transform: rotate(360deg); } }

.app-header { position: relative; z-index: 1034; }

.app-content { padding: 0; }

.app-content > .container-fluid,
.app-content-header > .container-fluid {
  padding-inline: clamp(1rem, 2.5vw, 1.75rem);
}

.app-content > .container-fluid { padding-bottom: 1.75rem; }

/* Page title + breadcrumb strip. */
.app-content-header {
  padding: 1.5rem 0 1.125rem;
  background: transparent;
}

.app-content-header h1 {
  font-size: 1.375rem;
  font-weight: 600;
  line-height: 1.3;
}

.app-content-header .breadcrumb {
  --bs-breadcrumb-divider-color: var(--bl-muted);
  --bs-breadcrumb-item-padding-x: .5rem;
  font-size: .8125rem;
}

.app-content-header .breadcrumb-item a {
  color: var(--bl-muted);
  text-decoration: none;
  transition: color var(--bl-ease);
}

.app-content-header .breadcrumb-item a:hover { color: var(--bl-primary); }
.app-content-header .breadcrumb-item.active { color: var(--bl-text); }

/*
 * Pinned bar in the shell grid's third row. Since it never scrolls, it is kept
 * slim and given the same surface as the topbar so the two read as one frame
 * around the content rather than as page content themselves.
 */
/* Deliberately not a flex container: flex drops the whitespace-only text node
   between <strong> and the em dash, running the two words together. */
.app-footer {
  padding: .625rem clamp(1rem, 2.5vw, 1.75rem);
  background: var(--bl-surface);
  border-top: 1px solid var(--bl-line);
  color: var(--bl-muted);
  font-size: .8125rem;
  line-height: 1.4;
}

.app-footer strong { color: var(--bl-text); font-weight: 600; }

/* The backdrop AdminLTE injects behind the off-canvas sidebar. */
.sidebar-overlay { backdrop-filter: blur(2px); }

/* ── 5. Sidebar ───────────────────────────────────────────────────────────── */

.app-sidebar {
  background: var(--bl-surface);
  border-right: 1px solid var(--bl-line);
  box-shadow: none;
}

.app-sidebar .sidebar-wrapper {
  padding: 0 .75rem 1.25rem;
}

/* Brand */
.app-sidebar .sidebar-brand {
  padding: 0;
  border-bottom: 1px solid var(--bl-line);
  background: transparent;
}

.app-sidebar .brand-link {
  display: flex;
  align-items: center;
  gap: .625rem;
  height: 64px;
  padding: 0 1.25rem;
  border: 0;
  text-decoration: none;
}

.app-sidebar .brand-image {
  width: 34px;
  height: 34px;
  margin: 0;
  padding: 5px;
  border-radius: 9px;
  background: linear-gradient(135deg, var(--bl-primary), var(--bl-primary-strong));
  box-shadow: 0 4px 12px rgba(var(--bl-primary-rgb), .32) !important;
  opacity: 1 !important;
}

.app-sidebar .brand-text {
  color: var(--bl-text);
  font-size: 1.0625rem;
  font-weight: 600 !important;
  letter-spacing: -.015em;
  white-space: nowrap;
}

/* Section eyebrow above a group of links. */
.app-sidebar .nav-header,
.bl-nav-header {
  padding: 1.25rem .75rem .5rem;
  color: var(--bl-muted);
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
}

/* Menu items */
.app-sidebar .sidebar-menu { gap: .125rem; padding-top: .875rem; }

.app-sidebar .sidebar-menu .nav-item { margin-bottom: .125rem; }

.app-sidebar .sidebar-menu .nav-link {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .5625rem .75rem;
  border-radius: var(--bl-radius-sm);
  color: var(--bl-nav);
  font-size: .875rem;
  font-weight: 500;
  transition: background-color var(--bl-ease), color var(--bl-ease);
}

/*
 * AdminLTE keeps menu labels on one line, so a name wider than the sidebar is
 * simply cut off by .sidebar-wrapper's overflow-x: hidden. Letting it wrap
 * means the width above is a comfort setting, not a hard limit on how long a
 * menu may be named.
 */
.app-sidebar .sidebar-menu .nav-link p {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .375rem;
  flex: 1;
  min-width: 0;
  margin: 0;
  white-space: normal;
  overflow-wrap: break-word;
  line-height: 1.35;
}

.app-sidebar .sidebar-menu .nav-icon {
  width: 1.125rem;
  margin: 0;
  font-size: 1.0625rem;
  text-align: center;
  flex-shrink: 0;
}

.app-sidebar .sidebar-menu .nav-link:hover,
.app-sidebar .sidebar-menu .nav-link:focus-visible {
  background: var(--bl-primary-soft);
  color: var(--bl-primary-strong);
}

/*
 * Active item: the one solid accent in the sidebar. AdminLTE marks it with
 * .active on the <a>, which the sidebar partial still sets from Url::isCurrent.
 */
.app-sidebar .sidebar-menu .nav-link.active,
.app-sidebar .sidebar-menu .nav-link.active:hover {
  background: linear-gradient(90deg, var(--bl-primary), var(--bl-primary-strong));
  color: #fff;
  box-shadow: 0 4px 12px rgba(var(--bl-primary-rgb), .35);
}

.app-sidebar .sidebar-menu .nav-link.active .nav-icon { color: #fff; }

/* Parent of the open page: highlighted, but never as loudly as the page itself. */
.app-sidebar .sidebar-menu > .nav-item.menu-open > .nav-link {
  background: var(--bl-primary-soft);
  color: var(--bl-primary-strong);
}

.app-sidebar .nav-arrow {
  flex-shrink: 0;
  font-size: .75rem;
  opacity: .7;
  transition: transform var(--bl-ease);
}

.app-sidebar .menu-open > .nav-link .nav-arrow { transform: rotate(90deg); }

/* Sub-menu: an indented rail rather than a differently coloured panel. */
.app-sidebar .nav-treeview {
  position: relative;
  margin: .125rem 0 .25rem;
  padding-left: 1.5rem;
}

.app-sidebar .nav-treeview::before {
  content: "";
  position: absolute;
  top: .25rem;
  bottom: .25rem;
  left: 1.0625rem;
  width: 1px;
  background: var(--bl-line-strong);
}

.app-sidebar .nav-treeview .nav-link {
  padding: .4375rem .75rem;
  font-size: .8125rem;
  font-weight: 400;
}

.app-sidebar .nav-treeview .nav-icon { font-size: .9375rem; }

/* Collapsed rail (desktop "sidebar-mini") keeps the icons centred. */
.sidebar-mini.sidebar-collapse .app-sidebar .sidebar-menu .nav-link {
  justify-content: center;
  padding-inline: 0;
}

/* ── 5b. Menu icon colours ────────────────────────────────────────────────── */

/*
 * A menu row can carry an optional tint, written by Menu::iconTint as nothing
 * but `style="--bl-icolor:#rrggbb"`. Everything that can show a menu icon reads
 * that property with its own default, so no extra class has to be threaded
 * through markup that already carries one — and an unset property simply falls
 * through to the default arm of the var().
 */
.app-sidebar .sidebar-menu .nav-icon { color: var(--bl-icolor, inherit); }

/*
 * The open item keeps its white icon on the accent gradient: a tint there would
 * sit on top of the accent and lose all contrast. Section 5's rule already
 * outranks the one above, which is why no !important is needed.
 */

/* Swatch picker on the menu form. */
.bl-color-picker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .3125rem;
  padding: .3125rem 0;
}

.bl-swatch { margin: 0; cursor: pointer; line-height: 0; }

.bl-swatch input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.bl-swatch > span {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  border: 1.5px solid transparent;
  background: color-mix(in srgb, var(--bl-icolor, var(--bl-muted)) 16%, transparent);
  color: var(--bl-icolor, var(--bl-muted));
  font-size: .75rem;
  transition: box-shadow var(--bl-ease), transform var(--bl-ease);
}

.bl-swatch > span::before {
  content: "";
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: currentColor;
}

/* The "no tint" option shows a slash instead of a filled dot. */
.bl-swatch-default > span { background: var(--bl-surface-soft); }
.bl-swatch-default > span::before { display: none; }

.bl-swatch:hover > span { transform: translateY(-1px); }

.bl-swatch input:checked + span {
  border-color: currentColor;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--bl-icolor, var(--bl-muted)) 24%, transparent);
}

.bl-swatch input:focus-visible + span {
  outline: 2px solid var(--bl-primary);
  outline-offset: 2px;
}

/* Free colour picker, sat at the end of the palette as one more swatch. */
.bl-color-custom {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  margin-left: .25rem;
  padding-left: .5rem;
  border-left: 1px solid var(--bl-line-strong);
}

.bl-color-custom input[type="color"] {
  width: 26px;
  height: 26px;
  padding: 0;
  border: 1.5px solid var(--bl-line-strong);
  border-radius: 8px;
  background: none;
  cursor: pointer;
}

/* Chrome/Safari draw the swatch in a nested element with its own padding. */
.bl-color-custom input[type="color"]::-webkit-color-swatch-wrapper { padding: 2px; }
.bl-color-custom input[type="color"]::-webkit-color-swatch { border: 0; border-radius: 5px; }
.bl-color-custom input[type="color"]::-moz-color-swatch { border: 0; border-radius: 5px; }

.bl-color-custom code {
  font-size: .6875rem;
  padding: .15rem .35rem;
  text-transform: uppercase;
}

/* ── 6. Topbar ────────────────────────────────────────────────────────────── */

.app-header {
  --bs-navbar-padding-y: 0;
  min-height: 64px;
  padding-block: 0;
  background: var(--bl-surface) !important;
  border-bottom: 1px solid var(--bl-line);
  box-shadow: none;
}

.app-header > .container-fluid {
  display: flex;
  align-items: center;
  gap: .75rem;
  min-height: 64px;
  padding-inline: clamp(.75rem, 2vw, 1.25rem);
}

/* Icon buttons: sidebar toggle, notifications, theme switch. */
.bl-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--bl-muted);
  font-size: 1.125rem;
  line-height: 1;
  text-decoration: none;
  transition: background-color var(--bl-ease), color var(--bl-ease);
}

.bl-icon-btn:hover,
.bl-icon-btn:focus-visible {
  background: var(--bl-primary-soft);
  color: var(--bl-primary-strong);
}

/* User chip */
.bl-user-chip {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .25rem .625rem .25rem .25rem;
  border-radius: 99px;
  color: var(--bl-text);
  text-decoration: none;
  transition: background-color var(--bl-ease);
}

.bl-user-chip:hover,
.bl-user-chip:focus-visible { background: var(--bl-surface-soft); color: var(--bl-text); }

.bl-user-chip::after { display: none; } /* Bootstrap's dropdown caret */

/* Berlaku untuk <img> maupun <video>: karyawan boleh memasang klip pendek
   sebagai foto profil, dan topbar menampilkannya apa adanya. */
.bl-user-avatar {
  display: block;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bl-primary-soft);
  box-shadow: 0 0 0 2px var(--bl-surface), 0 0 0 3px rgba(var(--bl-primary-rgb), .35);
}

.bl-user-meta { line-height: 1.2; text-align: left; }
.bl-user-name { font-size: .8125rem; font-weight: 600; }
.bl-user-role { font-size: .6875rem; color: var(--bl-muted); }

/* Profile dropdown */
.bl-profile-menu { min-width: 240px; padding: .5rem; }

.bl-profile-head {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .625rem .5rem .75rem;
  border-bottom: 1px solid var(--bl-line);
  margin-bottom: .5rem;
}

.bl-profile-head .bl-user-avatar { width: 40px; height: 40px; flex: 0 0 40px; }
.bl-profile-head-body { min-width: 0; }
.bl-profile-head strong {
  display: block;
  font-size: .875rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bl-profile-head small { color: var(--bl-muted); font-size: .75rem; }

/* ── Notifikasi navbar ────────────────────────────────────────────────────
   Satu lonceng untuk tukar jadwal DAN obrolan tim — lihat
   NotificationController dan public/js/blivos-notifications.js. Markupnya
   ditulis kosong di navbar.php dan diisi skrip lewat penjajakan berkala,
   sama seperti pola blivos-sync-notify.js.

   Dua hal yang dipisah dengan sengaja, dan sebelumnya bercampur:
    - WARNA IKON menjawab "kejadian apa ini secara umum — kabar baik, kabar
      buruk, perlu tindakan, atau obrolan" (lima kelas .bl-notif-ikon.is-* di
      bawah). Beberapa nilai `type` dari NotificationController BERBAGI kelas
      yang sama karena polaritasnya sama (poin_tambah dan tukar_disetujui
      sama-sama .is-setuju, "kabar baik" — lihat blivos-notifications.js:
      ikonUntuk()) tapi tetap dibedakan lewat GLYPH ikonnya (bintang lawan
      centang) supaya sekilas pandang tetap jelas jenis kejadiannya, bukan
      cuma baik-buruknya.
    - GARIS AKSEN DI TEPI KIRI menjawab "sudah saya lihat atau belum" —
      lihat .is-belum-dibaca. Sebelum ini keduanya digabung jadi satu wash
      warna primary yang menutupi seluruh baris, dan karena hampir semua
      jenis notifikasi kebetulan memakai warna primary yang sama, sebuah
      penolakan bisa tercetak dengan ikon centang hijau yang sama seperti
      persetujuan — pemisahan ini yang membuat keduanya tidak lagi bisa
      saling menyamar. */

.bl-notif { position: relative; }

.bl-notif-badge {
  position: absolute;
  top: 4px;
  right: 4px;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--bl-danger);
  color: #fff;
  font-size: .625rem;
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 0 0 2px var(--bl-surface);
}

.bl-notif-menu {
  width: 23rem;
  max-width: calc(100vw - 2rem);
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--bl-line);
  border-radius: var(--bl-radius-lg);
  box-shadow: 0 20px 44px -20px rgba(15, 18, 30, .35);
}

.bl-notif-kepala {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .875rem 1rem;
  border-bottom: 1px solid var(--bl-line);
  font-size: .875rem;
  font-weight: 600;
  color: var(--bl-text);
}

.bl-notif-baca-semua {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--bl-primary-strong);
  font-size: .75rem;
  font-weight: 600;
  cursor: pointer;
}

.bl-notif-baca-semua:hover { text-decoration: underline; }

.bl-notif-daftar {
  max-height: 23rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--bl-line-strong) transparent;
}

.bl-notif-daftar:focus-visible { outline: 2px solid var(--bl-primary); outline-offset: -2px; }

.bl-notif-kosong {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .625rem;
  padding: 2.75rem 1.5rem;
  color: var(--bl-muted);
  font-size: .8125rem;
  text-align: center;
}

.bl-notif-kosong i {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  font-size: 1.25rem;
  color: var(--bl-primary);
  background: var(--bl-primary-soft);
}

/* Baris satu notifikasi. Aksen tepi kiri TRANSPARAN secara bawaan dan hanya
   diberi warna oleh .is-belum-dibaca di bawah — dengan begitu setiap baris
   punya lebar dalam yang identik baik sudah dibaca maupun belum, dan garis
   itu tidak pernah membuat teksnya melompat beberapa piksel saat berpindah
   status setelah dibaca. */
.bl-notif-item {
  position: relative;
  display: flex;
  gap: .75rem;
  align-items: flex-start;
  padding: .8125rem 1rem .8125rem calc(1rem - 3px);
  border-left: 3px solid transparent;
  border-bottom: 1px solid var(--bl-line);
  text-decoration: none;
  color: inherit;
  transition: background-color var(--bl-ease), border-color var(--bl-ease);
}

.bl-notif-item:last-child { border-bottom: none; }
.bl-notif-item:hover, .bl-notif-item:focus-visible { background: var(--bl-surface-soft); color: inherit; }

.bl-notif-item.is-belum-dibaca {
  border-left-color: var(--bl-primary);
  background: color-mix(in srgb, var(--bl-primary) 6%, var(--bl-surface));
}

.bl-notif-item.is-belum-dibaca:hover {
  background: color-mix(in srgb, var(--bl-primary) 10%, var(--bl-surface));
}

.bl-notif-ikon {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  border-radius: 11px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  color: var(--bl-nav);
  background: var(--bl-surface-soft);
}

/* Lima varian, satu per nilai `type` — lihat blivos-notifications.js:ikonUntuk().
   "Menunggu" memakai warna yang sama dengan "Ajakan masuk": keduanya berarti
   sama bagi orangnya — "ada yang menunggu jawaban Anda" — hanya pengirimnya
   yang beda (rekan, atau giliran SPV/HRD). */
.bl-notif-ikon.is-chat { color: var(--bl-info); background: color-mix(in srgb, var(--bl-info) 15%, transparent); }
.bl-notif-ikon.is-masuk,
.bl-notif-ikon.is-menunggu { color: var(--bl-warning); background: color-mix(in srgb, var(--bl-warning) 16%, transparent); }
.bl-notif-ikon.is-setuju { color: var(--bl-success); background: color-mix(in srgb, var(--bl-success) 15%, transparent); }
.bl-notif-ikon.is-tolak { color: var(--bl-danger); background: color-mix(in srgb, var(--bl-danger) 14%, transparent); }

.bl-notif-teks { min-width: 0; flex: 1 1 auto; padding-top: .0625rem; }

.bl-notif-judul {
  display: flex;
  align-items: center;
  gap: .375rem;
  font-size: .8125rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--bl-text);
}

.bl-notif-item.is-belum-dibaca .bl-notif-judul::after {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--bl-primary);
  flex: 0 0 auto;
}

.bl-notif-isi {
  display: -webkit-box;
  margin-top: .1875rem;
  font-size: .75rem;
  line-height: 1.5;
  color: var(--bl-muted);
  overflow: hidden;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.bl-notif-waktu {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  margin-top: .375rem;
  font-size: .6875rem;
  color: var(--bl-muted);
  opacity: .85;
}

.bl-notif-kaki { padding: .75rem 1rem; border-top: 1px solid var(--bl-line); background: var(--bl-surface-soft); }

.bl-notif-push {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  width: 100%;
  padding: .5625rem;
  border: 1px solid var(--bl-line-strong);
  border-radius: var(--bl-radius-sm);
  background: var(--bl-surface);
  color: var(--bl-nav);
  font-size: .75rem;
  font-weight: 600;
  cursor: pointer;
  transition: all var(--bl-ease);
}

.bl-notif-push:hover:not(:disabled) { border-color: var(--bl-primary); color: var(--bl-primary-strong); }
.bl-notif-push.is-aktif { color: var(--bl-success); border-color: color-mix(in srgb, var(--bl-success) 40%, transparent); background: color-mix(in srgb, var(--bl-success) 8%, var(--bl-surface)); }
.bl-notif-push:disabled { opacity: .6; cursor: not-allowed; }

@media (max-width: 575.98px) {
  /*
   * `dropdown-menu-end` menempelkan tepi KANAN menu ke tepi KANAN tombol
   * lonceng — tapi lonceng bukan elemen paling kanan topbar (masih ada
   * tombol tema dan avatar di sebelahnya), jadi di layar sempit lebar tetap
   * 23rem itu menabrak tepi KIRI layar sebelum sempat digeser Popper. Yang
   * terpotong bukan cuma ujungnya: judul "Notifikasi", tombol "Tandai semua
   * dibaca", dan sebagian daftar ikut terdorong ke luar layar — persis
   * keluhan "tidak responsive".
   *
   * Dikunci sebagai lembar mengambang di bawah topbar (position: fixed,
   * lebar mengikuti layar) supaya posisinya tidak lagi bergantung pada di
   * mana tombolnya berada. !important perlu menimpa inline style yang
   * dipasang Popper sendiri (position/inset/transform) tiap kali dropdown
   * dibuka — tanpa itu Popper menimpa balik aturan ini setiap render.
   */
  .bl-notif-menu {
    position: fixed !important;
    inset: 4.5rem .75rem auto .75rem !important;
    transform: none !important;
    width: auto !important;
    max-width: none !important;
    max-height: calc(100dvh - 5.5rem);
    z-index: 1045;
  }

  .bl-notif-daftar { max-height: calc(100dvh - 13rem); }
}

/* Theme toggle swaps which glyph is shown, driven by data-bs-theme. */
.bl-theme-toggle .bi-sun { display: none; }
:root[data-bs-theme="dark"] .bl-theme-toggle .bi-sun { display: inline-block; }
:root[data-bs-theme="dark"] .bl-theme-toggle .bi-moon-stars { display: none; }

/* ── 7. Cards ─────────────────────────────────────────────────────────────── */

.card {
  --bs-card-bg: var(--bl-surface);
  --bs-card-border-color: var(--bl-line);
  --bs-card-border-radius: var(--bl-radius);
  --bs-card-inner-border-radius: calc(var(--bl-radius) - 1px);
  --bs-card-spacer-x: 1.375rem;
  --bs-card-spacer-y: 1.25rem;
  --bs-card-cap-bg: transparent;
  --bs-card-color: var(--bl-text);
  border: 1px solid var(--bl-line);
  border-radius: var(--bl-radius);
  box-shadow: var(--bl-shadow);
  margin-bottom: 1.25rem;
  transition: box-shadow var(--bl-ease), transform var(--bl-ease);
}

/* A hover lift, kept small enough not to feel like a button. */
.card:hover { box-shadow: var(--bl-shadow-md); }

.card.shadow,
.card.shadow-sm,
.card.shadow-lg { box-shadow: var(--bl-shadow) !important; }

.card-header {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: 1.125rem var(--bs-card-spacer-x);
  border-bottom: 1px solid var(--bl-line);
  background: transparent;
}

.card-header .card-title {
  margin: 0;
  color: var(--bl-text);
  font-size: .9375rem;
  font-weight: 600;
}

.card-header .card-title i { color: var(--bl-muted); }

.card-footer {
  padding: .875rem var(--bs-card-spacer-x);
  border-top: 1px solid var(--bl-line);
  background: transparent;
  color: var(--bl-muted);
  font-size: .8125rem;
}

.card-footer.bg-body-tertiary { background: var(--bl-surface-soft) !important; }

/* AdminLTE's own card colour variants would reintroduce its palette. */
.card.card-primary:not(.card-outline) > .card-header { background: var(--bl-primary); }
.card-outline { border-top-width: 1px; }

/* ── 8. Buttons ───────────────────────────────────────────────────────────── */

.btn {
  --bs-btn-border-radius: var(--bl-radius-sm);
  --bs-btn-padding-x: 1.125rem;
  --bs-btn-padding-y: .5rem;
  --bs-btn-font-size: .875rem;
  --bs-btn-font-weight: 500;
  --bs-btn-focus-box-shadow: 0 0 0 3px rgba(var(--bl-primary-rgb), .18);
  transition: background-color var(--bl-ease), border-color var(--bl-ease),
              color var(--bl-ease), box-shadow var(--bl-ease), transform var(--bl-ease);
}

.btn:active { transform: translateY(1px); }

.btn-sm {
  --bs-btn-padding-x: .75rem;
  --bs-btn-padding-y: .3125rem;
  --bs-btn-font-size: .8125rem;
  --bs-btn-border-radius: 7px;
}

.btn-lg {
  --bs-btn-padding-x: 1.5rem;
  --bs-btn-padding-y: .6875rem;
  --bs-btn-font-size: .9375rem;
  --bs-btn-border-radius: 10px;
}

/*
 * Bootstrap compiles each variant's colours into the class itself, so the token
 * swap in section 2 does not reach them — they are re-pointed one by one.
 */
.btn-primary {
  --bs-btn-bg: var(--bl-primary);
  --bs-btn-border-color: var(--bl-primary);
  --bs-btn-hover-bg: var(--bl-primary-strong);
  --bs-btn-hover-border-color: var(--bl-primary-strong);
  --bs-btn-active-bg: var(--bl-primary-strong);
  --bs-btn-active-border-color: var(--bl-primary-strong);
  --bs-btn-disabled-bg: var(--bl-primary);
  --bs-btn-disabled-border-color: var(--bl-primary);
  box-shadow: 0 4px 12px rgba(var(--bl-primary-rgb), .28);
}

.btn-primary:hover { box-shadow: 0 6px 18px rgba(var(--bl-primary-rgb), .36); }

.btn-outline-primary {
  --bs-btn-color: var(--bl-primary-strong);
  --bs-btn-border-color: rgba(var(--bl-primary-rgb), .5);
  --bs-btn-hover-bg: var(--bl-primary);
  --bs-btn-hover-border-color: var(--bl-primary);
  --bs-btn-active-bg: var(--bl-primary-strong);
  --bs-btn-active-border-color: var(--bl-primary-strong);
}

.btn-success { --bs-btn-bg: var(--bl-success); --bs-btn-border-color: var(--bl-success); --bs-btn-hover-bg: #22b263; --bs-btn-hover-border-color: #22b263; }
.btn-warning { --bs-btn-bg: var(--bl-warning); --bs-btn-border-color: var(--bl-warning); --bs-btn-color: #fff; --bs-btn-hover-color: #fff; --bs-btn-hover-bg: #f08f31; --bs-btn-hover-border-color: #f08f31; }
.btn-danger  { --bs-btn-bg: var(--bl-danger);  --bs-btn-border-color: var(--bl-danger);  --bs-btn-hover-bg: #d84546; --bs-btn-hover-border-color: #d84546; }
.btn-info    { --bs-btn-bg: var(--bl-info);    --bs-btn-border-color: var(--bl-info);    --bs-btn-color: #fff; --bs-btn-hover-color: #fff; --bs-btn-hover-bg: #00b9d0; --bs-btn-hover-border-color: #00b9d0; }

.btn-outline-success { --bs-btn-color: var(--bl-success); --bs-btn-border-color: rgba(40, 199, 111, .5); --bs-btn-hover-bg: var(--bl-success); --bs-btn-hover-border-color: var(--bl-success); }
.btn-outline-warning { --bs-btn-color: var(--bl-warning); --bs-btn-border-color: rgba(255, 159, 67, .5); --bs-btn-hover-bg: var(--bl-warning); --bs-btn-hover-border-color: var(--bl-warning); --bs-btn-hover-color: #fff; }
.btn-outline-danger  { --bs-btn-color: var(--bl-danger);  --bs-btn-border-color: rgba(234, 84, 85, .5);  --bs-btn-hover-bg: var(--bl-danger);  --bs-btn-hover-border-color: var(--bl-danger); }
.btn-outline-secondary {
  --bs-btn-color: var(--bl-muted);
  --bs-btn-border-color: var(--bl-line-strong);
  --bs-btn-hover-bg: var(--bl-surface-soft);
  --bs-btn-hover-border-color: var(--bl-line-strong);
  --bs-btn-hover-color: var(--bl-text);
  --bs-btn-active-bg: var(--bl-surface-soft);
  --bs-btn-active-color: var(--bl-text);
}

/* Square icon-only buttons in table action columns. */
.btn-sm > i:only-child { font-size: .875rem; }

/* ── 9. Forms ─────────────────────────────────────────────────────────────── */

.form-label {
  margin-bottom: .375rem;
  color: var(--bl-text);
  font-size: .8125rem;
  font-weight: 500;
}

.form-control,
.form-select {
  padding: .5625rem .875rem;
  border: 1px solid var(--bl-line-strong);
  border-radius: var(--bl-radius-sm);
  background-color: var(--bl-surface);
  color: var(--bl-text);
  font-size: .875rem;
  transition: border-color var(--bl-ease), box-shadow var(--bl-ease);
}

.form-control::placeholder { color: var(--bl-muted); }

.form-control:focus,
.form-select:focus {
  border-color: rgba(var(--bl-primary-rgb), .55);
  box-shadow: 0 0 0 3px rgba(var(--bl-primary-rgb), .12);
  background-color: var(--bl-surface);
  color: var(--bl-text);
}

.form-control:disabled,
.form-select:disabled { background-color: var(--bl-surface-soft); color: var(--bl-muted); }

.form-control-sm, .form-select-sm { padding: .375rem .625rem; font-size: .8125rem; }

.form-text { color: var(--bl-muted); font-size: .75rem; }

.input-group-text {
  border: 1px solid var(--bl-line-strong);
  border-radius: var(--bl-radius-sm);
  background: var(--bl-surface-soft);
  /* Falls back to the muted grey unless a .bl-icolor-* class supplies a tint —
     the menu form's icon preview uses that to echo the chosen colour. */
  color: var(--bl-icolor, var(--bl-muted));
  font-size: .875rem;
  transition: border-color var(--bl-ease), color var(--bl-ease);
}

/* An addon and its field read as one control, so they light up together. */
.input-group:focus-within .input-group-text {
  border-color: rgba(var(--bl-primary-rgb), .55);
  color: var(--bl-primary-strong);
}

.input-group .form-control:focus,
.input-group .form-select:focus { z-index: 5; }

.form-check-input {
  width: 1.05em;
  height: 1.05em;
  margin-top: .225em;
  border: 1.5px solid var(--bl-line-strong);
  background-color: var(--bl-surface);
  transition: background-color var(--bl-ease), border-color var(--bl-ease), box-shadow var(--bl-ease);
}

.form-check-input:checked {
  background-color: var(--bl-primary);
  border-color: var(--bl-primary);
}

.form-check-input:focus {
  border-color: rgba(var(--bl-primary-rgb), .55);
  box-shadow: 0 0 0 3px rgba(var(--bl-primary-rgb), .15);
}

.form-check-label { font-size: .875rem; }

.form-switch .form-check-input { width: 2em; border-radius: 2em; }

/* ── 10. Tables ───────────────────────────────────────────────────────────── */

.table {
  --bs-table-bg: transparent;
  --bs-table-color: var(--bl-text);
  --bs-table-border-color: var(--bl-line);
  --bs-table-striped-bg: var(--bl-surface-soft);
  --bs-table-striped-color: var(--bl-text);
  --bs-table-hover-bg: var(--bl-primary-soft);
  --bs-table-hover-color: var(--bl-text);
  font-size: .875rem;
  margin-bottom: 0;
}

.table > thead > tr > th {
  padding: .8125rem 1.375rem;
  border-bottom: 1px solid var(--bl-line);
  background: var(--bl-surface-soft);
  color: var(--bl-muted);
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  white-space: nowrap;
}

.table > tbody > tr > td {
  padding: .8125rem 1.375rem;
  border-bottom: 1px solid var(--bl-line);
  vertical-align: middle;
}

.table > tbody > tr:last-child > td { border-bottom: 0; }

.table-hover > tbody > tr { transition: background-color var(--bl-ease); }

/* Striping on top of the card surface reads as noise at this contrast level. */
.table-striped > tbody > tr:nth-of-type(odd) > * { --bs-table-bg-type: transparent; }

.card > .card-body.p-0 > .table-responsive > .table > tbody > tr:last-child > td:first-child { border-bottom-left-radius: var(--bl-radius); }
.card > .card-body.p-0 > .table-responsive > .table > tbody > tr:last-child > td:last-child { border-bottom-right-radius: var(--bl-radius); }

/* ── 11. Badges, alerts, dropdowns, modals, pagination ────────────────────── */

.badge {
  --bs-badge-padding-x: .5rem;
  --bs-badge-padding-y: .3em;
  --bs-badge-border-radius: 6px;
  --bs-badge-font-size: .6875rem;
  --bs-badge-font-weight: 600;
  letter-spacing: .01em;
}

/*
 * Solid badge variants become tinted chips: at this size a filled block of
 * colour is the loudest thing on the page, which is not what a status deserves.
 */
.badge.text-bg-success { background: rgba(40, 199, 111, .14) !important; color: #1f9d57 !important; }
.badge.text-bg-danger  { background: rgba(234, 84, 85, .14) !important;  color: #d43b3c !important; }
.badge.text-bg-warning { background: rgba(255, 159, 67, .16) !important; color: #d97b1d !important; }
.badge.text-bg-info    { background: rgba(0, 207, 232, .14) !important;  color: #0098ad !important; }
.badge.text-bg-primary { background: var(--bl-primary-soft) !important;  color: var(--bl-primary-strong) !important; }
.badge.text-bg-secondary { background: rgba(122, 127, 149, .14) !important; color: var(--bl-muted) !important; }
.badge.text-bg-dark    { background: rgba(47, 51, 73, .12) !important;   color: var(--bl-text) !important; }
.badge.text-bg-light   { background: var(--bl-surface-soft) !important;  color: var(--bl-muted) !important; }
.badge.border { border-color: var(--bl-line-strong) !important; }

:root[data-bs-theme="dark"] .badge.text-bg-success { color: #4ede93 !important; }
:root[data-bs-theme="dark"] .badge.text-bg-danger  { color: #ff8384 !important; }
:root[data-bs-theme="dark"] .badge.text-bg-warning { color: #ffbc7a !important; }
:root[data-bs-theme="dark"] .badge.text-bg-info    { color: #4fe1f2 !important; }

.alert {
  --bs-alert-border-radius: var(--bl-radius);
  padding: .9375rem 1.125rem;
  border: 1px solid transparent;
  border-left-width: 3px;
  font-size: .875rem;
}

.alert-success { background: rgba(40, 199, 111, .08);  border-color: rgba(40, 199, 111, .2);  border-left-color: var(--bl-success); color: var(--bl-text); }
.alert-danger  { background: rgba(234, 84, 85, .08);   border-color: rgba(234, 84, 85, .2);   border-left-color: var(--bl-danger);  color: var(--bl-text); }
.alert-warning { background: rgba(255, 159, 67, .09);  border-color: rgba(255, 159, 67, .22); border-left-color: var(--bl-warning); color: var(--bl-text); }
.alert-info    { background: rgba(0, 207, 232, .07);   border-color: rgba(0, 207, 232, .2);   border-left-color: var(--bl-info);    color: var(--bl-text); }
.alert-info > i, .alert-success > i, .alert-warning > i, .alert-danger > i { font-size: 1rem; }
.alert-success > i { color: var(--bl-success); }
.alert-danger > i  { color: var(--bl-danger); }
.alert-warning > i { color: var(--bl-warning); }
.alert-info > i    { color: var(--bl-info); }

.dropdown-menu {
  --bs-dropdown-border-color: var(--bl-line);
  --bs-dropdown-border-radius: var(--bl-radius);
  --bs-dropdown-bg: var(--bl-surface);
  --bs-dropdown-link-color: var(--bl-text);
  --bs-dropdown-link-hover-bg: var(--bl-primary-soft);
  --bs-dropdown-link-hover-color: var(--bl-primary-strong);
  --bs-dropdown-link-active-bg: var(--bl-primary);
  --bs-dropdown-item-padding-x: .75rem;
  --bs-dropdown-item-padding-y: .5rem;
  --bs-dropdown-font-size: .875rem;
  padding: .375rem;
  box-shadow: var(--bl-shadow-md);
}

.dropdown-item { border-radius: 7px; }
.dropdown-divider { border-color: var(--bl-line); }

.modal-content {
  border: 1px solid var(--bl-line);
  border-radius: var(--bl-radius-lg);
  background: var(--bl-surface);
  box-shadow: var(--bl-shadow-lg);
}

.modal-header, .modal-footer { border-color: var(--bl-line); padding: 1.125rem 1.375rem; }
.modal-body { padding: 1.375rem; }
.modal-title { font-size: 1.0625rem; font-weight: 600; }

/*
 * Latar belakang modal: kaca buram (frosted glass), bukan gelap pekat bawaan
 * Bootstrap. `.modal-backdrop` disuntikkan Bootstrap JS sebagai satu elemen
 * global yang sama di SETIAP modal di SELURUH halaman (bukan sesuatu yang
 * ditulis per halaman), jadi satu aturan di sini otomatis berlaku di mana
 * pun modal dibuka. Warnanya dibuat nyaris transparan dan mengikuti tema
 * aktif — putih tipis di mode terang, gelap tipis di mode gelap — supaya
 * yang benar-benar memisahkan modal dari halaman di baliknya adalah
 * BURAMNYA (backdrop-filter), bukan gelapnya.
 */
.modal-backdrop {
  background-color: rgba(255, 255, 255, .3);
  backdrop-filter: blur(8px) saturate(1.4);
  -webkit-backdrop-filter: blur(8px) saturate(1.4);
}
.modal-backdrop.show { opacity: 1; }

:root[data-bs-theme="dark"] .modal-backdrop { background-color: rgba(12, 13, 24, .45); }

.pagination {
  --bs-pagination-border-color: var(--bl-line-strong);
  --bs-pagination-bg: var(--bl-surface);
  --bs-pagination-color: var(--bl-muted);
  --bs-pagination-hover-bg: var(--bl-primary-soft);
  --bs-pagination-hover-color: var(--bl-primary-strong);
  --bs-pagination-hover-border-color: rgba(var(--bl-primary-rgb), .3);
  --bs-pagination-active-bg: var(--bl-primary);
  --bs-pagination-active-border-color: var(--bl-primary);
  --bs-pagination-focus-bg: var(--bl-primary-soft);
  --bs-pagination-focus-box-shadow: 0 0 0 3px rgba(var(--bl-primary-rgb), .15);
  --bs-pagination-border-radius: var(--bl-radius-sm);
  --bs-pagination-font-size: .875rem;
  gap: .25rem;
}

.page-link { border-radius: var(--bl-radius-sm) !important; }

.progress {
  --bs-progress-bg: var(--bl-surface-soft);
  --bs-progress-border-radius: 99px;
  --bs-progress-bar-bg: var(--bl-primary);
  height: .375rem;
}

/* Toasts and SweetAlert2 dialogs inherit the same surface + radius. */
.blivos-toast {
  border: 1px solid var(--bl-line) !important;
  border-left-width: 3px !important;
  border-radius: var(--bl-radius) !important;
  background: var(--bl-surface);
  box-shadow: var(--bl-shadow-md) !important;
}

.swal2-popup.blivos-dialog {
  border: 1px solid var(--bl-line);
  border-radius: var(--bl-radius-lg);
  box-shadow: var(--bl-shadow-lg);
}

/* ── 12. Dashboard widgets ────────────────────────────────────────────────── */

/* In-page anchors (e.g. the dashboard's #aktivitas) clear the sticky topbar. */
.app-main [id] { scroll-margin-top: 1.5rem; }

.bl-page-title {
  margin: 0 0 .25rem;
  font-size: 1.375rem;
  font-weight: 600;
}

.bl-page-sub { margin: 0; color: var(--bl-muted); font-size: .875rem; }

.bl-section-title {
  margin: 0 0 .875rem;
  color: var(--bl-muted);
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
}

/* Welcome card ---------------------------------------------------------- */

.bl-welcome {
  position: relative;
  overflow: hidden;
  height: 100%;
  margin-bottom: 0;
}

.bl-welcome .card-body { position: relative; z-index: 1; padding: 1.5rem; }

.bl-welcome-title {
  margin: 0 0 .25rem;
  font-size: 1.125rem;
  font-weight: 600;
}

.bl-welcome-sub { margin: 0 0 1.25rem; color: var(--bl-muted); font-size: .8125rem; }

.bl-welcome-amount {
  display: block;
  margin-bottom: .125rem;
  color: var(--bl-primary-strong);
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1.15;
}

.bl-welcome-amount-label {
  display: block;
  margin-bottom: 1.125rem;
  color: var(--bl-muted);
  font-size: .75rem;
}

/* Decorative badge in the top-right corner, hidden from assistive tech. */
.bl-welcome-art {
  position: absolute;
  top: 1.25rem;
  right: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 74px;
  height: 74px;
  border-radius: 20px;
  background: linear-gradient(135deg, rgba(var(--bl-primary-rgb), .16), rgba(var(--bl-primary-rgb), .04));
  color: var(--bl-primary);
  font-size: 2.125rem;
  pointer-events: none;
}

/* Soft halo behind the badge, painted on the card rather than under it. */
.bl-welcome::before {
  content: "";
  position: absolute;
  top: -70px;
  right: -60px;
  width: 190px;
  height: 190px;
  border-radius: 50%;
  background: rgba(var(--bl-primary-rgb), .05);
  pointer-events: none;
}

/* Statistics strip ------------------------------------------------------- */

.bl-stats { height: 100%; margin-bottom: 0; }

.bl-stats .card-body { display: flex; flex-direction: column; }

.bl-stats-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1.25rem;
  /* Sits on the card's baseline, level with the welcome card's button. */
  margin-top: auto;
}

.bl-stat { display: flex; align-items: center; gap: .75rem; min-width: 0; }

.bl-stat-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex: 0 0 40px;
  border-radius: 10px;
  font-size: 1.125rem;
}

/* One tint per metric — different hues, one saturation level. */
.bl-tint-primary { background: var(--bl-primary-soft); color: var(--bl-primary-strong); }
.bl-tint-success { background: rgba(40, 199, 111, .13); color: #1f9d57; }
.bl-tint-warning { background: rgba(255, 159, 67, .15); color: #d97b1d; }
.bl-tint-danger  { background: rgba(234, 84, 85, .13);  color: #d43b3c; }
.bl-tint-info    { background: rgba(0, 207, 232, .13);  color: #0098ad; }

:root[data-bs-theme="dark"] .bl-tint-success { color: #4ede93; }
:root[data-bs-theme="dark"] .bl-tint-warning { color: #ffbc7a; }
:root[data-bs-theme="dark"] .bl-tint-danger  { color: #ff8384; }
:root[data-bs-theme="dark"] .bl-tint-info    { color: #4fe1f2; }

/* The markup uses <span> throughout so nothing here relies on block defaults. */
.bl-stat-body { display: block; min-width: 0; }

.bl-stat-label {
  display: block;
  color: var(--bl-muted);
  font-size: .75rem;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.bl-stat-value { display: block; font-size: 1.125rem; font-weight: 600; line-height: 1.25; }

/* Small metric cards ----------------------------------------------------- */

/* Two-by-two block that has to end level with the tall cards beside it. */
.bl-metric-grid { height: 100%; align-content: stretch; }

.bl-metric { margin-bottom: 0; height: 100%; }
.bl-metric .card-body { display: flex; flex-direction: column; padding: 1.125rem 1.25rem; }
.bl-metric .bl-metric-label { margin-top: auto; }

.bl-metric-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: .5rem;
  margin-bottom: .875rem;
}

.bl-metric-head .bl-stat-icon { width: 36px; height: 36px; flex-basis: 36px; font-size: 1rem; }

.bl-metric-label { color: var(--bl-muted); font-size: .75rem; line-height: 1.3; }
.bl-metric-value { display: block; font-size: 1.5rem; font-weight: 600; line-height: 1.2; }
.bl-metric-foot { margin-top: .25rem; color: var(--bl-muted); font-size: .6875rem; }

.bl-delta {
  display: inline-flex;
  align-items: center;
  gap: .125rem;
  font-size: .75rem;
  font-weight: 600;
}

.bl-delta.up { color: var(--bl-success); }
.bl-delta.down { color: var(--bl-danger); }
.bl-delta.flat { color: var(--bl-muted); }

/* Bar chart -------------------------------------------------------------- */

.bl-chart-card { height: 100%; margin-bottom: 0; }
.bl-chart-card .card-body { display: flex; flex-direction: column; }

/* The plot grows into whatever height the row settles on. */
.bl-chart {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: .5rem;
  flex: 1 1 auto;
  min-height: 150px;
  margin: .25rem 0 1.25rem;
}

.bl-chart-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .5rem;
  flex: 1 1 0;
  min-width: 0;
  height: 100%;
}

.bl-bar-track {
  position: relative;
  display: flex;
  align-items: flex-end;
  width: 100%;
  max-width: 26px;
  flex: 1 1 auto;
}

.bl-bar-fill {
  display: block;
  width: 100%;
  min-height: 6px;
  border-radius: 6px;
  background: var(--bl-primary-soft);
  transition: height .45s cubic-bezier(.4, 0, .2, 1), background-color var(--bl-ease);
}

/* Only the peak day carries the solid accent — the rest stay as context. */
.bl-chart-col.is-peak .bl-bar-fill {
  background: linear-gradient(180deg, var(--bl-primary), var(--bl-primary-strong));
  box-shadow: 0 4px 12px rgba(var(--bl-primary-rgb), .3);
}

.bl-chart-col:hover .bl-bar-fill { background: rgba(var(--bl-primary-rgb), .28); }
.bl-chart-col.is-peak:hover .bl-bar-fill { background: linear-gradient(180deg, var(--bl-primary), var(--bl-primary-strong)); }

.bl-bar-label {
  color: var(--bl-muted);
  font-size: .6875rem;
  white-space: nowrap;
}

.bl-chart-col.is-peak .bl-bar-label { color: var(--bl-text); font-weight: 600; }

.bl-chart-summary { display: flex; align-items: center; gap: .875rem; }
.bl-chart-summary-figure { font-size: 1.5rem; font-weight: 600; line-height: 1; }
.bl-chart-summary-text { color: var(--bl-muted); font-size: .75rem; line-height: 1.45; }

/* Breakdown list --------------------------------------------------------- */

.bl-breakdown-head { display: flex; align-items: center; gap: .625rem; margin-bottom: .25rem; }
.bl-breakdown-figure { font-size: 1.75rem; font-weight: 600; line-height: 1.1; }
.bl-breakdown-note { margin-bottom: 1.375rem; color: var(--bl-muted); font-size: .75rem; }

.bl-breakdown-list { display: flex; flex-direction: column; gap: 1.125rem; }

.bl-breakdown-item { display: flex; align-items: center; gap: .75rem; min-width: 0; }

.bl-breakdown-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border-radius: 9px;
  font-size: 1rem;
}

.bl-breakdown-body { display: block; flex: 1 1 auto; min-width: 0; }

.bl-breakdown-name {
  font-size: .8125rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bl-breakdown-desc {
  color: var(--bl-muted);
  font-size: .6875rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bl-breakdown-side { display: block; flex: 0 0 74px; text-align: right; }
.bl-breakdown-value { display: block; font-size: .8125rem; font-weight: 600; }

.bl-breakdown-side .progress {
  height: 4px;
  margin-top: .375rem;
  background: var(--bl-surface-soft);
}

.bl-breakdown-side .progress-bar { background: var(--bl-primary); border-radius: 99px; }

/* Sign-in page ----------------------------------------------------------- */

.bl-auth-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  margin-bottom: .875rem;
  border-radius: 15px;
  background: linear-gradient(135deg, var(--bl-primary), var(--bl-primary-strong));
  color: #fff;
  font-size: 1.375rem;
  box-shadow: 0 8px 22px rgba(var(--bl-primary-rgb), .32);
}

/* ── 13. Loading & empty states ───────────────────────────────────────────── */

.bl-skeleton {
  border-radius: 6px;
  background: linear-gradient(90deg,
    var(--bl-surface-soft) 25%,
    rgba(var(--bl-primary-rgb), .07) 37%,
    var(--bl-surface-soft) 63%);
  background-size: 400% 100%;
  animation: bl-shimmer 1.4s ease infinite;
}

.bl-skeleton-line { height: .75rem; margin-bottom: .5rem; }
.bl-skeleton-line:last-child { width: 60%; margin-bottom: 0; }

@keyframes bl-shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .bl-skeleton { animation: none; }
  .bl-bar-fill { transition: none; }
  .app-main { scroll-behavior: auto; }
}

.bl-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .375rem;
  padding: 3rem 1.5rem;
  text-align: center;
}

.bl-empty-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin-bottom: .375rem;
  border-radius: 16px;
  background: var(--bl-surface-soft);
  color: var(--bl-muted);
  font-size: 1.5rem;
}

.bl-empty-title { color: var(--bl-text); font-size: .9375rem; font-weight: 600; }
.bl-empty-text { max-width: 26rem; color: var(--bl-muted); font-size: .8125rem; }

/* ── 14. Responsive ───────────────────────────────────────────────────────── */

@media (max-width: 1399.98px) {
  .bl-breakdown-side { flex-basis: 64px; }
}

@media (max-width: 991.98px) {
  /* Off-canvas drawer: AdminLTE slides it in, this gives it the floating look. */
  .app-sidebar {
    z-index: 1038;
    border-right: 0;
    box-shadow: var(--bl-shadow-lg) !important;
  }

  .app-content-header { padding-top: 1.125rem; }
}

@media (max-width: 767.98px) {
  .bl-stats-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.125rem; }
  .bl-welcome-art { width: 60px; height: 60px; font-size: 1.75rem; border-radius: 16px; }
  .app-content-header h1, .bl-page-title { font-size: 1.1875rem; }
  .card { margin-bottom: 1rem; }
  .table > thead > tr > th,
  .table > tbody > tr > td { padding-inline: 1rem; }
}

@media (max-width: 575.98px) {
  /* Keep the topbar to one row: the user's name drops out. */
  .bl-user-meta { display: none; }
  .bl-user-chip { padding-right: .25rem; }
  .app-header > .container-fluid { gap: .25rem; }
  .bl-stats-grid { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
  .bl-chart { height: 128px; gap: .25rem; }
  .bl-bar-label { font-size: .625rem; }
  .card-header { flex-wrap: wrap; }
}
