/* =========================================================================
   VA Dashboard — UI refresh foundation
   Loaded AFTER assets/css/argon.css and assets/css/custom.css.
   Scope: design tokens + layout shell + common components.
   Per-page styles live in their own page partials.
   ========================================================================= */

/* ---------- Body / UI font (Figtree) ----------------------------------- */
/* Self-hosted Figtree variable woff2 lives at public/fonts/figtree/ and is
   wired in via parent.blade.php. Applied to <body> so every element inherits
   it; the explicit list catches argon.css rules that hardcode "Open Sans"
   (body, .tooltip, .popover, .ql-container) so the old font can't leak in
   through the cascade. The CSS variable mirrors Bootstrap's so any rule
   using var(--font-family-sans-serif) — e.g. swal2 fallback — picks Figtree.
   `!important` on body is needed because public/assets/css/custom.css ships
   a legacy `body { font-family: 'Lexend Deca' !important }` rule we can't
   hand-edit (vendored file). app.css loads after custom.css, so the
   !important tie-break by source order makes Figtree win.
   Monetary nominal blocks below opt back into IBM Plex Sans via .font-nominal. */
:root {
  --font-family-sans-serif: 'Figtree', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
}
body {
  font-family: var(--font-family-sans-serif) !important;
}
.tooltip,
.popover,
.ql-container {
  font-family: var(--font-family-sans-serif);
}

/* ---------- Custom tooltip (Bootstrap 4) ------------------------------- */
/* Replaces the OS-default browser tooltip with a styled dark-navy bubble +
   arrow pointer. Bootstrap 4 reads the `title` attribute on the trigger
   element and renders:
     <div class="tooltip bs-tooltip-{top|right|bottom|left}">
       <div class="arrow"></div>
       <div class="tooltip-inner">title text</div>
     </div>
   Init lives in parent.blade.php — `$(body).tooltip({ selector: '[title]...' })`
   delegates to every descendant with a title attribute, including content
   added later (DataTables redraws, AJAX-injected fragments).
   To opt OUT for a specific element: add `.no-tooltip` class or use a
   `data-toggle=` attribute (both excluded by the delegation selector). */
.tooltip {
  font-size: .8125rem;
  pointer-events: none;
}
/* Argon ships .tooltip.show { opacity: .9 } — bump to full so the dark
   bubble + white text reads at full contrast. */
.tooltip.show { opacity: 1; }
.tooltip-inner {
  background-color: var(--text);
  color: #fff;
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius);
  max-width: 260px;
  font-weight: 500;
  line-height: 1.45;
  text-align: left;
  box-shadow: 0 8px 24px rgba(20, 30, 55, 0.18);
}
/* Arrow color matches bubble bg per placement. Covers both explicit
   .bs-tooltip-{side} and Popper's auto-placement [x-placement^=side]. */
.bs-tooltip-top .arrow::before,
.bs-tooltip-auto[x-placement^='top'] .arrow::before { border-top-color: var(--text); }
.bs-tooltip-bottom .arrow::before,
.bs-tooltip-auto[x-placement^='bottom'] .arrow::before { border-bottom-color: var(--text); }
.bs-tooltip-left .arrow::before,
.bs-tooltip-auto[x-placement^='left'] .arrow::before { border-left-color: var(--text); }
.bs-tooltip-right .arrow::before,
.bs-tooltip-auto[x-placement^='right'] .arrow::before { border-right-color: var(--text); }

/* ---------- Monetary font (IBM Plex Sans) ------------------------------ */
/* All monetary nominal displays — saldo cells, "Rp" prefixes, dashboard
   stat values, summary boxes — render in IBM Plex Sans. Its open digit
   shapes and tabular numerals make Rp amounts scan cleanly in columns
   (esp. long balances like Rp 1.234.567.890). Use `.font-nominal` as a
   utility class on any new element that shows money; the existing
   money-specific classes auto-pick it up. */
.font-nominal,
.saldo-value,
.saldo-masked,
.saldo-mask-dots,
.stat-value,
.summary-value,
.input-group-text {
  font-family: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}
/* AutoNumeric-formatted inputs (Ryuna.input_nominal) don't get a marker
   class. Tag them with `.font-nominal` in the markup when needed, or
   rely on the input-group context if they sit next to a "Rp" prefix:
   apply the font to form-controls inside an input-group where the first
   child is .input-group-text — covers Saldo Awal/Akhir filter inputs
   plus any "Rp <input>" combination across forms. */
.input-group:has(> .input-group-prepend > .input-group-text:only-child, > .input-group-text:first-child) > .form-control {
  font-family: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* ---------- Design tokens ------------------------------------------------ */
:root {
  /* Brand (kept from existing palette) */
  --brand-primary: #1F5080;
  --brand-primary-hover: #184068;
  --brand-primary-active: #122f4f;
  --brand-secondary: #225A8B;
  --brand-tint: rgba(31, 80, 128, .08);
  --brand-tint-strong: rgba(31, 80, 128, .14);

  /* Surfaces */
  --surface: #ffffff;
  --surface-muted: #f8f9fe;
  --surface-sunken: #f1f4f9;

  /* Borders */
  --border: #e6e9ef;
  --border-strong: #d6dae3;

  /* Text */
  --text: #172b4d;
  --text-muted: #6b7a90;
  --text-faint: #8898aa;

  /* Status (Argon defaults, kept) */
  --success: #2dce89;
  --info:    #11cdef;
  --warning: #fb6340;
  --danger:  #f5365c;

  /* Hyperlink — intentionally a brighter, more saturated blue than
     --brand-primary navy. Used by anchors inside table body cells so a
     name like "MITRA SATKER 9" or "0145" reads as a proper clickable
     link instead of blending into the dark navy body text. Hover darkens
     for an interactive affordance. */
  --link:       #1d6fd6;
  --link-hover: #1558a8;

  /* Radius */
  --radius-sm: 6px;
  --radius:    8px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --radius-pill: 999px;

  /* Shadow — flat & subtle */
  --shadow-xs: 0 1px 2px rgba(20, 30, 55, .04);
  --shadow-sm: 0 2px 6px rgba(20, 30, 55, .06);
  --shadow-md: 0 6px 18px rgba(20, 30, 55, .08);

  /* Motion */
  --ease: cubic-bezier(.2, .8, .2, 1);
  --dur: 160ms;

  /* Form control height — single source of truth so a text .form-control, a
     native <select class="form-control"> and a Select2 widget all render at
     exactly the same height when they sit side by side in a .form-row.
     43px = .875rem font * 1.5 line-height (21px) + .625rem padding * 2 (20px)
     + 1px border * 2, i.e. the natural height a text input already has. */
  --control-h: 2.6875rem;
}

/* ---------- Base --------------------------------------------------------- */
body {
  color: var(--text);
  background-color: var(--surface-muted);
  font-feature-settings: "cv11", "ss01";
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  color: var(--text);
  letter-spacing: -0.01em;
}

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

hr { border-color: var(--border); }

/* ---------- Brand surface (.bg-diy) — top navbar + page header --------- */
/* Layered background to give the blue band depth + movement:
     1. SVG topographic contour lines (white @ 9% opacity, tiles horizontally)
     2. Radial glow at top-right (lighter blue → fades back to brand-primary)
     3. Radial shadow at bottom-left (darker tone → fades back to brand-primary)
     4. Brand-primary solid color as the base.

   `background-attachment: fixed` is critical here. The navbar (`.navbar-top`)
   and the page header (`.header`) are two separate DOM elements
   (admin/parent.blade.php) — each would otherwise start its own background
   from (0,0), creating a visible horizontal seam where the wave abruptly
   resets at the navbar/header boundary. Anchoring all layers to the viewport
   makes both elements display the *same slice* of a single shared pattern,
   so the wave + glow + shadow flow continuously across the boundary.

   Sizes use viewport-relative dimensions (100% width × 220px tall) so the
   gradients fit inside the blue band rather than stretching down the full
   page height. Opacities kept low so navbar text + breadcrumb stay legible. */
.bg-diy,
.navbar-top.bg-diy,
.header.bg-diy {
  background-color: var(--brand-primary) !important;
  background-image:
    url("/img/ui/bg-wave-topo.svg"),
    radial-gradient(ellipse 75% 140% at 5% -10%, rgba(125, 180, 230, 0.32), rgba(31, 80, 128, 0) 60%),
    radial-gradient(ellipse 65% 110% at 105% 100%, rgba(8, 25, 55, 0.32), rgba(31, 80, 128, 0) 60%) !important;
  background-attachment: fixed, fixed, fixed !important;
  background-repeat: repeat, no-repeat, no-repeat !important;
  background-size: 400px 220px, 100% 220px, 100% 220px !important;
  background-position: center top, 0 0, 0 0 !important;
}
.navbar-top.bg-diy { border-bottom: 0 !important; }

/* ---------- Va-type toggle (Reguler / Satker) -------------------------- */
/* Segmented control yang dipasang di page header (.header.bg-diy — band
   biru gelap) untuk internal admin: switch konteks data reguler/satker
   pada halaman Dashboard, Disbursement, Cash Pooling. Markup:
     <div class="btn-group btn-group-sm vatype-toggle" role="group">
       <button class="btn active" data-vatype="reguler">Reguler</button>
       <button class="btn"        data-vatype="satker">Satker</button>
     </div>
   JS per-halaman meng-handle klik: re-register $.ajaxSetup header
   X-VA-TYPE + reload data. Active = solid putih + teks brand; inactive =
   outline putih transparan supaya kontras di atas band biru. */
.vatype-toggle-label {
  color: rgba(255, 255, 255, .7);
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.vatype-toggle .btn {
  background: transparent;
  border-color: rgba(255, 255, 255, .55);
  color: #fff;
  font-weight: 600;
  box-shadow: none;
}
.vatype-toggle .btn:hover {
  background: rgba(255, 255, 255, .14);
  color: #fff;
}
.vatype-toggle .btn.active {
  background: #fff;
  border-color: #fff;
  color: var(--brand-primary);
}

/* ---------- Cards -------------------------------------------------------- */
.card {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
  transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.card:hover { box-shadow: var(--shadow-sm); }

.card > .card-header {
  background-color: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 1rem 1.25rem;
  border-top-left-radius: var(--radius-lg);
  border-top-right-radius: var(--radius-lg);
}
.card > .card-header h1, .card > .card-header h2,
.card > .card-header h3, .card > .card-header h4,
.card > .card-header h5, .card > .card-header h6 {
  margin-bottom: 0;
  font-weight: 600;
}
/* …except a detail section title (transfer/SKN detail header), which needs its
   gap above the first detail row restored — the generic rule above zeroes it. */
.card > .card-header h6.detail-section-title {
  margin-bottom: 1.5rem;
}

/* ---------- Card-header tabs → browser "melekuk" tabs ------------------- */
/* (Transfer ⇄ Daftar Rekening Tujuan, SKN/RTGS tabs.) The header is a tinted
   "shelf"; the active tab is a white Chrome/browser-style tab with rounded top
   corners and two outward-curving feet at the bottom that blend into the white
   panel below. The feet are pure-CSS radial-gradient pseudo-elements — no image
   asset — so the curve stays crisp at any tab width. Inactive tabs are plain
   muted text so only the active tab carries the shape. */
.card > .card-header:has(.card-header-tabs) {
  /* tinted shelf so the white tab + its curved feet clearly stand out */
  background-color: #dde3ec;
  border-bottom: 0; /* tinted shelf meets the white panel below with no rule */
  padding: .5rem .75rem 0;
}
.card-header-tabs {
  margin: 0;
  border-bottom: 0;
  gap: .75rem; /* room between tabs for the curved feet to splay out */
}
.card-header-tabs .nav-item { margin-bottom: 0; }
.card-header-tabs .nav-link {
  position: relative;
  border: 0;
  border-radius: 0;
  padding: .6rem 1.25rem;
  font-weight: 600;
  font-size: .8125rem;
  color: var(--text-faint);
  background: transparent;
  transition: color var(--dur) var(--ease);
}
.card-header-tabs .nav-link:hover { color: var(--brand-primary); }
/* active = white tab body, rounded top corners, flat bottom that merges into
   the white panel below. A firmer gray stroke (--tab-stroke) outlines the top +
   sides. */
.card-header-tabs .nav-link.active {
  --tab-stroke: #c9d0d9;
  color: var(--brand-primary);
  font-weight: 700;
  background: var(--surface);
  border: 2px solid var(--tab-stroke);
  border-bottom: 0; /* bottom merges into panel */
  border-top-left-radius: 12px;
  border-top-right-radius: 12px;
}

.card > .card-body { padding: 1.25rem; }
.card > .card-footer {
  background-color: var(--surface);
  border-top: 1px solid var(--border);
  border-bottom-left-radius: var(--radius-lg);
  border-bottom-right-radius: var(--radius-lg);
  padding: 1rem 1.25rem;
}

/* Stat cards / card-stats keep their look but with new tokens */
.card-stats .card-body { padding: 1.25rem; }

/* ---------- Forms -------------------------------------------------------- */
label, .form-control-label {
  font-weight: 600;
  color: var(--text);
  margin-bottom: .375rem;
  font-size: .8125rem;
}

label .text-optional,
.form-control-label .text-optional {
  color: var(--text-faint);
  font-weight: 400;
  font-style: italic;
  margin-left: .25rem;
  font-size: .75rem;
}

.form-control,
.form-select,
.custom-select {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  background-color: var(--surface);
  padding: .625rem .875rem;
  height: auto;
  min-height: var(--control-h);
  font-size: .875rem;
  box-shadow: none;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.form-control::-moz-placeholder { color: var(--text-faint); }
.form-control::placeholder { color: var(--text-faint); }

/* A native <select class="form-control"> has a shorter intrinsic content box
   than a text input (the browser lays out the option text without the 1.5
   line-height an <input> gets), so `height: auto` alone leaves it ~1px short
   of the text field next to it. Pin it to the shared control height and let
   the browser centre the option text in the remaining box. */
select.form-control:not([multiple]):not([size]),
select.form-select:not([multiple]):not([size]),
select.custom-select:not([multiple]):not([size]) {
  height: var(--control-h);
}

.form-control:focus,
.form-select:focus,
.custom-select:focus {
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px var(--brand-tint);
  background-color: var(--surface);
  color: var(--text);
}

.form-control[readonly],
.form-control:disabled {
  background-color: var(--surface-sunken);
  color: var(--text-muted);
}

textarea.form-control { min-height: 5rem; }

/* Input group (e.g. "Rp" prefix) */
.input-group { box-shadow: none; }
.input-group > .form-control,
.input-group > .custom-select {
  border-radius: 0;
}
.input-group > .form-control:not(:last-child),
.input-group > .custom-select:not(:last-child) {
  border-right: 0;
}
.input-group > :first-child { border-top-left-radius: var(--radius); border-bottom-left-radius: var(--radius); }
.input-group > :last-child  { border-top-right-radius: var(--radius); border-bottom-right-radius: var(--radius); }

/* The rules above set the radius on the .input-group-prepend / .input-group-append
   WRAPPER, which has no visible border or background — the actual painted
   element is the .input-group-text inside. Apply the same radius directly
   to that inner element so the OUTER edge matches --radius cleanly, AND
   explicitly zero out the radius on the side facing the form-control so
   the junction is a single sharp vertical seam (without this, the inner
   element keeps Argon's default ~4px corner, which shows as a faint round
   notch at the icon ↔ input boundary when the page is zoomed). */
.input-group > .input-group-prepend:first-child > .input-group-text {
  border-top-left-radius: var(--radius);
  border-bottom-left-radius: var(--radius);
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.input-group > .input-group-append:last-child > .input-group-text {
  border-top-right-radius: var(--radius);
  border-bottom-right-radius: var(--radius);
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

/* When a .form-control is followed only by visually-empty siblings — hidden
   inputs (date-range filters stash start/end in <input type="hidden">) or a
   collapsed .invalid-feedback (Bootstrap validation message, display:none until
   triggered) — the rule above strips its right border + radius, leaving the
   field chopped open on the right. Detect "no VISIBLE sibling follows" via
   :has() and restore the right border + rounded corners. */
.input-group > .form-control:not(:has(~ *:not([type="hidden"]):not(.invalid-feedback))),
.input-group > .custom-select:not(:has(~ *:not([type="hidden"]):not(.invalid-feedback))) {
  border-right: 1px solid var(--border) !important;
  border-top-right-radius: var(--radius) !important;
  border-bottom-right-radius: var(--radius) !important;
}
.input-group:focus-within > .form-control:not(:has(~ *:not([type="hidden"]):not(.invalid-feedback))) {
  border-right-color: var(--brand-primary) !important;
}

/* `!important` is required here: argon.css ends with
   `.form-control-lg, .input-group-lg .form-control, .input-group-text
   { font-size: 1rem !important }`, which otherwise forces the prefix/suffix
   box to 16px. Its 24px line box then made the whole .input-group 46px tall —
   3px more than a standalone control — which is what made a Select2 or a
   native <select> inside a filter bar look short next to its icon box. */
.input-group-text {
  background-color: var(--surface-sunken);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: .8125rem !important;
  padding: .625rem .875rem;
}

.input-group:focus-within > .form-control,
.input-group:focus-within > .input-group-text,
.input-group:focus-within > .custom-select {
  border-color: var(--brand-primary);
}
.input-group:focus-within { box-shadow: 0 0 0 3px var(--brand-tint); border-radius: var(--radius); }

/* Help text */
.form-text, small.form-text {
  color: var(--text-faint);
  font-size: .75rem;
  margin-top: .375rem;
}

/* When a form-group is immediately followed by a related custom-control
   checkbox/radio (e.g. "Cabang" select → "Tampilkan data konsolidasi"
   toggle in dashboard cards), the default 1rem form-group margin-bottom
   creates a gap that visually detaches the toggle from the input it
   controls. Shrink the gap so the toggle reads as part of the same
   field cluster. Mirrors the existing `form-group.mb-2 + checkbox`
   pattern used in the topmost reference pair on dashboard internal. */
.form-group:has(+ .custom-control.custom-checkbox),
.form-group:has(+ .custom-control.custom-radio) {
  margin-bottom: .5rem;
}

/* Custom checkbox / radio — keep Argon markup, tighten visuals.
   Vertically center the box-indicator with the label text (Bootstrap's
   default `top: .25rem` aligns to the first line, which looks off-axis
   especially with our larger label font-weight). */
.custom-control {
  display: flex;
  align-items: center;
  min-height: 1.25rem;
}
/* Tighten spacing between consecutive checkbox/radio rows. Forms in this
   project habitually stack <div class="custom-control custom-checkbox mb-3">
   blocks — mb-3 = 1rem feels loose for grouped toggles like "Snap API?" +
   "Biaya setor mitra?". Reduce to 0.5rem only when the next sibling is
   another custom-control row; gaps to regular form fields stay 1rem so
   form-section rhythm isn't disturbed. !important because Bootstrap's
   .mb-3 utility ships with !important. */
.custom-control.custom-checkbox:has(+ .custom-control),
.custom-control.custom-radio:has(+ .custom-control) {
  margin-bottom: 0.5rem !important;
}
.custom-control-label {
  margin-bottom: 0;
  line-height: 1.25rem;
  cursor: pointer;
}
/* Argon forces `.custom-checkbox .custom-control-input ~ .custom-control-label
   { height: 1rem }` — that anchors the box `::before` to a 16px tall label
   while the text line-height pushes the text below it, leaving box and
   text visually misaligned. Match Argon's specificity to undo the height. */
.custom-checkbox .custom-control-input ~ .custom-control-label,
.custom-radio .custom-control-input ~ .custom-control-label {
  height: auto;
  line-height: 1.25rem;
}
.custom-control-label::before,
.custom-control-label::after {
  top: 50%;
  transform: translateY(-50%);
}
.custom-control-label::before {
  border-color: var(--border-strong);
  background-color: var(--surface);
  border-radius: 4px;
}
.custom-radio .custom-control-label::before { border-radius: 50%; }
.custom-control-input:focus ~ .custom-control-label::before {
  box-shadow: 0 0 0 3px var(--brand-tint);
}
.custom-control-input:checked ~ .custom-control-label::before {
  background-color: var(--brand-primary);
  border-color: var(--brand-primary);
}

/* Required asterisk */
label .required,
.form-control-label .required,
label.required::after {
  color: var(--danger);
}

/* Subtle background for table group header rows */
.bg-lighter {
  background-color: var(--surface-sunken) !important;
}

/* Form section divider — bisa pakai <div class="section-divider"> sebagai wrapper
   atau langsung <h5 class="section-heading"> tanpa wrapper, keduanya tampil sama */
.section-divider {
  margin: 1.5rem 0 0;
}
.section-heading {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
  margin: 1.5rem 0 .5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
  letter-spacing: -0.005em;
}
/* The first section heading in a card-body carries `.mt-0 .pt-0` to collapse
   its top spacing — at that point the divider line above it sits flush with
   the card-header's bottom border, which looks like a doubled-up rule and
   visually clamps the heading. Drop the border-top when those Bootstrap
   utilities are present so the first heading reads as a clean leading title
   while subsequent headings still get the divider as a section separator. */
.section-heading.pt-0 {
  border-top: 0;
}

/* ---------- Ringkasan stat card ---------------------------------------- */
/* Used by both dashboard variants (internal + external). The icon is
   absolutely-positioned to the card-body's vertical center — the previous
   flex-centered version aligned to the geometric middle of the (label+value)
   row, but the label is short and the value tall, so the icon visually sat
   closer to the label than to the value. Absolute positioning anchors the
   icon to the true card-body center regardless of content height.

   Markup contract per stat card:
     <div class="card card-ringkasan h-100">
       <div class="card-body">
         <p class="stat-label">Label</p>
         <h2 class="stat-value">Value</h2>
         <span class="stat-icon bg-[primary|success|danger|warning] text-white">
           <i data-lucide="icon-name"></i>
         </span>
       </div>
     </div>
*/
.card-ringkasan > .card-body {
  position: relative;
  padding: 1.25rem 1.5rem;
  /* Reserve right space for the absolute-positioned icon so long values
     (e.g. "Rp 999.099.699") don't slide underneath it. Icon = 2.5rem,
     right offset = 1.25rem, breathing gap = .75rem → 4.5rem total. */
  padding-right: 4.5rem;
  min-height: 5.5rem;
  /* Center the content (label + value) vertically. Without this the label
     anchors to the top of card-body via normal flow, while the icon sits at
     body's true vertical center — visually the icon then appears below the
     content. With justify-content:center, both the content stack and the
     icon land on the same horizontal axis. */
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.stat-label {
  font-size: .6875rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 600;
  /* Browser-default <p> margins explicitly reset. */
  margin: 0 0 .375rem !important;
}
/* Browser default + Argon both add margin on h2 — reset all four sides with
   !important to lock the cascade. */
.stat-value {
  font-size: 1.5rem !important;
  font-weight: 700 !important;
  color: var(--text) !important;
  line-height: 1.2 !important;
  margin: 0 !important;
}
/* Circular badge anchored to vertical center of card-body. Always a perfect
   circle (width === height === 2.5rem, border-radius 50%) regardless of any
   cascade — !important locks it in. */
.card-ringkasan .stat-icon {
  position: absolute;
  top: 50%;
  right: 1.25rem;
  transform: translateY(-50%);
  width: 2.5rem !important;
  height: 2.5rem !important;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50% !important;
  flex-shrink: 0;
  font-size: 1rem;
}
/* Lucide SVGs render at 1em via lucide-shim.css — pin to .9375rem (15px)
   so the glyph sits clearly inside the 2.5rem circle with even spacing. */
.card-ringkasan .stat-icon > svg {
  width: .9375rem !important;
  height: .9375rem !important;
}
/* Narrow viewports — trim icon + reserved right space. */
@media (max-width: 575.98px) {
  .card-ringkasan > .card-body {
    padding-right: 4rem;
    min-height: 5rem;
  }
  .card-ringkasan .stat-icon {
    width: 2.25rem !important;
    height: 2.25rem !important;
  }
  .card-ringkasan .stat-icon > svg {
    width: .875rem !important;
    height: .875rem !important;
  }
  .stat-value { font-size: 1.25rem !important; }
}

/* ---------- Logo / image upload picker --------------------------------- */
/* Used by manage/mitra forms (form.blade.php + form_edit.blade.php). The
   upload zone is a 150×150 dashed-border square with a stand-alone cloud
   glyph + "Klik untuk mengunggah" text centered inside. Promoted from
   inline form \3c style> to a single shared rule set so both forms get
   consistent visuals.

   Sizing strategy: container gets font-size: 6rem so lucide-shim.css's
   `svg.lucide { width: 1em }` rule resolves to 96px naturally (1em ≈
   parent font-size since SVG inherits it). PLUS we set width/height
   directly on the SVG with a more-specific chained selector + !important
   as belt-and-braces guard against any cascade conflict. */
.logo_upload_icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--brand-primary);
  margin: 0 auto .5rem;
  font-size: 6rem;
  line-height: 1;
}
.logo_image_picker .logo_upload_icon > svg,
.logo_image_picker .logo_upload_icon > i {
  width: 6rem !important;
  height: 6rem !important;
  min-width: 6rem !important;
  min-height: 6rem !important;
  flex-shrink: 0;
  stroke-width: 1.5;
}
/* Image-hover-handler chip at the picker's bottom-right corner — the
   Argon .icon-sm box is 2rem (32px) but the Lucide glyph inside renders
   at 1em ≈ 14-16px which looks lost in the box. Pin to 1.25rem (20px,
   ~62% of box) — Argon's intended .icon-sm svg size. font-size +
   !important on the container is belt-and-braces for the case where
   lucide-shim's `svg.lucide { width: 1em }` resolves against an
   inherited small font. */
.logo_image_picker .image-hover-handler {
  font-size: 1.25rem !important;
}
.logo_image_picker .image-hover-handler svg,
.logo_image_picker .image-hover-handler > i > svg {
  width: 1.25rem !important;
  height: 1.25rem !important;
  min-width: 1.25rem !important;
  min-height: 1.25rem !important;
  stroke-width: 2;
}


/* ---------- Multi-step wizard indicator -------------------------------- */
/* Used by all multi-step forms (manage/mitra, manage/merchant, manage/bpr,
   etc.). Reference markup lives in resources/views/pages/manage/mitra/form.blade.php:
     <div class="step-box">
       <div class="step-header">
         <div class="step-list">
           <div class="step-button" data-tab="1">
             <div class="step-header-number active">1</div>
             <div class="step-header-title">Mitra</div>
           </div>
           ...
         </div>
       </div>
       <div class="step-body" data-tab="1"> ... </div>
     </div>
   The custom Stepper class in public/js/global.js only tracks position;
   the visual state (which number chip is .active) is toggled directly by
   each form's stepper navigation JS. */
.step-header {
  padding-bottom: 1.25rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--border);
}
.step-list {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: flex-start;
  gap: .25rem;
}
.step-button {
  flex: 1;
  text-align: center;
  padding: 0;
  cursor: pointer;
  position: relative;
}
/* Connector line between adjacent step chips — sits behind the chip via
   z-index (chip has z-index:1, line has z-index:0). Anchored from the right
   edge of the current chip's bounding box (calc(50% + 1.125rem) = center +
   half-chip-width) to the left edge of the next chip. */
.step-button:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 1rem;
  left: calc(50% + 1.125rem);
  right: calc(-50% + 1.125rem);
  height: 2px;
  background-color: var(--border);
  z-index: 0;
  transform: translateY(-1px);
}
.step-header-number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  margin: 0 auto .5rem;
  line-height: 1;
  font-weight: 600;
  font-size: .8125rem;
  color: var(--text-faint);
  background-color: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: 50%;
  position: relative;
  z-index: 1;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.step-header-number.active {
  color: #fff;
  background-color: var(--brand-primary);
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 4px var(--brand-tint);
}
.step-header-title {
  text-align: center;
  font-size: .75rem;
  color: var(--text-muted);
  font-weight: 500;
}
.step-button:has(.step-header-number.active) .step-header-title {
  color: var(--brand-primary);
  font-weight: 600;
}

/* Flatpickr wrapper must fill its parent column, otherwise it shrinks to
   the trigger-icon width when nested inside a .form-group. */
.flatpickr-wrapper { width: 100% !important; }

/* ---------- Buttons ------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .375rem;
  border-radius: var(--radius);
  padding: .55rem 1.1rem;
  font-weight: 600;
  font-size: .8125rem;
  letter-spacing: .01em;
  border: 1px solid transparent;
  box-shadow: none;
  transition: background-color var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
/* Keep icon-only/text-only buttons clean: dropdown caret should sit inline
   without inheriting flex weirdness, but as a flex item it auto-centers. */
.btn .ni, .btn > i, .btn > svg {
  line-height: 1;
  display: inline-flex;
  align-items: center;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn:focus, .btn.focus { box-shadow: 0 0 0 3px var(--brand-tint); }

.btn-primary,
.btn-diy {
  background-color: var(--brand-primary);
  border-color: var(--brand-primary);
  color: #fff;
}
.btn-primary:hover, .btn-diy:hover {
  background-color: var(--brand-primary-hover);
  border-color: var(--brand-primary-hover);
  color: #fff;
}
/* :focus intentionally NOT included above — keyboard/auto focus should be
   indicated by the brand-tint ring (.btn:focus { box-shadow: ... }), not
   by darkening the background. Otherwise an autofocused button (e.g.
   "Lanjut" in a freshly-opened modal) reads as a different shade of blue
   than an idle .btn-primary on the same page. */
.btn-primary:active, .btn-diy:active,
.btn-primary:not(:disabled):not(.disabled):active {
  background-color: var(--brand-primary-active) !important;
  border-color: var(--brand-primary-active) !important;
}

.btn-outline-primary {
  color: var(--brand-primary);
  border-color: var(--brand-primary);
  background-color: transparent;
}
.btn-outline-primary:hover {
  background-color: var(--brand-primary);
  border-color: var(--brand-primary);
  color: #fff;
}

.btn-secondary {
  background-color: var(--surface);
  border-color: var(--border-strong);
  color: var(--text);
}
.btn-secondary:hover {
  background-color: var(--surface-sunken);
  border-color: var(--border-strong);
  color: var(--text);
}

.btn-link {
  color: var(--brand-primary);
  font-weight: 600;
}
.btn-link:hover { color: var(--brand-primary-hover); }

.btn:disabled, .btn.disabled,
.btn-primary:disabled, .btn-primary.disabled {
  background-color: var(--surface-sunken) !important;
  border-color: var(--border) !important;
  color: var(--text-faint) !important;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* gap tightened from the base .btn (.375rem): the icon↔label spacing reads
   loose against the smaller .75rem text in compact table-action buttons. */
.btn-sm { padding: .375rem .75rem; font-size: .75rem; border-radius: var(--radius-sm); gap: .3125rem; }
.btn-lg { padding: .75rem 1.5rem; font-size: .9375rem; border-radius: var(--radius); }

/* Icon button helper */
.btn .ni, .btn i, .btn > svg { vertical-align: middle; }

/* Action-button spacing in DataTable cells: standalone buttons placed
   side-by-side (e.g. Detail + Cetak) often ship without an explicit margin
   utility and end up touching. Add a consistent gutter between adjacent
   top-level buttons in a cell, while leaving real Bootstrap .btn-group
   stacks flush (their .btn children are nested, not direct cell children). */
td > .btn + .btn,
td > .btn + .btn-group,
td > .btn-group + .btn,
td > .btn-group + .btn-group { margin-left: .375rem; }

/* FAB (Panduan / help button) — custom.css sets size (60×60) and font-size
   for the old Nucleo glyph; we now render a Lucide SVG inside, so we override:
   - border-radius forced to 50% (the .btn rule above sets var(--radius) at the
     same specificity, so without !important the rounded-square wins);
   - padding zeroed because the button has fixed width/height (.btn's default
     padding pushes content off-center);
   - SVG sized to 1.75rem so the icon reads clearly in the 60px circle without
     filling it edge-to-edge (Lucide default is 24px which looked too small). */
.btn-fab {
  border-radius: 50% !important;
  padding: 0 !important;
  box-shadow: var(--shadow-md) !important;
}
/* !important to defeat Lucide's inline width/height attributes set when
   createIcons() replaces <i data-lucide> with the rendered <svg>. */
.btn-fab > svg,
.btn-fab > i > svg,
.btn-fab svg {
  width: 2.25rem !important;
  height: 2.25rem !important;
  stroke-width: 1.75;
}

/* ---------- Ryuna.blockUI / blockElement loader (Lottie) -------------- */
/* Replaces the old loading2.gif with a 3-dot wave Lottie animation rendered
   into `.ryuna-block-lottie` by Ryuna._mountLottie (see public/js/global.js).
   The block message DOM is:
     <div class="ryuna-block-content">
       <div class="ryuna-block-lottie"></div>  <- Lottie SVG mounts here
       <div class="ryuna-block-text">Please Wait</div>
     </div>
   Sized to match the JSON's 200x100 viewBox aspect ratio; .text uses our
   muted token so it doesn't compete with the animation. */
.ryuna-block-content {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: .5rem;
}
.ryuna-block-lottie {
  width: 88px;
  height: 44px;
  /* Hint for sub-pixel-smooth SVG playback under transform parents */
  transform: translateZ(0);
}
.ryuna-block-lottie svg {
  display: block;
  width: 100%;
  height: 100%;
}
.ryuna-block-text {
  font-size: .8125rem;
  font-weight: 500;
  color: var(--text-muted);
  letter-spacing: 0;
  line-height: 1.2;
}

/* DataTables processing indicator — same look + Lottie animation as Ryuna's
   blockUI box. DataTables BS4 default styling positions this absolutely
   centered with margin offsets and 200px width; we replace that with a
   translate-based centering + auto width so it matches the blockUI card
   exactly. The `language.processing` config (datatables-language.js) puts
   the .ryuna-block-content DOM inside, so the inner layout reuses the
   blockUI styles above. */
.dataTables_wrapper .dataTables_processing,
.dataTables_wrapper .dataTables_processing.card {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: auto;
  min-width: 160px;
  margin: 0;
  padding: 1.25rem 1.75rem;
  background-color: #fff;
  border: 0;
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(20, 30, 55, .12);
  text-align: center;
  z-index: 10020;
}

/* ---------- Modals ------------------------------------------------------- */
.modal-content {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.modal-header {
  border-bottom: 1px solid var(--border);
  padding: 1.125rem 1.5rem;
  align-items: center;
}
.modal-title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.01em;
}
.modal-header .close {
  color: var(--text-muted);
  font-weight: 400;
  font-size: 1.5rem;
  opacity: 1;
  text-shadow: none;
  padding: 0 .5rem;
  margin: -1rem -1rem -1rem auto;
  transition: color var(--dur) var(--ease);
}
.modal-header .close:hover { color: var(--brand-primary); }
.modal-body { padding: 1.5rem; }
.modal-footer {
  border-top: 1px solid var(--border);
  padding: 1rem 1.5rem;
  gap: .25rem;
}
/* Card-footer button groups across forms (transfer/skn_rtgs/show, role, etc.).
   Markup is typically `<div class="card-footer"><div class="row col-md-*">
   <button>...</button> <button>...</button></div></div>` — force a consistent
   tight gap between adjacent btn/btn-group children so action button rows
   look the same whether they live in a modal or a card. */
.card-footer .row > .btn + .btn,
.card-footer .row > .btn-group + .btn,
.card-footer .row > .btn + .btn-group,
.card-footer > .btn + .btn,
.card-footer > .btn-group + .btn,
.card-footer > .btn + .btn-group {
  margin-left: .25rem;
}

/* When a modal is open, the .modal-backdrop sits at z-index: 1040 (Bootstrap
   default), but Argon's .sidenav defaults to z-index: 1050 — so the backdrop
   dim affects the main content but stops at the sidebar, leaving it visually
   "lit up" while the rest is dimmed. Push the sidenav below the backdrop
   only while a modal is open (Bootstrap auto-adds `.modal-open` to <body>)
   so the dim wraps the whole page consistently. Reverts on modal close. */
body.modal-open .sidenav,
body.modal-open .navbar-vertical {
  z-index: 1030;
}

/* ---------- Flatpickr date picker inside modals ------------------------ */
/* Modal date fields (disbursement / cash pooling "Tanggal Eksekusi" /
   "Tanggal Tarik", VA create+edit effective/expired/birthdate) init
   flatpickr with `static: true`, which renders the calendar as an
   ABSOLUTELY-positioned popup directly below the input. Inside #myModal the
   .modal-content is `overflow: hidden` (needed so the rounded corners clip
   the header/body) — an absolute popup that extends past the input row is
   clipped at the modal edge, so the lower calendar rows + time picker become
   unreachable (reported on disbursement create). An absolute element has no
   layout footprint, so no amount of modal scrolling can reveal it.
   Fix: while the static calendar is OPEN inside a modal, drop it back into
   normal flow (like flatpickr's own `.inline` mode) so it expands the form
   height instead of overflowing the clip box. The modal then scrolls down to
   it (Bootstrap's default `.modal-open .modal { overflow-y: auto }`), and
   nothing is cut off. On close the calendar returns to display:none, so the
   extra height only exists while the user is actively picking a date.
   Selector carries 4 classes → beats flatpickr's `.static`/`.static.open`. */
.modal .flatpickr-calendar.static.open {
  position: relative;
  top: 0;
  margin-top: .375rem;
  margin-bottom: .25rem;
  box-shadow: var(--shadow-md);
}

/* ---------- Detail panels (modal show-views) ---------------------------- */
/* Replaces the legacy 2-col borderless table pattern used by every
   show.blade.php (label cell + value cell, ~20 rows of plain text). That
   pattern reads as a wall-of-rows with no visible grouping, which is fine
   for a settings table but poor UX for a "detail of an entity" view that
   users scan to find a specific attribute (status, balance, identity, etc).
   The new pattern groups related fields under a small section heading and
   lays the label/value pairs out in a responsive 2-col grid with stacked
   label-above-value typography — same density, much faster to scan.
   Reference implementation: manage/virtual_account/show.blade.php.

   Markup contract:
     <div class="detail-list">
       <section class="detail-section">
         <h6 class="detail-section-title">Identitas VA</h6>
         <div class="detail-grid">
           <div class="detail-row">
             <span class="detail-label">Nama VA</span>
             <span class="detail-value">…</span>
           </div>
           <div class="detail-row detail-row--full"> … </div>  // span both cols
         </div>
       </section>
       <section class="detail-section"> … </section>
     </div>
   Drop-in friendly: status badges, .font-nominal Rp values, multi-line
   text — all work as expected because the .detail-value is a generic span. */
.detail-list {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}
.detail-section + .detail-section {
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
}
.detail-section-title {
  font-size: .6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-muted);
  margin: 0 0 1.25rem;
  display: flex;
  align-items: center;
  gap: .5rem;
}
.detail-section-title > svg.lucide,
.detail-section-title > i {
  width: .9375rem;
  height: .9375rem;
  color: var(--brand-primary);
  flex-shrink: 0;
}
.detail-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  -moz-column-gap: 1.5rem;
       column-gap: 1.5rem;
  row-gap: 1rem;
}
/* Label sits in a fixed-share column on the left, value fills the rest on
   the right — both on one line, so each row reads "Label    Value". */
.detail-row {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  -moz-column-gap: 1rem;
       column-gap: 1rem;
  min-width: 0; /* enables word-break inside flex/grid item */
}
.detail-row--full {
  grid-column: 1 / -1;
}
/* Comparison pairs on approval detail popups ("Sekarang" vs "Perubahan"):
   pin each side to a fixed column so the left half is always the current
   value and the right half always the requested change — symmetry holds even
   when an odd row precedes the pair or one side wraps to more lines. */
.detail-row--now { grid-column: 1; }
.detail-row--change { grid-column: 2; }
.detail-label {
  flex: 0 0 40%;
  font-size: .85rem;
  color: var(--text-muted);
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.4;
}
/* Full-width rows span both grid columns; halve the label share so its
   absolute width still lines up with the labels in the normal two-up rows.
   A plain 20% leaves the value ~0.3rem off: a normal row's label is 40% of a
   *column* ((W − column-gap)/2), while a full row's label is a % of the full
   width W. The difference is exactly 0.2 × the 1.5rem grid column-gap = 0.3rem,
   so subtract it back to make full-row values line up with the left column. */
.detail-row--full .detail-label {
  flex-basis: calc(20% - 0.3rem);
}
.detail-value {
  flex: 1 1 0;
  min-width: 0;
  font-size: .95rem;
  color: var(--text);
  font-weight: 600;
  word-break: break-word;
  line-height: 1.4;
}
.detail-value--muted { color: var(--text-muted); font-weight: 500; }
.detail-value--empty { color: var(--text-faint); font-style: italic; font-weight: 500; }
/* Stack a multi-part value (e.g. number + a caption/badge below it) so every
   line shares the same left start instead of the badge wrapping with an indent. */
.detail-value--stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .35rem;
}
/* Compact list rendered inside a .detail-value (e.g. Approver / Checker pairs)
   — strip the browser's default bullet indent so it aligns with the value. */
.detail-value-list {
  margin: 0;
  padding-left: 1.1rem;
}
/* "PERHATIAN" notice (disbursement / cashpooling): stack the two halves
   vertically at every width — reads better than the side-by-side split — but
   keep the vertical rhythm tight so the block stays compact. The :first-child
   guard adds the gap only between the two stacked halves, not above the first. */
.notice-split > [class*="col-"] {
  flex: 0 0 100%;
  max-width: 100%;
}
.notice-split > [class*="col-"]:not(:first-child) {
  margin-top: .85rem;
}
/* Tighten the surrounding rhythm of the notice (heading, divider rule, the
   closing emphasis line) so stacking doesn't make the alert tall. Scoped via
   :has() to alerts that actually contain the notice, leaving other alerts as-is. */
.alert:has(.notice-split) .alert-heading {
  margin-bottom: .65rem;
}
.alert:has(.notice-split) hr {
  margin-top: .9rem;
  margin-bottom: .9rem;
}
.alert:has(.notice-split) ul {
  margin-bottom: 0;
}
.alert:has(.notice-split) ul li + li {
  margin-top: .3rem;
}
/* Narrow viewports collapse to a single column so labels + values keep
   their reading order without horizontal cramping. Every row then spans the
   full width, so labels share one ratio regardless of --full. */
@media (max-width: 575.98px) {
  .detail-grid { grid-template-columns: minmax(0, 1fr); }
  .detail-label,
  .detail-row--full .detail-label { flex-basis: 38%; }
  /* Single column: un-pin the comparison pairs so they stack in source
     order (Sekarang above Perubahan) instead of creating an implicit col 2. */
  .detail-row--now,
  .detail-row--change { grid-column: 1; }
}

/* ---------- Bill detail (Tagihan) rows ---------------------------------- */
/* Horizontally-scrollable field row. The arrows are sticky buttons pinned to
   each edge of the scroll viewport, the native scrollbar is hidden, and the
   arrows scroll the track via the existing .scroll-left / .scroll-right JS. */
.bill-row {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
}
.bill-track {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: flex-start;
  gap: .35rem;
  overflow-x: auto;
  scrollbar-width: none;       /* Firefox */
  -ms-overflow-style: none;    /* legacy Edge */
}
.bill-track::-webkit-scrollbar { display: none; }   /* WebKit */
.bill-fields {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  flex: 1 0 auto;            /* grow to fill the track so there is no empty gap */
}
.bill-field {
  /* grow to fill the full width when there is room (no empty gap), but never
     shrink below a generous width — so the row overflows the card on normal
     screens and the left/right scroll stays meaningful */
  flex: 1 0 28rem;
}
.bill-arrow {
  position: sticky;
  flex: 0 0 auto;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  font-size: .875rem;                     /* so 1.5em below matches the input */
  height: calc(1.5em + 1.25rem + 2px);    /* = Argon .form-control height */
  padding: 0;
  border: 1px solid var(--border);
  border-radius: .25rem;
  background: #fff;
  color: var(--brand-primary);
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}
.bill-arrow.scroll-left  { left: 0; }
.bill-arrow.scroll-right { right: 0; }
.bill-arrow:hover { background: var(--brand-primary); color: #fff; }
.bill-arrow > svg.lucide,
.bill-arrow > i { width: 1.15rem; height: 1.15rem; }
.bill-info-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: calc(1.5em + 1.25rem + 2px);    /* = Argon .form-control / input height */
}
.bill-info-btn > svg.lucide,
.bill-info-btn > i { width: 1.1rem; height: 1.1rem; }

/* ---------- "Konfigurasi Transfer Mitra" modal ------------------------- */
/* The 7-column table got cramped + horizontally scrolled in the modal —
   one card per jenis transaksi reads better: header (name + badges),
   two-up body (standar vs editable nominal), small audit foot. */
.trf-config-list {
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.trf-config-row {
  border: 1px solid var(--border);
  border-radius: .5rem;
  background: #fff;
  padding: 1rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: .85rem;
}
.trf-config-row__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
}
.trf-config-row__name {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
}
.trf-config-row__badges {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  flex-wrap: wrap;
}
.trf-config-row__body > .trf-config-row__cell + .trf-config-row__cell {
  /* Bootstrap 4's .row negative margin is killed by .no-gutters; pad the
     second column instead so the two fields don't touch each other. */
  padding-left: 1rem;
}
@media (max-width: 767.98px) {
  .trf-config-row__body > .trf-config-row__cell + .trf-config-row__cell {
    padding-left: 0;
  }
}
.trf-config-row__field-label {
  display: block;
  font-size: .8rem;
  color: var(--text-muted);
  margin-bottom: .35rem;
}
.trf-config-row__field-static {
  padding: .625rem .75rem;
  font-size: .875rem;
  font-weight: 600;
  line-height: 1.5;
  color: var(--text);
  background: var(--surface-muted, #f7fafc);
  border: 1px solid var(--border);
  border-radius: .375rem;
}
.trf-config-row__foot {
  font-size: .75rem;
  color: var(--text-muted);
  display: flex;
  flex-wrap: wrap;
  gap: .35rem .5rem;
  padding-top: .55rem;
  border-top: 1px dashed var(--border);
}
.trf-config-row__foot strong { font-weight: 600; color: var(--text); }
.trf-config-row__foot-sep { opacity: .5; }
.trf-config-empty {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--text-muted);
  background: var(--surface-muted, #f7fafc);
  border: 1px dashed var(--border);
  border-radius: .5rem;
}

/* ---------- Hirarki VA tree (jquery.jsontree) → node cards -------------- */
/* Each VA node is rendered as a card: a contact-round avatar on the left, the
   VA name + number stacked in the middle, and the balance on the right. The
   whole label opens a detail modal on click (handler reads data-va). Layered on
   top of the vendored jsontree markup — the hierarchy is kept via indentation;
   the plugin's fixed 20px node heights are overridden so the cards don't clip. */

/* unclip the plugin's fixed-height rows + drop their inner padding (the card
   provides its own); nesting is shown by the children indent below */
#hierarki_va.tree .tree-item,
#hierarki_va.tree .tree-branch-header {
  height: auto;
  line-height: normal;
  padding: 0;
}
#hierarki_va.tree .tree-item { max-width: 100%; }
#hierarki_va.tree .tree-item,
#hierarki_va.tree .tree-branch {
  margin: .4rem 0; /* breathing room between cards */
}
/* keep the tree guide-lines — vertical rail + horizontal ticks — softened to a
   thin solid grey and re-centred (top) on the taller cards */
#hierarki_va.tree:before,
#hierarki_va.tree .tree-branch .tree-branch-children:before {
  border-left: 1px solid var(--border);
}
#hierarki_va.tree .tree-branch:before,
#hierarki_va.tree .tree-item:before {
  border-top: 1px solid var(--border);
  top: 28px;  /* card vertical centre (~55px tall card) */
  width: 11px; /* stop the tick at the card's left edge — don't pierce into it */
}

/* node = card */
#hierarki_va.tree .tree-item-name,
#hierarki_va.tree .tree-branch-name {
  display: flex;
  align-items: center;
  gap: .75rem;
  width: 100%;
  max-width: 30rem; /* card stays a comfortable width, not full-bleed */
  padding: .55rem .8rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04);
  transition: border-color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease),
              background-color var(--dur) var(--ease);
}
#hierarki_va.tree .tree-item-name:hover,
#hierarki_va.tree .tree-branch-name:hover {
  cursor: pointer;
  border-color: var(--brand-primary);
  box-shadow: 0 4px 12px rgba(31, 80, 128, .12);
}
/* parent (branch) card slightly tinted so levels read apart */
#hierarki_va.tree .tree-branch > .tree-branch-header > .tree-branch-name {
  background: var(--surface-muted);
}

/* contact-round icon → avatar tile */
#hierarki_va.tree .va-node-icon {
  width: 36px;
  height: 36px;
  padding: 8px;
  margin: 0;
  flex-shrink: 0;
  color: var(--brand-primary);
  background: var(--brand-tint);
  border-radius: 8px;
}
/* leaf bullet hidden (the card is the node indicator); branch toggle kept */
#hierarki_va.tree .tree-item > .tree-item-name > .ace-icon:first-child {
  display: none;
}
#hierarki_va.tree .tree-branch-name > .ace-icon:first-child {
  top: 0;
  align-self: center;
  flex-shrink: 0;
}

/* label = flex row inside the card: text block (left) + balance (right) */
#hierarki_va.tree .tree-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex: 1 1 auto;
  min-width: 0;
  cursor: pointer;
}
#hierarki_va.tree .va-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
#hierarki_va.tree .va-name {
  font-weight: 600;
  font-size: .8125rem;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color var(--dur) var(--ease);
}
#hierarki_va.tree .va-digit {
  font-size: .72rem;
  font-weight: 500;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
#hierarki_va.tree .va-balance {
  flex-shrink: 0;
  font-size: .8125rem;
  font-weight: 700;
  color: var(--brand-primary);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
#hierarki_va.tree .tree-item-name:hover .va-name,
#hierarki_va.tree .tree-branch-name:hover .va-name {
  color: var(--link-hover);
}

/* ---------- Tables ------------------------------------------------------- */
.table {
  color: var(--text);
}
.table thead th,
.table .thead-light th {
  background-color: var(--surface-muted);
  color: var(--text-muted);
  font-weight: 600;
  font-size: .6875rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  border-top: 0;
  border-bottom: 1px solid var(--border);
  padding: .875rem 1rem;
}
.table tbody td {
  border-top: 1px solid var(--border);
  padding: .875rem 1rem;
  vertical-align: middle;
  font-size: .8125rem;
}
.table-hover tbody tr:hover {
  background-color: var(--surface-muted);
}
.table-striped tbody tr:nth-of-type(odd) {
  background-color: rgba(241, 244, 249, .5);
}

/* Text links inside table body cells. Across ~30 DataTable list pages the
   name/identifier column renders as `<a href="javascript:show(...)">{label}</a>`
   (e.g. user/module/list.blade.php:139). Without this rule those anchors
   inherit Argon's default `a { color: #5e72e4 }`, which sits visually too
   close to the table's dark navy body text (--text #172b4d) — the cell looks
   slightly emphasized but not clearly clickable.
   Color is a brighter, more saturated blue (--link) than brand-primary navy
   so the anchor visually pops out of the navy text column and reads as a
   proper hyperlink at a glance. Hover/focus darkens + underlines for an
   interactive affordance. `:not(.btn):not(.badge):not(.dropdown-item)`
   protects the action-column buttons (delete/edit/permission anchors carrying
   `.btn`), badge-styled anchors, and any dropdown items from being repainted. */
.table tbody td a:not(.btn):not(.badge):not(.dropdown-item):not(.dropdown-toggle) {
  color: var(--link);
  font-weight: 600;
  text-decoration: none;
  transition: color var(--dur) var(--ease), text-decoration-color var(--dur) var(--ease);
}
.table tbody td a:not(.btn):not(.badge):not(.dropdown-item):not(.dropdown-toggle):hover,
.table tbody td a:not(.btn):not(.badge):not(.dropdown-item):not(.dropdown-toggle):focus {
  color: var(--link-hover);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* ---------- Badges ------------------------------------------------------- */
.badge {
  border-radius: var(--radius-pill);
  padding: .35em .7em;
  font-weight: 600;
  font-size: .6875rem;
  letter-spacing: .02em;
}
.badge-primary { background-color: var(--brand-tint); color: var(--brand-primary); }
.badge-success { background-color: rgba(45, 206, 137, .12); color: #1f8f5f; }
.badge-info    { background-color: rgba(17, 205, 239, .12); color: #0c8aa5; }
.badge-warning { background-color: rgba(251, 99, 64, .12); color: #c8451f; }
.badge-danger  { background-color: rgba(245, 54, 92, .12); color: #c81f43; }
/* Neutral status (e.g. MENUNGGU). The default Bootstrap gray washed out against
   the near-white page/card surfaces, so use a stronger slate tint + darker text
   so the pill stays clearly visible while matching the soft-badge family. */
.badge-secondary,
.badge-default { background-color: rgba(107, 122, 144, .16); color: #4d5a6d; }

/* ---------- Sidebar (Argon .navbar-vertical) ---------------------------- */
.navbar-vertical {
  background-color: var(--surface) !important;
  border-right: 1px solid var(--border);
  box-shadow: none !important;
}
.navbar-vertical .navbar-brand {
  padding: 1.25rem 1.5rem;
}

/* Item: no horizontal margin (would shift icon off-center in mini mode);
   padding stays so icon + text breathes in full mode. */
.navbar-vertical .navbar-nav .nav-link {
  color: var(--text-muted) !important;
  font-weight: 500;
  font-size: .8125rem;
  padding: .625rem 1rem;
  margin: .125rem .5rem;
  border-radius: var(--radius);
  position: relative;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.navbar-vertical .navbar-nav .nav-link:hover {
  background-color: var(--surface-muted);
  color: var(--text) !important;
}

/* Sidebar nav icons. Lucide SVGs and the few legacy Nucleo (.ni) glyphs share
   one layout — a fixed 1.125rem slot + .75rem gap — so every row's label
   starts at the same x regardless of which icon set it uses. */
.navbar-vertical .navbar-nav .nav-link > i,
.navbar-vertical .navbar-nav .nav-link .ni,
.navbar-vertical .navbar-nav .nav-link > svg {
  color: var(--text-faint) !important;
  width: 1.125rem;
  min-width: 0;          /* override Argon's .nav-link > i { min-width: 2rem } */
  flex-shrink: 0;
  margin-right: .75rem;
  text-align: center;
  transition: color var(--dur) var(--ease);
}
.navbar-vertical .navbar-nav .nav-link > svg {
  height: 1.125rem;
}
.navbar-vertical .navbar-nav .nav-link .ni {
  font-size: 1.0625rem;
  position: static;      /* override Argon's .nav-link i.ni { top: 2px } nudge */
}
.navbar-vertical .navbar-nav .nav-link:hover > i,
.navbar-vertical .navbar-nav .nav-link:hover .ni,
.navbar-vertical .navbar-nav .nav-link:hover > svg {
  color: var(--brand-primary) !important;
}

/* Active state — light tint bg + brand text/icon (icon must be explicit
   to defeat Argon's default color). */
.navbar-vertical .navbar-nav .nav-link.active {
  background-color: var(--brand-tint) !important;
  color: var(--brand-primary) !important;
  font-weight: 600;
}
.navbar-vertical .navbar-nav .nav-link.active > i,
.navbar-vertical .navbar-nav .nav-link.active i,
.navbar-vertical .navbar-nav .nav-link.active .ni,
.navbar-vertical .navbar-nav .nav-link.active > svg {
  color: var(--brand-primary) !important;
}

/* Accent bar (only in full sidenav mode — hidden in mini mode below) */
.navbar-vertical .navbar-nav .nav-link.active::before {
  content: "";
  position: absolute;
  left: -.5rem;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 1.25rem;
  background-color: var(--brand-primary);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

/* Sub-nav (collapse) */
.navbar-vertical .navbar-nav .nav .nav-link {
  font-size: .75rem;
  padding-top: .4rem;
  padding-bottom: .4rem;
  color: var(--text-muted) !important;
}
.navbar-vertical .navbar-nav .nav .nav-link.active {
  background-color: transparent !important;
  color: var(--brand-primary) !important;
}
.navbar-vertical .navbar-nav .nav .nav-link.active::before { display: none; }

/* Mini / collapsed sidenav: center icons, hide accent bar that would protrude. */
.g-sidenav-hidden:not(.g-sidenav-show) .sidenav .navbar-nav .nav-link,
.g-sidenav-hide .sidenav .navbar-nav .nav-link {
  justify-content: center;
  padding-left: .5rem;
  padding-right: .5rem;
  margin-left: .25rem;
  margin-right: .25rem;
}
.g-sidenav-hidden:not(.g-sidenav-show) .sidenav .navbar-nav .nav-link.active::before,
.g-sidenav-hide .sidenav .navbar-nav .nav-link.active::before {
  display: none;
}
/* Mini mode: drop the label gap so the icon centers in the rail. */
.g-sidenav-hidden:not(.g-sidenav-show) .sidenav .navbar-nav .nav-link > i,
.g-sidenav-hide .sidenav .navbar-nav .nav-link > i,
.g-sidenav-hidden:not(.g-sidenav-show) .sidenav .navbar-nav .nav-link .ni,
.g-sidenav-hide .sidenav .navbar-nav .nav-link .ni,
.g-sidenav-hidden:not(.g-sidenav-show) .sidenav .navbar-nav .nav-link > svg,
.g-sidenav-hide .sidenav .navbar-nav .nav-link > svg {
  margin-right: 0;
}
/* Argon keeps the collapse-chevron pseudo-element in the flex row even when
   its content is emptied — `margin-left: auto` then shifts the icon off-center
   on items with submenus. Pull it out of layout in mini mode. */
.g-sidenav-hidden:not(.g-sidenav-show) .sidenav .navbar-nav .nav-link:after,
.g-sidenav-hide .sidenav .navbar-nav .nav-link:after {
  display: none !important;
}

/* ---------- Dropdowns ---------------------------------------------------- */
.dropdown-menu {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  padding: .375rem;
}
.dropdown-item {
  border-radius: var(--radius-sm);
  padding: .5rem .75rem;
  font-size: .8125rem;
  color: var(--text);
}
.dropdown-item:hover, .dropdown-item:focus {
  background-color: var(--surface-muted);
  color: var(--brand-primary);
}
.dropdown-item.active, .dropdown-item:active {
  background-color: var(--brand-tint);
  color: var(--brand-primary);
}

/* ---------- DataTables --------------------------------------------------- */
table.dataTable {
  border-collapse: separate !important;
  border-spacing: 0;
}
/* Top + bottom toolbar layout — left content (buttons / info text) hugs
   the left edge, right cluster (search+entries-dropdown / pagination)
   hugs the right edge. The default DataTables dom uses fixed Bootstrap
   cols (e.g. <"col-sm-6"B><"col-sm-3"f><"col-sm-3"l> for the top row,
   <"col-sm-5"i><"col-sm-7"p> for the bottom), which leaves visible gaps
   inside each col when content is narrower than the col allocation.
   Override every col to auto-width flex items and let the first col grow
   to absorb the empty space, pushing the right cluster flush to the edge.
   sm-only so phone (xs) still stacks via Bootstrap defaults. */
@media (min-width: 576px) {
  .dataTables_wrapper > .row:first-child,
  .dataTables_wrapper > .row:last-child {
    flex-wrap: nowrap;
    align-items: center;
  }
  .dataTables_wrapper > .row:first-child > [class*="col-"],
  .dataTables_wrapper > .row:last-child > [class*="col-"] {
    flex: 0 0 auto;
    width: auto;
    max-width: none;
  }
  .dataTables_wrapper > .row:first-child > [class*="col-"]:first-child,
  .dataTables_wrapper > .row:last-child > [class*="col-"]:first-child {
    flex: 1 1 auto;
  }
}

/* Search input: magnifying-glass icon embedded inside the input on the left,
   placeholder "Search..." set via datatables-language.js (language.search
   emptied so the default "Search:" prefix label disappears). */
.dataTables_wrapper .dataTables_filter {
  text-align: right;
}
.dataTables_wrapper .dataTables_filter label {
  margin-bottom: 0;
  display: inline-block;
}
/* Several pages override `language.search` to inject a <i> icon as a label
   prefix (legacy pattern, predates our icon-inside-input refresh). Hide that
   prefix icon — our background-image inside the input is the canonical one. */
.dataTables_wrapper .dataTables_filter label > i,
.dataTables_wrapper .dataTables_filter label > svg {
  display: none;
}
.dataTables_wrapper .dataTables_filter input {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: .5rem .75rem .5rem 2.25rem;
  margin-left: 0 !important;
  font-size: .8125rem;
  line-height: 1.4;
  min-width: 240px;
  background-color: var(--surface);
  background-image: url("/img/ui/datatables-search.svg");
  background-repeat: no-repeat;
  background-position: left .75rem center;
  background-size: 14px 14px;
}
.dataTables_wrapper .dataTables_filter input::-moz-placeholder {
  color: var(--text-faint);
}
.dataTables_wrapper .dataTables_filter input::placeholder {
  color: var(--text-faint);
}
/* The "Show <select> entries" length select — strip native browser chevron
   (bulky double-arrow, inconsistent across OS) and replace with a clean
   single SVG chevron. Height matches .btn / search input for a clean toolbar. */
.dataTables_wrapper .dataTables_length label {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: 0;
  font-weight: 500;
  color: var(--text-muted);
  font-size: .8125rem;
}
.dataTables_wrapper .dataTables_length select {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: .5rem 1.75rem .5rem .75rem;
  font-size: .8125rem;
  line-height: 1.4;
  background-color: var(--surface);
  color: var(--text);
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("/img/ui/datatables-chevron.svg");
  background-repeat: no-repeat;
  background-position: right .625rem center;
  background-size: 10px 6px;
}
.dataTables_wrapper .dataTables_filter input:focus,
.dataTables_wrapper .dataTables_length select:focus {
  outline: none;
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px var(--brand-tint);
}

/* Top toolbar row (buttons + length + filter): breathing room below so
   the table doesn't sit too close. Bottom row (info + pagination): breathing
   room above; info stays left, pagination right (space-between).
   Spacing lives on the row, NOT on the inner elements — DataTables defaults
   give .dataTables_info and .dataTables_paginate different padding-top, which
   throws off centering if we put margin/padding on the elements themselves. */
.dataTables_wrapper .row {
  align-items: center;
}
.dataTables_wrapper > .row:first-child {
  margin-bottom: 1.25rem;
}
.dataTables_wrapper > .row:last-child {
  margin-top: 1.75rem;
  align-items: center;
}
/* Force each column in the bottom row to be a flex container that aligns
   its content to its own vertical center. The pagination buttons are
   visually taller than the info text — without this, the info anchors to
   the top of its column while pagination centers in its column, making
   them appear misaligned. */
.dataTables_wrapper > .row:last-child > [class*="col-"] {
  display: flex;
  align-items: center;
  min-height: 2.25rem;
}
.dataTables_wrapper > .row:last-child > [class*="col-"]:first-child {
  justify-content: flex-start;
}
.dataTables_wrapper > .row:last-child > [class*="col-"]:last-child {
  justify-content: flex-end;
}
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_paginate {
  margin-top: 0 !important;
  margin-bottom: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}
.dataTables_wrapper .dataTables_info {
  text-align: left;
  line-height: 1.4;
}
.dataTables_wrapper .dataTables_paginate {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}
.dataTables_wrapper .dataTables_paginate .pagination {
  margin-bottom: 0;
  justify-content: flex-end;
  align-items: center;
}
.dataTables_wrapper .dataTables_paginate .paginate_button {
  border-radius: var(--radius-sm) !important;
  margin: 0 2px;
}
.dataTables_wrapper .dataTables_paginate .paginate_button.current,
.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
  background: var(--brand-primary) !important;
  border-color: var(--brand-primary) !important;
  color: #fff !important;
}
/* Separate the DataTables action buttons so each looks like a standalone
   chip rather than a connected btn-group segment. */
.dt-buttons,
.dt-buttons.btn-group {
  display: inline-flex;
  flex-wrap: wrap;
  gap: .5rem;
}
.dt-buttons > .btn,
.dt-buttons .btn-secondary {
  border-radius: var(--radius) !important;
  font-size: .75rem;
  margin-left: 0 !important;
  margin-right: 0 !important;
}

/* DataTable row body — compact density + cleaner action chips that match
   the reference's flat, breathable vibe. Scoped to .dataTable so plain
   `.table` markup (e.g. dashboard summary tables) keeps its airy spacing. */
.dataTable tbody td {
  padding: .65rem .875rem;
  font-size: .8125rem;
  vertical-align: middle;
}
.dataTable thead th {
  padding: .75rem .875rem;
  font-size: .6875rem;
}
.dataTable tbody tr {
  transition: background-color var(--dur) var(--ease);
}
.dataTable tbody tr:hover {
  background-color: var(--surface-muted);
}

/* Soften the DataTables sort indicator triangles — defaults render
   at full opacity making header noisy. Active direction stays bold + brand. */
.dataTable thead .sorting::before,
.dataTable thead .sorting::after,
.dataTable thead .sorting_asc::before,
.dataTable thead .sorting_asc::after,
.dataTable thead .sorting_desc::before,
.dataTable thead .sorting_desc::after {
  opacity: .3;
  font-size: .7em;
  color: var(--text-faint);
}
.dataTable thead .sorting_asc::before,
.dataTable thead .sorting_desc::after {
  opacity: 1;
  color: var(--brand-primary);
}

/* Action btn-group inside rows: standalone chips, not connected.
   This neutralizes the chunky dark-fill connected-look for action toolbars
   inside cells. */
.dataTable tbody td .btn-group {
  display: inline-flex;
  flex-wrap: nowrap;
  gap: .25rem;
  vertical-align: middle;
  background: transparent;
  box-shadow: none;
}

/* Action cell content stays left-aligned regardless of column className.
   Many list pages set the action column to `text-center`, but with action
   toolbars whose width varies row-to-row (1 button vs 7+ buttons + status
   pill), centering makes the toolbar visually drift across rows. Anchoring
   to the left keeps the first button at a consistent x for the user's eye.
   `:has()` scopes this strictly to cells that actually contain a toolbar,
   so status / amount columns that legitimately use `text-center` are not
   affected. */
.dataTable tbody td:has(.btn-group) {
  text-align: left !important;
}
.dataTable tbody td .btn-group > .btn,
.dataTable tbody td > .btn-sm {
  padding: .4rem .6rem;
  font-size: .75rem;
  border-radius: var(--radius-sm) !important;
  margin: 0 !important;
  box-shadow: none !important;
  line-height: 1.2;
  min-width: 2rem;
  min-height: 1.875rem;
}

/* The margin:0 above keeps the first action element flush-left, but adjacent
   standalone action buttons (e.g. a .btn-group toolbar + Detail + Cetak, or
   just Detail + Cetak) would otherwise touch. Re-add a gutter between siblings
   only. Higher specificity + !important is required to beat the margin:0 rule
   above (and the inline `ml-1` utility some buttons still carry). */
.dataTable tbody td > .btn-sm + .btn-sm,
.dataTable tbody td > .btn-group + .btn-sm,
.dataTable tbody td > .btn-sm + .btn-group,
.dataTable tbody td > .btn-group + .btn-group {
  margin-left: .375rem !important;
}

/* Icon-only action buttons in rows.
   Previously these used surface (white) bg + var(--border) border, which
   on a white row read as nearly invisible — icons looked like loose flags,
   not buttons. Now they have a tinted surface fill + stronger border so
   the chip boundary is clearly visible at rest, and a brand-tinted hover
   with a small shadow lift to make the interactive affordance obvious. */
.dataTable tbody td .btn-group .btn-secondary,
.dataTable tbody td .btn-group .btn-dark,
.dataTable tbody td .btn-group .btn-default {
  background-color: var(--surface-muted) !important;
  border: 1px solid var(--border-strong) !important;
  color: var(--text-muted) !important;
}
.dataTable tbody td .btn-group .btn-secondary:hover,
.dataTable tbody td .btn-group .btn-dark:hover,
.dataTable tbody td .btn-group .btn-default:hover {
  background-color: var(--brand-tint) !important;
  color: var(--brand-primary) !important;
  border-color: var(--brand-primary) !important;
  box-shadow: 0 1px 3px rgba(20, 30, 55, .10) !important;
}
.dataTable tbody td .btn-group .btn-secondary:focus-visible,
.dataTable tbody td .btn-group .btn-dark:focus-visible,
.dataTable tbody td .btn-group .btn-default:focus-visible {
  outline: none;
  border-color: var(--brand-primary) !important;
  box-shadow: 0 0 0 3px var(--brand-tint) !important;
}

/* Colored status / action buttons in rows: soft-tinted pill instead of
   chunky solid fill (matches the "soft badge" vibe in the references). */
.dataTable tbody td .btn-warning {
  background-color: rgba(251, 99, 64, .14) !important;
  color: #c8451f !important;
  border-color: transparent !important;
  font-weight: 600;
}
.dataTable tbody td .btn-warning:hover {
  background-color: rgba(251, 99, 64, .22) !important;
  color: #c8451f !important;
}
.dataTable tbody td .btn-danger {
  background-color: rgba(245, 54, 92, .14) !important;
  color: #c81f43 !important;
  border-color: transparent !important;
  font-weight: 600;
}
.dataTable tbody td .btn-danger:hover {
  background-color: rgba(245, 54, 92, .22) !important;
  color: #c81f43 !important;
}
.dataTable tbody td .btn-success {
  background-color: rgba(45, 206, 137, .14) !important;
  color: #1f8f5f !important;
  border-color: transparent !important;
  font-weight: 600;
}
.dataTable tbody td .btn-success:hover {
  background-color: rgba(45, 206, 137, .22) !important;
  color: #1f8f5f !important;
}
.dataTable tbody td .btn-info {
  background-color: rgba(17, 205, 239, .14) !important;
  color: #0c8aa5 !important;
  border-color: transparent !important;
  font-weight: 600;
}
.dataTable tbody td .btn-info:hover {
  background-color: rgba(17, 205, 239, .22) !important;
  color: #0c8aa5 !important;
}
.dataTable tbody td .btn-primary {
  background-color: var(--brand-tint) !important;
  color: var(--brand-primary) !important;
  border-color: transparent !important;
  font-weight: 600;
}
.dataTable tbody td .btn-primary:hover {
  background-color: var(--brand-tint-strong) !important;
  color: var(--brand-primary) !important;
}

/* Link cells (KODE, ID columns, etc.) — brand color w/ subtle weight. */
.dataTable tbody td a:not(.btn) {
  color: var(--brand-primary);
  font-weight: 600;
  text-decoration: none;
}
.dataTable tbody td a:not(.btn):hover {
  color: var(--brand-primary-hover);
  text-decoration: underline;
}

/* ---------- Select2 ------------------------------------------------------ */
.select2-container--default .select2-selection--single,
.select2-container--default .select2-selection--multiple {
  border: 1px solid var(--border) !important;
  border-radius: var(--radius) !important;
  min-height: var(--control-h);
  background-color: var(--surface);
}
/* Single-select: pin to the shared control height. The label is centred with
   flexbox rather than a hard-coded line-height so the box still centres its
   text when it has to stretch (see the .input-group rule further down).
   Horizontal padding (.375rem) plus the __rendered padding-left (.5rem) adds
   up to the .875rem left padding a .form-control uses, so the text starts on
   the same x. */
.select2-container--default .select2-selection--single {
  height: var(--control-h);
  padding: 0 .375rem;
  display: flex;
  align-items: center;
}
/* Multi-select grows with the chips, so it only gets a floor. */
.select2-container--default .select2-selection--multiple {
  padding: .25rem .375rem;
}
.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container--default.select2-container--focus .select2-selection--multiple {
  border-color: var(--brand-primary) !important;
  box-shadow: 0 0 0 3px var(--brand-tint);
}

/* When a Select2 sits inside a Bootstrap .input-group (icon-prefix filter
   pattern used by Balance Mutation and similar pages), the .select2-selection
   keeps the !important border-radius set above on all four corners — making
   it render as a fully-pill chip next to a flat-right icon box, with a
   visible seam between them. Mirror the behaviour of .form-control inside
   .input-group: flatten whichever side meets a prepend/append so the two
   elements read as a single continuous control. */
.input-group > .input-group-prepend:first-child + .select2 + .select2-container .select2-selection,
.input-group > .input-group-prepend:first-child ~ .select2-container .select2-selection {
  border-top-left-radius: 0 !important;
  border-bottom-left-radius: 0 !important;
}
.input-group:has(> .input-group-append:last-child) > .select2-container .select2-selection {
  border-top-right-radius: 0 !important;
  border-bottom-right-radius: 0 !important;
}
/* Select2 copies the original <select>'s width onto the container as an inline
   `width: 100%`. Inside the flex + flex-wrap .input-group that makes its
   hypothetical main size the full row, so it wraps onto a second line below
   the icon box instead of sitting beside it. Give it the same treatment BS4
   gives a .form-control in an input-group (`flex: 1 1 auto; width: 1%`);
   `!important` is needed to beat the inline style. */
.input-group > .select2-container {
  flex: 1 1 auto;
  width: 1% !important;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
  line-height: 1.5;
  font-size: .875rem;
  flex: 1 1 auto;
  min-width: 0;
  color: var(--text);
  padding-left: .5rem;
  /* Truncate long selected text (e.g. "VA-number - long owner name") to a
     single ellipsised line so the selection box keeps its fixed height
     instead of wrapping content under the input. The full text is exposed
     via the `title` attribute set by templateSelection (native tooltip on
     hover). padding-right leaves room for the clear-x button + arrow. */
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding-right: 1.75rem;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
  height: calc(var(--control-h) - 2px);
}
/* Match the .form-control font size in the dropdown itself so the list text
   and the closed control read as one widget (Select2 otherwise inherits the
   1rem body size). */
.select2-container--default .select2-results__option,
.select2-container--default .select2-search--dropdown .select2-search__field,
.select2-container--default .select2-selection--multiple .select2-selection__choice {
  font-size: .875rem;
}
.select2-dropdown {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
  background-color: var(--brand-primary) !important;
}

/* Rich-content Select2 dropdowns (Mitra + Va Parent in list filters) use
   the .select2-result-repository template with avatar + multi-line meta
   (title, VA number, balance). By default Select2 sizes the dropdown to
   the input width — but in compact filter contexts the input is narrow,
   causing the VA number + balance to be truncated. Force a minimum
   dropdown width so the full result row is readable regardless of input
   width. `:has()` scopes this so plain (text-only) Select2 dropdowns
   keep matching the input width. */
.select2-dropdown:has(.select2-result-repository) {
  min-width: 320px;
}
/* The rich row itself: avatar floats left, meta takes the rest. Ensure
   the meta block can fill the wider dropdown so long titles/numbers
   don't clip mid-row.
   Argon's vendored custom.css (public/assets/css/custom.css) ships a
   float-based legacy layout: __avatar { float:left; width:60px } and
   __meta { margin-left:70px } as a float-clear shim. Those leak into our
   flex parent and produce a ~140px void between the 40px avatar and the
   meta text. Reset width/margin/float so the flex gap is the only spacer. */
.select2-result-repository {
  display: flex !important;
  gap: .625rem;
  align-items: flex-start;
  padding: .25rem 0;
}
.select2-result-repository__avatar {
  flex: 0 0 auto;
  float: none !important;
  width: auto !important;
  margin-right: 0 !important;
}
.select2-result-repository__avatar img {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  -o-object-fit: cover;
     object-fit: cover;
}
.select2-result-repository__meta {
  flex: 1 1 auto;
  min-width: 0;
  margin-left: 0 !important;
}
.select2-result-repository__title {
  font-weight: 600;
  color: var(--text);
  font-size: .8125rem;
  line-height: 1.3;
}
.select2-result-repository__description {
  color: var(--text-muted);
  font-size: .75rem;
  word-break: break-all;
  line-height: 1.3;
}
.select2-result-repository__statistics {
  display: flex;
  gap: .75rem;
  margin-top: .15rem;
  color: var(--text-muted);
  font-size: .75rem;
}
/* When a row is highlighted (hover/keyboard), all its text and the icon
   should flip to white for legibility against the brand-primary fill. */
.select2-container--default .select2-results__option--highlighted[aria-selected] .select2-result-repository__title,
.select2-container--default .select2-results__option--highlighted[aria-selected] .select2-result-repository__description,
.select2-container--default .select2-results__option--highlighted[aria-selected] .select2-result-repository__statistics,
.select2-container--default .select2-results__option--highlighted[aria-selected] .select2-result-repository__forks {
  color: #fff;
}

/* ---------- Flatpickr ---------------------------------------------------- */
.flatpickr-input.form-control { background-color: var(--surface); }
.flatpickr-calendar {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

/* ---------- Pagination (non-datatable) ---------------------------------- */
.pagination .page-link {
  border: 1px solid var(--border);
  color: var(--text-muted);
  border-radius: var(--radius-sm) !important;
  margin: 0 2px;
  padding: .375rem .75rem;
  font-size: .8125rem;
}
.pagination .page-item.active .page-link {
  background-color: var(--brand-primary);
  border-color: var(--brand-primary);
  color: #fff;
}

/* ---------- Alerts ------------------------------------------------------- */
.alert {
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: .875rem 1rem;
  font-size: .8125rem;
}
/* Inline AJAX-response alert container — used by many forms (mitra, va,
   disbursement, transfer, login_guard, etc.) as <div id="response_container"></div>.
   When JS injects a validation/error alert into it, the container needs
   breathing room above so the alert doesn't sit flush against the form
   field / heading immediately preceding it. `:not(:empty)` keeps the
   spacing off when no alert is shown. */
#response_container:not(:empty) {
  margin-top: 1.25rem;
}
.alert-primary { background-color: var(--brand-tint); border-color: var(--brand-tint-strong); color: var(--brand-primary); }
.alert-success { background-color: rgba(45, 206, 137, .1);  border-color: rgba(45, 206, 137, .2);  color: #1f8f5f; }
.alert-info    { background-color: rgba(17, 205, 239, .1);  border-color: rgba(17, 205, 239, .2);  color: #0c8aa5; }
.alert-warning { background-color: rgba(251, 99, 64, .1);   border-color: rgba(251, 99, 64, .2);   color: #c8451f; }
.alert-danger  { background-color: rgba(245, 54, 92, .1);   border-color: rgba(245, 54, 92, .2);   color: #c81f43; }

/* ---------- Breadcrumb --------------------------------------------------- */
/* Items use inline-flex so icons inside <a> sit on the same horizontal
   centerline as adjacent text. */
.breadcrumb {
  align-items: center;
  margin-bottom: 0;
}
.breadcrumb-item,
.breadcrumb-item a {
  display: inline-flex;
  align-items: center;
}
.breadcrumb-item i,
.breadcrumb-item .ni,
.breadcrumb-item svg {
  display: inline-flex;
  align-items: center;
  line-height: 1;
  font-size: 1em;
}

/* ---------- Tabs (plain underline style — NOT the card-header browser tabs) */
/* :not(.card-header-tabs) so these generic rules never override the melekuk
   browser-tab styling defined above for card-header tabs. */
.nav-tabs:not(.card-header-tabs) {
  border-bottom: 1px solid var(--border);
}
.nav-tabs:not(.card-header-tabs) .nav-link {
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--text-muted);
  font-weight: 600;
  font-size: .8125rem;
  padding: .75rem 1rem;
  margin-bottom: -1px;
}
.nav-tabs:not(.card-header-tabs) .nav-link:hover { color: var(--text); border-bottom-color: var(--border-strong); }
.nav-tabs:not(.card-header-tabs) .nav-link.active {
  color: var(--brand-primary);
  background: transparent;
  border-bottom-color: var(--brand-primary);
}

/* ---------- Helpers reusable across pages ------------------------------- */
.summary-box {
  background-color: var(--brand-tint);
  border-radius: var(--radius-lg);
  padding: 1rem 1.25rem;
  color: var(--brand-primary);
}
.summary-box .summary-label { font-size: .75rem; color: var(--text-muted); font-weight: 500; }
.summary-box .summary-value { font-size: 1.25rem; font-weight: 700; color: var(--brand-primary); }

/* Segmented control (pill toggle) */
.segmented {
  display: inline-flex;
  background-color: var(--surface-sunken);
  border-radius: var(--radius);
  padding: .25rem;
  gap: .25rem;
}
.segmented > .segmented-item {
  flex: 1;
  border: 0;
  background: transparent;
  color: var(--text-muted);
  font-size: .8125rem;
  font-weight: 600;
  padding: .5rem 1rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.segmented > .segmented-item.active {
  background-color: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-xs);
}

/* Step indicator (for bd-wizard / custom steppers) */
.steps-indicator {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-bottom: 1.5rem;
}
.steps-indicator .step {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .8125rem;
  color: var(--text-faint);
  font-weight: 500;
}
.steps-indicator .step .step-dot {
  width: 1.5rem; height: 1.5rem;
  border-radius: 50%;
  background-color: var(--surface-sunken);
  color: var(--text-faint);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .75rem; font-weight: 600;
  border: 1px solid var(--border);
}
.steps-indicator .step.is-active { color: var(--text); font-weight: 600; }
.steps-indicator .step.is-active .step-dot {
  background-color: var(--brand-primary); color: #fff; border-color: var(--brand-primary);
}
.steps-indicator .step.is-done { color: var(--text-muted); }
.steps-indicator .step.is-done .step-dot {
  background-color: var(--success); color: #fff; border-color: var(--success);
}
.steps-indicator .step-sep {
  flex: 1; height: 1px; background-color: var(--border);
}

/* Empty state */
.empty-state {
  text-align: center;
  padding: 2.5rem 1.5rem;
  color: var(--text-muted);
}
.empty-state .empty-icon {
  font-size: 2.5rem;
  color: var(--text-faint);
  margin-bottom: .75rem;
}
.empty-state .empty-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: .25rem;
}

/* Soft divider */
.divider-soft { height: 1px; background: var(--border); margin: 1.25rem 0; border: 0; }

/* Card with brand accent header (optional helper) */
.card.card-accent { border-top: 3px solid var(--brand-primary); }

/* ---------- Compact filter bar (list-page header filters) -------------- */
/* Horizontal row of labeled inputs (Mitra, Va Parent, Status, date range,
   amount range, etc.) + filter/reset action buttons. Used by list pages
   that need many filter dimensions but want to keep them out of the card
   body so the data table gets full vertical space. Each .filter-field
   wraps one label + control; .filter-actions docks the buttons to the
   right (or wraps under at narrow widths). Inputs are sized smaller than
   the default form tokens — defaults target full-page forms where breathing
   room is valued; here we want density. */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: .75rem 1rem;
}
/* flex-basis: 0 + grow: 1 means every field in the same row takes the SAME
   computed width — `(row_width - gaps) / count`. Wrapping is driven purely
   by min-width: when computed width drops below it, the next field wraps.
   This avoids the previous mismatch where fields with different flex-basis
   values (e.g. --wide=200px vs default 140px) ended up unequal widths when
   only some-of-them shared a row. */
.filter-bar .filter-field {
  flex: 1 1 0;
  min-width: 140px;
  margin: 0;
}
/* --wide / --narrow modifiers are now no-ops in the equal-width layout.
   Kept as selectors so existing markup using them doesn't lose styling,
   but the sizing is uniform. */
.filter-bar .filter-field--wide,
.filter-bar .filter-field--narrow {
  flex: 1 1 0;
}
.filter-bar .filter-label {
  display: block;
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: .35rem;
  letter-spacing: 0;
  line-height: 1.2;
}
.filter-bar .form-control,
.filter-bar .input-group-text {
  font-size: .8125rem;
  padding: .45rem .75rem;
  min-height: 2.375rem;
  height: auto;
}
.filter-bar .input-group {
  flex-wrap: nowrap;
}
/* Select2 wraps the underlying <select>; its container must match the
   shrunken form-control height or the field looks misaligned. Argon's
   default Select2 size is taller (matches the page-form .form-control). */
.filter-bar .select2-container--default .select2-selection--single,
.filter-bar .select2-container--default .select2-selection--multiple {
  min-height: 2.375rem !important;
  height: 2.375rem !important;
  padding: .15rem .25rem !important;
}
.filter-bar .select2-container--default .select2-selection--single .select2-selection__rendered {
  line-height: 1.75rem !important;
  font-size: .8125rem;
  padding-left: .375rem;
}
.filter-bar .select2-container--default .select2-selection--single .select2-selection__arrow {
  height: 2.25rem !important;
}
.filter-bar .filter-actions {
  flex: 0 0 auto;
  display: flex;
  gap: .5rem;
  align-items: stretch;
  margin-left: auto;
}
.filter-bar .filter-actions .btn {
  height: 2.375rem;
  padding-top: 0;
  padding-bottom: 0;
  white-space: nowrap;
}
/* Very narrow screens: drop to single column, actions take their own full
   row at the bottom with buttons right-aligned. */
@media (max-width: 575.98px) {
  .filter-bar .filter-field {
    flex: 1 1 100%;
    min-width: 0;
  }
  .filter-bar .filter-actions {
    margin-left: 0;
    width: 100%;
    justify-content: flex-end;
  }
}

/* ---------- Legacy filter-section → compact bar (no markup change) ----- */
/* Most list pages predate the virtual_account/list compact filter-bar
   refactor and still use the legacy pattern:
     <div class="card-header">
       <h3><i data-lucide="filter"></i> Filter</h3>
       <div class="row">
         <div class="col-md-X form-group">
           <label>...</label>
           <input/select>
         </div>
         ...
         <div class="col-md-12 form-group">
           <button onclick="filter()">Filter</button>
         </div>
       </div>
     </div>
   Re-style every such section in-place: hide the redundant title (the
   inputs themselves communicate "filter"), turn .row into a flex bar of
   equal-width fields, dock the Filter button to the right, and shrink
   labels/inputs to the same density as filter-bar. Selector matches any
   card-header whose <h3> contains an .lucide-filter icon — narrow enough to
   skip non-filter card-headers (which usually don't have that icon). */
.card-header:has(> h3 > .lucide-filter) > h3 {
  display: none;
}
.card-header:has(> h3 > .lucide-filter) > .row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: .75rem 1rem;
  margin: 0;
}
/* Each col-* form-group becomes an equal-grow field. Override Bootstrap's
   col- max-width and per-col padding so they really do share the row. */
.card-header:has(> h3 > .lucide-filter) > .row > [class*="col-"].form-group {
  flex: 1 1 0;
  min-width: 140px;
  max-width: none;
  padding: 0;
  margin: 0;
}
/* The Filter button is conventionally in a col-md-12.form-group at the
   end. Detach from equal-grow and dock to the right edge of the row. */
.card-header:has(> h3 > .lucide-filter) > .row > .col-md-12.form-group {
  flex: 0 0 auto;
  margin-left: auto;
  min-width: 0;
}
.card-header:has(> h3 > .lucide-filter) > .row > .col-md-12.form-group > .btn {
  height: 2.375rem;
  white-space: nowrap;
}
/* Variant pattern (e.g. transaction/transfer, transaction/skn_rtgs): the
   Filter button sits as a DIRECT child of card-header — outside the .row,
   sibling of <h3> and the row. Without intervention it sticks directly to
   the bottom of the row above. Make the card-header a flex column so the
   button can dock to the right with a top gap. */
.card-header:has(> h3 > .lucide-filter) {
  display: flex;
  flex-direction: column;
}
.card-header:has(> h3 > .lucide-filter) > .btn {
  margin-top: 1rem;
  align-self: flex-start;
  height: 2.375rem;
  white-space: nowrap;
}
/* Field labels match filter-label visual: small, muted, tight margin. */
.card-header:has(> h3 > .lucide-filter) > .row [class*="col-"].form-group > label {
  font-size: .75rem;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: .35rem;
  letter-spacing: 0;
  line-height: 1.2;
}
/* Compact input density — same as filter-bar. */
.card-header:has(> h3 > .lucide-filter) > .row .form-control,
.card-header:has(> h3 > .lucide-filter) > .row .input-group-text {
  font-size: .8125rem;
  min-height: 2.375rem;
  padding: .45rem .75rem;
}
.card-header:has(> h3 > .lucide-filter) > .row .select2-container--default .select2-selection--single,
.card-header:has(> h3 > .lucide-filter) > .row .select2-container--default .select2-selection--multiple {
  min-height: 2.375rem !important;
  height: 2.375rem !important;
  padding: .15rem .25rem !important;
}
.card-header:has(> h3 > .lucide-filter) > .row .select2-container--default .select2-selection--single .select2-selection__rendered {
  line-height: 1.75rem !important;
  font-size: .8125rem;
  padding-left: .375rem;
}
.card-header:has(> h3 > .lucide-filter) > .row .select2-container--default .select2-selection--single .select2-selection__arrow {
  height: 2.25rem !important;
}
/* Mobile: drop to single column, button takes its own bottom row. */
@media (max-width: 575.98px) {
  .card-header:has(> h3 > .lucide-filter) > .row > [class*="col-"].form-group {
    flex: 1 1 100%;
    min-width: 0;
  }
  .card-header:has(> h3 > .lucide-filter) > .row > .col-md-12.form-group {
    margin-left: 0;
    width: 100%;
  }
}

/* Mitra dropdown with a leading search icon — visually communicates that
   the dropdown is searchable/typeable (Select2 is initialized later in JS,
   converting the bare <select> into a searchable input). The icon stays
   purely decorative (pointer-events: none) so clicks still reach the
   Select2 trigger underneath. The padding-left shift applies both to the
   raw <select> during the brief pre-Select2 render and to Select2's
   rendered single-selection text after init. */
.mitra-search-wrap {
  position: relative;
}
.mitra-search-icon {
  position: absolute;
  left: .875rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-faint);
  font-size: .8125rem;
  pointer-events: none;
  z-index: 2;
}
.mitra-search-wrap > .form-control,
.mitra-search-wrap .select2-container--default .select2-selection--single .select2-selection__rendered {
  padding-left: 2.25rem !important;
}

/* ---------- Saldo mask cell (hide/show balance in list tables) ---------- */
/* Used by manage/mitra/list and manage/merchant/list to mask a row's saldo
   behind a deliberate dot pattern, with a small eye-button that fetches +
   reveals the value on click. The actual value never enters the DOM until
   the user explicitly clicks reveal, so this stays sensitive-data-friendly.
   Masked text uses --text-faint so it recedes; the toggle is a real
   <button> (a11y) styled as a ghost icon-chip that tints to brand on hover. */
.saldo-cell {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  line-height: 1;
}
.saldo-masked {
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}
.saldo-mask-dots {
  letter-spacing: .15em;
  margin-left: .25em;
}
/* Color is intentionally NOT set here — .saldo-value renders in two
   contexts: navbar `.box-saldo` (parent `.text-white`, needs white) and
   list rows `.saldo-cell` inside a table cell (inherits dark from
   `.table { color: var(--text) }`). Letting inheritance pick the right
   color works for both; an explicit color here used to override the
   navbar's white and made the value unreadable on the brand-blue band. */
.saldo-value {
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}
.saldo-toggle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.saldo-toggle-btn:hover {
  background-color: var(--brand-tint);
  color: var(--brand-primary);
}
.saldo-toggle-btn:focus {
  outline: none;
  box-shadow: 0 0 0 3px var(--brand-tint);
}
.saldo-toggle-btn .fas,
.saldo-toggle-btn .far {
  font-size: .8125rem;
  line-height: 1;
}

/* In-cell saldo loader. Used by manage/mitra/list + manage/merchant/list
   while the AJAX request for the row's saldo is in-flight. Sits in the
   .position-absolute overlay above the .saldo-cell, hosting a small instance
   of the same 3-dot wave Lottie used by Ryuna.blockUI (see _mountLottie in
   public/js/global.js) plus a "Memuat..." label next to it. Sized smaller
   (40×16) than the global blockUI loader (88×44) so it fits inside a single
   table-row height — anything bigger would force the row to grow when the
   loader appears and snap back when it resolves, which looks janky.
   Visibility is toggled by .d-none rather than inline `display: none` so the
   flex centering on this rule isn't overwritten by jQuery's .show()/.hide(). */
.saldo-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .375rem;
  background-color: var(--surface);
}
.saldo-loading-lottie {
  width: 40px;
  height: 16px;
  flex-shrink: 0;
  transform: translateZ(0);
}
.saldo-loading-lottie svg {
  display: block;
  width: 100%;
  height: 100%;
}
.saldo-loading-text {
  font-size: .75rem;
  color: var(--text-muted);
  line-height: 1;
}

/* ---------- SweetAlert2 polish ------------------------------------------ */
.swal2-popup {
  border-radius: var(--radius-lg) !important;
  font-family: inherit !important;
}
.swal2-styled.swal2-confirm {
  background-color: var(--brand-primary) !important;
  border-radius: var(--radius) !important;
  font-weight: 600;
}
.swal2-styled.swal2-cancel {
  border-radius: var(--radius) !important;
  font-weight: 600;
}

/* ---------- Mitra Product Card (Compact Fee List) ----------------------- */
/* Uses design-tokens consistent with .detail-list pattern across the app. */
.mitra-product-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
  margin-bottom: 1.5rem;
}
.mitra-product-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 1rem 1.25rem;
  background: var(--surface-muted);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.mitra-product-title {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--text);
  flex: 1;
  min-width: 200px;
  line-height: 1.4;
}
.mitra-product-actions {
  flex: 0 0 auto;
}
.mitra-product-body {
  padding: 1.25rem;
}
/* Section title: match .detail-section-title style */
.mitra-product-subtitle {
  font-size: .6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-muted);
  margin: 0 0 1rem;
  display: flex;
  align-items: center;
  gap: .5rem;
}
/* Fee list container: vertical stack */
.fee-list {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
/* Each fee row: icon + label + value (horizontal, vertically centered) */
.fee-item {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--border);
}
.fee-item:last-child {
  padding-bottom: 0;
  border-bottom: none;
}
/* Icon: brand color, centered */
.fee-icon {
  flex: 0 0 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.fee-icon i,
.fee-icon svg {
  width: 20px;
  height: 20px;
  color: var(--brand-primary);
  stroke: var(--brand-primary);
}
/* Center section: fee name + min/max info */
.fee-label {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .35rem;
  min-width: 0;
}
/* Fee name: bold, readable */
.fee-name {
  font-size: .875rem;
  font-weight: 600;
  color: var(--text);
  line-height: 1.4;
}
/* Min/Max info: small, subtle */
.fee-info {
  font-size: .75rem;
  color: var(--text-faint);
  font-weight: 400;
  line-height: 1.3;
}
/* Right side: fee value — prominent */
.fee-value {
  flex: 0 0 auto;
  font-size: .95rem;
  font-weight: 600;
  color: var(--brand-primary);
  min-width: 80px;
  text-align: right;
  line-height: 1.4;
}

/* ---------- VA Usage Summary List --------------------------------------- */
/* Same visual rhythm as .fee-list — vertical stack with icon + label + value
   + action button on the right. */
.va-usage-list {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.va-usage-item {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.va-usage-item:last-child {
  padding-bottom: 0;
  border-bottom: none;
}
.va-usage-icon {
  flex: 0 0 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.va-usage-icon i,
.va-usage-icon svg {
  width: 20px;
  height: 20px;
  color: var(--brand-primary);
  stroke: var(--brand-primary);
}
.va-usage-label {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .25rem;
  min-width: 200px;
}
.va-usage-name {
  font-size: .875rem;
  font-weight: 600;
  color: var(--text);
  line-height: 1.4;
}
.va-usage-info {
  font-size: .75rem;
  color: var(--text-faint);
  font-weight: 400;
  line-height: 1.3;
}
.va-usage-value {
  flex: 0 0 auto;
  min-width: 80px;
  text-align: right;
}
.va-usage-count {
  font-size: 1.125rem;
  font-weight: 700;
  line-height: 1.4;
}
.va-usage-count--active {
  color: var(--brand-primary);
  text-decoration: none;
}
.va-usage-count--active:hover {
  color: var(--brand-primary-hover);
  text-decoration: underline;
}
.va-usage-count--zero {
  color: var(--text-faint);
}
.va-usage-actions {
  flex: 0 0 auto;
}
/* Empty state */
.va-usage-empty {
  text-align: center;
  padding: 2rem 1rem;
}
.va-usage-empty img {
  height: 180px;
  opacity: .85;
  margin-bottom: 1rem;
}
.va-usage-empty h4 {
  color: var(--text-muted);
  font-weight: 500;
  margin: 0;
}

/* ---------- Scrollbar (subtle) ------------------------------------------ */
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background-color: var(--border-strong); border-radius: var(--radius-pill); }
*::-webkit-scrollbar-thumb:hover { background-color: var(--text-faint); }
*::-webkit-scrollbar-track { background: transparent; }

