/* ============================================================================
 * components.css — shared ui_upmedik component styles, loaded app-wide AFTER
 * the compiled Tailwind bundle (style.css) in every ui_upmedik layout. Plain
 * CSS on theme tokens; no Tailwind rebuild needed. See -UPMEDIK_PREREQ.md.
 * ==========================================================================*/

/* Header action pills — Edit / PDF / Back all share ONE size & shape (pill).
 * Colour is the only thing that varies (variants below). See -UPMEDIK_PREREQ.md §5. */
.up-pill {
    display: inline-flex; align-items: center; justify-content: center; gap: .35rem;
    height: 2rem; padding: 0 1rem;
    border-radius: 9999px;                       /* pill (rounded-full — exempt from the .4rem rule) */
    font-size: .8rem; font-weight: 600; line-height: 1; white-space: nowrap;
    border: 1px solid transparent;
    text-decoration: none; cursor: pointer;
    transition: background-color .12s ease, color .12s ease, border-color .12s ease, opacity .12s ease;
}
.up-pill svg { height: .9rem; width: .9rem; flex-shrink: 0; }
/* .up-pill sets display:inline-flex; same-specificity + later-in-cascade beats
 * Tailwind's .hidden{display:none} from style.css, so a pill toggled hidden via
 * JS (classList.toggle('hidden', ...)) stayed visible. Two-class selector wins
 * on specificity regardless of source order — no !important needed. */
.up-pill.hidden { display: none; }

/* SAME TRAP, same fix, for the other components that set a display.
 * .upk-btn{display:inline-flex} and .upk-input{display:flex} live in
 * erp-compat.css at offsets ~50.8KB and ~51.9KB, while .hidden{display:none} is
 * at ~12.3KB of the same file — equal specificity, so cascade order handed it to
 * the component and `class="… upk-btn … hidden"` rendered VISIBLE. That is why
 * the Karyawan field on /4019_absensi showed two dropdowns (the raw <select>
 * above its widget), and why two buttons meant to start hidden did not.
 * Two-class selector wins on specificity whatever the source order. */
.upk-btn.hidden,
.upk-input.hidden { display: none; }

/* Solid primary (e.g. Edit). */
.up-pill--primary { background: var(--primary); color: var(--primary-foreground); }
.up-pill--primary:hover { opacity: .9; }

/* Locked — the action exists but this user may not perform it. Shown INSTEAD of
 * hiding the control, so the reason is on screen ([title]) rather than left to
 * the user to guess from a button that is not there. Not a button: render it as
 * a <span> so there is nothing to click and nothing to focus. */
.up-pill--locked {
    background: var(--secondary); color: var(--muted-foreground);
    border-color: var(--border); cursor: not-allowed; opacity: .7;
}

/* PDF export — green (e.g. Cetak Biodata → PDF). */
.up-pill--pdf { background: var(--emerald, #10b981); color: #fff; }
.up-pill--pdf:hover { opacity: .9; }

/* Unified "back to previous page" button (-UPMEDIK_PREREQ.md §5). Size/shape come
 * from `.up-pill` (the partial adds both classes). LIGHT-primary by default →
 * solid primary on hover. `margin-left:auto` pushes it to the RIGHT of its flex
 * header row. Render via `_partials/back_button`; never hand-roll one. */
.up-back {
    margin-left: auto;
    background: color-mix(in oklch, var(--primary) 12%, transparent);
    color: var(--primary);
    border-color: color-mix(in oklch, var(--primary) 22%, transparent);
}
.up-back:hover { background: var(--primary); color: var(--primary-foreground); border-color: var(--primary); }

/* ---------------------------------------------------------------------------
 * Selection pills / button-select — ONE definition for /elements and for every
 * panel that uses them. Three states, on request:
 *
 *     inactive  card background + a real --border ring (so the pill reads as a
 *               BUTTON, not as bare text — on the light-grey page background a
 *               --secondary fill with a --secondary border was invisible)
 *     hover     blue   (brand)
 *     selected  blue   (brand)
 *
 * Written HERE, not as Tailwind utilities, for two reasons: the bundle is
 * prebuilt and purged so a hover:border-* that no source file already uses does
 * not exist at runtime, and an INLINE style (which the datatable02 filter pills
 * use for their state) can never be overridden by a :hover class. A real class
 * with a real :hover rule is the only spelling that does all three.
 * ------------------------------------------------------------------------- */
/* ci_data's pill colours, verbatim (user 2026-09-15: "copy the colour from
   ci_data gizi_gudang#stock"): inactive = --secondary fill, active/hover = --primary.
   The ERP copy had drifted to a white card + border look. */
.up-select-pill {
    background: var(--secondary);
    color: var(--secondary-foreground);
    border-color: var(--secondary);
    transition: background-color .12s ease, color .12s ease, border-color .12s ease;
}



/* The two native Bootstrap radios left in the app: the vendor default is its own
   #0d6efd, a different blue from the brand. One blue, everywhere. */
.form-check-input:checked {
    background-color: var(--color-brand);
    border-color: var(--color-brand);
}

/* --------------------------------------------------------------------------
 * Submit-button busy state — the `indicator` contract
 *
 * Every form here writes the Metronic shape:
 *
 *     <button type="submit" class="upk-btn upk-btn-primary">
 *         <span class="indicator-label">Submit</span>
 *         <span class="indicator-progress">Please wait...
 *             <span class="spinner-border spinner-border-sm"></span></span>
 *     </button>
 *
 * Metronic's CSS hid `.indicator-progress` until the button was flagged busy.
 * That stylesheet is gone and NOTHING replaced it — there was not one rule for
 * either class anywhere in the app — so both spans painted at once and the
 * button read "Submit Please wait...". 64 labels across 52 files said that.
 *
 * The flag is `data-kt-indicator="on"`, which 44 files already set and clear;
 * _shared/submit_indicator.js supplies it for the forms that never did.
 * ------------------------------------------------------------------------- */
.indicator-progress { display: none; }
[data-kt-indicator="on"] .indicator-label { display: none; }
[data-kt-indicator="on"] .indicator-progress { display: inline-flex; align-items: center; }

/* A busy button must also LOOK unavailable, not merely refuse the second click. */
[data-kt-indicator="on"],
.upk-btn:disabled { opacity: .65; cursor: not-allowed; }

/* The spinner itself only existed under .legacy-scope, so on a ui_upmedik page
   the "Please wait" text had an invisible companion. Same geometry, unscoped. */
.spinner-border {
    display: inline-block; width: 1.25rem; height: 1.25rem;
    border: .2em solid currentColor; border-right-color: transparent;
    border-radius: 50%; animation: upk-spin .75s linear infinite;
}
.spinner-border-sm { width: 1rem; height: 1rem; border-width: .15em; }
@keyframes upk-spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------------------
 * `.d-none` — the Bootstrap utility 591 call sites use and NOTHING defined.
 *
 * Every `class="… d-none"` in the app was inert: filter rows meant to start
 * hidden (filter_tanggal, filter_range), panel Edit buttons, inline validation
 * messages — all of them painted. Bootstrap's own spelling, including the
 * !important and the later media query, so `d-none d-lg-flex` still means
 * "hidden on small, flex from lg" instead of hidden everywhere.
 * ------------------------------------------------------------------------- */
.d-none { display: none !important; }
@media (min-width: 768px) {
    /* The md tier was missing, and `d-none d-md-inline-block` therefore meant
       hidden EVERYWHERE — the helpdesk list's desktop RIWAYAT button (the one
       that expands the row inline) never painted, leaving only the phone
       variant, whose `d-md-none` was equally inert. */
    .d-md-none         { display: none !important; }
    .d-md-inline       { display: inline !important; }
    .d-md-inline-block { display: inline-block !important; }
    .d-md-block        { display: block !important; }
    .d-md-flex         { display: flex !important; }
}
@media (min-width: 992px) {
    .d-lg-flex  { display: flex !important; }
    .d-lg-block { display: block !important; }
}

/* ── Table header band — ONE definition, app-wide ─────────────────────────────
   Every <th> in the app carries the same 20%-primary tint (-UPMEDIK_PREREQ.md
   §10). It lives here rather than in each table's class string because that is
   exactly what went wrong: the tint was typed per table and drifted into four
   different answers — bg-primary/30 in the list views, bg-primary/20 in the
   charts shell, bg-primary/5 in one report, and nothing at all in the ERM
   panels and reg-detail tables. Four spellings, one intention.

   Keyed on the CELL, so a table built in JS (UpTable, the charts shell) gets the
   band without its renderer knowing about it — and so do the header rows written
   as a bare <tr> with no <thead> around them, which several report pages use.
   -UPMEDIK_PREREQ.md §10 words it the same way: every <th>, any table.

   Header text keeps the colour it already had — the tint is a band, not a theme. */
th,
.up-panel-head {
    background-color: color-mix(in oklch, var(--primary) 20%, transparent);
}

/* A section header inside a panel — "I. Pengkajian", "II. Pendidikan Kesehatan".
   It shares the declaration above deliberately: the header band was written as
   `bg-primary/15`, a DIFFERENT opacity of the same hue, and at 15% over the dark
   card it composites toward violet while the table headers beside it stay blue.
   Two blues in one panel read as two colours, so there is one. */
.up-panel-head { }

/* ── Fold card — a card whose body collapses ──────────────────────────────────
   The ui_upmedik answer to Bootstrap's `data-bs-toggle="collapse"`. Built on
   <details>/<summary>, so open/close costs no JS and survives with the Bootstrap
   bundle gone; the shell already keeps that state per element.

   Usage:
     <details class="up-fold rounded-xl border border-border bg-card shadow-sm
                     overflow-hidden" open>
       <summary class="up-panel-head flex items-center gap-3 px-4 py-3 …">
         <h3>…</h3><svg class="up-fold-chev ml-auto …">…</svg>
       </summary>
       <div class="p-4">…</div>
     </details>

   `list-style:none` + the webkit rule kill the native disclosure triangle
   (Safari needs the ::-webkit- one even when the summary is display:flex). */
   NOT for dropdown MENUS. Those have their own contract already — the
   `data-upx-dropdown` / `-dd-trigger` / `-dd-menu` trio from the golden element
   at /elements#menus. One shape per job; a <details>-based menu next to it would
   be a second dropdown idiom in the same app. */
.up-fold > summary { list-style: none; cursor: pointer; user-select: none; }
.up-fold > summary::-webkit-details-marker { display: none; }
.up-fold-chev { transition: transform .15s ease; }
.up-fold[open] > summary .up-fold-chev { transform: rotate(180deg); }

/* ── Solid row-action buttons — ONE definition, app-wide ──────────────────────
   -UPMEDIK_PREREQ.md §7b: every button inside a table row / item-repeater is a
   SOLID fill with contrasting text. The fill hues live HERE, not in per-page
   class strings, because the first sweep mapped them onto the theme tokens
   (--teal 70% L, --rose 68% L) — pastel palette values meant for badges — and
   every Edit/Hapus button came out washed out. Buttons use the same 600-level
   strength as the approved accents (violet #7c3aed, export green #16a34a).

   Usage: class="up-btn-teal" (Edit) · "up-btn-amber" (Batal/Tolak) ·
   "up-btn-rose" (Hapus/destructive). Sizing/typography stays with the caller. */
.up-btn-teal  { background-color: #0d9488; color: #fff; }
.up-btn-amber { background-color: #d97706; color: #fff; }
.up-btn-rose  { background-color: #e11d48; color: #fff; }
.up-btn-teal:hover,
.up-btn-amber:hover,
.up-btn-rose:hover { opacity: .9; }

/* Workflow accent button (Approve / Mutasi / Proses RO) — same violet as the
   approved #7c3aed accent, solid per §7b. */
.up-btn-violet { background-color: #7c3aed; color: #fff; }
.up-btn-violet:hover { opacity: .9; }

/* ── THE button colour rule — three roles, three colours ─────────────────────
   Standing user decision (2026-08-29). Every button in the app is one of:

     1. AKSI      (Tambah / Edit / Simpan / Konfirmasi / Detail / Proses) → BIRU
                  class="upk-btn upk-btn-primary"
     2. CETAK     (PDF / Excel / CSV / Print)                             → HIJAU
                  class="upk-btn upk-btn-success"
     3. HAPUS /
        BATAL     (Hapus / Batal / Tolak / Reject)                        → MERAH
                  class="upk-btn upk-btn-danger"

   This SUPERSEDES the older per-hue mapping in -UPMEDIK_PREREQ.md §7b /
   DATATABLE_CONFIG §0.1 (Edit = teal, Batal = amber): Edit is an action, so it
   is blue, and Batal is a cancel, so it is red. up-btn-teal/amber survive only
   for the pages not yet swept.

   `upk-btn` carries the SIZE (padding/font/radius/inline-flex, erp-compat.css)
   and the variant carries only the fill — a colour class on its own renders as
   cramped unstyled text, which is what up-btn-teal did on the Aksi cells. */
.upk-btn-success { background-color: #16a34a; color: #fff; }
.upk-btn-success:hover { opacity: .9; }

/* ── Status badges / pills — SOLID by default, ONE definition ─────────────────
   Standing user decision (2026-08-10): EVERYTHING is solid unless the user
   explicitly asks for soft. The old `bg-<hue>/15 text-<hue>` badge tints made
   status chips look washed out / disabled. Same 600-level hues as the buttons;
   no hover (badges are not controls). */
.up-badge-emerald { background-color: #16a34a; color: #fff; }
.up-badge-amber   { background-color: #d97706; color: #fff; }
.up-badge-rose    { background-color: #e11d48; color: #fff; }
.up-badge-teal    { background-color: #0d9488; color: #fff; }
.up-badge-violet  { background-color: #7c3aed; color: #fff; }
.up-badge-muted   { background-color: #64748b; color: #fff; }

/* ==========================================================================
 * THE WORKSPACE SHELL — REGBAR + ACTIONBAR
 *
 * ONE definition, read by BOTH shells: /charts (_layouts/charts/shell_master.php)
 * and every main_master page that calls _shared/_workspace_shell.php. These rules
 * lived inline in shell_master's <style>, which meant a second page could copy
 * the markup and silently get none of the behaviour — the dense inline row, the
 * 2-line clamp, the phone collapse. Moved here so the region is one thing.
 *
 * Selectors are CLASSES (.hms-bio), not ids: a page may hold one of these, and
 * an id cannot be reused. shell_master's #hms-bio div carries the class too.
 * ========================================================================== */

/* ACTION BAR — plain TEXT actions, not buttons; hover turns blue. The bar is a
 * row of verbs separated by bullets, which is why nothing here has a fill: a row
 * of eight solid pills reads as eight competing primary actions. */
.actionbar-btn { background: none; border: 0; padding: 0; font: inherit; cursor: pointer; color: var(--muted-foreground); transition: color .15s; }
.actionbar-btn:hover { color: #2563eb; }
.actionbar-btn:disabled { opacity: .5; cursor: not-allowed; }

/* REGBAR biodata — the dense `Label : Value ·` run.
 * Base (mobile-first) is the label-over-value grid; the media queries below turn
 * it into the inline row. Driven here rather than with sm:/lg: utilities because
 * the base `grid`/`uppercase` classes would win the cascade. */
.hms-bio-toggle { display: none; }

/* PHONE (< 640): show ONLY the fields flagged `id` (ID Reg / ID Visit), laid out
 * INLINE ("ID Reg : 13486") rather than stacked, so the sticky bar cannot eat a
 * phone screen. The rest is reachable through the Reg Details button. */
@media (max-width: 639.98px) {
    .hms-bio .hms-bio-item:not(.hms-bio-id) { display: none; }
    .hms-bio > .hms-bio-sep { display: none; }          /* drop the bullet separators */
    .hms-bio { display: flex; flex-wrap: wrap; column-gap: .9rem; row-gap: .1rem; }
    .hms-bio .hms-bio-id { flex-direction: row; align-items: baseline; gap: .3rem; white-space: nowrap; }
    .hms-bio .hms-bio-id .hms-bio-label { text-transform: none; letter-spacing: normal; font-size: .72rem; }
    .hms-bio .hms-bio-id .hms-bio-sep { display: inline; }   /* the ":" after the label */
}

/* TABLET + DESKTOP (>= 640): the dense inline bullet row — fills the width,
 * never the sparse label-over-value grid. Clamped to ~2 lines; a page may reveal
 * a "Reg Details" control when it overflows. */
@media (min-width: 640px) {
    .hms-bio { display: flex; flex-wrap: wrap; align-items: center; column-gap: .5rem; row-gap: .25rem; }
    .hms-bio .hms-bio-item  { flex-direction: row; align-items: center; gap: .25rem; white-space: nowrap; flex: 0 0 auto; }
    .hms-bio .hms-bio-val   { overflow: visible; text-overflow: clip; }
    .hms-bio .hms-bio-sep   { display: inline; }
    .hms-bio .hms-bio-label { text-transform: none; letter-spacing: normal; font-size: .75rem; }
    .hms-bio.hms-bio-clamp  { max-height: 2.6rem; overflow: hidden; }  /* ~2 lines */
}

/* SIDE-PANE CHEVRON — the one collapse/expand control, on both shells.
 *
 * NO resting fill. It sits ON the dark pane, and a filled rounded square there
 * reads as a second, heavier UI element competing with the pane's own content;
 * /charts had `bg-sidepane-hover` baked in, which is why the same control looked
 * like two different buttons depending on which page you were on. The fill is
 * the HOVER state and nothing else — the chevron itself is the affordance.
 *
 * Direction is the state: "<" collapses, ">" re-opens. main_master flips one
 * glyph with scaleX(-1); /charts ships two buttons, one per state.
 */
.sidepane-chevron {
    display: grid; place-items: center; flex-shrink: 0;
    height: 1.5rem; width: 1.5rem;
    border-radius: .375rem;
    background: none; border: 0; padding: 0; cursor: pointer;
    color: var(--sidepane-muted);
    transition: background-color .12s ease, color .12s ease;
}
.sidepane-chevron:hover { background-color: var(--sidepane-hover); color: var(--sidepane-fg); }
.sidepane-chevron svg { height: 1rem; width: 1rem; }

/* ── A CARD INSIDE THE SIDE PANE, LIT BY WHICH ONE YOU ARE SHOWING ───────────
 * The pane itself stays dark. What decides a card's SURFACE is whether it is the
 * registration currently open in the content area — not whether it is still an
 * open visit:
 *
 *   SHOWN     — a LIGHT card. It is the one the whole right-hand side is about,
 *               so it steps forward off the dark pane.
 *   THE REST  — DARK cards. They recede into the pane's own tone and are read
 *               only when you go looking for them.
 *
 * AKTIF vs ARSIP is a different question and the badges already answer it: green
 * for a live registration, rose for a closed one, on either surface. Driving the
 * surface off the badge instead meant clicking SHOW on an archived visit lit up
 * everything EXCEPT the one you had just opened.
 *
 * Neither variant fights the pane's rules selector by selector. Each REDECLARES
 * the --sidepane-* tokens for its own subtree, so the layout's
 * `#app-sidebar .text-muted-foreground { color: var(--sidepane-muted) }` lands
 * on the page's muted grey inside a light card and on the pane's pale grey
 * inside a dark one. One rule, two surfaces, no specificity race — and it holds
 * under either shell, because it never names the pane's id.
 *
 * --border goes with them, so `border-border` (the card's own edge, and the
 * hairline down the visits list inside it) follows the surface it is drawn on
 * instead of cutting a light line across a dark card. `border-primary` is a
 * different token and survives, which is why the shown card keeps its blue edge.
 */
.ws-card {
    background-color: var(--ws-card-surface);
    color: var(--sidepane-fg);
}
/* THE ONE BEING SHOWN.
 *
 * A wash of primary over the card, not plain white: the light/dark split already
 * says which one this is, and the tint keeps it reading as the SELECTED card
 * rather than merely the pale one.
 *
 * sRGB, not oklch: --card is white, which is achromatic, and an oklch mix
 * interpolates its UNDEFINED hue toward 0 — the "6% blue" came out visibly pink.
 * sRGB has no hue to interpolate, so the tint is the primary. */
.ws-card[data-rail-current="1"] {
    --ws-card-surface: color-mix(in srgb, var(--primary) 6%, var(--card));
    --sidepane-fg:     var(--card-foreground);
    --sidepane-muted:  var(--muted-foreground);
    --sidepane-border: var(--border);
}
/* EVERY OTHER REGISTRATION. Lifted a few percent off the pane rather than set to
 * it exactly: at the pane's own colour the card is an outline with nothing in
 * it. */
.ws-card:not([data-rail-current="1"]) {
    --ws-card-surface: color-mix(in srgb, var(--sidepane-fg) 6%, var(--sidepane-bg));
    --border:          var(--sidepane-border);
}

/* ── Segmented option rows / state-flag buttons ───────────────────────────────
   "Pick one of these visible options" and "this button reflects a state"
   (filter chips, jenis diskon, produk golongan/kategori, mom kategori) used to
   ride on the bare-BOOTSTRAP .btn-primary / .btn-light-primary / .btn-success
   compat rules in erp-compat.css. Those are deleted (2026-09-16): they were the
   source of the washed-out amber/teal/pastel buttons the rest of the app had
   already moved off, and nothing but these toggles still referenced them.

   The JS toggles these class names with addClass/removeClass, so they are
   PLAIN CLASSES, not [data-active] like .up-select-pill — the pill group's
   attribute contract cannot be driven by addClass. Solid per THE LAW; the
   caller still supplies size/shape (h-7 px-2.5 rounded-md text-xs …). */
/* ═══════════════════════════════════════════════════════════════════════════
 * THE ONE BUTTON — read this before styling any button in ci_erp.
 * Standing user decision, 2026-09-16, after buttons came out different on
 * /inti_company, /master_data#data and /4030_hr_list/add three times running.
 *
 *   class="upk-btn upk-btn-primary"     AKSI    (Tambah/Edit/Simpan/Detail/Pilih)
 *   class="upk-btn upk-btn-success"     CETAK   (PDF/Excel/CSV/Print/Import)
 *   class="upk-btn upk-btn-danger"      HAPUS   (Hapus/Batal/Tolak)
 *   class="upk-btn upk-btn-outline"     neutral (Tutup on a modal footer)
 *   class="upk-btn upk-btn-ghost"       borderless (icon-less inline action)
 *
 * These FIVE are the only button classes in the app — 1304 call sites, nothing
 * else (2026-09-16 sweep). ONE token per role, so there is exactly one blue,
 * one red and one green sitewide:
 *     primary -> var(--primary)      (was var(--brand): a SECOND, darker blue,
 *                                     which is why /inti_company and /gudang
 *                                     visibly disagreed)
 *     danger  -> var(--destructive)
 *     success -> #16a34a
 *
 * RULES
 *   1. NEVER hand-roll a button class string in a view/controller/JS, and never
 *      copy one between pages. Two copies drift — that is exactly how this app
 *      ended up with three button geometries at once.
 *   2. NEVER add !px-*, !py-*, text-[11px], h-9, rounded-* or any size override
 *      to a button. If a size is genuinely needed, add a MODIFIER here.
 *   3. NEVER introduce a gradient, mesh or bevel on a button (see the deleted
 *      --btn-primary-mesh feature in erp-compat.css).
 *   4. The geometry lives in ONE rule — `.upk-btn` in erp-compat.css — and is
 *      deliberately the same shape as every input and card: radius var(--radius)
 *      (.4rem), min-height 2rem, padding 0 .75rem, 12px/500. It used to use
 *      --radius-sm (2.4px) which made every button look square next to its own
 *      form fields; that was the bug, in one line, on every page.
 *   5. Success feedback is NOT alert(). A success path reloads / refreshes the
 *      table, or uses upNotify. Keep alert() for errors only.
 * ═══════════════════════════════════════════════════════════════════════════ */


/* ═══════════════════════════════════════════════════════════════════════════
 * THE ONE PILL — read this before styling any pill/chip/segmented option.
 * Standing user decision, 2026-09-16 (same principle as THE ONE BUTTON above).
 *
 * The app had THREE pill looks at once:
 *   .up-select-pill  rounded-md (6.4px), 500  — filters (/gudang, _pill_group)
 *   .upk-chip        TWO rules fighting: compiled --radius-sm (2.4px, 600) and a
 *                    later 9999px stadium — form radio chips (/4030_hr_list/add)
 *   .up-seg          plain classes, no geometry — segmented JS toggles
 *
 * They are ONE control with three DRIVERS, so they share one visual definition
 * and differ only in how "selected" is set:
 *   [data-active]                 filters / _pill_group / _filter_select  (JS)
 *   input.btn-check:checked + …   form radio groups / _form_choice        (CSS sibling)
 *   .up-seg-on / .up-seg-done     addClass toggles in legacy page JS      (JS)
 *
 * Geometry lives HERE, not at the call site — a page must never add px-*, py-*,
 * rounded-*, text-[11px] or a second border to a pill. Reference look: the
 * /gudang filter pills.
 * ═══════════════════════════════════════════════════════════════════════════ */
.up-select-pill,
.upk-chip,
.up-seg, .up-seg-on, .up-seg-done {
    display: inline-flex; align-items: center; justify-content: center; gap: .375rem;
    min-height: 1.75rem; padding: 0 .75rem;
    border: 1px solid var(--border); border-radius: var(--radius);
    background: var(--card); color: var(--foreground);
    font-size: 12px; font-weight: 500; line-height: 1.25;
    white-space: nowrap; cursor: pointer; text-decoration: none;
    transition: background-color .15s, color .15s, border-color .15s;
}
.upk-chip-group { display: flex; flex-wrap: wrap; align-items: center; gap: .375rem; }
/* the radio input itself is hidden — the label IS the control */
.upk-chip-group .btn-check,
input.btn-check { position: absolute; clip: rect(0, 0, 0, 0); pointer-events: none; }

/* SELECTED — one blue, whichever driver set it */
.up-select-pill[data-active],
.up-select-pill[aria-pressed="true"],
.upk-chip.active,
.upk-chip[aria-pressed="true"],
.btn-check:checked + .upk-chip,
.up-seg-on {
    background: var(--primary); border-color: var(--primary); color: var(--primary-foreground);
}
/* the one green state a segmented row can carry (mom "selesai") */
.up-seg-done { background: #16a34a; border-color: #16a34a; color: #fff; }

/* Hover only on UNSELECTED — hovering the chosen pill must not look like a change */
.up-select-pill:not([data-active]):not([aria-pressed="true"]):hover,
.upk-chip:not(.active):not([aria-pressed="true"]):hover,
.up-seg:hover { border-color: var(--primary); color: var(--primary); }
.btn-check:focus-visible + .upk-chip,
.up-select-pill:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
