/* ============================================================================
   design-system.css — Sarpras Operations product design system (v1.31.24.0)

   The AUTHORITATIVE component layer of the product redesign. Loaded LAST
   (after style.css, platform.css and every module stylesheet), so for any
   shared component the rule here is the one that renders.

   WHY A FINAL LAYER (and not edits scattered through 22k lines of CSS):
   the app grew through eleven visual passes — platform.css alone defines
   `.v2-topbar` four times and `.v2-kpi-card` seven times, and four modules
   shipped their own palettes. The tokens are now unified at the source
   (platform.css :root, the module scopes alias them); this file gives every
   shared COMPONENT one recipe on top of those tokens. Retiring the
   superseded legacy rules is a separate, mechanical clean-up (see
   docs/DESIGN-SYSTEM.md §10) — doing it in the same change would make this
   redesign impossible to review or roll back.

   Rules of this file
   - Tokens only. No raw colours except inside the token blocks.
   - Presentation only. No selector here changes layout that JS measures,
     hides/shows content, or alters what a control does.
   - Every animated property is transform/opacity (or a one-shot colour).
   - Reduced motion: style.css's global blankets zero every duration here.

   Contents
     1. Base & typography        6. Data display (KPI, tables, badges)
     2. Focus & selection         7. Overlays (modal, drawer, sheet, toast)
     3. App shell                 8. Login & splash
     4. Buttons                   9. Module refinements
     5. Form controls            10. Responsive (phone, foldable, landscape)
   ========================================================================== */


/* ── 1. Base & typography ─────────────────────────────────────────────────── */

:root {
  /* Type scale — 13px is the dense-data floor; body copy is 14px. */
  --ds-text-xs:   12px;   /* captions, meta, table header */
  --ds-text-sm:   13px;   /* secondary text, dense tables, chips */
  --ds-text-md:   14px;   /* body, controls */
  --ds-text-lg:   16px;   /* card / section titles */
  --ds-text-xl:   20px;   /* page titles */
  --ds-text-2xl:  24px;   /* KPI values */
  --ds-text-3xl:  30px;   /* the one hero figure per screen */

  /* Re-point the legacy type tokens onto the scale (they drive hundreds of
     existing rules — keeping their names, changing their values). */
  --type-display-xl: clamp(26px, 3vw, 32px);
  --type-display-lg: clamp(20px, 2.1vw, 24px);
  --type-heading-xl: 17px;
  --type-heading-lg: 18px;
  --type-heading-md: 15px;
  --type-heading-sm: 14px;
  --type-body:       14px;
  --type-body-lg:    15px;
  --type-body-sm:    13px;
  --type-caption:    12px;
  --type-label:      11.5px;

  /* Rhythm — denser than the previous "keynote" spacing (26/56px gaps). */
  --space-hero:       20px;
  --space-section:    24px;
  --space-subsection: 16px;
  --space-card:       12px;
  --workspace-section-gap: 24px;
  --workspace-card-gap:    12px;
  --workspace-pad-top:     20px;

  /* Motion — the product tiers (docs/MOTION-SYSTEM.md §2), one vocabulary. */
  --motion-ease:   cubic-bezier(.16, 1, .3, 1);
  --motion-normal: 200ms;
  /* Springs (product reimagining) — sampled from a damped spring into CSS
     linear() (SS20.1-C7-work/rp-tools/spring.cjs; Motion's visualDuration +
     bounce convention). The listed duration is the full settle; time sibling
     motion off the visual duration. Overshoot never exceeds 0.3% — this is an
     operations tool. Under reduced motion style.css zeroes every duration. */
  --ease-spring-snap: linear(0, 0.0882, 0.2669, 0.4564, 0.6214, 0.7503, 0.8439, 0.908, 0.9496, 0.9751, 0.9898, 0.9977, 1.0014, 1.0028, 1.0029, 1.0025, 1.002, 1.0014, 1); /* 0.22s, bounce .12 → 305ms */
  --ease-spring-panel: linear(0, 0.0443, 0.1453, 0.2692, 0.3956, 0.5133, 0.6166, 0.7039, 0.7754, 0.8325, 0.8771, 0.9114, 0.9372, 0.9563, 0.9703, 0.9803, 0.9874, 0.9922, 0.9955, 0.9977, 1); /* 0.32s, bounce .08 → 335ms */
  --spring-snap-ms: 305ms;
  --spring-panel-ms: 335ms;

  --accent-hover:  color-mix(in srgb, var(--accent) 86%, #000);
  --accent-press:  color-mix(in srgb, var(--accent) 76%, #000);
  --accent-subtle: color-mix(in srgb, var(--accent) 10%, transparent);
  --accent-line:   color-mix(in srgb, var(--accent) 24%, transparent);
}
[data-theme="dark"] {
  --accent-hover:  color-mix(in srgb, var(--accent) 88%, #fff);
  --accent-press:  color-mix(in srgb, var(--accent) 78%, #fff);
  --accent-subtle: color-mix(in srgb, #5CCB8D 14%, transparent);
  --accent-line:   color-mix(in srgb, #5CCB8D 32%, transparent);
}

html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  font-family: var(--font-sans);
  font-size: var(--ds-text-md);
  line-height: 1.5;
  letter-spacing: 0;
  color: var(--text);
  background: var(--canvas);
  font-feature-settings: "kern";
  text-rendering: optimizeLegibility;
}
/* Every number in an operations product is compared with the one next to it:
   tabular figures everywhere digits line up (tables, KPIs, times, money). */
table, .v2-kpi-value, [class*="kpi-value"], [class*="-stat-num"], [class*="stat-value"],
.date-display, .timeline-hours, .wsp-hero__stat-big, time, .ds-num {
  font-variant-numeric: tabular-nums;
}
h1, h2, h3, h4 { font-family: var(--font-display); letter-spacing: -0.01em; }

/* Mono is for identifiers only (reference numbers, IDs, plates) — never for
   prose dates. The old date control rendered "Sel, 13 Okt 2026" in mono. */
#filterDate, .date-input, .date-display { font-family: var(--font-sans); }

::placeholder { color: var(--faint); opacity: 1; }


/* ── 2. Focus & selection ─────────────────────────────────────────────────── */

/* One visible focus treatment for every keyboard-focusable control that does
   not draw its own. :focus-visible only — pointer clicks never show it. */
:where(button, [role="button"], a, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
:where(input, select, textarea):focus-visible { outline: none; }


/* ── 3. App shell ─────────────────────────────────────────────────────────── */

/* The shell is a FRAME around the work: the deck on the left (navigation,
   identity, who you are) and a quiet topbar that says where you are.
   Reimagining v2: the deck is a WHITE labelled panel in light (green court-
   line marks, a shuttle-yellow dot on the active screen) and stays the deep
   court green in dark — every colour below is a --deck-* token, so the two
   themes differ only in platform.css. Hooks (.domshell-rail*, .domshell-tabbar, .v2-topbar*) are
   unchanged — js/shell/domain-shell.js owns routing, this section owns looks. */

/* 3.1 The deck (.domshell-rail) — shared by all modes */
.domshell-rail,
.domshell-rail.domshell-rail--mobile-drawer {
  background-color: var(--deck);
  /* Court geometry: the baseline + service lines of a badminton half-court,
     drawn once, static, at 6% — the identity is in the frame, not on data. */
  background-image: var(--deck-court);
  background-repeat: no-repeat;
  background-position: left 0 bottom 0;
  background-size: 248px auto;
  border-right: 1px solid var(--side-border);
  color: var(--deck-text);
  padding: 12px 10px 10px;
}
:root {
  /* Court geometry under the deck footer — PBSI green hairlines on the white
     deck, pale lines on the dark one. */
  --deck-court: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 248 132' fill='none' stroke='%230A6B3C' stroke-opacity='.08' stroke-width='1'%3E%3Cpath d='M14 132V40h220v92M14 64h220M34 40v92M214 40v92M124 64v68'/%3E%3Cpath d='M-10 30C70 -2 170 -6 260 22' stroke='%23C9AE00' stroke-dasharray='2 5' stroke-opacity='.35'/%3E%3C/svg%3E");
  --deck-logo-shadow: 0 0 0 1px var(--border), 0 4px 10px -6px rgba(40,36,20,.35);
  --deck-avatar-ring: color-mix(in srgb, var(--deck-marker) 30%, transparent);
}
[data-theme="dark"] {
  --deck-court: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 248 132' fill='none' stroke='%23DCE7E0' stroke-opacity='.06' stroke-width='1'%3E%3Cpath d='M14 132V40h220v92M14 64h220M34 40v92M214 40v92M124 64v68'/%3E%3Cpath d='M-10 30C70 -2 170 -6 260 22' stroke-dasharray='2 5' stroke-opacity='.09'/%3E%3C/svg%3E");
  --deck-logo-shadow: 0 0 0 1px rgba(255,255,255,.12), 0 6px 14px -6px rgba(0,0,0,.6);
  --deck-avatar-ring: rgba(242,216,11,.28);
}
.domshell-rail-brand { position: relative; padding: 2px 2px 14px; gap: 10px; }
.domshell-rail-logo,
[data-theme="dark"] .domshell-rail-logo {
  width: 36px;
  height: 36px;
  padding: 3px;
  border-radius: 10px;
  border: 0;
  background: #FFFFFF;
  box-shadow: var(--deck-logo-shadow);
}
.domshell-rail-brandname {
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--deck-strong);
}
.domshell-rail-brandver {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .02em;
  color: var(--deck-muted);
}
.domshell-deck-toggle {
  margin-left: auto;
  flex: 0 0 auto;
  display: none;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--deck-muted);
  cursor: pointer;
  transition: background-color var(--motion-fast) ease, color var(--motion-fast) ease;
}
.domshell-deck-toggle:hover { background: var(--deck-hover); color: var(--deck-strong); }
.domshell-deck-toggle:focus-visible { outline: 2px solid var(--deck-focus); outline-offset: 1px; }
body.deck-can-expand .domshell-deck-toggle { display: inline-flex; }
/* Collapsed rail: the toggle only shows inside the opened flyout (it would
   not fit beside the logo in 72px). */
body.deck-collapsed .domshell-rail:not(:hover):not(:focus-within) .domshell-deck-toggle { opacity: 0; pointer-events: none; }

.domshell-rail-list { gap: 2px; }
.domshell-rail-item {
  position: relative;
  height: 40px;
  padding: 0 11px;
  gap: 12px;
  border-radius: var(--r-md);
  color: var(--deck-muted);
}
.domshell-rail-item:hover,
.domshell-rail-item:focus-visible { background: var(--deck-hover); color: var(--deck-strong); }
.domshell-rail-item:focus-visible { outline: 2px solid var(--deck-focus); outline-offset: -2px; }
.domshell-rail-item--active,
.domshell-rail-item--active:hover {
  background: var(--deck-active);
  color: var(--deck-active-fg);
}
.domshell-rail-item--active .domshell-rail-icon { color: var(--deck-marker); }
/* Active marker: a court line on the deck's inner edge (green on the white
   deck, shuttle yellow on the dark one). Scales in
   (transform only); position + weight + colour, never colour alone. */
.domshell-rail-item::before {
  content: "";
  position: absolute;
  left: -10px;
  top: 10px;
  bottom: 10px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--deck-marker);
  transform: scaleY(0);
  transition: transform var(--motion-pop, 160ms) var(--ease-spring-snap, var(--motion-ease));
}
.domshell-rail-item--active::before { transform: scaleY(1); }
.domshell-rail-label { font-size: var(--ds-text-md); font-weight: 500; letter-spacing: 0; }
.domshell-rail-item--active .domshell-rail-label { font-weight: 600; }

.domshell-deck-sep {
  height: 1px;
  margin: 8px 8px;
  background: var(--deck-line);
  flex: 0 0 auto;
}

/* Nested screens — a court line runs down from the domain icon; the active
   screen is a shuttle-yellow mark on that line. Hidden unless the deck is
   expanded (or in the phone drawer) AND the entry is active. */
.domshell-deck-screens {
  display: none;
  position: relative;
  list-style: none;
  margin: 2px 0 6px;
  padding: 0 0 0 33px;
}
.domshell-deck-screens::before {
  content: "";
  position: absolute;
  left: 21px;
  top: 2px;
  bottom: 6px;
  width: 1px;
  background: var(--deck-line);
}
.domshell-deck-screen {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 32px;
  padding: 6px 10px;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--deck-muted);
  font: inherit;
  font-size: var(--ds-text-sm);
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--motion-fast) ease, color var(--motion-fast) ease;
}
.domshell-deck-screen:hover { background: var(--deck-hover); color: var(--deck-strong); }
.domshell-deck-screen:focus-visible { outline: 2px solid var(--deck-focus); outline-offset: -2px; color: var(--deck-strong); }
.domshell-deck-screen::before {
  content: "";
  position: absolute;
  left: -15px;
  top: 50%;
  width: 7px;
  height: 7px;
  margin-top: -3.5px;
  border-radius: 50%;
  background: var(--shuttle);
  box-shadow: 0 0 0 1.5px var(--deck-marker), 0 0 0 4px var(--deck);
  transform: scale(0);
  transition: transform var(--motion-pop, 160ms) var(--ease-spring-snap, var(--motion-ease));
}
.domshell-deck-screen--active { color: var(--deck-strong); font-weight: 600; }
.domshell-deck-screen--active::before { transform: scale(1); }
.domshell-deck-screen-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

body.deck-expanded .domshell-deck-entry--active .domshell-deck-screens,
.domshell-rail--mobile-drawer .domshell-deck-entry--active .domshell-deck-screens {
  display: block;
  animation: deck-screens-in var(--motion-base, 200ms) var(--motion-ease) both;
}
@keyframes deck-screens-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

.domshell-rail-footer {
  border-top: 1px solid var(--deck-line);
  padding: 10px 2px 2px;
  gap: 10px;
}
.domshell-rail-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--deck-active);
  color: var(--deck-active-fg);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .02em;
  box-shadow: inset 0 0 0 1px var(--deck-avatar-ring);
}
.domshell-rail-username { font-size: var(--ds-text-sm); font-weight: 600; color: var(--deck-strong); }
.domshell-rail-userrole { font-size: 11.5px; color: var(--deck-muted); }

/* 3.2 Collapsed rail (≥768px with a pointer, below 1200px or by choice):
   72px icons; the labelled flyout opens over content on hover/focus. */
.domshell-rail:hover,
.domshell-rail:focus-within { width: 220px; box-shadow: var(--shadow-lg); }

/* 3.3 Expanded deck (≥1200px, hover pointer, default) */
@media (min-width: 768px) {
  body.deck-expanded .domshell-rail,
  body.deck-expanded .domshell-rail:hover,
  body.deck-expanded .domshell-rail:focus-within {
    width: 248px;
    box-shadow: none;
    transition: none;
  }
  body.deck-expanded.domain-shell-active .main-area { margin-left: 248px; }
  body.deck-expanded .domshell-rail-label,
  body.deck-expanded .domshell-rail-brandtext,
  body.deck-expanded .domshell-rail-usertext { opacity: 1; transition: none; }
  body.deck-expanded .domshell-rail-list {
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--deck-line) transparent;
    margin: 0 -4px;
    padding: 0 4px;
  }
  /* The deck lists every screen of the active domain — the top tab row would
     repeat it. A nested sub-row (if a screen has one) still shows. */
  body.deck-expanded .domshell-tabbar:not([data-has-sub]) { display: none !important; }
  body.deck-expanded .domshell-tabbar .domshell-tabrow:not(.domshell-tabrow--sub) { display: none; }
}

/* 3.4 Touch tablets & foldables (no hover): COMPACT labelled rail, 80px. */
@media (min-width: 768px) and (hover: none) {
  .domshell-rail,
  .domshell-rail:hover,
  .domshell-rail:focus-within { width: 80px; padding: 10px 6px; box-shadow: none; }
  body.domain-shell-active .main-area { margin-left: 80px; }
  .domshell-rail-brand { justify-content: center; padding: 2px 0 12px; }
  .domshell-rail-brandtext, .domshell-rail-usertext { display: none; }
  .domshell-rail-item {
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    height: auto;
    min-height: 56px;
    padding: 6px 2px;
    text-align: center;
  }
  .domshell-rail-item::before { left: -6px; top: 12px; bottom: 12px; }
  .domshell-rail-label {
    opacity: 1;
    font-size: 11px;
    font-weight: 500;
    line-height: 1.2;
    white-space: normal;
    max-width: 68px;
    overflow-wrap: anywhere;
  }
  .domshell-deck-sep { margin: 6px 10px; }
  .domshell-rail-footer { justify-content: center; }
  .domshell-rail-list { overflow-y: auto; scrollbar-width: none; overscroll-behavior: contain; }
  .domshell-rail-list::-webkit-scrollbar { display: none; }
}
@media (min-width: 768px) and (hover: none) and (max-height: 560px) {
  .domshell-rail-brand, .domshell-rail-footer { display: none; }
  .domshell-rail-item { min-height: 46px; gap: 2px; }
}

/* 3.5 Phone drawer — the same deck, full labels, active screens nested. */
body.v2-shell-active #sidebar.domshell-drawer-host { background: var(--deck); color: var(--deck-text); border-right: 0; }
/* The drawer's own chrome (brand header, footer) belongs to the deck too. */
body.v2-shell-active #sidebar.domshell-drawer-host .sidebar-header,
body.v2-shell-active #sidebar.domshell-drawer-host .sidebar-footer {
  background: var(--deck);
  border-color: var(--deck-line);
  color: var(--deck-text);
}
body.v2-shell-active #sidebar.domshell-drawer-host .sidebar-brand-title { color: var(--deck-strong); font-weight: 600; }
body.v2-shell-active #sidebar.domshell-drawer-host .sidebar-logo {
  background: #FFFFFF;
  border-radius: 10px;
  padding: 3px;
}
body.v2-shell-active #sidebar.domshell-drawer-host .sidebar-close {
  color: var(--deck-muted);
  background: transparent;
  border-color: var(--deck-line);
}
body.v2-shell-active #sidebar.domshell-drawer-host .sidebar-close:hover { color: var(--deck-strong); background: var(--deck-hover); }
body.v2-shell-active #sidebar.domshell-drawer-host .sidebar-footer * { color: var(--deck-muted); }
/* v2: no court drawing in the phone drawer — the list is long enough that it
   sat UNDER the last items (Insights / Control) instead of under the footer. */
.domshell-rail.domshell-rail--mobile-drawer { border-right: 0; background-image: none; }
.domshell-rail--mobile-drawer .domshell-rail-item { height: 44px; }
.domshell-rail--mobile-drawer .domshell-deck-screen { min-height: 40px; }

/* 3.6 Topbar — says where you are. 60px, one hairline; the page title is the
   level-1 heading (setCrumb()); the domain sits above it in small caps. */
body.v2-shell-active .v2-topbar {
  min-height: 60px;
  height: 60px;
  padding: 0 20px 0 24px;
  background: var(--topbar-bg);
  border-bottom: 1px solid var(--border);
  box-shadow: none;
  gap: 8px;
}
#v2TopbarCrumb { gap: 2px; min-width: 0; margin-right: 8px; }
body.v2-shell-active .v2-topbar-label,
.v2-topbar-label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--faint);
  opacity: 1;
}
body.v2-shell-active .v2-topbar-title,
.v2-topbar-title {
  font-family: var(--font-sans);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.012em;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
body.v2-shell-active .v2-topbar-search {
  height: 36px;
  min-width: 200px;
  max-width: 320px;
  flex: 0 1 300px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: none;
  transition: border-color var(--motion-fast) ease, background-color var(--motion-fast) ease, box-shadow var(--motion-fast) ease;
}
body.v2-shell-active .v2-topbar-search:hover { border-color: var(--border-strong); }
body.v2-shell-active .v2-topbar-search:focus-within {
  background: var(--surface);
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}
body.v2-shell-active .v2-topbar-search-input { font-size: var(--ds-text-sm); color: var(--text); }
body.v2-shell-active .v2-topbar-search svg { color: var(--faint); }

/* Icon buttons (theme, notifications) and the palette trigger share one 36px
   recipe — quiet until hovered. */
body.v2-shell-active .v2-topbar-icon-btn,
body.v2-shell-active #btnHeaderNotif,
body.v2-shell-active .header-notif-btn {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--muted);
  box-shadow: none;
  transition: background-color var(--motion-fast) ease, color var(--motion-fast) ease, border-color var(--motion-fast) ease;
}
body.v2-shell-active .v2-topbar-icon-btn:hover,
body.v2-shell-active #btnHeaderNotif:hover,
body.v2-shell-active .header-notif-btn:hover {
  background: var(--hover);
  color: var(--text);
  border-color: var(--border);
}
.domshell-palette-trigger {
  height: 36px;
  border-radius: 10px;
  border-color: var(--border);
  background: var(--surface);
  color: var(--muted);
  font-size: var(--ds-text-sm);
  font-weight: 500;
}

/* Date navigation — only where the viewed date changes content: the Board
   (workspace "dashboard" — timeline, list and the driver's own board). On
   every other screen it was a disabled-looking dead control. */
body.v2-shell-active[data-workspace]:not([data-workspace="dashboard"]) .v2-topbar .date-nav { display: none; }
body.v2-shell-active .v2-topbar .date-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  height: 36px;
  padding: 2px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: none;
}
body.v2-shell-active .v2-topbar .date-nav .btn-today,
body.v2-shell-active .v2-topbar .date-nav .btn-icon,
body.v2-shell-active .v2-topbar .date-nav button {
  height: 30px;
  min-height: 0;
  min-width: 30px;
  padding: 0 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  font-size: var(--ds-text-sm);
  font-weight: 500;
  box-shadow: none;
}
body.v2-shell-active .v2-topbar .date-nav .btn-icon { padding: 0; width: 30px; flex: 0 0 30px; }
/* "Hari Ini" never shrinks; the date trigger (compact "14 Okt") yields. */
body.v2-shell-active .v2-topbar .date-nav .btn-today { flex: 0 0 auto; white-space: nowrap; }
body.v2-shell-active .v2-topbar .date-nav .pbsi-datepicker { min-width: 0; flex: 0 1 auto; }
body.v2-shell-active .v2-topbar .date-nav .pbsi-datepicker-trigger { min-width: 0; overflow: hidden; }
body.v2-shell-active .v2-topbar .date-nav button:hover:not(:disabled) { background: var(--surface); color: var(--text); box-shadow: var(--shadow-xs); }
body.v2-shell-active .v2-topbar .date-nav button:disabled { opacity: .45; background: transparent; color: var(--faint); }
body.v2-shell-active .v2-topbar .date-nav .date-display,
body.v2-shell-active .v2-topbar .date-nav .date-input,
body.v2-shell-active .v2-topbar .date-nav input {
  font-family: var(--font-sans);
  font-size: var(--ds-text-sm);
  font-weight: 500;
  color: var(--text);
  background: transparent;
  border: 0;
}

/* User card */
body.v2-shell-active .v2-topbar .header-user-area {
  height: 40px;
  padding: 3px 12px 3px 3px;
  border-radius: var(--r-full);
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: none;
  transition: background-color var(--motion-fast) ease, border-color var(--motion-fast) ease;
}
body.v2-shell-active .v2-topbar .header-user-area:hover { background: var(--hover); border-color: var(--border-strong); }
.v2-topbar-avatar {
  background: var(--court);
  color: var(--shuttle);
  font-weight: 600;
  letter-spacing: .02em;
}
body.v2-shell-active #headerDisplayName { font-size: var(--ds-text-sm); font-weight: 600; color: var(--text); }
body.v2-shell-active .v2-topbar-user-role { font-size: 11px; color: var(--faint); }

@media (max-width: 767px) {
  body.v2-shell-active .v2-topbar { height: auto; min-height: 52px; padding: 6px 10px; }
  /* Phones: the middle slot says WHERE you are; on the Board it holds the
     date controls instead (the Board's own header names the screen). */
  body.v2-shell-active[data-workspace]:not([data-workspace="dashboard"]) #v2TopbarCrumb {
    display: flex !important;
    grid-area: dnav;
    min-width: 0;
    margin: 0 0 0 4px;
  }
  body.v2-shell-active #v2TopbarCrumb .v2-topbar-label { font-size: 9.5px; }
  body.v2-shell-active #v2TopbarCrumb .v2-topbar-title { font-size: 15px; }
  body.v2-shell-active .v2-topbar .date-nav .btn-icon { width: 26px; min-width: 26px; flex-basis: 26px; }
}
@media (max-width: 380px) {
  body.v2-shell-active .v2-topbar .date-nav .btn-today { padding: 0 6px; }
  /* The prose date does not fit beside four controls: the trigger becomes
     its calendar icon (its aria-label still announces the date). */
  body.v2-shell-active .v2-topbar .date-nav .pbsi-datepicker-trigger { padding: 0; width: 30px; flex: 0 0 30px; justify-content: center; }
  body.v2-shell-active .v2-topbar .date-nav .pbsi-datepicker-display { display: none; }
  /* ≤380px the theme switch stays one tap away in Profil → Tampilan. */
  body.v2-shell-active .v2-topbar .v2-topbar-theme-btn { display: none; }
  .bottom-nav-item { padding-left: 1px; padding-right: 1px; }
  .bottom-nav-item span { letter-spacing: -0.015em; }
}
@media (max-width: 300px) {
  /* Folded foldables (~280px): day-step arrows yield; "Hari Ini" + the
     calendar still reach every date. */
  body.v2-shell-active .v2-topbar .date-nav .btn-icon { display: none; }
}

/* 3.7 Screen tabs (collapsed rail, tablets, phones) — underline tabs. */
.domshell-tabbar {
  background: var(--topbar-bg);
  border-bottom: 1px solid var(--border);
  padding: 0 var(--workspace-edge, 40px) 0 calc(var(--workspace-edge, 40px) - 12px);
}
.domshell-tabrow {
  gap: 0;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  width: auto;
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  animation: none;
}
.domshell-tabrow::-webkit-scrollbar { display: none; }
.domshell-tab {
  position: relative;
  height: 44px;
  padding: 0 12px;
  border-radius: 0;
  background: transparent;
  color: var(--muted);
  font-size: var(--ds-text-md);
  font-weight: 500;
  box-shadow: none;
}
.domshell-tab:hover,
.domshell-tab:focus-visible { color: var(--text); background: transparent; }
.domshell-tab:focus-visible { outline-offset: -4px; border-radius: var(--r-sm); }
.domshell-tab::after {
  content: "";
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: -1px;
  height: 2px;
  border-radius: 2px 2px 0 0;
  background: var(--accent);
  transform: scaleX(0);
  opacity: 0;
  transition: transform var(--motion-pop, 160ms) var(--ease-spring-snap, var(--motion-ease)), opacity var(--motion-fast) linear;
}
.domshell-tab--active,
.domshell-tab--active:hover {
  background: transparent;
  color: var(--text);
  font-weight: 600;
  box-shadow: none;
}
.domshell-tab--active::after { transform: scaleX(1); opacity: 1; }
.domshell-tabrow--sub {
  border-top: 1px solid var(--border);
  padding: 8px 0;
  gap: 4px;
}
.domshell-tabrow--sub .domshell-tab { height: 30px; padding: 0 10px; border-radius: var(--r-full); font-size: var(--ds-text-sm); }
.domshell-tabrow--sub .domshell-tab::after { display: none; }
.domshell-tabrow--sub .domshell-tab--active { background: var(--accent-subtle); color: var(--accent-fg); }

/* 3.7b Navigation crossfade — near-instant (UX/motion audit #1). A workspace
   change (domain switch) ran a 300ms root crossfade, and while a View
   Transition runs its overlay takes pointer hit-testing (documented in
   platform.css SS14), so every navigation also swallowed clicks for 300ms+.
   Navigation happens tens of times a day: 120ms keeps the "content changed"
   cue and gives the page back almost at once. Scoped to navigations only
   (html.domshell-nav-transition is set by setWorkspace for the transition's
   lifetime) — the theme crossfade keeps its own duration. Reduced motion:
   setWorkspace skips the View Transition entirely. */
html.domshell-nav-transition::view-transition-old(root),
html.domshell-nav-transition::view-transition-new(root) {
  animation-duration: 120ms;
  animation-timing-function: cubic-bezier(.23, 1, .32, 1);
}

/* 3.8 Canvas */
body.v2-shell-active .main-area,
body.v2-shell-active .main-content { background: var(--canvas); }
/* One phone gutter: 16px from the screen edge to content on every screen
   (was 8px under 481px — main-content 8 + workspace 0 — and 24px above). */
@media (max-width: 767px) {
  body.v2-shell-active .main-content { padding-left: 16px; padding-right: 16px; }
  body.v2-shell-active .main-content > .v2-workspace { padding-left: 0; padding-right: 0; }
}


/* ── 4. Buttons ───────────────────────────────────────────────────────────── */
/* Hierarchy: primary (one per view, court green) · secondary (outlined) ·
   ghost (text) · danger (outlined red; solid only inside a confirmation).
   Height 36px desktop, 44px on touch (see §10). Press = scale .97 (instant
   feedback; motion system "press" tier). */

.btn-primary, .p-btn-primary, .v2-panel-btn--primary, .v2-admin-add-btn,
.gud-btn.-primary, .eng-btn.-primary, .sf-btn--primary,
.req-sheet__btn--primary, .login-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--control-h);
  padding: 0 16px;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  background: var(--accent);
  background-image: none;
  color: var(--on-accent);
  font-family: var(--font-sans);
  font-size: var(--ds-text-md);
  font-weight: 600;
  letter-spacing: 0;
  box-shadow: var(--shadow-xs);
  filter: none;
  cursor: pointer;
  transition: background-color var(--motion-fast) ease, box-shadow var(--motion-fast) ease, transform 80ms ease;
}
.btn-primary:hover:not(:disabled), .p-btn-primary:hover:not(:disabled), .v2-panel-btn--primary:hover:not(:disabled),
.v2-admin-add-btn:hover:not(:disabled), .gud-btn.-primary:hover:not(:disabled), .eng-btn.-primary:hover:not(:disabled),
.sf-btn--primary:hover:not(:disabled), .login-submit:hover:not(:disabled) {
  background: var(--accent-hover);
  filter: none;
  transform: none;
}
.btn-primary:active:not(:disabled), .p-btn-primary:active:not(:disabled), .gud-btn.-primary:active:not(:disabled),
.eng-btn.-primary:active:not(:disabled), .v2-admin-add-btn:active:not(:disabled), .login-submit:active:not(:disabled) {
  background: var(--accent-press);
  transform: scale(.97);
}

.btn-secondary, .p-btn-ghost, .v2-panel-btn--ghost, .gud-btn, .eng-btn,
.v2-analytics-export-btn, .v2-admin-config-ghost-btn, .exec-reset, .sf-btn {
  min-height: var(--control-h);
  border-radius: var(--r-md);
  font-family: var(--font-sans);
  font-size: var(--ds-text-md);
  font-weight: 500;
  letter-spacing: 0;
}
.btn-secondary, .p-btn-ghost, .v2-panel-btn--ghost, .gud-btn:not(.-primary):not(.-danger):not(.-tone-violet),
.eng-btn:not(.-primary):not(.-tone-violet), .v2-analytics-export-btn, .v2-admin-config-ghost-btn, .exec-reset {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--text);
  box-shadow: var(--shadow-xs);
}
.btn-secondary:hover:not(:disabled), .p-btn-ghost:hover:not(:disabled), .v2-panel-btn--ghost:hover:not(:disabled),
.gud-btn:not(.-primary):not(.-danger):hover:not(:disabled), .eng-btn:not(.-primary):hover:not(:disabled),
.v2-analytics-export-btn:hover:not(:disabled), .v2-admin-config-ghost-btn:hover:not(:disabled), .exec-reset:hover:not(:disabled) {
  background: var(--hover);
  border-color: var(--border-strong);
  color: var(--text);
  transform: none;
}
.gud-btn.-sm, .eng-btn.-sm { min-height: var(--control-h-sm); height: var(--control-h-sm); font-size: var(--ds-text-sm); border-radius: var(--r-sm); }
.gud-btn.-big, .eng-btn.-big { height: 48px; border-radius: var(--r-md); font-size: var(--ds-text-md); }
.gud-btn, .eng-btn { height: var(--control-h); }

/* Danger — outlined by default; the filled variant is reserved for the final
   confirm step of an irreversible action. */
.btn-danger, .gud-btn.-danger, .p-btn-danger {
  background: var(--danger);
  border: 1px solid transparent;
  color: #fff;
  border-radius: var(--r-md);
  font-weight: 600;
}
.btn-danger:hover:not(:disabled), .gud-btn.-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--danger) 88%, #000); filter: none; }
.eng-btn.-danger, .gud-btn.-danger-ghost {
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--danger) 40%, var(--border));
  color: var(--danger);
}
.eng-btn.-danger:hover:not(:disabled), .gud-btn.-danger-ghost:hover:not(:disabled) { background: var(--danger-bg); border-color: var(--danger); color: var(--danger); }

button:disabled, .btn-primary:disabled, .gud-btn:disabled, .eng-btn:disabled { cursor: not-allowed; }


/* ── 5. Form controls ─────────────────────────────────────────────────────── */

.form-group label, .sf-label, .drawer label:not(.multi-day-checkbox-label):not([class*="toggle"]) {
  font-size: var(--ds-text-sm);
  font-weight: 500;
  color: var(--text);
  letter-spacing: 0;
  text-transform: none;
}
.form-group input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
.form-group select, .form-group textarea,
.gud-input, .eng-input, .v2-admin-config-input, .exec-search,
.drawer input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
.drawer select, .drawer textarea {
  min-height: var(--control-h);
  border: 1px solid var(--input-border);
  border-radius: var(--r-md);
  background: var(--input-bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--ds-text-md);
  box-shadow: var(--shadow-xs);
  transition: border-color var(--motion-fast) ease, box-shadow var(--motion-fast) ease;
}
.form-group textarea, .drawer textarea { min-height: 88px; line-height: 1.5; }
.form-group input:hover:not(:disabled):not(:focus), .form-group select:hover:not(:disabled):not(:focus),
.gud-input:hover:not(:focus), .eng-input:hover:not(:focus) { border-color: var(--border-strong); }
.form-group input:focus, .form-group select:focus, .form-group textarea:focus,
.gud-input:focus, .eng-input:focus, .v2-admin-config-input:focus,
.drawer input:focus, .drawer select:focus, .drawer textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}
.form-group input[aria-invalid="true"], .drawer input[aria-invalid="true"],
.form-group select[aria-invalid="true"], .drawer select[aria-invalid="true"] {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 16%, transparent);
}
.sf-field-error, .sf-inline-error, .login-error-v2 {
  color: var(--danger);
  font-size: var(--ds-text-sm);
}
input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }

/* Segmented controls (Timeline/Daftar, Agenda mode switch, chart ranges). */
.v2-tl-view-toggle, .cal-modeswitch {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 2px;
  gap: 2px;
}
.v2-tl-view-btn, .cal-modeswitch button {
  border-radius: var(--r-sm);
  font-size: var(--ds-text-sm);
  font-weight: 500;
  color: var(--muted);
}
.v2-tl-view-btn.active, .v2-tl-view-btn[aria-pressed="true"], .v2-tl-view-btn--active,
.cal-modeswitch button[aria-selected="true"] {
  background: var(--surface);
  color: var(--text);
  font-weight: 600;
  box-shadow: var(--shadow-sm);
}


/* ── 6. Data display ──────────────────────────────────────────────────────── */

/* 6.1 Cards — flat: surface + 1px border, no shadow at rest. */
.eng-card, .gud-card, .v2-surface-card, .v2-list-card, .notif-card, .dash-card,
.v2-analytics-card, .card {
  border-radius: var(--r-lg);
  border-color: var(--border);
  box-shadow: none;
}

/* 6.2 KPI tiles — ONE recipe for Board/Petty Cash/Overtime/Engineering:
   label (sentence case, muted) → value (24px, tabular, text colour) →
   caption. Status is carried by the small icon tile, not by a coloured left
   border or a coloured number — a red "0 employees" read as an error. */
body.v2-shell-active .v2-kpi-card, .v2-kpi-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: none;
  padding: 16px;
  gap: 4px;
}
.v2-kpi-card[data-kpi] { border-left: 1px solid var(--border); }
body.v2-shell-active .v2-kpi-card:hover { box-shadow: none; border-color: var(--border-strong); transform: none; }
/* Reimagined: label first (mono, small caps), the number leads, the icon
   becomes a small tone mark in the corner — figures, not decorated cards. */
body.v2-shell-active .v2-kpi-card, .v2-kpi-card { position: relative; padding: 16px 18px 18px; }
.v2-kpi-card .v2-kpi-icon {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 26px;
  height: 26px;
  margin: 0;
  border-radius: var(--r-sm);
}
.v2-kpi-card .v2-kpi-label {
  order: -1;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--faint);
  padding-right: 34px;
}
.v2-kpi-card .v2-kpi-value,
.v2-kpi-card[data-kpi] .v2-kpi-value {
  margin-top: 6px;
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--text);
}
.v2-kpi-card .v2-kpi-sub { font-size: var(--ds-text-xs); color: var(--faint); }
.eng-kpi-label, .an-label {
  font-size: var(--ds-text-xs);
  font-weight: 500;
  letter-spacing: .02em;
  text-transform: none;
  color: var(--muted);
}
.eng-kpi-value { font-weight: 600; font-size: var(--ds-text-2xl); letter-spacing: -0.01em; }

/* ── 6.2b Ledger strips (reimagining v2) ────────────────────────────────── */
/* A row of figures is ONE ledger, not four floating cards (the generic
   "KPI card row" every dashboard template ships): a single surface, figures
   divided by hairlines drawn as inset shadows so ANY column count — and the
   2-up phone wrap — gets a clean grid with no doubled or dangling borders.
   Applies to Petty Cash, Overtime (KPIs + budget), Gudang overview,
   Engineering hero stats and the Administration overview. Same content and
   order; only the composition changes. */
.rx-ledger,
.gud-ov-grid,
.eng-hero-stats,
.v2-admin-overview-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow: hidden;
}
.rx-ledger > .rx-figure,
.gud-ov-grid > .gud-ov-card,
.eng-hero-stats > .eng-kpi,
.v2-admin-overview-cards > .v2-admin-overview-card {
  min-width: 0;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: -1px 0 0 var(--border), 0 -1px 0 var(--border);
  padding: 16px 20px 18px;
}
/* The lead figure of a ledger carries the court line — the one number the
   strip is about. */
.rx-ledger > .rx-figure:first-child::before,
.gud-ov-grid > .gud-ov-card:first-child::before,
.eng-hero-stats > .eng-kpi:first-child::before,
.v2-admin-overview-cards > .v2-admin-overview-card:first-child::before {
  content: "";
  position: absolute;
  left: 20px;
  top: 0;
  width: 24px;
  height: 3px;
  border-radius: 0 0 2px 2px;
  background: var(--accent);
}
.gud-ov-grid > .gud-ov-card, .eng-hero-stats > .eng-kpi, .v2-admin-overview-cards > .v2-admin-overview-card { position: relative; }
@media (max-width: 600px) {
  .rx-ledger, .gud-ov-grid, .eng-hero-stats, .v2-admin-overview-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rx-ledger > .rx-figure, .gud-ov-grid > .gud-ov-card, .eng-hero-stats > .eng-kpi, .v2-admin-overview-cards > .v2-admin-overview-card { padding: 14px 14px 16px; }
}

/* 6.3 Tables — 13px rows, sticky-able 12px header, hairline rows. */
.eng-table, .gud-table, .p-table, .ot-records-table, .ot-history-table, .ot-preview-table,
.ot-closing-table, .v2-req-review-table, .v2-asg-review-table, .rm-matrix-table, .exec-table--dense {
  font-size: var(--ds-text-sm);
  border-collapse: separate;
  border-spacing: 0;
}
.eng-table th, .gud-table th, .p-table th, .ot-records-table th, .ot-history-table th, .ot-preview-table th,
.ot-closing-table th, .v2-req-review-table th, .v2-asg-review-table th, .rm-matrix-table th {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--faint);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.eng-table td, .gud-table td, .p-table td, .ot-records-table td, .ot-history-table td,
.v2-req-review-table td, .rm-matrix-table td { border-bottom: 1px solid var(--grid); }
.eng-table tbody tr:hover td, .gud-table tbody tr:hover td, .p-table tbody tr:hover td,
.ot-records-table tbody tr:hover td { background: var(--hover); }

/* 6.4 Badges, pills, chips — 22px, 12px text, tinted; always carry a label. */
.p-pill, .exec-pill, .eng-pill, .gud-pill, .badge-status, .role-badge, .v2-user-status-pill {
  font-family: var(--font-sans);
  font-size: var(--ds-text-xs);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  border-radius: var(--r-full);
  line-height: 1.5;
}
.exec-badge, .v2-analytics-claude .eyebrow .tag, .an-tag {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  border-radius: var(--r-sm);
}
.v2-filter-chip, .gud-chip, .eng-chip {
  border-radius: var(--r-full);
  font-size: var(--ds-text-sm);
  font-weight: 500;
}

/* 6.5 Empty states — calm, centred, one next step. */
.eng-empty, .gud-empty {
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background:
    linear-gradient(var(--surface-2), var(--surface-2)) padding-box;
  padding: 44px 24px;
}
.eng-empty-ic, .gud-empty-ic {
  width: 44px;
  height: 44px;
  border-radius: var(--r-md);
  background: var(--surface-3);
  color: var(--muted);
  margin-bottom: 12px;
}
/* The empty state is an editorial moment: a serif line says what this space
   is for; the hint and the one action do the work. */
.eng-empty-t, .gud-empty-t { font-family: var(--font-editorial); font-size: 24px; font-weight: 400; letter-spacing: -0.01em; line-height: 1.15; color: var(--text); }
.eng-empty-h, .gud-empty-h { font-size: var(--ds-text-sm); color: var(--muted); }

/* 6.6 Page headers inside modules — one size for every module (Gudang used
   30px/800, Engineering 26px, Overtime 18px, Analytics 28px). */
.gud-page-title, .eng-page-title, .exec-head__title {
  font-family: var(--font-display);
  font-size: clamp(22px, 2.2vw, 28px);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
/* Eyebrows across modules: mono small caps led by the court-line mark — the
   same device that opens every band on Today. */
.gud-page-crumb, .eng-page-crumb {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 8px;
}
.gud-page-crumb::before, .eng-page-crumb::before {
  content: "";
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
}
.gud-page-lede, .eng-page-lede, .exec-head__sub { font-size: var(--ds-text-md); color: var(--muted); margin-top: 4px; }
.gud-sec-tag, .eng-sec-tag {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}
.gud-sec-title, .eng-sec-title, .v2-analytics-claude .eyebrow h2 {
  font-family: var(--font-display);
  font-size: var(--ds-text-lg);
  font-weight: 600;
  letter-spacing: -0.005em;
}
.p-shead h2, .v2-dash-header h2 {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}


/* 6.7 rx-* — the shared presentation vocabulary (product reimagining) for
   modules whose renderers used to inline every style (Petty Cash, Overtime):
   page head, figure tile, panel, empty state. Same recipes as the class-based
   modules above, so every module reads as one product. */
.rx-page-head { margin: 4px 0 18px; }
.rx-title,
.pc-root h2.rx-title {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-size: clamp(22px, 2.2vw, 28px);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--text);
}
.rx-lede { margin: 0; font-size: var(--ds-text-md); line-height: 1.55; color: var(--muted); max-width: 70ch; }

.rx-figure {
  position: relative;
  flex: 1;
  min-width: 150px;
  display: flex;
  flex-direction: column;
  padding: 16px 18px 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  /* Values size to the TILE, not the viewport: six-across budget tiles and
     four-across KPI tiles both read without overflow. */
  container-type: inline-size;
}
.rx-figure__label {
  padding-right: 36px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--faint);
}
.rx-figure__value {
  margin-top: 8px;
  font-family: var(--font-display);
  font-size: clamp(18px, 13cqi, 28px);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  overflow-wrap: anywhere;
}
.rx-figure__note { margin-top: 6px; font-size: var(--ds-text-xs); line-height: 1.45; color: var(--faint); }
.rx-figure__mark {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 26px;
  height: 26px;
  border-radius: var(--r-sm);
  display: flex;
  align-items: center;
  justify-content: center;
}
.rx-figure__flag { margin-top: 10px; }

.rx-panel {
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.rx-panel__title {
  margin-bottom: 6px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--text);
}

.rx-empty { padding: 44px 24px; text-align: center; }
.rx-empty__mark {
  width: 46px;
  height: 46px;
  margin: 0 auto 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-lg);
  background: var(--surface-3);
  color: var(--muted);
}
.rx-empty__title {
  font-family: var(--font-editorial);
  font-size: 22px;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--text);
}
.rx-empty__hint { max-width: 340px; margin: 6px auto 0; font-size: var(--ds-text-sm); line-height: 1.5; color: var(--muted); }


/* ── 7. Overlays ──────────────────────────────────────────────────────────── */

.modal-overlay, .drawer-overlay.is-open, .bottom-sheet-overlay, .domshell-palette-overlay {
  background: var(--scrim);
}
body.v2-shell-active .modal-box, .modal-box, .eng-modal-box, .gud-modal-box, .domshell-palette-box {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
}
.modal-header { border-bottom: 1px solid var(--border); }
.modal-title, .eng-modal-title, .gud-modal-title {
  font-family: var(--font-display);
  font-size: var(--ds-text-lg);
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--text);
}
.modal-close {
  width: 32px;
  height: 32px;
  border-radius: var(--r-md);
  color: var(--muted);
}
.modal-close:hover { background: var(--hover); color: var(--text); }
.drawer {
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
}
.bottom-sheet {
  background: var(--surface);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: var(--shadow-lg);
}
.bottom-sheet-handle { background: var(--border-strong); }

/* Overlay entrances settle on the panel spring (product reimagining): a
   physical arrival that comes to rest without visible overshoot (≤0.3%).
   ENTRANCES only — the drawer's close uses its base accelerate curve (the
   .is-open class is removed on close, so this rule no longer applies), and
   modal/sheet exits are inert ghost copies (js/ui/modal-motion.js) that keep
   their own --ease-exit. Reduced motion zeroes every duration (style.css). */
.drawer-overlay.is-open .drawer {
  transition-duration: var(--spring-panel-ms, 335ms);
  transition-timing-function: var(--ease-spring-panel, cubic-bezier(.16,1,.3,1));
}
@media (min-width: 601px) {
  body.v2-shell-active .modal-box {
    animation-duration: 300ms;
    animation-timing-function: var(--ease-spring-panel, cubic-bezier(.16,1,.3,1));
  }
}
@media (max-width: 600px) {
  body.v2-shell-active .modal-box,
  .bottom-sheet.open, .bottom-sheet.is-open {
    animation-duration: var(--spring-panel-ms, 335ms);
    animation-timing-function: var(--ease-spring-panel, cubic-bezier(.16,1,.3,1));
  }
}

/* Toasts — ONE inverse surface for every severity (dark in light mode, light
   in dark mode); severity = coloured icon + a 3px leading bar (light: court green, v2). Was a solid
   status fill with white text, which measured 2.2:1 for success in dark mode
   (white on #5CC184). Icon tones are picked for contrast against the
   INVERSE surface, so each theme uses the other theme's status values. */
:root {
  --toast-bg: #123522; --toast-fg: #F1F6F2;
  --toast-ok: #61C98A; --toast-danger: #F17F75; --toast-warn: #E2A84C; --toast-info: #83A9EE;
}
[data-theme="dark"] {
  --toast-bg: #E5ECE7; --toast-fg: #111814;
  --toast-ok: #17733A; --toast-danger: #B4271E; --toast-warn: #935607; --toast-info: #2455B0;
}
.toast,
.toast--success, .toast--error, .toast--warning, .toast--info {
  background: var(--toast-bg);
  color: var(--toast-fg);
  border-radius: var(--r-md);
  font-size: var(--ds-text-sm);
  font-weight: 500;
  box-shadow: var(--shadow-lg);
}
.toast--success { box-shadow: inset 3px 0 0 var(--toast-ok), var(--shadow-lg); }
.toast--error   { box-shadow: inset 3px 0 0 var(--toast-danger), var(--shadow-lg); }
.toast--warning { box-shadow: inset 3px 0 0 var(--toast-warn), var(--shadow-lg); }
.toast--info    { box-shadow: inset 3px 0 0 var(--toast-info), var(--shadow-lg); }
.toast--success .toast__ico { color: var(--toast-ok); }
.toast--error   .toast__ico { color: var(--toast-danger); }
.toast--warning .toast__ico { color: var(--toast-warn); }
.toast--info    .toast__ico { color: var(--toast-info); }
.toast__close:hover, .toast__close:focus-visible { background: color-mix(in srgb, var(--toast-fg) 14%, transparent); }


/* ── 8. Login & splash ────────────────────────────────────────────────────── */

/* The entrance. Two halves of one composition: the COURT (deck green, PBSI
   crest, a badminton half-court in fine lines, one shuttle trajectory, an
   editorial line in Instrument Serif) and the FORM. The court is the same
   colour as the app's navigation deck — on a genuine sign-in it contracts
   into it (js/components/entry-transition.js).
   Choreography is one-shot and decorative only: the form is interactive from
   the first frame and never waits for the court to finish drawing. */

.login-screen {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(400px, 1fr);
  background: var(--canvas); /* v2: the form sits on the warm ivory canvas, white fields on top */
  overflow: hidden;
}

/* 8.1 Court half */
.login-court {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 40px 48px 44px;
  background:
    radial-gradient(120% 80% at 0% 100%, rgba(14,138,69,.42), transparent 60%),
    radial-gradient(90% 60% at 100% 0%, rgba(242,216,11,.12), transparent 55%),
    var(--court);
  color: var(--court-text);
  isolation: isolate;
}
.login-court-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
}
.login-court-lines .lc-l {
  fill: none;
  stroke: rgba(220,231,224,.16);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.login-court-lines .lc-net {
  fill: none;
  stroke: rgba(220,231,224,.42);
  stroke-width: 1.5;
  stroke-dasharray: 0.004 0.009;
  vector-effect: non-scaling-stroke;
}
.login-trajectory {
  fill: none;
  stroke: var(--shuttle);
  stroke-width: 1.4;
  stroke-linecap: round;
  opacity: .85;
  vector-effect: non-scaling-stroke;
}
.login-shuttle path:first-child { fill: rgba(255,255,255,.92); }
.login-shuttle-ribs { fill: none; stroke: rgba(12,25,18,.35); stroke-width: 1; }
.login-shuttle circle { fill: #FFFFFF; stroke: var(--shuttle); stroke-width: 1.5; }

.login-court-top { display: flex; align-items: center; gap: 14px; position: relative; }
.login-screen .brand-mark--login {
  width: 52px;
  height: 52px;
  border-radius: 14px;
  border: 0;
  background: #FFFFFF;
  box-shadow: 0 0 0 1px rgba(255,255,255,.14), 0 12px 28px -12px rgba(0,0,0,.7);
}
.login-screen .brand-mark--login img { padding: 6px; }
.login-brand-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.login-brand-name {
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: #FFFFFF;
}
.login-brand-sub {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--court-muted);
}
.login-court-copy { position: relative; max-width: 560px; }
.login-headline {
  margin: 0 0 22px;
  font-family: var(--font-editorial);
  font-size: clamp(34px, 3.6vw, 54px);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -0.012em;
  color: #FFFFFF;
  text-wrap: balance;
  white-space: normal;
  overflow-wrap: anywhere;
}
.login-headline em { font-style: italic; color: var(--shuttle); }
.login-modules {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--court-muted);
}
.login-modules li { position: relative; }
.login-modules li + li::before {
  content: "";
  position: absolute;
  left: -11px;
  top: 50%;
  width: 4px;
  height: 4px;
  margin-top: -2px;
  border-radius: 50%;
  background: rgba(220,231,224,.3);
}

/* 8.2 Form half */
.login-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: auto;
  max-width: none;
  min-height: 0;
  margin: 0;
  padding: 48px clamp(28px, 6vw, 88px) 28px;
  background: var(--canvas);
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow-y: auto;
  animation: none;
}
[data-theme="dark"] .login-card { background: var(--surface); border: 0; box-shadow: none; }
.login-card-body { width: 100%; max-width: 380px; margin: auto 0; }
.login-kicker {
  margin: 0 0 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent-fg);
}
.login-title {
  margin: 0 0 8px;
  font-family: var(--font-editorial);
  font-size: 44px;
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.015em;
  color: var(--text);
}
.login-sub { margin: 0 0 28px; font-size: var(--ds-text-md); line-height: 1.55; color: var(--muted); }

.login-card .form-group { margin-bottom: 16px; }
.login-card .form-group label {
  display: block;
  margin-bottom: 6px;
  font-size: var(--ds-text-sm);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
}
/* #modalLogin: the generic form-control recipe (§5) is more specific than a
   class chain; the login's 16px (no iOS focus zoom) must win at every width. */
#modalLogin .form-group input {
  width: 100%;
  height: 48px;
  padding: 0 14px;
  font-family: var(--font-sans);
  font-size: 16px; /* ≥16px: iOS never zooms the login field */
  color: var(--text);
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: 10px;
  box-shadow: var(--shadow-xs);
  outline: none;
  transition: border-color var(--motion-fast) ease, box-shadow var(--motion-fast) ease, background-color var(--motion-fast) ease;
}
#modalLogin .form-group input:hover:not(:disabled) { border-color: var(--border-strong); }
#modalLogin .form-group input:focus { border-color: var(--accent); box-shadow: var(--focus-ring); }
#modalLogin .form-group input:disabled { opacity: .7; }
.login-card .form-group input::placeholder { color: var(--faint); }
.login-card #loginPin { letter-spacing: .3em; font-family: var(--font-mono); }
.login-card #loginPin::placeholder { letter-spacing: .2em; }
.login-card #loginPin[type="text"] { letter-spacing: .18em; }

.login-pin-wrap { position: relative; }
.login-pin-wrap input { padding-right: 52px; }
.login-pin-toggle {
  position: absolute;
  top: 2px;
  right: 2px;
  bottom: 2px;
  width: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--faint);
  cursor: pointer;
  transition: color var(--motion-fast) ease, background-color var(--motion-fast) ease;
}
.login-pin-toggle:hover { color: var(--text); background: var(--hover); }
.login-pin-toggle .lpt-hide,
.login-pin-toggle[aria-pressed="true"] .lpt-show { display: none; }
.login-pin-toggle[aria-pressed="true"] .lpt-hide { display: block; }

.login-error-v2 {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 2px 0 14px;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--danger-bg);
  color: var(--danger);
  font-size: var(--ds-text-sm);
  font-weight: 500;
  line-height: 1.45;
  animation: login-msg-in var(--motion-base, 200ms) var(--motion-ease) both;
}
.login-error-v2[hidden] { display: none; }
.login-error-v2 svg { width: 15px; height: 15px; flex-shrink: 0; margin-top: 2px; }
@keyframes login-msg-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

.login-notice {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin: -8px 0 20px;
  padding: 12px 14px;
  border-radius: 10px;
  background: var(--info-bg);
  color: var(--info);
  font-size: var(--ds-text-sm);
  line-height: 1.45;
  animation: login-msg-in var(--motion-base, 200ms) var(--motion-ease) both;
}
.login-notice[hidden] { display: none; }
.login-notice strong { display: block; font-weight: 600; }
.login-notice[data-kind="offline"] { background: var(--warn-bg); color: var(--warn); }
.login-notice svg { width: 16px; height: 16px; flex-shrink: 0; margin-top: 1px; }

.login-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  min-height: 48px;
  margin-top: 6px;
  border: 0;
  border-radius: 10px;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0;
  cursor: pointer;
  box-shadow: 0 1px 0 rgba(255,255,255,.12) inset, 0 8px 18px -10px color-mix(in srgb, var(--accent) 80%, #000);
  transition: background-color var(--motion-fast) ease, box-shadow var(--motion-fast) ease, transform 80ms ease;
}
.login-submit:hover:not(:disabled) { background: var(--accent-hover); }
.login-submit:active:not(:disabled) { transform: scale(.985); }
.login-submit-arrow { transition: transform var(--spring-snap-ms, 300ms) var(--ease-spring-snap, var(--motion-ease)); }
.login-submit:hover:not(:disabled) .login-submit-arrow { transform: translateX(3px); }
/* In progress is not disabled: the button keeps its full colour (the spinner
   and label say what is happening); only real disabled states fade. */
.login-submit[data-sf-state]:disabled { opacity: 1; }
.login-submit[data-sf-state="saving"] { background: var(--accent-hover); cursor: progress; }
.login-submit[data-sf-state="success"] { background: var(--ok); }
.login-submit[data-sf-state="success"] .sf-icon--check { color: #FFFFFF; }
.login-submit:disabled { filter: none; }

.login-net {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 18px 0 0;
  font-size: var(--ds-text-xs);
  color: var(--faint);
}
.login-net-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 0 3px var(--ok-bg); }
.login-net[data-online="false"] { color: var(--warn); }
.login-net[data-online="false"] .login-net-dot { background: var(--warn); box-shadow: 0 0 0 3px var(--warn-bg); }

.login-foot-text {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 12px;
  width: 100%;
  max-width: 380px;
  margin: 32px 0 0;
  font-size: 11.5px;
  text-align: left;
  color: var(--faint);
}
.login-foot-ver { font-family: var(--font-mono); }

/* 8.3 States */
/* Invalid credentials: one small horizontal shake of the form — physical
   feedback that the attempt was rejected (the message carries the meaning). */
.login-screen[data-state="rejected"] .login-card-body { animation: login-reject 300ms var(--ease-exit, ease) 1; }
@keyframes login-reject {
  0%, 100% { transform: none; }
  25% { transform: translateX(-5px); }
  50% { transform: translateX(4px); }
  75% { transform: translateX(-2px); }
}
.login-screen[aria-busy="true"] .login-card-body { cursor: progress; }

/* 8.4 Entrance choreography — once per page load, decorative only. */
@media (prefers-reduced-motion: no-preference) {
  html:not([data-anim="off"]) .login-screen[data-enter] .lc-l,
  html:not([data-anim="off"]) .login-screen[data-enter] .lc-net {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
    animation: lc-draw 1100ms var(--motion-ease) forwards;
  }
  html:not([data-anim="off"]) .login-screen[data-enter] .lc-net { animation: lc-fade 600ms ease 420ms both; stroke-dasharray: 0.004 0.009; stroke-dashoffset: 0; }
  html:not([data-anim="off"]) .login-screen[data-enter] .lc-l:nth-child(2) { animation-delay: 90ms; }
  html:not([data-anim="off"]) .login-screen[data-enter] .lc-l:nth-child(3) { animation-delay: 160ms; }
  html:not([data-anim="off"]) .login-screen[data-enter] .lc-l:nth-child(4) { animation-delay: 230ms; }
  html:not([data-anim="off"]) .login-screen[data-enter] .lc-l:nth-child(5) { animation-delay: 300ms; }
  html:not([data-anim="off"]) .login-screen[data-enter] .login-trajectory {
    stroke-dasharray: 1 1;
    stroke-dashoffset: 1;
    animation: lc-draw 1000ms cubic-bezier(.3,.1,.2,1) 520ms forwards;
  }
  html:not([data-anim="off"]) .login-screen[data-enter] .login-shuttle {
    opacity: 0;
    animation: lc-shuttle 420ms var(--ease-spring-snap, var(--motion-ease)) 1380ms forwards;
  }
  html:not([data-anim="off"]) .login-screen[data-enter] .login-court-top,
  html:not([data-anim="off"]) .login-screen[data-enter] .login-court-copy > * {
    animation: lc-rise 640ms var(--motion-ease) both;
  }
  html:not([data-anim="off"]) .login-screen[data-enter] .login-headline { animation-delay: 120ms; }
  html:not([data-anim="off"]) .login-screen[data-enter] .login-modules { animation-delay: 240ms; }
  /* The form is NOT delayed: a 220ms fade with no transform, inputs live. */
  html:not([data-anim="off"]) .login-screen[data-enter] .login-card-body { animation: lc-fade 220ms ease both; }
}
@keyframes lc-draw { to { stroke-dashoffset: 0; } }
@keyframes lc-shuttle { from { opacity: 0; transform: translate(596px, 210px) rotate(-8deg) scale(.6); } to { opacity: 1; transform: translate(596px, 210px) rotate(-8deg); } }
@keyframes lc-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes lc-fade { from { opacity: 0; } to { opacity: 1; } }

/* 8.5 Exit (success) — entry-transition.js drives the court's clip-path into
   the deck's footprint; these classes only stage the halves. */
.login-screen.is-leaving { background: transparent; pointer-events: none; }
.login-screen.is-leaving .login-card {
  transition: opacity 200ms var(--ease-exit, ease), transform 260ms var(--ease-exit, ease);
  opacity: 0;
  transform: translateX(12px);
}
.login-screen.is-leaving .login-court-copy,
.login-screen.is-leaving .login-court-art,
.login-screen.is-leaving .login-brand-text { transition: opacity 140ms var(--ease-exit, ease); opacity: 0; }

/* Logout: the deck widens over the workspace while the real sign-out runs
   (entry-transition.js playLogoutExitTransition), then the page reloads onto
   the same green — splash, then the login court. Decorative, inert. */
.logout-veil {
  position: fixed;
  inset: 0;
  z-index: 99990;
  pointer-events: none;
  background: var(--court);
}

/* 8.6 Responsive — stacked below 960px: a court BAND above the form. */
@media (max-width: 959px) {
  .login-screen {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .login-court {
    min-height: 0;
    padding: max(20px, env(safe-area-inset-top)) 24px 28px;
    gap: 22px;
  }
  .login-court-copy { max-width: 520px; }
  .login-headline { font-size: clamp(26px, 6.4vw, 36px); margin-bottom: 0; }
  .login-modules { display: none; }
  .login-card {
    justify-content: flex-start;
    padding: 28px 24px max(24px, env(safe-area-inset-bottom));
    overflow: visible;
  }
  .login-card-body { margin: 0 auto; }
  .login-foot-text { margin: 28px auto 0; }
  .login-title { font-size: 34px; }
  .login-sub { margin-bottom: 22px; }
}
@media (max-width: 959px) and (max-height: 620px), (max-width: 380px) {
  /* Short landscape phones / narrow phones (and an open virtual keyboard
     shrinks the visual viewport, not this layout): the band keeps only the
     identity row so the form stays near the top. */
  .login-court-copy { display: none; }
  .login-court { padding-bottom: 18px; }
}
@media (max-width: 380px) {
  .login-card { padding-left: 16px; padding-right: 16px; }
  .login-court { padding-left: 16px; padding-right: 16px; }
  .login-title { font-size: 30px; }
  .login-screen .brand-mark--login { width: 44px; height: 44px; }
  .login-brand-sub { letter-spacing: .03em; }
}

/* 8.7 Splash — the same deck green as the login court and the app's deck,
   so cold start → login → workspace is one continuous surface. */
#app-splash,
[data-theme="dark"] #app-splash {
  background:
    radial-gradient(120% 80% at 0% 100%, rgba(14,138,69,.28), transparent 60%),
    var(--court);
}
.app-splash-inner { gap: 6px; }
#app-splash .brand-mark--splash {
  width: 72px;
  height: 72px;
  border-radius: 18px;
  border: 0;
  background: #FFFFFF;
  box-shadow: 0 0 0 1px rgba(255,255,255,.14), 0 16px 36px -14px rgba(0,0,0,.8);
}
.app-splash-name {
  margin-top: 12px;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: #FFFFFF;
}
.app-splash-sub {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .08em;
  color: var(--court-muted);
}
/* A real pending state (app bootstrap), so an indeterminate bar is honest.
   It only appears if loading takes longer than ~380ms. */
.app-splash-progress {
  position: relative;
  display: block;
  width: 120px;
  height: 2px;
  margin-top: 22px;
  overflow: hidden;
  border-radius: 2px;
  background: rgba(220,231,224,.12);
  opacity: 0;
  animation: startup-spinner-in 160ms ease 380ms forwards;
}
.app-splash-progress span {
  position: absolute;
  inset: 0 auto 0 0;
  width: 40%;
  border-radius: 2px;
  background: var(--shuttle);
  animation: splash-rally 1.1s cubic-bezier(.45,0,.55,1) infinite alternate;
}
@keyframes splash-rally { from { transform: translateX(-20%); } to { transform: translateX(170%); } }
.app-splash-status {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--court-muted);
  opacity: 0;
  animation: startup-spinner-in 160ms ease 380ms forwards;
}
@media (prefers-reduced-motion: reduce) {
  .app-splash-progress span { animation: none; width: 100%; opacity: .5; }
  .app-splash-progress, .app-splash-status { animation: none; opacity: 1; }
}
html[data-anim="off"] .app-splash-progress span { animation: none; width: 100%; opacity: .5; }

.brand-mark { border-color: var(--border); }


/* ── 9. Module refinements ────────────────────────────────────────────────── */

/* ── 9.4 Overtime → Karyawan rows (UX audit #4) ─────────────────────────── */
/* The unit / employee name takes the free space; on phones the row wraps so
   the name gets the WHOLE first line and the status pill + actions move to a
   right-aligned second line (long unit names used to wrap one word per line
   beside full-width buttons). The inline 40px indent (reorder arrows) needs
   !important to relax on phones; scoped to this media query only. */
.ot-emp-name, .ot-unit-name { flex: 1 1 0; min-width: 0; }
@media (max-width: 600px) {
  .ot-emp-row { flex-wrap: wrap; row-gap: 8px; padding-left: 16px !important; }
  .ot-emp-name { flex-basis: calc(100% - 44px); }
  .ot-emp-status { margin-left: auto; }
  .ot-unit-head { flex-wrap: wrap; row-gap: 8px; }
  .ot-unit-name { flex-basis: calc(100% - 30px); }
  .ot-unit-count { margin-left: auto; }
}

/* ── 9.3 Insights — narrative verdicts (product reimagining) ────────────── */
/* Every analysis opens with a sentence ("Operasi perlu perhatian."). It
   speaks in the same editorial voice as the Today briefing, so a verdict
   reads the same wherever it appears; figures stay in Plex. */
.v2-analytics-claude .level.hero .hero-title,
.v2-analytics-claude .exa-hero__verdict {
  font-family: var(--font-editorial);
  font-size: clamp(30px, 3.1vw, 44px);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -0.015em;
}
.v2-analytics-claude .level.hero .hero-title .hl { font-style: italic; }
.v2-analytics-claude .level > .eyebrow h2,
.v2-analytics-claude .v2-analytics-section-header { letter-spacing: -0.005em; }

/* ── 9.2 Roles & people (product reimagining) ───────────────────────────── */
/* A role is an identity, not a status. Roles used the status palette (admin =
   danger red, driver = warning amber, viewer = success green), so every admin
   avatar read as an error. Roles now have their own tones: admin sits on the
   deck (shuttle yellow on court green — authority), bidang is blue, driver is
   PBSI green, viewer is neutral. Status pills keep the status palette. */
:root {
  --role-admin-bg: #0B4A2B;  --role-admin-fg: #F2D80B;
  --role-bidang-bg: var(--info-bg);   --role-bidang-fg: var(--info);
  --role-driver-bg: var(--brand-subtle); --role-driver-fg: var(--accent-fg);
  --role-viewer-bg: var(--surface-3); --role-viewer-fg: var(--muted);
}
[data-theme="dark"] { --role-admin-bg: #17301F; --role-admin-fg: #F2D80B; }
.v2-role-pill--admin, .role-badge[data-role="admin"], .profile-role-chip[data-role="admin"] { background: var(--role-admin-bg); color: var(--role-admin-fg); border-color: transparent; }
.v2-role-pill--bidang, .role-badge[data-role="bidang"], .profile-role-chip[data-role="bidang"] { background: var(--role-bidang-bg); color: var(--role-bidang-fg); border-color: transparent; }
.v2-role-pill--driver, .role-badge[data-role="driver"], .profile-role-chip[data-role="driver"] { background: var(--role-driver-bg); color: var(--role-driver-fg); border-color: transparent; }
.v2-role-pill--viewer, .role-badge[data-role="viewer"], .profile-role-chip[data-role="viewer"] { background: var(--role-viewer-bg); color: var(--role-viewer-fg); border-color: transparent; }
.v2-user-role-pill {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  border-radius: var(--r-xs);
  padding: 3px 7px;
}
.v2-user-avatar--admin  { background: var(--role-admin-bg);  border-color: var(--role-admin-bg);  color: var(--role-admin-fg); }
.v2-user-avatar--bidang { background: var(--role-bidang-bg); border-color: transparent; color: var(--role-bidang-fg); }
.v2-user-avatar--driver { background: var(--role-driver-bg); border-color: transparent; color: var(--role-driver-fg); }
.v2-user-avatar--viewer { background: var(--role-viewer-bg); border-color: transparent; color: var(--role-viewer-fg); }

/* People rows: ONE visible action (Edit / Lihat); lifecycle actions are quiet
   text buttons that only take colour on intent — the destructive ones in the
   danger tone. Same buttons, same hooks, same confirmations. */
.v2-user-card { border-radius: var(--r-lg); border-color: var(--border); box-shadow: none; transition: border-color var(--motion-fast) ease, background-color var(--motion-fast) ease; }
/* People lists (v2) — one surface per list, people as hairline rows (were a
   stack of separate rounded cards). Role groups keep their disclosure
   header as the surface's first row. Same markup, buttons and hooks. */
.user-role-group {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow: hidden;
  margin-bottom: 12px;
}
.user-role-group > .user-role-header {
  width: 100%;
  border: 0;
  border-radius: 0;
  background: var(--surface-2);
  padding: 10px 16px;
}
.user-role-body > .v2-user-card,
#v2AdminDriverList > .v2-user-card {
  margin: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  border-top: 1px solid var(--border);
  background: transparent;
}
#v2AdminDriverList {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow: hidden;
  gap: 0;
}
#v2AdminDriverList > .v2-user-card:first-child { border-top: 0; }
@media (hover: hover) and (pointer: fine) {
  .user-role-body > .v2-user-card:hover,
  #v2AdminDriverList > .v2-user-card:hover { background: var(--hover); border-color: var(--border); }
}
.user-role-body > .user-role-empty { padding: 14px 16px; border-top: 1px solid var(--border); }
.v2-user-card:hover { border-color: var(--border-strong); }
body .v2-user-btn--toggle, body .v2-user-btn--archive {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  color: var(--muted);
}
body .v2-user-btn--toggle:hover, body .v2-user-btn--archive:hover,
body .v2-user-btn--toggle:focus-visible, body .v2-user-btn--archive:focus-visible {
  background: var(--danger-bg);
  border-color: transparent;
  color: var(--danger);
}

/* ── 9.1 Board — lanes on a bright court (reimagining v2) ──────────────── */
/* The Board is a schedule you READ, then act on. v2 composition:
     header   — eyebrow · a serif sentence that says the shown day (bentrok /
                tanpa driver called out) · the live "Sekarang" score line
                (the four KPI tiles, same ids, now one line)
     lanes    — one lane per driver, alternating a faint court tint; trips are
                WHITE cards with a vehicle stripe (--v, set by timeline.js);
                STATUS owns the surface: running = green tint, done = quiet,
                conflict = coral outline + net hatch, no driver = dashed
     now      — the green now-line with a shuttle-yellow ball on the top lane
     Urutan   — the list view as an order of play (hour in the gutter, a
                "Sekarang" rule) — renderListView()
   Everything is anchored on #v2TimelineSurface so it outranks the eleven
   legacy passes in style.css/platform.css without !important. Geometry the
   engine measures (--hour-width, block left/width) is untouched. */

/* A driver's full name must be readable on the lane (long Balinese/Javanese
   names were cut to "I Gust…"): the column grows on tablets/desktops. The
   engine reads --driver-col from :root for its scroll maths (timeline.js
   _driverColPx), so it is set there, never on the surface. */
@media (min-width: 768px) { :root { --driver-col: 148px; } }
@media (min-width: 1200px) { :root { --driver-col: 176px; } }

#v2TimelineSurface {
  --lane-tint: color-mix(in srgb, var(--accent) 3.5%, var(--surface));
  --row-height: 70px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: none;
}

/* Header */
body.v2-shell-active #v2TimelineSurface .v2-tl-header {
  align-items: flex-start;
  gap: 16px;
  padding: 20px 22px 14px;
  border-bottom: 0;
  background: transparent;
}
#v2TimelineSurface .v2-tl-header-left { display: flex; flex-direction: column; gap: 6px; min-width: 0; flex: 1 1 auto; white-space: normal; }
#v2TimelineSurface .v2-tl-eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}
#v2TimelineSurface .v2-tl-eyebrow::before { content: ""; width: 18px; height: 2px; background: var(--accent); flex: none; }
body.v2-shell-active #v2TimelineSurface .v2-tl-title { font: inherit; color: var(--muted); letter-spacing: inherit; }
body.v2-shell-active #v2TimelineSurface .v2-tl-sub { font: inherit; color: var(--faint); letter-spacing: .04em; }
#v2TimelineSurface .v2-tl-sub::before { content: "· jam kerja · "; }
body.v2-shell-active #v2TimelineSurface .v2-tl-title { text-transform: uppercase; }
/* The shown day is said by the headline (and the topbar date control); the
   engine-owned #timelineDateLabel stays in the DOM, visually hidden. */
body.v2-shell-active #v2TimelineSurface .v2-tl-header-right .timeline-date-label {
  position: absolute !important;
  width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.v2-board-headline {
  margin: 2px 0 0;
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: clamp(26px, 2.5vw, 34px);
  line-height: 1.04;
  letter-spacing: -0.01em;
  color: var(--text);
  text-wrap: balance;
}
.v2-board-headline:empty { display: none; }
.v2-board-headline em { font-style: italic; color: var(--accent-fg); }
.v2-board-headline-flag { color: var(--danger); }
.v2-board-headline-note {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  vertical-align: middle;
  color: var(--faint);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  padding: 2px 8px;
}

/* "Sekarang" score line — the former KPI tiles */
body.v2-shell-active #v2KpiStrip {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 0;
  margin: 2px 0 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  grid-template-columns: none;
}
#v2KpiStrip .v2-kpi-lead {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-right: 12px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent-fg);
}
#v2KpiStrip .v2-kpi-lead::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--shuttle);
  box-shadow: 0 0 0 1.5px var(--accent);
}
body.v2-shell-active #v2KpiStrip .v2-kpi-card {
  display: inline-flex;
  flex-direction: row;
  flex: none;
  width: auto;
  min-width: 0;
  align-items: baseline;
  gap: 5px;
  min-height: 0;
  margin: 0 12px 0 0;
  padding: 0 12px 0 0;
  border: 0;
  border-right: 1px solid var(--border);
  border-radius: 0;
  background: none;
  box-shadow: none;
  transform: none;
}
body.v2-shell-active #v2KpiStrip .v2-kpi-card:last-child { border-right: 0; }
body.v2-shell-active #v2KpiStrip .v2-kpi-value {
  order: 0;
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
}
body.v2-shell-active #v2KpiStrip .v2-kpi-label {
  order: 1;
  font-family: var(--font-sans);
  font-size: var(--ds-text-sm);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}
#v2KpiStrip .v2-kpi-label::after { content: none !important; } /* the phone short-label swap (platform.css) does not apply to the score line */
body.v2-shell-active #v2KpiStrip .v2-kpi-card::before,
body.v2-shell-active #v2KpiStrip .v2-kpi-card::after,
body.v2-shell-active #v2KpiStrip .v2-kpi-icon,
body.v2-shell-active #v2KpiStrip .v2-kpi-sub { display: none; }
#v2DashHeader { display: none !important; } /* its "Operasional" label moved into the header eyebrow */

body.v2-shell-active #v2TimelineSurface .v2-tl-header-right { min-width: 0; align-items: center; gap: 10px; }

/* Filters */
body.v2-shell-active #v2TimelineSurface .v2-filter-bar { padding: 0 22px 14px; gap: 8px; border-bottom: 1px solid var(--border); background: transparent; }

/* Hour ruler */
#v2TimelineSurface .timeline-header-row { background: var(--surface-2); border-bottom: 1px solid var(--border); }
#v2TimelineSurface .timeline-corner {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .1em;
  color: var(--faint);
  background: var(--surface-2);
}
#v2TimelineSurface .hour-cell { font-size: 11px; color: var(--faint); border-right-color: var(--grid); }
#v2TimelineSurface .hour-cell.hour-shaded { background: color-mix(in srgb, var(--text) 2.5%, transparent); }
#v2TimelineSurface .hour-cell.hour-current { background: var(--accent-subtle); color: var(--accent-fg); font-weight: 600; }

/* Lanes */
#v2TimelineSurface .driver-row:nth-child(even) .driver-slots { background-color: var(--lane-tint); }
#v2TimelineSurface .driver-row { border-bottom-color: var(--border); }
body.v2-shell-active #v2TimelineSurface .driver-label { background: var(--surface); border-right: 1px solid var(--border); padding: 6px 12px; }
#v2TimelineSurface .driver-row:nth-child(even) .driver-label { background: var(--lane-tint); }
body.v2-shell-active #v2TimelineSurface .driver-label::before {
  background: var(--brand-subtle);
  color: var(--accent-fg);
  box-shadow: none;
  font-weight: 600;
}
body.v2-shell-active #v2TimelineSurface .driver-label .driver-name {
  font-size: var(--ds-text-sm);
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
  white-space: normal;
  overflow: hidden;
  text-overflow: clip;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow-wrap: anywhere;
}
body.v2-shell-active #v2TimelineSurface .driver-label .driver-phone { font-family: var(--font-mono); font-size: 10px; color: var(--faint); }
body.v2-shell-active #v2TimelineSurface .driver-label--unassigned,
#v2TimelineSurface .driver-row--unassigned .driver-slots { background: var(--danger-bg); }
body.v2-shell-active #v2TimelineSurface .driver-label--unassigned .driver-name,
body.v2-shell-active #v2TimelineSurface .driver-label--unassigned .driver-lane-count { color: var(--danger); }
#v2TimelineSurface .empty-slots-hint { color: var(--faint); font-size: 11.5px; }

/* Now — the green line; on the top lane it carries the shuttle */
#v2TimelineSurface .today-line { background: var(--accent); opacity: 1; width: 2px; }
#v2TimelineSurface .driver-row:first-child .today-line::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 50%;
  width: 10px;
  height: 10px;
  margin-left: -5px;
  border-radius: 50%;
  background: var(--shuttle);
  box-shadow: 0 0 0 2px var(--accent);
}

/* Trips — white cards, a vehicle stripe, status owns the surface */
body.v2-shell-active #v2TimelineSurface .assignment-block,
#v2TimelineSurface .assignment-block {
  top: 8px;
  height: calc(var(--row-height) - 16px);
  padding: 6px 10px 5px 13px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-auto-rows: min-content;
  align-content: start;
  row-gap: 1px;
  overflow: clip;
  color: var(--text);
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--v, var(--border-strong)) 32%, var(--border));
  border-radius: 10px;
  box-shadow: inset 4px 0 0 var(--v, var(--border-strong)), 0 1px 2px rgba(40, 36, 20, .06);
  filter: none;
  opacity: 1;
  transition: box-shadow var(--motion-fast, 140ms) ease, border-color var(--motion-fast, 140ms) ease, background-color var(--motion-fast, 140ms) ease;
}
@media (hover: hover) and (pointer: fine) {
  #v2TimelineSurface .assignment-block:hover {
    filter: none;
    border-color: color-mix(in srgb, var(--v, var(--border-strong)) 60%, var(--border));
    box-shadow: inset 4px 0 0 var(--v, var(--border-strong)), 0 6px 16px -8px rgba(40, 36, 20, .35);
  }
}
/* Line 3 is the state when there is one (badges, in words), else the
   vehicle · destination line — the state must survive a narrow block. */
#v2TimelineSurface .assignment-block > .block-meta-row + .block-sub { display: none; }
#v2TimelineSurface .assignment-block > .block-time,
#v2TimelineSurface .assignment-block > .block-purpose,
#v2TimelineSurface .assignment-block > .block-meta-row,
#v2TimelineSurface .assignment-block > .block-sub {
  position: sticky;
  left: calc(var(--driver-col, 110px) + 8px);
  align-self: flex-start;
  width: max-content;
  max-width: max(0px, calc(100% - var(--blk-hidden, 0px)));
  min-width: 0;
}
body.v2-shell-active #v2TimelineSurface .block-time {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--muted);
  opacity: 1;
}
body.v2-shell-active #v2TimelineSurface .assignment-block > .block-purpose {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--text);
}
#v2TimelineSurface .block-sub {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11px;
  line-height: 1.3;
  color: var(--faint);
}
#v2TimelineSurface .block-meta-row { display: flex; gap: 4px; align-items: center; min-width: 0; overflow: hidden; }
body.v2-shell-active #v2TimelineSurface .block-status-badge {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--surface-3);
  color: var(--muted);
  border: 0;
}
body.v2-shell-active #v2TimelineSurface .block-status-badge--started { background: var(--accent); color: var(--on-accent); }
body.v2-shell-active #v2TimelineSurface .block-status-badge--conflict { background: var(--danger-bg); color: var(--danger); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--danger) 40%, transparent); }
body.v2-shell-active #v2TimelineSurface .block-status-badge--unassigned { background: var(--warn-bg); color: var(--warn); }
body.v2-shell-active #v2TimelineSurface .block-status-badge--overtime { background: var(--info-bg); color: var(--info); }
#v2TimelineSurface .block-meta-separator { display: none; }
#v2TimelineSurface .block-vehicle-shape { top: auto; bottom: 6px; left: auto; right: 8px; width: 7px; height: 7px; background: var(--v); opacity: .9; }
#v2TimelineSurface .block-convoy-mark { color: var(--muted); right: 20px; bottom: 5px; }
#v2TimelineSurface .block-conflict-dot { background: var(--danger); border-color: var(--surface); }

/* Status */
body.v2-shell-active #v2TimelineSurface .assignment-block.is-started {
  outline: 0;
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
}
body.v2-shell-active #v2TimelineSurface .assignment-block.is-started .block-time { color: var(--accent-fg); }
body.v2-shell-active #v2TimelineSurface .assignment-block.is-completed,
body.v2-shell-active #v2TimelineSurface .assignment-block.is-completed:hover {
  opacity: 1;
  filter: none;
  background: var(--surface-2);
  border-color: var(--border);
  box-shadow: inset 4px 0 0 color-mix(in srgb, var(--v, var(--border-strong)) 45%, var(--surface-2));
}
body.v2-shell-active #v2TimelineSurface .assignment-block.is-completed > .block-purpose { font-weight: 500; color: var(--muted); }
body.v2-shell-active #v2TimelineSurface .assignment-block.is-conflict {
  border: 1.5px solid var(--danger);
  background-color: var(--surface);
  background-image: repeating-linear-gradient(135deg, color-mix(in srgb, var(--danger-bg) 80%, transparent) 0 5px, transparent 5px 11px);
}
body.v2-shell-active #v2TimelineSurface .assignment-block.is-unassigned { border: 1.5px dashed var(--warn); }
body.v2-shell-active #v2TimelineSurface .assignment-block.is-cancelled { opacity: .55; }
body.v2-shell-active #v2TimelineSurface .assignment-block.is-cancelled > .block-purpose { text-decoration: line-through; }
#v2TimelineSurface .assignment-block.continues-next-day { border-right: 2px dashed var(--border-strong); }
#v2TimelineSurface .assignment-block.continues-prev-day { border-left: 2px dashed var(--border-strong); }
#v2TimelineSurface .assignment-block.continues-next-day::after,
#v2TimelineSurface .assignment-block.continues-prev-day::before { color: var(--faint); }
#v2TimelineSurface .assignment-block:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#v2TimelineSurface .resize-handle { opacity: 0; }
@media (hover: hover) and (pointer: fine) {
  #v2TimelineSurface .assignment-block:hover .resize-handle { opacity: .6; }
}

/* Legend */
body.v2-shell-active #v2TimelineSurface .legend { padding: 12px 22px; background: transparent; border-top: 1px solid var(--border); }

/* Urutan — the order of play */
body.v2-shell-active #v2ListView { padding: 6px 22px 22px; gap: 0; }
#v2ListView .v2-oop-hour {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  border-top: 1px solid var(--border);
  padding: 6px 0;
}
#v2ListView .v2-oop-hour:first-child { border-top: 0; }
#v2ListView .v2-oop-hour-num {
  font-family: var(--font-editorial);
  font-size: 34px;
  line-height: 1;
  padding-top: 8px;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}
#v2ListView .v2-oop-hour-num small { font-family: var(--font-mono); font-size: 10px; letter-spacing: .08em; text-transform: uppercase; }
#v2ListView .v2-oop-hour-rows { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
body.v2-shell-active #v2ListView .v2-list-card {
  position: relative;
  display: grid;
  grid-template-columns: 104px minmax(0, 1fr) auto;
  align-items: center;
  gap: 4px 14px;
  padding: 10px 12px 10px 16px;
  margin: 0;
  border: 0;
  border-radius: var(--r-lg);
  background: transparent;
  box-shadow: none;
  transition: background-color var(--motion-fast, 140ms) ease;
}
#v2ListView .v2-list-card::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 12px;
  bottom: 12px;
  width: 3px;
  border-radius: 2px;
  background: var(--v);
}
@media (hover: hover) and (pointer: fine) { #v2ListView .v2-list-card:hover { background: var(--hover); } }
#v2ListView .v2-list-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
#v2ListView .v2-list-card-time { font-family: var(--font-mono); font-size: 12px; font-weight: 500; color: var(--muted); white-space: nowrap; }
#v2ListView .v2-list-card-title {
  font-size: var(--ds-text-md);
  font-weight: 600;
  color: var(--text);
  line-height: 1.35;
  white-space: normal;
  overflow: hidden;
  text-overflow: clip;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow-wrap: anywhere;
}
#v2ListView .v2-list-card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 12px; margin-top: 2px; font-size: 12.5px; color: var(--muted); }
#v2ListView .v2-list-vehicle-chip { display: inline-flex; align-items: center; gap: 6px; padding: 0; border: 0; background: none; color: var(--muted); font-size: 12.5px; }
#v2ListView .v2-list-vehicle-dot { width: 8px; height: 8px; }
#v2ListView .v2-list-card-dest::before { content: "→ "; color: var(--faint); }
#v2ListView .v2-list-card-status { display: flex; gap: 6px; align-items: center; justify-self: end; }
#v2ListView .v2-list-status-pill {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: var(--r-full);
  border: 0;
  background: var(--surface-3);
  color: var(--muted);
}
#v2ListView .v2-list-status-pill--started { background: var(--accent); color: var(--on-accent); }
#v2ListView .v2-list-status-pill--completed { background: var(--ok-bg); color: var(--ok); }
#v2ListView .v2-list-flag {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: var(--r-full);
}
#v2ListView .v2-list-flag--conflict { background: var(--danger-bg); color: var(--danger); }
#v2ListView .v2-list-flag--unassigned { background: var(--warn-bg); color: var(--warn); }
body.v2-shell-active #v2ListView .v2-list-card--started { background: color-mix(in srgb, var(--accent) 7%, transparent); }
body.v2-shell-active #v2ListView .v2-list-card--completed .v2-list-card-title { color: var(--muted); font-weight: 500; }
#v2ListView .v2-list-card.is-conflict::before { background: repeating-linear-gradient(180deg, var(--danger) 0 4px, transparent 4px 7px); }
#v2ListView .v2-list-card.is-unassigned .v2-list-card-driver { color: var(--warn); font-weight: 600; }
#v2ListView .v2-oop-now {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 6px 56px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--accent-fg);
}
#v2ListView .v2-oop-now::before { content: ""; width: 9px; height: 9px; border-radius: 50%; background: var(--shuttle); box-shadow: 0 0 0 2px var(--accent); flex: none; }
#v2ListView .v2-oop-now::after { content: ""; flex: 1; height: 2px; background: var(--accent); border-radius: 1px; }

/* Board header on narrower screens */
@media (max-width: 900px) {
  body.v2-shell-active #v2TimelineSurface .v2-tl-header { flex-wrap: wrap; row-gap: 12px; }
  body.v2-shell-active #v2TimelineSurface .v2-tl-header-right { flex-basis: 100%; margin-left: 0; }
}
@media (max-width: 600px) {
  #v2TimelineSurface { --row-height: 62px; border-radius: var(--r-lg); }
  #v2TimelineSurface .v2-tl-header-left { flex-basis: 100%; width: 100%; }
  body.v2-shell-active #v2KpiStrip { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2px 12px; }
  #v2KpiStrip .v2-kpi-lead { grid-column: 1 / -1; margin-bottom: 2px; }
  body.v2-shell-active #v2KpiStrip .v2-kpi-card { margin: 0; padding: 0; border-right: 0; }
  body.v2-shell-active #v2KpiStrip .v2-kpi-label { font-size: var(--ds-text-xs); white-space: normal; overflow: visible; text-overflow: clip; }
  body.v2-shell-active #v2TimelineSurface .v2-tl-header { padding: 16px 14px 12px; }
  body.v2-shell-active #v2TimelineSurface .v2-tl-header-right { justify-content: space-between; gap: 8px; }
  .v2-board-headline { font-size: 26px; }
  #v2TimelineSurface .v2-tl-sub { display: none; }
  body.v2-shell-active #v2KpiStrip .v2-kpi-card { margin-right: 8px; padding-right: 8px; }
  body.v2-shell-active #v2TimelineSurface .v2-filter-bar {
    padding: 0 14px 12px;
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    scroll-padding-inline: 14px;
  }
  body.v2-shell-active #v2TimelineSurface .v2-filter-bar::-webkit-scrollbar { display: none; }
  body.v2-shell-active #v2TimelineSurface .v2-filter-bar .v2-filter-chip { flex: none; width: auto; min-width: 0; max-width: 180px; } /* a native select sizes to its LONGEST option (a long driver name) */
  body.v2-shell-active #v2ListView { padding: 4px 10px 16px; }
  #v2ListView .v2-oop-hour { grid-template-columns: 38px minmax(0, 1fr); }
  #v2ListView .v2-oop-hour-num { font-size: 26px; }
  #v2ListView .v2-oop-now { margin-left: 38px; }
  body.v2-shell-active #v2ListView .v2-list-card { grid-template-columns: minmax(0, 1fr); padding: 10px 8px 10px 14px; }
  #v2ListView .v2-list-card-status { justify-self: start; flex-wrap: wrap; }
  #v2TimelineSurface .block-sub { display: none; }
}
@media (max-width: 360px) {
  .v2-board-headline { font-size: 22px; }
  body.v2-shell-active #v2TimelineSurface .v2-tl-header { padding: 14px 12px 10px; row-gap: 10px; }
}

/* ── 9.0 Today — the briefing (product reimagining) ─────────────────────── */
/* Today is editorial: one masthead that SAYS the situation (serif verdict,
   readiness gauge, today's figures), then the bands that need a decision,
   then the detail; the full Agenda & To-Do tool follows the briefing.
   Scoped by host id (#v2HomeWorkspace / #v2AgendaWorkspace) because the
   workspace stylesheet is injected by JS after this file (workspace-
   styles.js) — an id outranks it without !important. */

/* The topbar already titles the screen; the workspace's own header stays for
   assistive tech only (no second visual title). */
/* Role workspaces without a hero (driver, bidang, engineering): the header IS
   the masthead — same editorial voice as the executive verdict. */
#v2HomeWorkspace .wsp-header { gap: 6px; margin: 4px 0 8px; padding-bottom: 22px; border-bottom: 1px solid var(--border); }
#v2HomeWorkspace .wsp-eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--faint);
}
#v2HomeWorkspace .wsp-title {
  margin: 0;
  font-family: var(--font-editorial);
  font-size: clamp(30px, 3.2vw, 44px);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -0.015em;
  color: var(--text);
}
#v2HomeWorkspace .wsp-subtitle { margin: 0; font-size: 15px; color: var(--muted); }
#v2HomeWorkspace .wsp-root--zoned .wsp-header {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  padding: 0;
  border: 0;
}

/* Masthead */
#v2HomeWorkspace .wsp-hero {
  background: transparent;
  border: 0;
  border-radius: 0;
  border-bottom: 1px solid var(--border);
  padding: 8px 0 28px;
  text-align: left;
  gap: 18px 40px;
  overflow: visible;
}
#v2HomeWorkspace .wsp-hero__eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--faint);
}
#v2HomeWorkspace .wsp-hero__headline {
  font-family: var(--font-editorial);
  font-size: clamp(32px, 3.5vw, 50px);
  font-weight: 400;
  line-height: 1.04;
  letter-spacing: -0.015em;
  max-width: 20ch;
  color: var(--text);
  text-wrap: balance;
}
#v2HomeWorkspace .wsp-hero__hl { font-style: italic; }
#v2HomeWorkspace .wsp-hero__insight {
  margin: 4px 0 0;
  max-width: 62ch;
  font-size: 15px;
  line-height: 1.55;
  color: var(--muted);
}
#v2HomeWorkspace .wsp-hero__health { align-items: flex-start; }
#v2HomeWorkspace .wsp-hero__healthmeta { align-items: flex-start; }
#v2HomeWorkspace .wsp-hero__panel-label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--faint);
}
#v2HomeWorkspace .wsp-hero__scoreval { font-family: var(--font-sans); font-size: 30px; font-weight: 600; }

/* Today's figures: a quiet row of numbers divided by hairlines — the numbers
   carry the weight, not chip chrome. */
#v2HomeWorkspace .wsp-hero__stats { gap: 0; padding: 0; align-items: stretch; }
#v2HomeWorkspace .wsp-hero__stats-label { display: none; }
#v2HomeWorkspace .wsp-hero__stat {
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 2px 22px 2px 0;
  margin-right: 22px;
  background: transparent;
  border: 0;
  border-right: 1px solid var(--border);
  border-radius: 0;
}
#v2HomeWorkspace .wsp-hero__stat:last-child { border-right: 0; margin-right: 0; }
#v2HomeWorkspace .wsp-hero__stat-icon { display: none; }
#v2HomeWorkspace .wsp-hero__stat-big { font-family: var(--font-sans); font-size: 26px; font-weight: 600; line-height: 1.1; letter-spacing: -0.02em; }
#v2HomeWorkspace .wsp-hero__stat-lbl { font-size: var(--ds-text-xs); font-weight: 500; color: var(--muted); }

@media (min-width: 1100px) {
  #v2HomeWorkspace .wsp-hero {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "eyebrow health"
      "verdict health"
      "stats   health"
      "domains domains"
      "pulse   pulse"
      "details details";
    align-items: start;
  }
  #v2HomeWorkspace .wsp-hero__health {
    flex-direction: column;
    align-items: center;
    padding: 8px 8px 0 32px;
    border-left: 1px solid var(--border);
  }
  #v2HomeWorkspace .wsp-hero__healthmeta { align-items: center; }
  #v2HomeWorkspace .wsp-hero__gwrap svg { width: 152px; height: 152px; }
  #v2HomeWorkspace .wsp-hero__stats { padding-top: 6px; padding-left: 0; }
}
@media (min-width: 768px) and (max-width: 1099px) {
  #v2HomeWorkspace .wsp-hero__stats { padding-left: 0; }
}
@media (max-width: 767px) {
  #v2HomeWorkspace .wsp-hero { padding: 4px 0 22px; gap: 16px; }
  #v2HomeWorkspace .wsp-hero__health { flex-direction: row; align-items: center; gap: 16px; }
  #v2HomeWorkspace .wsp-hero__gwrap svg { width: 96px; height: 96px; }
  #v2HomeWorkspace .wsp-hero__scoreval { font-size: 22px; }
  #v2HomeWorkspace .wsp-hero__stats { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 0; }
  #v2HomeWorkspace .wsp-hero__stat { margin-right: 0; padding-right: 12px; }
  #v2HomeWorkspace .wsp-hero__stat:nth-child(odd) { border-right: 0; }
}

/* Bands — a short court line leads every band's eyebrow: the briefing reads
   as a sequence of named sections, not a wall of cards. */
#v2HomeWorkspace .wsp-zone__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}
#v2HomeWorkspace .wsp-zone__eyebrow::before {
  content: "";
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
}
/* Block and card titles are HEADINGS (sans), under the band's mono eyebrow. */
#v2HomeWorkspace .wsp-block__head .wsp-block__title,
#v2HomeWorkspace .wsp-card__title {
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.005em;
  text-transform: none;
  color: var(--text);
}
/* Bands whose single block repeats the band name word for word: the eyebrow
   names it once (the section keeps its aria-label). */
#v2HomeWorkspace [data-zone-id="agenda"] .wsp-block__head,
#v2HomeWorkspace [data-zone-id="outlook"] .wsp-block__head { display: none; }
#v2HomeWorkspace .wsp-zone__heading {
  font-family: var(--font-sans);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* ── 9.0b Today v2 — the order of play beside the briefing ──────────────── */
/* "Urutan Hari Ini" (exec-today-order) is the day as a programme sheet: a
   white panel to the right of Sekarang + Keputusan on desktop, a full-width
   band under them on tablets, right after Sekarang on phones (DOM order).
   The zone grid is workspace-styles.js's 12 columns; rows are placed
   explicitly here so the panel spans both left-hand bands. */
@media (min-width: 1100px) {
  #v2HomeWorkspace .wsp-zone[data-zone-id="now"] { grid-column: 1 / span 7; grid-row: 2; }
  #v2HomeWorkspace .wsp-zone[data-zone-id="decisions"] { grid-column: 1 / span 7; grid-row: 3; }
  #v2HomeWorkspace .wsp-zone[data-zone-id="order"] { grid-column: 8 / span 5; grid-row: 2 / span 2; }
}
/* Wide desktops: the programme sheet rises beside the masthead itself, so
   the day's order is visible without scrolling past the verdict. */
@media (min-width: 1280px) {
  #v2HomeWorkspace .wsp-zone[data-zone-id="masthead"] { grid-column: 1 / span 8; grid-row: 1; }
  #v2HomeWorkspace .wsp-zone[data-zone-id="now"] { grid-column: 1 / span 8; grid-row: 2; }
  #v2HomeWorkspace .wsp-zone[data-zone-id="decisions"] { grid-column: 1 / span 8; grid-row: 3; }
  #v2HomeWorkspace .wsp-zone[data-zone-id="order"] { grid-column: 9 / span 4; grid-row: 1 / span 3; }
}
@media (min-width: 601px) and (max-width: 1099px) {
  #v2HomeWorkspace .wsp-zone[data-zone-id="now"] { grid-column: 1 / span 6; grid-row: 2; }
  #v2HomeWorkspace .wsp-zone[data-zone-id="decisions"] { grid-column: 7 / span 6; grid-row: 2; }
  #v2HomeWorkspace .wsp-zone[data-zone-id="order"] { grid-column: 1 / span 12; grid-row: 3; }
}
#v2HomeWorkspace .wsp-zone[data-zone-id="order"] {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: 18px 18px 14px;
  gap: 10px;
}
#v2HomeWorkspace [data-zone-id="order"] .wsp-block__head { display: none; }
#v2HomeWorkspace [data-zone-id="order"] .wsp-block,
#v2HomeWorkspace [data-zone-id="order"] .wsp-card { background: none; border: 0; box-shadow: none; padding: 0; }
.wsp-order { display: flex; flex-direction: column; gap: 10px; }
.wsp-order__sum { margin: 0; font-size: var(--ds-text-sm); color: var(--muted); }
.wsp-order__sum b { font-family: var(--font-mono); font-weight: 600; color: var(--text); }
.wsp-order__sum b.is-bad { color: var(--danger); }
.wsp-order__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.wsp-order__list > li { border-top: 1px dashed var(--border); }
.wsp-order__list > li:first-child { border-top: 0; }
.wsp-order__row {
  display: grid;
  grid-template-columns: 62px minmax(0, 1fr) auto;
  align-items: start;
  gap: 2px 10px;
  width: 100%;
  padding: 9px 6px;
  border: 0;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--motion-fast, 140ms) ease;
}
@media (hover: hover) and (pointer: fine) { .wsp-order__row:hover { background: var(--hover); } }
.wsp-order__row:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.wsp-order__time { font-family: var(--font-mono); font-size: 12px; font-weight: 500; line-height: 1.3; color: var(--muted); padding-top: 1px; overflow-wrap: anywhere; }
.wsp-order__main { display: flex; flex-direction: column; min-width: 0; }
.wsp-order__title { font-size: var(--ds-text-sm); font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
.wsp-order__meta { font-size: 12px; color: var(--faint); }
.wsp-order__row--completed .wsp-order__title { color: var(--muted); font-weight: 500; }
.wsp-order__row--started { background: color-mix(in srgb, var(--accent) 7%, transparent); }
.wsp-order__row--started .wsp-order__time { color: var(--accent-fg); }
.wsp-order__row--event .wsp-order__time { color: var(--info); }
.wsp-order__flags { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; }
.wsp-order__flag {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: var(--r-full);
  background: var(--danger-bg);
  color: var(--danger);
  white-space: nowrap;
}
.wsp-order__now { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-top: 0 !important; font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--accent-fg); }
.wsp-order__now::before { content: ""; width: 9px; height: 9px; border-radius: 50%; background: var(--shuttle); box-shadow: 0 0 0 2px var(--accent); flex: none; }
.wsp-order__now::after { content: ""; flex: 1; height: 2px; background: var(--accent); border-radius: 1px; }
.wsp-order__now + li { border-top: 0; }
.wsp-order__more { margin: 0; font-size: 12px; color: var(--faint); }
.wsp-order__links { display: flex; flex-wrap: wrap; gap: 8px; padding-top: 4px; }

#v2HomeWorkspace .wsp-hero__board {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  margin: 10px 0 0;
  padding: 8px 12px;
  border-radius: var(--r-md);
  background: var(--danger-bg);
  color: var(--text);
  font-size: var(--ds-text-sm);
  width: fit-content;
  max-width: 100%;
}
#v2HomeWorkspace .wsp-hero__board b { color: var(--danger); font-weight: 600; }
#v2HomeWorkspace .wsp-hero__board-mark { width: 8px; height: 8px; border-radius: 50%; background: var(--danger); flex: none; }
#v2HomeWorkspace .wsp-hero__board .wsp-btn { min-height: 28px; padding: 2px 10px; font-size: 12.5px; }

/* ── 9.0c Role workspaces as one sheet (v2) ─────────────────────────────── */
/* The bidang / driver / engineering Todays were a grid of floating cards.
   They are now ONE sheet with hairline-divided sections (the ledger idea at
   page scale): the same widgets, order and actions, read as a single
   briefing page instead of a dashboard of tiles. Executive (zoned) Today is
   untouched here. */
#v2HomeWorkspace .wsp-root:not(.wsp-root--zoned) .wsp-grid {
  gap: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow: hidden;
}
#v2HomeWorkspace .wsp-root:not(.wsp-root--zoned) .wsp-grid > .wsp-card {
  margin: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: -1px 0 0 var(--border), 0 -1px 0 var(--border);
  padding: 20px 22px 22px;
}
#v2HomeWorkspace .wsp-root:not(.wsp-root--zoned) .wsp-card__title {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ── 9.3 Kalender & To-Do — its own Today screen (reimagining v2) ───────── */
/* The Agenda tool used to sit under the whole briefing (after the launcher).
   It is now Today → "Kalender & To-Do" (domain-shell.js), and reads as a
   time-and-task workspace:
     head    — eyebrow + one serif sentence about today (agenda-workspace-view
               todaySentence: agenda today · due · terlewat)
     period  — the month/week as a serif title between its arrows
     month   — ONE surface with hairlines (was 35 floating cards); a cell
               names its first two items on wide screens (dots on narrow
               ones), today is sunlit, the selected day is ringed
     day     — the selected day beside the grid (≥1100px), below it otherwise
   Selectors are anchored on #v2AgendaWorkspace: agenda-styles.js injects its
   own <style> at runtime, after this file. Hooks and actions unchanged. */

#v2AgendaWorkspace { margin-top: 0; border-top: 0; padding-top: 4px; }

/* Head */
#v2AgendaWorkspace .cal-header { margin-bottom: 10px; align-items: flex-start; }
#v2AgendaWorkspace .cal-head-text { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
#v2AgendaWorkspace .cal-title {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}
#v2AgendaWorkspace .cal-title::before { content: ""; width: 18px; height: 2px; background: var(--accent); flex: none; }
#v2AgendaWorkspace .cal-headline {
  margin: 0;
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: clamp(26px, 2.6vw, 36px);
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: var(--text);
  text-wrap: balance;
}
#v2AgendaWorkspace .cal-headline em { font-style: italic; color: var(--accent-fg); }
#v2AgendaWorkspace .cal-headline-flag { color: var(--danger); }
#v2AgendaWorkspace .cal-headline:empty { display: none; }
#v2AgendaWorkspace .cal-header + .cal-header { margin-top: -4px; margin-bottom: 18px; }
#v2AgendaWorkspace .cal-header-actions { gap: 8px; }
#v2AgendaWorkspace .cal-header-actions .cal-btn { min-height: 34px; border-radius: var(--r-md); }

/* Period bar + Bulan/Minggu */
#v2AgendaWorkspace .cal-calview-region { display: flex; flex-direction: column; gap: 12px; }
#v2AgendaWorkspace .cal-calview-region > .cal-filters { order: 2; margin: 0; }
#v2AgendaWorkspace .cal-calview-region > .cal-periodbar { order: 1; }
#v2AgendaWorkspace .cal-calview-region > .cal-split { order: 3; }
#v2AgendaWorkspace .cal-calview-region > .cal-empty-hint { order: 4; }
#v2AgendaWorkspace .cal-periodbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
#v2AgendaWorkspace .cal-period { display: flex; align-items: center; gap: 4px; }
#v2AgendaWorkspace .cal-period-label {
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: clamp(24px, 2.2vw, 30px);
  line-height: 1.1;
  margin: 0 8px;
  color: var(--text);
}

/* Split: grid | selected day */
#v2AgendaWorkspace .cal-split { display: block; }
@media (min-width: 1100px) {
  #v2AgendaWorkspace .cal-split--with-day {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(300px, 340px);
    gap: 20px;
    align-items: start;
  }
  #v2AgendaWorkspace .cal-split-day { position: sticky; top: 76px; }
}

/* Month grid — one surface, hairlines */
#v2AgendaWorkspace .cal-grid-head {
  gap: 0;
  margin: 0;
  border: 1px solid var(--border);
  border-bottom: 0;
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  background: var(--surface-2);
}
#v2AgendaWorkspace .cal-grid-head span {
  padding: 9px 10px;
  text-align: left;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .1em;
  color: var(--faint);
}
#v2AgendaWorkspace .cal-grid {
  gap: 0;
  border: 1px solid var(--border);
  border-radius: 0 0 var(--r-xl) var(--r-xl);
  overflow: hidden;
  background: var(--surface);
}
#v2AgendaWorkspace .cal-grid .cal-cell {
  position: relative;
  min-height: 104px;
  min-width: 0;
  padding: 8px 8px 6px;
  gap: 3px;
  border: 0;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  background: var(--surface);
  transition: background-color var(--motion-fast, 140ms) ease;
}
#v2AgendaWorkspace .cal-grid .cal-cell:nth-child(7n) { border-right: 0; }
#v2AgendaWorkspace .cal-grid:not(.cal-week-row) .cal-cell:nth-last-child(-n + 7) { border-bottom: 0; }
@media (hover: hover) and (pointer: fine) {
  #v2AgendaWorkspace .cal-grid .cal-cell:hover { background: var(--hover); border-color: var(--border); }
}
#v2AgendaWorkspace .cal-grid .cal-cell--out { opacity: 1; background: var(--surface-2); }
#v2AgendaWorkspace .cal-grid .cal-cell--out .cal-cell-num { color: var(--faint); font-weight: 400; }
#v2AgendaWorkspace .cal-cell-num {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: -3px 0 0 -3px;
  border-radius: 999px;
}
#v2AgendaWorkspace .cal-grid .cal-cell--today { background: color-mix(in srgb, var(--shuttle) 16%, var(--surface)); }
#v2AgendaWorkspace .cal-cell--today .cal-cell-num { background: var(--accent); color: var(--on-accent); font-weight: 600; }
#v2AgendaWorkspace .cal-grid .cal-cell--selected { box-shadow: inset 0 0 0 2px var(--accent); }
#v2AgendaWorkspace .cal-grid .cal-cell:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }

/* Cell contents: titles on wide screens, dots on narrow ones */
#v2AgendaWorkspace .cal-cell-evs { display: none; flex-direction: column; gap: 2px; min-width: 0; }
#v2AgendaWorkspace .cal-cell-ev {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11.5px;
  line-height: 1.45;
  padding: 0 6px;
  border-radius: 5px;
  color: var(--text);
  background: var(--info-bg);
}
#v2AgendaWorkspace .cal-cell-ev b { font-family: var(--font-mono); font-weight: 500; font-size: 10.5px; color: var(--info); }
#v2AgendaWorkspace .cal-cell-ev--task { background: var(--surface-3); }
#v2AgendaWorkspace .cal-cell-ev--task::before { content: "○ "; color: var(--muted); }
#v2AgendaWorkspace .cal-cell-ev--late { background: var(--danger-bg); color: var(--danger); }
#v2AgendaWorkspace .cal-cell-ev--done { color: var(--faint); text-decoration: line-through; background: transparent; }
#v2AgendaWorkspace .cal-cell-ev--more { background: transparent; color: var(--faint); font-size: 11px; }
@media (min-width: 900px) {
  #v2AgendaWorkspace .cal-grid:not(.cal-week-row) .cal-cell-evs { display: flex; }
  #v2AgendaWorkspace .cal-grid:not(.cal-week-row) .cal-cell-label { display: none; }
}
#v2AgendaWorkspace .cal-range-bar {
  height: 18px;
  line-height: 18px;
  margin: 0 -8px;
  padding: 0 8px;
  font-size: 11px;
  font-weight: 600;
  border-top: 2px solid var(--bar-c, var(--accent));
}
#v2AgendaWorkspace .cal-range-bar--cap-left { margin-left: 0; border-top-left-radius: 4px; border-bottom-left-radius: 4px; }
#v2AgendaWorkspace .cal-range-bar--cap-right { margin-right: 0; border-top-right-radius: 4px; border-bottom-right-radius: 4px; }

/* Week view — taller days, same surface */
#v2AgendaWorkspace .cal-week-row .cal-cell { min-height: 220px; }

/* Selected day */
#v2AgendaWorkspace .cal-daydetail {
  margin-top: 16px;
  padding: 18px 18px 8px;
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  background: var(--surface);
}
#v2AgendaWorkspace .cal-split-day .cal-daydetail { margin-top: 0; }
#v2AgendaWorkspace .cal-daydetail-heading {
  margin: 0 0 10px;
  font-family: var(--font-editorial);
  font-weight: 400;
  font-size: 26px;
  line-height: 1.1;
  color: var(--text);
}
#v2AgendaWorkspace .cal-daydetail-eyebrow {
  display: block;
  margin-bottom: 4px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}
#v2AgendaWorkspace .cal-daylabel {
  margin: 14px 0 4px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}
#v2AgendaWorkspace .cal-daydetail-empty { padding: 18px 0 14px; font-family: var(--font-editorial); font-size: 19px; line-height: 1.3; color: var(--muted); }

/* Rows (Daftar, day panel) */
#v2AgendaWorkspace .cal-row { border-radius: var(--r-md); }
#v2AgendaWorkspace .cal-row-time { font-family: var(--font-mono); font-size: 12px; font-weight: 500; color: var(--muted); }
#v2AgendaWorkspace .cal-row-title { font-weight: 600; color: var(--text); }
#v2AgendaWorkspace .cal-modeswitch button[aria-selected="true"] { font-weight: 600; }

/* Daftar — days as a programme: the day in serif on the left, its items on
   the right (stacked on narrow screens); "Akan Datang" stays a small eyebrow. */
#v2AgendaWorkspace [data-agenda-view-root] > .cal-daygroup { padding: 14px 0; border-top: 1px solid var(--border); }
#v2AgendaWorkspace [data-agenda-view-root] > .cal-daygroup:first-child { border-top: 0; padding-top: 4px; }
#v2AgendaWorkspace [data-agenda-view-root] > .cal-daygroup > .cal-daylabel:first-child {
  margin: 0 0 6px;
  font-family: var(--font-editorial);
  font-size: 24px;
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
}
@media (min-width: 900px) {
  #v2AgendaWorkspace [data-agenda-view-root] > .cal-daygroup { display: grid; grid-template-columns: 200px minmax(0, 1fr); column-gap: 20px; }
  #v2AgendaWorkspace [data-agenda-view-root] > .cal-daygroup > .cal-daylabel:first-child { grid-row: 1 / span 40; padding-top: 10px; }
  #v2AgendaWorkspace [data-agenda-view-root] > .cal-daygroup > :not(.cal-daylabel) { grid-column: 2; }
}
#v2AgendaWorkspace [data-agenda-view-root] > .cal-daylabel { margin: 22px 0 6px; opacity: 1 !important; }
@media (hover: hover) and (pointer: fine) { #v2AgendaWorkspace .cal-row:hover { background: var(--hover); } }

/* To-Do — labelled filter rows, tasks on one surface with hairlines */
#v2AgendaWorkspace .cal-filters[aria-label="Filter status"]::before,
#v2AgendaWorkspace .cal-filters[aria-label="Filter prioritas"]::before {
  align-self: center;
  width: 76px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}
#v2AgendaWorkspace .cal-filters[aria-label="Filter status"]::before { content: "Status"; }
#v2AgendaWorkspace .cal-filters[aria-label="Filter prioritas"]::before { content: "Prioritas"; }
#v2AgendaWorkspace [data-agenda-view-root] > .cal-todo-row {
  margin: 0;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-top-width: 0;
  border-radius: 0;
  background: var(--surface);
}
#v2AgendaWorkspace [data-agenda-view-root] > .cal-filters + .cal-filters + .cal-todo-row { margin-top: 14px; border-top-width: 1px; border-radius: var(--r-xl) var(--r-xl) 0 0; }
#v2AgendaWorkspace [data-agenda-view-root] > .cal-todo-row:last-child { border-radius: 0 0 var(--r-xl) var(--r-xl); }
#v2AgendaWorkspace [data-agenda-view-root] > .cal-filters + .cal-filters + .cal-todo-row:last-child { border-radius: var(--r-xl); }
#v2AgendaWorkspace .cal-checkbox { border-radius: 6px; }

/* Narrow */
@media (max-width: 600px) {
  #v2AgendaWorkspace .cal-grid .cal-cell { min-height: 54px; padding: 6px 4px 4px; }
  /* agenda-styles.js hides the whole label here, dots included — phones keep the dots (the day panel below names them). */
  #v2AgendaWorkspace .cal-grid:not(.cal-week-row) .cal-cell-label { display: flex; }
  #v2AgendaWorkspace .cal-cell-dot { width: 5px; height: 5px; }
  #v2AgendaWorkspace .cal-grid-head span { padding: 8px 4px; text-align: center; letter-spacing: .04em; }
  #v2AgendaWorkspace .cal-range-bar { height: 6px; font-size: 0; margin: 2px -4px 0; border-top-width: 0; }
  #v2AgendaWorkspace .cal-week-row .cal-cell { min-height: 0; }
  #v2AgendaWorkspace .cal-header + .cal-header { margin-top: 0; }
  /* One scrolling action row on phones (Export + the three create buttons
     used to wrap onto a second line at 390px). */
  #v2AgendaWorkspace .cal-header-actions {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    width: 100%;
    padding-bottom: 2px;
  }
  #v2AgendaWorkspace .cal-header-actions::-webkit-scrollbar { display: none; }
  #v2AgendaWorkspace .cal-header-actions > * { flex: none; }
}



/* Users list — base button recipe; row hierarchy (one visible action,
   quiet lifecycle actions) lives in §9.2. */
.v2-user-btn {
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  font-size: var(--ds-text-sm);
  font-weight: 500;
}
.v2-user-btn:hover { background: var(--hover); }


/* Administration overview — the three counts become KPI tiles (were bare
   42px/700 numbers floating above the toolbar). */
.v2-admin-overview-cards { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; }
/* Same figure recipe as every other module (§6.2/§6.7): mono small-caps
   label above, the number leads. */
.v2-admin-overview-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 16px 18px 18px;
  gap: 8px;
  flex-direction: column-reverse; /* label above value, without touching markup order */
}
.v2-admin-overview-value { font-family: var(--font-display); font-size: 28px; font-weight: 600; line-height: 1.1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; color: var(--text); }
.v2-admin-overview-label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Administration / Analytics workspace: an EMPTY overview row still took a
   flex gap, adding ~32px of blank space above every Analytics screen. */
.v2-admin-overview-row:empty { display: none; }
.v2-analytics-shell { padding-top: 8px; }
.v2-admin-content { margin-top: 0; }

/* Small stat tiles (role summary in the user drawer, data-quality stats) —
   metadata inside a form, so 16px figures, not 26px headlines; status tones
   come from the canonical tokens (were raw #c97900 / #2F7D62 literals). */
.v2-dq-stats { gap: 8px; }
.v2-dq-stat-card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 10px 12px;
}
.v2-dq-stat-value { font-family: var(--font-display); font-size: var(--ds-text-lg); font-weight: 600; letter-spacing: -0.005em; font-variant-numeric: tabular-nums; }
.v2-dq-stat-label { font-size: var(--ds-text-xs); color: var(--muted); text-transform: none; letter-spacing: 0; }
.v2-dq-stat-card--warn, [data-theme="dark"] .v2-dq-stat-card--warn { background: var(--warn-bg); border-color: color-mix(in srgb, var(--warn) 35%, transparent); }
.v2-dq-stat-card--ok,   [data-theme="dark"] .v2-dq-stat-card--ok   { background: var(--ok-bg);   border-color: color-mix(in srgb, var(--ok) 35%, transparent); }

/* Toolbars (search · filters · primary action) — ONE row on desktop: the
   custom role select used to stretch to the full row (1246px) and push the
   add button onto a third line. */
.v2-admin-toolbar { gap: 8px; padding: 16px 0; align-items: center; }
.v2-admin-toolbar > .v2-admin-search { flex: 1 1 260px; }
.v2-admin-toolbar > .pbsi-select { flex: 0 0 auto; width: auto; min-width: 180px; }
.v2-admin-toolbar > .v2-admin-add-btn { margin-left: auto; }
.v2-admin-search, .v2-admin-filter, .pbsi-select-trigger, .pbsi-datepicker-trigger {
  min-height: var(--control-h);
  border-radius: var(--r-md);
  font-family: var(--font-sans);
  font-size: var(--ds-text-md);
}
.v2-admin-search, .v2-admin-filter, .pbsi-select-trigger {
  border: 1px solid var(--input-border);
  /* background-COLOR only: the shorthand reset the search field's icon (gone in
     light; tiled across the field in dark, where a later rule re-adds the image
     but background-repeat had already been reset to repeat). */
  background-color: var(--input-bg);
  color: var(--text);
  box-shadow: var(--shadow-xs);
}
.v2-admin-search:focus, .pbsi-select-trigger:focus-visible, .pbsi-select-trigger[aria-expanded="true"] {
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
  outline: none;
}
/* The date picker trigger renders the date as prose — sans, tabular digits. */
.pbsi-datepicker-trigger, .pbsi-datepicker-display, .pbsi-datepicker-display-full, .pbsi-datepicker-display-compact {
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
}


/* Analytics / fleet KPI cards (renderAnalyticsKPICard → .v2-analytics-kpi-card,
   used by Vehicles' fleet header and the Analytics screens) — same KPI recipe
   as §6.2: tone moves to the icon; values stay neutral EXCEPT danger, where a
   red number is a deliberate alarm (e.g. "Peringatan kritis 4"). */
.v2-analytics-kpi-card,
.v2-analytics-kpi-card--ok, .v2-analytics-kpi-card--warn, .v2-analytics-kpi-card--info, .v2-analytics-kpi-card--danger {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: none;
}
.v2-analytics-kpi-card-title {
  font-size: var(--ds-text-sm);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}
.v2-exec-kpi-grid .v2-analytics-kpi-card-title { font-size: var(--ds-text-sm); letter-spacing: 0; }
.v2-analytics-kpi-card-value { font-weight: 600; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.v2-analytics-kpi-card--ok .v2-analytics-kpi-card-value,
.v2-analytics-kpi-card--warn .v2-analytics-kpi-card-value { color: var(--text); }
.v2-analytics-kpi-card-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: var(--r-sm);
  background: var(--surface-3); color: var(--muted);
}
.v2-analytics-kpi-card--ok     .v2-analytics-kpi-card-icon { background: var(--ok-bg);     color: var(--ok); }
.v2-analytics-kpi-card--warn   .v2-analytics-kpi-card-icon { background: var(--warn-bg);   color: var(--warn); }
.v2-analytics-kpi-card--info   .v2-analytics-kpi-card-icon { background: var(--info-bg);   color: var(--info); }
.v2-analytics-kpi-card--danger .v2-analytics-kpi-card-icon { background: var(--danger-bg); color: var(--danger); }
.v2-analytics-kpi-card-sub { font-size: var(--ds-text-xs); color: var(--faint); }

/* Configuration form labels — sentence case like every other form label
   (were 11px uppercase tracked). */
.v2-admin-config-label {
  font-size: var(--ds-text-sm);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
}

/* Requests queue empty state — the shared empty-state well (was bare text). */
.v2-pending-empty {
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-lg);
  padding: 40px 24px;
  text-align: center;
  color: var(--muted);
  font-size: var(--ds-text-md);
  background: transparent;
}

/* "Diperbarui 13 Okt 21:46 · 3 driver" is prose metadata — sans, not mono. */
.exec-head__meta { font-family: var(--font-sans); font-variant-numeric: tabular-nums; }


/* ── 10. Responsive ───────────────────────────────────────────────────────── */

/* While typing on a touch phone (body.is-typing, js/ui/typing-state.js) the
   bottom nav and FAB step aside, like native tab bars. Needed because the
   viewport's interactive-widget=resizes-content lifts fixed bottom UI above
   the Android keyboard — they would otherwise sit over the field's content.
   (The FAB's display is set inline by JS, hence !important.) */
@media (max-width: 767px) and (pointer: coarse) {
  body.is-typing .bottom-nav,
  body.is-typing #fabAdd { display: none !important; }
}

/* Touch: 44px minimum targets wherever a coarse pointer is the input. */
@media (pointer: coarse) {
  .btn-primary, .btn-secondary, .btn-danger, .p-btn, .gud-btn, .eng-btn, .v2-user-btn,
  .v2-analytics-export-btn, .domshell-tab, .domshell-rail-item {
    min-height: var(--touch-min);
  }
  .form-group input:not([type="checkbox"]):not([type="radio"]), .form-group select,
  .gud-input, .eng-input, .drawer input:not([type="checkbox"]):not([type="radio"]), .drawer select {
    min-height: var(--touch-min);
    font-size: 16px; /* prevents iOS focus zoom */
  }
}

/* Topbar controls on touch: the phone topbar cannot fit 44px-wide buttons at
   320px, so each keeps its 30–36px look and gets an invisible hit area that
   extends it to ~44px (WCAG 2.5.8 target spacing; neighbours keep ≥8px gaps,
   so hit areas never overlap a different control by more than its own gap). */
@media (pointer: coarse) and (max-width: 1023px) {
  .v2-topbar :is(#sidebarToggle, .v2-topbar-icon-btn, #btnHeaderNotif, .domshell-palette-trigger, .v2-topbar-avatar) { position: relative; }
  .v2-topbar :is(#sidebarToggle, .v2-topbar-icon-btn, #btnHeaderNotif, .domshell-palette-trigger, .v2-topbar-avatar)::after {
    content: ""; position: absolute; inset: -6px -4px;
  }
  .v2-topbar .date-nav button { position: relative; }
  .v2-topbar .date-nav button::after { content: ""; position: absolute; inset: -7px 0; }
  .v2-tl-view-btn { min-height: 36px; }
  .v2-admin-nav-tab { min-height: 40px; }
  /* Agenda (Today) — its stylesheet is injected at runtime AFTER this file,
     so these carry one extra class of specificity. */
  .cal-root .cal-btn, .cal-root .cal-modeswitch button { min-height: 40px; }
}

@media (max-width: 767px) {
  .domshell-tabbar { padding: 0 4px; }
  .domshell-tab { height: 44px; padding: 0 12px; }
  body.v2-shell-active .v2-topbar { min-height: 52px; }

  /* The shell's screen tabs are now inline on phones (js/shell/domain-shell.js
     syncResponsive), so the modules' own mobile chip switchers — same screens,
     same order — would be a second, duplicate navigation row. */
  body.domain-shell-active .pc-embed-nav,
  body.domain-shell-active .ot-embed-nav { display: none !important; }

  /* KPI strip on phones keeps its short-label mechanism (label text at 0,
     data-short via ::after) — §6.2 sets the label size at higher specificity,
     so restore it here. */
  .v2-kpi-card .v2-kpi-label { font-size: 0; }
  .v2-kpi-card .v2-kpi-label::after { font-size: var(--ds-text-xs); font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--muted); }
  body.v2-shell-active .v2-kpi-card, .v2-kpi-card { padding: 12px; border-radius: var(--r-lg); }
  .v2-kpi-card .v2-kpi-value { font-size: 22px; }
}

/* ── Confirmation dialog (js/ui/confirm-dialog.js) ─────────────────────────
   Audit remediation A5 (2026-10-15): the one themed replacement for the
   native confirm()/prompt(). A centred card on a dimmed page; the danger
   variant only recolours the confirm button (.btn-danger) and the title rule,
   the message stays calm text. Tokens only, so dark mode follows. */
.pbsi-confirm {
  border: 0; padding: 0; margin: auto;
  width: min(420px, calc(100vw - 32px));
  max-height: calc(100dvh - 32px);
  border-radius: var(--r-xl, 20px);
  background: var(--surface); color: var(--text);
  box-shadow: var(--shadow-lg);
}
.pbsi-confirm::backdrop { background: color-mix(in srgb, #0b120e 46%, transparent); }
.pbsi-confirm__box { display: flex; flex-direction: column; gap: 12px; padding: 22px 22px 18px; }
.pbsi-confirm__title { margin: 0; font-size: var(--ds-text-lg, 17px); font-weight: 600; line-height: 1.3; color: var(--text); }
.pbsi-confirm--danger .pbsi-confirm__title { color: var(--danger); }
.pbsi-confirm__msg { color: var(--muted); font-size: var(--ds-text-sm, 14px); line-height: 1.55; }
.pbsi-confirm__msg p { margin: 0 0 8px; }
.pbsi-confirm__msg p:last-child { margin-bottom: 0; }
.pbsi-confirm__label { font-size: var(--ds-text-sm, 14px); font-weight: 600; color: var(--text); margin-top: 4px; }
.pbsi-confirm__opt { font-weight: 400; color: var(--muted); }
.pbsi-confirm__reason {
  width: 100%; min-height: 76px; resize: vertical; box-sizing: border-box;
  padding: 10px 12px; border-radius: var(--r-md, 10px);
  border: 1px solid var(--input-border, var(--border)); background: var(--input-bg, var(--surface));
  color: var(--text); font: inherit; font-size: var(--ds-text-sm, 14px);
}
.pbsi-confirm__reason:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.pbsi-confirm__reason[aria-invalid="true"] { border-color: var(--danger); }
.pbsi-confirm__actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px; flex-wrap: wrap; }
.pbsi-confirm__actions > button { min-height: 44px; min-width: 96px; }
@media (max-width: 480px) {
  .pbsi-confirm__actions { flex-direction: column-reverse; }
  .pbsi-confirm__actions > button { width: 100%; }
}
@media (prefers-reduced-motion: no-preference) {
  html:not([data-anim="off"]) .pbsi-confirm[open] { animation: pbsi-confirm-in var(--motion-pop, 160ms) var(--motion-ease, ease-out); }
  html:not([data-anim="off"]) .pbsi-confirm[open]::backdrop { animation: pbsi-confirm-fade var(--motion-pop, 160ms) ease-out; }
}
@keyframes pbsi-confirm-in { from { opacity: 0; transform: translateY(6px) scale(.98); } to { opacity: 1; transform: none; } }
@keyframes pbsi-confirm-fade { from { opacity: 0; } to { opacity: 1; } }

/* Audit remediation A6 — Home load failure. One alert above the workspace when
   the analytics engines could not load; failed widgets show their own error
   (.wsp-empty--error) with the same "Coba lagi". Scoped by host id because
   workspace-styles.js is injected after this file. */
#v2HomeWorkspace .wsp-load-alert {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  margin: 0 0 16px; padding: 12px 16px; border-radius: var(--r-lg, 14px);
  background: var(--warn-bg); color: var(--text); border: 1px solid color-mix(in srgb, var(--warn) 40%, transparent);
}
#v2HomeWorkspace .wsp-load-alert p { margin: 0; font-size: var(--ds-text-sm, 14px); line-height: 1.5; }
#v2HomeWorkspace .wsp-empty--error[role="alert"] { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
#v2HomeWorkspace .wsp-empty--error[role="alert"] p { margin: 0; }
#v2HomeWorkspace .wsp-load-alert .wsp-btn, #v2HomeWorkspace .wsp-empty--error .wsp-btn { min-height: 44px; }

/* Audit remediation A4 — your own row in User Management: the lifecycle
   buttons are replaced by a quiet note (another admin can still act on it). */
.v2-user-self-note {
  display: inline-flex; align-items: center; min-height: 36px; padding: 0 10px;
  font-size: var(--ds-text-xs, 12px); font-weight: 600; color: var(--muted);
  border: 1px dashed var(--border-strong); border-radius: var(--r-md, 10px);
}

/* ── Audit remediation C2 (2026-10-15) — touch targets ─────────────────────
   Measured on a touch-emulated 390px phone (hit areas incl. ::after
   extensions). Two controls were under the WCAG 2.5.8 AA minimum (24px): the
   Today "Lihat rincian skor" disclosure (19px) and the Rekap Lembur employee
   rows. The rest were 26-37px (AA, but short of the 44px the rest of the app
   uses on touch); the most-used families are raised here. Touch only — the
   desktop density is unchanged. Overtime/Petty Cash buttons carry inline
   styles, so they are matched by their data-act hooks. */
@media (pointer: coarse) {
  #v2HomeWorkspace .wsp-hero__details > summary { display: flex; align-items: center; min-height: 44px; }
  #v2HomeWorkspace .wsp-btn { min-height: 40px; }
  #v2HomeWorkspace .wsp-btn--link { display: inline-flex; align-items: center; }
  #v2HomeWorkspace .wsp-segmented__btn { min-height: 40px; }
  #v2HomeWorkspace .wsp-pulse__dot { position: relative; }
  #v2HomeWorkspace .wsp-pulse__dot::after { content: ""; position: absolute; inset: -9px; }
  [data-unit-block] label { min-height: 44px; }
  [data-act="selectAllUnit"], [data-act="clearUnit"], [data-act="bulkCopyYesterdayUnit"],
  [data-act="openBudgetEditor"], [data-act="recalculateSummaries"], [data-act="setTrendGranularity"],
  .pbsi-datepicker-preset, .pbsi-datepicker-trigger { min-height: 40px; }
  .v2-filter-chip, .v2-admin-filter, .v2-admin-add-btn, .v2-analytics-tab, .exec-reset { min-height: 44px; }
  .cal-root .cal-btn--sm { min-height: 40px; }
  .sidebar-close { min-width: 44px; min-height: 44px; }
  .ot-check { min-height: 44px; }
}

/* Audit remediation C6 — Board timeline edge hints ("‹ 2 trip sebelumnya").
   Shown only while same-day trips are fully outside the visible hours. */
.timeline-wrapper { position: relative; }
.tl-edge-hint {
  position: absolute; top: 5px; z-index: 25; /* above the sticky hours header (z 20) */
  display: inline-flex; align-items: center; min-height: 28px; padding: 0 12px;
  font: inherit; font-size: var(--ds-text-xs, 12px); font-weight: 600;
  color: var(--accent-fg); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--r-full, 999px);
  box-shadow: var(--shadow-sm); cursor: pointer;
}
.tl-edge-hint--right { right: 12px; }
.tl-edge-hint:hover { background: var(--hover); }
.tl-edge-hint:focus-visible { outline: 2px solid var(--accent-fg); outline-offset: 2px; }
.tl-edge-hint[hidden] { display: none; }
@media (pointer: coarse) { .tl-edge-hint { min-height: 32px; top: 3px; } .tl-edge-hint::after { content: ""; position: absolute; inset: -6px -2px; } }

/* ── Audit remediation C7/D2 (2026-10-15) — one presentation per fact ───────
   • "Peluncur Eksekutif" lists the same ten destinations the expanded deck
     already shows on screen, so it is hidden while the deck is expanded. It
     stays where the deck is collapsed or behind the phone menu, where it is
     the quickest way to those screens.
   • On phones the hero's mini timeline repeats "Urutan hari ini", which sits
     right below it with the same trips in more detail; it is dropped there to
     shorten the page. Desktop keeps both (side by side, different jobs). */
body.deck-expanded #v2HomeWorkspace .wsp-zone[data-zone-id="explore"] { display: none; }
@media (max-width: 767px) {
  #v2HomeWorkspace .wsp-pulse { display: none; }
}

/* Audit remediation D2 (2026-10-15) — one navigation layer per screen. Inside
   the domain shell, the shell's own screen tabs (inline on phones, the deck on
   desktop) already list Users/Settings, Drivers/Vehicles/Audit and the
   Analytics screens; the legacy admin and analytics tab strips repeated them
   as a second row on phones. Same treatment as .pc-embed-nav/.ot-embed-nav. */
body.domain-shell-active .v2-admin-nav { display: none !important; }
/* The Users/Drivers overview rows are now empty (their counts live in the
   stats strip); collapse the container so it leaves no gap. */
#v2AdminOverviewRow:empty { display: none; }
.v2-pending-empty__sub { margin-top: 4px; font-size: var(--ds-text-sm, 14px); color: var(--muted); }

/* Audit remediation D3 (2026-10-15) — one trip-status vocabulary. The trip
   drawer's badges used their own mapping (Ditugaskan green, Berlangsung
   orange, Selesai blue) while the Board said Dijadwalkan grey, Berlangsung
   solid green, Selesai green. The Board's is canonical (docs/PRODUCT.md):
   scheduled = neutral, live = the accent, done = success, cancelled = danger.
   The label always carries the meaning; colour only reinforces it. */
.badge-status--pending, .badge-status--approved, .badge-status--assigned {
  background: var(--surface-3); color: var(--muted); border-color: var(--border-strong);
}
.badge-status--started { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.badge-status--completed { background: var(--ok-bg); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.badge-status--cancelled { background: var(--danger-bg); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, transparent); }

/* Audit remediation D5 — a keyboard tip means nothing on a touch screen. */
@media (pointer: coarse) { .ot-kbd-hint { display: none; } }

/* ── Audit remediation E (2026-10-15) — typography: quieter, one family ───
   IBM Plex Sans carries every operational label; Plex Mono is kept for clock
   times and codes (alignment), Instrument Serif only for the one narrative
   headline per screen (docs/DESIGN-SYSTEM.md). Figure labels were 10.5px
   uppercase mono with wide tracking under every number ("TOTAL NOMINAL"),
   the loudest thing in each tile and hard to read on a phone. They are now
   12px sans in their natural case — the number leads, the label explains.
   (.v2-kpi-label keeps its own size: phones swap it for a short ::after label.) */
.rx-figure__label, .v2-admin-overview-label {
  font-family: var(--font-sans); font-size: var(--ds-text-xs, 12px); font-weight: 500;
  letter-spacing: 0; text-transform: none; color: var(--muted);
}
.v2-kpi-card .v2-kpi-label { font-family: var(--font-sans); letter-spacing: 0; text-transform: none; }
/* Numbers that sit in columns or change in place keep their width (no jitter
   when a count ticks from 9 to 10, aligned rupiah in tables). :where() adds no
   specificity, so any component that already chose its numerals still wins. */
:where(td, th, .rx-figure__value, .v2-kpi-value, .v2-admin-overview-value, .exa-ring__v, .exa-metric__head b,
  .wsp-hero__stat-big, .v2-admin-stats-chip-count, .gud-ov-value, .v2-list-card-time, .hour-cell) {
  font-variant-numeric: tabular-nums;
}

/* Audit remediation G1 (2026-10-15) — no bounce on a large surface. The
   request sheet entered on the 1.3 overshoot curve (a whole panel wobbling
   past its resting place); small marks (selection tick, switch knob) keep
   their tactile overshoot. */
.req-sheet { transition: transform .24s var(--motion-ease, cubic-bezier(.2, .8, .2, 1)), opacity .2s ease; }
