/* =========================================================================
   VF MARKET — DESIGN SYSTEM TOKENS (phase 11, "VF Market Design System" handoff)
   -------------------------------------------------------------------------
   One token set, two modes: light = :root, dark = html.dark-mode (RSMode).
   One theme (round 4b): these --vf-* tokens are the store look; html.dark-mode swaps them for dark --vf-*
   values only, so every component follows without page CSS.
   The older --rs-* tokens (themes.css) now resolve to these values.
   ========================================================================= */
/* P2-29 / phase 14: the metric-matched fallback faces and the font-family tokens live in themes.css. */
:root {
  /* colour — semantic */
  --vf-surface-1: #F4F5FA;          /* page background */
  --vf-surface-2: #FFFFFF;          /* cards, sheets, bars */
  --vf-surface-3: #EEEFF6;          /* inset fill, hover, chips, search */
  --vf-border: #E4E4EE;
  --vf-border-strong: #8A8AA2;      /* inputs, secondary buttons: >=3:1 boundary on surface */
  --vf-table-head: #F8F8FC;
  --vf-text-1: #1E1B4B;             /* headings, values */
  --vf-text-2: #5B5A72;             /* body, labels */
  --vf-text-3: #6E6D84;             /* hints, meta, placeholders */
  --vf-accent: #4B3FD6;
  --vf-accent-hover: #3B30B8;
  --vf-accent-text: #4B3FD6;        /* links, accent text on surfaces (≥ 4.5:1) */
  --vf-accent-subtle: #EEECFF;
  --vf-on-accent: #FFFFFF;
  --vf-tier-bronze: #B8733A; --vf-tier-silver: #9AA4B2; --vf-tier-gold: #D4A514;   /* member tier medals (admin + dashboard) */
  --vf-hero: #4B3FD6;               /* dashboard saldo header */
  --vf-hero-border: 0 solid transparent;
  --vf-hero-text: #FFFFFF;
  --vf-hero-muted: #DCD9FF;
  --vf-hero-accent: #D9D5FF;
  --vf-hero-chip: rgba(255, 255, 255, .16);
  --vf-hero-shadow: 0 12px 32px rgba(75, 63, 214, .28);
  --vf-navbg: color-mix(in srgb, var(--vf-surface-2) 84%, transparent);   /* follows the global theme (phase 13) */
  --vf-neutral: var(--vf-text-2);  --vf-neutral-subtle: var(--vf-surface-3);   /* Kedaluwarsa: not an error */
  --vf-success: #13795B;  --vf-success-subtle: #E3F6EE;
  --vf-warning: #8A5300;  --vf-warning-subtle: #FFF4DB;
  --vf-danger:  #C2303A;  --vf-danger-subtle:  #FDE8E9;
  --vf-info:    #1D5FC2;  --vf-info-subtle:    #E5F0FF;
  --vf-on-danger: #FFFFFF;
  --vf-on-success: #FFFFFF;
  /* fixed colours that must not follow themes: brand marks and QR codes (black on white so every scanner reads them) */
  --vf-brand-wa: #25D366;  --vf-on-brand-wa: #04140A;
  --vf-brand-tg: #29A9EA;
  --vf-e-up: 0 -4px 16px rgba(30, 27, 75, .06);   /* fixed bars above content (phase 13 token) */
  --vf-qr-bg: #FFFFFF;  --vf-qr-ink: #000000;  --vf-qr-size: clamp(220px, 62vw, 260px); /* P2-13: QR grows on 390/430 */
  /* controls drawn over photos (image viewer, carousel): always light on dark glass */
  --vf-media-bg: #000000;  --vf-on-media: #FFFFFF;  --vf-media-scrim: rgba(15, 17, 26, .55);
  --vf-scrim: rgba(30, 27, 75, .42);      /* popups: + blur 6px (Popups board) */
  --vf-scrim-solid: rgba(22, 18, 66, .62);
  --vf-focus: #4B3FD6;
  /* inverse surface: toast, tooltip */
  --vf-inverse: #1E1B4B;
  --vf-on-inverse: #FFFFFF;
  --vf-inverse-action: #C9C3FF;
  --vf-inverse-success: #5FE0B0;
  --vf-inverse-warning: #FFC56B;
  --vf-inverse-danger: #FF8A8F;
  /* wordmark glow (rgb triplet) */
  --vf-glow: 75, 63, 214;
  --vf-hero-glow: 217, 213, 255;
  /* banner / carousel control fill */
  --vf-ctl: rgba(255, 255, 255, .92);

  /* spacing — 8px scale */
  --vf-s-4: 4px; --vf-s-8: 8px; --vf-s-12: 12px; --vf-s-16: 16px; --vf-s-24: 24px;
  --vf-s-32: 32px; --vf-s-48: 48px; --vf-s-64: 64px;
  --vf-page-pad: 16px;
  --vf-card-pad: 16px;
  --vf-card-gap: 12px;
  --vf-inner-gap: 8px;
  --vf-pair-gap: 4px;
  --vf-grid-gap: 8px;               /* 3-column product grid (≤ 767) */
  --vf-hit: 48px;
  --vf-container: 1184px;

  /* type — phase 14: Outfit text + ALL headings, Inter numbers / badges / labels, Fugaz One ONLY for the store-name wordmark
     headline (families: themes.css). Phone values here, desktop (>= 1024) below. 12px floor. */
  /* Phase 14 type scale (Outfit unless noted; phone here, desktop >= 1024 below). Numbers use Inter (--vf-font-num). */
  --vf-t-display: 800 30px/36px var(--vf-font);
  --vf-t-h1: 700 22px/28px var(--vf-font);
  --vf-t-h2: 700 18px/26px var(--vf-font);
  --vf-t-h3: 600 16px/24px var(--vf-font);
  --vf-t-sec: 700 17px/24px var(--vf-font);
  --vf-t-saldo: 800 26px/32px var(--vf-font-num);
  --vf-t-price-lg: 800 22px/28px var(--vf-font-num);
  --vf-t-price-sm: 700 14px/20px var(--vf-font-num);
  --vf-t-code: 500 13px/18px var(--vf-font-mono);
  --vf-t-headline: var(--vf-t-h2);
  --vf-t-title: var(--vf-t-sec);
  --vf-t-title-sm: var(--vf-t-h3);
  --vf-t-body: 400 15px/22px var(--vf-font);
  --vf-t-body-sm: 400 14px/20px var(--vf-font);
  --vf-t-label: 500 13px/18px var(--vf-font);
  --vf-t-caption: 400 12px/16px var(--vf-font);
  /* Phase 13 (item 7) fixed UI type roles, retyped for phase 14. */
  --vf-t-caption-md: 500 12px/16px var(--vf-font);  --vf-t-caption-strong: 600 12px/16px var(--vf-font);
  --vf-t-small: 400 13px/18px var(--vf-font);  --vf-t-small-md: 500 13px/18px var(--vf-font);  --vf-t-small-strong: 600 13px/18px var(--vf-font);
  --vf-t-ui: 500 14px/20px var(--vf-font);  --vf-t-ui-strong: 600 14px/20px var(--vf-font);
  --vf-t-btn: 600 15px/22px var(--vf-font);  --vf-t-mono-sm: 500 12px/16px var(--vf-font-mono);
  --vf-t-card-title: 600 15px/22px var(--vf-font);  --vf-t-num-sm: 700 14px/20px var(--vf-font-num);
  --vf-t-small-loose: 400 13px/18px var(--vf-font);  --vf-t-body-lg: 400 16px/24px var(--vf-font);  --vf-t-code-sm: 500 13px/18px var(--vf-font-mono);
  /* Phase 14 roles: numbers, stat values, badges / chips, small uppercase labels (eyebrows). */
  --vf-t-num: 700 15px/22px var(--vf-font-num);
  --vf-t-stat: 800 18px/26px var(--vf-font-num);
  --vf-t-badge: 600 12px/16px var(--vf-font-num);
  --vf-t-eyebrow: 700 12px/16px var(--vf-font-num);
  --vf-eyebrow-track: .06em;
  --vf-top-h: 52px;  --vf-wm-size: 20px;
  --vf-ico-tile: 36px;  --vf-ico: 18px;  --vf-hero-pad: 16px;
  --vf-w-read: 100%;  --vf-w-form: 100%;  --vf-w-list: 100%;
  --vf-kv: minmax(0, 1fr);  --vf-kv-gap: 2px;  --vf-kv-row: 10px 0;

  /* radius — themes change card / control radius together */
  --vf-r-8: 8px; --vf-r-full: 999px;
  /* --vf-r-12, --vf-r-16, --vf-r-card (cards, popups) and --vf-r-ctl (buttons, inputs): one definition, further down */
  --vf-r-chip: 8px;    /* chips, badges, tooltip */

  /* elevation (light) */
  --vf-e0: 0 0 0 1px var(--vf-border);
  /* --vf-e1..e3 and --vf-card-border: one definition, further down */

  /* motion */
  --vf-dur-in: 200ms;  --vf-ease-in: cubic-bezier(.2, 0, 0, 1);
  --vf-dur-out: 150ms; --vf-ease-out: cubic-bezier(.4, 0, 1, 1);
  --vf-dur-press: 100ms;
}
html.dark-mode {
  --vf-e-up: 0 -4px 16px rgba(0, 0, 0, .35);
  --vf-surface-1: #0E0D17;
  --vf-surface-2: #171527;
  --vf-surface-3: #1E1C31;
  --vf-border: #24213A;
  --vf-border-strong: #6B6790;
  --vf-table-head: #1E1C31;
  --vf-text-1: #F4F3FF;
  --vf-text-2: #A3A1B8;
  --vf-text-3: #8D8AA6;
  --vf-accent: #6D5FF5;
  --vf-accent-hover: #7F72F7;
  --vf-accent-text: #B4ABFF;
  --vf-accent-subtle: #24204A;
  --vf-on-accent: #FFFFFF;
  --vf-hero: #2A2560;
  --vf-hero-border: 0 solid transparent;
  --vf-hero-text: #F4F3FF;
  --vf-hero-muted: #C9C3FF;
  --vf-hero-accent: #C9C3FF;
  --vf-hero-chip: rgba(255, 255, 255, .10);
  --vf-hero-shadow: none;
  --vf-navbg: color-mix(in srgb, var(--vf-surface-2) 84%, transparent);   /* follows the global theme (phase 13) */
  --vf-card-border: 1px solid #24213A;
  --vf-success: #5FE0B0;  --vf-success-subtle: #123B30;
  --vf-warning: #FFC56B;  --vf-warning-subtle: #3A2A0C;
  --vf-danger:  #FF8A8F;  --vf-danger-subtle:  #3D1418;
  --vf-info:    #8CB8FF;  --vf-info-subtle:    #132542;
  --vf-on-danger: #1A0505;
  --vf-on-success: #0A2A1E;
  --vf-scrim: rgba(5, 4, 12, .6);
  --vf-scrim-solid: rgba(5, 4, 20, .80);
  --vf-focus: #B4ABFF;
  --vf-inverse: #F4F3FF;
  --vf-on-inverse: #0E0D17;
  --vf-inverse-action: #4B3FD6;
  --vf-inverse-success: #13795B;
  --vf-inverse-warning: #8A5300;
  --vf-inverse-danger: #C2303A;
  --vf-glow: 139, 128, 251;
  --vf-hero-glow: 139, 128, 251;
  --vf-ctl: rgba(14, 13, 23, .72);
  /* dark: border + 1px top highlight instead of shadows */
  --vf-e0: 0 0 0 1px var(--vf-border);
  --vf-e1: none;
  --vf-e2: 0 8px 24px rgba(0, 0, 0, .35);
  --vf-e3: 0 0 0 1px var(--vf-border), 0 24px 64px rgba(0, 0, 0, .55);
  color-scheme: dark;
}
/* Phase 12 spacing: phone (< 1024) page 16 · section 24 · card 16 · grid 8; desktop page 32 · section 32 · card 24 · grid 16. */
:root { --vf-section-gap: 24px; }
@media (min-width: 1024px) {
  :root {
    --vf-section-gap: 32px; --vf-page-pad: 32px; --vf-card-pad: 24px; --vf-card-gap: 16px; --vf-inner-gap: 12px; --vf-grid-gap: 16px;
    --vf-t-display: 800 48px/56px var(--vf-font); --vf-t-h1: 700 32px/40px var(--vf-font); --vf-t-h2: 700 24px/30px var(--vf-font);
    --vf-t-h3: 600 18px/26px var(--vf-font); --vf-t-sec: 700 20px/28px var(--vf-font); --vf-t-saldo: 800 36px/44px var(--vf-font-num);
    --vf-t-price-lg: 800 28px/36px var(--vf-font-num); --vf-t-price-sm: 700 15px/22px var(--vf-font-num); --vf-t-code: 500 14px/20px var(--vf-font-mono);
    --vf-t-body: 400 16px/24px var(--vf-font); --vf-t-label: 500 14px/20px var(--vf-font); --vf-t-stat: 800 22px/28px var(--vf-font-num);
    --vf-top-h: 64px; --vf-wm-size: 20px; --vf-ico-tile: 40px; --vf-ico: 20px; --vf-hero-pad: 24px;
    --vf-w-read: 720px; --vf-w-form: 640px; --vf-w-list: 1200px;
    --vf-kv: 180px minmax(0, 1fr); --vf-kv-gap: 16px; --vf-kv-row: 12px 0;
  }
}

/* ===== GLOBAL THEMES — round 4: the store has ONE look, the default tokens above (light + html.dark-mode). The other
   themes (kertas, sakura, samudra; earlier arena, terminal, emas) were removed at the owner's request. ===== */
html[data-vf-dark-only] [data-rs-mode-toggle] { display: none !important; }

/* =========================================================================
   VF MARKET — SHARED UI LAYER
   -------------------------------------------------------------------------
   Built only on the tokens in /css/themes.css (load that first).
   Contains: base, focus, app shell (top bar, bottom nav, page layout) and the
   shared components used by customer and admin pages. Page-specific CSS
   should compose these classes instead of re-implementing them.

   Naming: .rs-<component>, .rs-<component>--<variant>, .rs-<component>__<part>
   ========================================================================= */

/* ---------- Base ---------- */
/* P0-01 (phase 11 mobile audit): pages without Bootstrap had content-box sizing, so sheets with padding were wider
   than the viewport and their close button was clipped. One rule for every element. */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  background-color: var(--vf-surface-1);
  /* Layered depth: a static, low-contrast indigo wash at the top of every page
     (themes.css --rs-page-bg). Follows light/dark and the admin global theme. */
  background-image: var(--rs-page-bg);
  background-repeat: no-repeat;
  line-height: var(--rs-lh);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img, svg, video { max-width: 100%; }
/* Form controls do not inherit the page font by default (Chrome renders <button> in Arial):
   one typeface everywhere (v9 F3). Zero specificity, so component rules still win. */
:where(button, input, select, textarea, optgroup) { font-family: inherit; }
/* ---------- System base (phase 9, task I) ----------
   Zero-specificity defaults so every element is on the scales without page CSS doing anything:
   - line height of every element = the pair of its font size (12→16 … 48→56, multiples of 4);
   - UA defaults that are off the scales (heading sizes/margins, 1em paragraph margins, 13.33px
     form controls, bold = 700) are replaced by tokens. Component rules still win. */
:where(*) { line-height: var(--rs-lh-auto); }
:where(body) { font-size: var(--rs-ts-sm); }
:where(button, input, select, textarea, optgroup) { font-size: var(--rs-ts-sm); }
:where(h1, h2, h3, h4, h5, h6, b, strong, th, dt, legend) { font-weight: var(--rs-fw-semibold); }
:where(h1, h2, h3, h4, h5, h6, p, ul, ol, dl, blockquote, figure, pre) { margin-block: 0; }
:where(p + p, p + ul, p + ol, ul + p, ol + p) { margin-top: var(--rs-s-16); }
/* Phase 14 type: headings Outfit 700 (h1 22/30 → 32/40, −0.02em; h2 18/26 → 24/32; h3 600 16/22 → 18/26), body Outfit 15/22 → 16/24. */
:where(h1) { font: var(--vf-t-h1); letter-spacing: -0.02em; }
:where(h2) { font: var(--vf-t-h2); }
:where(h3) { font: var(--vf-t-h3); }
:where(body) { font-family: var(--vf-font); }
:where(h4, h5, h6) { font-size: var(--rs-ts-sm); }
:where(small) { font-size: var(--rs-ts-caption); }
:where(ul, ol) { padding-inline-start: var(--rs-s-24); }
:where(fieldset) { margin: 0; padding: 0; border: 0; min-width: 0; }
:where(code, kbd, pre, samp) { font-family: var(--rs-font-mono); font-variant-numeric: tabular-nums; }
:root { --bs-font-sans-serif: var(--rs-font); --bs-body-font-family: var(--rs-font); --bs-font-monospace: var(--rs-font-mono); }
::selection { background: var(--vf-accent-subtle); color: var(--vf-text-1); }
h1, h2, .rs-page-title, .rs-section-title { text-wrap: balance; }
p { text-wrap: pretty; }
/* Everything clickable shows the pointer (skill checklist: cursor-pointer). */
:where(a[href], button:not(:disabled), summary, label[for], [role="button"], [role="tab"], select) { cursor: pointer; }
:where(button, a, [role="button"]) { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }

/* Dot texture on every page (AGENT v7): a fixed layer behind all content, fading toward the
   bottom of the viewport. Cards, tables and forms are solid surfaces above it, so text never
   sits on the pattern. Static (not animated). */
body::before { position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background-image: var(--rs-dot-pattern); background-size: var(--rs-dot-gap) var(--rs-dot-gap);
  -webkit-mask-image: linear-gradient(to bottom, var(--vf-text-1) 0, transparent 88%); mask-image: linear-gradient(to bottom, var(--vf-text-1) 0, transparent 88%);
}
/* Ambient loops pause when the tab is hidden (class set by global-theme.js). */
html.rs-tab-hidden *, html.rs-tab-hidden *::before, html.rs-tab-hidden *::after { animation-play-state: paused; }

/* One visible focus style for every interactive element (keyboard only). */
:where(a, button, input, select, textarea, summary, [tabindex], [role="button"]):focus-visible {
  /* primary-text is contrast-checked (>= 4.5:1) on every surface in every theme, so the
     ring stays visible even when a light global theme has a pale accent. */
  outline: 2px solid var(--vf-accent);
  outline-offset: 2px;
}
:where(input, select, textarea):focus-visible { outline-offset: 0; }

.rs-visually-hidden {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: 0;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
a.rs-visually-hidden:focus { top: 8px; left: 8px; z-index: var(--rs-z-toast, 1000); width: auto; height: auto; padding: 12px 16px; clip: auto; background: var(--vf-accent); color: var(--vf-on-accent); border-radius: 12px; }   /* skip link: visible when tabbed to */

.rs-nowrap { white-space: nowrap; }
.rs-muted { color: var(--vf-text-2); }
.rs-subtle { color: var(--vf-text-3); }

/* ---------- App shell: top bar ---------- */

/* The ONE element allowed a light blur (MASTER.md §1 L2): the sticky header, so the
   page wash shows through slightly while scrolling. Solid fallback without support. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .rs-topbar {
    background: color-mix(in srgb, var(--vf-surface-2) 84%, transparent);
    -webkit-backdrop-filter: saturate(1.5) blur(12px);
    backdrop-filter: saturate(1.5) blur(12px);
  }
}
.rs-topbar__inner {
  padding: 0 var(--vf-page-pad);
}
.rs-topbar__brand { gap: var(--rs-space-2);
  font-weight: var(--rs-fw-bold); font-size: var(--rs-fs-lg);
  letter-spacing: var(--rs-tracking-tight);
  color: var(--vf-text-1); white-space: nowrap;
}

.rs-topbar__brand:hover { color: var(--vf-text-1); }
/* Uploaded store logo: one height everywhere (AGENT C4), any aspect ratio kept. */
.rs-topbar__brand-logo { height: var(--rs-logo-h); width: auto; max-width: 120px; border-radius: var(--vf-r-chip); object-fit: contain; flex-shrink: 0; }
.rs-topbar__back { margin-left: calc(-1 * var(--rs-s-16)); } /* arrow glyph lines up with the page gutter */
.rs-topbar__title {
  font-size: var(--rs-fs-lg); font-weight: var(--rs-fw-semibold);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}

.rs-icon-btn {
  font-size: var(--rs-ts-base); line-height: var(--rs-lh-auto);
}
.rs-icon-btn { transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.rs-icon-btn--plain { border-color: transparent; background: transparent; }

.rs-balance {
  display: inline-flex; align-items: center; gap: var(--rs-space-2);
  height: 40px; padding: 0 var(--rs-s-4) 0 var(--rs-s-16);
  border: 1px solid var(--vf-border); border-radius: var(--vf-r-ctl);
  background: var(--vf-surface-2); color: var(--vf-text-1); text-decoration: none;
}
.rs-balance:hover { color: var(--vf-text-1); border-color: var(--vf-border-strong); }
.rs-balance { transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.rs-balance__text { display: flex; flex-direction: column; line-height: var(--rs-lh-auto); }
.rs-balance__label { font-size: var(--rs-fs-2xs); color: var(--vf-text-3); font-weight: var(--rs-fw-medium); text-transform: none; letter-spacing: var(--rs-tracking-caps); }
.rs-balance__amount { font-size: var(--rs-fs-md); font-weight: var(--rs-fw-bold); font-variant-numeric: tabular-nums; white-space: nowrap; }
.rs-balance__add {
  position: relative; width: 32px; height: 32px; border-radius: var(--vf-r-ctl);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--vf-accent); color: var(--vf-on-accent); font-size: var(--rs-ts-base);
}
/* Phones/tablets (< 1024px): top-up lives in the bottom navigation ("Deposit"), so the chip only shows
   the balance — one top-up control per screen (phase 9). Desktop keeps the "+" (no bottom nav there). */
/* (topbar.ejs renders a static chip below 1024px and the "+" link chip from 1024px.) */
.rs-balance--static { padding-right: var(--rs-s-16); cursor: default; }
.rs-balance--static:active { transform: none; }
@media (min-width: 1024px) { .rs-topbar__mob.rs-topbar__mob { display: none; } }
.rs-avatar {
  position: relative;
  width: 40px; height: 40px; border-radius: var(--rs-radius-full); flex-shrink: 0;
  overflow: hidden; display: inline-flex; align-items: center; justify-content: center;
  background: var(--vf-accent-subtle); color: var(--vf-accent-text);
  font-weight: var(--rs-fw-semibold); font-size: var(--rs-fs-md);
  border: 1px solid var(--vf-border); text-decoration: none;
}
.rs-avatar img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* Phones with the balance chip: the page title in the bar would be cut to "Sunti…" and the page
   repeats it as its H1 right below, so the bar keeps only the back arrow (v9 layout). */
@media (max-width: 479.98px) { .rs-topbar__inner:has(.rs-balance) .rs-topbar__title { display: none; } }
@media (max-width: 419.98px) {
  .rs-topbar__inner { gap: var(--rs-space-2); }
  .rs-topbar__hide-xs { display: none !important; }
  .rs-balance { padding-left: var(--rs-s-8); }
}

/* Desktop header (>= 1024px): search, category nav, history + theme toggle.
   Below 1024px these are hidden and the bottom navigation takes over. */
/* Doubled class on purpose: .vf-btn / .rs-icon-btn (declared later, same specificity) set display and
   used to win, so the desktop-only "Daftar" showed on phones (finding 7). */
.rs-topbar__search, .rs-topbar__cats, .rs-topbar__desk.rs-topbar__desk { display: none; }
/* R4 (phase 10): the wordmark is in the bar of every page, also next to a back arrow on phones;
   the short page title is then not repeated in the bar (the page's own H1 says it right below). */
.rs-topbar__title.rs-topbar__title { display: none; }
.rs-menu__desk-only { display: none; }
.rs-topbar__search { position: relative; flex: 1 1 auto; max-width: 520px; margin: 0 var(--rs-space-4); }
.rs-topbar__search > :is(.bi, .rs-icon) { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--vf-text-3); pointer-events: none; font-size: var(--rs-ts-base); }
.rs-topbar__search-input {
  width: 100%; height: 40px; padding: 0 var(--rs-s-16) 0 var(--rs-s-40);
  background: var(--vf-surface-3); color: var(--vf-text-1);
  border: 1px solid var(--vf-border); border-radius: var(--vf-r-ctl); font: inherit; line-height: var(--rs-lh-auto); font-size: var(--rs-fs-base);
}
.rs-topbar__search-input::placeholder { color: var(--vf-text-3); }
.rs-topbar__search-input:focus { outline: none; background: var(--vf-surface-2); border-color: var(--vf-accent); box-shadow: var(--rs-focus-ring); }
.rs-topbar__cats { border-top: 1px solid var(--vf-border); }
.rs-topbar__cats-inner { max-width: var(--rs-page-max); margin: 0 auto; padding: 0 var(--vf-page-pad); display: flex; gap: var(--rs-space-1); overflow-x: auto; scrollbar-width: none; }
.rs-topbar__cats a {
  flex: 0 0 auto; display: inline-flex; align-items: center; min-height: 40px; padding: 0 var(--rs-space-3);
  color: var(--vf-text-2); font-size: var(--rs-fs-md); font-weight: var(--rs-fw-medium); text-decoration: none;
  border-bottom: 2px solid transparent;
}
.rs-topbar__cats a:first-child { margin-left: calc(-1 * var(--rs-space-3)); }
.rs-topbar__cats a:hover { color: var(--vf-text-1); }
.rs-topbar__cats a[aria-current="page"] { color: var(--vf-accent-text); border-bottom-color: var(--vf-accent); }
@media (min-width: 1024px) {
  .rs-topbar__search { display: block; }
  .rs-topbar__cats { display: block; }
  .rs-topbar__desk.rs-topbar__desk { display: inline-flex; }
  .rs-menu__desk-only { display: block; }
  /* The dashboard has its own category tabs right under the heading: no second category row there. */
  .rs-topbar--no-cats .rs-topbar__cats { display: none; }
  .rs-topbar__back, .rs-topbar__title { display: none; }
  .rs-topbar__brand--desk { display: inline-flex; }
  .rs-bottomnav { display: none; }
  html body.rs-has-bottomnav { padding-bottom: 0; }
}

/* ---------- App shell: site menu (topbar "Menu" sheet) ---------- */
.rs-menu {
  margin: 0 0 0 auto; padding: 0; border: 0;
  width: min(320px, 88vw); max-width: none; height: 100dvh; max-height: none;
  background: var(--vf-surface-2); color: var(--vf-text-1);
  border-left: 1px solid var(--vf-border);
  box-shadow: var(--vf-e3);
}
.rs-menu::backdrop { background: var(--rs-overlay); }
.rs-menu__panel { display: flex; flex-direction: column; min-height: 100%; }
.rs-menu__head {
  display: flex; align-items: center; justify-content: space-between;
  min-height: var(--rs-topbar-h); padding: 0 var(--rs-space-2) 0 var(--rs-space-4);
  border-bottom: 1px solid var(--vf-border);
}
.rs-menu__title { font-weight: var(--rs-fw-semibold); font-size: var(--rs-fs-lg); }
.rs-menu__account { padding: var(--rs-space-3) var(--rs-space-4); border-bottom: 1px solid var(--vf-border); display: flex; flex-direction: column; gap: var(--rs-s-4); }
.rs-menu__name { font-weight: var(--rs-fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rs-menu__meta { font-size: var(--rs-fs-sm); color: var(--vf-text-2); font-variant-numeric: tabular-nums; }
/* Sentence case like the rest of the site (AGENT C1). */
.rs-menu__group { margin: var(--rs-space-4) var(--rs-space-4) var(--rs-space-1); font-size: var(--rs-fs-sm); font-weight: var(--rs-fw-semibold); color: var(--vf-text-3); }
.rs-menu__list { list-style: none; margin: 0; padding: 0 var(--rs-space-2); display: flex; flex-direction: column; gap: var(--rs-s-4); }
.rs-menu__item {
  display: flex; align-items: center; gap: var(--rs-space-3); width: 100%;
  min-height: var(--rs-control-h); padding: 0 var(--rs-space-3);
  border: 0; border-radius: var(--vf-r-ctl); background: transparent;
  color: var(--vf-text-1); text-decoration: none; text-align: left;
  font: inherit; line-height: var(--rs-lh-auto); font-weight: var(--rs-fw-medium); cursor: pointer;
}
.rs-menu__item :is(.bi, .rs-icon) { color: var(--vf-text-2); font-size: var(--rs-ts-base); width: 20px; text-align: center; flex-shrink: 0; }
.rs-menu__item:hover { background: var(--rs-surface-hover); color: var(--vf-text-1); }
.rs-menu__item[aria-current="page"] { background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
.rs-menu__item[aria-current="page"] :is(.bi, .rs-icon) { color: var(--vf-accent-text); }
.rs-menu__item[aria-pressed="true"] :is(.bi, .rs-icon) { color: var(--vf-accent-text); }
.rs-switch {
  position: relative; margin-left: auto; flex-shrink: 0; width: 36px; height: 20px;
  border-radius: var(--rs-radius-full); background: var(--vf-border-strong);
}
.rs-switch::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: var(--rs-radius-full); background: var(--vf-surface-2); box-shadow: var(--vf-e1);
  transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
[aria-pressed="true"] > .rs-switch { background: var(--vf-accent); }
[aria-pressed="true"] > .rs-switch::after { transform: translateX(16px); }
.rs-menu__hint { margin-left: auto; white-space: nowrap; font-size: var(--rs-fs-sm); font-weight: var(--rs-fw-regular); color: var(--vf-text-3); }
.rs-menu__hint + .rs-switch { margin-left: var(--rs-space-2); }
.rs-menu__foot { margin-top: auto; padding: var(--rs-space-3) var(--rs-space-4) calc(var(--rs-space-4) + env(safe-area-inset-bottom)); border-top: 1px solid var(--vf-border); display: flex; flex-direction: column; gap: var(--rs-space-2); }
.rs-menu__logout { color: var(--vf-danger); }
.rs-menu__logout:hover { color: var(--vf-danger); }
/* The avatar is desktop-only (phones: "Profil" in the bottom navigation). */

/* ---------- App shell: bottom navigation ---------- */
.rs-bottomnav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--rs-z-nav);
  background: var(--vf-surface-2);
  border-top: 1px solid var(--vf-border);
  padding-bottom: env(safe-area-inset-bottom, 0);
}
.rs-bottomnav__inner {
  max-width: 560px; margin: 0 auto; height: var(--rs-bottomnav-h);
  display: grid; grid-template-columns: repeat(5, 1fr);
}
.rs-bottomnav__item {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--rs-s-4);
  min-height: var(--rs-hit); padding: 0; margin: 0; border: 0; background: none;
  color: var(--vf-text-3); text-decoration: none; cursor: pointer;
  font: inherit; line-height: var(--rs-lh-auto); font-size: var(--rs-fs-2xs); font-weight: var(--rs-fw-medium);
}
.rs-bottomnav__item :is(.bi, .rs-icon) { font-size: var(--rs-ts-xl); line-height: var(--rs-lh-auto); }
.rs-bottomnav__item:hover { color: var(--vf-text-1); }
.rs-bottomnav__item[aria-current="page"] { color: var(--vf-accent-text); font-weight: var(--rs-fw-semibold); }

/* ---------- Page layout ---------- */
.rs-page { max-width: var(--rs-page-max); margin: 0 auto; padding: var(--rs-space-5) var(--vf-page-pad) var(--rs-space-6); }
.rs-page--narrow { max-width: var(--rs-page-narrow); }
.rs-page-head { display: flex; align-items: flex-start; gap: var(--rs-space-3); margin-bottom: var(--rs-space-5); }
.rs-page-head__text { min-width: 0; flex: 1; }
.rs-page-title { margin: 0; font-size: var(--rs-ts-2xl); line-height: var(--rs-lh-auto); font-weight: var(--rs-fw-semibold); letter-spacing: var(--rs-tracking-display); color: var(--vf-text-1); }
@media (min-width: 1024px) { .rs-page-title { font-size: var(--rs-ts-3xl); } }
.rs-page-sub { margin: var(--rs-space-1) 0 0; font-size: var(--rs-fs-base); color: var(--vf-text-2); }
.rs-page-head__actions { display: flex; gap: var(--rs-space-2); flex-shrink: 0; }
@media (max-width: 575.98px) {
  .rs-page { padding: var(--rs-space-4) var(--vf-page-pad) var(--rs-space-5); }
  .rs-page-title { font-size: var(--rs-ts-2xl); }
}

.rs-section { margin-top: var(--vf-section-gap); }
/* Anchor jumps (#semua-produk, #faq …) land below the sticky header, never under it. */
html { scroll-padding-top: calc(var(--rs-header-h) + var(--rs-space-3)); }
.rs-section:first-child { margin-top: 0; }
.rs-section-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--rs-space-3); margin-bottom: var(--rs-space-3); }
.rs-section-head .rs-section-link { flex-shrink: 0; }
/* Links/controls in a heading row must not make the row taller than the heading (a var(--rs-hit)
   link baseline-aligned to a 25px title pushed the title down 6–10px and broke the section
   rhythm, AGENT G4/S5). The var(--rs-hit) target is kept by an invisible ::before. */
.rs-section-link { position: relative; }
.rs-section-link::before { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: var(--rs-hit); transform: translateY(-50%); }
/* One section-heading size everywhere (AGENT S5): 20px / 24px >= 1024 via --rs-fs-section;
   the count is muted text, a "Lihat semua" link sits right on the same baseline. */
.rs-section-title { margin: 0; font-size: var(--rs-fs-section); font-weight: var(--rs-fw-bold); letter-spacing: 0; line-height: var(--rs-lh-tight); color: var(--vf-text-1); }
.rs-section-count { font-size: var(--rs-fs-base); font-weight: var(--rs-fw-medium); color: var(--vf-text-3); font-variant-numeric: tabular-nums; margin-left: var(--rs-s-4); letter-spacing: 0; }
.rs-section-link { font-size: var(--rs-fs-md); color: var(--vf-accent-text); text-decoration: none; font-weight: var(--rs-fw-medium); }
.rs-eyebrow { font-size: var(--rs-fs-xs); font-weight: var(--rs-fw-semibold); letter-spacing: var(--rs-tracking-caps); text-transform: none; color: var(--vf-text-3); }

/* ---------- Card ---------- */

.rs-card--muted { background: var(--vf-surface-3); box-shadow: none; }
.rs-card--raised { background: var(--rs-surface-elevated); box-shadow: var(--vf-e2); }
.rs-card--lg { padding: var(--rs-space-5); }

.rs-card__head { display: flex; align-items: center; justify-content: space-between; gap: var(--rs-space-3); margin-bottom: var(--rs-space-3); }
.rs-card__title { margin: 0; font-size: var(--rs-fs-base); font-weight: var(--rs-fw-semibold); color: var(--vf-text-1); }
.rs-divider { height: 1px; background: var(--vf-border); border: 0; margin: var(--rs-space-4) 0; }

/* ---------- Buttons ---------- */
.vf-btn { line-height: var(--rs-lh-auto); font-size: var(--rs-ts-sm); font-weight: var(--rs-fw-medium); line-height: var(--rs-lh-auto);
}
.vf-btn .bi { font-size: var(--rs-icon-16); line-height: var(--rs-lh-auto); }
/* Pressed: a small scale (transform only), released instantly on pointer up. */

.vf-btn--primary:active { color: var(--vf-on-accent); }

.vf-btn--secondary:active { background: var(--vf-surface-3); }

.vf-btn--tonal:hover { background: color-mix(in srgb, var(--vf-accent-subtle) 70%, var(--vf-accent) 12%); }

.vf-btn--danger-outline { border-color: var(--rs-danger-border); }

.vf-btn--sm { font-size: var(--rs-ts-sm); }
.vf-btn:disabled, a.vf-btn[aria-disabled="true"] { pointer-events: none; }   /* round 2: a <button aria-disabled> stays tappable so it can explain what is missing */
/* Loading: set aria-busy="true" (and disabled) while a request runs. The label stays in
   the DOM for screen readers; a spinner replaces it visually. */

.vf-btn[aria-busy="true"]::after { left: 50%; top: 50%;
}

.vf-btn--secondary[aria-busy="true"], .vf-btn--ghost[aria-busy="true"], .vf-btn--tonal[aria-busy="true"] { --rs-btn-spin: var(--vf-text-2); }
/* Success feedback after an action (e.g. "Tersalin"): brief, colour + icon + text. */
.vf-btn.is-success { box-shadow: none; }
@media (pointer: coarse) {
  .vf-btn--sm, .btn { min-height: var(--rs-control-h); }
  .rs-icon-btn, .rs-avatar, .rs-mode-toggle { width: var(--rs-hit); height: var(--rs-hit); }
  .rs-balance { height: var(--rs-hit); }
}

/* ---------- Form fields ---------- */
.rs-field { margin-bottom: var(--rs-space-4); }
.rs-label { font-size: var(--rs-ts-sm); font-weight: var(--rs-fw-medium); }
.rs-help { font-size: var(--rs-fs-sm); }
.rs-error { font-size: var(--rs-fs-sm); }
.rs-input, .rs-select, .rs-textarea { line-height: var(--rs-lh-auto); font-size: var(--rs-fs-lg); /* 16px: no iOS zoom on focus */
}
.rs-textarea { resize: vertical; }

.rs-input:hover:not(:focus):not(:disabled), .rs-select:hover:not(:focus):not(:disabled), .rs-textarea:hover:not(:focus):not(:disabled) { border-color: var(--vf-text-3); }

.rs-input[aria-invalid="true"]:focus { box-shadow: 0 0 0 3px color-mix(in srgb, var(--vf-danger) 25%, transparent); }
.rs-input:disabled, .rs-select:disabled, .rs-textarea:disabled { background: var(--vf-surface-3); color: var(--vf-text-3); cursor: not-allowed; }
.rs-input[readonly] { background: var(--vf-surface-3); }
.rs-success-text { font-size: var(--rs-fs-sm); color: var(--vf-success); }
@media (min-width: 768px) and (pointer: fine) {
  .rs-input, .rs-select, .rs-textarea { font-size: var(--rs-fs-base); }
}
.rs-input-group { position: relative; display: flex; align-items: stretch; }
.rs-input-group__addon {
  display: inline-flex; align-items: center; padding: 0 var(--rs-s-16);
  border: 1px solid var(--vf-border-strong); border-right: 0;
  border-radius: var(--vf-r-ctl) 0 0 var(--vf-r-ctl);
  background: var(--vf-surface-3); color: var(--vf-text-2); font-weight: var(--rs-fw-semibold);
}
.rs-input-group__addon + .rs-input { border-radius: 0 var(--vf-r-ctl) var(--vf-r-ctl) 0; }

/* ---------- Badge (status) ---------- */
.rs-badge {
  font-size: var(--rs-fs-xs); font-weight: var(--rs-fw-semibold); line-height: var(--rs-lh-auto);
}
.rs-badge--success { border-color: var(--rs-success-border); }
.rs-badge--warning { border-color: var(--rs-warning-border); }
.rs-badge--danger {  border-color: var(--rs-danger-border); }
.rs-badge--info {    border-color: var(--rs-info-border); }
.rs-dot { width: 6px; height: 6px; border-radius: var(--rs-radius-full); background: currentColor; display: inline-block; }

/* ---------- Alert ---------- */
.rs-alert {
  display: flex; gap: var(--rs-space-3); align-items: flex-start;
  padding: var(--rs-space-3) var(--rs-space-4);
  border: 1px solid var(--vf-border); border-radius: var(--vf-r-card);
  background: var(--vf-surface-3); color: var(--vf-text-1);
  font-size: var(--rs-fs-base);
}
.rs-alert > .bi { font-size: var(--rs-ts-base); line-height: var(--rs-lh-auto); flex-shrink: 0; }
.rs-alert__title { font-weight: var(--rs-fw-semibold); margin: 0 0 var(--rs-s-4); }
.rs-alert__body { color: var(--vf-text-2); margin: 0; }
.rs-alert--success { background: var(--vf-success-subtle); border-color: var(--rs-success-border); }
.rs-alert--success > .bi { color: var(--vf-success); }
.rs-alert--warning { background: var(--vf-warning-subtle); border-color: var(--rs-warning-border); }
.rs-alert--warning > .bi { color: var(--vf-warning); }
.rs-alert--danger  { background: var(--vf-danger-subtle);  border-color: var(--rs-danger-border); }
.rs-alert--danger > .bi { color: var(--vf-danger); }
.rs-alert--info    { background: var(--vf-info-subtle);    border-color: var(--rs-info-border); }
.rs-alert--info > .bi { color: var(--vf-info); }

/* ---------- Segmented control / filter tabs ---------- */
.rs-seg {
  display: flex; gap: var(--rs-space-1); overflow-x: auto; scrollbar-width: none;
  padding: var(--rs-s-4); border-radius: var(--vf-r-ctl);
  background: var(--vf-surface-3); border: 1px solid var(--vf-border);
}
.rs-seg::-webkit-scrollbar { display: none; }
/* Edge fade where more tabs are hidden (classes set by global-theme.js, AGENT C2). */
.rs-seg.is-more-end { -webkit-mask-image: linear-gradient(90deg, var(--vf-text-1) calc(100% - 32px), transparent); mask-image: linear-gradient(90deg, var(--vf-text-1) calc(100% - 32px), transparent); }
.rs-seg.is-more-start { -webkit-mask-image: linear-gradient(90deg, transparent, var(--vf-text-1) 32px); mask-image: linear-gradient(90deg, transparent, var(--vf-text-1) 32px); }
.rs-seg.is-more-start.is-more-end { -webkit-mask-image: linear-gradient(90deg, transparent, var(--vf-text-1) 32px, var(--vf-text-1) calc(100% - 32px), transparent); mask-image: linear-gradient(90deg, transparent, var(--vf-text-1) 32px, var(--vf-text-1) calc(100% - 32px), transparent); }
.rs-seg__item {
  position: relative; isolation: isolate;
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: var(--rs-s-8);
  min-height: 36px; padding: 0 var(--rs-s-16); border-radius: var(--vf-r-ctl); border: 0;
  background: transparent; color: var(--vf-text-2);
  font: inherit; line-height: var(--rs-lh-auto); font-size: var(--rs-fs-md); font-weight: var(--rs-fw-medium);
  text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
/* Selected pill: a layer that fades/scales in (opacity + transform), so a rapid
   sequence of taps simply retargets; the final state is set by the attribute. */
.rs-seg__item::before {
  content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  background: var(--vf-surface-2); box-shadow: var(--vf-e1);
  opacity: 0; transform: scale(0.9);
  transition: opacity var(--vf-dur, 140ms) var(--vf-ease, ease-out), transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
.rs-seg__item:hover { color: var(--vf-text-1); }
.rs-seg__item[aria-selected="true"], .rs-seg__item[aria-pressed="true"], .rs-seg__item.is-active, .rs-seg__item[aria-current="page"] {
  color: var(--vf-text-1); font-weight: var(--rs-fw-semibold);
}
.rs-seg__item[aria-selected="true"]::before, .rs-seg__item[aria-pressed="true"]::before, .rs-seg__item.is-active::before, .rs-seg__item[aria-current="page"]::before {
  opacity: 1; transform: none;
}
.rs-seg__count { font-size: var(--rs-fs-2xs); color: var(--vf-text-3); font-variant-numeric: tabular-nums; }
@media (pointer: coarse) { .rs-seg__item { min-height: var(--rs-hit); } }

/* ---------- Step indicator (checkout flows: deposit) ---------- */
.rs-steps { counter-reset: none; }
.rs-steps__item { flex: 1 1 0; align-items: center; padding-bottom: var(--rs-space-2); border-bottom: 2px solid var(--vf-border); font-size: var(--rs-fs-md); font-weight: var(--rs-fw-medium); }
.rs-steps__num { width: 22px; height: 22px; flex-shrink: 0; align-items: center; justify-content: center; border-radius: var(--rs-radius-full); border: 1px solid var(--vf-border-strong); font-size: var(--rs-fs-xs); font-weight: var(--rs-fw-semibold); font-variant-numeric: tabular-nums; }
.rs-steps__label { text-overflow: ellipsis; }
.rs-steps__item[aria-current="step"] { border-bottom-color: var(--vf-accent); }
.rs-steps__item[aria-current="step"] .rs-steps__num { background: var(--vf-accent); border-color: var(--vf-accent); color: var(--vf-on-accent); }
.rs-steps__item.is-done { border-bottom-color: var(--vf-accent-subtle); }
.rs-steps__item.is-done .rs-steps__num { background: var(--vf-accent-subtle); border-color: var(--vf-accent-subtle); color: var(--vf-accent-text); }

/* ---------- Collapsible section ---------- */
.rs-collapse { border: 1px solid var(--vf-border); border-radius: var(--vf-r-ctl); background: var(--vf-surface-3); }
.rs-collapse__head { width: 100%; min-height: var(--rs-control-h); display: flex; align-items: center; justify-content: space-between; gap: var(--rs-space-3); padding: 0 var(--rs-space-3); border: 0; background: none; color: var(--vf-text-1); font: inherit; line-height: var(--rs-lh-auto); font-size: var(--rs-fs-base); font-weight: var(--rs-fw-semibold); text-align: left; cursor: pointer; }
.rs-collapse__head .bi:first-child { color: var(--vf-text-2); margin-right: var(--rs-s-8); }
.rs-collapse__chev { color: var(--vf-text-2); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.rs-collapse__head[aria-expanded="true"] .rs-collapse__chev { transform: rotate(180deg); }
.rs-collapse__body { padding: 0 var(--rs-space-3) var(--rs-space-3); }

/* Invalid-input nudge (state change only; skipped with reduced motion) */

/* ---------- Key/value rows (order summaries) ---------- */
.rs-kv { display: flex; flex-direction: column; }
.rs-kv__row { display: flex; justify-content: space-between; gap: var(--rs-space-4); padding: var(--rs-s-8) 0; border-bottom: 1px solid var(--vf-border); font-size: var(--rs-fs-base); }
.rs-kv__row:last-child { border-bottom: 0; }
.rs-kv__key { color: var(--vf-text-2); }
.rs-kv__val { color: var(--vf-text-1); font-weight: var(--rs-fw-semibold); text-align: right; font-variant-numeric: tabular-nums; word-break: break-word; }
.rs-kv__row--total .rs-kv__key { color: var(--vf-text-1); font-weight: var(--rs-fw-semibold); }
.rs-kv__row--total .rs-kv__val { font-size: var(--rs-fs-lg); font-weight: var(--rs-fw-bold); }

/* ---------- Price ---------- */
.rs-price { font-weight: var(--rs-fw-bold); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
.rs-price__was { font-size: var(--rs-fs-sm); color: var(--vf-text-3); text-decoration: line-through; font-weight: var(--rs-fw-regular); margin-left: var(--rs-s-8); }
.rs-price__off { font-size: var(--rs-fs-xs); color: var(--vf-danger); font-weight: var(--rs-fw-semibold); margin-left: var(--rs-s-8); }

/* ---------- Table ---------- */
.rs-table-wrap { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; border: 1px solid var(--vf-border); border-radius: var(--vf-r-card); background: var(--vf-surface-2); }
.rs-table { width: 100%; border-collapse: collapse; font-size: var(--rs-fs-md); }
.rs-table th { position: sticky; top: 0; background: var(--vf-surface-3); color: var(--vf-text-2); font-size: var(--rs-fs-xs); font-weight: var(--rs-fw-semibold); text-transform: none; letter-spacing: var(--rs-tracking-caps); text-align: left; padding: var(--rs-s-8) var(--rs-s-16); border-bottom: 1px solid var(--vf-border); white-space: nowrap; }
.rs-table td { padding: var(--rs-s-16); border-bottom: 1px solid var(--vf-border); color: var(--vf-text-1); vertical-align: middle; }
.rs-table tr:last-child td { border-bottom: 0; }
.rs-table tbody tr:hover td { background: var(--rs-surface-hover); }
.rs-table .rs-num, .rs-table td.is-num { text-align: right; font-variant-numeric: tabular-nums; }

/* ---------- Product grid + card (MASTER.md §7, Task C) ----------
   ONE grid for every product list. The same tokens drive the flat grid (.rs-product-grid), each
   dashboard category section (.rs-catgroup, heading on its own row) and the carousel rows
   (.rs-hscroll), so a card has the same width everywhere:
     --pg-cols  3 at every width (owner, phase 9)
     --pg-gap   8px below 768px · 16px from 768px · 24px from 1180px (task I)
   The page container keeps its max width (--rs-page-max). A short last row stays left-aligned.
   Tabs/search only toggle [hidden] on cards and sections. */
/* Phase 18: columns are admin-chosen per breakpoint — --pg-cols-m on phones, --pg-cols-d ≥ 768 px (set on :root by the
   inline app.locals.cardGridStyle; the var() fallbacks keep the default 3 / 3). The track width is the LARGER of a
   minimum card width (--pg-floor) and the target card width for THIS container; with auto-fill that gives exactly the
   chosen number of columns when they fit, and fewer (never narrower than the floor) when the container is too narrow
   — so a high column count can never look cramped, and a narrow region (e.g. the dashboard beside its sidebar) simply
   shows fewer columns. --pg-floor: 148 px on phones (2 columns at 360-480 px), 150 px on desktop. */
.rs-product-grid, .rs-catflow, .rs-catgroup, .rs-hscroll, .vf-pgrid { --pg-cols: var(--pg-cols-m, 3); --pg-gap: var(--rs-s-8); --pg-floor: 148px; }
@media (min-width: 768px) { .rs-product-grid, .rs-catflow, .rs-catgroup, .rs-hscroll, .vf-pgrid { --pg-cols: var(--pg-cols-d, 3); --pg-gap: var(--rs-s-16); --pg-floor: 150px; } }
@media (min-width: 1180px) { .rs-product-grid, .rs-catflow, .rs-catgroup, .rs-hscroll { --pg-gap: var(--rs-s-24); } }
.rs-product-grid, .rs-catgroup {
  display: grid;
  --pg-track: max(var(--pg-floor), (100% - (var(--pg-cols) - 1) * var(--pg-gap)) / var(--pg-cols) - 0.5px);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--pg-track)), 1fr));
  gap: var(--pg-gap);
  align-items: stretch;   /* equal heights per row; the fixed card slots keep the content aligned */
  min-width: 0;
}
/* R1 (phase 10) — one row utility for every non-product multi-column group (replaces the phase-9
   "stretch the leftovers" rule): N items per row at equal width, flex-basis
   calc((100% - (N-1) x gap) / N); a short last row keeps that width and is CENTRED as a group
   (1 leftover in a 3-column group sits in the middle, 2 sit centred side by side). Items in a row
   share one height. --fill-n / --fill-gap / --fill-row-gap per group. No nth-child spans.
   .rs-fill--stretch keeps the old fill behaviour, only where centring would look wrong
   (form controls / filters / option pickers and key-value detail grids — listed in CHANGES R1). */
.rs-fill.rs-fill { display: flex; flex-wrap: wrap; justify-content: center; align-items: stretch; column-gap: var(--fill-gap, var(--rs-s-8)); row-gap: var(--fill-row-gap, var(--fill-gap, var(--rs-s-8))); }
.rs-fill.rs-fill > * { flex: 0 1 calc((100% - (var(--fill-n, 2) - 1) * var(--fill-gap, var(--rs-s-8))) / var(--fill-n, 2)); min-width: 0; grid-column: auto; }
.rs-fill.rs-fill--stretch > * { flex-grow: 1; }
.rs-fill.rs-fill > * :where(p, li, .rs-help) { max-width: 65ch; }
.rs-fill.rs-fill > * :where(.vf-btn:not(.vf-btn--block)) { flex-grow: 0; width: auto; }
.rs-catgroup__head, .rs-product-grid > .rs-grid-span, .rs-catgroup > .rs-grid-span { grid-column: 1 / -1; }
/* Dashboard "Semua produk": category sections stacked with one rhythm. */
.rs-catflow { display: flex; flex-direction: column; gap: var(--rs-s-32); min-width: 0; }
.rs-product-grid > [hidden], .rs-catgroup > [hidden], .rs-catflow > [hidden] { display: none !important; }
/* Press: the card gives way (0.97, --vf-dur-press 100ms) — unless the press is on one of its buttons. */
/* Media corners: rank top-left · quick view top-right · flag bottom-left. */
/* Flags sit on product art: the tint is layered over an opaque surface so the text keeps its
   contrast on any image in both modes (dark danger-bg alone is 12% alpha). */
/* Unavailable (sold out / coming soon): clearly muted, still tidy. */

/* Quick view: a round eye in the media's top-right corner — 32px visual (36px >= 768),
   var(--rs-hit) hit area, above the card link. */
.vf-pcard__qv {
  position: absolute; z-index: 3; top: var(--pc-inset, 8px); right: var(--pc-inset, 8px);
  width: var(--pc-qv, 32px); height: var(--pc-qv, 32px); padding: 0; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--rs-radius-full); border: 1px solid var(--vf-border);
  background: color-mix(in srgb, var(--vf-surface-2) 92%, transparent); color: var(--vf-text-1);
  box-shadow: var(--vf-e1); font-size: var(--rs-icon-16); cursor: pointer;
  transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
.vf-pcard__qv::before { content: ''; position: absolute; left: 50%; top: 50%; width: var(--rs-hit); height: var(--rs-hit); margin: calc(-1 * var(--rs-s-24)) 0 0 calc(-1 * var(--rs-s-24)); border-radius: var(--rs-radius-full); }
.vf-pcard__qv:hover { background: var(--vf-surface-2); color: var(--vf-accent-text); }
.vf-pcard__qv:focus-visible { outline: 2px solid var(--vf-accent-text); outline-offset: 2px; }

/* Card body: four fixed slots, fixed rhythm, no auto margins (Task C), on the type scale (task I).
   Phone (< 768): title caption 12/16 w500 (2 lines = 32px) · meta caption · price sm 14/20 w600 ·
   "Mulai"/struck price caption · stock caption · 8px padding · 4px slot gap · 32px "Beli".
   From 768: title sm 14/20 w500 · price base 16/24 w600 · 16px padding · 40px "Beli".
   Every hit area >= 48px. */
/* Meta: one line (real sold count / admin rating only — task H). Items that do not fit wrap onto
   the hidden 2nd line instead of being cut. Omitted for a whole section that has no meta data. */
/* Task H: the section decides whether the slot exists. Any card with meta → every card keeps the
   (possibly empty) slot so the row lines up; no card with meta → the slot is dropped section-wide. */
/* phase 14.8: was a :has(:not()) on the whole grid — Chrome re-styles the grid on every class change inside it (scroll reveal) → jank. */
/* Price: row 1 = "Mulai" and/or the struck normal price (always reserved, so every price in a
   row starts at the same height), row 2 = the price / skeleton / note. */   /* every price/note/skeleton starts at the same height */
/* Stock / status: dot + text, never colour alone; one fixed line, never truncated. */

/* ---------- Motion: see vf-feedback.css (the one motion layer). Transform + opacity only, off under reduced motion. ---------- */
@media (prefers-reduced-motion: no-preference) {
  /* 5) Category tab change: the visible product section fades in (opacity only, no layout jump). */
}   /* decorative sweep, 3 x 300ms */

/* 4) Primary glow: Beli, top-up "+", "Belanja sekarang" (.vf-btn--glow) and the active
      category tab. One halo layer (::before / ::after) whose OPACITY changes: soft at rest
      (≈ accent 35% alpha, 18px blur), full on hover, keyboard focus and press — --vf-dur-out. */
.vf-btn--glow, .rs-balance__add { isolation: isolate; }
.vf-btn--glow::before, .rs-balance__add::before { position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none;
  box-shadow: var(--rs-glow-action); opacity: 0.6; transition: opacity var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
.vf-btn--glow:is(:hover, :focus-visible, :active)::before, .rs-balance:is(:hover, :focus-visible, :active) .rs-balance__add::before { opacity: 1; box-shadow: var(--rs-glow-action-strong); }
/* Focused field: the focus ring plus a soft halo. */
@media (prefers-reduced-motion: reduce) {
  .vf-btn:active, .btn:active, .rs-seg__item:active, .rs-balance:active, .rs-icon-btn:active, .vf-pcard__qv:active { transform: none !important; }
}

/* ---------- Glowing headline (v10, AUDIT V10-T3) ----------
   Only on: the landing store name, the dashboard greeting name, the admin dashboard title.
   A soft indigo halo breathes in a 3.6s ease-in-out loop. Only text-shadow changes (paint,
   no layout); the text colour itself never changes, so its contrast is the fixed AA pair
   --rs-primary-text / surface. Paused with the tab hidden (html.rs-tab-hidden, global rule);
   static soft glow under prefers-reduced-motion. */
.rs-glow-text.rs-glow-text { color: var(--rs-hl-color); } /* doubled class: wins over page title colours */

/* ---------- Horizontal scroll row (scroll-snap, aligned to the page gutter) ----------
   Set --hscroll-bleed to the page gutter so the row can run edge-to-edge on phones while
   the first card still lines up with the content. Cards peek to signal more content. */
.rs-hscroll {
  --hscroll-bleed: 0px;
  /* The 2px/8px padding gives focus rings and card shadows room; negative block margins
     cancel it so the row adds no extra space to the section rhythm (AGENT G4). */
  margin: calc(-1 * var(--rs-s-4)) calc(-1 * var(--hscroll-bleed)) calc(-1 * var(--rs-space-2)); padding: var(--rs-s-4) var(--hscroll-bleed) var(--rs-space-2);
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--hscroll-bleed); scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.rs-hscroll::-webkit-scrollbar { display: none; }
.rs-hscroll:focus-visible { outline: 2px solid var(--vf-accent-text); outline-offset: 2px; border-radius: var(--vf-r-card); }
.rs-hscroll.is-dragging { scroll-snap-type: none; cursor: grabbing; }
/* Track columns = the product grid's columns (shared --pg-cols / --pg-gap tokens above),
   so a popular row lines up card-for-card with the grid below. With <= --pg-cols items
   nothing scrolls and the row reads exactly like a grid row (AGENT G3). */
.rs-hscroll__track {
  display: grid; grid-auto-flow: column;
  /* Phase 18: same minimum-card-width floor as the grid, so a high column count makes the carousel scroll (more,
     readable cards) instead of shrinking the cards below --pg-floor. */
  grid-auto-columns: max(var(--pg-floor), (100% - (var(--pg-cols) - 1) * var(--pg-gap)) / var(--pg-cols));
  column-gap: var(--pg-gap);
}
/* Every card in a row is as tall as the tallest one (equal heights, Task A); the card's fixed
   slots (title / meta / price / stock / actions) keep its content aligned at that height. */
.rs-hscroll__track { list-style: none; margin: 0; padding: 0; }
.rs-hscroll__item { scroll-snap-align: start; min-width: 0; display: flex; align-items: stretch; }
.rs-hscroll.is-static { overflow-x: hidden; scroll-snap-type: none; }
.rs-row-nav { display: inline-flex; gap: 0; margin: calc(-1 * var(--rs-s-8)) calc(-1 * var(--rs-s-4)) calc(-1 * var(--rs-s-8)) 0; flex-shrink: 0; }
.rs-row-nav[hidden] { display: none; }
.rs-row-hint { display: inline-flex; align-items: center; gap: var(--rs-s-4); flex-shrink: 0; font-size: var(--rs-fs-sm); font-weight: var(--rs-fw-medium); color: var(--vf-text-3); }
.rs-row-hint[hidden] { display: none; }

/* ---------- Quick view (partials/quick-view.ejs) ---------- */
.rs-qv {
  width: min(440px, calc(100vw - 24px)); max-height: min(86dvh, 720px); padding: 0; margin: auto;
  border: 1px solid var(--vf-border); border-radius: var(--vf-r-card);
  background: var(--vf-surface-2); color: var(--vf-text-1); box-shadow: var(--vf-e3); overflow: hidden;
}
.rs-qv::backdrop { background: var(--rs-overlay); }
/* Enter: scale+fade from slightly below (dialog), slide up on phones (sheet).
   Exit (.is-closing, set by quick-view.js): faster, accelerating. */
.rs-qv[open] { display: flex; flex-direction: column; }
@media (max-width: 575.98px) {
  .rs-qv { width: 100vw; max-width: 100vw; margin: auto 0 0; border-radius: var(--vf-r-card) var(--vf-r-card) 0 0; border-bottom: 0; }
}
.rs-qv__media { position: relative; aspect-ratio: 16 / 9; background: var(--vf-surface-3); border-bottom: 1px solid var(--vf-border); flex-shrink: 0; }
.rs-qv__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; padding: var(--rs-space-3); }
.rs-qv__media .rs-qv__icon { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: var(--rs-ts-3xl); color: var(--vf-text-2); }
.rs-qv__close { position: absolute; top: var(--rs-space-2); right: var(--rs-space-2); z-index: 1; }
.rs-qv__body { padding: var(--rs-space-4); overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: var(--rs-space-2); }
.rs-qv__title { margin: 0; font-size: var(--rs-fs-xl); font-weight: var(--rs-fw-semibold); line-height: var(--rs-lh-auto); letter-spacing: var(--rs-tracking-tight); }
.rs-qv__row { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--rs-s-4) var(--rs-space-3); }
.rs-qv__price { font-size: var(--rs-fs-2xl); font-weight: var(--rs-fw-bold); font-variant-numeric: tabular-nums; }
.rs-qv__from { font-size: var(--rs-fs-sm); color: var(--vf-text-2); }
.rs-qv__was { font-size: var(--rs-fs-sm); color: var(--vf-text-3); }
.rs-qv__rating { display: inline-flex; align-items: center; gap: var(--rs-s-4); font-size: var(--rs-fs-sm); font-weight: var(--rs-fw-semibold); }
.rs-qv__rating .bi { color: var(--vf-warning); }
.rs-qv__desc { margin: 0; font-size: var(--rs-fs-base); line-height: var(--rs-lh-auto); color: var(--vf-text-2); white-space: pre-wrap; overflow-wrap: anywhere; }
.rs-qv__foot { padding: var(--rs-space-3) var(--rs-space-4) calc(var(--rs-space-4) + env(safe-area-inset-bottom, 0)); border-top: 1px solid var(--vf-border); display: flex; gap: var(--rs-space-2); flex-shrink: 0; }
.rs-qv__foot .vf-btn { flex: 1; }

/* ---------- Empty / loading ---------- */

.rs-empty > .bi { font-size: var(--rs-ts-2xl); display: block; margin-bottom: var(--rs-space-2); }
.rs-empty__title { font-weight: var(--rs-fw-semibold); }
.rs-empty__body { font-size: var(--rs-fs-base); }

/* Shimmer = a transformed highlight (GPU-friendly); static block with reduced motion. */
.rs-skeleton::after {
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--vf-surface-2) 65%, transparent), transparent);
}
@media (prefers-reduced-motion: reduce) { .rs-skeleton::after { opacity: 0; } }
.rs-spinner { width: 1em; height: 1em; border: 2px solid currentColor; border-right-color: transparent; border-radius: var(--rs-radius-full); display: inline-block; animation: rs-spin 0.7s linear infinite; vertical-align: -0.125em; }
@keyframes rs-spin { to { transform: rotate(360deg); } }

/* ---------- Round carousel buttons (product rows, partials/product-section.ejs) ----------
   var(--rs-hit) hit area, --rs-ctrl-visual (36px) visible circle drawn by ::before. The dashboard banner
   has its own on-banner controls (views/dashboard.ejs). */
/* var(--rs-hit) hit area, --rs-ctrl-visual (34px) visible circle drawn by ::before (AGENT S1). */
.rs-carousel__btn {
  position: relative; width: var(--rs-hit); height: var(--rs-hit); display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  padding: 0; border: 0; background: none; color: var(--vf-text-1); font-size: var(--rs-ts-sm); cursor: pointer;
}
.rs-carousel__btn::before {
  content: ''; position: absolute; left: 50%; top: 50%; width: var(--rs-ctrl-visual); height: var(--rs-ctrl-visual);
  margin: calc(var(--rs-ctrl-visual) / -2) 0 0 calc(var(--rs-ctrl-visual) / -2);
  border-radius: var(--rs-radius-full); border: 1px solid var(--vf-border); background: var(--vf-surface-2); box-shadow: var(--vf-e1);
  transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
.rs-carousel__btn > .bi { position: relative; }
.rs-carousel__btn:hover::before { background: var(--rs-surface-hover); border-color: var(--vf-border-strong); }
.rs-carousel__btn:focus-visible { outline: none; }
.rs-carousel__btn:focus-visible::before { outline: 2px solid var(--vf-accent-text); outline-offset: 2px; }
.rs-carousel__btn:disabled { opacity: 0.45; cursor: default; }

/* ---------- Toast (polite, never steals focus; auto-dismiss 4–5 s) ---------- */
.rs-toast {
  position: fixed; left: 50%; bottom: calc(var(--rs-bottomnav-h) + env(safe-area-inset-bottom, 0) + var(--rs-space-4)); z-index: var(--rs-z-toast);
  display: flex; align-items: center; gap: var(--rs-s-8); width: max-content; max-width: min(92vw, 480px);
  padding: var(--rs-s-16); border-radius: var(--vf-r-card);
  background: var(--rs-surface-elevated); color: var(--vf-text-1); border: 1px solid var(--vf-border); box-shadow: var(--vf-e3);
  font-size: var(--rs-fs-md); font-weight: var(--rs-fw-medium);
  transform: translate(-50%, 12px); opacity: 0; pointer-events: none;
  transition: opacity var(--vf-dur, 140ms) var(--vf-ease, ease-out), transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
.rs-toast.is-shown { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.rs-toast > .bi { font-size: var(--rs-ts-base); flex-shrink: 0; }
.rs-toast--warning > .bi { color: var(--vf-warning); }
.rs-toast--success > .bi { color: var(--vf-success); }
.rs-toast--danger > .bi { color: var(--vf-danger); }

/* ---------- Entrance (only where it helps orientation) ---------- */

/* ---------- Element-level system overrides (after Bootstrap's reboot, same specificity) ---------- */
h1, h2, h3, h4, h5, h6, legend, button, input, optgroup, select, textarea, label { line-height: var(--rs-lh-auto); }   /* Bootstrap sets 1.2 / inherit */
legend { font-size: var(--rs-ts-base); }
b, strong { font-weight: var(--rs-fw-semibold); }
code, kbd, samp { font-size: var(--rs-ts-caption); }
:where(button, input, select, textarea) { padding: 0; }
.btn { --bs-btn-padding-x: var(--rs-s-16); --bs-btn-padding-y: var(--rs-s-8); --bs-btn-font-size: var(--rs-ts-sm); --bs-btn-line-height: 20px; --bs-btn-border-radius: var(--vf-r-ctl); }
.form-control, .form-select { padding: var(--rs-s-8) var(--rs-s-16); font-size: var(--rs-ts-sm); line-height: var(--rs-lh-auto); }
.form-select { padding-right: var(--rs-s-40); }
.modal-header, .modal-body, .modal-footer { padding: var(--rs-s-16); }
.table > :not(caption) > * > * { padding: var(--rs-s-8) var(--rs-s-16); }
.row { --bs-gutter-x: var(--rs-s-24); --bs-gutter-y: 0; }
 
.badge { padding: var(--rs-s-4) var(--rs-s-8); font-size: var(--rs-ts-caption); font-weight: var(--rs-fw-semibold); }
   

/* ---------- Bootstrap mapping ----------
   Pages built on Bootstrap pick up the same tokens (both modes). Low
   specificity on purpose: page CSS can still refine. */
.btn { font-family: inherit; font-weight: var(--rs-fw-semibold); border-radius: var(--vf-r-ctl); }
.btn-primary { --bs-btn-bg: var(--vf-accent); --bs-btn-border-color: var(--vf-accent); --bs-btn-hover-bg: var(--vf-accent-hover); --bs-btn-hover-border-color: var(--vf-accent-hover); --bs-btn-active-bg: var(--vf-accent-hover); --bs-btn-active-border-color: var(--vf-accent-hover); --bs-btn-disabled-bg: var(--vf-accent); --bs-btn-disabled-border-color: var(--vf-accent); --bs-btn-color: var(--vf-on-accent); --bs-btn-hover-color: var(--vf-on-accent); }
.form-control, .form-select {
  background-color: var(--vf-surface-2); color: var(--vf-text-1);
  border-color: var(--vf-border-strong); border-radius: var(--vf-r-ctl);
  min-height: var(--rs-control-h);
}
.form-control:focus, .form-select:focus { background-color: var(--vf-surface-2); color: var(--vf-text-1); border-color: var(--vf-accent); box-shadow: var(--rs-focus-ring); }
.form-control::placeholder { color: var(--vf-text-3); }
.form-label { font-weight: var(--rs-fw-semibold); font-size: var(--rs-fs-md); color: var(--vf-text-1); }

.modal-content { background: var(--rs-surface-elevated); box-shadow: var(--vf-e3); color: var(--vf-text-1); border: 1px solid var(--vf-border); border-radius: var(--vf-r-card); }
.modal-header, .modal-footer { border-color: var(--vf-border); }
.modal.fade .modal-dialog { transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out), opacity var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.btn { transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.table { --bs-table-bg: transparent; --bs-table-color: var(--vf-text-1); --bs-table-border-color: var(--vf-border); --bs-table-hover-bg: var(--rs-surface-hover); --bs-table-hover-color: var(--vf-text-1); }
html.dark-mode .btn-close { filter: invert(1) grayscale(100%) brightness(200%); }

/* =====================================================================
   R4 (phase 10) — two-tone animated wordmark, one class for every header.
   First part = primary text colour; last word = indigo accent whose
   brightness pulses (3.6s ease-in-out) with a soft glow that grows and
   fades with it. Only color + text-shadow animate (no layout change).
   Contrast against the header background, both ends of the pulse:
     dark  (#131220 header): #8b80fb 5.8:1 … #c4bdff 10.6:1
     light (#fefefe header): #5442e6 6.3:1 … #3d2fae 9.4:1   (>= 4.5:1)
   Phase 14: the family is the brand token (Fugaz One); never the browser's synthetic italic.
   ===================================================================== */
:root {
  --rs-wm-light: #5442e6;               /* lighter end (light mode) */
  --rs-wm-deep: #3d2fae;                /* deeper end (light mode) */
  --rs-wm-glow-rgb: 84, 66, 230;
  --rs-wm-glow-lo: 0.10;
  --rs-wm-glow-hi: 0.32;
}
html.dark-mode {
  --rs-wm-light: #c4bdff;
  --rs-wm-deep: #8b80fb;
  --rs-wm-glow-rgb: 120, 106, 255;
  --rs-wm-glow-lo: 0.18;
  --rs-wm-glow-hi: 0.55;
}
.rs-wordmark {
  font-family: var(--vf-font-brand);
  font-weight: 400;
  font-style: normal;
  transform: none;
  line-height: inherit;
}
/* Paused while the tab is hidden by the existing global html.rs-tab-hidden rule (global-theme.js). */
@media (prefers-reduced-motion: reduce) {
  .rs-wordmark__accent { color: var(--rs-wm-deep); text-shadow: 0 0 6px rgba(var(--rs-wm-glow-rgb), var(--rs-wm-glow-lo)); }
}

/* =====================================================================
   R2 (phase 10) — SVG icons from the vendored Bootstrap Icons sprite
   (public/icons/bi-sprite.svg, MIT). views/partials/icon.ejs renders
   <svg class="rs-icon rs-icon--16|20|24"><use href="…#bi-name"></svg>;
   window.RSIcon(name, size, label) is the JS twin. currentColor fill.
   Icon tile = 40px square, radius 8px, tinted surface, same everywhere.
   ===================================================================== */
.rs-icon { display: inline-block; flex-shrink: 0; vertical-align: -0.125em; fill: currentColor; overflow: visible; }
.rs-icon--16 { width: 16px; height: 16px; }
.rs-icon--20 { width: 20px; height: 20px; }
.rs-icon--24 { width: 24px; height: 24px; }
.rs-icon--em { width: 1em; height: 1em; }
.rs-icon-tile {
  --tile-bg: var(--vf-accent-subtle); --tile-fg: var(--vf-accent-text);
  width: 40px; height: 40px; flex: 0 0 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--vf-r-ctl);
  background: var(--tile-bg); color: var(--tile-fg);
}
.rs-icon-tile--success { --tile-bg: color-mix(in srgb, var(--vf-success) 14%, transparent); --tile-fg: var(--vf-success); }
.rs-icon-tile--warning { --tile-bg: color-mix(in srgb, var(--vf-warning) 16%, transparent); --tile-fg: var(--vf-warning); }
.rs-icon-tile--danger  { --tile-bg: color-mix(in srgb, var(--vf-danger) 14%, transparent);  --tile-fg: var(--vf-danger); }
.rs-icon-tile--info    { --tile-bg: color-mix(in srgb, var(--vf-info) 14%, transparent);    --tile-fg: var(--vf-info); }
.rs-icon-tile--neutral { --tile-bg: var(--vf-surface-3); --tile-fg: var(--vf-text-2); }

/* =====================================================================
   R3 (phase 10) — one popup style for every popup on every page.
   Attributes are set by the popup layer in global-theme.js (RSPopup):
   [data-rs-scrim] custom overlay, [data-rs-surface] the box,
   [data-rs-open] while open, [data-rs-stacked] on popups above the first.
   ===================================================================== */
:root {
  --rs-overlay: var(--vf-scrim-solid);
}
html.dark-mode {
  --rs-overlay: var(--vf-scrim-solid);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  :root, html.dark-mode { --rs-overlay: var(--vf-scrim); }
}
/* Scrim: custom overlays, native dialog backdrops, Bootstrap backdrops */

.modal-backdrop.modal-backdrop { --bs-backdrop-opacity: 1; --bs-backdrop-bg: transparent; }
/* Bootstrap backdrop: fades together with the dialog (not one after the other) — no transition
   for Bootstrap to wait on; an animation instead (RSPopup adds .rs-bd-leaving on hide.bs.modal). */
.modal-backdrop.fade { transition: none; }
/* only one blur layer: popups opened on top of another reuse the first one's */
[data-rs-scrim][data-rs-stacked], dialog[data-rs-stacked]::backdrop, .modal-backdrop[data-rs-stacked] {
  background: transparent !important; -webkit-backdrop-filter: none; backdrop-filter: none;
}
/* Surface: soft corners + overlay elevation */

[data-rs-surface="sheet"][data-rs-surface] { border-radius: var(--vf-r-card) var(--vf-r-card) 0 0 !important; box-shadow: var(--vf-e3); }
[data-rs-surface="side"][data-rs-surface] { border-radius: var(--vf-r-card) 0 0 var(--vf-r-card) !important; box-shadow: var(--vf-e3); }
[data-rs-surface="side-left"][data-rs-surface] { border-radius: 0 var(--vf-r-card) var(--vf-r-card) 0 !important; box-shadow: var(--vf-e3); }
/* Motion: enter 200ms (decelerating), exit 150ms (accelerating). Popups that already animate
   themselves keep their own motion ([data-rs-own-motion], normalised to the same tokens); the
   others get this fade + lift on enter, and on exit while RSPopup keeps them painted
   ([data-rs-leaving], 150ms) after the page hid them. */
@media (prefers-reduced-motion: no-preference) {
  [data-rs-leaving] { pointer-events: none !important; }
  .modal.fade { transition: opacity var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
  .modal.fade.show { transition-duration: var(--vf-dur, 140ms); transition-timing-function: var(--vf-ease-in); }
  .modal.fade .modal-dialog { transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); transform: translateY(8px) scale(0.98); }
  .modal.show .modal-dialog { transition-duration: var(--vf-dur, 140ms); transition-timing-function: var(--vf-ease-in); transform: none; }
}
/* RSDialog (alert / confirm) — global-theme.js */
.rs-dlg {
  width: min(400px, calc(100vw - 32px)); padding: 0; margin: auto; border: 1px solid var(--vf-border);
  border-radius: var(--vf-r-card); background: var(--vf-surface-2); color: var(--vf-text-1); box-shadow: var(--vf-e3);
}
.rs-dlg__body { display: flex; gap: var(--rs-space-3); align-items: flex-start; padding: var(--rs-space-5) var(--rs-space-4) var(--rs-space-4); }
.rs-dlg__text { min-width: 0; }
.rs-dlg__title { margin: 0 0 var(--rs-s-4); font-size: var(--rs-fs-lg); font-weight: var(--rs-fw-semibold); line-height: var(--rs-lh-auto); }
.rs-dlg__msg { margin: 0; font-size: var(--rs-fs-base); line-height: var(--rs-lh-auto); color: var(--vf-text-2); white-space: pre-line; overflow-wrap: anywhere; }
.rs-dlg__foot { display: flex; gap: var(--rs-space-2); padding: 0 var(--rs-space-4) var(--rs-space-4); }
.rs-dlg__foot > .vf-btn { flex: 1 1 0; min-width: 0; }

html.dark-mode .vf-btn--danger { color: var(--vf-on-danger); }

html.dark-mode .vf-btn--danger:hover { color: var(--vf-on-danger); }

/* R1 + R2 (phase 10): short info items in a 3-item row ([Item] | [Item] | [Item] at every width):
   icon tile on top, title, one short line — centred, wrapping, never cut. */
.rs-info3.rs-info3 { --fill-n: 3; --fill-gap: var(--rs-s-8); }
.rs-info3 > * { display: flex; flex-direction: column; align-items: center; gap: var(--rs-s-4); text-align: center; min-width: 0; }
.rs-info3 > * > .rs-icon-tile { margin-bottom: var(--rs-s-4); }
.rs-info3 :where(p) { margin: 0; overflow-wrap: anywhere; }
@media (min-width: 768px) { .rs-info3.rs-info3 { --fill-gap: var(--rs-s-16); } }   /* status group: stock + meta read as one block */
/* Quick view: [hidden] wins over component display rules (the "Stok habis" badge showed on every product). */
.rs-qv [hidden] { display: none !important; }

/* Phase 10 D8: every empty state ends with a next step (shared row of actions). */

.rs-empty__actions:empty { display: none; }
.rs-seg > [hidden] { display: none !important; }
/* Phase 10 D15: inline note under an image-URL field that uses http:// */
.rs-field-warn { display: flex; align-items: flex-start; gap: var(--rs-s-8); margin: var(--rs-s-8) 0 0; font-size: var(--rs-fs-sm); color: var(--rs-warning, var(--vf-text-2)); }
.rs-field-warn .rs-icon { flex-shrink: 0; margin-top: 2px; }
.rs-field-warn[hidden] { display: none; }
/* Phase 10 D6: on the narrowest phones (< 375px) a 3-column card is 86px inside; a six-digit price
   ("Rp 250.000") needs ~90px. The body's side padding drops to 4px there so the price stays on one line. */

/* =========================================================================
   PHASE 11 — DESIGN-SYSTEM COMPONENTS (.vf-*)
   The canonical components from "VF Market Design System". The older .rs-*
   classes that render the same thing share these rules (selector lists), so
   pages built before phase 11 follow the system without markup changes.
   ========================================================================= */
body { background: var(--vf-surface-1); color: var(--vf-text-1); font-family: var(--vf-font); }
body::before { content: none; }
.vf-num, .rs-num { font-variant-numeric: tabular-nums; }
.vf-mono { font-family: var(--vf-font-mono); font-weight: 500; font-variant-numeric: tabular-nums; letter-spacing: 0; }
.vf-t-display { font: var(--vf-t-display); letter-spacing: -0.02em; }
.vf-t-headline { font: var(--vf-t-headline); }
.vf-t-title { font: var(--vf-t-title); }
.vf-t-title-sm { font: var(--vf-t-title-sm); }
.vf-t-body { font: var(--vf-t-body); }
.vf-t-body-sm { font: var(--vf-t-body-sm); }
.vf-t-label { font: var(--vf-t-label); }
.vf-t-caption { font: var(--vf-t-caption); }
.vf-text-2 { color: var(--vf-text-2); }
.vf-text-3 { color: var(--vf-text-3); }
:where(a, button, input, select, textarea, summary, [tabindex], [role="button"]):focus-visible { outline-color: var(--vf-focus); }

/* ---------- Page container + hierarchy ---------- */
.vf-page { max-width: calc(var(--vf-container) + 2 * var(--vf-page-pad)); margin: 0 auto; padding: var(--vf-page-pad) var(--vf-page-pad) var(--vf-section-gap); display: flex; flex-direction: column; gap: var(--vf-section-gap); }
.vf-page--task { max-width: calc(560px + 2 * var(--vf-page-pad)); gap: 16px; }
.vf-section { display: flex; flex-direction: column; gap: var(--vf-card-gap); min-width: 0; }
.vf-section__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; min-width: 0; }
.vf-section__titles { display: flex; flex-direction: column; gap: var(--vf-pair-gap); min-width: 0; }
.vf-section__title { margin: 0; font: var(--vf-t-title-sm); color: var(--vf-text-1); }
.vf-section__count { font: var(--vf-t-caption-md); color: var(--vf-text-2); margin-left: 4px; }
.vf-section__sub { margin: 0; font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-section__link { flex-shrink: 0; min-height: var(--vf-hit); display: inline-flex; align-items: center; gap: 4px; padding: 0 8px; margin-right: -8px; font: 600 14px/20px var(--vf-font); color: var(--vf-accent-text); text-decoration: none; }
@media (min-width: 1024px) { .vf-section__title { font: var(--vf-t-title); } .vf-section__sub { font: 400 14px/20px var(--vf-font); } .vf-section__link { font-size: 14px; } }
.vf-split { display: grid; gap: 24px; align-items: start; }
@media (min-width: 1024px) { .vf-split { grid-template-columns: minmax(0, 1fr) 392px; } }

/* ---------- Card ---------- */
.vf-card, .rs-card {
  background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: var(--vf-r-card);
  box-shadow: var(--vf-e1); padding: var(--vf-card-pad); color: var(--vf-text-1);
}
.vf-card { display: flex; flex-direction: column; gap: var(--vf-inner-gap); min-width: 0; }
.vf-card--raised { box-shadow: var(--vf-e2); }
.vf-card--flush, .rs-card--flush { padding: 0; overflow: hidden; gap: 0; }
.vf-card--tonal { background: var(--vf-accent-subtle); box-shadow: none; }
.vf-card--info { background: var(--vf-info-subtle); box-shadow: none; color: var(--vf-text-1); }
.vf-card__title { margin: 0; font: var(--vf-t-h3); color: var(--vf-text-1); }

/* ---------- Buttons ---------- */
.vf-btn, .vf-btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: var(--vf-hit); padding: 0 20px; border-radius: var(--vf-r-ctl); border: 1px solid transparent;
  font: var(--vf-t-btn); text-decoration: none; white-space: nowrap; cursor: pointer; user-select: none;
  transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
.vf-btn .rs-icon, .vf-btn .rs-icon { width: 20px; height: 20px; }
/* Phase 12 D3 M5: pressed scale .98 (100ms), focus ring 2px page colour + 4px accent. */

.vf-btn:focus-visible, .vf-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--vf-surface-1), 0 0 0 4px var(--vf-accent); }
.vf-btn--primary, .vf-btn--primary { background: var(--vf-accent); color: var(--vf-on-accent); border-color: transparent; box-shadow: none; }
.vf-btn--primary:hover, .vf-btn--primary:hover { background: var(--vf-accent-hover); color: var(--vf-on-accent); }
.vf-btn--primary:active, .vf-btn--primary:active { background: var(--vf-accent-hover); }
.vf-btn--secondary, .vf-btn--secondary { background: var(--vf-surface-2); color: var(--vf-text-1); border-color: var(--vf-border-strong); }
.vf-btn--secondary:hover, .vf-btn--secondary:hover { background: var(--vf-surface-3); color: var(--vf-text-1); }
.vf-btn--tonal, .vf-btn--tonal { background: var(--vf-accent-subtle); color: var(--vf-accent-text); border-color: transparent; }
.vf-btn--tonal:hover, .vf-btn--tonal:hover { background: color-mix(in srgb, var(--vf-accent-subtle) 80%, var(--vf-accent) 12%); color: var(--vf-accent-text); }
.vf-btn--ghost, .vf-btn--ghost { background: transparent; color: var(--vf-accent-text); border-color: transparent; padding: 0 16px; }
.vf-btn--ghost:hover, .vf-btn--ghost:hover { background: var(--vf-surface-3); color: var(--vf-accent-text); }
.vf-btn--danger, .vf-btn--danger { background: var(--vf-danger); color: var(--vf-on-danger); border-color: transparent; }
.vf-btn--danger:hover, .vf-btn--danger:hover { background: color-mix(in srgb, var(--vf-danger) 88%, var(--vf-text-1)); color: var(--vf-on-danger); filter: none; }
.vf-btn--danger-outline { background: var(--vf-surface-2); color: var(--vf-danger); border-color: color-mix(in srgb, var(--vf-danger) 35%, var(--vf-surface-2)); }
.vf-btn--danger-outline:hover { background: var(--vf-danger-subtle); color: var(--vf-danger); }
.vf-btn--danger-outline { background: var(--vf-surface-2); color: var(--vf-danger); border-color: color-mix(in srgb, var(--vf-danger) 45%, var(--vf-surface-2)); }
.vf-btn--block, .vf-btn--block { display: flex; width: 100%; }
/* Small: 40px visual (tables, toolbars) with a 48px hit area. */
.vf-btn--sm, .vf-btn--sm { min-height: 40px; padding: 0 16px; font: var(--vf-t-ui-strong); }
.vf-btn--sm::before, .vf-btn--sm::before { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: var(--vf-hit); transform: translateY(-50%); }
/* Phase 12 D3 M5: disabled = opacity .45 and the label stays (it carries the reason, e.g. "Stok habis"). */
.vf-btn:disabled, .vf-btn[aria-disabled="true"], .vf-btn:disabled, .vf-btn[aria-disabled="true"] { background: var(--vf-surface-3); color: var(--vf-text-2); border-color: var(--vf-border); cursor: not-allowed; box-shadow: none; transform: none; }   /* opaque: a disabled sticky button never shows the page through it */
/* Loading: a 16px spinner takes the icon's place, the label reads "Memproses" (global-theme.js), width locked. */
.vf-btn[aria-busy="true"], .vf-btn[aria-busy="true"] { pointer-events: none; opacity: 1; color: inherit; }
.vf-btn--primary[aria-busy="true"], .vf-btn--primary[aria-busy="true"] { color: var(--vf-on-accent); }
.vf-btn[aria-busy="true"] > *, .vf-btn[aria-busy="true"] > * { visibility: visible; }
.vf-btn[aria-busy="true"]:disabled, .vf-btn[aria-busy="true"]:disabled { opacity: 1; }
.vf-btn[aria-busy="true"] .rs-icon, .vf-btn[aria-busy="true"] .rs-icon { display: none; }
.vf-btn[aria-busy="true"]::after, .vf-btn[aria-busy="true"]::after { content: ''; position: static; order: -1; flex: none; width: 16px; height: 16px; margin: 0; border-radius: 999px; border: 2px solid var(--vf-btn-spin, var(--vf-text-2)); border-right-color: transparent; animation: rs-spin .7s linear infinite; }
.vf-btn--primary[aria-busy="true"], .vf-btn--primary[aria-busy="true"] { --vf-btn-spin: var(--vf-on-accent); --rs-btn-spin: var(--vf-on-accent); }
.vf-icon-btn, .rs-icon-btn {
  position: relative; width: var(--vf-hit); height: var(--vf-hit); flex-shrink: 0; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--vf-r-ctl); border: 0; background: transparent; color: var(--vf-text-1); cursor: pointer; text-decoration: none;
}
.vf-icon-btn:hover, .rs-icon-btn:hover { background: var(--vf-surface-3); color: var(--vf-text-1); }
.vf-icon-btn--outline { border: 1px solid var(--vf-border); }
.vf-icon-btn--accent { color: var(--vf-accent-text); }
.vf-icon-btn--muted { color: var(--vf-text-2); }
.vf-btn--glow::before, .rs-balance__add::before { content: none; }

/* ---------- Inputs ---------- */
.vf-field, .rs-field { display: flex; flex-direction: column; gap: var(--vf-pair-gap); }
.vf-label, .rs-label { font: var(--vf-t-label); color: var(--vf-text-1); }
.vf-help, .rs-help { margin: 0; font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-error, .rs-error { margin: 0; display: flex; gap: 4px; align-items: center; font: var(--vf-t-caption); color: var(--vf-danger); }
.vf-input, .rs-input, .rs-select, .rs-textarea, .vf-select, .vf-textarea {
  width: 100%; min-height: var(--vf-hit); padding: 0 16px; border-radius: var(--vf-r-ctl);
  border: 1px solid var(--vf-border-strong); background: var(--vf-surface-2); color: var(--vf-text-1);
  font: var(--vf-t-body-lg); box-shadow: none;
}
.vf-textarea, .rs-textarea { padding: 12px 16px; min-height: 96px; }
.vf-input::placeholder, .rs-input::placeholder, .rs-textarea::placeholder { color: var(--vf-text-3); }
.vf-input:focus, .rs-input:focus, .rs-select:focus, .rs-textarea:focus, .vf-select:focus, .vf-textarea:focus { outline: none; border-color: var(--vf-accent); box-shadow: inset 0 0 0 1px var(--vf-accent); }
.vf-input[aria-invalid="true"], .rs-input[aria-invalid="true"], .rs-select[aria-invalid="true"] { border-color: var(--vf-danger); box-shadow: inset 0 0 0 1px var(--vf-danger); }
.vf-input:disabled, .rs-input:disabled { background: var(--vf-surface-3); color: var(--vf-text-3); }
@media (min-width: 768px) and (pointer: fine) { .vf-input, .rs-input, .rs-select, .rs-textarea { font-size: 16px; } }
.vf-input-wrap { position: relative; display: flex; align-items: center; }
.vf-input-wrap > .vf-input__prefix { position: absolute; left: 16px; color: var(--vf-text-2); pointer-events: none; font: 400 16px/24px var(--vf-font); }
.vf-input-wrap > .vf-input__prefix + .vf-input { padding-left: 44px; }

.vf-search > input { width: 100%; min-height: var(--vf-hit); padding: 0 16px 0 40px; border: 0; border-radius: var(--vf-r-ctl); background: var(--vf-surface-3); color: var(--vf-text-1); font: 400 16px/24px var(--vf-font); }
.vf-search > input:focus { outline: none; box-shadow: inset 0 0 0 2px var(--vf-accent); background: var(--vf-surface-2); }

/* ---------- Tabs: category chips (scroll) + underline tabs ---------- */
.vf-chips { display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; padding: 4px var(--vf-page-pad); margin: -4px calc(-1 * var(--vf-page-pad)); }
.vf-chips::-webkit-scrollbar { display: none; }
.vf-chips.is-more-end { -webkit-mask-image: linear-gradient(90deg, black calc(100% - 32px), transparent); mask-image: linear-gradient(90deg, black calc(100% - 32px), transparent); }
.vf-chip-btn {
  position: relative; flex: none; min-height: 40px; padding: 0 16px; display: inline-flex; align-items: center; gap: 8px;
  border-radius: var(--vf-r-full); border: 1px solid var(--vf-border); background: var(--vf-surface-2); color: var(--vf-text-1);
  font: var(--vf-t-ui); white-space: nowrap; text-decoration: none; cursor: pointer;
}
.vf-chip-btn::before { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: var(--vf-hit); transform: translateY(-50%); }
.vf-chip-btn:hover { border-color: var(--vf-border-strong); color: var(--vf-text-1); }
.vf-chip-btn[aria-pressed="true"], .vf-chip-btn[aria-current="page"], .vf-chip-btn.is-active { background: var(--vf-text-1); border-color: var(--vf-text-1); color: var(--vf-surface-2); }
.vf-chip-btn--link { color: var(--vf-accent-text); padding-right: 16px; }
.vf-chip-btn--sm { font-size: 14px; }
.vf-chips__divider { flex: none; width: 1px; height: 24px; align-self: center; background: var(--vf-border); }
@media (min-width: 1024px) {
  .vf-chips--wrap { flex-wrap: wrap; overflow: visible; margin: 0; padding: 0; }
  .vf-chips--wrap .vf-chip-btn { min-height: var(--vf-hit); padding: 0 20px; }
}
.vf-tabs { display: flex; gap: 24px; border-bottom: 1px solid var(--vf-border); overflow-x: auto; scrollbar-width: none; }
.vf-tabs::-webkit-scrollbar { display: none; }
.vf-tabs--fill { gap: 0; }
.vf-tabs--fill > .vf-tab { flex: 1 1 0; justify-content: center; }
.vf-tab {
  flex: none; min-height: var(--vf-hit); display: inline-flex; align-items: center; gap: 8px; padding: 0; border: 0; background: none;
  font: var(--vf-t-ui); color: var(--vf-text-2); text-decoration: none; white-space: nowrap; cursor: pointer; box-shadow: inset 0 -2px 0 transparent;
}
.vf-tab:hover { color: var(--vf-text-1); }
.vf-tab[aria-selected="true"], .vf-tab[aria-current="page"], .vf-tab.is-active { color: var(--vf-accent-text); font-weight: 600; box-shadow: inset 0 -2px 0 var(--vf-accent); }
.vf-tab__count { font: var(--vf-t-caption-strong); color: var(--vf-text-3); }
/* Segmented: 48px items (phase 13; was 44) (neighbours). */
.vf-seg { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; padding: 4px; border-radius: var(--vf-r-ctl); background: var(--vf-surface-3); }
.vf-seg__item { min-height: 48px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 0 12px; border: 0; border-radius: var(--vf-r-8); background: transparent; color: var(--vf-text-2); font: var(--vf-t-ui); cursor: pointer; text-decoration: none; }
.vf-seg__item[aria-checked="true"], .vf-seg__item[aria-selected="true"], .vf-seg__item[aria-pressed="true"], .vf-seg__item.is-active { background: var(--vf-surface-2); color: var(--vf-text-1); font-weight: 600; box-shadow: var(--vf-e1); }

/* ---------- Status chips & badges ---------- */
.vf-chip, .rs-badge {
  display: inline-flex; align-items: center; gap: 4px; height: 24px; padding: 0 8px; border-radius: var(--vf-r-chip); border: 0;
  font: var(--vf-t-caption-strong); background: var(--vf-surface-3); color: var(--vf-text-2);
}
.vf-chip .rs-icon { width: 12px; height: 12px; }
.vf-chip--sm { height: 20px; padding: 0 8px; font-size: 12px; border-radius: 6px; }
.vf-chip--success, .rs-badge--success { background: var(--vf-success-subtle); color: var(--vf-success); }
.vf-chip--warning, .rs-badge--warning { background: var(--vf-warning-subtle); color: var(--vf-warning); }
.vf-chip--danger,  .rs-badge--danger  { background: var(--vf-danger-subtle);  color: var(--vf-danger); }
.vf-chip--info,    .rs-badge--info    { background: var(--vf-info-subtle);    color: var(--vf-info); }
.vf-chip--neutral { background: var(--vf-surface-3); color: var(--vf-text-2); }
.vf-chip--accent { background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
.vf-chip--solid { background: var(--vf-accent); color: var(--vf-on-accent); }
.vf-chip--inverse { background: var(--vf-text-1); color: var(--vf-surface-2); }

/* ---------- Stat tile (3 equal columns, never ellipsis, never wrap) ---------- */
.vf-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.vf-stats--card { gap: 0; padding: 16px 4px; background: var(--vf-surface-2); border-radius: var(--vf-r-card); box-shadow: var(--vf-e2); border: var(--vf-card-border); }
.vf-stat { display: flex; flex-direction: column; gap: 8px; min-width: 0; padding: 12px; background: var(--vf-surface-2); border: 1px solid var(--vf-border); border-radius: var(--vf-r-ctl); }
.vf-stats--card > .vf-stat { align-items: center; text-align: center; padding: 0 8px; border: 0; border-radius: 0; background: none; }
.vf-stats--card > .vf-stat + .vf-stat { border-left: 1px solid var(--vf-border); }
.vf-stat__icon { width: 40px; height: 40px; border-radius: var(--vf-r-ctl); display: inline-flex; align-items: center; justify-content: center; background: var(--vf-accent-subtle); color: var(--vf-accent-text); flex: none; }
.vf-stat__icon--success { background: var(--vf-success-subtle); color: var(--vf-success); }
.vf-stat__icon--warning { background: var(--vf-warning-subtle); color: var(--vf-warning); }
.vf-stat__icon--danger { background: var(--vf-danger-subtle); color: var(--vf-danger); }
.vf-stat__icon--info { background: var(--vf-info-subtle); color: var(--vf-info); }
.vf-stat__text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.vf-stat__value { font: var(--vf-t-btn); font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--vf-text-1); }
.vf-stat__rp { font-size: 12px; font-weight: 500; color: var(--vf-text-2); }
.vf-stat__label { font: var(--vf-t-caption); color: var(--vf-text-2); }
@media (min-width: 1024px) { .vf-stat__value { font-size: 16px; } }

/* ---------- List row (server status, riwayat, menu) ---------- */
.vf-list { background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: var(--vf-r-card); box-shadow: var(--vf-e1); overflow: hidden; }
.vf-list--outline { box-shadow: none; border: 1px solid var(--vf-border); }
.vf-row { display: flex; align-items: center; gap: 12px; min-height: 64px; padding: 8px 8px 8px 16px; color: var(--vf-text-1); text-decoration: none; min-width: 0; }
.vf-row + .vf-row, .vf-list > * + .vf-row { border-top: 1px solid var(--vf-border); }
.vf-row--tall { min-height: 72px; padding: 12px 16px; }
.vf-row--menu { min-height: 56px; }
a.vf-row:hover, button.vf-row:hover { background: var(--vf-surface-3); color: var(--vf-text-1); }
button.vf-row { width: 100%; border: 0; background: none; text-align: left; font: inherit; cursor: pointer; }
.vf-row__lead { flex: none; color: var(--vf-text-3); display: inline-flex; }
.vf-row__tile { flex: none; width: 40px; height: 40px; border-radius: var(--vf-r-ctl); display: inline-flex; align-items: center; justify-content: center; background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
.vf-row__tile--success { background: var(--vf-success-subtle); color: var(--vf-success); }
.vf-row__tile--neutral { background: var(--vf-surface-3); color: var(--vf-text-2); }
.vf-row__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.vf-row__title { font: var(--vf-t-btn); color: var(--vf-text-1); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vf-row__title--md { font: var(--vf-t-ui); }
.vf-row__meta { font: var(--vf-t-caption); color: var(--vf-text-2); display: flex; gap: 4px; align-items: center; min-width: 0; }
.vf-row__state { font: 400 14px/20px var(--vf-font); display: inline-flex; gap: 4px; align-items: center; }
.vf-row__state--success { color: var(--vf-success); }
.vf-row__state--danger { color: var(--vf-danger); }
.vf-row__state--muted { color: var(--vf-text-2); }
.vf-row__end { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.vf-row__amount { font: var(--vf-t-ui-strong); font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--vf-text-1); }
.vf-row__amount--plus { color: var(--vf-success); }
.vf-row__action { flex: none; min-height: var(--vf-hit); display: inline-flex; align-items: center; gap: 4px; padding: 0 8px; border-radius: var(--vf-r-ctl); font: 600 14px/20px var(--vf-font); color: var(--vf-accent-text); text-decoration: none; background: none; border: 0; cursor: pointer; }
.vf-row__chev { flex: none; color: var(--vf-text-3); }

/* ---------- Key / value rows + copy rows ---------- */
.vf-kv { display: flex; flex-direction: column; }
.vf-kv__row { display: flex; justify-content: space-between; gap: 16px; padding: 12px 16px; font: var(--vf-t-body-sm); }
/* Phase 12 key-value rule: label above value below 576px; from 576 a 2-column grid (180px | value), value left-aligned. */
.vf-kv--stack .vf-kv__row { display: grid; grid-template-columns: var(--vf-kv); gap: var(--vf-kv-gap); padding: var(--vf-kv-row); align-items: center; }
.vf-kv--stack .vf-kv__key { font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-kv--stack .vf-kv__val { text-align: left; font: var(--vf-t-ui); display: flex; align-items: center; gap: 4px; min-width: 0; }
.vf-kv--stack .vf-kv__val .vf-mono { font: var(--vf-t-code); overflow-wrap: anywhere; min-width: 0; }
@media (min-width: 576px) { .vf-kv--stack { --vf-kv: 180px minmax(0, 1fr); --vf-kv-gap: 16px; } .vf-kv--stack .vf-kv__key { font-size: 14px; line-height: 18px; } }
.vf-kv__row + .vf-kv__row, .vf-kv > * + .vf-copy { border-top: 1px solid var(--vf-border); }
.vf-kv__key { color: var(--vf-text-2); flex: none; }
.vf-kv__val { color: var(--vf-text-1); text-align: right; font-variant-numeric: tabular-nums; min-width: 0; overflow-wrap: anywhere; }
.vf-kv__row--total { font: var(--vf-t-btn); }
.vf-kv__row--total .vf-kv__key { color: var(--vf-text-1); }
.vf-kv__head { padding: 12px 16px 4px; font: var(--vf-t-ui-strong); }
.vf-copy { display: flex; align-items: center; gap: 8px; padding: 4px 4px 4px 16px; min-width: 0; }
.vf-copy__text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.vf-copy__label { font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-copy__value { font: var(--vf-t-ui-strong); font-variant-numeric: tabular-nums; letter-spacing: .01em; overflow-wrap: anywhere; }
@media (min-width: 1024px) { .vf-kv__row { padding: 16px 20px; } .vf-copy { padding-left: 20px; } .vf-kv__head { padding: 16px 20px 4px; font-size: 16px; } }

/* ---------- Table → phone stacked rows ---------- */
.vf-table-card { background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: var(--vf-r-card); box-shadow: var(--vf-e1); overflow: hidden; }
.vf-table { width: 100%; border-collapse: collapse; font: var(--vf-t-body-sm); color: var(--vf-text-1); }
.vf-table th { height: 44px; padding: 0 16px; background: color-mix(in srgb, var(--vf-surface-3) 45%, var(--vf-surface-2)); border-bottom: 1px solid var(--vf-border); text-align: left; font: var(--vf-t-caption-strong); color: var(--vf-text-2); white-space: nowrap; }
.vf-table td { padding: 8px 16px; height: 56px; border-top: 1px solid var(--vf-border); vertical-align: middle; }
.vf-table tbody tr:first-child td { border-top: 0; }
.vf-table th:first-child, .vf-table td:first-child { padding-left: 20px; }
.vf-table .is-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.vf-table .is-actions { width: 56px; text-align: right; }
.vf-table .is-ellipsis { max-width: 1px; width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vf-table__foot { min-height: 56px; display: flex; align-items: center; gap: 4px; padding: 0 8px 0 20px; border-top: 1px solid var(--vf-border); font: 400 14px/20px var(--vf-font); color: var(--vf-text-2); }
.vf-table__foot > :first-child { flex: 1; }
/* Phone: each row becomes a card (same data, same order, no horizontal scroll). */
@media (max-width: 767.98px) {
  .vf-table.vf-table--stack { display: block; background: none; }
  .vf-table-card:has(.vf-table--stack) { background: none; box-shadow: none; border: 0; border-radius: 0; overflow: visible; }
  .vf-table.vf-table--stack thead { display: none; }
  .vf-table.vf-table--stack tbody { display: flex; flex-direction: column; gap: 8px; }
  .vf-table.vf-table--stack tr { display: grid; grid-template-columns: auto 1fr; gap: 4px 16px; padding: 12px 16px; background: var(--vf-surface-2); border-radius: var(--vf-r-card); box-shadow: var(--vf-e1); border: var(--vf-card-border); }
  .vf-table.vf-table--stack td { display: contents; height: auto; padding: 0; border: 0; }
  .vf-table.vf-table--stack td::before { content: attr(data-label); font: var(--vf-t-small-loose); color: var(--vf-text-2); text-align: left; }
  .vf-table.vf-table--stack td > * { text-align: right; font: var(--vf-t-small-loose); justify-self: end; min-width: 0; overflow-wrap: anywhere; }
  .vf-table.vf-table--stack td.is-primary { display: block; grid-column: 1 / -1; order: -2; }
  .vf-table.vf-table--stack td.is-primary::before { content: none; }
  .vf-table.vf-table--stack td.is-primary > * { text-align: left; font: var(--vf-t-btn); justify-self: start; }
  .vf-table.vf-table--stack td.is-status { order: -1; grid-column: 1 / -1; display: block; }
  .vf-table.vf-table--stack td.is-status::before { content: none; }
  .vf-table.vf-table--stack td.is-status > * { justify-self: start; }
  .vf-table.vf-table--stack td.is-actions { grid-column: 1 / -1; display: flex; justify-content: flex-end; width: auto; }
  .vf-table.vf-table--stack td.is-actions::before { content: none; }
  .vf-table.vf-table--stack td:empty { display: none; }
  /* a whole-row cell (empty state, notice) keeps its own layout */
  .vf-table.vf-table--stack td[colspan] { display: block; grid-column: 1 / -1; }
  .vf-table.vf-table--stack td[colspan]::before { content: none; }
  .vf-table.vf-table--stack td[colspan] > * { text-align: center; justify-self: stretch; }
  .vf-table.vf-table--stack tr:has(> td[colspan] > .vf-empty) { background: var(--vf-surface-2); }
}

/* ---------- Empty state + skeleton ---------- */
.vf-empty, .rs-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center; padding: 24px 16px; color: var(--vf-text-2); }

.vf-empty__icon--lg { width: 64px; height: 64px; }
.rs-empty > .rs-icon, .rs-empty > .bi { width: 56px; height: 56px; padding: 16px; border-radius: var(--vf-r-full); background: var(--vf-surface-3); color: var(--vf-text-3); box-sizing: border-box; margin: 0; }
.vf-empty__title, .rs-empty__title { margin: 4px 0 0; font: var(--vf-t-btn); color: var(--vf-text-1); }
.vf-empty__body, .rs-empty__body { margin: 0; max-width: 320px; font: var(--vf-t-small-loose); color: var(--vf-text-2); text-wrap: pretty; }
.vf-empty__actions, .rs-empty__actions { margin-top: 4px; display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.vf-empty--card { background: var(--vf-surface-2); border: 1px solid var(--vf-border); border-radius: var(--vf-r-card); }
.vf-skel, .rs-skeleton { position: relative; overflow: hidden; background: var(--vf-surface-3); border-radius: 6px; }
.vf-skel::after, .rs-skeleton::after { content: ''; position: absolute; inset: 0; transform: translateX(-100%); background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--vf-surface-2) 60%, transparent), transparent); }
.vf-skel--line { height: 12px; }
.vf-skel--tile { aspect-ratio: 1; border-radius: var(--vf-r-ctl); }
@media (prefers-reduced-motion: reduce) { .vf-skel::after, .rs-skeleton::after { opacity: 0; } }

/* ---------- Stepper: process (3 segments) + quantity ---------- */
.vf-stepper, .rs-steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(var(--steps, 3), minmax(0, 1fr)); gap: 8px; }
.vf-stepper__item, .rs-steps__item { display: flex; flex-direction: column; gap: 8px; text-align: center; font: var(--vf-t-caption-md); color: var(--vf-text-2); border: 0; padding: 0; min-width: 0; }
.vf-stepper__item::before, .rs-steps__item::before { content: ''; height: 4px; border-radius: 2px; background: var(--vf-border); }
.vf-stepper__item.is-done, .rs-steps__item.is-done { color: var(--vf-success); }
.vf-stepper__item.is-done::before, .rs-steps__item.is-done::before { background: var(--vf-success); }
.vf-stepper__item[aria-current="step"], .rs-steps__item[aria-current="step"] { color: var(--vf-accent-text); font-weight: 600; }
.vf-stepper__item[aria-current="step"]::before, .rs-steps__item[aria-current="step"]::before { background: var(--vf-accent); }
.rs-steps__num { display: none; }
.rs-steps__label { white-space: nowrap; overflow: visible; }
.vf-qty { display: inline-flex; align-items: stretch; border: 1px solid var(--vf-border-strong); border-radius: var(--vf-r-ctl); overflow: hidden; background: var(--vf-surface-2); }
.vf-qty__btn { width: 48px; height: 48px; display: inline-flex; align-items: center; justify-content: center; border: 0; background: none; color: var(--vf-text-1); cursor: pointer; }
.vf-qty__btn:disabled { color: var(--vf-text-3); cursor: not-allowed; }
.vf-qty__val { width: 56px; border: 0; border-left: 1px solid var(--vf-border); border-right: 1px solid var(--vf-border); text-align: center; font: 600 16px/24px var(--vf-font); font-variant-numeric: tabular-nums; background: none; color: var(--vf-text-1); }

/* ---------- Option group (3 equal 48px options) ---------- */
.vf-options { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.vf-option { position: relative; min-height: 48px; display: flex; align-items: center; justify-content: center; padding: 0 8px; border-radius: var(--vf-r-ctl); border: 1px solid var(--vf-border); background: var(--vf-surface-2); color: var(--vf-text-1); font: var(--vf-t-ui); font-variant-numeric: tabular-nums; white-space: nowrap; cursor: pointer; text-align: center; }
.vf-option:hover { border-color: var(--vf-border-strong); }
.vf-option[aria-pressed="true"], .vf-option[aria-checked="true"], .vf-option.is-active, input:checked + .vf-option { border: 2px solid var(--vf-accent); background: var(--vf-accent-subtle); color: var(--vf-accent-text); font-weight: 600; padding: 0 7px; }
.vf-option:disabled, .vf-option[aria-disabled="true"] { background: var(--vf-surface-3); color: var(--vf-text-3); cursor: not-allowed; }

/* ---------- Sticky action bar (task screens, < 1024) ---------- */
.vf-actionbar { position: sticky; bottom: 0; z-index: var(--rs-z-sticky); display: flex; align-items: center; gap: 16px; padding: 12px 16px calc(20px + env(safe-area-inset-bottom, 0)); margin: 0 calc(-1 * var(--vf-page-pad)) calc(-1 * var(--vf-section-gap)); background: var(--vf-surface-2); border-top: 1px solid var(--vf-border); }
.vf-actionbar--2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.vf-actionbar__total { display: flex; flex-direction: column; flex: none; }
.vf-actionbar__total span:first-child { font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-actionbar__total span:last-child { font: 600 18px/26px var(--vf-font); font-variant-numeric: tabular-nums; }
.vf-actionbar > .vf-btn--primary:last-child { flex: 1; }
@media (min-width: 1024px) { .vf-actionbar { position: static; margin: 0; padding: 0; border: 0; background: none; } }
/* P1-05/06: the one fixed purchase bar on phones / tablets (product, stock, OTP, SMM order, panel); inline >= 1024.
   Pages that use it set body.vf-has-actionbar (reserves the height) and do not show the bottom nav. */
.vf-actionbar--fixed { position: fixed; left: 0; right: 0; bottom: 0; margin: 0; padding: 12px var(--vf-page-pad) calc(12px + env(safe-area-inset-bottom, 0px)); z-index: var(--rs-z-sticky); box-shadow: var(--vf-e-up); }
.vf-actionbar--fixed > .vf-btn, .vf-actionbar--fixed > .vf-btn { min-height: 48px; min-width: 0; }
@media (min-width: 1024px) { .vf-actionbar--fixed { position: static; padding: 0; box-shadow: none; } }

/* ---------- Timer chip + timeline ---------- */
.vf-timer { height: 32px; padding: 0 12px; border-radius: var(--vf-r-full); display: inline-flex; align-items: center; gap: 8px; background: var(--vf-warning-subtle); color: var(--vf-warning); font: 600 14px/20px var(--vf-font); font-variant-numeric: tabular-nums; }

.vf-timeline { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 20px 1fr; column-gap: 12px; font: var(--vf-t-small); }
.vf-timeline__dot { display: flex; flex-direction: column; align-items: center; }
.vf-timeline__dot::before { content: ''; width: 12px; height: 12px; margin-top: 3px; border-radius: var(--vf-r-full); background: var(--vf-success); box-sizing: border-box; }
.vf-timeline__dot::after { content: ''; flex: 1; width: 2px; min-height: 24px; background: var(--vf-border); }
.vf-timeline__dot.is-done::after { background: var(--vf-success); }
.vf-timeline__dot.is-current::before { background: var(--vf-surface-2); border: 2px solid var(--vf-warning); }
.vf-timeline__dot.is-failed::before { background: var(--vf-danger); }
.vf-timeline__dot.is-todo::before { background: var(--vf-surface-2); border: 2px solid var(--vf-border); }
.vf-timeline__dot:last-of-type::after { content: none; }
.vf-timeline__text { padding-bottom: 12px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.vf-timeline__text b { font-weight: 500; }
.vf-timeline__text.is-current b { font-weight: 600; color: var(--vf-warning); }
.vf-timeline__text span { color: var(--vf-text-2); }

/* ---------- Status result block (success / waiting / failed) ---------- */
.vf-result { display: flex; flex-direction: column; align-items: center; gap: 12px; text-align: center; padding: 8px 0; }
.vf-result__icon { width: 64px; height: 64px; border-radius: var(--vf-r-full); display: inline-flex; align-items: center; justify-content: center; background: var(--vf-success-subtle); color: var(--vf-success); }
.vf-result__icon .rs-icon { width: 32px; height: 32px; }
.vf-result__icon--warning { background: var(--vf-warning-subtle); color: var(--vf-warning); }
.vf-result__icon--danger { background: var(--vf-danger-subtle); color: var(--vf-danger); }
.vf-result__title { margin: 0; font: var(--vf-t-title); color: var(--vf-text-1); }
.vf-result__body { margin: 0; font: var(--vf-t-body-sm); color: var(--vf-text-2); max-width: 36ch; }

/* ---------- Wordmark (owner, phase 12b): Saira 700, 20px on every screen, letter-spacing −0.5px, no transform;
   two-tone (last word in the accent) kept. Same rule for a .navbar-brand. ---------- */

.vf-wordmark, .rs-wordmark { display: inline-block; font: 400 var(--vf-wm-size, 20px)/1.2 var(--vf-font-brand); letter-spacing: 0; text-transform: none; color: var(--vf-text-1); white-space: nowrap; font-synthesis: none; padding-inline-end: .12em; }
.vf-wordmark__head, .rs-wordmark__head { color: inherit; }
.vf-wordmark__accent, .rs-wordmark__accent { --wm-glow: var(--vf-glow); display: inline-block; color: var(--vf-accent-text); text-shadow: none; }
@media (prefers-reduced-motion: reduce) { .vf-wordmark__accent, .rs-wordmark__accent { filter: none; text-shadow: none; } }

/* ---------- Top bar (phase 12 Shell): 52 / 64, wordmark · nav (>= 1024) · saldo chip · menu 48 ---------- */
.rs-topbar { position: sticky; top: 0; z-index: var(--rs-z-nav); background: var(--vf-surface-2); border-bottom: 1px solid var(--vf-border); -webkit-backdrop-filter: none; backdrop-filter: none; padding-top: env(safe-area-inset-top, 0px); }
.rs-topbar__inner { max-width: none; height: var(--vf-top-h); min-height: 0; margin: 0; padding: 0 max(0px, env(safe-area-inset-right, 0px)) 0 max(var(--vf-page-pad), env(safe-area-inset-left, 0px)); display: flex; align-items: center; gap: 8px; }
/* Audit P1-01: a long store name shrinks with an ellipsis; the saldo chip and the menu never leave the bar. */
.rs-topbar__brand { flex: 0 1 auto; min-height: var(--vf-hit); display: inline-flex; align-items: center; text-decoration: none; margin-right: 0; min-width: 0; overflow: hidden; padding-right: 4px; }
.rs-topbar__brand .rs-wordmark { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.vf-topnav { min-width: 0; }
.rs-topbar__actions { margin-left: auto; flex: none; display: flex; align-items: center; gap: 4px; min-width: 0; }
.vf-top__menu { width: 48px; height: 48px; color: var(--vf-text-1); }
.vf-top__auth { min-height: 40px; padding: 0 12px; font-size: 14px; }
.vf-top__desk { display: none; }
@media (min-width: 1024px) { .vf-top__desk { display: inline-flex; } }
.vf-top__menu .rs-icon { width: 22px; height: 22px; }
.vf-saldo-chip { height: 36px; max-width: 100%; padding: 0 3px 0 8px; border-radius: 999px; background: var(--vf-accent-subtle); color: var(--vf-accent-text); display: inline-flex; align-items: center; gap: 8px; text-decoration: none; min-width: 0; }
.vf-saldo-chip::after { inset: -6px 0; }   /* 48px hit area */
.vf-saldo-chip > .rs-icon { width: 14px; height: 14px; flex: none; }
.vf-saldo-chip__amount { font: 600 14px/20px var(--vf-font-num); font-variant-numeric: tabular-nums; color: var(--vf-text-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.vf-saldo-chip__plus { width: 30px; height: 30px; flex: none; border-radius: 999px; background: var(--vf-accent); color: var(--vf-on-accent); display: inline-flex; align-items: center; justify-content: center; }
.vf-saldo-chip__plus .rs-icon { width: 12px; height: 12px; }
.vf-saldo-chip:hover .vf-saldo-chip__plus { background: var(--vf-accent-hover); }
.vf-topnav { display: none; }
.rs-topbar__cats, .vf-topbar__saldo, .rs-topbar__back, .rs-topbar__title { display: none !important; }
@media (min-width: 1024px) {
  .rs-topbar__inner { padding: 0 24px 0 var(--vf-page-pad); gap: 24px; }
  .vf-topnav { display: flex; gap: 4px; align-items: center; }
  .vf-topnav a, .vf-topnav button { height: 48px; padding: 0 16px; display: inline-flex; align-items: center; font: var(--vf-t-ui); color: var(--vf-text-2); text-decoration: none; background: none; border: 0; box-shadow: inset 0 -2px 0 transparent; white-space: nowrap; cursor: pointer; }
  .vf-topnav a:hover, .vf-topnav button:hover { color: var(--vf-text-1); }
  .vf-topnav [aria-current="page"] { color: var(--vf-accent-text); font-weight: 600; box-shadow: inset 0 -2px 0 var(--vf-accent); }
}
/* Back row under the bar (pages with a parent): "← Parent", desktop adds "/ Page". 48px tall. */
.vf-backrow { width: 100%; max-width: calc(var(--vf-w-list) + 2 * var(--vf-page-pad)); margin: 0 auto; padding: 0 var(--vf-page-pad); height: 48px; display: flex; align-items: center; gap: 8px; font: var(--vf-t-ui); color: var(--vf-text-2); min-width: 0; }
@media (min-width: 1024px) { .vf-backrow { max-width: calc(1200px + 2 * var(--vf-page-pad)); } }
.vf-backrow a { display: inline-flex; align-items: center; gap: 8px; min-height: 48px; color: var(--vf-accent-text); font-weight: 600; text-decoration: none; white-space: nowrap; }
.vf-backrow a .rs-icon { width: 16px; height: 16px; }
.vf-backrow__sep, .vf-backrow__here { display: none; }
.vf-backrow__here { color: var(--vf-text-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
@media (min-width: 1024px) { .vf-backrow__sep, .vf-backrow__here { display: inline; } }

/* ---------- Bottom nav (phase 12 + D3 M6): floating, blurred, pill + raised Deposit; < 1024 only ---------- */
.rs-bottomnav.vf-bnav { position: fixed; left: 0; right: 0; bottom: 0; top: auto; height: calc(64px + env(safe-area-inset-bottom, 0px)); padding-bottom: env(safe-area-inset-bottom, 0px); box-sizing: border-box; z-index: var(--rs-z-nav); border-radius: 16px 16px 0 0; background: var(--vf-navbg); border: 1px solid var(--vf-border); box-shadow: var(--vf-e2);  padding: 0; }
.vf-bnav .rs-bottomnav__inner { position: relative; height: 100%; max-width: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); }
.vf-bnav .rs-bottomnav__item { position: relative; z-index: 1; min-height: 0; height: 100%; min-width: 0; padding: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; color: var(--vf-text-2); font: var(--vf-t-caption-md); background: none; border: 0; text-decoration: none; }
.vf-bnav .rs-bottomnav__item::before { content: none; }
.vf-bnav .rs-bottomnav__item[aria-current="page"] { color: var(--vf-accent-text); font-weight: 600; }
.vf-bnav__ico { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; }
.vf-bnav__ico .rs-icon { width: 24px; height: 24px; }
.vf-bnav__pill { position: absolute; top: 8px; left: calc((var(--vf-bnav-i, 0) * 20% + 10%) - 28px); width: 56px; height: 32px; border-radius: 999px; background: var(--vf-accent-subtle); }
.vf-bnav .vf-bnav__deposit { justify-content: flex-start; padding-bottom: 8px; color: var(--vf-text-2); }
.vf-bnav__fab { width: 52px; height: 52px; margin-top: -22px; flex: none; border-radius: 999px; background: var(--vf-accent); color: var(--vf-on-accent); box-shadow: 0 6px 16px color-mix(in srgb, var(--vf-accent) 35%, transparent), 0 0 0 4px var(--vf-surface-1); display: flex; align-items: center; justify-content: center; transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-bnav__fab .rs-icon { width: 24px; height: 24px; }
body.rs-has-bottomnav { padding-bottom: calc(104px + env(safe-area-inset-bottom, 0px)); }   /* 64 px bar + 22 px raised Deposit button + 18 px air */
html:has(> body.rs-has-bottomnav) { scroll-padding-bottom: calc(104px + env(safe-area-inset-bottom, 0px)); }   /* keyboard focus never lands under the bar */
@media (min-width: 1024px) { .rs-bottomnav.vf-bnav { display: none; } body.rs-has-bottomnav { padding-bottom: 0; } html:has(> body.rs-has-bottomnav) { scroll-padding-bottom: 0; } }
/* Keyboard open (global-theme.js sets html.vf-kb-open from visualViewport): fixed bars step aside. */
html.vf-kb-open .rs-bottomnav.vf-bnav, html.vf-kb-open .vf-actionbar--fixed, html.vf-kb-open .vf-pd__action, html.vf-kb-open .pay-page .pay-actions, html.vf-kb-open #globalSaveBar { display: none; }

/* ---------- Slim footer (phase 12): trust line + © / links; column on phones, row >= 1024 ---------- */
.vf-foot.elaina-footer { margin-top: 48px; padding: 12px var(--vf-page-pad) 16px; border-top: 1px solid var(--vf-border); background: none; display: flex; flex-direction: column; align-items: center; justify-content: space-between; gap: 4px 24px; font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-foot__trust { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 16px; }
.vf-foot__trust span { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.vf-foot__trust .rs-icon { width: 14px; height: 14px; }
.vf-foot__links { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; }
.vf-foot__copy { padding: 0 8px; }
.vf-foot__links a, .vf-foot__links button { height: 48px; padding: 0 8px; display: inline-flex; align-items: center; color: var(--vf-text-1); white-space: nowrap; text-decoration: none; background: none; border: 0; font: inherit; cursor: pointer; }
.vf-foot__links a:hover, .vf-foot__links button:hover { color: var(--vf-accent-text); }
@media (min-width: 1024px) { .vf-foot.elaina-footer { flex-direction: row; padding-bottom: 16px; } }
body:not(.rs-has-bottomnav) .vf-foot.elaina-footer { padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }

/* ---------- Menu sheet (phase 12 E12): phone bottom sheet r20 + handle; >= 1024 panel 380 under the menu button ---------- */
.rs-menu.vf-menu { position: fixed; inset: auto 0 0 0; top: auto; left: 0; right: 0; width: 100%; max-width: 100%; height: auto; max-height: calc(100dvh - 24px); margin: 0; padding: 8px 0 calc(24px + env(safe-area-inset-bottom, 0px)); border: 0; border-radius: 20px 20px 0 0; background: var(--vf-surface-2); color: var(--vf-text-1); box-shadow: var(--vf-e2); overflow-y: auto; overscroll-behavior: contain; }
.rs-menu.vf-menu::backdrop { background: var(--vf-scrim); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
html.dark-mode .rs-menu.vf-menu::backdrop { background: var(--vf-scrim); }
.vf-menu .rs-menu__panel { min-height: 0; display: flex; flex-direction: column; }
.vf-menu__handle { align-self: center; width: 36px; height: 4px; border-radius: 2px; background: var(--vf-border-strong); margin: 4px 0 8px; flex: none; }
.vf-menu .rs-menu__head { padding: 0 8px 0 20px; min-height: 48px; border: 0; display: flex; align-items: center; justify-content: space-between; }
.vf-menu .rs-menu__title { margin: 0; font: var(--vf-t-h3); }
.vf-menu .rs-menu__head .rs-icon-btn { width: 48px; height: 48px; color: var(--vf-text-2); }
.vf-menu__account { margin: 4px 16px 8px; padding: 12px 16px; border-radius: var(--vf-r-card); background: var(--vf-accent-subtle); display: flex; align-items: center; gap: 12px; min-width: 0; }

.vf-menu__who { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.vf-menu__name { font: var(--vf-t-ui-strong); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vf-menu__saldo { font: 600 14px/20px var(--vf-font-num); color: var(--vf-accent-text); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vf-menu__account .vf-btn { flex: none; min-height: 48px; padding: 0 16px; font-size: 14px; }
.vf-menu .rs-menu__group { margin: 0; padding: 12px 20px 4px; font: var(--vf-t-caption-strong); color: var(--vf-text-2); letter-spacing: 0; text-transform: none; }
.vf-menu .rs-menu__list { list-style: none; margin: 0; padding: 0; gap: 0; }
.vf-menu .rs-menu__item { width: 100%; min-height: 48px; padding: 0 12px 0 20px; border: 0; border-radius: 0; background: none; display: flex; align-items: center; gap: 16px; font: 500 16px/24px var(--vf-font); color: var(--vf-text-1); text-decoration: none; text-align: left; cursor: pointer; }
.vf-menu .rs-menu__item > span:first-of-type { flex: 1; min-width: 0; }
.vf-menu .rs-menu__item .rs-icon { width: 20px; height: 20px; color: var(--vf-text-2); flex: none; }
.vf-menu .rs-menu__item:hover { background: var(--vf-surface-3); }
.vf-menu .rs-menu__item[aria-current="page"] { background: none; color: var(--vf-accent-text); font-weight: 600; }
.vf-menu .rs-menu__item[aria-current="page"] .rs-icon { color: var(--vf-accent-text); }
.vf-menu .rs-menu__item--danger, .vf-menu .rs-menu__item--danger .rs-icon { color: var(--vf-danger); }
.vf-menu__music { margin: 8px 16px 0; padding: 8px 8px 8px 16px; border: 1px solid var(--vf-border); border-radius: var(--vf-r-card); display: flex; align-items: center; gap: 12px; }
.vf-menu__music-icon { color: var(--vf-text-2); display: inline-flex; }
.vf-menu__music-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.vf-menu__music-text span:first-child { font: var(--vf-t-ui); }
.vf-menu__music-text span:last-child { font: var(--vf-t-caption); color: var(--vf-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vf-menu__music-btn { width: 48px; height: 48px; flex: none; border: 0; border-radius: 12px; background: var(--vf-surface-3); color: var(--vf-text-1); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
.vf-menu__music-btn[aria-pressed="true"] { background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
@media (min-width: 1024px) {
  .rs-menu.vf-menu { inset: calc(var(--vf-top-h) + 12px) 16px auto auto; width: 380px; max-height: calc(100dvh - var(--vf-top-h) - 24px); border-radius: 16px; padding: 8px 0 16px; }
  .vf-menu__handle { display: none; }
}

.vf-qty { align-self: flex-start; }

/* =========================================================================
   PHASE 11 — ONE POPUP FAMILY (public/js/vf-popup.js, "Popups" board)
   ========================================================================= */
:root { --rs-scrim: var(--vf-scrim); --rs-scrim-solid: var(--vf-scrim-solid); --rs-scrim-blur: 6px; }
html.dark-mode { --rs-scrim: var(--vf-scrim); --rs-scrim-solid: var(--vf-scrim-solid); }
.vf-pop {
  padding: 24px; margin: auto; border: 0; width: min(420px, calc(100vw - 32px)); max-height: calc(100dvh - 32px);
  border-radius: var(--vf-r-card); background: var(--vf-surface-2); color: var(--vf-text-1); box-shadow: var(--vf-e3);
  display: none; flex-direction: column; gap: 16px; overflow: auto; overscroll-behavior: contain;
}
.vf-pop[open] { display: flex; }
.vf-pop::backdrop { background: var(--vf-scrim); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .vf-pop::backdrop { background: var(--vf-scrim-solid); } }
.vf-pop__icon { width: 48px; height: 48px; border-radius: var(--vf-r-ctl); display: inline-flex; align-items: center; justify-content: center; flex: none; background: var(--vf-info-subtle); color: var(--vf-info); }
.vf-pop__icon--danger { background: var(--vf-danger-subtle); color: var(--vf-danger); }
.vf-pop__icon--warning { background: var(--vf-warning-subtle); color: var(--vf-warning); }
.vf-pop__icon--success { background: var(--vf-success-subtle); color: var(--vf-success); }
.vf-pop__icon--neutral { background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
.vf-pop__text { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.vf-pop__title { margin: 0; font: var(--vf-t-h3); color: var(--vf-text-1); }
.vf-pop__body { margin: 0; font: var(--vf-t-body-sm); color: var(--vf-text-2); white-space: pre-line; overflow-wrap: anywhere; text-wrap: pretty; }
.vf-pop__actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.vf-pop__actions--one { grid-template-columns: 1fr; }
.vf-pop__actions .vf-btn { min-width: 0; padding: 0 12px; font-size: 14px; white-space: normal; text-align: center; line-height: 20px; }
.vf-pop--wide { width: min(480px, calc(100vw - 32px)); }
/* Bottom sheet: phones slide up from the bottom; ≥ 1024 a centred dialog (max 480, handle hidden). */
.vf-pop--sheet { width: 100%; max-width: 100%; margin: auto 0 0; padding: 8px 16px calc(24px + env(safe-area-inset-bottom, 0px)); border-radius: 20px 20px 0 0; max-height: 85dvh; box-shadow: var(--vf-e2); gap: 12px; }
.vf-pop__handle { align-self: center; width: 36px; height: 4px; border-radius: 2px; background: var(--vf-border-strong); flex: none; margin-top: 4px; }
.vf-pop__head { display: flex; align-items: center; gap: 8px; touch-action: none; min-height: 48px; padding-left: 4px; }
.vf-pop__head .vf-pop__title { flex: 1; }
.vf-pop__close { margin-right: -8px; }
.vf-pop__content { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.vf-pop__ref { display: flex; align-items: center; gap: 8px; padding: 4px 4px 4px 12px; border-radius: 12px; background: var(--vf-surface-3); }
.vf-pop__ref-text { flex: 1; min-width: 0; display: flex; flex-direction: column; font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-pop__ref b { font: var(--vf-t-code); color: var(--vf-text-1); overflow-wrap: anywhere; }
/* Help sheet (phase 12 E12b): lead, two 72px option rows, then the ID row. */
.vf-help__lead { margin: -4px 4px 0; font: var(--vf-t-body-sm); color: var(--vf-text-2); text-wrap: pretty; }
.vf-help__opts { display: flex; flex-direction: column; gap: 8px; }
.vf-help__opt { min-height: 72px; width: 100%; border: 1px solid var(--vf-border); border-radius: var(--vf-r-card); padding: 12px 12px 12px 16px; display: flex; align-items: center; gap: 12px; background: var(--vf-surface-2); color: var(--vf-text-1); text-decoration: none; text-align: left; font: inherit; cursor: pointer; }
.vf-help__opt:hover { background: var(--vf-surface-3); color: var(--vf-text-1); }
.vf-help__opt > .rs-icon { color: var(--vf-text-3); flex: none; }
.vf-help__tile { width: 40px; height: 40px; flex: none; border-radius: 12px; background: var(--vf-accent-subtle); color: var(--vf-accent-text); display: inline-flex; align-items: center; justify-content: center; }
.vf-help__tile--wa { background: var(--vf-success-subtle); color: var(--vf-success); }
.vf-help__txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.vf-help__txt span:first-child { font: var(--vf-t-btn); }
.vf-help__txt span:last-child { font: var(--vf-t-caption); color: var(--vf-text-2); }
@media (min-width: 1024px) {
  .vf-pop--sheet { width: min(480px, calc(100vw - 32px)); margin: auto; padding: 24px; border-radius: var(--vf-r-card); max-height: calc(100dvh - 64px); }
  /* Anchored panel under the menu button (menu + help sheets, E12 / E12b at 1280): 380 wide, r16. */
  .vf-pop--sheet.vf-pop--anchor { position: fixed; inset: calc(var(--vf-top-h) + 12px) 16px auto auto; width: 380px; margin: 0; padding: 8px 16px 16px; border-radius: 16px; max-height: calc(100dvh - var(--vf-top-h) - 24px); }
  .vf-pop__handle { display: none; }
}
/* Toast: inverse surface, one at a time. Phone: 16px above the bottom nav. Desktop: top-centre, 24px under the bar. */
.vf-toast {
  position: fixed; z-index: var(--rs-z-toast); left: 16px; right: 16px;
  bottom: calc(64px + env(safe-area-inset-bottom, 0) + 16px);
  display: flex; align-items: center; gap: 12px; padding: 4px 4px 4px 16px; min-height: 56px;
  border-radius: var(--vf-r-ctl); background: var(--vf-inverse); color: var(--vf-on-inverse); box-shadow: var(--vf-e2);
  opacity: 0; transform: translateY(8px); transition: opacity var(--vf-dur, 140ms) var(--vf-ease, ease-out), transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
body:not(.rs-has-bottomnav) .vf-toast { bottom: calc(16px + env(safe-area-inset-bottom, 0)); }
.vf-toast.is-shown { opacity: 1; transform: none; }
.vf-toast.is-leaving { opacity: 0; transform: translateY(8px); transition-duration: var(--vf-dur, 140ms); transition-timing-function: var(--vf-ease-out); }
.vf-toast__icon { display: inline-flex; flex: none; color: var(--vf-inverse-success); }
.vf-toast--warning .vf-toast__icon { color: var(--vf-inverse-warning); }
.vf-toast--danger .vf-toast__icon { color: var(--vf-inverse-danger); }
.vf-toast--info .vf-toast__icon { color: var(--vf-inverse-action); }
.vf-toast__text { flex: 1; min-width: 0; font: var(--vf-t-ui); overflow-wrap: anywhere; }
.vf-toast__action, .vf-toast__close { flex: none; min-height: 48px; min-width: 48px; display: inline-flex; align-items: center; justify-content: center; padding: 0 12px; border: 0; background: none; color: var(--vf-inverse-action); font: var(--vf-t-ui-strong); text-decoration: none; white-space: nowrap; cursor: pointer; border-radius: var(--vf-r-8); }
.vf-toast__close { padding: 0; }
@media (min-width: 1024px) {
  .vf-toast, body:not(.rs-has-bottomnav) .vf-toast { top: calc(64px + 24px); bottom: auto; left: 50%; right: auto; width: min(420px, calc(100vw - 32px)); transform: translate(-50%, -8px); }
  .vf-toast.is-shown { transform: translate(-50%, 0); }
  .vf-toast.is-leaving { transform: translate(-50%, -8px); }
}
@media (prefers-reduced-motion: reduce) { .vf-toast, .vf-toast.is-leaving { transform: none; } @media (min-width: 1024px) { .vf-toast, .vf-toast.is-shown, .vf-toast.is-leaving { transform: translateX(-50%); } } }
/* Info tooltip: inverse r-12, max 260, 8px from its 48px (.bi) button. */
.vf-tip { position: absolute; z-index: calc(var(--rs-z-toast) + 1); max-width: min(260px, calc(100vw - 16px)); padding: 12px; border-radius: var(--vf-r-ctl); background: var(--vf-inverse); color: var(--vf-on-inverse); font: var(--vf-t-small); box-shadow: var(--vf-e2); }
.vf-tip::before { content: ''; position: absolute; left: calc(var(--arrow-x, 50%) - 5px); width: 10px; height: 10px; background: inherit; transform: rotate(45deg); }
.vf-tip.is-above::before { bottom: -5px; }
.vf-tip.is-below::before { top: -5px; }
.vf-tip-btn { width: 48px; height: 48px; margin: -16px -12px; display: inline-flex; align-items: center; justify-content: center; border: 0; background: none; color: var(--vf-accent-text); cursor: pointer; vertical-align: middle; }
/* Pages' own overlays normalised by RSPopup get the same look. */
[data-rs-surface="dialog"][data-rs-surface], .modal-content.modal-content { border-radius: var(--vf-r-card) !important; box-shadow: var(--vf-e3); background: var(--vf-surface-2); color: var(--vf-text-1); }
[data-rs-scrim][data-rs-scrim], dialog::backdrop, .modal-backdrop.modal-backdrop { background: var(--vf-scrim) !important; -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }

/* Quick view (Popups board 6.2) — shares .vf-pop / .vf-pop--sheet. */
.vf-qv__head { display: flex; gap: 12px; align-items: flex-start; }
.vf-qv__thumb { position: relative; width: 88px; height: 88px; flex: none; border-radius: var(--vf-r-ctl); background: var(--vf-surface-3); color: var(--vf-text-3); overflow: hidden; display: inline-flex; align-items: center; justify-content: center; }
.vf-qv__thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.vf-qv__text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.vf-qv__title { margin: 0; font: 600 18px/24px var(--vf-font); color: var(--vf-text-1); overflow-wrap: anywhere; }
.vf-qv__price-row { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 8px; }
.vf-qv__price { font: 600 18px/26px var(--vf-font); color: var(--vf-accent-text); font-variant-numeric: tabular-nums; }
.vf-qv__from, .vf-qv__was { font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-qv__meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.vf-qv__meta:not(:has(> :not([hidden]))) { display: none; }
.vf-qv__rating { display: inline-flex; align-items: center; gap: 4px; font: 600 14px/20px var(--vf-font); color: var(--vf-text-2); }
.vf-qv__rating .rs-icon { color: var(--vf-warning); }
.vf-qv__close { margin: -8px -8px 0 0; }
.vf-qv__desc { margin: 0; font: 400 14px/20px var(--vf-font); color: var(--vf-text-2); white-space: pre-wrap; overflow-wrap: anywhere; text-wrap: pretty; }
.vf-qv__foot { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.vf-qv__foot > [hidden] { display: none; }
.vf-qv__foot > .vf-btn--block { grid-column: 1 / -1; }
.vf-qv [hidden] { display: none !important; }

/* ---------- Icons (phase 11 scope 3): SVG sprite only ----------
   Converted icons keep the class "bi" and size 'em', so they follow the font size exactly as the old icon font did. */
svg.bi { display: inline-block; width: 1em; height: 1em; flex-shrink: 0; vertical-align: -0.125em; fill: currentColor; }
.vf-ic-c-yellow { color: var(--accent-yellow); }
.vf-ic-c-purple { color: var(--accent-purple); }
.vf-ic-c-blue { color: var(--accent-blue, var(--vf-accent-text)); }
.vf-ic-c-cyan { color: var(--accent-cyan); }
.vf-ic-c-orange { color: var(--accent-orange); }
.vf-ic-c-green { color: var(--accent-green); }
.vf-ic-muted { color: var(--vf-text-2); }
.vf-ic-warning { color: var(--vf-warning); }
.vf-ic-success { color: var(--vf-success); }
.vf-ic-danger { color: var(--vf-danger); }
.vf-ic-accent { color: var(--vf-accent-text); }
.vf-ic-fs-sm { font-size: var(--rs-ts-sm); }
.vf-ic-fs-base { font-size: var(--rs-ts-base); }
.vf-ic-fs-lg { font-size: var(--rs-ts-lg); }
.vf-ic-fs-xl { font-size: var(--rs-ts-xl); }
.vf-ic-fs-2xl { font-size: var(--rs-ts-2xl); }
.vf-ic-fs-3xl { font-size: var(--rs-ts-3xl); }
svg.vf-ic-block { display: block; }
.vf-ic-mb-8 { margin-bottom: var(--rs-s-8); }
.vf-ic-mt-4 { margin-top: var(--rs-s-4); }
.vf-ic-mr-4 { margin-right: var(--rs-s-4); }
.vf-ic-mr-8 { margin-right: var(--rs-s-8); }
.vf-ic-dim { opacity: .5; }
.vf-ic-noshrink { flex-shrink: 0; }
.vf-ic-field-lead { position: absolute; left: .75rem; top: 50%; transform: translateY(-50%); color: var(--vf-text-3); font-size: var(--rs-ts-sm); }

/* Scope 4: Suntik Sosmed is its own page — a link at the end of the category tabs, not a filter. */
.rs-seg__item.vf-seg-link { gap: 4px; text-decoration: none; color: var(--vf-accent-text); }
.rs-seg__item.vf-seg-link .rs-icon { flex-shrink: 0; }

html, body { margin: 0; }

/* =====================================================================
   PHASE 12 — DASHBOARD (D1 A1 / A1b, C Dashboard). Phones: one column, page 16 · section 24 · grid 8.
   >= 1024: hero + stats side by side (1fr 392), banner full width, then main column + 392 side column with
   the server status (sticky top 88). Max width 1200 (lists).
   ===================================================================== */
.vf-dash { display: flex; flex-direction: column; gap: var(--vf-section-gap); width: 100%; max-width: calc(var(--vf-w-list) + 2 * var(--vf-page-pad)); margin: 0 auto; padding: 16px var(--vf-page-pad) 0; }
.vf-dash > script, .vf-dash > style, .vf-dash > .rs-visually-hidden { position: absolute; }
.vf-dash__top { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--vf-grid-gap) 24px; }
.vf-saldo-hero { background: var(--vf-hero); color: var(--vf-hero-text); border-radius: 20px; border: var(--vf-hero-border); padding: var(--vf-hero-pad); display: flex; flex-direction: column; gap: 16px; box-shadow: var(--vf-hero-shadow); min-width: 0; }
.vf-saldo-hero__text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.vf-saldo-hero__hello { font: var(--vf-t-body-sm); color: var(--vf-hero-muted); overflow-wrap: anywhere; }
.vf-saldo-hero__amount { font: var(--vf-t-saldo); letter-spacing: -0.02em; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.vf-saldo-hero__actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.vf-saldo-hero__btn { height: 48px; border-radius: 12px; background: var(--vf-hero-chip); color: var(--vf-hero-text); display: flex; align-items: center; justify-content: center; gap: 8px; font: var(--vf-t-btn); text-decoration: none; min-width: 0; transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-saldo-hero__btn:hover { color: var(--vf-hero-text); filter: brightness(1.08); }
.vf-saldo-hero__btn--primary { background: var(--vf-hero-text); color: var(--vf-hero); }
.vf-saldo-hero__btn--primary:hover { color: var(--vf-hero); }
.vf-saldo-hero__btn .rs-icon { width: 20px; height: 20px; flex: none; }
.vf-stats { margin: 0; background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 16px; box-shadow: var(--vf-e1); display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 16px 4px; align-content: center; }
.vf-stats__item { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; padding: 0 8px; min-width: 0; }
.vf-stats__item + .vf-stats__item { border-left: 1px solid var(--vf-border); }
.vf-stats dt { font: var(--vf-t-caption); color: var(--vf-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.vf-stats dd { margin: 0; font: 600 16px/24px var(--vf-font-num); font-variant-numeric: tabular-nums; color: var(--vf-text-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
@media (max-width: 429.98px) { .vf-stats dd { font-size: 16px; } }
@media (max-width: 374.98px) { .vf-stats__item { padding: 0 8px; } .vf-stats dd { font-size: 14px; } }
.vf-dash__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--vf-section-gap) 24px; align-items: start; }
.vf-dash__main { display: flex; flex-direction: column; gap: var(--vf-section-gap); min-width: 0; }
.vf-dash__aside { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
@media (min-width: 1024px) {
  .vf-dash__top, .vf-dash__grid { grid-template-columns: minmax(0, 1fr) 392px; }
  .vf-dash__aside { position: sticky; top: 88px; }
}
/* Section heads (title Sora --vf-t-sec, description 13/18, "Lihat semua" 48px). */
.vf-sec-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.vf-sec-head__text { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.vf-sec-title { margin: 0; font: var(--vf-t-sec); color: var(--vf-text-1); letter-spacing: 0; }
.vf-sec-sub { font: var(--vf-t-small); color: var(--vf-text-2); }
.vf-sec-link { flex: none; height: 48px; padding: 0 4px; display: inline-flex; align-items: center; gap: 4px; font: var(--vf-t-ui-strong); color: var(--vf-accent-text); white-space: nowrap; text-decoration: none; }
.vf-sec-link:hover { color: var(--vf-accent-hover); text-decoration: underline; text-underline-offset: 3px; }
.vf-dash__aside .vf-sec-title { margin-bottom: 0; }
.vf-dash .showcase .rs-hscroll { --hscroll-bleed: var(--vf-page-pad); }
@media (min-width: 1024px) { .vf-dash .showcase .rs-hscroll { --hscroll-bleed: 0px; } }
/* Category groups in "Semua produk". */
.vf-dash .cat-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.vf-dash .cat-heading-title { font: var(--vf-t-h3); color: var(--vf-text-1); margin: 0; }
.vf-dash .cat-heading-title .dash-count { font: var(--vf-t-caption-md); color: var(--vf-text-2); margin-left: 4px; }
.vf-dash .cat-heading-link { text-decoration: none; display: inline-flex; align-items: center; gap: 4px; min-height: 48px; padding: 0 4px; font: var(--vf-t-ui-strong); color: var(--vf-accent-text); flex-shrink: 0; }
.vf-dash .cat-heading-link .rs-icon { display: none; }
.vf-dash .cat-heading-link[hidden] { display: none; }

/* Announcement */
.notice-bar { display: flex; align-items: flex-start; gap: 8px; padding: 12px 16px; background: var(--vf-accent-subtle); border-radius: 12px; }
.notice-icon { font-size: 16px; color: var(--vf-accent-text); flex-shrink: 0; margin-top: 2px; }
.notice-marquee { flex: 1; min-width: 0; }
.notice-text { font: var(--vf-t-small); color: var(--vf-text-2); overflow-wrap: anywhere; }
.notice-text strong { color: var(--vf-text-1); font-weight: 600; }

/* ---------- Banner (phase 12 C Dashboard): 148 → 280 tall, r16, 48px round arrows (s2), dots 6px (active 16×6
   accent) in 24×48 targets, pause 28px in a 48 target; controls only with 2+ banners. ---------- */
.banner-wrap { position: relative; }
.banner-inner { position: relative; border-radius: 16px; overflow: hidden; border: 1px solid var(--vf-border); background: var(--vf-surface-3); }
.banner-slide { display: none; position: relative; width: 100%; height: 148px; border-radius: 0; overflow: hidden; color: var(--vf-text-1); }
.banner-slide.active { display: block; }
.banner-inner .banner-slide[hidden] { display: none; }
.banner-slide-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; -webkit-user-drag: none; user-select: none; }
@media (min-width: 600px) { .banner-slide { height: auto; aspect-ratio: 8 / 3; max-height: 280px; } }
@media (min-width: 1024px) { .banner-slide { aspect-ratio: auto; height: 280px; } }
.banner-ctrls { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.banner-ctrls[hidden] { display: none; }
.banner-ctrls > * { pointer-events: auto; }
.banner-arrow { position: absolute; top: 50%; margin-top: -24px; width: 48px; height: 48px; padding: 0; border-radius: 999px; background: var(--vf-surface-2); border: 1px solid var(--vf-border); color: var(--vf-text-1); box-shadow: var(--vf-e1); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.banner-arrow--prev { left: 4px; }
.banner-arrow--next { right: 4px; }
.banner-arrow .rs-icon { width: 16px; height: 16px; font-size: 16px; }
.banner-arrow::before, .banner-pause::before { content: none; }
.banner-dots { position: absolute; left: 50%; bottom: 0; transform: translateX(-50%); height: 48px; display: flex; align-items: center; gap: 0; padding: 0; background: none; box-shadow: none; }
.banner-dots button { width: 24px; height: 48px; padding: 0; border: 0; background: none; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
.banner-dots button::before { content: none; }
.banner-dots button::after { content: ''; width: 6px; height: 6px; border-radius: 3px; background: var(--vf-text-3); }
.banner-dots button.active::after { width: 16px; background: var(--vf-accent); }
.banner-pause { position: absolute; bottom: 0; left: calc(50% + var(--bn-dots-w, 36px)); width: 48px; height: 48px; padding: 0; border: 0; background: none; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; color: var(--vf-text-1); }
.banner-pause > .rs-icon { box-sizing: content-box; width: 14px; height: 14px; padding: 6px; border-radius: 999px; background: var(--vf-surface-2); border: 1px solid var(--vf-border); }
.banner-arrow:focus-visible, .banner-pause:focus-visible, .banner-dots button:focus-visible { outline: 2px solid var(--vf-focus); outline-offset: -2px; border-radius: 999px; }
@media (min-width: 1024px) { .banner-arrow--prev { left: 12px; } .banner-arrow--next { right: 12px; } }

/* Search (kept from phase 11: the bar has no search) — 48px field, r12. */
.search-bar-wrap { margin-bottom: 12px; }
.search-bar-inner { display: flex; align-items: center; gap: 8px; min-height: 48px; padding: 0 16px; background: var(--vf-surface-2); border: 1px solid var(--vf-border-strong); border-radius: 12px; }
.search-bar-inner:focus-within { border-color: var(--vf-accent); box-shadow: 0 0 0 2px var(--vf-surface-1), 0 0 0 4px var(--vf-accent); }
.search-bar-icon { color: var(--vf-text-3); font-size: 16px; flex-shrink: 0; }
.search-bar-input { flex: 1; min-width: 0; align-self: stretch; min-height: 46px; background: transparent; border: 0; outline: none; color: var(--vf-text-1); font: var(--vf-t-body-lg); }
.search-bar-input::placeholder { color: var(--vf-text-3); }
.search-no-result { grid-column: 1 / -1; }

/* Category chips: Semua + admin categories (40 visual / 48 target), divider, Suntik Sosmed ↗. Phone scrolls, >= 1024 wraps. */
.vf-catchips { display: flex; gap: 8px; overflow-x: auto; margin: 0 calc(-1 * var(--vf-page-pad)) 12px; padding: 4px var(--vf-page-pad); scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.vf-catchips::-webkit-scrollbar { display: none; }
.vf-catchip { flex: none; display: inline-flex; align-items: center; gap: 8px; height: 40px; margin: 4px 0; padding: 0 16px; border-radius: 999px; background: var(--vf-surface-2); color: var(--vf-text-1); border: 1px solid var(--vf-border); font: var(--vf-t-ui); white-space: nowrap; cursor: pointer; text-decoration: none; transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-catchip::before { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: 48px; margin-top: -24px; }
.vf-catchip:hover { background: var(--vf-surface-3); }
.vf-catchip:focus-visible { outline: 2px solid var(--vf-focus); outline-offset: 2px; }
.vf-catchip.active, .vf-catchip[aria-pressed="true"] { background: var(--vf-text-1); color: var(--vf-surface-1); border-color: var(--vf-text-1); }
.vf-catchip[hidden] { display: none; }
.vf-catchips__divider { flex: none; width: 1px; height: 24px; align-self: center; background: var(--vf-border); }
.vf-catchip--link { color: var(--vf-accent-text); padding: 0 16px; }
.vf-catchip--link .rs-icon { width: 14px; height: 14px; }
.vf-catchip--link:hover { color: var(--vf-accent-text); }
@media (min-width: 1024px) { .vf-catchips { flex-wrap: wrap; overflow: visible; margin: 0 0 12px; padding: 0; } }

/* Status server panel rows (64 tall): tile · name + dot status · "Lihat paket". */
.srv-list { list-style: none; margin: 0; padding: 0; overflow: hidden; }
.srv-row { display: flex; align-items: center; gap: 12px; min-height: 64px; padding: 8px 4px 8px 16px; }
.srv-row + .srv-row { border-top: 1px solid var(--vf-border); }
.vf-tile { width: var(--vf-ico-tile); height: var(--vf-ico-tile); flex: none; border-radius: 12px; background: var(--vf-surface-3); color: var(--vf-text-2); display: inline-flex; align-items: center; justify-content: center; }
.vf-tile .rs-icon { width: var(--vf-ico); height: var(--vf-ico); }
.srv-row__main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.srv-row__name { font: var(--vf-t-ui-strong); color: var(--vf-text-1); }
.srv-row__state { display: inline-flex; align-items: center; gap: 4px; font: var(--vf-t-caption); color: var(--vf-text-2); font-variant-numeric: tabular-nums; }
.srv-row__dot { width: 8px; height: 8px; flex: none; border-radius: 999px; background: currentColor; }
.srv-row__state.is-online { color: var(--vf-success); }
.srv-row__state.is-down { color: var(--vf-danger); }
.srv-row__ping { color: var(--vf-text-2); }
.srv-row__ping::before { content: '·'; margin: 0 4px; }
.srv-row__link { flex-shrink: 0; height: 48px; padding: 0 12px; display: inline-flex; align-items: center; font: var(--vf-t-small-strong); color: var(--vf-accent-text); white-space: nowrap; text-decoration: none; border-radius: 8px; }
.srv-row__link:hover { background: var(--vf-surface-3); }

/* ---------- Product card (phase 12 C Dashboard): r12, media 1:1 → 16:10, tinted placeholder, 3 lines ---------- */
.vf-pgrid, .rs-product-grid.vf-pgrid { display: grid; --pg-track: max(var(--pg-floor, 150px), (100% - (var(--pg-cols, 3) - 1) * var(--vf-grid-gap)) / var(--pg-cols, 3) - 0.5px); grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--pg-track)), 1fr)); gap: var(--vf-grid-gap); }   /* phase 18: admin-chosen columns, container-aware floor */
.vf-pcard { position: relative; display: flex; flex-direction: column; min-width: 0; padding: 0; background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: var(--vf-r-ctl); box-shadow: var(--vf-e1); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }   /* UX-CARD-01: no box-shadow transition, no clip (the media clips itself) */
.vf-pcard::before { content: none; }
.vf-pcard:hover { box-shadow: var(--vf-e2); }
.vf-pcard:has(.vf-pcard__link:focus-visible) { outline: 2px solid var(--vf-focus); outline-offset: 2px; }
:root { --vf-ph-l: 0.95; --vf-ph-c: 0.035; --vf-ic-l: 0.48; --vf-ic-c: 0.15; }
html.dark-mode { --vf-ph-l: 0.27; --vf-ph-c: 0.05; --vf-ic-l: 0.84; --vf-ic-c: 0.11; }
.vf-pcard__media { position: relative; aspect-ratio: 1 / 1; background: var(--vf-surface-3); background: oklch(var(--vf-ph-l) var(--vf-ph-c) var(--pc-h, 240)); color: var(--vf-text-2); color: oklch(var(--vf-ic-l) var(--vf-ic-c) var(--pc-h, 240)); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.vf-pcard__ph { display: inline-flex; }
.vf-pcard__ph .rs-icon { width: 26px; height: 26px; }
.vf-pcard__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.vf-pcard__body { padding: 8px 8px 8px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.vf-pcard__name { margin: 0; font: var(--vf-t-small-md); color: var(--vf-text-1); min-height: 36px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.vf-pcard__link { color: inherit; text-decoration: none; background: none; border: 0; padding: 0; font: inherit; text-align: inherit; cursor: pointer; }
.vf-pcard__link::after { content: ''; position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
/* WP6A 6.1 (USR-GLB-06): price that could not be loaded -> note + "Coba lagi" above the card link overlay */
.vf-pcard__note--err { color: var(--vf-danger); }
.vf-pcard__link:focus-visible { outline: none; }
.vf-pcard__price { margin: 0; font: var(--vf-t-price-sm); font-variant-numeric: tabular-nums; color: var(--vf-text-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vf-pcard__from { font: var(--vf-t-caption); color: var(--vf-text-2); margin-right: 3px; text-transform: lowercase; }
.vf-pcard__was { font: var(--vf-t-caption); color: var(--vf-text-3); }
.vf-pcard__note { font: var(--vf-t-small-md); color: var(--vf-text-2); }
.vf-pcard__sk { display: inline-block; width: 64px; height: 14px; border-radius: 4px; vertical-align: middle; }
/* Fact line: 11/14 as drawn (C Dashboard) — the one place below the 12px floor, so "Proses otomatis" fits a 3-up card. */
.vf-pcard__fact { margin: 0; display: flex; align-items: center; gap: 4px; font: var(--vf-t-caption); color: var(--vf-text-2); white-space: nowrap; overflow: hidden; min-width: 0; }
@media (max-width: 374.98px) { .vf-pcard__fact .rs-icon { display: none; } }
@media (min-width: 1024px) { .vf-pcard__fact { font-size: 12px; line-height: 16px; } }
.vf-pcard__fact span { overflow: hidden; text-overflow: ellipsis; }
.vf-pcard__fact .rs-icon { width: 12px; height: 12px; flex: none; }
.vf-pcard__fact--auto { color: var(--vf-success); }
.vf-pcard__fact--out { color: var(--vf-danger); }
.vf-pcard.is-soldout .vf-pcard__media > :not(.vf-pcard__qv) { filter: grayscale(.6); opacity: .7; }   /* the quick-view eye stays on top and tappable */
.rs-catgroup { gap: var(--vf-grid-gap); }
@media (max-width: 359.98px) { .vf-pcard__body { padding: 8px; } }
@media (min-width: 1024px) {
  .vf-pcard__media { aspect-ratio: 16 / 10; }
  .vf-pcard__ph .rs-icon { width: 32px; height: 32px; }
  .vf-pcard__body { padding: 12px 16px 16px; }
  .vf-pcard__name { font-size: 14px; line-height: 20px; min-height: 40px; }
}

/* Empty / no-result card (D1 S5, S8): centred card, 48 icon circle, title, body, actions. */
.vf-empty { grid-column: 1 / -1; background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 16px; box-shadow: var(--vf-e1); padding: 32px var(--vf-card-pad); display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px; }
.vf-empty__icon { width: 48px; height: 48px; border-radius: 999px; background: var(--vf-surface-3); color: var(--vf-text-2); display: inline-flex; align-items: center; justify-content: center; margin-bottom: 4px; }
.vf-empty__icon--danger { background: var(--vf-danger-subtle); color: var(--vf-danger); }
.vf-empty__title { margin: 0; font: 600 16px/24px var(--vf-font-head); color: var(--vf-text-1); overflow-wrap: anywhere; text-wrap: balance; }
.vf-empty__body { margin: 0; max-width: 40ch; font: var(--vf-t-body-sm); color: var(--vf-text-2); text-wrap: pretty; }
.vf-empty__actions { margin-top: 8px; display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.vf-empty__actions .vf-btn { min-height: 48px; }

/* =====================================================================
   PHASE 11 SCOPE 5 — PRODUCT DETAIL (board S3 "Product detail", panel pages)
   Phones: one column (page-pad 16, card gap 16), fixed action bar (total + "Beli sekarang").
   >= 1024: main column + 392px purchase card, sticky top 88; the action bar ends the card.
   ===================================================================== */
body.vf-has-actionbar { padding-bottom: calc(84px + env(safe-area-inset-bottom, 0)); }
.vf-pd { max-width: calc(var(--vf-container) + 2 * var(--vf-page-pad)); }
.vf-crumb { display: none; }
.vf-pd__grid { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.vf-pd__main, .vf-pd__buy, .vf-pd__buycard { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.vf-pd p, .vf-pd h1, .vf-pd h2, .vf-pd dl, .vf-pd dd { margin: 0; }
.vf-pd__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.vf-pd__chips .vf-chip { height: 24px; padding: 0 8px; border-radius: 8px; font: 600 12px/24px var(--vf-font); gap: 4px; }
.vf-pd__title { font: 600 20px/28px var(--vf-font); color: var(--vf-text-1); letter-spacing: -0.01em; }
.vf-pd__price { font: 600 24px/32px var(--vf-font); color: var(--vf-accent-text); font-variant-numeric: tabular-nums; }
.vf-pd__per { font: var(--vf-t-small-loose); color: var(--vf-text-2); }
.vf-pd__desc { font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.vf-pd .vf-options { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.vf-pd .vf-option { white-space: normal; line-height: 18px; padding-top: 4px; padding-bottom: 4px; }
.vf-specs { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; font: var(--vf-t-small-loose); color: var(--vf-text-2); }
.vf-specs > div { display: flex; justify-content: space-between; gap: 8px; min-width: 0; }
.vf-specs dd { color: var(--vf-text-1); font-weight: 600; text-align: right; }
.vf-seg--nav { overflow-x: auto; scrollbar-width: none; }
.vf-seg--nav .vf-seg__item.active { background: var(--vf-surface-2); color: var(--vf-text-1); font-weight: 600; box-shadow: var(--vf-e1); }
.vf-pd .vf-seg__item.active { background: var(--vf-surface-2); color: var(--vf-text-1); font-weight: 600; box-shadow: var(--vf-e1); }
.vf-pd .rs-field { display: flex; flex-direction: column; gap: 4px; margin: 0; }
.vf-pd .rs-label { font: 500 14px/20px var(--vf-font); color: var(--vf-text-1); }
.vf-pd .rs-help, .vf-pd .vf-help { font: var(--vf-t-caption); color: var(--vf-text-2); margin: 0; }
.vf-pd .ord-notif:empty { display: none; }
.vf-pd .ord-notif { font: var(--vf-t-caption); }
.vf-pd .ord-notif .text-success { color: var(--vf-success); }
.vf-pd .ord-notif .text-danger { color: var(--vf-danger); }
.vf-pd .ord-notif .text-warning { color: var(--vf-warning); }
.vf-pd .pnl-opt { font-weight: 400; color: var(--vf-text-2); }
.vf-pd .pnl-mine { flex-direction: row; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.vf-pd .pnl-mine__title { font: var(--vf-t-btn); }
.vf-pd .pnl-mine__meta { font: var(--vf-t-small); color: var(--vf-text-2); }
/* Action bar: fixed to the bottom on phones / tablets. */
.vf-pd__action { position: fixed; left: 0; right: 0; bottom: 0; margin: 0; z-index: var(--rs-z-sticky); }
.vf-actionbar__label { font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-actionbar__value { font: 600 18px/26px var(--vf-font); color: var(--vf-text-1); font-variant-numeric: tabular-nums; white-space: nowrap; }
.vf-actionbar__value .pnl-was { font: var(--vf-t-caption); color: var(--vf-text-2); text-decoration: line-through; margin-left: 4px; }
.vf-actionbar__error { font: 500 14px/20px var(--vf-font); color: var(--vf-danger); }
.vf-pd__action .vf-btn--primary { flex: 1; min-height: 48px; }
@media (min-width: 1024px) {
  body.vf-has-actionbar { padding-bottom: 0; }
  .vf-pd { padding-top: 24px; gap: 16px; }
  .vf-crumb { display: flex; }
  .vf-crumb a { display: inline-flex; align-items: center; gap: 8px; min-height: 48px; font: var(--vf-t-ui); color: var(--vf-text-2); text-decoration: none; }
  .vf-crumb a:hover { color: var(--vf-accent-text); }
  .vf-pd__grid { display: grid; grid-template-columns: minmax(0, 1fr) 392px; gap: 24px; align-items: start; }
  .vf-pd__buy { position: sticky; top: 88px; }
  .vf-pd__buycard { background: var(--vf-surface-2); border-radius: var(--vf-r-card); box-shadow: var(--vf-e1); border: var(--vf-card-border, 0); padding: 8px 0 24px; gap: 0; }
  .vf-pd__buycard > .vf-card { box-shadow: none; border: 0; border-radius: 0; padding: 16px 24px; }
  .vf-pd__buycard > .vf-card + .vf-card { border-top: 1px solid var(--vf-border); }
  .vf-pd__action { position: static; display: flex; flex-direction: column; align-items: stretch; gap: 12px; padding: 16px 24px 0; border-top: 1px solid var(--vf-border); background: none; }
  .vf-pd__action .vf-actionbar__total { flex-direction: row; justify-content: space-between; align-items: baseline; }
  .vf-pd__title { font-size: 24px; line-height: 30px; }
}
.vf-pd__extra { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.vf-pd .vf-seg__item .rs-icon { flex-shrink: 0; }
@media (min-width: 1024px) {
  .vf-pd__main { grid-column: 1; grid-row: 1; }
  .vf-pd__extra { grid-column: 1; grid-row: 2; }
  .vf-pd__buy { grid-column: 2; grid-row: 1 / span 2; }
}

/* ---------- Full-screen status view (VF.status, board S3 "Status pembayaran") ---------- */
dialog.vf-status { position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: var(--vf-surface-1); color: var(--vf-text-1); display: flex; flex-direction: column; overflow: hidden; }
dialog.vf-status:not([open]) { display: none; }
dialog.vf-status::backdrop { background: var(--vf-surface-1); }
html.vf-status-open { overflow: hidden; }
.vf-status__bar { flex: none; height: 56px; display: flex; align-items: center; gap: 4px; padding: 0 4px; background: var(--vf-surface-2); border-bottom: 1px solid var(--vf-border); }
.vf-status__bartitle { font: 600 16px/24px var(--vf-font); }
.vf-status__body { flex: 1; overflow-y: auto; width: 100%; max-width: calc(560px + 32px); margin: 0 auto; padding: 24px 16px 16px; display: flex; flex-direction: column; gap: 16px; }
.vf-status__card { gap: 0; }
.vf-status__cardtitle { margin: 0; padding: 12px 16px 4px; font: var(--vf-t-ui-strong); }
.vf-status__note { margin: 0; font: var(--vf-t-small-loose); color: var(--vf-text-2); text-align: center; }
.vf-status__actions { flex: none; position: static; margin: 0; }
.vf-status__actions .vf-btn { min-height: 48px; }
@media (min-width: 1024px) {
  .vf-status__body { padding-top: 48px; }
  .vf-status__actions { width: 100%; max-width: calc(560px + 32px); margin: 0 auto; padding: 0 16px 32px; display: flex; justify-content: flex-end; gap: 8px; border: 0; background: none; }
  .vf-status__actions .vf-btn { flex: none; min-width: 160px; }
}
.vf-status__body > * { flex-shrink: 0; }
.vf-kv dt, .vf-kv dd { margin: 0; font-weight: inherit; }
.vf-kv .vf-kv__key { font-weight: 400; }
@media (min-width: 1024px) { .vf-status__actions.vf-status__actions > .vf-btn { flex: none; } }
.vf-kv { margin: 0; }

/* =====================================================================
   PHASE 12 — PRODUCT PAGES (D1 B1 Product detail, E10 Stock product, C Product). Back row above; one column on
   phones; >= 1024 main column + 392 summary card (sticky top 88). Cards r16, padding 16 → 24, gap 16.
   ===================================================================== */
.vf-pd2 { width: 100%; max-width: calc(var(--vf-w-list) + 2 * var(--vf-page-pad)); margin: 0 auto; padding: 8px var(--vf-page-pad) 0; }
.vf-pd2 p, .vf-pd2 h1, .vf-pd2 h2 { margin: 0; }
.vf-pd2__flash { margin-bottom: 16px; }
.vf-pd2__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px 24px; align-items: start; }
.vf-pd2__main, .vf-pd2__side { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
@media (min-width: 1024px) {
  .vf-pd2__grid { grid-template-columns: minmax(0, 1fr) 392px; }
  .vf-pd2__side { position: sticky; top: 88px; }
}
.vf-pd2 .vf-card { gap: 12px; }
.vf-pd2__head { flex-direction: row; align-items: flex-start; gap: 16px; }
.vf-pd2__tile { position: relative; width: 88px; height: 88px; flex: none; border-radius: 16px; overflow: hidden; display: inline-flex; align-items: center; justify-content: center; background: var(--vf-surface-3); background: oklch(var(--vf-ph-l) var(--vf-ph-c) var(--pc-h, 240)); color: var(--vf-text-2); color: oklch(var(--vf-ic-l) var(--vf-ic-c) var(--pc-h, 240)); }
.vf-pd2__tile .rs-icon { width: 32px; height: 32px; }
.vf-pd2__tile img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.vf-pd2__headtext { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.vf-chip-cat { height: 22px; padding: 0 8px; border-radius: 6px; background: var(--vf-surface-3); color: var(--vf-text-2); font: 600 12px/22px var(--vf-font); text-decoration: none; white-space: nowrap; }
.vf-chip-cat::after { inset: -13px -4px; }
.vf-pd2__title { font: var(--vf-t-h1); letter-spacing: -0.015em; color: var(--vf-text-1); text-wrap: balance; overflow-wrap: anywhere; }
.vf-pd2__facts { display: flex; flex-wrap: wrap; gap: 4px 12px; font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-fact { display: inline-flex; align-items: center; gap: 4px; }
.vf-fact .rs-icon { width: 12px; height: 12px; flex: none; }
.vf-fact--ok { color: var(--vf-success); }
.vf-fact--danger { color: var(--vf-danger); }
.vf-fact--warn { color: var(--vf-warning); }
/* Notice (sold out, warnings): tinted block, icon + bold title + text. */
.vf-notice { display: flex; gap: 12px; align-items: flex-start; padding: 12px 16px; border-radius: 12px; font: var(--vf-t-small); background: var(--vf-info-subtle); color: var(--vf-info); }
.vf-notice > .rs-icon { flex: none; width: 18px; height: 18px; margin-top: 1px; }
.vf-notice > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.vf-notice b { font-weight: 600; }
.vf-notice--danger { background: var(--vf-danger-subtle); color: var(--vf-danger); }
.vf-notice--warning { background: var(--vf-warning-subtle); color: var(--vf-warning); }
.vf-notice--success { background: var(--vf-success-subtle); color: var(--vf-success); }
/* Quantity row (E10): label + hint left, 48px stepper right. */
.vf-qtyrow { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.vf-qtyrow__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.vf-qtyrow__label { font: var(--vf-t-label); color: var(--vf-text-1); margin: 0; }
.vf-qtyrow__hint { font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-pd2 .qty-stepper { display: flex; align-items: center; gap: 0; max-width: none; height: auto; border: 1px solid var(--vf-border-strong); border-radius: 12px; overflow: hidden; flex: none; }
.vf-pd2 .qty-btn { width: 48px; height: 48px; border: 0; border-radius: 0; background: none; color: var(--vf-accent-text); display: inline-flex; align-items: center; justify-content: center; }
.vf-pd2 .qty-btn:disabled { color: var(--vf-text-3); opacity: 1; }
.vf-pd2 .qty-input { width: 48px; height: 48px; border: 0; padding: 0; text-align: center; background: none; color: var(--vf-text-1); font: 600 16px/24px var(--vf-font); font-variant-numeric: tabular-nums; -moz-appearance: textfield; }
.vf-pd2 .qty-input:focus { outline: none; box-shadow: none; }
.vf-pd2 .qty-stepper:focus-within { border-color: var(--vf-accent); }
.vf-pd2__buy .pd-block { margin: 0; display: flex; flex-direction: column; gap: 8px; }
.vf-pd2__buy .balance-warn { margin: 8px 0 0; }
.vf-pd2__buy .pd-cta-note { margin: 0; font: var(--vf-t-caption); color: var(--vf-text-2); text-align: left; }
.vf-pd2__cta { margin: 0; }
.vf-pd2__cta .vf-btn { min-height: 48px; }
.vf-pd2 .vf-pd2__price { display: none; }   /* the price lives in the summary card and the action bar (B1) */
.vf-pd2 .pd-media, .vf-pd2 .pd-desc { width: auto; max-width: none; grid-area: auto; }
.vf-pd2 .pd-media .carousel-wrap { border: 0; border-radius: 0; box-shadow: none; max-height: 40vh; }
.vf-pd2 .desc-text { font: var(--vf-t-body); color: var(--vf-text-2); white-space: pre-line; overflow-wrap: anywhere; text-wrap: pretty; max-width: none; }
.vf-pd2 .rating-block { margin-top: 8px; padding-top: 12px; border-top: 1px solid var(--vf-border); }
/* Inputs inside product cards: label 13/18 500, field 48 r12, hint 12. */
.vf-pd2 .script-field-group { display: flex; flex-direction: column; gap: 8px; margin: 0; }
.vf-pd2 .script-field-label { margin: 0; font: var(--vf-t-label); color: var(--vf-text-1); }
.vf-pd2 .script-field-input, .vf-pd2 .pd-voucher-row .rs-input { min-height: 48px; padding: 0 16px; border: 1px solid var(--vf-border-strong); border-radius: 12px; background: var(--vf-surface-2); color: var(--vf-text-1); font: 400 16px/24px var(--vf-font); }
.vf-pd2 .script-field-input:focus, .vf-pd2 .pd-voucher-row .rs-input:focus { outline: none; border-color: var(--vf-accent); box-shadow: 0 0 0 2px var(--vf-surface-2), 0 0 0 4px var(--vf-accent); }
.vf-pd2 .script-field-hint { margin: 0; font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-pd2 .pd-voucher-row { display: flex; gap: 8px; }
.vf-pd2 .pd-voucher-row .vf-btn { min-height: 48px; }
/* Payment method: two 64px radio cards (Saldo / QRIS); selected = 2px accent + accent-subtle. */
.vf-pd2 .pd-pay { border: 0; margin: 0; padding: 0; min-width: 0; display: flex; flex-direction: column; gap: 12px; }
.vf-pd2 .pd-pay legend { padding: 0; margin: 0 0 12px; float: left; width: 100%; }
.vf-pd2 .pd-pay-list { clear: both; display: flex; flex-direction: column; gap: 8px; }
.vf-pd2 .pd-pay-opt { position: relative; min-height: 64px; margin: 0; padding: 8px 16px; border-radius: 12px; border: 1px solid var(--vf-border); background: var(--vf-surface-2); color: var(--vf-text-1); display: flex; align-items: center; gap: 12px; cursor: pointer; font: var(--vf-t-ui-strong); }
.vf-pd2 .pd-pay-opt > .rs-icon { width: 32px; height: 32px; padding: 8px; flex: none; border-radius: var(--vf-r-ctl); background: var(--vf-surface-3); color: var(--vf-accent-text); box-sizing: border-box; }
.vf-pd2 .pd-pay-opt .opt-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.vf-pd2 .pd-pay-opt .opt-sub { font: var(--vf-t-caption); color: var(--vf-text-2); font-variant-numeric: tabular-nums; }
.vf-pd2 .pd-pay-opt.opt-muted .opt-sub { color: var(--vf-danger); }
.vf-pd2 .pd-pay-opt input[type="radio"] { order: 3; width: 20px; height: 20px; margin: 0; flex: none; accent-color: var(--vf-accent); }
.vf-pd2 .pd-pay-opt:has(input:checked) { border: 2px solid var(--vf-accent); padding: 7px 15px; background: var(--vf-accent-subtle); }
.vf-pd2 .pd-pay-opt:has(input:focus-visible) { outline: 2px solid var(--vf-focus); outline-offset: 2px; }
.vf-pd2 .pd-pay-foot { margin: 0; font: var(--vf-t-small); color: var(--vf-text-2); display: flex; flex-wrap: wrap; gap: 4px 8px; }
.vf-pd2 .pd-pay-foot a { color: var(--vf-accent-text); font-weight: 600; min-height: 24px; }
.vf-pd2 .pd-pending { margin: 0; }
/* Summary rows (Harga / Jumlah / Total). */
.vf-sum { margin: 0; padding-top: 4px; border-top: 1px solid var(--vf-border); display: flex; flex-direction: column; }
.vf-sum__row { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; font: var(--vf-t-body-sm); color: var(--vf-text-2); font-variant-numeric: tabular-nums; }
.vf-sum__row dt { font-weight: 400; }
.vf-sum__row dd { margin: 0; white-space: nowrap; color: var(--vf-text-2); }
.vf-sum__row--total { font: var(--vf-t-btn); color: var(--vf-text-1); }
.vf-sum__row--total dd { font-family: var(--vf-font-num); font-weight: 600; color: var(--vf-text-1); }
/* Phone action bar: "Total · Saldo" + amount, "Bayar sekarang" 48. >= 1024 the bar is the card's full-width CTA. */
.vf-pd2 .vf-pd__action { box-shadow: var(--vf-e-up); }
.vf-pd2 .vf-pd__action .vf-btn--primary { flex: 1 1 auto; min-width: 0; padding: 0 20px; }   /* 12b: fills the row */
@media (min-width: 1024px) {
  .vf-pd2 .vf-pd__action { position: static; padding: 0; margin: 0; border: 0; background: none; box-shadow: none; display: block; }
  .vf-pd2 .vf-pd__action .vf-actionbar__total { display: none; }
  .vf-pd2 .vf-pd__action .vf-btn--primary { width: 100%; }
}
.vf-pd2 .pd-owned { display: flex; flex-direction: column; gap: 12px; }
.vf-pd2 .pd-owned__actions { display: flex; flex-direction: column; gap: 8px; margin: 0; }

/* =====================================================================
   PRODUCT DETAIL FORK — shared by views/produk-detail.ejs and views/produk-stok-detail.ejs (P1-07).
   These rules were copied in both pages' \3c style>; one copy now, scoped to body.vf-pdx with :where()
   (zero specificity, so each page's remaining rules still win exactly as before). Carousel <= 40vh.
   ===================================================================== */
:where(.vf-pdx) .pd-page p { margin: 0; }
:where(.vf-pdx) .pd-page h1, :where(.vf-pdx) .pd-page h2, :where(.vf-pdx) .pd-page h3 { margin: 0; }
:where(.vf-pdx) .pd-flash { margin-bottom: var(--rs-space-4); }

:where(.vf-pdx) .pd-media { grid-area: auto; min-width: 0; }

:where(.vf-pdx) .pd-desc { min-width: 0; }
@media (min-width: 768px) {
  :where(.vf-pdx) .pd-page { padding-left: var(--vf-page-pad); padding-right: var(--vf-page-pad); }
}
@media (min-width: 900px) {
  
  :where(.vf-pdx) .pd-media { grid-area: media; }
  :where(.vf-pdx) .pd-desc { grid-area: desc; }
  :where(.vf-pdx) .pd-media, :where(.vf-pdx) .pd-desc { width: 100%; max-width: 620px; }
  
}
:where(.vf-pdx) .carousel-wrap {
    position: relative; width: 100%; aspect-ratio: 4 / 3; max-height: 40vh; overflow: hidden; border: 1px solid var(--vf-border);
  }
:where(.vf-pdx) .carousel-track {
    display: flex; width: 100%; height: 100%; overflow-x: auto; scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
  }
:where(.vf-pdx) .carousel-track::-webkit-scrollbar { display: none; }
:where(.vf-pdx) .carousel-slide { position: relative; flex: 0 0 100%; scroll-snap-align: start; height: 100%; }
:where(.vf-pdx) .carousel-zoom {
    display: block; width: 100%; height: 100%; padding: 0; margin: 0; border: 0;
    background: transparent; cursor: zoom-in;
  }
:where(.vf-pdx) .carousel-zoom:focus-visible { outline-offset: -3px; }
:where(.vf-pdx) .carousel-slide img { width: 100%; height: 100%; object-fit: contain; display: block; }
@media (min-width: 600px) and (max-width: 899.98px) {
  :where(.vf-pdx) .carousel-wrap { aspect-ratio: 16 / 10; }
  :where(.vf-pdx) .carousel-slide img { object-fit: contain; }
}
:where(.vf-pdx) .carousel-fallback {
    position: absolute; inset: 0; display: none; align-items: center; justify-content: center;
    color: var(--vf-text-3); font-size: var(--rs-ts-3xl); pointer-events: none;
  }
:where(.vf-pdx) .carousel-slide.is-broken img { visibility: hidden; }
:where(.vf-pdx) .carousel-slide.is-broken .carousel-zoom { cursor: default; }
:where(.vf-pdx) .carousel-slide.is-broken .carousel-fallback { display: flex; }
:where(.vf-pdx) .carousel-arrow {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
    width: 40px; height: 40px; border-radius: var(--vf-r-ctl);
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--vf-surface-2); color: var(--vf-text-1); border: 1px solid var(--vf-border);
    box-shadow: var(--vf-e1); cursor: pointer;
  }
:where(.vf-pdx) .carousel-arrow:hover { background: var(--rs-surface-hover); }
:where(.vf-pdx) .carousel-arrow-left { left: var(--rs-space-3); }
:where(.vf-pdx) .carousel-arrow-right { right: var(--rs-space-3); }
:where(.vf-pdx) .carousel-indicator {
    position: absolute; bottom: var(--rs-space-3); right: var(--rs-space-3); z-index: 2;
    background: var(--vf-surface-2); color: var(--vf-text-1); border: 1px solid var(--vf-border);
    font-size: var(--rs-fs-sm); font-weight: var(--rs-fw-semibold); font-variant-numeric: tabular-nums;
    padding: var(--rs-s-4) var(--rs-s-8); border-radius: var(--vf-r-chip);
  }
:where(.vf-pdx) .lb-overlay {
    position: fixed; inset: 0; background: var(--vf-hero); z-index: var(--rs-z-toast);
    display: none; flex-direction: column; touch-action: none;
  }
html.dark-mode :where(.vf-pdx) .lb-overlay { background: var(--vf-surface-1); }
:where(.vf-pdx) .lb-overlay.open { display: flex; }
:where(.vf-pdx) .lb-topbar {
    position: absolute; top: 0; left: 0; right: 0; z-index: 10;
    display: flex; align-items: center; justify-content: space-between; gap: var(--rs-space-3);
    padding: calc(var(--rs-space-3) + env(safe-area-inset-top, 0px)) var(--rs-space-4) var(--rs-space-3);
    pointer-events: none;
  }
:where(.vf-pdx) .lb-close, :where(.vf-pdx) .lb-indicator { pointer-events: auto; }
:where(.vf-pdx) .lb-close {
    width: var(--rs-hit); height: var(--rs-hit); border-radius: var(--vf-r-ctl);
    border: 1px solid var(--rs-inverse-border); background: var(--vf-hero); color: var(--vf-hero-text);
    display: inline-flex; align-items: center; justify-content: center; font-size: var(--rs-ts-lg); cursor: pointer;
  }
html.dark-mode :where(.vf-pdx) .lb-close { background: var(--vf-surface-2); border-color: var(--vf-border); color: var(--vf-text-1); }
:where(.vf-pdx) .lb-close:focus-visible { outline-color: var(--vf-hero-text); }
:where(.vf-pdx) .lb-indicator {
    color: var(--vf-hero-text); font-size: var(--rs-fs-md); font-weight: var(--rs-fw-semibold);
    font-variant-numeric: tabular-nums;
  }
:where(.vf-pdx) .lb-track {
    flex: 1; display: flex; width: 100%; height: 100%; overflow-x: auto;
    scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; scrollbar-width: none;
    touch-action: pan-x;
  }
:where(.vf-pdx) .lb-track::-webkit-scrollbar { display: none; }
:where(.vf-pdx) .lb-slide {
    flex: 0 0 100%; height: 100%; scroll-snap-align: start;
    display: flex; align-items: center; justify-content: center; overflow: hidden;
  }
:where(.vf-pdx) .lb-slide img {
    max-width: 100%; max-height: 100%; width: auto; height: auto;
    object-fit: contain; user-select: none; -webkit-user-drag: none; transform-origin: center center;
  }

:where(.vf-pdx) .pd-price { margin-top: var(--rs-space-4); display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--rs-space-1) var(--rs-space-2); }
:where(.vf-pdx) .pd-price__final { font-size: var(--rs-fs-3xl); line-height: var(--rs-lh-auto); font-weight: var(--rs-fw-bold); color: var(--vf-text-1); font-variant-numeric: tabular-nums; letter-spacing: var(--rs-tracking-tight); }
:where(.vf-pdx) .pd-price__was { font-size: var(--rs-fs-base); color: var(--vf-text-3); text-decoration: line-through; font-variant-numeric: tabular-nums; }
:where(.vf-pdx) .pd-price__off { font-size: var(--rs-fs-sm); font-weight: var(--rs-fw-semibold); color: var(--vf-danger); font-variant-numeric: tabular-nums; }
:where(.vf-pdx) .pd-price__voucher { flex-basis: 100%; display: flex; align-items: center; gap: var(--rs-s-8); font-size: var(--rs-fs-md); color: var(--vf-success); font-weight: var(--rs-fw-medium); }
:where(.vf-pdx) .pd-price__note { flex-basis: 100%; font-size: var(--rs-fs-sm); color: var(--vf-text-3); }

:where(.vf-pdx) .pd-block + .pd-block { margin-top: var(--rs-space-5); }

:where(.vf-pdx) .pd-voucher-row { display: flex; gap: var(--rs-space-2); }
:where(.vf-pdx) .pd-voucher-row .rs-input { flex: 1; min-width: 0; text-transform: none; }
:where(.vf-pdx) .pd-voucher-row .rs-input::placeholder { text-transform: none; }
:where(.vf-pdx) .pd-voucher-row .vf-btn { flex-shrink: 0; }
:where(.vf-pdx) .pd-voucher-msg { margin-top: var(--rs-s-8); font-size: var(--rs-fs-md); color: var(--vf-text-2); display: flex; align-items: flex-start; gap: var(--rs-s-8); }
:where(.vf-pdx) .pd-voucher-msg:empty { display: none; }
:where(.vf-pdx) .pd-voucher-msg .bi { margin-top: var(--rs-s-4); flex-shrink: 0; }
:where(.vf-pdx) .pd-voucher-msg.is-success { color: var(--vf-success); }
:where(.vf-pdx) .pd-voucher-msg.is-error { color: var(--vf-danger); }

:where(.vf-pdx) .desc-text { font-size: var(--rs-fs-base); line-height: var(--rs-lh-auto); color: var(--vf-text-1); white-space: pre-line; overflow-wrap: anywhere; max-width: 68ch; }
:where(.vf-pdx) .rating-block { margin-top: var(--rs-space-5); padding-top: var(--rs-space-4); border-top: 1px solid var(--vf-border); display: flex; align-items: center; gap: var(--rs-space-3); }
:where(.vf-pdx) .rating-stars { color: var(--vf-warning); font-size: var(--rs-ts-base); display: flex; gap: var(--rs-s-4); }
:where(.vf-pdx) .rating-value { font-size: var(--rs-fs-lg); font-weight: var(--rs-fw-bold); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
:where(.vf-pdx) .rating-caption { font-size: var(--rs-fs-md); color: var(--vf-text-2); }
:where(.vf-pdx) .ps-overlay {
    position: fixed; inset: 0; background: var(--rs-overlay); z-index: var(--rs-z-modal);
    display: flex; align-items: flex-end; justify-content: center; padding: 0;
  }
:where(.vf-pdx) .ps-box {
    width: 100%; max-width: 440px; max-height: calc(100dvh - var(--rs-space-5)); overflow-y: auto;
    background: var(--vf-surface-2); color: var(--vf-text-1); border: 1px solid var(--vf-border);
    border-radius: var(--vf-r-card) var(--vf-r-card) 0 0; box-shadow: var(--vf-e3);
    padding: var(--rs-space-5) var(--rs-space-4) calc(var(--rs-space-4) + env(safe-area-inset-bottom, 0px));
  }
@media (min-width: 576px) {
  :where(.vf-pdx) .ps-overlay { align-items: center; padding: var(--rs-space-4); }
  :where(.vf-pdx) .ps-box { border-radius: var(--vf-r-card); max-height: calc(100dvh - var(--rs-space-6)); padding: var(--rs-space-5); }
}
:where(.vf-pdx) .ps-head { display: flex; align-items: flex-start; gap: var(--rs-space-3); margin-bottom: var(--rs-space-4); }
:where(.vf-pdx) .ps-icon { font-size: var(--rs-ts-xl); line-height: var(--rs-lh-auto); color: var(--vf-success); flex-shrink: 0; }
:where(.vf-pdx) .ps-icon.ps-warn { color: var(--vf-warning); }
:where(.vf-pdx) .ps-title { font-size: var(--rs-fs-xl); font-weight: var(--rs-fw-bold); margin: 0; color: var(--vf-text-1); }
:where(.vf-pdx) .ps-subtitle { font-size: var(--rs-fs-base); color: var(--vf-text-2); margin: var(--rs-s-4) 0 0; line-height: var(--rs-lh-auto); }
:where(.vf-pdx) .ps-receipt { border-top: 1px solid var(--vf-border); border-bottom: 1px solid var(--vf-border); margin-bottom: var(--rs-space-4); }
:where(.vf-pdx) .ps-row { display: flex; justify-content: space-between; gap: var(--rs-space-4); padding: var(--rs-s-8) 0; border-bottom: 1px solid var(--vf-border); font-size: var(--rs-fs-base); }
:where(.vf-pdx) .ps-row:last-child { border-bottom: 0; }
:where(.vf-pdx) .ps-row > span:first-child { color: var(--vf-text-2); flex-shrink: 0; }
:where(.vf-pdx) .ps-row > span:last-child { font-weight: var(--rs-fw-semibold); text-align: right; word-break: break-word; font-variant-numeric: tabular-nums; min-width: 0; }
:where(.vf-pdx) .ps-row .ps-good { color: var(--vf-success); }
:where(.vf-pdx) .ps-row .ps-was { text-decoration: line-through; color: var(--vf-text-3); font-weight: var(--rs-fw-regular); font-size: var(--rs-ts-caption); margin-left: var(--rs-s-4); }
:where(.vf-pdx) .ps-row .ps-break { word-break: break-all; }
:where(.vf-pdx) .ps-warn-text { margin-bottom: var(--rs-space-4); }
:where(.vf-pdx) .ps-msg-card { margin-bottom: var(--rs-space-4); }
:where(.vf-pdx) .ps-actions { display: flex; flex-direction: column; gap: var(--rs-space-2); }

:where(.vf-pdx) .carousel-wrap { background: var(--vf-surface-3); border-radius: var(--vf-r-card); box-shadow: var(--vf-e1); }

/* =====================================================================
   PHASE 12 — QRIS CHECKOUT (D1 B2 Checkout QRIS, E1 / E1b Deposit payment, C Flow) — deposit-payment.ejs and
   produk-qris-payment.ejs. Form width 640. Stepper, QR card with the two actions inside (no fixed bar — P0-04: the
   unstyled fixed bar is gone, the bottom nav stays), details card, "Cara bayar", danger-text "Batalkan transaksi".
   ===================================================================== */
.pay-page.vf-page--task, .pay-page.vf-pay { max-width: calc(640px + 2 * var(--vf-page-pad)); padding-top: 0; gap: 16px; }
.pay-page .pay-shell, .pay-page .pay-card, .pay-page #payment-body { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.pay-page p, .pay-page h2, .pay-page ol, .pay-page dl { margin: 0; }
/* Stepper: 3 segments — 4px bar + numbered dot 20 + label; done = check, current = text-1 600. */
.vf-steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.vf-steps__item { display: flex; align-items: center; gap: 8px; padding-top: 8px; border-top: 4px solid var(--vf-border); font: var(--vf-t-caption-md); color: var(--vf-text-2); min-width: 0; white-space: nowrap; }
.vf-steps__item.is-done { border-top-color: var(--vf-accent); }
.vf-steps__item.is-current { border-top-color: var(--vf-accent); color: var(--vf-text-1); font-weight: 600; }
.vf-steps__dot { width: 20px; height: 20px; flex: none; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; font: 600 12px/1 var(--vf-font); background: transparent; color: var(--vf-text-2); }
.vf-steps__item.is-done .vf-steps__dot, .vf-steps__item.is-current .vf-steps__dot { background: var(--vf-accent); color: var(--vf-on-accent); }
.vf-steps__dot .rs-icon { width: 12px; height: 12px; }
/* QR card */
.pay-qris { align-items: center; text-align: center; gap: 12px; padding: 20px var(--vf-card-pad) var(--vf-card-pad); }
.pay-qris .pay-status { height: 28px; padding: 0 8px; border-radius: 999px; font: var(--vf-t-caption-strong); display: inline-flex; align-items: center; gap: 8px; }
.pay-status__in { display: inline-flex; align-items: center; gap: 8px; }
.pay-qris .pay-status .rs-dot[hidden] { display: none; }
.vf-qrsave { display: flex; flex-direction: column; align-items: center; gap: 12px; text-align: center; font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.vf-qrsave img { background: var(--vf-qr-bg); padding: 12px; border-radius: 12px; border: 1px solid var(--vf-border); width: 240px; height: auto; }
.pay-qris .pay-status .rs-icon { width: 12px; height: 12px; }
.vf-timer.is-expired { background: var(--vf-danger-subtle); color: var(--vf-danger); }
.pay-qris__label { font: var(--vf-t-small); color: var(--vf-text-2); }
.pay-qris__amountrow { display: inline-flex; align-items: center; gap: 4px; margin-top: -8px !important; }
.pay-qris__amount { font: var(--vf-t-price-lg); color: var(--vf-text-1); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.pay-qris__note { font: var(--vf-t-caption); color: var(--vf-text-2); max-width: 40ch; }
.pay-page .qr-box { padding: 12px; border: 1px solid var(--vf-border); border-radius: 12px; overflow: hidden; background: var(--vf-qr-bg); }
.pay-page .pay-actions { position: static; width: 100%; max-width: 346px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 4px 0 0; padding: 0; border: 0; background: none; box-shadow: none; }
.pay-page .pay-actions:has(> :only-child) { grid-template-columns: minmax(0, 1fr); }
.pay-page .pay-actions .vf-btn, .pay-page .pay-actions .vf-btn { min-height: 48px; min-width: 0; padding: 0 12px; }
/* Details: ID (mono + copy), rows. */
.pay-detail { padding: 0 var(--vf-card-pad); }
.pay-detail .vf-kv__row { padding: 12px 0; }
.vf-kv__copy { margin: -12px -8px -12px 0; }
/* Cara bayar: section title + numbered list (20px accent-subtle circles). */
.pay-how { display: flex; flex-direction: column; gap: 8px; }
.pay-how__title { margin: 0 !important; font: var(--vf-t-section) !important; }   /* phase 14.6: section-title role */
.pay-page .success-overlay, .pay-page .ended-overlay { text-align: center; padding: 24px var(--vf-card-pad); background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 16px; box-shadow: var(--vf-e1); }
.pay-page .pay-result__icon { width: 56px; height: 56px; margin: 0 auto 12px; border-radius: 999px; display: flex; align-items: center; justify-content: center; font-size: 24px; background: var(--vf-success-subtle); color: var(--vf-success); }
.pay-page .pay-result__icon .rs-icon { width: 24px; height: 24px; }
.pay-page .ended-overlay .pay-result__icon { background: var(--vf-surface-3); color: var(--vf-text-2); }
.pay-page .pay-result__title { margin: 0 0 4px !important; font: var(--vf-t-h2); color: var(--vf-text-1); }
.pay-page .pay-result__desc { margin: 0 auto 8px !important; max-width: 40ch; font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.pay-page .pay-result__plus { margin: 4px 0 12px !important; font: var(--vf-t-price-lg); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
.pay-page .pay-result__actions { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; margin-top: 16px; }
@media (min-width: 576px) { .pay-page .pay-result__actions:has(> :nth-child(2)) { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.pay-page .pay-result__kv { margin: 12px 0 0 !important; text-align: left; }
.vf-numlist { list-style: none; margin: 0; padding: 0; counter-reset: n; display: flex; flex-direction: column; gap: 8px; font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.vf-numlist li { counter-increment: n; display: flex; gap: 12px; align-items: flex-start; }
.vf-numlist li::before { content: counter(n); flex: none; width: 20px; height: 20px; margin-top: 0; border-radius: 999px; background: var(--vf-accent-subtle); color: var(--vf-accent-text); display: inline-flex; align-items: center; justify-content: center; font: 600 12px/1 var(--vf-font); }
.vf-btn--danger-text, .pay-btn-cancel { align-self: center; color: var(--vf-danger); background: none; }
.vf-btn--danger-text:hover, .pay-btn-cancel:hover { color: var(--vf-danger); background: var(--vf-danger-subtle); }
@media (min-width: 1024px) {
  .pay-page.vf-pay, .pay-page.vf-page--task { padding-top: 0; }
  .pay-qris .qr-box #qr-canvas, .pay-qris .qr-box #qr-canvas img, .pay-qris .qr-box #qr-canvas canvas { width: var(--vf-qr-size); height: var(--vf-qr-size); }
}

/* =====================================================================
   PHASE 12 — DEPOSIT (D1 B4, S11 inline errors) — views/deposit.ejs. Form width 640.
   ===================================================================== */
.dp-page { gap: 16px; }
.vf-dp__head { display: flex; flex-direction: column; gap: 4px; }
.dp-page .vf-dp__h1 { margin: 0; font: var(--vf-t-h1); letter-spacing: -0.015em; color: var(--vf-text-1); }
.vf-dp__saldo-line { margin: 0; font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.vf-dp__saldo-line strong { color: var(--vf-text-1); font-weight: 600; font-variant-numeric: tabular-nums; }
.dp-form { display: flex; flex-direction: column; gap: 16px; }
.dp-card { gap: 12px; }
.dp-card .preset-grid { margin: 0; }
/* Presets: 3 × 2, 48 tall, Sora 600 14 tabular, nowrap; selected = 2px accent + accent-subtle. */
.vf-presets { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.vf-preset { min-height: 48px; min-width: 0; padding: 0 8px; border: 1px solid var(--vf-border-strong); border-radius: 12px; background: var(--vf-surface-2); color: var(--vf-text-1); font: var(--vf-t-num-sm); font-variant-numeric: tabular-nums; white-space: nowrap; cursor: pointer; transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-preset:hover { background: var(--vf-surface-3); }
.vf-preset[aria-pressed="true"] { border: 2px solid var(--vf-accent); background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
.vf-preset:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--vf-surface-1), 0 0 0 4px var(--vf-accent); }
@media (max-width: 359.98px) { .vf-preset { font-size: 14px; } }
/* Fields (S11): label 13/18 500, control 48 r12, hint 12; error = 2px danger border + icon + 12px danger message. */
.vf-field__label { margin: 4px 0 -8px; font: var(--vf-t-label); color: var(--vf-text-1); }
.vf-field__hint { margin: -8px 0 0; font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-field__hint[hidden], .vf-field__error[hidden] { display: none; }
.vf-field__error { margin: -8px 0 0; display: flex; align-items: center; gap: 4px; font: var(--vf-t-caption); color: var(--vf-danger); }
.vf-field__error .rs-icon { width: 14px; height: 14px; flex: none; }
.vf-dp__amount { display: flex; align-items: center; gap: 8px; min-height: 48px; padding: 0 16px; border: 1px solid var(--vf-border-strong); border-radius: 12px; background: var(--vf-surface-2); }
.vf-dp__amount:focus-within { border: 2px solid var(--vf-accent); padding: 0 15px; }
.vf-dp__amount:has([aria-invalid="true"]) { border: 2px solid var(--vf-danger); padding: 0 15px; }
.vf-dp__amount .vf-input { flex: 1; min-width: 0; border: 0; padding: 0; min-height: 48px; background: transparent; box-shadow: none; outline: none; font: 600 16px/24px var(--vf-font); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
.vf-dp__prefix { font: 400 16px/24px var(--vf-font); color: var(--vf-text-2); }
.vf-sum--plain { border-top: 0; padding-top: 0; }
.vf-sum--plain .vf-sum__row + .vf-sum__row { border-top: 1px solid var(--vf-border); }
.vf-notice--info { background: var(--vf-info-subtle); color: var(--vf-info); margin: 0; }
.vf-notice__link { align-self: flex-start; min-height: 32px; display: inline-flex; align-items: center; font-weight: 600; color: inherit; text-decoration: underline; text-underline-offset: 3px; }
@media (pointer: coarse) { .vf-notice__link { min-height: 44px; } }   /* WP7 7.1 CROSS-01 */
.dp-page .dp-pending { margin: 0; }

/* =====================================================================
   PHASE 12 — RIWAYAT (D1 C1 list, C2 detail, C3 empty filter, S6, S9) — views/history.ejs. Lists max 1200.
   ===================================================================== */
.hist-page { max-width: calc(var(--vf-w-list) + 2 * var(--vf-page-pad)); gap: 12px; padding-top: 0; }
.hist-page h1, .hist-page h2, .hist-page p { margin: 0; }
.hist-head { display: flex; flex-direction: column; gap: 4px; margin-bottom: 4px; }
.hist-head__title { font: var(--vf-t-h1); letter-spacing: -0.015em; color: var(--vf-text-1); }
.hist-head__sub { font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.hist-toolbar { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }
.hist-search { position: relative; width: 100%; display: flex; align-items: center; gap: 8px; min-height: 48px; padding: 0 16px; border: 1px solid var(--vf-border-strong); border-radius: 12px; background: var(--vf-surface-2); color: var(--vf-text-3); }
.hist-search:focus-within { border: 2px solid var(--vf-accent); padding: 0 15px; }
.hist-search input { flex: 1; min-width: 0; min-height: 48px; border: 0; padding: 0; background: none; outline: none; color: var(--vf-text-1); font: 400 16px/24px var(--vf-font); }
.hist-search input::placeholder { color: var(--vf-text-3); }
.hist-period { min-height: 48px; padding: 0 12px; display: inline-flex; align-items: center; gap: 8px; border: 1px solid var(--vf-border-strong); border-radius: 12px; background: var(--vf-surface-2); color: var(--vf-text-1); font: var(--vf-t-ui); cursor: pointer; }
.hist-period .rs-icon:last-child { color: var(--vf-text-2); }
/* Type segmented control: 40 items in a 48 track. */
.vf-seg.hist-seg { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px; padding: 4px; border-radius: 12px; background: var(--vf-surface-3); width: 100%; }
.hist-seg .vf-seg__item { min-height: 40px; min-width: 0; padding: 0 8px; border: 0; border-radius: 9px; background: none; color: var(--vf-text-2); font: var(--vf-t-small-md); white-space: nowrap; cursor: pointer; box-shadow: none; position: relative; }
.hist-seg .vf-seg__item::before { content: ''; position: absolute; inset: -4px 0; }
.hist-seg .vf-seg__item.active, .hist-seg .vf-seg__item[aria-selected="true"] { background: var(--vf-surface-2); color: var(--vf-text-1); font-weight: 600; box-shadow: var(--vf-e1); }
/* Filter chips: 36 visual in a 48 hit; selected = accent text + accent-subtle + accent border. */
.hist-chips { display: flex; gap: 8px; overflow-x: auto; margin: 0 calc(-1 * var(--vf-page-pad)); padding: 8px var(--vf-page-pad); scrollbar-width: none; }
.hist-chips::-webkit-scrollbar { display: none; }
.vf-fchip { flex: none; height: 36px; padding: 0 12px; border-radius: 999px; border: 1px solid var(--vf-border); background: var(--vf-surface-2); color: var(--vf-text-1); font: var(--vf-t-small-md); white-space: nowrap; cursor: pointer; }
.vf-fchip::before { content: ''; position: absolute; inset: -6px 0; }
.vf-fchip[aria-pressed="true"] { border-color: var(--vf-accent); background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
/* List card: 72px rows — tile 36 · name (1 line) + time · amount + status chip. */
.hist-page .hist-card { background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 16px; box-shadow: var(--vf-e1); padding: 0; overflow: hidden; display: block; }
.hist-page .hist-card:has(.hist-empty) { background: none; box-shadow: none; border: 0; overflow: visible; }
.hist-page .hist-row { display: flex; align-items: center; gap: 12px; min-height: 72px; padding: 12px 16px; border: 0; background: none; cursor: pointer; }
.hist-page .hist-row[hidden] { display: none; }
.hist-page .hist-row:not([hidden]) ~ .hist-row:not([hidden]) { border-top: 1px solid var(--vf-border); }
.hist-page .hist-row:hover { background: var(--vf-surface-3); }
.hist-page .hist-row:focus-visible { outline: 2px solid var(--vf-focus); outline-offset: -2px; }
.hist-page .hist-icon { width: var(--vf-ico-tile); height: var(--vf-ico-tile); flex: none; border-radius: 12px; display: inline-flex; align-items: center; justify-content: center; font-size: 18px; background: oklch(var(--vf-ph-l) var(--vf-ph-c) 275); color: oklch(var(--vf-ic-l) var(--vf-ic-c) 275); }
.hist-page .hist-row[data-stype="deposit"] .hist-icon { background: oklch(var(--vf-ph-l) var(--vf-ph-c) 150); color: oklch(var(--vf-ic-l) var(--vf-ic-c) 150); }
.hist-page .hist-row[data-stype="nokos"] .hist-icon { background: oklch(var(--vf-ph-l) var(--vf-ph-c) 175); color: oklch(var(--vf-ic-l) var(--vf-ic-c) 175); }
.hist-page .hist-row[data-stype="apkprem"] .hist-icon { background: oklch(var(--vf-ph-l) var(--vf-ph-c) 0); color: oklch(var(--vf-ic-l) var(--vf-ic-c) 0); }
.hist-page .hist-row[data-stype="produk"] .hist-icon { background: oklch(var(--vf-ph-l) var(--vf-ph-c) 305); color: oklch(var(--vf-ic-l) var(--vf-ic-c) 305); }
.hist-page .hist-row[data-stype="smm"] .hist-icon { background: oklch(var(--vf-ph-l) var(--vf-ph-c) 330); color: oklch(var(--vf-ic-l) var(--vf-ic-c) 330); }
.hist-page .hist-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.hist-page .hist-main, .hist-page .hist-sub { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-width: 0; }
.hist-page .hist-label { flex: 1; min-width: 0; font: var(--vf-t-ui-strong); color: var(--vf-text-1); }
.hist-page .hist-amount { flex: none; font: var(--vf-t-num-sm); color: var(--vf-text-1); font-variant-numeric: tabular-nums; white-space: nowrap; }
.hist-page .hist-row[data-stype="deposit"][data-status="success"] .hist-amount { color: var(--vf-success); }
.hist-page .hist-date { flex: 1; min-width: 0; font: var(--vf-t-caption); color: var(--vf-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hist-page .hist-type, .hist-page .hist-when, .hist-page .hist-id { display: none; }
.hist-page .hist-chev { display: none; }
.hist-page .spill { flex: none; display: inline-flex; }
.hist-page .spill .vf-status { height: 22px; padding: 0 8px; font: 600 12px/22px var(--vf-font); }
.hist-page .hist-detail { display: none; }
.hist-thead { display: none; }
.hist-nores[hidden], .hist-thead[hidden], .hist-page .hist-card[hidden] { display: none; }   /* WP6C 6.10: the empty card shell used to stay above "Tidak ada transaksi yang cocok" */
.hist-range-list .vf-row { min-height: 56px; text-decoration: none; color: var(--vf-text-1); }
.hist-range-list .vf-row.active { color: var(--vf-accent-text); font-weight: 600; }
/* Pager: "1–20 dari 1.284" + prev / next 48. */
.vf-pager { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 4px; }
.vf-pager[hidden] { display: none; }
.vf-pager__info { font: var(--vf-t-small); color: var(--vf-text-2); font-variant-numeric: tabular-nums; }
.vf-pager__btns { display: inline-flex; gap: 8px; }
.vf-pager .vf-icon-btn { width: 48px; height: 48px; border: 1px solid var(--vf-border); background: var(--vf-surface-2); }
.vf-pager .vf-icon-btn:disabled { color: var(--vf-text-3); background: var(--vf-surface-1); cursor: default; }
@media (min-width: 1024px) {
  .hist-toolbar { flex-direction: row; align-items: center; }
  .hist-search { max-width: 520px; }
  .vf-seg.hist-seg { max-width: 640px; }
  .hist-seg .vf-seg__item { font-size: 14px; }
  .hist-chips { margin: 0; padding: 4px 0; flex-wrap: wrap; overflow: visible; }
  /* Real table >= 1024: header 44 (table-head colour), rows 60. */
  .hist-thead:not([hidden]) { display: grid; grid-template-columns: minmax(0, 1fr) 180px 140px 140px 140px; column-gap: 16px; align-items: center; height: 44px; padding: 0 16px 0 68px; margin-bottom: -12px; border-radius: 16px 16px 0 0; background: var(--vf-table-head); border: var(--vf-card-border); border-bottom: 0; font: var(--vf-t-caption-strong); color: var(--vf-text-2); }
  .hist-thead:not([hidden]) + .hist-card { border-radius: 0 0 16px 16px; }
  .hist-thead span:nth-child(4) { text-align: right; }
  .hist-page .hist-row { min-height: 60px; padding: 8px 16px; }
  .hist-page .hist-info { display: grid; grid-template-columns: minmax(0, 1fr) 180px 140px 140px 140px; grid-template-rows: auto auto; column-gap: 16px; row-gap: 0; align-items: center; }
  .hist-page .hist-main, .hist-page .hist-sub { display: contents; }
  .hist-page .hist-label { grid-column: 1; grid-row: 1; }
  .hist-page .hist-type { display: block; grid-column: 1; grid-row: 2; font: var(--vf-t-caption); color: var(--vf-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .hist-page .hist-id { display: block; grid-column: 2; grid-row: 1 / span 2; font: var(--vf-t-code); font-size: 14px; color: var(--vf-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .hist-page .hist-when { display: block; grid-column: 3; grid-row: 1 / span 2; font: var(--vf-t-body-sm); color: var(--vf-text-1); white-space: nowrap; font-variant-numeric: tabular-nums; }
  .hist-page .hist-amount { grid-column: 4; grid-row: 1 / span 2; text-align: right; }
  .hist-page .spill { grid-column: 5; grid-row: 1 / span 2; justify-self: start; }
  .hist-page .hist-date { display: none; }
}

/* Detail (C2): full screen on phones, page layout >= 1024 — head card (tile 44, h2, subline, amount price-lg + status
   chip), the row's own detail block (data rows on surface-3, KV), help card "Butuh bantuan?" + Hubungi. */
.hist-dv .vf-status__body { max-width: calc(560px + 32px); }
.hist-dv__main, .hist-dv__side { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.hist-dv__summary { gap: 12px; }
.hist-dv__sumrow { display: grid; grid-template-columns: 44px minmax(0, 1fr); grid-template-areas: "tile text" "amount amount"; gap: 12px; align-items: center; }
.hist-dv__tile { grid-area: tile; }
.hist-dv__tile .hist-icon { width: 44px; height: 44px; border-radius: 12px; display: inline-flex; align-items: center; justify-content: center; font-size: 22px; background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
.hist-dv__sumtext { grid-area: text; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.hist-dv__name { margin: 0; font: var(--vf-t-h2); color: var(--vf-text-1); overflow-wrap: anywhere; }
.hist-dv__meta { margin: 0; font: var(--vf-t-small); color: var(--vf-text-2); }
.hist-dv__amount { grid-area: amount; margin: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; font: var(--vf-t-price-lg); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
.hist-dv__chip { display: none; }
.hist-dv__detail { padding: 8px var(--vf-card-pad) var(--vf-card-pad); gap: 0; }
.hist-dv__detail .hist-detail { display: block !important; padding: 0; border: 0; background: none; }
.hist-dv__detail .rs-kv { border: 0; display: flex; flex-direction: column; }
.hist-dv__detail .rs-kv__row { display: grid; grid-template-columns: var(--vf-kv); gap: var(--vf-kv-gap); padding: var(--vf-kv-row); border-bottom: 1px solid var(--vf-border); }
.hist-dv__detail .rs-kv__row:last-child { border-bottom: 0; }
.hist-dv__detail .rs-kv__key { font: var(--vf-t-caption); color: var(--vf-text-2); }
.hist-dv__detail .rs-kv__val { max-width: none; text-align: left; font: var(--vf-t-ui); color: var(--vf-text-1); overflow-wrap: anywhere; }
@media (min-width: 576px) { .hist-dv__detail .rs-kv__row { grid-template-columns: 120px minmax(0, 1fr); gap: 16px; } .hist-dv__detail .rs-kv__key { font-size: 14px; line-height: 18px; } }
.hist-dv__detail .hist-code { font: var(--vf-t-code); }
.hist-dv__detail .cred-row { min-height: 48px; margin-top: 8px; padding: 4px 4px 4px 8px; border: 0; border-radius: 12px; background: var(--vf-surface-3); }
.hist-dv__detail .cred-row-val { font: var(--vf-t-code); }
.hist-dv__detail .hist-actions { display: flex; flex-wrap: wrap; gap: 8px; padding-top: 12px; }
.hist-dv__detail .hist-actions .vf-btn { min-height: 48px; }
.hist-dv__help { flex-direction: row; align-items: center; gap: 12px; padding: 12px 12px 12px 16px; background: var(--vf-surface-2); box-shadow: var(--vf-e1); }
.hist-dv__helpic { width: 36px; height: 36px; flex: none; border-radius: 12px; background: var(--vf-accent-subtle); color: var(--vf-accent-text); display: inline-flex; align-items: center; justify-content: center; }
.hist-dv__helpic .rs-icon { width: 18px; height: 18px; }
.hist-dv__helptext { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; font: var(--vf-t-caption); color: var(--vf-text-2); }
.hist-dv__helptext strong { font: var(--vf-t-ui-strong); color: var(--vf-text-1); }
.hist-dv__helpbtn { flex: none; min-height: 48px; border: 1px solid var(--vf-border-strong); color: var(--vf-text-1); }
.hist-dv .vf-status__body { padding-bottom: 32px; }
@media (min-width: 1024px) {
  .hist-dv .vf-status__body { max-width: calc(1200px + 64px); padding: 32px; display: grid; grid-template-columns: minmax(0, 1fr) 392px; gap: 24px; align-items: start; }
}

/* =====================================================================
   PHASE 12 — PROFIL (D1 Profil) — views/profile.ejs. Head card, then groups "Akun" | "Preferensi" (2 columns
   >= 1024); list rows 56 with chevron; Tampilan = segmented Terang / Gelap / Sistem (38 in a 44 track); Keluar.
   ===================================================================== */
.pf-page { max-width: calc(var(--vf-w-list) + 2 * var(--vf-page-pad)); padding-top: 0; gap: 0; }
.pf-head { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 16px; }
.pf-head #photoInput { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.pf-page .pf-avatar-wrap { position: relative; width: 56px; height: 56px; flex: none; padding: 0; border: 0; border-radius: 999px; background: none; cursor: pointer; }
.pf-page .pf-avatar, .pf-page .pf-avatar-initials { width: 56px; height: 56px; border-radius: 999px; }
.pf-page .pf-avatar-initials { display: flex; align-items: center; justify-content: center; background: var(--vf-accent-subtle); color: var(--vf-accent-text); font: 600 20px/1 var(--vf-font-head); }
.pf-page .pf-avatar-edit-btn { position: absolute; right: -2px; bottom: -2px; width: 24px; height: 24px; border-radius: 999px; background: var(--vf-surface-2); border: 1px solid var(--vf-border); color: var(--vf-text-2); display: inline-flex; align-items: center; justify-content: center; font-size: 12px; }
.pf-page .pf-avatar-wrap::after { content: ''; position: absolute; inset: -4px; }
.pf-head__text { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.pf-head__name { margin: 0; font: var(--vf-t-h2); color: var(--vf-text-1); overflow-wrap: anywhere; }
.pf-head__email { margin: 0; font: var(--vf-t-body-sm); color: var(--vf-text-2); overflow-wrap: anywhere; }
.pf-head__role { margin-top: 4px; height: 22px; padding: 0 8px; font: 600 12px/22px var(--vf-font); border-radius: 6px; }
.pf-head .pf-tier { flex: 1 1 100%; }
.pf-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 24px; align-items: start; }
.pf-col { display: flex; flex-direction: column; min-width: 0; }
@media (min-width: 1024px) { .pf-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.pf-page .pf-section { margin-top: 16px; }
.pf-group { margin: 0 0 8px; padding: 0 4px; font: var(--vf-t-caption-strong); color: var(--vf-text-2); }
.pf-page .pf-list { padding: 0; }
.pf-page .acc-item + .acc-item, .pf-page .acc-item + .pf-linkrow, .pf-page .pf-linkrow + .pf-linkrow { border-top: 1px solid var(--vf-border); }
.pf-page .acc-trigger, .pf-linkrow { width: 100%; min-height: 56px; padding: 8px 12px 8px 16px; border: 0; background: none; display: flex; align-items: center; gap: 12px; text-align: left; color: var(--vf-text-1); text-decoration: none; cursor: pointer; }
.pf-page .acc-trigger:hover, .pf-linkrow:hover { background: var(--vf-surface-3); color: var(--vf-text-1); }
.pf-page .acc-icon { width: 20px; height: 20px; flex: none; display: inline-flex; align-items: center; justify-content: center; color: var(--vf-text-2); background: none; border-radius: 0; font-size: 18px; }
.pf-page .acc-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0; }
.pf-page .acc-title { font: 500 16px/24px var(--vf-font); color: var(--vf-text-1); }
.pf-page .acc-subtitle { font: var(--vf-t-caption); color: var(--vf-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pf-page .acc-chevron { color: var(--vf-text-3); transform: rotate(-90deg); }
.pf-page .acc-item.open .acc-chevron { transform: rotate(0deg); }
.pf-chev { color: var(--vf-text-3); flex: none; width: 16px; margin-right: 4px; }
.pf-page .acc-panel-inner { padding: 4px 16px 16px; }
.pf-page .acc-panel-inner form { max-width: none; display: flex; flex-direction: column; gap: 12px; }
.pf-sep { border: 0; border-top: 1px solid var(--vf-border); margin: 16px 0; }
.pf-pref { min-height: 56px; padding: 8px 8px 8px 16px; display: flex; align-items: center; gap: 12px; }
.pf-pref .acc-title { flex: 1; }
.vf-seg.pf-mode { display: inline-grid; grid-template-columns: repeat(3, auto); gap: 2px; padding: 3px; border-radius: var(--vf-r-ctl); background: var(--vf-surface-3); }
.pf-mode .vf-seg__item { min-height: 38px; padding: 0 8px; border: 0; border-radius: 8px; background: none; color: var(--vf-text-2); font: var(--vf-t-caption-md); cursor: pointer; position: relative; }
.pf-mode .vf-seg__item::before { content: ''; position: absolute; inset: -5px 0; }
.pf-mode .vf-seg__item[aria-checked="true"] { background: var(--vf-surface-2); color: var(--vf-text-1); font-weight: 600; box-shadow: var(--vf-e1); }
.pf-page .pf-logout { margin-top: 16px; }
.pf-logout__btn { color: var(--vf-danger); }
.pf-logout__btn:hover { color: var(--vf-danger); background: var(--vf-danger-subtle); }
.pf-page .pf-flash { margin-bottom: 16px; }

/* =====================================================================
   PHASE 11 SCOPE 6 — ADMIN (board "Screens - Admin")
   Shell: phone 56px app bar (wordmark + inverse "Admin" chip + 48px menu → sidebar drawer, no bottom nav);
   desktop 248px sidebar, items 44px, active = accent-subtle + accent text. Content pad 16 / 32.
   ===================================================================== */

/* Dashboard KPI groups: 3 groups x 3 tiles, always one row of 3. Phone: tiles are separate cards;
   desktop: one card per group. Money uses the short form below 1280. */

/* Chart card "Order 7 hari terakhir": bars (accent, r-4 top) or the empty state (dashed area keeps the height). */

/* Admin tables (board S7.2/S7.3): header 44px tinted, rows 56–60px, money right-aligned tabular, chips,
   48px row menu; below 1024 the users table becomes 72px list rows (avatar, name, role chip, saldo right). */

/* Admin Transaksi tables (legacy .table-card markup) on the board's table spec. */

/* 769–1439: Metode moves to the row detail (it is listed there) so Aksi stays visible without sideways scroll. */

/* ===== ADMIN — Panels: server cards + stock stepper (board S7.4) ===== */

/* ===== ADMIN — Settings: underline tabs 48px, main column + 340px hint column (board S7.5) ===== */

/* Config problem shown inside the tab where it is fixed (phase 10 D14), info-subtle like the hints. */
.cfg-hint { display: flex; align-items: flex-start; gap: 8px; margin: 0 0 16px; padding: 12px 16px; border-radius: var(--vf-r-ctl); background: var(--vf-info-subtle); color: var(--vf-text-1); font: var(--vf-t-small-loose); }
.cfg-hint .rs-icon { flex: none; margin-top: 2px; color: var(--vf-info); }

/* ===== ADMIN — Settings › Tema: pinned "Kembali ke default" + 7 theme tiles (Design System 2.6, board S7.5) ===== */
.th-current { display: flex; align-items: center; gap: 12px; padding: 12px 16px; margin: 0 0 16px; background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: var(--vf-r-card); box-shadow: var(--vf-e1); }
@media (max-width: 767.98px) { .th-current { position: sticky; top: 104px; z-index: 30; } }
.th-current__text { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
.th-current__text b { font: var(--vf-t-ui-strong); color: var(--vf-text-1); }
.th-current__text span { font: var(--vf-t-caption); color: var(--vf-text-2); }
.th-current__reset { flex: none; }
.th-current__reset:disabled { opacity: 1; color: var(--vf-text-3); background: var(--vf-surface-3); border-color: transparent; cursor: default; }
.th-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 575.98px) { .th-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; } }
.th-tile { --pv-s1: #F4F5FA; --pv-s2: #FFFFFF; --pv-bd: #E4E4EE; --pv-ac: #4B3FD6; --pv-on: #FFFFFF; --pv-tx: #1E1B4B; --pv-r: 16px; --pv-rb: 12px;
  display: flex; flex-direction: column; align-items: stretch; gap: 4px; min-width: 0; padding: 8px 8px 12px; text-align: left; cursor: pointer;
  background: var(--vf-surface-2); border: 1px solid var(--vf-border-strong); border-radius: var(--vf-r-ctl); color: var(--vf-text-1); font: inherit; }
.th-tile:hover { border-color: var(--vf-accent); }
.th-tile[aria-checked="true"] { border-color: var(--vf-accent); box-shadow: 0 0 0 1px var(--vf-accent); }
.th-tile__pv { display: flex; flex-direction: column; justify-content: space-between; gap: 8px; height: 76px; padding: 8px; margin-bottom: 4px; background: var(--pv-s1); border-radius: calc(var(--pv-rb) - 2px); }
.th-tile__bar { display: flex; flex-direction: column; gap: 4px; padding: 8px 8px; background: var(--pv-s2); border: 1px solid var(--pv-bd); border-radius: calc(var(--pv-r) / 2); }
.th-tile__bar span { display: block; height: 4px; border-radius: 2px; background: var(--pv-tx); opacity: .7; width: 70%; }
.th-tile__bar span + span { width: 45%; opacity: .35; }
.th-tile__pill { align-self: flex-start; padding: 2px 8px; background: var(--pv-ac); color: var(--pv-on); border-radius: calc(var(--pv-rb) / 1.5); font: var(--vf-t-caption-strong); }
.th-tile__name { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font: var(--vf-t-ui-strong); }
.th-tile__modes { font: var(--vf-t-caption-md); color: var(--vf-text-2); }
.th-tile__desc { font: var(--vf-t-caption); color: var(--vf-text-3); }
@media (max-width: 575.98px) { .th-tile__desc { display: none; } }
/* Tile previews show each theme's own colours (light version) whatever theme the admin page currently wears. */
.th-tile--kertas   { --pv-s1: #F6F4EF; --pv-s2: #FFFFFF; --pv-bd: #E7E3D9; --pv-ac: #4338CA; --pv-on: #FFFFFF; --pv-tx: #1D1B17; --pv-r: 12px; --pv-rb: 10px; }
.th-tile--arena    { --pv-s1: #0B0B0E; --pv-s2: #16161B; --pv-bd: #2A2A31; --pv-ac: #FF6B2C; --pv-on: #1A0A00; --pv-tx: #F4F4F6; --pv-r: 8px;  --pv-rb: 6px; }
.th-tile--terminal { --pv-s1: #050A07; --pv-s2: #0C1610; --pv-bd: #1B2E21; --pv-ac: #3DDC84; --pv-on: #04140A; --pv-tx: #E3F5EA; --pv-r: 8px;  --pv-rb: 6px; }
.th-tile--sakura   { --pv-s1: #FFF5F8; --pv-s2: #FFFFFF; --pv-bd: #F3D3DF; --pv-ac: #C2255C; --pv-on: #FFFFFF; --pv-tx: #3B0F22; --pv-r: 20px; --pv-rb: 16px; }
.th-tile--emas     { --pv-s1: #0F0D08; --pv-s2: #1A160D; --pv-bd: #3A3220; --pv-ac: #D4A93C; --pv-on: #1A1405; --pv-tx: #F6F0E0; --pv-r: 12px; --pv-rb: 10px; }
.th-tile--samudra  { --pv-s1: #F2F7FA; --pv-s2: #FFFFFF; --pv-bd: #D3E2EA; --pv-ac: #0B6E8A; --pv-on: #FFFFFF; --pv-tx: #0C2A36; --pv-r: 12px; --pv-rb: 10px; }
.th-pick__note { margin: 12px 0 0; }

/* ===== Touch targets (scope 9 crawl): every phone target ≥ 44 × 44 ===== */
.rs-alert__body > a:only-child { display: inline-flex; align-items: center; min-height: 48px; }

/* Admin › Transaksi › Order panel (admin gaps tab) */
.panel-order-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
.panel-order-error { margin-top: 4px; font: var(--vf-t-small); color: var(--vf-danger); }
.panel-order-note { display: block; margin-top: 4px; font: var(--vf-t-caption); color: var(--vf-text-2); }

/* Text tones (status words inside sentences) */
.vf-tone-success { color: var(--vf-success); }
.vf-tone-warning { color: var(--vf-warning); }
.vf-tone-danger { color: var(--vf-danger); }

/* ===== GENERATED UTILITIES (scope 8) — one class per former inline declaration; !important keeps inline precedence. ===== */

.u-ai-center { align-items:center !important; }
.u-ai-flex-start { align-items:flex-start !important; }
.u-b-1px-dashed-border-color { border:1px dashed var(--border-color) !important; }

.u-b-1px-solid-border-color { border:1px solid var(--border-color) !important; }
.u-b-1px-solid-rs-border { border:1px solid var(--vf-border) !important; }
.u-b-1px-solid-rs-danger-border { border:1px solid var(--rs-danger-border) !important; }
.u-b-1px-solid-rs-succe-n3be9 { border:1px solid var(--rs-success-border) !important; }

.u-b-none { border:none !important; }

.u-bc-border-color { border-color:var(--border-color) !important; }

.u-bg-bg-secondary { background:var(--bg-secondary) !important; }

.u-bg-rs-danger-bg { background:var(--vf-danger-subtle) !important; }

.u-bg-rs-success-bg { background:var(--vf-success-subtle) !important; }
.u-bg-rs-surface-2 { background:var(--vf-surface-3) !important; }
.u-bt-1px-solid-border-color { border-top:1px solid var(--border-color) !important; }
.u-c-accent-cyan { color:var(--accent-cyan) !important; }
.u-c-accent-green { color:var(--accent-green) !important; }
.u-c-accent-purple { color:var(--accent-purple) !important; }

.u-c-accent-yellow { color:var(--accent-yellow) !important; }
.u-c-rs-accent-text { color:var(--vf-accent-text) !important; }
.u-c-rs-danger { color:var(--vf-danger) !important; }

.u-c-rs-success { color:var(--vf-success) !important; }
.u-c-rs-text { color:var(--vf-text-1) !important; }
.u-c-rs-text-2 { color:var(--vf-text-2) !important; }
.u-c-rs-warning { color:var(--vf-warning) !important; }
.u-c-text-muted { color:var(--text-muted) !important; }
.u-c-text-primary { color:var(--text-primary) !important; }
.u-c-text-secondary { color:var(--text-secondary) !important; }

.u-cur-pointer { cursor:pointer !important; }

.u-display-flex-s { display:flex; }

.u-fd-column { flex-direction:column !important; }

.u-fs-rs-fs-md { font-size:var(--rs-fs-md) !important; }

.u-fs-rs-ts-base { font-size:var(--rs-ts-base) !important; }
.u-fs-rs-ts-caption { font-size:var(--rs-ts-caption) !important; }
.u-fs-rs-ts-sm { font-size:var(--rs-ts-sm) !important; }
.u-fsh-0 { flex-shrink:0 !important; }

.u-fw-400 { font-weight:400 !important; }
.u-fw-600 { font-weight:600 !important; }
.u-fw-rs-fw-regular { font-weight:var(--rs-fw-regular) !important; }
.u-fwr-wrap { flex-wrap:wrap !important; }
.u-fx-1 { flex:1 !important; }

.u-gap-rs-s-16 { gap:var(--rs-s-16) !important; }
.u-gap-rs-s-8 { gap:var(--rs-s-8) !important; }

.u-gcol-1-1 { grid-column:1/-1 !important; }
.u-jc-space-between { justify-content:space-between !important; }
.u-lh-rs-lh-auto { line-height:var(--rs-lh-auto) !important; }
.u-ls-0 { letter-spacing:0 !important; }
.u-m-0 { margin:0 !important; }

.u-m-rs-s-24-0 { margin:var(--rs-s-24) 0 !important; }
.u-m-rs-s-4-0 { margin:var(--rs-s-4) 0 !important; }
.u-maxh-220px { max-height:220px !important; }

.u-maxw-220px { max-width:220px !important; }
.u-maxw-260px { max-width:260px !important; }
.u-maxw-280px { max-width:280px !important; }
.u-maxw-420px { max-width:420px !important; }
.u-maxw-520px { max-width:520px !important; }

.u-mb-0 { margin-bottom:0 !important; }
.u-mb-rs-s-16 { margin-bottom:var(--rs-s-16) !important; }
.u-mb-rs-s-24 { margin-bottom:var(--rs-s-24) !important; }
.u-mb-rs-s-8 { margin-bottom:var(--rs-s-8) !important; }

.u-minh-220px { min-height:220px !important; }
.u-minh-56px { min-height:56px !important; }
.u-minw-0 { min-width:0 !important; }

.u-mt-0 { margin-top:0 !important; }
.u-mt-calc-1-x-rs-s-8 { margin-top:calc(-1 * var(--rs-s-8)) !important; }
.u-mt-rs-s-16 { margin-top:var(--rs-s-16) !important; }
.u-mt-rs-s-24 { margin-top:var(--rs-s-24) !important; }
.u-mt-rs-s-4 { margin-top:var(--rs-s-4) !important; }
.u-mt-rs-s-8 { margin-top:var(--rs-s-8) !important; }

.u-ofy-auto { overflow-y:auto !important; }

.u-p-rs-s-16 { padding:var(--rs-s-16) !important; }
.u-p-rs-s-16-rs-s-16 { padding:var(--rs-s-16) var(--rs-s-16) !important; }
.u-p-rs-s-16-rs-s-24 { padding:var(--rs-s-16) var(--rs-s-24) !important; }
.u-p-rs-s-24 { padding:var(--rs-s-24) !important; }
.u-p-rs-s-8-rs-s-16 { padding:var(--rs-s-8) var(--rs-s-16) !important; }

.u-pt-rs-s-16 { padding-top:var(--rs-s-16) !important; }
.u-r-radius-btn { border-radius:var(--radius-btn) !important; }
.u-r-rs-radius-lg { border-radius:var(--vf-r-card) !important; }

.u-r-rs-radius-sm { border-radius:var(--vf-r-ctl) !important; }
.u-ta-center { text-align:center !important; }

.u-ta-right { text-align:right !important; }

.u-tt-none { text-transform:none !important; }
.u-w-100pct { width:100% !important; }

.u-w-auto { width:auto !important; }
.u-wb-break-all { word-break:break-all !important; }
/* ===== END GENERATED UTILITIES ===== */

/* ==========================================================================
   Auth (D4 Masuk / D5 Daftar) — phase 12. Guest shell (normal top bar + slim footer, no bottom nav),
   centred h1 + sub, one card max 420 (Google → "atau" → fields → link → primary), switch link below.
   Fields: label 13/18 above a 48px input; error = 2px danger border + icon + message; eye toggle 48 hit.
   ========================================================================== */
body.vf-auth { margin: 0; min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; }
.vf-auth :where(h1, h2, p) { margin: 0; }
.vf-auth .auth-main { flex: 1; width: 100%; display: flex; flex-direction: column; align-items: center; padding: 24px var(--vf-page-pad) 32px; }
.vf-auth .auth-panel { width: 100%; max-width: 420px; }
.vf-auth .auth-head { text-align: center; margin-bottom: 16px; }
.vf-auth .auth-title { font: var(--vf-t-h1); color: var(--vf-text-1); }
.vf-auth .auth-sub { margin-top: 4px; color: var(--vf-text-2); font: var(--vf-t-body-sm); }
.vf-auth .auth-card { background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); padding: var(--vf-card-pad); display: flex; flex-direction: column; gap: 0; }
@media (min-width: 576px) { .vf-auth .auth-card { padding: var(--vf-card-pad); } }
@media (min-width: 1024px) { .vf-auth .auth-main { padding-top: 32px; } }
.vf-auth .auth-flash { margin-bottom: 16px; }
.vf-auth .auth-google { min-height: 48px; gap: 8px; font-weight: 600; }
.vf-auth .auth-divider { display: flex; align-items: center; gap: 12px; margin: 16px 0; color: var(--vf-text-3); font: var(--vf-t-caption); }
.vf-auth .auth-divider::before, .vf-auth .auth-divider::after { content: ""; flex: 1; height: 1px; background: var(--vf-border); }
.vf-auth .rs-field { display: flex; flex-direction: column; gap: 8px; margin: 0 0 16px; }
.vf-auth .rs-label { margin: 0; font: var(--vf-t-small-md); color: var(--vf-text-1); }
.vf-auth .rs-input { min-height: 48px; font-size: 16px; }
.vf-auth .rs-field.is-invalid .rs-input, .vf-auth .rs-input[aria-invalid="true"] { border: 2px solid var(--vf-danger); }
.vf-auth .rs-field .vf-field__error { margin: 0; }
.vf-auth .auth-field-hint { margin: 0; font: var(--vf-t-caption); color: var(--vf-text-2); }
/* Password field with the show/hide button inside the input (48px hit). */
.auth-pw { position: relative; }
.auth-pw .rs-input { padding-right: 48px; width: 100%; }
.auth-pw__toggle { position: absolute; top: 0; right: 0; bottom: 0; width: 48px; min-height: 48px; height: auto; color: var(--vf-text-3); }
.auth-pw__toggle:hover { background: transparent; color: var(--vf-text-1); }
.auth-pw__toggle[aria-pressed="true"] { color: var(--vf-text-1); }
/* +62 prefix (D5 Nomor WhatsApp) */

.vf-auth .auth-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: -2px 0 16px; }

.vf-auth .auth-check { display: inline-flex; align-items: center; gap: 8px; min-height: 48px; color: var(--vf-text-2); font: var(--vf-t-small); cursor: pointer; user-select: none; }
.vf-auth .auth-check input { width: 18px; height: 18px; margin: 0; accent-color: var(--vf-accent); }
.vf-auth .auth-link { background: none; border: 0; padding: 0; min-height: 48px; display: inline-flex; align-items: center; font: var(--vf-t-small-strong); color: var(--vf-accent-text); text-decoration: none; cursor: pointer; }
.vf-auth .auth-link:hover { text-decoration: underline; text-underline-offset: 2px; }
.vf-auth .auth-turnstile { margin-bottom: 16px; min-height: 65px; max-width: 100%; overflow: hidden; }
.vf-auth .auth-submit { min-height: 48px; }
.vf-auth .auth-alt { margin-top: 12px; text-align: center; color: var(--vf-text-2); font: var(--vf-t-body-sm); }
.vf-auth .auth-alt .auth-link { font-size: 14px; }
.vf-auth .auth-role { margin-top: 4px; }
.vf-auth .auth-role .auth-link { color: var(--vf-text-3); font-weight: 500; }
.vf-auth .auth-panel[data-auth-mode="admin"] [data-user-only] { display: none; }

/* ==========================================================================
   Error pages (D6 404 / D7 500): code Sora 700 64 accent · h2 · one sentence · primary + secondary 48.
   Centred, max 420. Header and (signed in) the bottom nav stay.
   ========================================================================== */
body.vf-errpage { margin: 0; min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; }
.vf-err { flex: 1; display: flex; align-items: center; justify-content: center; padding: 48px 16px; }
.vf-err__box { width: 100%; max-width: 420px; text-align: center; }
.vf-err__box > * { margin: 0; }
.vf-err__code { font: 600 64px/1 var(--vf-font-num); letter-spacing: -.02em; color: var(--vf-accent); font-variant-numeric: tabular-nums; }
.vf-err__title { margin-top: 12px; font: var(--vf-t-h2); color: var(--vf-text-1); }
.vf-err__text { margin-top: 8px; font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.vf-err__actions { margin-top: 20px; display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.vf-err__actions .vf-btn { min-height: 48px; padding: 0 16px; gap: 8px; font-size: 14px; }
.vf-err__ref { margin-top: 16px; font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-err__ref .vf-mono { color: var(--vf-text-1); cursor: copy; }

/* ==========================================================================
   Reading pages (D2 Info / D3 Syarat): width 720, h1 + sub, one card, h3 + --t-body text-2 per section, gap 20.
   ========================================================================== */
.vf-read { width: 100%; max-width: calc(var(--vf-w-read, 720px) + 2 * var(--vf-page-pad, 12px)); margin: 0 auto; padding: 12px var(--vf-page-pad, 12px) 32px; }
.vf-read :where(h1, h2, h3, p, ul) { margin: 0; }
.vf-read__head { margin-bottom: 16px; }
.vf-read__head h1 { font: var(--vf-t-h1); color: var(--vf-text-1); }
.vf-read__sub { margin-top: 4px; font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-read__card { background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); padding: var(--vf-card-pad); display: flex; flex-direction: column; gap: 24px; min-width: 0; }
@media (min-width: 576px) { .vf-read__card { padding: var(--vf-card-pad); } }
.vf-read__sec { display: flex; flex-direction: column; gap: 8px; min-width: 0; scroll-margin-top: calc(var(--vf-top-h, 52px) + 12px); }
.vf-read__sec h2 { font: var(--vf-t-card-title); color: var(--vf-text-1); }
.vf-read__sec p, .vf-read__sec li { font: 400 14px/20px var(--vf-font); color: var(--vf-text-2); overflow-wrap: anywhere; }
.vf-read__sec strong { color: var(--vf-text-1); font-weight: 600; }
.vf-read__sec a, .vf-read__inl { color: var(--vf-accent-text); font-weight: 600; text-decoration: none; }
.vf-read__sec a:hover, .vf-read__inl:hover { text-decoration: underline; text-underline-offset: 2px; }
.vf-read__inl { background: none; border: 0; padding: 0; font: inherit; font-weight: 600; cursor: pointer; }
.vf-read__links { list-style: none; padding: 0; display: flex; flex-direction: column; }
.vf-read__links li + li { border-top: 1px solid var(--vf-border); }
.vf-read__sec .vf-read__links a { display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 8px 0; color: var(--vf-text-1); font-weight: 400; text-decoration: none; }
.vf-read__links a > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.vf-read__links strong { font: var(--vf-t-ui); }
.vf-read__links small { font: var(--vf-t-caption); color: var(--vf-text-2); display: block; } /* phase 13: reading page — descriptions are never cut */
.vf-read__links .rs-icon { flex: none; color: var(--vf-text-3); }
.vf-read__faq { display: flex; flex-direction: column; }
.vf-read__faq details + details { border-top: 1px solid var(--vf-border); }
.vf-read__faq summary { min-height: 48px; display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none; font: var(--vf-t-ui); color: var(--vf-text-1); }
.vf-read__faq summary::-webkit-details-marker { display: none; }
.vf-read__faq summary::after { content: ""; margin-left: auto; flex: none; width: 8px; height: 8px; border-right: 2px solid var(--vf-text-3); border-bottom: 2px solid var(--vf-text-3); transform: rotate(45deg); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-read__faq details[open] summary::after { transform: rotate(-135deg); }
.vf-read__faq details > p { padding: 0 0 12px; }
.vf-read__bans { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 4px 12px; }
.vf-read__bans li { display: flex; align-items: center; gap: 8px; }
.vf-read__bans .rs-icon, .vf-read__bans .bi { color: var(--vf-danger); flex: none; }
.vf-read__credit { padding-top: 12px; border-top: 1px solid var(--vf-border); font: var(--vf-t-caption); color: var(--vf-text-3); }

/* ==========================================================================
   Category pages (D1 A2 Apk Premium / A3 Nokos / A4 Suntik Sosmed / A5 Panel / A6 Reseller):
   back row 48 → 8 → header (tile 36 + h1 + 14/20 description, action 48) → 16 → toolbar (search) → 16 → content.
   List width 1200, detail width 720. Grid = .vf-pgrid (3 columns at every width).
   ========================================================================== */
.vf-catpage { width: 100%; max-width: calc(var(--vf-w-list, 1200px) + 2 * var(--vf-page-pad, 12px)); margin: 0 auto; padding: 8px var(--vf-page-pad, 12px) 32px; }
.vf-catpage--detail { max-width: calc(var(--vf-w-read, 720px) + 2 * var(--vf-page-pad, 12px)); }
.vf-catpage :where(h1, h2, h3, p) { margin: 0; }
.vf-cathead { display: grid; grid-template-columns: 36px minmax(0, 1fr); column-gap: 12px; row-gap: 16px; align-items: start; margin-bottom: 16px; }
.vf-cathead__tile { width: 36px; height: 36px; border-radius: var(--vf-r-ctl); display: inline-flex; align-items: center; justify-content: center; background: var(--vf-surface-3); background: oklch(var(--vf-ph-l) var(--vf-ph-c) var(--pc-h, 240)); color: oklch(var(--vf-ic-l) var(--vf-ic-c) var(--pc-h, 240)); }
.vf-cathead__text { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.vf-cathead__title { font: var(--vf-t-h1); color: var(--vf-text-1); overflow-wrap: anywhere; }
.vf-cathead__desc { font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.vf-cathead__action { grid-column: 1 / -1; min-height: 48px; gap: 8px; }
@media (min-width: 576px) {
  .vf-cathead { grid-template-columns: 36px minmax(0, 1fr) auto; }
  .vf-cathead__action { grid-column: auto; align-self: center; }
}
@media (min-width: 1024px) { .vf-cathead { grid-template-columns: 40px minmax(0, 1fr) auto; } .vf-cathead__tile { width: 40px; height: 40px; } }
.vf-cattools { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 16px; }
.vf-search { position: relative; flex: 1 1 100%; display: flex; align-items: center; }
@media (min-width: 576px) { .vf-search { flex: 0 1 330px; } }
.vf-search > .rs-icon, .vf-search > .bi { position: absolute; left: 14px; width: 16px; height: 16px; color: var(--vf-text-3); pointer-events: none; }
.vf-search .rs-input { width: 100%; min-height: 48px; padding-left: 40px; font-size: 16px; border-radius: var(--vf-r-ctl); }
.vf-catpage .vf-empty { grid-column: 1 / -1; }
.vf-catpage .rs-seg { max-width: 100%; overflow-x: auto; }
/* Phase 12 QA (A2 at 360/390): "mulai Rp 24.000" does not fit a 3-column phone card (≈ 84–97px text width) and was
   clipped mid-number — a defect, so the audit wins over the frame here: "mulai" wraps above the amount when it does
   not fit, and the price slot keeps two lines in a grid that has any "mulai" price so rows stay aligned. */
@media (max-width: 575.98px) {
  .vf-pcard .vf-pcard__price { white-space: normal; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 3px; }
  .vf-pcard .vf-pcard__price > * { white-space: nowrap; flex: 0 0 auto; max-width: 100%; }
  .vf-pcard__price .vf-pcard__now { overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
  .vf-pgrid:has(.vf-pcard__from) .vf-pcard .vf-pcard__price, .vf-pgrid:has(.vf-pcard__sk) .vf-pcard .vf-pcard__price { min-height: 36px; align-content: flex-end; }
}
.vf-search .rs-input { background: var(--vf-surface-2); border: 1px solid var(--vf-border-strong); }
.vf-catpage__flash { margin-bottom: 16px; }
/* Grid items wrapped for filtering (Nokos / Suntik Sosmed): the wrapper is transparent to the grid. */
.vf-pgrid > .otp-prod-card, .vf-pgrid > .smm-plat-item { display: contents; }
.vf-pgrid > .otp-prod-card[hidden], .vf-pgrid > .smm-plat-item[hidden] { display: none; }
.vf-empty[hidden] { display: none; }

/* ---------- D1 A5 Panel Pterodactyl (views/panel.ejs) ---------- */
.pnl-page .pnl-block { margin-bottom: 16px; }
/* status: header (title + "SERVERn · cpu" mono caption, chip dot + text), 3 meters in one row (6px accent). */
.pnl-page .pnl-status { padding: var(--vf-card-pad); display: flex; flex-direction: column; gap: 12px; }
@media (min-width: 576px) { .pnl-page .pnl-status { padding: var(--vf-card-pad); } }
.pnl-page .pnl-status__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin: 0; }
.pnl-page .pnl-status__title { font: var(--vf-t-card-title); color: var(--vf-text-1); }
.pnl-page .pnl-status__meta { margin-top: 2px; font: var(--vf-t-mono-sm); color: var(--vf-text-2); letter-spacing: .02em; }
.pnl-page .srv-status-badge { display: inline-flex; align-items: center; gap: 8px; min-height: 28px; padding: 0 8px; border-radius: 999px; border: 0; font: var(--vf-t-caption-strong); background: var(--vf-success-subtle); color: var(--vf-success); white-space: nowrap; }
.pnl-page .srv-status-badge.offline { background: var(--vf-danger-subtle); color: var(--vf-danger); }
.pnl-page .srv-status-badge.is-checking { background: var(--vf-surface-3); color: var(--vf-text-2); }
.pnl-page .srv-stats-rows { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
@media (min-width: 1024px) { .pnl-page .srv-stats-rows { gap: 16px; } }
.pnl-page .srv-stat-row:first-child { order: 3; }
.pnl-page .srv-stat-meta { display: flex; align-items: baseline; justify-content: space-between; gap: 4px; margin-bottom: 8px; min-width: 0; }
.pnl-page .srv-stat-label { font: var(--vf-t-caption); color: var(--vf-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.pnl-page .srv-stat-val { font: var(--vf-t-caption-strong); color: var(--vf-text-1); font-variant-numeric: tabular-nums; white-space: nowrap; }
.pnl-page .srv-stat-val .ping-chip { background: none; padding: 0; border: 0; font: inherit; color: inherit; }
@media (min-width: 1024px) { .pnl-page .srv-stat-label, .pnl-page .srv-stat-val { font-size: 12px; line-height: 16px; } }
.pnl-page .srv-bar-track { height: 6px; background: var(--vf-surface-3); border-radius: 999px; overflow: hidden; }
.pnl-page .srv-bar-fill { height: 100%; background: var(--vf-accent); border-radius: inherit; }
.pnl-page .srv-divider { margin: 0; border: 0; border-top: 1px solid var(--vf-border); }
.pnl-page .srv-counters { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.pnl-page .srv-counter-lbl { font: var(--vf-t-caption); color: var(--vf-text-2); }
.pnl-page .srv-counter-val { font: var(--vf-t-card-title); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
.pnl-page .pnl-status__note { font: var(--vf-t-small); color: var(--vf-text-2); }
/* packages: phone rows (name + chip, spec caption, price / 30 hari, 48px Pilih); >= 1024 table. */
.pnl-pkgs__title { margin: 0 0 12px; }
.pnl-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "name btn" "cap btn" "price btn"; column-gap: 12px; row-gap: 2px; align-items: center; padding: 12px var(--vf-card-pad); background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); }
.pnl-row.is-picked { outline: 2px solid var(--vf-accent); outline-offset: -2px; }
.pnl-row__name { grid-area: name; display: flex; align-items: center; gap: 8px; min-width: 0; font: var(--vf-t-ui-strong); color: var(--vf-text-1); }
.pnl-row__name > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.pnl-row.is-out .pnl-row__name { font-weight: 500; }
.pnl-row__price { grid-area: price; font: 400 12px/16px var(--vf-font); color: var(--vf-text-2); }
.pnl-row__price b { font: var(--vf-t-num-sm); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
.pnl-row__btn { grid-area: btn; min-height: 48px; min-width: 64px; padding: 0 16px; }
.pnl-row__btn-l { display: none; }
.pnl-row__btn--off { background: var(--vf-surface-3); color: var(--vf-text-3); cursor: not-allowed; }
@media (min-width: 1024px) {
  .pnl-row { display: grid; grid-template-columns: minmax(0, 2.4fr) repeat(3, minmax(0, 1fr)) minmax(0, 1.3fr) 140px; grid-template-areas: none; column-gap: 16px; align-items: center; padding: 0 16px; }
  .pnl-row { min-height: 60px; border: 0; border-radius: 0; box-shadow: none; border-top: 1px solid var(--vf-border); }
  .pnl-row__name, .pnl-row__price, .pnl-row__btn { grid-area: auto; }
  .pnl-row__price { text-align: right; }
  .pnl-row__per { display: none; }
  .pnl-row__btn { justify-self: end; min-height: 40px; }
  .pnl-row__btn-s { display: none; } .pnl-row__btn-l { display: inline; }
}
/* order steps (after "Pilih") */
.pnl-order[hidden] { display: none !important; }
.pnl-order { margin-top: 8px; scroll-margin-top: calc(var(--vf-top-h, 52px) + 12px); }
#pnlPicked { scroll-margin-top: calc(var(--vf-top-h, 52px) + 12px); }
#pnlPicked:focus { outline: none; }
.pnl-picked__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.pnl-picked__change { min-height: 48px; }
.pnl-picked__price { font: var(--vf-t-small); color: var(--vf-text-2); }
.pnl-picked__price #pdPrice { font: var(--vf-t-price-lg); color: var(--vf-text-1); }

/* ---------- D1 A6 Upgrade ke Reseller (views/reseller-product.ejs) ---------- */
.rp-stack { display: flex; flex-direction: column; gap: 16px; }
.rp-page .rp-card { padding: var(--vf-card-pad); gap: 12px; }
@media (min-width: 576px) { .rp-page .rp-card { padding: var(--vf-card-pad); } }
.rp-hero { flex-direction: row !important; align-items: center; gap: 16px !important; }   /* beats .rp-page .rp-card and .vf-card on the same element */
.rp-logo { position: relative; width: 56px; height: 56px; flex: none; border-radius: 12px; overflow: hidden; display: inline-flex; align-items: center; justify-content: center; background: oklch(var(--vf-ph-l) var(--vf-ph-c) 275); color: oklch(var(--vf-ic-l) var(--vf-ic-c) 275); }
@media (min-width: 1024px) { .rp-logo { width: 56px; height: 56px; } }
.rp-logo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.rp-hero__text { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.rp-hero__name { margin: 0; font: 600 16px/24px var(--vf-font-head); color: var(--vf-text-1); overflow-wrap: anywhere; }
@media (min-width: 1024px) { .rp-hero__name { font-size: 20px; line-height: 28px; } }
.rp-hero__price { margin: 0; font: var(--vf-t-caption); color: var(--vf-text-2); }
.rp-hero__price b { font: var(--vf-t-price-lg); color: var(--vf-text-1); font-variant-numeric: tabular-nums; margin-right: 4px; }
.rp-hero__rating { margin: 0; display: inline-flex; align-items: center; gap: 4px; font: var(--vf-t-caption); color: var(--vf-text-2); }
.rp-hero__rating .rs-icon { color: var(--vf-warning); }
.rp-terms { color: var(--vf-text-1); }
.rp-summary .vf-kv__row + .vf-kv__row { border-top: 1px solid var(--vf-border); }
.rp-summary .is-short { color: var(--vf-danger); font-weight: 600; }
.rp-actions { display: flex; flex-direction: column; gap: 8px; }
.rp-actions form { margin: 0; display: flex; }
.rp-actions .vf-btn { width: 100%; min-height: 48px; }
@media (min-width: 576px) { .rp-actions--2 { display: grid; grid-template-columns: 1fr 1fr; } }
.rp-actions .vf-btn:disabled { background: var(--vf-surface-3); color: var(--vf-text-3); border-color: transparent; opacity: 1; }

/* ---------- D1 E4 OTP service (views/otp/_template.ejs + public/js/otp.js) ---------- */
.otp-page .otp-servers { display: flex; width: 100%; margin-bottom: 16px; }
.otp-page .otp-servers .rs-seg__item { flex: 1 1 0; white-space: nowrap; }
@media (min-width: 576px) { .otp-page .otp-servers { width: auto; max-width: 420px; } }
.otp-page .otp-form { background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); padding: var(--vf-card-pad); }
@media (min-width: 576px) { .otp-page .otp-form { padding: var(--vf-card-pad); } }
.otp-page .otp-fields { counter-reset: otpstep; }
.otp-page .otp-field:not(.d-none) .rs-label { display: inline-flex; align-items: center; gap: 8px; font: var(--vf-t-small-md); color: var(--vf-text-1); }
.otp-page .otp-field:not(.d-none) .rs-label::before { counter-increment: otpstep; content: counter(otpstep); width: 18px; height: 18px; flex: none; border-radius: 999px; background: var(--vf-accent); color: var(--vf-on-accent); display: inline-flex; align-items: center; justify-content: center; font: 600 12px/1 var(--vf-font); }
.otp-page .otp-field .form-select { min-height: 48px; font-size: 16px; }
.otp-page .price-info-box { border-radius: var(--vf-r-ctl); background: var(--vf-surface-3); }
.otp-page .otp-actions { display: grid; grid-template-columns: 1fr; gap: 8px; margin-top: 12px; }
.otp-page .otp-actions .vf-btn { min-height: 48px; width: 100%; }
@media (min-width: 400px) { .otp-page .otp-actions { grid-template-columns: 1fr 1fr; } }
/* E4b–E4d order card: "Nomor kamu" + warning chip with mm:ss, mono number box with a 48px copy, dashed OTP slot. */
.otp-page .modern-card { background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); padding: var(--vf-card-pad); }
.otp-page .mc-label { font: var(--vf-t-card-title); color: var(--vf-text-1); }
.otp-page .mc-number { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 8px; min-height: 56px; padding: 0 4px 0 12px; border-radius: var(--vf-r-ctl); background: var(--vf-surface-3); font: 500 20px/28px var(--vf-font-mono); font-variant-numeric: tabular-nums; color: var(--vf-text-1); overflow-wrap: anywhere; }
.otp-page .mc-number.is-pending { font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.otp-page .mc-copy { width: 48px; height: 48px; flex: none; color: var(--vf-accent-text); }
.otp-page .mc-timer { display: inline-flex; align-items: center; gap: 4px; min-height: 24px; padding: 0 8px; border-radius: 999px; background: var(--vf-warning-subtle); color: var(--vf-warning); font: var(--vf-t-caption-strong); font-variant-numeric: tabular-nums; white-space: nowrap; }
.otp-page .mc-timer.is-muted { background: var(--vf-surface-3); color: var(--vf-text-2); }
.otp-page .otp-wait { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 56px; margin: 0; border: 1px dashed var(--vf-border-strong); border-radius: var(--vf-r-ctl); font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.otp-page .otp-badge { font: 600 28px/36px var(--vf-font-mono); letter-spacing: .12em; color: var(--vf-success); }
.otp-page .mc-actions .vf-btn { min-height: 48px; }
.otp-page .mc-btn-batal:not(:disabled) { background: var(--vf-surface-2); color: var(--vf-danger); border: 1px solid var(--vf-border-strong); }

/* ---------- D1 E5 APK Premium product (views/apkprem/_template.ejs) ---------- */
.ap-page .vf-pd2__head { position: relative; }
.ap-page .ap-tut { min-height: 48px; align-self: flex-start; }
.ap-opts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.ap-opt { position: relative; min-height: 64px; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px; padding: 8px 8px; text-align: left; background: var(--vf-surface-2); border: 1px solid var(--vf-border-strong); border-radius: var(--vf-r-ctl); color: var(--vf-text-1); font: inherit; cursor: pointer; }
.ap-opt:hover:not([disabled]) { border-color: var(--vf-accent); }
.ap-opt[aria-checked="true"] { border: 2px solid var(--vf-accent); padding: 7px 7px; background: var(--vf-accent-subtle); }
.ap-opt[aria-checked="true"] .ap-opt__name { color: var(--vf-accent-text); }
.ap-opt:focus-visible { outline: 2px solid var(--vf-focus, var(--vf-accent)); outline-offset: 2px; }
.ap-opt__name { font: var(--vf-t-caption); color: var(--vf-text-1); overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.ap-opt__price { font: 600 14px/20px var(--vf-font-num); font-variant-numeric: tabular-nums; color: var(--vf-text-1); white-space: nowrap; }
.ap-opt__was { font: var(--vf-t-caption); color: var(--vf-text-3); }
.ap-opt__meta { font: var(--vf-t-caption); color: var(--vf-text-2); }
.ap-opt.is-out { background: var(--vf-surface-3); border-color: transparent; opacity: .7; cursor: not-allowed; }
.ap-opt.is-out .ap-opt__name, .ap-opt.is-out .ap-opt__price { color: var(--vf-text-3); }
.ap-opt-skel { height: 64px; border-radius: var(--vf-r-ctl); }
@media (min-width: 1024px) { .ap-opt__name { font-size: 14px; line-height: 18px; } .ap-opt__price { font-size: 14px; line-height: 20px; } }
.ap-page .ap-desc { margin: 0; font: 400 14px/20px var(--vf-font); color: var(--vf-text-2); overflow-wrap: anywhere; }
.ap-page .ap-link { background: none; border: 0; padding: 0; font: inherit; font-weight: 600; color: var(--vf-accent-text); cursor: pointer; }
.ap-page .ap-state { grid-column: 1 / -1; box-shadow: none; border: 0; padding: 16px 0; }

/* ---------- D1 E6 Suntik Sosmed platform (views/smm/platform.ejs) ---------- */
.smm-plat .smm-srv { display: flex; width: 100%; margin-bottom: 16px; }
.smm-plat .smm-srv .vf-seg__item { flex: 1 1 0; }
@media (min-width: 576px) { .smm-plat .smm-srv { width: auto; max-width: 320px; } }
.smm-plat .smm-tools { flex-direction: column; align-items: stretch; }
@media (min-width: 576px) { .smm-plat .smm-tools .vf-search { flex: 0 1 auto; max-width: 330px; } }
.smm-plat .smm-chips { flex: 1 1 100%; }
.smm-plat .smm-chips .vf-fchip { min-height: 36px; flex: none; }
.smm-tbl { display: flex; flex-direction: column; gap: 8px; }
.smm-tbl__head { display: none; }
.smm-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "main btn" "price btn"; column-gap: 12px; row-gap: 4px; align-items: center; padding: 12px var(--vf-card-pad); background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); }
.smm-row[hidden] { display: none; }
.smm-row__id, .smm-row__range { display: none; }
.smm-row__main { grid-area: main; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.smm-row__name { font: var(--vf-t-ui-strong); color: var(--vf-text-1); overflow-wrap: anywhere; }
.smm-row__note { font: var(--vf-t-caption); color: var(--vf-text-2); overflow-wrap: anywhere; }
.smm-row__note:empty { display: none; }
.smm-row__price { grid-area: price; font: 400 12px/16px var(--vf-font); color: var(--vf-text-2); }
.smm-row__price b { font: var(--vf-t-num-sm); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
.smm-row__btn { grid-area: btn; min-height: 48px; min-width: 64px; padding: 0 16px; }
@media (min-width: 1024px) {
  .smm-tbl { gap: 0; background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); overflow: clip; }
  .smm-tbl__head, .smm-row { display: grid; grid-template-columns: 72px minmax(0, 1fr) 150px 150px 96px; grid-template-areas: none; column-gap: 16px; align-items: center; padding: 0 16px; }
  .smm-tbl__head { min-height: 44px; background: var(--vf-table-head, var(--vf-surface-3)); font: var(--vf-t-caption-strong); color: var(--vf-text-2); position: sticky; top: var(--vf-top-h, 64px); z-index: 1; }
  .smm-tbl__head > span:nth-child(3), .smm-tbl__head > span:nth-child(4) { text-align: right; }
  .smm-row { min-height: 60px; padding-top: 8px; padding-bottom: 8px; border: 0; border-radius: 0; box-shadow: none; border-top: 1px solid var(--vf-border); }
  .smm-row__id { display: block; font: var(--vf-t-code); color: var(--vf-text-2); }
  .smm-row__main, .smm-row__price, .smm-row__btn { grid-area: auto; }
  .smm-row__rangecap { display: none; }
  .smm-row__price { text-align: right; }
  .smm-row__per { display: none; }
  .smm-row__range { display: block; text-align: right; font: var(--vf-t-body-sm); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
  .smm-row__btn { justify-self: end; min-height: 40px; }
}

/* ---------- D1 E7 Suntik Sosmed order (views/smm/order.ejs) ---------- */
.smm-order .vf-cathead { margin-bottom: 16px; }
.smm-order .smm-form { padding: var(--vf-card-pad); gap: 16px; }
@media (min-width: 576px) { .smm-order .smm-form { padding: var(--vf-card-pad); } }
.smm-order .rs-field { display: flex; flex-direction: column; gap: 8px; margin: 0; }
.smm-order .rs-label { margin: 0; font: var(--vf-t-small-md); color: var(--vf-text-1); }
.smm-order .rs-input { min-height: 48px; font-size: 16px; }
.smm-order .rs-field.is-invalid .rs-input { border: 2px solid var(--vf-danger); }
.smm-order .vf-field__error { margin: 0; }
.smm-order .smm-qty { font: 600 16px/24px var(--vf-font-num); font-variant-numeric: tabular-nums; }
.smm-hint { margin: 0; font: var(--vf-t-caption); color: var(--vf-text-2); }
.smm-quick { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.smm-quick__btn { min-height: 48px; border-radius: var(--vf-r-ctl); border: 1px solid var(--vf-border-strong); background: var(--vf-surface-2); color: var(--vf-text-1); font: 600 14px/20px var(--vf-font-num); font-variant-numeric: tabular-nums; cursor: pointer; }
.smm-quick__btn[aria-pressed="true"] { border: 2px solid var(--vf-accent); background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
.smm-note { display: flex; flex-direction: column; gap: 4px; padding: 12px; border-radius: var(--vf-r-ctl); background: var(--vf-surface-3); font: var(--vf-t-small); color: var(--vf-text-2); }
.smm-note b { font-weight: 600; color: var(--vf-text-1); font-size: 12px; }
.smm-saldo { font: var(--vf-t-caption); color: var(--vf-text-2); }
.smm-saldo:empty { display: none; }
.smm-saldo.is-low { color: var(--vf-danger); }
.smm-order #btnSaldo { min-height: 48px; }
.smm-order #btnSaldo:disabled { background: var(--vf-surface-3); color: var(--vf-text-3); border-color: transparent; opacity: 1; }
.smm-paynote { margin: 0; font: var(--vf-t-small); color: var(--vf-text-2); text-align: center; }
.smm-paynote a { color: var(--vf-accent-text); font-weight: 600; }

/* ---------- D1 E8 Suntik Sosmed history (views/smm/history.ejs) ---------- */
.smm-hist .smm-hseg { display: flex; width: 100%; margin-bottom: 16px; overflow-x: auto; }
.smm-hist .smm-hseg .vf-seg__item { flex: 1 0 auto; white-space: nowrap; padding: 0 8px; font-size: 14px; }
@media (min-width: 576px) { .smm-hist .smm-hseg { width: auto; max-width: 520px; } }
.smm-htbl { display: flex; flex-direction: column; background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); overflow: clip; }
.smm-htbl__head { display: none; }
.smm-hrow { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "main cost" "main st" "prog prog"; column-gap: 12px; row-gap: 4px; padding: 12px var(--vf-card-pad); }
.smm-hrow + .smm-hrow { border-top: 1px solid var(--vf-border); }
.smm-hrow[hidden] { display: none; }
.smm-hrow__main { grid-area: main; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.smm-hrow__name { font: var(--vf-t-ui-strong); color: var(--vf-text-1); overflow-wrap: anywhere; }
.smm-hrow__target { font: var(--vf-t-caption); color: var(--vf-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.smm-hrow__id { display: none; }
.smm-hrow__cost { grid-area: cost; justify-self: end; font: var(--vf-t-num-sm); font-variant-numeric: tabular-nums; color: var(--vf-text-1); white-space: nowrap; }
.smm-hrow__st { grid-area: st; justify-self: end; }
.smm-hrow__st .vf-chip { min-height: 22px; font-size: 12px; padding: 0 8px; }
.smm-hrow__st .vf-chip .rs-icon { display: none; }
.smm-hrow__prog { grid-area: prog; display: flex; flex-direction: column; gap: 8px; padding-top: 8px; min-width: 0; }
.smm-hrow__line { font: var(--vf-t-caption); color: var(--vf-text-2); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.smm-hrow__ref { display: none; }
.smm-hrow .refresh-btn { grid-area: prog; display: none; }
.smm-bar { display: block; height: 6px; border-radius: 999px; background: var(--vf-surface-3); overflow: hidden; }
.smm-bar > span { display: block; height: 100%; border-radius: inherit; background: var(--vf-accent); }
.smm-bar--done > span { background: var(--vf-success); }
.smm-bar--part > span { background: var(--vf-warning); }
/* phones: the refresh control sits on the count line */
@media (max-width: 1023.98px) {
  .smm-hrow { grid-template-areas: "main cost" "main st" "prog ref"; }
  .smm-hrow .refresh-btn { display: inline-flex; grid-area: ref; align-self: end; width: 48px; height: 48px; margin: -8px -8px -8px 0; }
}
@media (min-width: 1024px) {
  .smm-htbl__head, .smm-hrow { display: grid; grid-template-columns: minmax(0, 1fr) 170px 110px 190px 150px 48px; grid-template-areas: none; column-gap: 16px; align-items: center; padding: 0 16px; }
  .smm-htbl__head { min-height: 44px; background: var(--vf-table-head, var(--vf-surface-3)); font: var(--vf-t-caption-strong); color: var(--vf-text-2); position: sticky; top: var(--vf-top-h, 64px); z-index: 1; }
  .smm-htbl__head > span:nth-child(3) { text-align: right; }
  .smm-hrow { min-height: 60px; padding-top: 8px; padding-bottom: 8px; }
  .smm-hrow[hidden] { display: none; }
  .smm-hrow__main, .smm-hrow__cost, .smm-hrow__st, .smm-hrow__prog { grid-area: auto; justify-self: stretch; }
  .smm-hrow__id { display: block; font: var(--vf-t-code); color: var(--vf-text-2); overflow: hidden; text-overflow: ellipsis; }
  .smm-hrow__cost { text-align: right; }
  .smm-hrow__prog { padding: 0; }
  .smm-hrow__ref { display: block; }
  .smm-hrow .refresh-btn { display: inline-flex; grid-area: auto; width: 40px; height: 40px; }
}

/* ---------- D1 E9 Alight Motion flow (views/produk-alight-motion.ejs) ---------- */
.am-page .am-head { margin-bottom: 16px; }
.am-head__price { margin: 4px 0 0; font: var(--vf-t-small); color: var(--vf-text-3); }
.am-head__price b { font: var(--vf-t-price-lg); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
.am-page .am-card.vf-card { padding: var(--vf-card-pad); gap: 12px; margin-bottom: 16px; border-radius: 12px; }
@media (min-width: 576px) { .am-page .am-card.vf-card { padding: var(--vf-card-pad); } }
.am-page .am-card-label, .am-page .am-step-title { margin: 0; font: var(--vf-t-card-title); color: var(--vf-text-1); }
.am-page .am-step-sub, .am-page .am-field-label { font: var(--vf-t-small); color: var(--vf-text-2); }
.am-page .am-field-label { font-weight: 500; color: var(--vf-text-1); }
.am-page .am-input { min-height: 48px; font-size: 16px; border-radius: var(--vf-r-ctl); border: 1px solid var(--vf-border-strong); background: var(--vf-surface-2); color: var(--vf-text-1); padding: 0 12px; width: 100%; }
.am-page textarea.am-input { padding: 12px; min-height: 96px; }
.am-page .am-input:focus { outline: none; border-color: var(--vf-accent); box-shadow: 0 0 0 3px var(--vf-accent-subtle); }
.am-page .am-btn { min-height: 48px; border-radius: var(--vf-r-ctl); font: var(--vf-t-ui-strong); display: inline-flex; align-items: center; justify-content: center; gap: 8px; width: 100%; }
.am-page .am-btn-primary { background: var(--vf-accent); color: var(--vf-on-accent); border: 0; }
.am-page .am-btn-primary:disabled { background: var(--vf-surface-3); color: var(--vf-text-3); }
.am-page .am-btn-ghost { background: var(--vf-surface-2); color: var(--vf-text-1); border: 1px solid var(--vf-border-strong); width: auto; padding: 0 16px; }
.am-page .am-steps__bar { height: 6px; background: var(--vf-surface-3); }
.am-page .am-steps__item.is-current .am-steps__bar { background: var(--vf-accent); }
.am-page .am-steps__item.is-done .am-steps__bar { background: var(--vf-success); }
.am-page .am-steps__item { font: var(--vf-t-caption-md); }
.am-page .am-timer { display: inline-flex; align-items: center; min-height: 24px; padding: 0 8px; border-radius: 999px; background: var(--vf-warning-subtle); color: var(--vf-warning); font: var(--vf-t-caption-strong); font-variant-numeric: tabular-nums; }
.am-page .am-desc { background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); padding: var(--vf-card-pad); }
@media (min-width: 576px) { .am-page .am-desc { padding: var(--vf-card-pad); } }
.am-page .am-desc-title { margin: 0 0 8px; font: var(--vf-t-card-title); color: var(--vf-text-1); }

/* ---------- D1 E2 Panel success (views/panel-success.ejs) ---------- */
.ps-page { display: flex; flex-direction: column; gap: 16px; }
.ps-result { align-items: center; text-align: center; padding: 24px 16px; gap: 8px; }
.ps-ok { width: 56px; height: 56px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; background: var(--vf-success-subtle); color: var(--vf-success); }
.ps-title { margin: 4px 0 0; font: var(--vf-t-h2); color: var(--vf-text-1); }
.ps-sub { margin: 0; font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.ps-card { padding: var(--vf-card-pad); gap: 12px; }
@media (min-width: 576px) { .ps-card { padding: var(--vf-card-pad); } }
.ps-card__title { display: flex; align-items: center; gap: 8px; margin: 0; }
.ps-cred { display: flex; flex-direction: column; gap: 8px; }
.ps-cred__row { display: flex; align-items: center; gap: 4px; min-height: 56px; padding: 8px 4px 8px 12px; border-radius: var(--vf-r-ctl); background: var(--vf-surface-3); color: inherit; text-decoration: none; }
.ps-cred__text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ps-cred__label { font: var(--vf-t-caption); color: var(--vf-text-2); }
.ps-cred__val { font: var(--vf-t-code); color: var(--vf-text-1); overflow-wrap: anywhere; }
.ps-cred__val--muted { font: var(--vf-t-small); color: var(--vf-text-2); }
.ps-pass[data-mask="1"] { letter-spacing: .1em; }
.ps-cred__btn { width: 48px; height: 48px; flex: none; display: inline-flex; align-items: center; justify-content: center; border: 0; border-radius: var(--vf-r-ctl); background: transparent; color: var(--vf-accent-text); cursor: pointer; }
.ps-cred__btn:hover { background: var(--vf-surface-2); }
.ps-cred__row--link:hover { background: var(--vf-accent-subtle); }
.ps-actions { display: flex; flex-direction: column; gap: 8px; }
.ps-actions .vf-btn { min-height: 48px; width: 100%; }
@media (min-width: 576px) { .ps-actions { display: grid; grid-template-columns: 1fr 1fr; } }

/* ---------- D1 E3 Panel reseller (views/panel-reseller.ejs) ---------- */
.pr-page .pr-head { display: flex; flex-direction: column; gap: 4px; margin-bottom: 16px; }
.pr-grid { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.pr-side { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.pr-side > .pr-card, .pr-side > .rs-card { margin: 0; }
@media (min-width: 1024px) { .pr-grid { display: grid; grid-template-columns: minmax(0, 1fr) 392px; gap: 24px; align-items: start; } .pr-side { position: sticky; top: 88px; } }
.pr-list__head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.pr-list__count { font: var(--vf-t-caption); color: var(--vf-text-2); }
.pr-tbl { background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); overflow: clip; }
.pr-tbl__head { display: none; }
.pr-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "user st" "cap st"; column-gap: 12px; row-gap: 2px; align-items: center; min-height: 64px; padding: 12px var(--vf-card-pad); }
.pr-row + .pr-row { border-top: 1px solid var(--vf-border); }
.pr-row__user { grid-area: user; font: var(--vf-t-code); color: var(--vf-text-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.pr-row__cap { grid-area: cap; font: var(--vf-t-caption); color: var(--vf-text-2); overflow-wrap: anywhere; }
.pr-row__cell { display: none; }
.pr-row__st { grid-area: st; }
.pr-row__st .vf-chip { min-height: 22px; font-size: 12px; padding: 0 8px; }
.pr-row__st .vf-chip .rs-icon { display: none; }
@media (min-width: 1024px) {
  .pr-tbl__head, .pr-row { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) 90px 100px 96px; grid-template-areas: none; column-gap: 16px; align-items: center; padding: 0 16px; }
  .pr-tbl__head { min-height: 44px; background: var(--vf-table-head, var(--vf-surface-3)); font: var(--vf-t-caption-strong); color: var(--vf-text-2); }
  .pr-tbl__head > span:nth-child(4) { text-align: right; }
  .pr-row { min-height: 52px; }
  .pr-row__user, .pr-row__st { grid-area: auto; }
  .pr-row__cap { display: none; }
  .pr-row__cell { display: block; font: var(--vf-t-small); color: var(--vf-text-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .pr-row__price { text-align: right; font-variant-numeric: tabular-nums; }
}
.pr-page .pr-card { background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: 12px; box-shadow: var(--vf-e1); padding: var(--vf-card-pad); }
@media (min-width: 576px) { .pr-page .pr-card { padding: var(--vf-card-pad); } }
.pr-page .field-input, .pr-page .rs-input { min-height: 48px; font-size: 16px; }
.pr-page .btn-submit { min-height: 48px; }
.pr-page .srv-tabs { display: flex; width: 100%; overflow-x: auto; }
.pr-page .srv-tabs .rs-seg__item { flex: 1 0 auto; }
.pr-page .pkg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
.pr-page .pkg-item .d-block { display: block; }
.pr-page .pkg-name { font: var(--vf-t-ui-strong); }
.pr-page .pkg-price { font: var(--vf-t-num-sm); font-variant-numeric: tabular-nums; }
.pr-page .pkg-specs { font: var(--vf-t-caption); color: var(--vf-text-2); }
.vf-errstate__code { margin: 4px 0 0; font: var(--vf-t-caption); color: var(--vf-text-2); }

/* ---------- D2 AD1 Admin dashboard (views/admin/dashboard.ejs) ---------- */

/* AD1: KPI groups 2 + 1 from 1024 (money short form below 1280), chart bars tinted with today in accent + values. */

/* F13 action cells: buttons wrap, 44px targets, empty cell hidden in stacked rows. */
.vf-table td.is-actions { width: auto; white-space: nowrap; }
.vf-table td.is-actions .vf-btn { min-height: 40px; margin-left: 8px; }
.vf-table td.is-actions:empty { padding: 0; }
@media (max-width: 1023.98px) {
  .vf-table.vf-table--stack td.is-actions { flex-wrap: wrap; gap: 8px; white-space: normal; }
  .vf-table.vf-table--stack td.is-actions .vf-btn { min-height: 48px; margin: 0; flex: 1 1 auto; }
  .vf-table.vf-table--stack td.is-actions:empty { display: none; }
}

/* ---------- D2 AD11 Live Chat viewer (views/admin/livechat.ejs) — read-only ---------- */

/* P1-11/12/13: the toast as a manual popover (top layer) — reset the UA popover box; offsets come from the bottom-nav
   variable (64px bar floating 12px up) and the fixed action bar (84px), never a hard-coded 64px. */
.vf-toast { top: auto; width: auto; height: auto; margin: 0; border: 0; overflow: visible; inset-block-start: auto; }
.vf-toast[popover] { color: var(--vf-on-inverse); background: var(--vf-inverse); }
body.rs-has-bottomnav .vf-toast { bottom: calc(var(--rs-bottomnav-h) + 12px + env(safe-area-inset-bottom, 0px) + 12px); }
body.vf-has-actionbar .vf-toast { bottom: calc(84px + env(safe-area-inset-bottom, 0px) + 12px); }
body:not(.rs-has-bottomnav):not(.vf-has-actionbar) .vf-toast { bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
@media (min-width: 1024px) { body .vf-toast, body.rs-has-bottomnav .vf-toast, body.vf-has-actionbar .vf-toast { top: calc(var(--vf-top-h, 64px) + 24px); bottom: auto; } }

/* Item 9: no form control under 16px on phones (iOS zoom), incl. the old rule near ui.css:1819. */
@media (max-width: 767.98px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]), select, textarea, .rs-input, .rs-select, .form-control, .form-select { font-size: 16px !important; }
}
/* Item 10 (P1-15/16): profile service power buttons wrap into a 3-column grid on phones; the users pager wraps and
   shows "Halaman x / y" instead of a number row that overflows. */
@media (max-width: 575.98px) {
  .svc-power { display: grid !important; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; width: 100%; }
  .svc-power .vf-btn, .svc-power .vf-btn:first-child, .svc-power .vf-btn:last-child { border-radius: var(--vf-r-8, 8px); min-height: 48px; margin: 0; }
  
  
  
  
}

/* Item 11: generic stacked admin tables on phones (classes added by global-theme.js). */

.vf-fade-r { -webkit-mask-image: linear-gradient(90deg, black calc(100% - 32px), transparent); mask-image: linear-gradient(90deg, black calc(100% - 32px), transparent); }
.vf-fade-l { -webkit-mask-image: linear-gradient(90deg, transparent, black 32px); mask-image: linear-gradient(90deg, transparent, black 32px); }
.vf-fade-l.vf-fade-r { -webkit-mask-image: linear-gradient(90deg, transparent, black 32px, black calc(100% - 32px), transparent); mask-image: linear-gradient(90deg, transparent, black 32px, black calc(100% - 32px), transparent); }
/* KPI tiles 2-up on narrow phones where three would truncate (item 11). */

/* Item 12 (P1-21): 48px targets inside admin modals; the close button always sits last (right) in the header. */
.modal-overlay .modal-close, .adm-dialog .modal-close, .adm-dialog .adm-icon-btn { min-width: 48px; min-height: 48px; width: 48px; height: 48px; display: inline-flex; align-items: center; justify-content: center; }
.modal-overlay .modal-header, .adm-dialog__head { display: flex; align-items: center; gap: 8px; }
.modal-overlay .modal-header .modal-close, .adm-dialog__head .modal-close { order: 99; margin-left: auto; flex: none; }
.modal-overlay .btn, .modal-overlay .vf-btn, .modal-overlay .vf-btn, .adm-dialog .vf-btn, .adm-dialog .vf-btn, .modal-overlay .btn-system-action { min-height: 48px; }
.modal-overlay input:not([type="checkbox"]):not([type="radio"]), .modal-overlay select, .adm-dialog input:not([type="checkbox"]):not([type="radio"]), .adm-dialog select { min-height: 48px; }
.modal-overlay .modal-box, .adm-dialog__box { max-height: calc(100dvh - 32px); overflow-y: auto; overscroll-behavior: contain; }

/* Item 17: 100dvh after 100vh everywhere (page styles still say 100vh), sticky-safe overflow on the admin wrapper,
   and the left/right safe areas (landscape notch) on the page body; fixed bars already inset themselves. */
@supports (min-height: 100dvh) {
  html body .adm-wrapper, html body .adm-main, html body .app-wrapper { min-height: 100dvh; }
}

html body { padding-left: env(safe-area-inset-left, 0px); padding-right: env(safe-area-inset-right, 0px); }
html.vf-kb-open .smm-order #btnSaldo, html.vf-kb-open .vf-toast { /* keep the CTA in flow; toasts never cover the field being typed */ }
html.vf-kb-open .vf-toast { display: none; }
/* Item 7 (P2-06/07): a chip/badge never pushes its row wider than the screen. */
.vf-chip, .rs-badge { max-width: 100%; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ==========================================================================
   Phase 12b — phone consistency pass (owner: "mobile friendly, nothing too big, zoomed, uneven or untidy").
   One type floor (12px), one page gutter (--vf-page-pad 16) and one card padding (--vf-card-pad 16) on phones,
   every control >= 48px tall or with a 48px hit area (phase 13: 44 → 48, handoff README) that does not change the drawing.
   ========================================================================== */
/* hit areas that keep the drawn size (chips, saldo pill, category chip) */
.vf-saldo-chip, .vf-chip-cat, .vf-fchip, .vf-catchip, .vf-top__auth .vf-btn { position: relative; }
.vf-saldo-chip::after, .vf-top__auth .vf-btn::after { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: 48px; transform: translateY(-50%); }
.vf-chip-cat::after { content: ''; position: absolute; left: -4px; right: -4px; top: 50%; height: 48px; transform: translateY(-50%); }
.vf-fchip::after, .vf-catchip::after { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: 48px; transform: translateY(-50%); }
@media (max-width: 1023.98px) {
  /* segmented controls: one height everywhere */
  .vf-seg__item, .rs-seg__item, .vf-seg--nav .vf-seg__item { min-height: 48px; }
  /* footer links: 48 x 48 minimum */
  .vf-foot__links a, .vf-foot__links button { min-width: 48px; min-height: 48px; display: inline-flex; align-items: center; justify-content: center; }
  /* same heading rhythm on every page: h1 22/30, section 16/22, card title 15/20 */
  .vf-cathead__title, .vf-read__head h1, .vf-auth .auth-title, .vf-pd2__title, .adm-title { font: var(--vf-t-h1); }
  .vf-card__title, .vf-read__sec h2, .pnl-status__title, .rp-hero__name, .am-card-label, .am-step-title { font: var(--vf-t-card-title); }
  /* buttons: one height for primary actions on phones */
  .vf-btn:not(.vf-btn--sm):not(.vf-icon-btn), .vf-btn:not(.vf-btn--sm):not(.rs-icon-btn) { min-height: 48px; }
  /* no text under 12px anywhere on customer pages */
  .rs-help, .rs-error, .vf-help, small { font-size: max(12px, 1em); }
}
@media (max-width: 1023.98px) {
  html body .vf-seg__item, html body .rs-seg__item { min-height: 48px !important; height: auto !important; }
  html body .carousel-arrow { width: 48px; height: 48px; }
}
.am-page .am-card.vf-card { border: var(--vf-card-border); }
/* Phase 14 (replaces the phase-12b Saira rule): the store name is Fugaz One 400, 20px, no transform, no case change.
   Wins over every older wordmark rule (topbar, landing, auth, admin sidebar and phone bar). */
html body .rs-wordmark, html body .vf-wordmark { font-family: var(--vf-font-brand); font-weight: 400; font-size: 20px; line-height: 1.2; letter-spacing: 0; text-transform: none; transform: none; font-style: normal; padding-inline-end: 0; }
/* Phase 12b: footer on phones — the © line on its own row, the three links on one centred row (no orphan "Bantuan"). */
@media (max-width: 1023.98px) {
  .vf-foot__copy { flex-basis: 100%; text-align: center; padding: 8px 0 0; }
  .vf-foot__links { column-gap: 4px; }
}
/* Phase 12b: the card fact line never truncates mid-word on narrow 3-column grids — "Otomatis" under 430px. */
.vf-fact-short { display: none; }
@media (max-width: 429.98px) { .vf-fact-long { display: none; } .vf-fact-short { display: inline; } }
/* Phase 12b: the fixed action bar — total on the left, the button takes the rest of the row (no empty strip). */
@media (max-width: 1023.98px) {
  html body .vf-actionbar > .vf-btn, html body .vf-actionbar > form, html body .vf-actionbar > .vf-actionbar__cta, html body .vf-pd__action > .vf-btn, html body .vf-pd__action > button { flex: 1 1 auto; min-width: 0; width: auto; }
  .vf-actionbar > form > .vf-btn, .vf-actionbar > form > button { width: 100%; }
}
@media (max-width: 575.98px) { .vf-pd .pnl-mine > .vf-btn, .vf-pd .pnl-mine > .vf-btn, .pnl-page .pnl-mine > .vf-btn, .pnl-page .pnl-mine > .vf-btn { width: 100%; } }

/* =====================================================================================================
   PHASE 13 — audit P2 fixes (customer)
   ===================================================================================================== */
/* P2-40: the sheet handle is a drag target — no browser panning on it, and a 48px grab area. */
.vf-pop__handle { position: relative; touch-action: none; }
.vf-pop__handle::before { content: ""; position: absolute; left: 50%; top: 50%; width: 96px; height: 48px; transform: translate(-50%, -50%); }
/* P2-13: QR retry button inside the overlay. */
.qr-overlay #qr-retry { margin-top: 4px; }
/* P2-19: a disabled OTP server tab shows "Nonaktif" under its label instead of cutting it ("Nonak…"). */
.otp-page .otp-servers .rs-seg__item:disabled { flex-direction: column; gap: 0; white-space: normal; line-height: 16px; text-align: center; }
.otp-page .otp-servers .rs-seg__item:disabled .otp-servers__tag { display: block; font-size: 12px; line-height: 16px; }
/* P1-21 / P2-43: the keyed scroll lock also locks <html> (admin pages clip x on html, so a body lock alone let
   the page scroll behind dialogs). */
html.vf-scroll-locked { overflow: hidden; }
/* P2-24: masked password + eye toggle inside a field group (panel order, panel reseller). */
.vf-pwfield { position: relative; flex: 1 1 auto; min-width: 0; display: flex; }
.vf-pwfield > .rs-input, .vf-pwfield > .vf-input { flex: 1 1 auto; min-width: 0; padding-right: 52px; }
.vf-pwfield > [data-vf-pw-toggle] { position: absolute; right: 0; top: 50%; transform: translateY(-50%); width: 48px; height: 48px; display: inline-flex; align-items: center; justify-content: center; border: 0; background: none; color: var(--vf-text-2); cursor: pointer; border-radius: 12px; }
.vf-pwfield > [data-vf-pw-toggle]:hover { color: var(--vf-text-1); }
.pnl-group > .vf-pwfield > .rs-input { border-top-right-radius: 0; border-bottom-right-radius: 0; }
/* P2-26: OTP list retry under the field; APK "Bantuan" inline button gets a 48px target. */
.otp-field__msg { flex-wrap: wrap; }
.otp-field__retry { margin-left: auto; }
/* Decision 3: "Lupa password" row + link on Profil (restored). README: the link is a 48px target. */
button.pf-linkrow { font: inherit; }
.pf-forgot-link .pf-link { min-height: 48px; display: inline-flex; align-items: center; text-align: left; }

/* =====================================================================================================
   PHASE 13 — motion (owner: only the agreed tokens 150 / 200 / 300 ms) · D3 M1–M6 + M5 states
   in 200ms --vf-ease-in · out 150ms --vf-ease-out · press 100ms · slow 300ms (bars, section reveal)
   ===================================================================================================== */
:root { --vf-dur-slow: 300ms; --vf-press-scale: .96; }
@media (prefers-reduced-motion: reduce) { :root { --vf-dur-in: 0ms; --vf-dur-out: 0ms; --vf-dur-press: 0ms; --vf-dur-slow: 0ms; } }
/* D3 M1: under reduced motion every duration is 0, except spinners, which keep turning (no scale). */

/* M5 button states. Pressed = scale .96 (owner, phase 13), 100ms. Hover only where a real pointer hovers (P2-31: no
   "stuck" hover colour after a tap on phones). Reduced motion keeps a non-motion press cue (darker fill). */
.vf-btn:disabled:active, .vf-btn:disabled:active, .vf-btn[aria-busy="true"]:active { transform: none; }
@media (hover: none) {
  .vf-btn--primary:hover, .vf-btn--primary:hover { background: var(--vf-accent); }
  .vf-btn--secondary:hover, .vf-btn--secondary:hover { background: var(--vf-surface-2); }
  .vf-btn--tonal:hover, .vf-btn--tonal:hover { background: var(--vf-accent-subtle); }
  .vf-btn--ghost:hover, .vf-btn--ghost:hover, .vf-icon-btn:hover, .rs-icon-btn:hover { background: transparent; }
  .vf-catchip:hover { background: var(--vf-surface-2); }
  .vf-catchip.active:hover, .vf-catchip[aria-pressed="true"]:hover { background: var(--vf-text-1); }
  .rs-bottomnav__item:hover { color: inherit; }
  .pf-page .acc-trigger:hover, .pf-linkrow:hover { background: none; }
}
@media (prefers-reduced-motion: reduce) {
  .vf-btn:active, .vf-btn:active, .vf-catchip:active, .vf-icon-btn:active, .rs-icon-btn:active { transform: none; filter: brightness(.9); }
}
/* M5 success / error flash (VF.btnFlash): the label says what happened for 1.6 s, colour follows the status tokens. */
.vf-btn.is-success, .vf-btn.is-success { background: var(--vf-success-subtle); border-color: var(--vf-success); color: var(--vf-success); }
.vf-btn.is-error, .vf-btn.is-error { background: var(--vf-danger-subtle); border-color: var(--vf-danger); color: var(--vf-danger); }

/* M3 page transition: View Transitions across pages (Chrome / Edge / Safari 18.2+); top bar + bottom nav stay put,
   the bottom-nav pill slides to the new tab. Back / reload: no animation (global-theme.js skips it).
   Fallback (no View Transitions): the new <main> fades in 200ms (opacity only, so fixed bars inside it never move). */
@media (prefers-reduced-motion: no-preference) {
  .rs-topbar, .vf-top { view-transition-name: vf-top; }
  .rs-bottomnav.vf-bnav { view-transition-name: vf-bnav; }
  .vf-bnav__pill { view-transition-name: vf-bnav-pill; }
}
@media (prefers-reduced-motion: no-preference) {
  .rs-rv-anim { animation-duration: var(--vf-dur-slow); animation-timing-function: var(--vf-ease-in); }
  .rs-tab-fade { animation-duration: var(--vf-dur-in); }
}

/* M4 skeletons: shapes match the final layout; visible only after 300ms (fast loads never flash grey);
   shimmer 1.2s linear surface-3 → surface-2. */
.vf-skel--val { display: inline-block; width: 72px; height: 14px; vertical-align: middle; border-radius: 6px; }
.vf-skel--num { display: inline-block; width: 48px; height: 18px; vertical-align: middle; border-radius: 6px; }
.vf-skel-list { display: flex; flex-direction: column; }
.vf-skel-row { display: grid; grid-template-columns: 40px minmax(0, 1fr) 72px; gap: 12px; align-items: center; padding: 12px 16px; }
.vf-skel-row + .vf-skel-row { border-top: 1px solid var(--vf-border); }
.vf-skel-row .vf-skel--tile { width: 40px; height: 40px; aspect-ratio: auto; }
.vf-skel-row__text { display: flex; flex-direction: column; gap: 8px; }
.vf-skel-row__text .vf-skel--line:last-child { width: 60%; }
.vf-skel-kv { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 16px; padding: 12px 0; }
.vf-skel-kv + .vf-skel-kv { border-top: 1px solid var(--vf-border); }
.vf-skel-kv .vf-skel--line:last-child { justify-self: end; width: 70%; }

/* The M2 entry loader is gone (UX-FLK-01): an overlay that appears after the page has painted hides content that was already visible. */

/* M6 bottom nav: Deposit press .94 (100ms, rule above at .vf-bnav__fab), pill slides 200ms, nav never hides on scroll. */

/* =====================================================================================================
   PHASE 13 — 48px tap targets on phones (handoff README "Touch targets": phase 11/12 used 44 in places)
   ===================================================================================================== */
@media (max-width: 1023.98px) {
  .vf-search > input, .vf-search input, #histSearch, .hist-search input, .search-input, input[type="search"] { min-height: 48px; }
  .vf-icon-btn, .rs-icon-btn { min-width: 48px; min-height: 48px; }
  .vf-fchip, .vf-catchip, .vf-chip-cat { min-height: 40px; }
  .vf-auth .auth-link, .auth-link { min-height: 48px; min-width: 48px; display: inline-flex; align-items: center; justify-content: center; }
  #authRoleToggle { min-height: 48px; }
  .auth-check { min-height: 48px; display: inline-flex; align-items: center; gap: 12px; }
}
/* Buttons that sit inside a sentence ("… Buka Bantuan.") keep the text flow and get a 48px hit area. */
.ap-link--btn, .vf-read__inl { position: relative; }
.ap-link--btn::after, .vf-read__inl::after { content: ''; position: absolute; left: -4px; right: -4px; top: 50%; height: 48px; transform: translateY(-50%); }
/* Bootstrap modal close (OTP confirmation): 48 x 48 target, same icon size. */
.modal .btn-close { box-sizing: border-box; width: 48px; height: 48px; padding: 0; background-position: center; background-size: 14px; margin: -8px -8px -8px auto; }

/* =====================================================================================================
   PHASE 13 — D3 M8 component board: the pieces that had no shared class yet (all tokens, 48px targets).
   Existing pieces stay where they are: buttons (.vf-btn), inputs (.vf-input + aria-invalid), select/textarea,
   tabs/segmented (.vf-seg), chips (.vf-chip / .vf-fchip / .vf-catchip), status chips (partials/status-chip),
   stat tile (.vf-stat), saldo card (.vf-saldo*), product card (partials/product-card), list rows (.vf-row),
   table + phone rows (.vf-table / .vf-table--stack), key-value (.vf-kv), steppers (.vf-stepper, .vf-qty),
   pagination (.vf-pager), empty (.vf-empty), alert (.rs-alert), copy field (.vf-copy), timer chip (.vf-timer).
   ===================================================================================================== */
/* Inline field error (README "Inline errors"): 2px danger border, then icon + 12px message under the field. */
.vf-input[aria-invalid="true"], .rs-input[aria-invalid="true"], .vf-select[aria-invalid="true"], .vf-textarea[aria-invalid="true"], .rs-textarea[aria-invalid="true"] { border-color: var(--vf-danger); box-shadow: inset 0 0 0 1px var(--vf-danger); }
.vf-error .rs-icon, .rs-error .rs-icon { width: 16px; height: 16px; flex: none; }
/* Checkbox + radio: native control (accent colour follows the theme), 20px, the whole label is a 48px target. */
.vf-check, .vf-radio { display: inline-flex; align-items: center; gap: 12px; min-height: 48px; font: 400 16px/24px var(--vf-font); color: var(--vf-text-1); cursor: pointer; }
.vf-check input, .vf-radio input { width: 20px; height: 20px; margin: 0; flex: none; accent-color: var(--vf-accent); cursor: pointer; }
.vf-check input:focus-visible, .vf-radio input:focus-visible { outline: 2px solid var(--vf-accent); outline-offset: 2px; }
/* Switch: 44 x 26 track, 20px knob, 48px row; role="switch" + aria-checked on a <button>, or a checkbox inside. */
.vf-switch { position: relative; display: inline-flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 48px; font: 400 16px/24px var(--vf-font); color: var(--vf-text-1); cursor: pointer; background: none; border: 0; padding: 0; text-align: left; }
.vf-switch__track { position: relative; width: 44px; height: 26px; flex: none; border-radius: 999px; background: var(--vf-border-strong); }
.vf-switch__track::after { content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 999px; background: var(--vf-surface-2); box-shadow: var(--vf-e1); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-switch[aria-checked="true"] .vf-switch__track, .vf-switch input:checked + .vf-switch__track { background: var(--vf-accent); }
.vf-switch[aria-checked="true"] .vf-switch__track::after, .vf-switch input:checked + .vf-switch__track::after { transform: translateX(18px); }
.vf-switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.vf-switch:focus-visible .vf-switch__track, .vf-switch input:focus-visible + .vf-switch__track { box-shadow: 0 0 0 2px var(--vf-surface-1), 0 0 0 4px var(--vf-accent); }
/* Breadcrumb (≥ 1024 on admin and long flows). */
.vf-breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin: 0 0 8px; padding: 0; list-style: none; font: var(--vf-t-small); color: var(--vf-text-2); }
.vf-breadcrumb li + li::before { content: '›'; margin-right: 4px; color: var(--vf-text-3); }
.vf-breadcrumb a { color: var(--vf-text-2); text-decoration: none; display: inline-flex; align-items: center; min-height: 48px; }
.vf-breadcrumb a:hover { color: var(--vf-text-1); }
.vf-breadcrumb [aria-current="page"] { color: var(--vf-text-1); font-weight: 500; }
/* Progress bar (orders, SMM, uploads). */
.vf-progress { position: relative; height: 6px; border-radius: 999px; background: var(--vf-surface-3); overflow: hidden; }
.vf-progress__fill { position: absolute; inset: 0 auto 0 0; width: var(--vf-progress, 0%); border-radius: inherit; background: var(--vf-accent); }
.vf-progress--success .vf-progress__fill { background: var(--vf-success); }
.vf-progress--warning .vf-progress__fill { background: var(--vf-warning); }
/* Avatar: initial on accent-subtle, image cover. */
.vf-avatar { width: 40px; height: 40px; flex: none; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; overflow: hidden; background: var(--vf-accent-subtle); color: var(--vf-accent-text); font: 600 16px/1 var(--vf-font-head); }
.vf-avatar img { width: 100%; height: 100%; object-fit: cover; }
.vf-avatar--lg { width: 64px; height: 64px; font-size: 24px; }
/* QR card: QR always black on white in every theme (README). */
.vf-qr { display: inline-flex; padding: 12px; border-radius: 12px; background: var(--vf-qr-bg); border: 1px solid var(--vf-border); }
.vf-qr > img, .vf-qr > canvas { display: block; width: var(--vf-qr-size); height: var(--vf-qr-size); image-rendering: pixelated; }
/* Badge alias (count / label); status words use the status chip instead. */
.vf-badge { display: inline-flex; align-items: center; min-height: 20px; padding: 0 8px; border-radius: 999px; background: var(--vf-surface-3); color: var(--vf-text-2); font: var(--vf-t-caption-strong); white-space: nowrap; }
.vf-badge--accent { background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
/* Alert alias with the vf- name (same look as .rs-alert). */
.vf-alert { display: flex; gap: 12px; align-items: flex-start; padding: 12px 16px; border-radius: 12px; background: var(--vf-info-subtle); color: var(--vf-text-1); font: var(--vf-t-body-sm); }
.vf-alert--warning { background: var(--vf-warning-subtle); }
.vf-alert--danger { background: var(--vf-danger-subtle); }
.vf-alert--success { background: var(--vf-success-subtle); }

/* =====================================================================================================
   PHASE 13 — search on top (item 3) + live panel status (item 5), merged from p13-customer.css
   ===================================================================================================== */
/* Phase 13 customer additions (search on top, panel live status). Merged into ui.css at the end of phase 13. Tokens only. */
.p13-ssearch {
  --p13-stick: calc(var(--vf-top-h) + 1px + env(safe-area-inset-top, 0px));
  position: sticky; top: var(--p13-stick); z-index: var(--rs-z-sticky);
  margin-left: calc(-1 * var(--vf-page-pad)); margin-right: calc(-1 * var(--vf-page-pad));
  padding: 8px var(--vf-page-pad);
  background: var(--vf-surface-1);
  box-shadow: 0 1px 0 transparent;
}
.p13-ssearch.is-stuck { box-shadow: 0 1px 0 var(--vf-border); }

/* Dashboard: search + chips directly under the saldo card (the flex column's section gap is closed up). */
.vf-dash > .p13-ssearch { margin-top: -8px; margin-bottom: 0; }
.vf-dash > .p13-ssearch + .vf-catchips { margin-top: calc(-1 * var(--vf-section-gap)); margin-bottom: 0; }
.vf-dash > .p13-ssearch .search-bar-inner { background: var(--vf-surface-2); }
/* "Semua produk" lands below the stuck search when a chip, ?kategori= or ?q= scrolls it into view. */
.vf-dash #semua-produk { scroll-margin-top: calc(var(--vf-top-h) + 1px + env(safe-area-inset-top, 0px) + 64px + 8px); }

/* Category pages: the row replaces the old .vf-cattools search; chips follow it. */
.vf-catpage > .p13-ssearch { margin-bottom: 8px; }
.vf-catpage > .p13-ssearch .vf-search { flex: none; width: 100%; }
.vf-catpage > .p13-ssearch .vf-search .rs-input { min-height: 48px; }
@media (min-width: 576px) { .vf-catpage > .p13-ssearch .vf-search { max-width: 480px; } }
.vf-catpage .p13-cattools { margin-bottom: 16px; }
.vf-catpage .p13-cattools:empty, .vf-catpage .p13-cattools:not(:has(.vf-catchips)) { margin-bottom: 8px; }
.vf-catpage .p13-cattools .vf-catchips { flex: 1 1 100%; margin-bottom: 0; }

/* Chips: 48px tap height on phones (the 40px pill keeps its drawing). */
@media (max-width: 1023.98px) {
  .vf-catchip::after { height: 48px; }
}

/* ==========================================================================
   Item 5 — panel page (/panel-1 … /panel-4): live "Status server", "Panel kamu" (audit P2-10)
   Phone: Panel kamu → Status server → Server 1–4 → Paket tersedia → order steps (Pembayaran last).
   >= 1024: two columns — status (and Panel kamu) left, sticky under the top bar; server switch + packages right.
   ========================================================================== */
.p13-pnl { display: flex; flex-direction: column; min-width: 0; }
.p13-pnl__side, .p13-pnl__main { display: flex; flex-direction: column; min-width: 0; }
@media (min-width: 1024px) {
  .p13-pnl { display: grid; grid-template-columns: minmax(0, 380px) minmax(0, 1fr); gap: 24px; align-items: start; }
  .p13-pnl__side { position: sticky; top: calc(var(--vf-top-h) + 1px + 16px); }
}

/* Panel kamu (compact, near the top) */
.pnl-page .p13-mine { display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding: var(--vf-card-pad); }
.p13-mine__title { font: var(--vf-t-card-title); color: var(--vf-text-1); }
.p13-mine__meta { margin-top: 2px; font: var(--vf-t-body-sm); color: var(--vf-text-2); overflow-wrap: anywhere; }
.p13-mine__user { font-family: var(--vf-font-mono); color: var(--vf-text-1); }
.p13-mine__actions { display: flex; flex-wrap: wrap; gap: 8px; }
.p13-mine__actions .vf-btn { min-height: 48px; }
.p13-mine__note { flex: 1 1 100%; font: var(--vf-t-small); color: var(--vf-text-2); }
@media (max-width: 575.98px) { .p13-mine__actions { flex: 1 1 100%; } .p13-mine__actions .vf-btn { flex: 1 1 0; } }
@media (min-width: 1024px) { .p13-pnl__side .p13-mine__actions { flex: 1 1 100%; } .p13-pnl__side .p13-mine__actions .vf-btn { flex: 1 1 0; } }

/* Live status card */
.pnl-page .p13-live .srv-counters[hidden], .pnl-page .p13-live .srv-divider[hidden], .pnl-page .p13-live .srv-stats-rows[hidden], .p13-live__down[hidden] { display: none !important; }
.pnl-page .p13-live .srv-stats-rows { grid-template-columns: minmax(0, 1fr); gap: 16px; margin: 0; }
.pnl-page .p13-live .srv-stat-row:first-child { order: 0; }
.pnl-page .p13-live .srv-stat-meta { flex-wrap: wrap; align-items: baseline; gap: 2px 12px; margin-bottom: 8px; }
.pnl-page .p13-live .srv-stat-label { font: var(--vf-t-body-lg); color: var(--vf-text-2); overflow: visible; }
.pnl-page .p13-live .srv-stat-val { margin: 0; margin-left: auto; text-align: right; font: 600 16px/24px var(--vf-font); color: var(--vf-text-1); font-variant-numeric: tabular-nums; white-space: normal; }
.pnl-page .p13-live .p13-live__sub { display: block; font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.pnl-page .p13-live .srv-bar-track { height: 8px; }
.pnl-page .p13-live .srv-status-badge { min-height: 32px; font-size: 14px; line-height: 20px; }
.pnl-page .p13-live .srv-counter-lbl { font: var(--vf-t-body-sm); }
.pnl-page .p13-live .srv-counter-val { font: 600 18px/26px var(--vf-font-num); }

.p13-live__down { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }
.pnl-page .p13-live__down .pnl-status__note { font: var(--vf-t-body-lg); color: var(--vf-text-2); }
.p13-live__retry { min-height: 48px; }
.p13-live__foot { margin: 0; font: var(--vf-t-body-sm); color: var(--vf-text-2); font-variant-numeric: tabular-nums; }
@media (min-width: 1024px) {
  .pnl-page .p13-live .srv-stat-label, .pnl-page .p13-live .srv-stat-val { font-size: 14px; line-height: 20px; }
  .pnl-page .p13-live .p13-live__sub { font-size: 14px; line-height: 18px; }
  .pnl-page .p13-live__down .pnl-status__note { font-size: 14px; line-height: 20px; }
}

/* Packages in the right column (>= 1024): the table keeps its columns in the narrower space. */
@media (min-width: 1024px) {
  .p13-pnl__main .pnl-row { grid-template-columns: minmax(0, 2fr) repeat(3, minmax(0, 1fr)) minmax(0, 1.3fr) 120px; column-gap: 12px; }
  .p13-pnl__main .pnl-row__btn { padding: 0 12px; }
}

/* Phase 13: search field 48px tall on phones (README touch targets). */
.p13-ssearch input, .p13-ssearch .vf-input { min-height: 48px; }
/* Phase 13 QA: the "Isi saldo" link next to the saldo shortfall note gets a 48px hit area. */
.vf-pd2 .pd-pay-foot > a, .pd-pay-foot > a { position: relative; display: inline-flex; align-items: center; min-height: 48px; }

/* =====================================================================================================
   PHASE 14 — R2: spacing / radius / shadow tokens + component base (buttons, inputs, cards, chips)
   Reference look (Sairi pages): white cards with a 1px border and a soft shadow, 12 / 16 / 24 radii,
   pill chips, one accent per action. Colours stay the VF tokens; themes still override radius / elevation.
   Spacing scale (unchanged values, one name set): 4 · 8 · 12 · 16 · 24 · 32 (+ 48 · 64 for page rhythm).
   ===================================================================================================== */
:root {
  --vf-r-12: 12px; --vf-r-16: 16px; --vf-r-24: 24px;
  --vf-r-card: 16px;      /* cards, banner, dialogs */
  --vf-r-ctl: 12px;       /* buttons, inputs, tiles, product card */
  --vf-r-sheet: 24px;     /* phone sheets (top corners), hero cards */
  --vf-r-pill: 999px;     /* chips, badges, status chips, theme switch */
  --vf-e1: 0 1px 2px rgba(30, 27, 75, .05);
  --vf-e2: 0 1px 2px rgba(30, 27, 75, .05), 0 12px 32px -8px rgba(30, 27, 75, .14);
  --vf-e3: 0 24px 64px -12px rgba(30, 27, 75, .30);
  --vf-e-hover: 0 2px 4px rgba(30, 27, 75, .04), 0 16px 32px -12px rgba(30, 27, 75, .20);
  --vf-card-border: 1px solid var(--vf-border);
  --vf-ring: 0 0 0 2px var(--vf-focus);   /* opaque 2px ring, theme-aware through --vf-focus */
  --vf-ring-danger: 0 0 0 4px color-mix(in srgb, var(--vf-danger) 18%, transparent);
  --vf-lift: translateY(-2px);
}
html.dark-mode {
  --vf-e-hover: 0 0 0 1px var(--vf-border-strong), 0 16px 32px -12px rgba(0, 0, 0, .65);
  --vf-e-accent: 0 8px 20px -8px color-mix(in srgb, var(--vf-accent) 55%, transparent);
}

/* Angular themes keep square-ish chips (their own chip radius); the others use pills. */

/* ---- Cards: 16 radius, 1px border + e1; interactive cards lift 2px on hover (pointer devices). ---- */
.vf-card, .rs-card { border-radius: var(--vf-r-card); border: var(--vf-card-border); box-shadow: var(--vf-e1); }
.vf-card--tonal, .vf-card--info { border-color: transparent; }

/* ---- Buttons: 48 tall (40 drawn + 48 hit for --sm), 12 radius, Outfit 600 15; one primary per card. ---- */
.vf-btn, .vf-btn { border-radius: var(--vf-r-ctl); font: var(--vf-t-btn); letter-spacing: .005em; }
.vf-btn--sm, .vf-btn--sm { font: var(--vf-t-ui-strong); }
.vf-btn--primary, .vf-btn--primary { box-shadow: var(--vf-e-accent); }
.vf-btn--primary:disabled, .vf-btn--primary:disabled, .vf-btn--primary[aria-disabled="true"] { box-shadow: none; }
@media (hover: hover) and (pointer: fine) {
  .vf-btn:not(:disabled):not([aria-disabled="true"]):not([aria-busy="true"]):hover,
  .vf-btn:not(:disabled):not([aria-disabled="true"]):not([aria-busy="true"]):hover { transform: translateY(-1px); }
}
.vf-btn:focus-visible, .vf-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--vf-surface-1), 0 0 0 4px var(--vf-focus); }

/* ---- Inputs: 48 tall, 12 radius; focus = accent border + 4px soft ring; invalid = danger border + ring. ---- */
.vf-input, .rs-input, .rs-select, .rs-textarea, .vf-select, .vf-textarea { border-radius: var(--vf-r-ctl); font-family: var(--vf-font); }
.vf-input:focus, .rs-input:focus, .rs-select:focus, .rs-textarea:focus, .vf-select:focus, .vf-textarea:focus { border-color: var(--vf-accent); box-shadow: var(--vf-ring); }
.vf-input[aria-invalid="true"], .rs-input[aria-invalid="true"], .rs-select[aria-invalid="true"], .vf-textarea[aria-invalid="true"] { border-color: var(--vf-danger); box-shadow: none; }
.vf-input[aria-invalid="true"]:focus, .rs-input[aria-invalid="true"]:focus, .rs-select[aria-invalid="true"]:focus { box-shadow: var(--vf-ring-danger); }
.vf-search > input { border-radius: var(--vf-r-ctl); font-family: var(--vf-font); }
.vf-search > input:focus { box-shadow: inset 0 0 0 1px var(--vf-accent), var(--vf-ring); }
.vf-label, .rs-label { font: var(--vf-t-label); }
.vf-error, .rs-error { font: var(--vf-t-caption-md); }

/* ---- Chips and badges: pill, Inter 600 12 (status, counts, labels); filter chips stay Outfit. ---- */
.vf-chip, .rs-badge { border-radius: var(--vf-r-pill); font: var(--vf-t-badge); letter-spacing: .01em; padding: 0 8px; }
.vf-chip--sm { border-radius: var(--vf-r-pill); font: var(--vf-t-badge); padding: 0 8px; }
.vf-chip-btn { border-radius: var(--vf-r-pill); font: 600 14px/20px var(--vf-font); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-chip-cat { border-radius: var(--vf-r-pill); font: var(--vf-t-badge); line-height: 22px; }
.vf-section__count { font: var(--vf-t-badge); color: var(--vf-text-3); }
/* Eyebrow: small uppercase label above a value (stat cards, card heads). */
.vf-eyebrow { margin: 0; font: var(--vf-t-eyebrow); letter-spacing: var(--vf-eyebrow-track); text-transform: uppercase; color: var(--vf-text-3); }
@media (prefers-reduced-motion: reduce) {
  .vf-btn:hover, .vf-btn:hover { transform: none !important; }
  .vf-chip-btn:active { transform: none; }
}

/* =====================================================================================================
   PHASE 14 — R3: header, wordmark, theme switch, menu button
   ===================================================================================================== */
/* Wordmark (owner, after phase 14): Fugaz One, NO box. First words in the text colour, the last word in the accent
   text colour (two-tone, >= 4.5:1 in every theme). A one-word store name is the accent word alone. */
html body .rs-wordmark { display: inline-flex; align-items: baseline; gap: .28em; padding-inline-end: .06em; }
.rs-wordmark__head { color: inherit; }
html body .rs-wordmark__accent, html body .vf-wordmark__accent {
  display: inline; padding: 0; border-radius: 0; background: none; box-shadow: none; transform: none;
  color: var(--vf-accent-text); text-shadow: none; filter: none; animation: none; line-height: inherit;
}
/* On the saldo hero / any accent surface the accent word uses the hero text colours. */
.vf-top--hero .rs-wordmark__accent, .vf-hero .rs-wordmark__accent { color: var(--vf-hero-accent); }

/* Top bar: sticky surface bar with a hairline + soft shadow (reference), wordmark · nav · switch · saldo · menu. */
.rs-topbar.vf-top { box-shadow: var(--vf-e1); }
.vf-topnav a, .vf-topnav button { font-family: var(--vf-font); }

/* Theme switch (partials/theme-toggle.ejs): pill 40 drawn / 48 hit, knob slides 300 ms (transform only). */
.vf-theme-pill {
  position: relative; flex: none; display: inline-flex; align-items: center; gap: 8px; height: 40px; padding: 0 16px 0 4px;
  border: 1px solid var(--vf-border); border-radius: var(--vf-r-pill); background: var(--vf-surface-2); color: var(--vf-text-1);
  font: 600 13px/1 var(--vf-font); white-space: nowrap; cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
.vf-theme-pill::before { content: ''; position: absolute; left: -4px; right: -4px; top: 50%; height: var(--vf-hit); transform: translateY(-50%); }
.vf-theme-pill--bare { padding: 0 4px; }
.vf-theme-pill:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--vf-surface-1), 0 0 0 4px var(--vf-focus); }
@media (hover: hover) and (pointer: fine) { .vf-theme-pill:hover { border-color: var(--vf-border-strong); } }
.vf-theme-pill__track { position: relative; flex: none; width: 52px; height: 30px; border-radius: var(--vf-r-pill); background: var(--vf-surface-3); box-shadow: inset 0 0 0 1px var(--vf-border); }
.vf-theme-pill__knob {
  position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: var(--vf-r-pill); display: grid; place-items: center;
  background: var(--vf-surface-2); color: var(--vf-warning); box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
  transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
.vf-theme-pill__knob .rs-icon { grid-area: 1 / 1; width: 14px; height: 14px; transition: opacity var(--vf-dur, 140ms) var(--vf-ease, ease-out), transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-theme-pill__moon { opacity: 0; transform: rotate(-90deg); }
html.dark-mode .vf-theme-pill__track { background: var(--vf-accent); box-shadow: none; }
html.dark-mode .vf-theme-pill__knob { transform: translateX(22px); background: var(--vf-surface-2); color: var(--vf-accent-text); }
html.dark-mode .vf-theme-pill__sun { opacity: 0; transform: rotate(90deg); }
html.dark-mode .vf-theme-pill__moon { opacity: 1; transform: none; }
.vf-theme-pill__label { min-width: 3.4em; }
@media (prefers-reduced-motion: reduce) { .vf-theme-pill:active { transform: none; } }

/* In the top bar from 768 px; on phones the switch is the first row of the menu (no room next to the saldo chip). */
.vf-top__theme { display: none; }
@media (min-width: 768px) { .vf-top__theme { display: inline-flex; margin-right: 4px; } }
.vf-menu__mode { margin: 4px 16px 8px; padding: 4px 4px 4px 16px; min-height: 56px; border: 1px solid var(--vf-border); border-radius: var(--vf-r-card); display: flex; align-items: center; gap: 12px; }
.vf-menu__mode-icon { display: inline-flex; color: var(--vf-text-2); }
.vf-menu__mode-text { flex: 1; min-width: 0; font: var(--vf-t-ui); color: var(--vf-text-1); }
.vf-menu__mode .vf-theme-pill { border-color: transparent; background: none; }
@media (min-width: 768px) { .vf-menu__mode { display: none; } }
html[data-vf-dark-only] .vf-menu__mode { display: none; }

/* Menu button: small 40 px rounded square with three lines (48 hit), opens the menu sheet / dropdown. */
.vf-top__menu.rs-icon-btn { width: 48px; height: 48px; background: none; }
.vf-burger { width: 40px; height: 40px; border-radius: var(--vf-r-ctl); border: 1px solid var(--vf-border); background: var(--vf-surface-2); display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-burger > span { display: block; width: 16px; height: 2px; border-radius: 2px; background: var(--vf-text-1); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out), opacity var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-burger > span:nth-child(2) { width: 12px; margin-left: 4px; }
@media (hover: hover) and (pointer: fine) { .vf-top__menu:hover .vf-burger { border-color: var(--vf-border-strong); } .vf-top__menu.rs-icon-btn:hover { background: none; } }
.vf-top__menu[aria-expanded="true"] .vf-burger > span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.vf-top__menu[aria-expanded="true"] .vf-burger > span:nth-child(2) { opacity: 0; }
.vf-top__menu[aria-expanded="true"] .vf-burger > span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }
/* Menu dropdown (>= 1024) and sheet: 24 radius on phones, 16 as a dropdown, softer rows. */
.rs-menu.vf-menu { border-radius: var(--vf-r-sheet) var(--vf-r-sheet) 0 0; }
@media (min-width: 1024px) { .rs-menu.vf-menu { border-radius: var(--vf-r-card); border: 1px solid var(--vf-border); box-shadow: var(--vf-e3); } }
.vf-menu .rs-menu__group { font: var(--vf-t-eyebrow); letter-spacing: var(--vf-eyebrow-track); text-transform: uppercase; color: var(--vf-text-3); }
.vf-menu .rs-menu__item { border-radius: var(--vf-r-ctl); margin: 0 8px; width: calc(100% - 16px); padding-left: 12px; }
:root { --vf-ease-spring: cubic-bezier(.16, 1, .3, 1); }

/* Reveal */
.vf-d1 { --d: 1; } .vf-d2 { --d: 2; } .vf-d3 { --d: 3; } .vf-d4 { --d: 4; } .vf-d5 { --d: 5; } .vf-d6 { --d: 6; }

/* Dialogs and sheets: one motion for the whole popup family. */
@media (prefers-reduced-motion: no-preference) and (min-width: 1024px) {
  .rs-menu.vf-menu { transform-origin: top right; }
}
/* Dialog card: 24 radius sheet on phones, 16 radius centred card from 1024 (layout from phase 12); blurred scrim. */
.vf-pop { border-radius: var(--vf-r-card); box-shadow: var(--vf-e3); }
.vf-pop--sheet { border-radius: var(--vf-r-sheet) var(--vf-r-sheet) 0 0; }
@media (min-width: 1024px) { .vf-pop--sheet { border-radius: var(--vf-r-card); } }
.vf-pop::backdrop, .rs-menu.vf-menu::backdrop { -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }

/* Accordion (FAQ on the landing, Info, Terms). Markup: .vf-acc > details.vf-acc__item > summary.vf-acc__q + .vf-acc__a */
.vf-acc { display: flex; flex-direction: column; gap: 8px; }
.vf-acc__item { border: 1px solid var(--vf-border); border-radius: var(--vf-r-ctl); background: var(--vf-surface-2); overflow: clip; }
.vf-acc__item[open] { border-color: var(--vf-border-strong); }
.vf-acc__q { list-style: none; display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 12px 16px; cursor: pointer; font: 600 16px/24px var(--vf-font); color: var(--vf-text-1); -webkit-tap-highlight-color: transparent; }
.vf-acc__q::-webkit-details-marker { display: none; }
.vf-acc__q::marker { content: ''; }
.vf-acc__q > :first-child { flex: 1; min-width: 0; }
.vf-acc__chev { flex: none; width: 32px; height: 32px; border-radius: var(--vf-r-pill); display: grid; place-items: center; background: var(--vf-surface-3); color: var(--vf-text-2); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-acc__item[open]:not(.is-acc-closing) > .vf-acc__q .vf-acc__chev { transform: rotate(180deg); background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
.vf-acc__q:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--vf-focus); border-radius: var(--vf-r-ctl); }
@media (hover: hover) and (pointer: fine) { .vf-acc__q:hover .vf-acc__chev { background: var(--vf-accent-subtle); color: var(--vf-accent-text); } }
.vf-acc__a { padding: 0 16px; }
.vf-acc__a > :first-child { padding-top: 0; }
.vf-acc__a > :last-child { padding-bottom: 16px; }
.vf-acc__a p, .vf-acc__a li { font: var(--vf-t-body-sm); color: var(--vf-text-2); }
@media (min-width: 1024px) { .vf-acc__q { padding: 16px 20px; font-size: 16px; } .vf-acc__a { padding: 0 20px; } .vf-acc__a p { font: var(--vf-t-body); } }

/* Live pulse: a solid dot with a ring that grows and fades (2 s loop, transform + opacity). */
.vf-live-dot, .srv-row__dot { position: relative; flex: none; display: inline-block; width: 8px; height: 8px; border-radius: 999px; background: currentColor; }
.vf-live-dot::after, .srv-row__state.is-online .srv-row__dot::after { content: ''; position: absolute; inset: 0; border-radius: inherit; background: currentColor; }
@media (prefers-reduced-motion: reduce) { .vf-live-dot::after, .srv-row__state.is-online .srv-row__dot::after { opacity: 0; } }

/* List entry: rows of a list marked .vf-list-in fade up once, 40 ms apart (first 8 rows), on page load only. */

/* =====================================================================================================
   PHASE 14 — R6: dashboard (C07) + product cards / sections
   Hierarchy: saldo hero (24 radius) → three rounded stat cards → search → chips → sections (title + count chip
   + "Lihat semua") → 3-column grid (frozen) · server status card with live chips. One primary action per card.
   ===================================================================================================== */
.vf-saldo-hero { border-radius: var(--vf-r-sheet); position: relative; overflow: hidden; isolation: isolate; }
.vf-saldo-hero__hello { font: 500 14px/20px var(--vf-font); }
.vf-saldo-hero__amount { font: var(--vf-t-saldo); letter-spacing: -0.02em; }
.vf-saldo-hero__btn { font: 600 16px/24px var(--vf-font); border-radius: var(--vf-r-ctl); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
@media (hover: hover) and (pointer: fine) { .vf-saldo-hero__btn:hover { transform: translateY(-1px); } }

/* Stat cards */
.vf-stats { padding: 0; gap: 8px; background: none; border: 0; box-shadow: none; align-content: stretch; }
.vf-stats__item, .vf-stats__item + .vf-stats__item {
  display: grid; grid-template-rows: auto auto 1fr; align-content: start; gap: 2px; padding: 12px; min-width: 0;
  background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: var(--vf-r-card); box-shadow: var(--vf-e1);
}
.vf-stats dt { display: contents; }
.vf-stats__ic { width: 32px; height: 32px; margin-bottom: 8px; border-radius: var(--vf-r-ctl); display: grid; place-items: center; background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
.vf-stats__ic .rs-icon { width: 18px; height: 18px; }
.vf-stats__lbl { min-height: 32px; white-space: normal; font: var(--vf-t-eyebrow); letter-spacing: .04em; text-transform: uppercase; color: var(--vf-text-3); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.vf-stats dd { align-self: end; font: var(--vf-t-stat); font-variant-numeric: tabular-nums; }
@media (max-width: 374.98px) { .vf-stats__item, .vf-stats__item + .vf-stats__item { padding: 8px; } .vf-stats dd { font-size: 16px; } }
@media (min-width: 480px) { .vf-stats__lbl { min-height: 16px; -webkit-line-clamp: 1; } }
@media (min-width: 1024px) { .vf-stats__lbl { min-height: 32px; -webkit-line-clamp: 2; } .vf-stats dd { font-size: 18px; line-height: 26px; } }

/* Search + chips */
.search-bar-inner { border-radius: var(--vf-r-card); border-color: var(--vf-border); box-shadow: var(--vf-e1); background: var(--vf-surface-2); }
.search-bar-inner:focus-within { border-color: var(--vf-accent); box-shadow: var(--vf-ring); }
.search-bar-input { font-family: var(--vf-font); }
.vf-catchip { font: 600 14px/20px var(--vf-font); border: 1px solid var(--vf-border); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }

/* Section heads: title Outfit 700, count as a pill, link with arrow */
.vf-sec-title { font: var(--vf-t-sec); letter-spacing: -0.01em; }
.vf-sec-sub { font: var(--vf-t-small); color: var(--vf-text-3); }
.vf-sec-link, .vf-dash .cat-heading-link { font: 600 14px/20px var(--vf-font); }
.vf-dash .cat-heading-title { font: 600 16px/24px var(--vf-font); display: inline-flex; align-items: center; gap: 8px; }
.vf-dash .cat-heading-title .dash-count { margin-left: 0; display: inline-flex; align-items: center; height: 22px; padding: 0 8px; border-radius: var(--vf-r-pill); background: var(--vf-surface-3); color: var(--vf-text-2); font: var(--vf-t-badge); }
@media (min-width: 1024px) { .vf-dash .cat-heading-title { font-size: 18px; line-height: 26px; } }

/* Product card (3-column grid frozen): 14 radius, Outfit name, Inter price, lift on hover (R2). */
.vf-pcard__name { font: 500 14px/20px var(--vf-font); }
.vf-pcard__price { font-family: var(--vf-font-num); font-weight: 600; }
.vf-pcard__fact { font: 500 12px/16px var(--vf-font); }
@media (prefers-reduced-motion: reduce) { .vf-pcard:active { transform: none; } }
.vf-dash__banner, .banner-wrap { border-radius: var(--vf-r-card); }

/* Server status card: rows with a status chip; Online carries the live pulse. */
.srv-list.vf-card { border-radius: var(--vf-r-card); }
.srv-row__name { font: 600 16px/24px var(--vf-font); }
.srv-row__state { align-self: flex-start; display: inline-flex; align-items: center; gap: 8px; height: 24px; margin-top: 2px; padding: 0 8px; border-radius: var(--vf-r-pill); background: var(--vf-surface-3); color: var(--vf-text-2); font: var(--vf-t-badge); }
.srv-row__state.is-online { background: var(--vf-success-subtle); color: var(--vf-success); }
.srv-row__state.is-down { background: var(--vf-danger-subtle); color: var(--vf-danger); }
.srv-row__state .srv-row__ping { color: inherit; opacity: .8; }
.srv-row__dot { width: 7px; height: 7px; }

/* Empty states: icon tile, title, one sentence, one next-step button. */
.vf-empty { border-radius: var(--vf-r-card); gap: 8px; padding: 32px 20px; }
.vf-empty__icon { width: 56px; height: 56px; margin-bottom: 8px; background: var(--vf-accent-subtle); color: var(--vf-accent-text); box-shadow: 0 0 0 8px color-mix(in srgb, var(--vf-accent-subtle) 45%, transparent); }
.vf-empty__icon--danger { background: var(--vf-danger-subtle); color: var(--vf-danger); box-shadow: 0 0 0 8px color-mix(in srgb, var(--vf-danger-subtle) 45%, transparent); }
.vf-empty__title { font: 600 16px/24px var(--vf-font); }

/* =====================================================================================================
   PHASE 14 — R7: Info and Terms (reading pages) — 16 radius card, FAQ accordion; Terms sections as accordion items
   ===================================================================================================== */
.vf-read__head h1 { font: var(--vf-t-h1); letter-spacing: -0.02em; }
.vf-read__sub { font: var(--vf-t-small); color: var(--vf-text-2); }
.vf-read__card { border-radius: var(--vf-r-card); }
.vf-read__sec h2 { font: 600 16px/24px var(--vf-font); }
/* Terms: the card becomes a stack of accordion items (each section keeps its id for deep links). */
.vf-read__card--acc { background: none; border: 0; box-shadow: none; padding: 0; gap: 8px; }
.vf-read__card--acc > .vf-read__sec { gap: 0; }
.vf-read__card--acc .vf-acc__q h2 { margin: 0; font: 600 16px/24px var(--vf-font); color: var(--vf-text-1); }
.vf-read__card--acc .vf-acc__a { display: flex; flex-direction: column; gap: 12px; }
.vf-read__card--acc .vf-acc__a > p, .vf-read__card--acc .vf-acc__a li { font: 400 14px/20px var(--vf-font); }
.vf-read__card--acc .vf-read__credit { padding: 12px 4px 0; text-align: center; }
@media (min-width: 1024px) { .vf-read__card--acc .vf-acc__q h2 { font-size: 16px; } .vf-read__card--acc .vf-acc__a > p { font-size: 16px; line-height: 22px; } }
/* Info: the FAQ items sit inside the card → lighter frame. */
.vf-read__card:not(.vf-read__card--acc) .vf-acc__item { background: var(--vf-surface-1); }
/* Terms notice: one running sentence (the phase-12 column layout split "Penting: … tidak dapat dikembalikan …" into broken lines). */
.vf-read__sec .vf-notice > span { display: block; }

/* =====================================================================================================
   PHASE 14 — R8: product pages (Panel C14, Nokos C18–C19, APK Premium C20–C21, Suntik Sosmed C22–C25,
   produk C26–C29) on the same option / segment / select / card system as the dashboard (open item Q10).
   `:root` in front of a selector lifts it above the pages' own \3c style> blocks without !important.
   ===================================================================================================== */
/* Segmented controls (server tabs, payment / install choice, OTP servers, Riwayat tabs) */
:root :is(.vf-seg, .rs-seg) { border-radius: var(--vf-r-card); background: var(--vf-surface-3); }
:root .vf-seg__item, :root .rs-seg__item { border-radius: var(--vf-r-ctl); font: 600 14px/20px var(--vf-font); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
:root :is(.vf-seg__item, .rs-seg__item):is([aria-checked="true"], [aria-selected="true"], [aria-pressed="true"], .is-active, .active, [aria-current="page"]) { background: var(--vf-surface-2); color: var(--vf-text-1); box-shadow: var(--vf-e1), 0 0 0 1px var(--vf-border); }

/* Option cards: packages, variants, payment methods — one look, one selected state */
:root :is(.vf-option, .ap-opt, .pay-opt, .am-pay-opt, .payment-option, .vf-pd2 .pd-pay-opt, .chat-sheet-opt) {
  border-radius: var(--vf-r-card); border: 1px solid var(--vf-border); background: var(--vf-surface-2); box-shadow: var(--vf-e1);
  transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out);
}
@media (hover: hover) and (pointer: fine) {
  :root :is(.vf-option, .ap-opt, .pay-opt, .am-pay-opt, .payment-option, .vf-pd2 .pd-pay-opt, .chat-sheet-opt):not([disabled]):not(.is-out):hover { border-color: var(--vf-border-strong); background: var(--vf-surface-2); transform: translateY(-1px); }
}
:root :is(.vf-option[aria-pressed="true"], .vf-option[aria-checked="true"], .vf-option.is-active, .ap-opt[aria-checked="true"], .pay-opt.selected, .am-pay-opt.selected, .am-pay-opt.active, .payment-option.selected, .vf-pd2 .pd-pay-opt:has(input:checked)) {
  border: 2px solid var(--vf-accent); background: var(--vf-accent-subtle); box-shadow: 0 0 0 4px color-mix(in srgb, var(--vf-accent) 10%, transparent);
}
:root .ap-opt.is-out { box-shadow: none; }
:root :is(.ap-opt__price, .pnl-row__price, .vf-actionbar__value, .vf-sum__row--total dd) { font-family: var(--vf-font-num); font-weight: 600; }
@media (prefers-reduced-motion: reduce) { :root :is(.vf-option, .ap-opt, .pay-opt, .am-pay-opt, .payment-option, .vf-pd2 .pd-pay-opt, .chat-sheet-opt) { transform: none !important; } }

/* Selects: same height, radius, focus ring as inputs, one chevron */
:root :is(select.form-select, select.rs-select, select.vf-select, .vf-pd2 select, .otp-page select, .smm-order select) {
  min-height: 48px; border-radius: var(--vf-r-ctl); border: 1px solid var(--vf-border-strong); background-color: var(--vf-surface-2); color: var(--vf-text-1);
  font: 400 16px/24px var(--vf-font); padding-right: 40px; -webkit-appearance: none; appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--vf-text-2) 50%), linear-gradient(135deg, var(--vf-text-2) 50%, transparent 50%);
  background-position: calc(100% - 20px) 21px, calc(100% - 15px) 21px; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
:root :is(select.form-select, select.rs-select, select.vf-select, .vf-pd2 select, .otp-page select, .smm-order select):focus { border-color: var(--vf-accent); box-shadow: var(--vf-ring); outline: none; }
:root :is(select.form-select, select.rs-select, select.vf-select):disabled { background-color: var(--vf-surface-3); color: var(--vf-text-3); }
@media (min-width: 768px) and (pointer: fine) { :root :is(select.form-select, select.rs-select, select.vf-select, .vf-pd2 select, .otp-page select, .smm-order select) { font-size: 16px; } }

/* Panel package rows: rounded cards with the price in Inter and one "Pilih" action */
:root .pnl-row { border-radius: var(--vf-r-card); }
:root .pnl-row__name { font: 600 16px/24px var(--vf-font); }

/* Product head (icon / logo tile + category chip + name) and buy card */
:root .vf-pd2__tile { border-radius: 16px; }
:root .vf-pd2__title { font: var(--vf-t-prodtitle); letter-spacing: -0.01em; }   /* phase 14.3: product names use the product-title role (20 / 24), not h1 */
:root .vf-actionbar--fixed { border-radius: 20px 20px 0 0; border-top: 1px solid var(--vf-border); box-shadow: var(--vf-e-up); }
@media (min-width: 1024px) { :root .vf-actionbar--fixed { border-radius: 0; } }

/* Numbered field steps (OTP "1 Layanan · 2 Negara · 3 Operator") use the badge font */
/* Category chip in product heads: drawn 24 px pill (the 48 px hit area stays on ::after); the phase-13 40 px
   min-height drew it as a tall grey box. */
:root .vf-chip-cat { min-height: 0; height: 24px; display: inline-flex; align-items: center; align-self: flex-start; padding: 0 8px; background: var(--vf-accent-subtle); color: var(--vf-accent-text); }

/* =====================================================================================================
   PHASE 14 — R9: auth, deposit, history, profile (same tokens and components; markup: reveal / list-entry classes)
   ===================================================================================================== */
/* Auth (login, register, forgot): 24 radius card from 768 px, Outfit 800 title, one primary button */
.vf-auth .auth-title { font: 600 24px/32px var(--vf-font); letter-spacing: -0.02em; }
.vf-auth .auth-sub { font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.vf-auth .auth-card { border-radius: var(--vf-r-card); box-shadow: var(--vf-e2); }
@media (min-width: 768px) { .vf-auth .auth-card { border-radius: var(--vf-r-sheet); padding: 28px; } .vf-auth .auth-title { font-size: 32px; line-height: 40px; } }
.vf-auth .auth-divider span { font: var(--vf-t-eyebrow); letter-spacing: var(--vf-eyebrow-track); text-transform: uppercase; color: var(--vf-text-3); }

/* History */
.hist-head__title { font: var(--vf-t-h1); letter-spacing: -0.02em; }
.hist-card { border-radius: var(--vf-r-card); }
.hist-amount { font-family: var(--vf-font-num); font-weight: 600; font-variant-numeric: tabular-nums; }
.hist-label-text { font-weight: 600; }
.hist-icon { border-radius: 12px; }
.hist-period, .hist-search { border-radius: var(--vf-r-ctl); }

/* Deposit */
.dp-hist-meta { font: var(--vf-t-badge); color: var(--vf-text-3); }

/* Profile: account card + grouped rows; group labels as eyebrows */
:root h2.pf-group { font: var(--vf-t-eyebrow); letter-spacing: var(--vf-eyebrow-track); text-transform: uppercase; color: var(--vf-text-3); }
.pf-list { border-radius: var(--vf-r-card); }

/* =====================================================================================================
   PHASE 14.1 — layout + typography pass (owner, after phase 14)
   1) page titles: no box around them; Outfit 800 (phase 14.5: Fugaz One only for the store name); calmer sizes
   2) dashboard: one spacing rhythm, compact stat rows on desktop, smaller product media on desktop
   3) references (21st.dev / shadcn conventions, only what fits): hairline cards that sharpen their border on
      hover, header that gains a shadow once the page scrolls, a single shimmer pass on the landing CTA
   Containers already share one width (1200 content, 32 px gutters ≥ 1024, 16 px on phones) — kept.
   ===================================================================================================== */
/* ---- Type scale (desktop titles were 32 px and read as zoomed in) ---- */
:root { --vf-t-pagetitle: 800 24px/30px var(--vf-font); --vf-t-prodtitle: 700 20px/28px var(--vf-font); }
@media (min-width: 1024px) {
  :root {
    --vf-t-h1: 700 28px/36px var(--vf-font); --vf-t-h2: 700 22px/28px var(--vf-font); --vf-t-sec: 700 18px/26px var(--vf-font);
    --vf-t-saldo: 800 32px/40px var(--vf-font-num); --vf-t-price-lg: 800 24px/30px var(--vf-font-num);
    --vf-t-pagetitle: 800 28px/36px var(--vf-font); --vf-t-prodtitle: 700 24px/30px var(--vf-font);
  }
}
/* Page titles (category pages, reading pages, Riwayat, Isi saldo, auth, error pages): Outfit 800, plain text.
   OWNER RULE (phase 14.5): Fugaz One is used ONLY for the store name (.rs-wordmark / .vf-wordmark / .navbar-brand). */
html body :is(.vf-cathead__title, .vf-read__head h1, .hist-head__title, .vf-dp__h1, .vf-auth .auth-title, .vf-err__title) {
  font: var(--vf-t-pagetitle); letter-spacing: -0.02em; color: var(--vf-text-1); background: none; border: 0; padding: 0; box-shadow: none;
}
/* Product names stay Outfit for readability. */
html body .vf-pd2__title, :root .vf-pd2 .vf-pd2__title { font: var(--vf-t-prodtitle); letter-spacing: -0.01em; }

/* ---- No box around page titles ---- */
/* Category page head: the icon sits beside the title without a tile. */
html body .vf-cathead { grid-template-columns: 24px minmax(0, 1fr); column-gap: 12px; align-items: center; margin-bottom: 20px; }
html body .vf-cathead__tile { width: 24px; height: 24px; background: none; border-radius: 0; color: var(--vf-accent-text); align-self: start; margin-top: 4px; }
html body .vf-cathead__tile .rs-icon { width: 22px; height: 22px; }
html body .vf-cathead__desc { grid-column: 2; }
@media (min-width: 768px) { html body .vf-cathead { grid-template-columns: 24px minmax(0, 1fr) auto; } }
@media (min-width: 1024px) { html body .vf-cathead { grid-template-columns: 28px minmax(0, 1fr) auto; } html body .vf-cathead__tile { width: 28px; height: 28px; margin-top: 6px; } html body .vf-cathead__tile .rs-icon { width: 26px; height: 26px; } }
/* Product head: the product image + chip + name sit on the page, not inside a card. */
html body .vf-pd2__head.vf-card { background: none; border: 0; box-shadow: none; padding: 0 0 4px; gap: 16px; align-items: center; }
html body .vf-pd2__tile { width: 72px; height: 72px; border-radius: 16px; }
@media (min-width: 1024px) { html body .vf-pd2__tile { width: 88px; height: 88px; } }
/* Landing headline: the store name is coloured text, no highlight band (landing.css). */

/* ---- Dashboard ---- */
.vf-dash { --vf-dash-gap: 20px; }
@media (min-width: 1024px) { .vf-dash { --vf-dash-gap: 28px; } }
.vf-dash .vf-dash__top { margin-bottom: -8px; }
@media (min-width: 1024px) { .vf-dash .vf-dash__top { margin-bottom: -16px; } }   /* desktop main gap is 32 px */   /* main is a 24 px flex column; the sticky search adds 8 px → 16 px visual gap */

.vf-dash__main, .vf-dash__grid { row-gap: var(--vf-dash-gap); }
/* "Semua produk" is the section title; each category under it is a sub-head (one step smaller, lighter rule above). */
.vf-dash #allTitle { font: var(--vf-t-sec); margin-bottom: 4px; }
.vf-dash .rs-catgroup + .rs-catgroup .rs-catgroup__head { margin-top: 12px; }
.vf-dash .cat-heading-title { font: 600 16px/24px var(--vf-font); }
@media (min-width: 1024px) { .vf-dash .cat-heading-title { font-size: 16px; line-height: 24px; } }
/* Stat cards: 3 small cards under the hero on phones; on desktop a column of compact rows beside the hero
   (icon · label · value on one line), so nothing stretches into tall narrow boxes. */
@media (min-width: 1024px) {
  .vf-dash .vf-stats { grid-template-columns: minmax(0, 1fr); grid-auto-rows: 1fr; gap: 8px; }
  .vf-dash .vf-stats__item, .vf-dash .vf-stats__item + .vf-stats__item { grid-template-columns: 36px minmax(0, 1fr) auto; grid-template-rows: none; align-items: center; column-gap: 12px; padding: 8px 16px; }
  .vf-dash .vf-stats__ic { margin: 0; width: 36px; height: 36px; }
  .vf-dash .vf-stats__lbl { min-height: 0; -webkit-line-clamp: 1; }
  .vf-dash .vf-stats dd { align-self: center; font: 600 18px/26px var(--vf-font-num); }
}
/* Product cards: on desktop the media is 16:9 (the 1:1 / 16:10 art made a 3-column row very tall). Grid stays 3 columns. */
@media (min-width: 1024px) {
  .vf-dash .vf-pcard__media, .vf-catpage .vf-pcard__media { aspect-ratio: 16 / 9; }
  .vf-pcard__ph .rs-icon { width: 24px; height: 24px; }
  .vf-pcard__body { padding: 8px 12px 12px; }
  .vf-pcard__name { font: 600 14px/20px var(--vf-font); min-height: 20px; }
}
/* Saldo hero: same height as the stat column on desktop, calmer padding. */
@media (min-width: 1024px) { .vf-saldo-hero { padding: 24px 28px; justify-content: space-between; } }

/* ---- Product information area (produk, produk-stok, APK, Alight): one hierarchy ---- */
:root .vf-pd2 .vf-card > h2, :root .vf-pd2 .vf-card__title { font: 600 16px/24px var(--vf-font); color: var(--vf-text-1); }
:root .vf-pd2 .vf-card p { font: var(--vf-t-body-sm); color: var(--vf-text-2); }
@media (min-width: 1024px) { :root .vf-pd2 .vf-card > h2, :root .vf-pd2 .vf-card__title { font-size: 18px; line-height: 24px; } :root .vf-pd2 .vf-card p { font: var(--vf-t-body); } }

/* ---- References (21st.dev / shadcn conventions) ---- */
/* Cards: hairline border that sharpens on hover (no big shadow jump). */
.rs-topbar.vf-top { box-shadow: none; }
html.vf-scrolled .rs-topbar.vf-top { box-shadow: 0 1px 0 var(--vf-border), 0 8px 24px -16px rgba(30, 27, 75, .35); }
html.vf-scrolled .vf-landing__nav { box-shadow: 0 8px 24px -18px rgba(0, 0, 0, .45); }
/* Landing CTA: one light sweep on hover (transform only). */
.vf-landing__cta .vf-landing__btn { position: relative; overflow: hidden; isolation: isolate; }
.vf-landing__cta .vf-landing__btn::before { content: ''; position: absolute; inset: 0; z-index: -1; background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, .28) 50%, transparent 70%); transform: translateX(-120%); }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .vf-landing__cta .vf-landing__btn:hover::before { transform: translateX(120%); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
}

/* =====================================================================================================
   PHASE 14.2 — mobile-first pass for the remaining pages (payment / QRIS, reseller, Alight Motion, SMM order +
   history, panel success, error / maintenance, auth). The store is used mostly on phones: everything below is
   designed at 360–412 px first; desktop only widens. Shared components, so every page that uses them follows.
   ===================================================================================================== */
/* Phone basics */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-padding-top: calc(var(--vf-top-h, 52px) + 16px); }
:is(.vf-chips, .vf-catchips, .rs-seg, .vf-seg--nav, .rs-hscroll) { overscroll-behavior-x: contain; }
:is(dialog, .vf-pop, .rs-menu) { overscroll-behavior: contain; }
img { max-width: 100%; height: auto; }
@media (max-width: 374.98px) { :root { --vf-page-pad: 14px; --vf-card-pad: 14px; } }

/* Steppers (deposit, QRIS payment, Alight Motion): Inter step numbers, rounded bars, current step in the accent. */
.vf-steps__item { border-top-width: 3px; border-radius: 0; font: 500 12px/16px var(--vf-font); }
.vf-steps__item.is-current { font-weight: 600; }
.vf-steps__dot { font: 600 12px/1 var(--vf-font-num); }
.vf-steps__item.is-current .vf-steps__dot { background: var(--vf-accent); color: var(--vf-on-accent); border-color: var(--vf-accent); }

/* Numbered lists (Cara bayar, reseller terms, OTP guides) */
.vf-numlist { gap: 12px; font: 400 14px/20px var(--vf-font); }
.vf-numlist li::before { width: 22px; height: 22px; margin-top: 0; font: 600 12px/22px var(--vf-font-num); text-align: center; }

/* Key–value rows: readable keys, values in the text colour, numbers in Inter */
.vf-kv__row { font: 400 14px/20px var(--vf-font); }
.vf-kv__val { font-weight: 600; }
.vf-kv__row--total .vf-kv__val { font-family: var(--vf-font-num); font-weight: 600; }

/* QRIS payment card (deposit + produk QRIS): the amount is the hero, QR on white, timer as a pill. */
.pay-qris { border-radius: var(--vf-r-sheet); align-items: center; text-align: center; }
.pay-qris__label { font: var(--vf-t-eyebrow); letter-spacing: var(--vf-eyebrow-track); text-transform: uppercase; color: var(--vf-text-3); }
.pay-qris__amount { font: 600 32px/40px var(--vf-font-num); letter-spacing: -0.02em; }
@media (min-width: 1024px) { .pay-qris__amount { font-size: 34px; line-height: 40px; } }
.vf-timer { font-variant-numeric: tabular-nums; }
.vf-qr, .pay-qris .vf-qr { border-radius: 16px; }
.pay-how__title { font: var(--vf-t-sec); }

/* Result / status views (payment success, panel success, VF.status) */
.pay-result__title { font: var(--vf-t-pagetitle); letter-spacing: -0.02em; }
.pay-result__desc { font: var(--vf-t-body-sm); color: var(--vf-text-2); }
.pay-result__icon { border-radius: 999px; }

/* Reseller upgrade page */
.rp-hero__name { font: 600 16px/24px var(--vf-font); }
.rp-hero__price { font-family: var(--vf-font-num); font-weight: 600; }
.rp-terms { font: 400 14px/20px var(--vf-font); }
.rp-logo { border-radius: var(--vf-r-card); }

/* Notices: one radius and comfortable phone padding */
.vf-notice { border-radius: var(--vf-r-card); padding: 12px 16px; font: 400 14px/20px var(--vf-font); }

/* Error / maintenance pages: centred, page-title font, one primary + one secondary action, thumb-reachable on phones */
.vf-err__code { font: 600 72px/1 var(--vf-font-num); letter-spacing: -0.03em; }
@media (max-width: 767.98px) { .vf-err__actions, .vf-err .vf-empty__actions { width: 100%; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } }

/* Fixed action bar on phones: never covers the last field (page gets the bar's height as bottom space). */
@media (max-width: 1023.98px) { body:has(.vf-actionbar--fixed) main { padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px)); } }

/* =====================================================================================================
   PHASE 14.6 — one heading scale on every remaining page (store, product pages, admin). Owner rules kept:
   Fugaz One ONLY for the store name; every heading Outfit; mobile first (phone sizes, desktop ≥ 1024 below).
     page title     Outfit 800 24 → 28   (store pages + admin .adm-title)
     product name   Outfit 700 20 → 24
     section title  Outfit 700 18 → 20   (headings that sit on the page, above cards)
     card title     Outfit 700 16 → 17   (headings inside a card, sheet or dialog)
     group label    Inter 700 12, uppercase (labels above a group of rows / KPIs)
   `:root` lifts these above the pages' own \3c style> blocks without !important.
   ===================================================================================================== */
:root { --vf-t-section: 700 18px/26px var(--vf-font); --vf-t-cardtitle: 700 16px/24px var(--vf-font); }
@media (min-width: 1024px) { :root { --vf-t-section: 700 20px/28px var(--vf-font); --vf-t-cardtitle: 700 17px/24px var(--vf-font); } }

:root :is(.vf-sec-title, .rs-section-title, .vf-dash #allTitle) { font: var(--vf-t-section); letter-spacing: -0.01em; color: var(--vf-text-1); }
:root :is(.vf-card__title, .rs-card__title, .pnl-status__title, .pnl-mine__title, .am-card-label, .am-desc-title, .modal-title, .vf-pop__title, .vf-read__sec > h2, .adm-box__title, .adm-card__title, .adm-settings .section-title, .rp-hero__name) {
  font: var(--vf-t-cardtitle); letter-spacing: -0.005em; color: var(--vf-text-1);
}
:root :is(.vf-empty__title, .adm-empty__t, .adm-empty__title, .rs-empty__title) { font: var(--vf-t-cardtitle); }
/* Admin page titles follow the store's page-title role (typography only; admin layout unchanged). */

/* Group labels: admin KPI groups use the same eyebrow as the profile groups and the menu. */

/* Accordion questions (FAQ, Terms sections) stay one step under card titles: Outfit 600 15 → 16. */
:root .vf-acc__q, :root .vf-read__card--acc .vf-acc__q h2 { font: 600 16px/24px var(--vf-font); }
@media (min-width: 1024px) { :root .vf-acc__q, :root .vf-read__card--acc .vf-acc__q h2 { font-size: 16px; line-height: 24px; } }
/* Phase 14.6 (mobile first): on 320–374 px phones a 3-column card is ~92 px wide; the price keeps its full amount
   (e.g. Rp 150.000) with a slightly tighter number style and body padding instead of an ellipsis. */
@media (max-width: 374.98px) {
  .vf-pcard__body { padding: 8px 8px 8px; }
  .vf-pcard__price { font-size: 14px; letter-spacing: -0.02em; }
}

/* =====================================================================================================
   PHASE 14.7 — result views and dialogs on the same rules (no box around a page title, Outfit only, mobile first)
   ===================================================================================================== */
/* Panel success: the result (icon + "Panel siap dipakai" + period) sits on the page; the login data stays in its card. */
:root .ps-result.vf-card { background: none; border: 0; box-shadow: none; padding: 8px 0 4px; }
:root .ps-title, :root .pay-result__title { font: var(--vf-t-pagetitle); letter-spacing: -0.02em; color: var(--vf-text-1); margin: 0; }
/* Dialog, sheet and menu headings: the card-title role. */
:root :is(.vf-pop__title, .vf-menu .rs-menu__title, .vf-status__title, .hist-sheet__title, .vf-sheet__title, .chat-sheet-title, .lc-head__title) { font: var(--vf-t-cardtitle); letter-spacing: -0.005em; }
/* Full-screen status view (VF.status, Riwayat detail): bar title = card-title role, the result headline = section role. */
:root .vf-status__bartitle { font: var(--vf-t-cardtitle); }
:root .vf-result__title, :root .hist-dv__name { font: var(--vf-t-section); letter-spacing: -0.01em; }

/* =====================================================================================================
   PHASE 14.8 — (1) Panel page in the owner's panel1.ejs concept, (2) smooth motion, (3) glowing title
   ===================================================================================================== */

/* ---- (1) Panel: quick actions → server tabs → server card → "Panel kamu" → package cards ---- */
.pnl-page .pnl-qa { padding: 0; }
.pnl-page .pnl-qa__btns { display: grid; grid-template-columns: 1fr; }
.pnl-page .pnl-qa__btn { display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 4px; min-height: 48px; padding: 8px 8px; border-radius: var(--vf-r-card); border: 1px solid var(--vf-border); background: var(--vf-surface-1); color: var(--vf-text-1); font: 600 14px/20px var(--vf-font); text-decoration: none; text-align: center; cursor: pointer; -webkit-tap-highlight-color: transparent; transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.pnl-page .pnl-qa__btn .bi, .pnl-page .pnl-qa__btn svg { color: var(--vf-accent-text); }
@media (hover: hover) { .pnl-page .pnl-qa__btn:hover { border-color: var(--vf-border-strong); } }
.pnl-page .pnl-qa__btn--accent { background: var(--vf-accent-subtle); border-color: transparent; color: var(--vf-accent-text); }

.pnl-page .pnl-tabs { display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; margin: 0 0 16px; padding: 2px 0; }
.pnl-page .pnl-tabs::-webkit-scrollbar { display: none; }
.pnl-page .pnl-tab { flex: none; display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 16px; border-radius: 999px; border: 1px solid var(--vf-border); background: var(--vf-surface-2); color: var(--vf-text-2); font: 600 14px/20px var(--vf-font); text-decoration: none; white-space: nowrap; transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.pnl-page .pnl-tab.active { background: var(--vf-accent); border-color: transparent; color: var(--vf-on-accent); box-shadow: none; }

.pnl-page .p13-live .pnl-status__head, .pnl-page .pnl-minecard .pnl-status__head { display: flex; align-items: center; justify-content: flex-start; gap: 12px; }
/* Server card head: icon | name + meta, status chip under the name (the side column is only 380 px wide, and
   "Tidak dapat dihubungi" next to the name squeezed it into broken words). */
.pnl-page .p13-live .pnl-status__head { display: grid; grid-template-columns: 40px minmax(0, 1fr); column-gap: 12px; row-gap: 8px; align-items: start; }
.pnl-page .p13-live .pnl-status__head .pnl-status__icon { grid-row: 1 / span 2; }
.pnl-page .p13-live .pnl-status__head .srv-status-badge { grid-column: 2; justify-self: start; }
.pnl-page .pnl-status__name { flex: 1 1 auto; min-width: 0; }
.pnl-page .pnl-status__icon { flex: none; display: inline-grid; place-items: center; width: 40px; height: 40px; border-radius: 12px; background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
.pnl-page .pnl-status__icon--accent { background: var(--vf-success-subtle); color: var(--vf-success); }
.pnl-page .p13-live .pnl-status__title { margin: 0; font: var(--vf-t-cardtitle); color: var(--vf-text-1); overflow-wrap: break-word; }
.pnl-page .p13-live .pnl-status__meta { margin: 2px 0 0; font: 500 12px/16px var(--vf-font-num); letter-spacing: .02em; color: var(--vf-text-2); overflow-wrap: anywhere; }
.pnl-page .srv-status-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; }
.pnl-page .p13-live .srv-stat-label { display: inline-flex; align-items: center; gap: 8px; }
.pnl-page .pnl-ic { flex: none; display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: 8px; }
.pnl-page .pnl-ic--ping { background: var(--vf-success-subtle); color: var(--vf-success); }
.pnl-page .pnl-ic--ram { background: var(--vf-info-subtle); color: var(--vf-info); }
.pnl-page .pnl-ic--disk { background: var(--vf-accent-subtle); color: var(--vf-accent-text); }
/* Meter bars: scaleX instead of width → no layout per update, runs on the compositor. */
.pnl-page .srv-bar-fill, .pnl-page .p13-live .srv-bar-fill { width: 100%; transform: scaleX(0); transform-origin: left center; transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.pnl-page .srv-bar-fill.bar-ping { background: var(--vf-success); }
.pnl-page .srv-bar-fill.bar-ram { background: var(--vf-info); }
.pnl-page .srv-bar-fill.bar-disk { background: var(--vf-accent); }
.pnl-page .srv-counter-item { display: flex; align-items: center; gap: 12px; min-width: 0; }
.pnl-page .srv-counter-icon { flex: none; display: inline-grid; place-items: center; width: 36px; height: 36px; border-radius: var(--vf-r-ctl); }
.pnl-page .srv-counter-icon.ic-users { background: var(--vf-info-subtle); color: var(--vf-info); }
.pnl-page .srv-counter-icon.ic-server { background: var(--vf-success-subtle); color: var(--vf-success); }
.pnl-page .pnl-minecard { flex-direction: column; align-items: stretch; }
.pnl-page .pnl-minecard .p13-mine__title { margin: 0; font: var(--vf-t-cardtitle); }
.pnl-page .pnl-minecard .p13-mine__actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; flex: none; }
.pnl-page .pnl-minecard .p13-mine__actions .vf-btn { width: 100%; }
.pnl-page .pnl-minecard .p13-mine__actions .vf-btn:only-child { grid-column: 1 / -1; }

.pnl-page .pnl-pkgs__head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; margin: 0 0 12px; }
.pnl-page .pnl-pkgs__head .pnl-pkgs__title { margin: 0; }
.pnl-page .pnl-cards { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
@media (min-width: 600px) { .pnl-page .pnl-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
:root .pnl-page .pnl-row.pnl-pkg { display: flex; flex-direction: column; align-items: stretch; text-align: left; grid-template-columns: none; grid-template-areas: none; gap: 12px; min-height: 0; padding: 16px; border: var(--vf-card-border); border-radius: var(--vf-r-card); background: var(--vf-surface-2); box-shadow: var(--vf-e1); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
:root .pnl-page .pnl-row.pnl-pkg.is-picked { outline: 0; border-color: var(--vf-accent); box-shadow: 0 0 0 3px rgba(var(--vf-glow), .22); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) { :root .pnl-page .pnl-row.pnl-pkg:not(.is-out):hover { transform: translateY(-2px); border-color: var(--vf-border-strong); } }
.pnl-page .pnl-pkg__top { min-width: 0; }
:root .pnl-page .pnl-pkg__name { display: block; margin: 0; font: var(--vf-t-cardtitle); color: var(--vf-text-1); overflow-wrap: anywhere; }
.pnl-page .pnl-pkg__sub { margin: 2px 0 0; font: 500 12px/16px var(--vf-font); color: var(--vf-text-2); }
:root .pnl-page .pnl-pkg__price { margin: 0; text-align: left; font: 400 14px/20px var(--vf-font); color: var(--vf-text-2); }
:root .pnl-page .pnl-pkg__price b { font: 600 24px/30px var(--vf-font-num); color: var(--vf-text-1); font-variant-numeric: tabular-nums; }
:root .pnl-page .pnl-pkg .pnl-row__per { display: inline; }
.pnl-page .pnl-pkg__specs { margin: 0; padding: 4px 12px; border-radius: 12px; background: var(--vf-surface-1); border: 1px solid var(--vf-border); }
.pnl-page .pnl-pkg__specs > div { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 36px; }
.pnl-page .pnl-pkg__specs > div + div { border-top: 1px solid var(--vf-border); }
.pnl-page .pnl-pkg__specs dt { font: 600 12px/16px var(--vf-font-num); letter-spacing: .06em; text-transform: uppercase; color: var(--vf-text-2); }
.pnl-page .pnl-pkg__specs dd { margin: 0; font: 600 14px/20px var(--vf-font-num); color: var(--vf-text-1); text-align: right; font-variant-numeric: tabular-nums; }
:root .pnl-page .pnl-pkg .pnl-row__btn { width: 100%; min-height: 48px; margin-top: auto; justify-self: stretch; justify-content: center; gap: 8px; }
:root .pnl-page .pnl-pkg .pnl-row__btn-s { display: inline; }
:root .pnl-page .pnl-pkg .pnl-row__btn-l { display: none; }
.pnl-page .pkg-option[aria-checked="true"] .bi, .pnl-page .pkg-option[aria-checked="true"] svg { display: none; }

/* (3) Phase 14.8 glowing page titles: REMOVED in phase 15.1 (owner: the glow belongs to the store name only). */

/* ---- (2) Smooth motion: shorter, lighter, compositor-only ---- */   /* cards reveal on phones too since UX-CARD-02 */
:root { --vf-dur-modal: 240ms; --vf-dur-modal-out: 180ms; --vf-dur-reveal: 360ms; }
@media (prefers-reduced-motion: reduce) { :root { --vf-dur-modal: 0ms; --vf-dur-modal-out: 0ms; --vf-dur-reveal: 0ms; } }
@media (prefers-reduced-motion: no-preference) {
  .vf-list-in > * { animation-duration: 280ms; }
}
/* A fixed bar with backdrop blur re-blurs the page under it on every scrolled frame (the main source of
   scroll stutter on mid-range phones). The bottom nav, landing nav and sticky header get a near-opaque fill instead. */
html body .rs-bottomnav.vf-bnav { -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--vf-surface-2); }   /* opaque: content never shows through or under the bar */
html body .vf-landing__nav { -webkit-backdrop-filter: none; backdrop-filter: none; background: color-mix(in srgb, var(--l-bg, var(--vf-surface-1)) 97%, transparent); }
@media (max-width: 1023.98px) { html body .rs-topbar { -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--vf-surface-2); } }
/* Dialog scrims: a lighter blur (the page behind does not move while a dialog is open, but the first frame is cheaper). */
.vf-pop::backdrop, .rs-menu.vf-menu::backdrop { -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
/* Header shadow appears with opacity on a pseudo layer would need markup; keep the shadow but drop its transition. */
.rs-topbar.vf-top, .vf-landing__nav { transition: none; }
/* Product cards: no shadow transition while scrolling a long grid (press scale stays). */

/* =====================================================================================================
   PHASE 15.1 — owner rule: the glowing / pulsing effect belongs to the STORE NAME ONLY ("VF Market": the accent word
   "Market" glows with a slow gradient wave and a soft pulse). Nothing else on the site glows, pulses or shines:
   page titles, badges, status dots, buttons and tabs are plain again.
   ===================================================================================================== */
/* Back to plain: no shine sweep on "Hemat x%" / #1 badges, no pulsing ring on live dots, no coloured halo under
   primary buttons or the Deposit button (a neutral elevation instead). */
.vf-live-dot::after, .srv-row__state.is-online .srv-row__dot::after { content: none; animation: none; }
:root { --vf-e-accent: 0 1px 2px rgba(17, 16, 40, .12); }
html.dark-mode { --vf-e-accent: none; }
html body .vf-bnav__fab { box-shadow: 0 2px 8px rgba(17, 16, 40, .18); }
html.dark-mode body .vf-bnav__fab { box-shadow: 0 2px 8px rgba(0, 0, 0, .45); }
html body .rs-wordmark__accent, html body .vf-wordmark__accent {
  --wm-c: var(--vf-accent-text);
  --wm-hi: color-mix(in srgb, var(--vf-accent-text) 55%, #fff);
  --wm-rgb: var(--vf-glow);
  position: relative; isolation: auto; display: inline-block; color: var(--wm-c);
  background-image: linear-gradient(90deg, var(--wm-c) 0%, var(--wm-hi) 25%, var(--wm-c) 50%, var(--wm-hi) 75%, var(--wm-c) 100%);
  background-size: 200% 100%; background-repeat: repeat-x; background-position: 0 0;
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
  filter: none; padding-inline-end: .06em;   /* the clipped gradient covers the slanted last letter */
}
/* The wordmark is the stacking context, so the glow (z-index -1) paints UNDER the gradient letters, not over them. */
html body .rs-wordmark, html body .vf-wordmark { isolation: isolate; }
/* Phase 16.1: the glow is a blurred copy of the word itself (data-wm, partials/wordmark.ejs), so it follows the
   letters — no rounded "pill" behind the word (owner screenshot). Blurred once, only its opacity breathes. */
html body .rs-wordmark__accent::before, html body .vf-wordmark__accent::before {
  content: attr(data-wm); position: absolute; z-index: -1; left: 0; top: 0; right: auto; bottom: auto; pointer-events: none; white-space: nowrap;
  color: rgb(var(--wm-rgb)); -webkit-text-fill-color: rgb(var(--wm-rgb)); background: none;
  filter: blur(5px); opacity: .3;
}
html.dark-mode body .rs-wordmark__accent, html.dark-mode body .vf-wordmark__accent { --wm-hi: color-mix(in srgb, var(--vf-accent-text) 45%, #fff); }
html body .vf-top--hero .rs-wordmark__accent, html body .vf-hero .rs-wordmark__accent { --wm-c: var(--vf-hero-accent); --wm-hi: color-mix(in srgb, var(--vf-hero-accent) 50%, #fff); }
html body .vf-landing__brand .rs-wordmark__accent { --wm-c: var(--l-wm, var(--vf-accent-text)); --wm-hi: color-mix(in srgb, var(--l-wm, var(--vf-accent-text)) 50%, #fff); --wm-rgb: var(--l-glow, var(--vf-glow)); }
@media (prefers-reduced-motion: no-preference) {
  html body .is-scrolling .rs-wordmark__accent, html body .is-scrolling .rs-wordmark__accent::before,
  html body .is-scrolling .vf-wordmark__accent, html body .is-scrolling .vf-wordmark__accent::before { animation-play-state: paused; }
}
/* constant keyframe values (no var()) so Chrome runs the pulse on the compositor */
@media (forced-colors: active) {
  html body .rs-wordmark__accent, html body .vf-wordmark__accent { background: none; -webkit-text-fill-color: currentColor; animation: none; }
  html body .rs-wordmark__accent::before, html body .vf-wordmark__accent::before { content: none; }
}
@media print {
  html body .rs-wordmark__accent, html body .vf-wordmark__accent { background: none; -webkit-text-fill-color: currentColor; animation: none; }
  html body .rs-wordmark__accent::before, html body .vf-wordmark__accent::before { content: none; }
}

/* =====================================================================================================
   PHASE 16 — owner items 2 & 3: page background + global theme consistency
   ===================================================================================================== */
/* Background: a quiet dot grid at the top of every store page that fades out after ~560 px. One static paint that
   scrolls with the page (no fixed layer, no animation), coloured from the theme's own text colour so it fits all
   7 themes × light / dark. Cards and bars are solid, so text never sits on the dots. Admin pages stay plain. */
:root { --vf-dot: color-mix(in srgb, var(--vf-text-1) 11%, transparent); --vf-dot-gap: 22px; }
html.dark-mode { --vf-dot: color-mix(in srgb, var(--vf-text-1) 14%, transparent); }
body:not(.vf-landing)::before {
  content: ""; position: absolute; z-index: -1; left: 0; right: 0; top: 0; height: 560px; pointer-events: none;
  background-image: radial-gradient(var(--vf-dot) 1px, transparent 1.5px); background-size: var(--vf-dot-gap) var(--vf-dot-gap); background-position: center top;
  -webkit-mask-image: linear-gradient(to bottom, black, transparent); mask-image: linear-gradient(to bottom, black, transparent);
}
@media print { body::before { content: none !important; } }


/* Phase 16 (owner item 4): sound switch — same size and motion as the light/dark switch, own on-state. */
.vf-sw { position: relative; flex: none; display: inline-flex; align-items: center; height: 40px; padding: 0 4px; border: 0; background: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.vf-sw::before { content: ''; position: absolute; left: -4px; right: -4px; top: 50%; height: var(--vf-hit); transform: translateY(-50%); }
.vf-sw__track { position: relative; width: 52px; height: 30px; border-radius: var(--vf-r-pill); background: var(--vf-surface-3); box-shadow: inset 0 0 0 1px var(--vf-border); }
.vf-sw__knob { position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: var(--vf-r-pill); background: var(--vf-surface-2); box-shadow: 0 1px 3px rgba(0, 0, 0, .18); transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
.vf-sw[aria-checked="true"] .vf-sw__track { background: var(--vf-accent); box-shadow: none; }
.vf-sw[aria-checked="true"] .vf-sw__knob { transform: translateX(22px); }
.vf-sw:focus-visible { outline: none; } .vf-sw:focus-visible .vf-sw__track { box-shadow: 0 0 0 2px var(--vf-surface-1), 0 0 0 4px var(--vf-focus); }
.vf-menu__sound { margin-top: 0; }
@media (min-width: 768px) { .vf-menu__mode.vf-menu__sound { display: flex; margin-top: 4px; } }
html[data-vf-dark-only] .vf-menu__mode.vf-menu__sound { display: flex; }
.vf-menu__sound[hidden] { display: none !important; }
/* UX-SND-02: volume slider next to the sound switch. The filled part is --vf-range (set from vf-sound.js). */
.vf-menu__vol { margin-top: 0; }
.vf-menu__vol .vf-menu__mode-icon { width: 20px; height: 20px; }
.vf-landing__menurow-gap { display: inline-block; width: 20px; height: 20px; flex: none; }
.vf-range { -webkit-appearance: none; appearance: none; flex: 0 1 140px; min-width: 96px; height: 44px; margin: 0 8px 0 auto; background: none; cursor: pointer; touch-action: pan-y; -webkit-tap-highlight-color: transparent; }
.vf-range::-webkit-slider-runnable-track { height: 6px; border-radius: 999px; background: linear-gradient(to right, var(--vf-accent) var(--vf-range, 70%), var(--vf-surface-3) var(--vf-range, 70%)); box-shadow: inset 0 0 0 1px var(--vf-border); }
.vf-range::-moz-range-track { height: 6px; border-radius: 999px; background: var(--vf-surface-3); box-shadow: inset 0 0 0 1px var(--vf-border); }
.vf-range::-moz-range-progress { height: 6px; border-radius: 999px; background: var(--vf-accent); }
.vf-range::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 22px; height: 22px; margin-top: -8px; border: 0; border-radius: 999px; background: var(--vf-surface-2); box-shadow: 0 1px 4px rgba(0, 0, 0, .35), 0 0 0 1px var(--vf-border-strong); }
.vf-range::-moz-range-thumb { width: 22px; height: 22px; border: 0; border-radius: 999px; background: var(--vf-surface-2); box-shadow: 0 1px 4px rgba(0, 0, 0, .35), 0 0 0 1px var(--vf-border-strong); }
.vf-range:focus-visible { outline: 2px solid var(--vf-focus); outline-offset: 2px; border-radius: 8px; }
.vf-range:disabled { opacity: .45; cursor: not-allowed; }
html.vf-restore .vf-list-in > * { animation: none; }
/* Back to a filtered list: the list stays invisible (space kept) until VFView has re-applied the filter (≤ 1.5 s cap). */
/* Back to a page that was left scrolled down: the content stays hidden until the saved position is applied
   (global-theme.js VFView → shown()), so it no longer paints at the top first and then jumps. Header and bottom bar
   stay; Chrome keeps the previous page on screen meanwhile (paint holding). Safety: head-assets removes it at 1.5 s. */
/* While a page initialises (html.vf-preload, head-assets.ejs) state set by scripts appears at once — no transition. */

/* =====================================================================================================
   PHASE 17 — complete product card (owner). Markup: partials/product-card.ejs; data rules: helpers/card_display.js.
   Media overlays (no layout cost): top-left rank / label, top-right "-x%", bottom-left ★ rating.
   Body: optional category · name · price · foot pushed to the bottom (sold count + fact), so in a row of equal-height
   cards the prices line up at the top and the fact lines at the bottom. Text ≥ 12 px, status colours from the
   theme's status tokens (contrast-checked in every theme). No glow, no new animation.
   ===================================================================================================== */
.vf-pcard__body { flex: 1 1 auto; }
.vf-pcard__foot { margin-top: auto; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.vf-pcard__cat { margin: 0; font: 600 12px/16px var(--vf-font); color: var(--vf-text-2); overflow-wrap: break-word; }   /* wraps, never cut */
.vf-pcard__sold { margin: 0; display: flex; align-items: flex-start; gap: 4px; font: 500 12px/16px var(--vf-font); color: var(--vf-text-2); min-width: 0; font-variant-numeric: tabular-nums; }   /* wraps on the smallest phones */
.vf-pcard__sold .rs-icon { width: 12px; height: 12px; flex: none; margin-top: 2px; }
.vf-pcard__fact--low { color: var(--vf-warning); font-weight: 600; }
@media (max-width: 374.98px) { .vf-pcard__sold .rs-icon { display: none; } }

.vf-pcard__chip, .vf-pcard__off, .vf-pcard__star {
  position: absolute; z-index: 2; pointer-events: none; display: inline-flex; align-items: center; gap: 3px;
  height: 20px; padding: 0 8px; border-radius: 6px; font: 600 12px/16px var(--vf-font-num); letter-spacing: 0; white-space: nowrap;
  max-width: calc(100% - 12px); overflow: hidden; box-shadow: 0 1px 2px rgba(0, 0, 0, .12);
}
.vf-pcard__chip { top: 6px; left: 6px; font-family: var(--vf-font); font-weight: 600; background: var(--vf-accent-subtle); color: var(--vf-accent-text); border: 1px solid color-mix(in srgb, currentColor 22%, transparent); }
.vf-pcard__chip--info { background: var(--vf-info-subtle); color: var(--vf-info); }
.vf-pcard__chip--danger { background: var(--vf-danger-subtle); color: var(--vf-danger); }
.vf-pcard__chip--success { background: var(--vf-success-subtle); color: var(--vf-success); }
.vf-pcard__chip--warning { background: var(--vf-warning-subtle); color: var(--vf-warning); }
.vf-pcard__chip--rank { font-family: var(--vf-font-num); font-weight: 600; font-variant-numeric: tabular-nums; background: var(--vf-surface-2); color: var(--vf-text-1); border-color: var(--vf-border); }
.vf-pcard__chip--rank.is-top { background: var(--vf-accent); color: var(--vf-on-accent); border-color: transparent; }
.vf-pcard__chip .rs-icon { width: 11px; height: 11px; flex: none; }
.vf-pcard__off { top: 6px; right: 6px; background: var(--vf-danger); color: var(--vf-on-danger); font-variant-numeric: tabular-nums; }
.vf-pcard__star { left: 6px; bottom: 6px; background: var(--vf-surface-2); color: var(--vf-text-1); border: 1px solid var(--vf-border); font-variant-numeric: tabular-nums; }
.vf-pcard__star .rs-icon { width: 11px; height: 11px; color: var(--vf-warning); flex: none; }
/* A label never gets cut: on a narrow card it wraps to a second line (still ≥ 12 px) instead; next to a discount
   it keeps clear of it. The rank chip drops its trophy on the smallest phones. */
.vf-pcard__chip { height: auto; min-height: 20px; padding-top: 2px; padding-bottom: 2px; white-space: normal; overflow-wrap: break-word; line-height: 14px; text-align: left; }
.vf-pcard__media:has(.vf-pcard__off) .vf-pcard__chip { max-width: calc(100% - 62px); }
@media (max-width: 399.98px) {
  .vf-pcard__chip, .vf-pcard__off, .vf-pcard__star { padding-left: 4px; padding-right: 4px; border-radius: 5px; }
  .vf-pcard__chip, .vf-pcard__off { top: 4px; } .vf-pcard__chip, .vf-pcard__star { left: 4px; } .vf-pcard__off { right: 4px; } .vf-pcard__star { bottom: 4px; }
  .vf-pcard__chip { max-width: calc(100% - 8px); }
  .vf-pcard__media:has(.vf-pcard__off) .vf-pcard__chip { max-width: calc(100% - 52px); }
}
@media (max-width: 374.98px) { .vf-pcard__chip--rank .rs-icon { display: none; } }
@media (min-width: 768px) {
  .vf-pcard__chip, .vf-pcard__off, .vf-pcard__star { height: 22px; padding: 0 8px; }
  .vf-pcard__chip { top: 8px; left: 8px; } .vf-pcard__off { top: 8px; right: 8px; } .vf-pcard__star { left: 8px; bottom: 8px; }
  .vf-pcard__chip .rs-icon, .vf-pcard__star .rs-icon { width: 12px; height: 12px; }
}
.vf-pcard.is-soldout .vf-pcard__off, .vf-pcard.is-soldout .vf-pcard__chip:not(.vf-pcard__chip--rank) { display: none; }
@media print { .vf-pcard__chip, .vf-pcard__off, .vf-pcard__star { box-shadow: none; } }
/* The price line wraps at every width (was phones only): a struck "harga normal" moves under the price instead of
   being cut on narrow desktop columns (1024 with the side panel, admin preview). */
.vf-pcard .vf-pcard__price { white-space: normal; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 4px; overflow: visible; }
.vf-pcard .vf-pcard__price > * { white-space: nowrap; flex: 0 0 auto; max-width: 100%; }
/* Size budget (cards stay compact: ≤ 260 px tall on phones, no taller than wide on desktop):
   phones leave the category out (the section title already groups the products); from 1024 px the sold count sits
   on the fact line's right instead of its own line. */
@media (max-width: 767.98px) { .vf-pcard__cat { display: none; } }
@media (min-width: 1024px) {
  .vf-pcard__foot { flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: space-between; column-gap: 8px; row-gap: 2px; }
  .vf-pcard__foot .vf-pcard__sold { order: 2; }
  .vf-pcard__foot .vf-pcard__fact { order: 1; }
}
/* Produk populer / pilihan carousel ‹ › buttons showed as empty circles: the circle (::before, positioned) was painted
   over the SVG chevron (only the old .bi icon font was lifted above it). */
.rs-carousel__btn > .rs-icon { position: relative; }

/* ---------------------------------------------------------------------------------------------------------------------------
   Legacy utility names (FND-FW-04). Bootstrap is gone; these few names are still written in older views and scripts
   (otp.js, main.js, panel.ejs, profile.ejs, panel-reseller.ejs). Same meaning, project colors. New code uses the tw: layer.
   --------------------------------------------------------------------------------------------------------------------------- */
.d-block { display: block !important; }
.d-none { display: none !important; }
.text-success { color: var(--vf-success) !important; }
.text-danger { color: var(--vf-danger) !important; }
.text-warning { color: var(--vf-warning) !important; }
.small { font-size: .875em; }
.text-break { overflow-wrap: break-word !important; }
.p-2 { padding: .5rem; }

/* =====================================================================================================
   UX-THM-01 — theme switch: circular reveal from the toggle (global-theme.js, RSMode). The old and the new page
   are both captured; the new one is revealed by a growing clip-path circle (animated from JS, 500 ms). The bars that
   keep their own transition names across page loads are folded into the root capture for this transition so the
   whole page changes together. Fallback without View Transitions: html.vf-theme-fade eases the colours (.35 s).
   ===================================================================================================== */
html.vf-theme-vt :is(.rs-topbar, .vf-top, .rs-bottomnav.vf-bnav, .vf-bnav__pill) { view-transition-name: none !important; }
/* the sun and the moon swap with a rotate + scale (morph) as the knob slides */
.vf-theme-pill__moon { transform: rotate(-90deg) scale(.4); }
html.dark-mode .vf-theme-pill__sun { transform: rotate(90deg) scale(.4); }

/* UX-FLK-04: a changed status value cross-fades in place; the element is never replaced. */
.srv-row__ping[hidden] { display: none; }

/* UX-FLK-02: the banner box has its final height before any image arrives (same sizes as a slide), and a failed slide
   cannot collapse it: with no working slide the fallback panel fills the same box. */
.banner-inner { min-height: 150px; }
@media (min-width: 600px) { .banner-inner { min-height: 0; aspect-ratio: 8 / 3; max-height: 282px; } }
@media (min-width: 1024px) { .banner-inner { aspect-ratio: auto; min-height: 282px; } }
.banner-slide.banner-fallback.active { display: flex; align-items: center; justify-content: center; height: 100%; min-height: 148px; background: linear-gradient(135deg, var(--vf-accent-subtle), var(--vf-surface-3)); }
.banner-fallback__mark { font-size: 28px; }
.banner-inner .banner-slide.banner-fallback[hidden] { display: none; }

/* =====================================================================================================
   UX-DD-01 — the one dropdown: .vf-dd (public/js/vf-dd.js). The menu is moved to <body> and placed with position: fixed,
   so it never depends on, or is clipped by, an ancestor. 6 px container padding, 10 x 12 px items, 8 px radius, 44 px items on
   touch, bottom sheet under 640 px.
   ===================================================================================================== */
.vf-dd { position: relative; display: inline-block; }
.vf-dd__menu {
  position: fixed; left: 0; top: 0; z-index: calc(var(--rs-z-toast, 1000) + 5);
  box-sizing: border-box; min-width: max(var(--vf-dd-w, 0px), 200px); max-width: calc(100vw - 24px); max-height: min(60vh, 360px); overflow: auto; overscroll-behavior: contain;
  margin: 0; padding: 8px; border: 1px solid var(--vf-border); border-radius: 8px; background: var(--vf-surface-2); color: var(--vf-text-1); box-shadow: var(--vf-e3, 0 8px 24px rgba(0, 0, 0, .28));
}
.vf-dd__menu { transition-property: none !important; }   /* left/top must jump to the computed spot: under reduced motion a global .01 ms transition on `all` still draws one frame at the page corner */
.vf-dd__menu[hidden] { display: none; }
.vf-dd__menu:focus { outline: none; }
.vf-dd__item {
  display: flex; align-items: center; gap: 12px; width: 100%; box-sizing: border-box; min-height: 40px; margin: 0; padding: 8px 12px; border: 0; border-radius: 8px;
  background: none; color: inherit; font: var(--vf-t-ui, 500 14px/20px var(--vf-font)); text-align: left; text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.vf-dd__item:hover, .vf-dd__item:focus-visible { background: var(--vf-surface-3); }
.vf-dd__item[aria-disabled="true"], .vf-dd__item:disabled { opacity: .5; cursor: not-allowed; }
.vf-dd__item.is-danger { color: var(--vf-danger); }
.vf-dd__icon { flex: none; display: inline-flex; width: 20px; justify-content: center; color: var(--vf-text-2); }
.vf-dd__item.is-danger .vf-dd__icon { color: inherit; }
.vf-dd__text { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.vf-dd__label, .vf-dd__help { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vf-dd__item > .rs-icon + * , .vf-dd__item > .rs-icon { flex: none; }
.vf-dd__help { font: var(--vf-t-caption, 400 12px/16px var(--vf-font)); color: var(--vf-text-2); }
.vf-dd__sep { height: 1px; margin: 8px 4px; border: 0; background: var(--vf-border); }
@media (pointer: coarse) { .vf-dd__item { min-height: 44px; } }
@media (prefers-reduced-motion: no-preference) {
  .vf-dd__menu[data-side="top"].is-open { transform-origin: bottom; }
}

/* under 640 px: a bottom sheet with a backdrop */
.vf-dd__backdrop { position: fixed; inset: 0; z-index: calc(var(--rs-z-toast, 1000) + 4); background: rgba(0, 0, 0, .45); }
.vf-dd__menu.is-sheet {
  left: 0 !important; right: 0; top: auto !important; bottom: 0; width: 100%; min-width: 0; max-width: none; max-height: min(60vh, 360px);
  border-radius: 16px 16px 0 0; border-width: 1px 0 0; padding: 8px 8px calc(8px + env(safe-area-inset-bottom, 0px));
}
.vf-dd__menu.is-sheet .vf-dd__item { min-height: 48px; }
.vf-pcard { isolation: isolate; }
.vf-pcard::before { content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit; box-shadow: var(--vf-e-hover); opacity: 0; pointer-events: none; }
.vf-pcard__media { border-top-left-radius: inherit; border-top-right-radius: inherit; overflow: hidden; }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
    .vf-pcard::before { transition: opacity var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
  .vf-pcard__img { transition: transform var(--vf-dur, 140ms) var(--vf-ease, ease-out); }
  .vf-pcard:hover { transform: translateY(-4px); box-shadow: var(--vf-e1); }
  .vf-pcard:hover::before { opacity: 1; }
  .vf-pcard:hover .vf-pcard__img { transform: scale(1.04); }
}

/* UX-DD-02: panel menus on the .vf-dd engine (the site menu, the landing menu). Same look as the old dialog sheet. */
.vf-dd__menu--panel { max-height: calc(100dvh - 24px); overscroll-behavior: contain; }
.vf-dd__menu--panel.vf-menu { width: 380px; max-width: calc(100vw - 24px); padding: 8px 0 16px; border: 1px solid var(--vf-border); border-radius: var(--vf-r-card); background: var(--vf-surface-2); box-shadow: var(--vf-e3); }
.vf-dd__menu--panel.vf-menu.is-sheet { width: 100%; max-width: none; max-height: calc(100dvh - 24px); padding: 8px 0 calc(24px + env(safe-area-inset-bottom, 0px)); border-width: 1px 0 0; border-radius: var(--vf-r-sheet, 20px) var(--vf-r-sheet, 20px) 0 0; }
.vf-dd__menu--panel.vf-menu:not(.is-sheet) .vf-menu__handle { display: none; }
.vf-dd__menu--panel.vf-menu.is-sheet .vf-menu__handle { display: block; }
.vf-top__dd { display: inline-flex; }
.rs-hscroll.is-more-r { -webkit-mask-image: linear-gradient(90deg, black calc(100% - 32px), transparent); mask-image: linear-gradient(90deg, black calc(100% - 32px), transparent); }
.rs-hscroll.is-more-l { -webkit-mask-image: linear-gradient(90deg, transparent, black 32px); mask-image: linear-gradient(90deg, transparent, black 32px); }
.rs-hscroll.is-more-l.is-more-r { -webkit-mask-image: linear-gradient(90deg, transparent, black 32px, black calc(100% - 32px), transparent); mask-image: linear-gradient(90deg, transparent, black 32px, black calc(100% - 32px), transparent); }
.rs-hscroll.rs-hscroll.rs-hscroll:focus-visible { -webkit-mask-image: none; mask-image: none; }   /* tripled class: wins over .is-more-l.is-more-r */

/* WP6A 6.5 (USR-CAT-01) the quick-view eye (.vf-pcard__qv above) shares the top-right corner with a discount chip: then it moves to
   the bottom-right corner (the rating star is bottom-left). */
.vf-pcard__media:has(.vf-pcard__off) .vf-pcard__qv { top: auto; bottom: var(--pc-inset); }

/* WP6C 6.11 (USR-INF-02) unread admin replies on every "Bantuan" entry (public/js/livechat.js setUnread). */
[data-rs-help][data-unread]:not(.vf-bnav .rs-bottomnav__item) { position: relative; }   /* only while a badge shows */
.vf-unread { position: absolute; top: 2px; right: 50%; transform: translateX(22px); min-width: 18px; height: 18px; padding: 0 4px; border-radius: 999px; background: var(--vf-danger); color: var(--vf-on-danger); font: 600 12px/16px var(--vf-font-num); text-align: center; pointer-events: none; box-shadow: 0 0 0 2px var(--vf-surface-2); }
.vf-top__nav [data-rs-help] .vf-unread, .rs-slimfoot [data-rs-help] .vf-unread, .vf-foot [data-rs-help] .vf-unread { top: -6px; right: -10px; transform: none; }

/* WP6C 6.11 (USR-INF-01) table of contents on long reading pages (/terms) */
.vf-toc { margin: 0 0 16px; padding: 16px; background: var(--vf-surface-2); border: var(--vf-card-border); border-radius: var(--vf-r-card); }
.vf-toc__title { margin: 0 0 8px; font: var(--vf-t-ui-strong); color: var(--vf-text-1); }
.vf-toc__list { margin: 0; padding: 0 0 0 20px; columns: 1; column-gap: 24px; font: var(--vf-t-small); }
@media (min-width: 768px) { .vf-toc__list { columns: 2; } }
.vf-toc__list li { break-inside: avoid; padding: 2px 0; color: var(--vf-text-3); }
.vf-toc__list a { display: inline-block; min-height: 32px; padding: 8px 0; color: var(--vf-accent-text); text-decoration: none; }
@media (pointer: coarse) { .vf-toc__list a { min-height: 44px; display: inline-flex; align-items: center; } }   /* CROSS-01: 44 px targets on touch */
.vf-toc__list a:hover { text-decoration: underline; text-underline-offset: 3px; }
.vf-read__sec[id] { scroll-margin-top: 80px; }
/* WP6C 6.11 /bantuan: a button row (opens the help sheet) laid out like the link rows */
.vf-read__sec .vf-read__links .vf-read__linkbtn { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 56px; padding: 8px 0; border: 0; background: none; color: var(--vf-text-1); font: inherit; text-align: left; cursor: pointer; }
.vf-read__links .vf-read__linkbtn > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.vf-read__links .vf-read__linkbtn small, .vf-read__links a small { color: var(--vf-text-2); }
.vf-read__links .vf-read__linkbtn:focus-visible { outline: 2px solid var(--vf-accent-text); outline-offset: 2px; border-radius: 8px; }
