/* ============================================================================
 * 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.
 * ==========================================================================*/

/* ═══ MOVED 2026-09-25 → assets/ui_upmedik/css/upk.css (THE component kit,
   @layer components, _md/_docs/UI_KIT.md, APP_GEREJA_CMS_MIGRATION.md D22):
   .up-pill / .up-back · the .up-select-pill / .upk-chip / .up-seg pill ("THE ONE
   PILL") · .upk-btn-success and every other button colour · up-btn-* · up-badge-*
   · the <th> / .up-panel-head header band · @keyframes upk-spin · the
   ".upk-btn.hidden / .upk-input.hidden" guards (unneeded now: utilities beat the
   components layer, so `hidden` just works). Restyle a component THERE only. ═══ */


/* 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"] { 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; }

/* --------------------------------------------------------------------------
 * `.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; }
}


/* ── 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); }


/* ==========================================================================
 * 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);
}
