/* AKM Mobile + AKM CRM — design tokens. One family with TMS (2026-10-14, owner): porcelain canvas, midnight chrome,
   cobalt signal, Mona Sans. The names are semantic (signal, chrome), never a colour word. */
:root {
    --signal: #264cb3;          /* primary action, 7.6:1 with white */
    --signal-deep: #1d3d94;     /* focus ring, pressed */
    --on-signal: #ffffff;
    --signal-soft: #e5edfd;
    --signal-wash: #f2f6fe;
    --signal-lit: #9db6ff;      /* accent on midnight */
    --accent: #3360cc;          /* links, "done" marks */
    --ink: #181e2a;
    --sub: #5f656f;
    --bg: #f4f6f8;
    --card: #ffffff;
    --line: #e3e6ea;
    --line-strong: #cdd2d8;
    --off: #eceff3;
    --night: #3d4b9a;
    --ok: #187c49;
    --danger: #c02c29;
    --chrome: #101727;
    --chrome-2: #192134;
    --chrome-3: #283043;
    --on-chrome: #edf0f6;
    --on-chrome-muted: #a5abb8;
    --font-display: 'Mona Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-body: 'Mona Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono: 'Mona Sans', ui-sans-serif, system-ui, sans-serif;
    --nav-h: 68px;
    --top-h: 56px;
    --warn-bg: #fdf1da;
    --warn-line: #f0d9a8;
    --warn-ink: #9c5905;
    --warn-deep: #7a4604;
    --night-bg: #e6e9f7;
    --night-ink: #33407e;
    --ok-ink: #187c49;
    --shadow-sheet: 0 12px 28px -14px rgba(16, 23, 39, .30);
}

/* ---- fonts: the app's own files, precached by the worker — the first paint never waits for another host.
   Latin subsets of the weights the screens use (OFL; fonts/OFL.txt). ---- */
@font-face { font-family: 'Mona Sans'; font-style: normal; font-weight: 400; font-display: swap; src: url('../fonts/mona-sans-latin-400-normal.woff2') format('woff2'); }
@font-face { font-family: 'Mona Sans'; font-style: normal; font-weight: 500; font-display: swap; src: url('../fonts/mona-sans-latin-500-normal.woff2') format('woff2'); }
@font-face { font-family: 'Mona Sans'; font-style: normal; font-weight: 600; font-display: swap; src: url('../fonts/mona-sans-latin-600-normal.woff2') format('woff2'); }
@font-face { font-family: 'Mona Sans'; font-style: normal; font-weight: 700; font-display: swap; src: url('../fonts/mona-sans-latin-700-normal.woff2') format('woff2'); }

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: 14px;
    -webkit-tap-highlight-color: transparent;
}

#app { min-height: 100dvh; }

/* ---- app shell ---- */
.shell { min-height: 100dvh; display: flex; flex-direction: column; }
.shell-main { position: relative; flex: 1; padding: 4px 14px calc(var(--nav-h) + 18px); max-width: 520px; width: 100%; margin: 0 auto; }

/* The bell is the last button of the app bar. */
.bell {
    position: relative; flex: none;
    width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
    background: none; border: 0; padding: 0; cursor: pointer; color: var(--ink);
    -webkit-tap-highlight-color: transparent;
}
.bell svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.bell:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; border-radius: 9px; }
/* The count, not just a dot: "three waiting" and "one waiting" are different days. */
.bell-dot {
    position: absolute; top: 4px; right: 2px; min-width: 16px; height: 16px; padding: 0 4px;
    border-radius: 99px; background: var(--danger, #c02c29); color: #fff;
    font: 700 10px/16px var(--font-body); text-align: center;
}
.notif-row {
    display: block; width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
    font: inherit; color: inherit; padding: 10px 0; border-bottom: 1px solid var(--off);
}
.notif-row:disabled { cursor: default; }
/* Read vs unread on two channels at once — weight AND a dot. Colour alone loses on a bright screen
   outdoors, which is where this app is read, and "which of these is new" is the only question the
   badge is answering. */
.notif-row.unread { background: linear-gradient(90deg, rgba(51,96,204,.07), transparent 60%); }
.notif-row.unread > span:nth-child(2) { font-weight: 600; color: var(--ink); }
.notif-row.read > span:nth-child(2) { color: var(--sub); }
/* The date heading STICKS. That is the whole mechanism that lets the rows below it carry a bare clock:
   scroll as far as you like and the day the row belongs to is still on screen. Without it the rows go
   undated the moment the heading leaves the viewport — which is exactly what people hit. */
.notif-group {
    position: sticky; top: -1px; z-index: 1;
    background: var(--card);
    font: 700 11px var(--font-body); color: var(--sub);
    padding: 14px 0 5px; border-bottom: 1px solid var(--line);
}
.notif-group:first-child { padding-top: 4px; }
/* A picked file, before it is sent. Reads as one object with a way to undo it — not a table row, and
   not a card: it is a thing the person is carrying, and they may put it back down. */
.attach-chip {
    display: flex; align-items: center; gap: 8px; margin-top: 6px;
    background: var(--off); border: 1px solid var(--line); border-radius: 10px; padding: 7px 8px 7px 10px;
}
.attach-kind {
    font: 700 9px var(--font-body); letter-spacing: .06em; color: var(--sub);
    background: var(--card); border: 1px solid var(--line); border-radius: 5px; padding: 2px 5px; flex: none;
}
.attach-name {
    flex: 1; min-width: 0; font-size: 12px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.attach-x {
    flex: none; width: 44px; height: 44px; margin: -9px; border: 0; /* 44px hit area, 26px of layout */ border-radius: 50%; cursor: pointer;
    background: none; color: var(--sub); font: 400 20px/1 var(--font-body);
}
.attach-x:focus-visible { outline: 2px solid var(--signal); outline-offset: 1px; }
/* A booked ticket on a request's detail: each leg reads like the stub of a boarding pass — when on the left, the route in
   the middle, the booking code at the end; a dashed rule between legs is the perforation. */
.tk-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.tk-leg { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px dashed var(--line); }
.tk-head + .tk-leg { margin-top: 8px; }
.tk-leg__when { flex: none; width: 54px; display: flex; flex-direction: column; line-height: 1.25; }
.tk-leg__when b { font-size: 12px; }
.tk-leg__when span { font-size: 11px; color: var(--sub); }
.tk-leg__body { flex: 1; min-width: 0; }
.tk-leg__route { font-weight: 600; font-size: 13px; }
.tk-leg__meta { font-size: 11px; color: var(--sub); margin-top: 2px; }
.tk-leg__end { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.tk-leg__code { font-size: 12px; font-weight: 700; letter-spacing: .06em; }
.tk-leg__price { font-size: 11px; color: var(--sub); }
/* Already sent: a link to open it, never a delete. */
.attach-open {
    display: flex; align-items: center; gap: 8px; margin-top: 6px; text-decoration: none; color: inherit;
    background: var(--off); border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px;
}
.submitted { display: flex; align-items: center; gap: 7px; margin-top: 5px; }
.submitted .mono { font-size: 11px; color: var(--sub); font-variant-numeric: tabular-nums; }
.notif-when { display: flex; align-items: center; gap: 7px; margin-top: 2px; }
.notif-when .mono { font-size: 11px; color: var(--sub); font-variant-numeric: tabular-nums; }
/* An unanswered pengajuan expires on its own, so its age is a fact that changes the decision. Amber,
   not red: it is a nudge about time, not a failure. */
.notif-waited {
    font: 700 10px var(--font-body); color: #9c5905;
    background: #fdf1da; border-radius: 99px; padding: 2px 7px;
}
.notif-dot {
    display: inline-block; width: 6px; height: 6px; border-radius: 50%;
    background: var(--signal); margin-right: 5px; vertical-align: 1px;
}
/* A text action inside a sheet header: it must look pressable without competing with the title. */
.linkish {
    background: none; border: 0; padding: 0; cursor: pointer; flex: none;
    font: 600 12px var(--font-body); color: var(--accent); text-decoration: underline;
}
.linkish:disabled { opacity: .5; cursor: default; }
.notif-kind { font: 700 10px var(--font-body); letter-spacing: .05em; text-transform: uppercase; color: var(--sub); }
.notif-kind.act { color: #9c5905; }

.topbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 0 6px; }
.topbar h1 { font-family: var(--font-display); font-size: 26px; font-weight: 600; margin: 0; }
.topbar .sub { font-size: 12px; color: var(--sub); }

.card { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 13px 15px; margin-bottom: 10px; }
.card h2 { font-family: var(--font-display); font-size: 18px; font-weight: 600; margin: 0 0 4px; }

/* A card that opens its own breakdown. It has to LOOK operable — a statistic that silently happens to
   be tappable is a statistic nobody taps — but the affordance stays quiet: these sit five in a column,
   and five shouting cards is a busier screen than five silent ones, not a clearer one. The cue is a
   chevron on a small label, plus the pressed state a finger expects. */
.card-tap {
    display: block; font: inherit; color: inherit; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: transform .12s ease, border-color .12s ease;
}
.card-tap:active { transform: scale(.988); border-color: var(--signal); }
.card-tap:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.tap-hint {
    display: block; margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--off);
    font: 600 11px var(--font-body); letter-spacing: .04em; text-transform: uppercase;
    color: var(--sub);
}
.tap-hint::after { content: " ›"; font-size: 13px; }
.muted { color: var(--sub); }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

.btn {
    display: block; width: 100%; text-align: center; border: 0; cursor: pointer;
    background: var(--signal); color: var(--on-signal);
    font: 600 15px var(--font-body); border-radius: 9px; padding: 13px; min-height: 48px;
}
/* Every interactive element, including the ones styled inline. Keyboard users and switch-access
   users had no visible focus anywhere except .btn and .navlink before this. */
:where(button, a, select, textarea, input, [role="button"]):focus-visible {
    outline: 3px solid var(--signal-deep);
    outline-offset: 2px;
}
.btn.ghost { background: var(--card); border: 1px solid var(--line); color: var(--ink); }

.pill { display: inline-block; border-radius: 999px; padding: 4px 10px; font: 600 11px/1.2 var(--font-body); }
.pill.amb { background: #fdf1da; color: #9c5905; }
.pill.grn { background: #e6f5ec; color: #187c49; }
.pill.red { background: #fcebe9; color: #c02c29; }
.pill.gry { background: var(--off); color: var(--sub); }

/* ---- app chrome: top bar, drawer, bottom bar (same frame as TMS: midnight drawer, porcelain canvas) ---- */
.topbar-app {
    position: sticky; top: 0; z-index: 20; height: calc(var(--top-h) + env(safe-area-inset-top)); padding-top: env(safe-area-inset-top);
    display: flex; align-items: center; gap: 6px; padding-left: 8px; padding-right: 8px;
    border-bottom: 1px solid var(--line);
}
/* The frosted glass lives on a layer BEHIND the bar, never on the bar: a backdrop-filter (or filter/transform) on an
   element makes it the containing block of every position:fixed descendant, and the bell's sheet is one — it was
   squeezed into the bar's 56px and the notifications could not be seen (owner, 15 Oct). */
.topbar-app::before {
    content: ""; position: absolute; inset: 0; z-index: -1;
    background: rgba(244, 246, 248, .88); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
.top-btn {
    position: relative; width: 44px; height: 44px; flex: none; display: flex; align-items: center; justify-content: center;
    border: 0; background: none; color: var(--ink); border-radius: 9px; cursor: pointer; padding: 0; text-decoration: none;
}
.top-btn:active { background: var(--off); }
.top-btn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.top-brand { display: flex; align-items: center; gap: 9px; min-width: 0; flex: 1; text-decoration: none; color: var(--ink); }
.brand-mark {
    flex: none; width: 28px; height: 28px; border-radius: 8px; background: var(--chrome); color: var(--signal-lit);
    display: flex; align-items: center; justify-content: center; font: 700 14px/1 var(--font-display); letter-spacing: -.02em;
}
.brand-word { font: 600 15px/1.1 var(--font-display); letter-spacing: -.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The bell is a top-bar button now; it sits in the flow, not over the page. */
.top-btn .bell-dot { top: 4px; right: 2px; }

.scrim { position: fixed; inset: 0; z-index: 60; background: rgba(16, 23, 39, .52); opacity: 0; pointer-events: none; transition: opacity .2s ease; }
.drawer-open .scrim { opacity: 1; pointer-events: auto; }
.drawer {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 61; width: min(84vw, 320px);
    display: flex; flex-direction: column; background: var(--chrome); color: var(--on-chrome);
    padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom);
    transform: translateX(-102%); visibility: hidden; transition: transform .24s cubic-bezier(.2, .8, .2, 1), visibility 0s linear .24s;
    box-shadow: 18px 0 40px -24px rgba(0, 0, 0, .6);
}
.drawer-open .drawer { transform: none; visibility: visible; transition: transform .24s cubic-bezier(.2, .8, .2, 1), visibility 0s; }
.drawer-head { display: flex; align-items: center; gap: 10px; padding: 14px 12px 12px 16px; border-bottom: 1px solid var(--chrome-3); }
.drawer-head .brand-mark { background: var(--chrome-2); width: 32px; height: 32px; }
.drawer-head .brand-word { flex: 1; font-size: 16px; color: var(--on-chrome); }
.drawer-head .top-btn { color: var(--on-chrome-muted); }
.drawer-scroll { flex: 1; overflow-y: auto; padding: 8px 10px 12px; overscroll-behavior: contain; }
.drawer-group { margin: 14px 0 4px; padding: 0 10px; font: 600 11px/1 var(--font-body); letter-spacing: .02em; color: var(--on-chrome-muted); }
.drawer-link {
    display: flex; align-items: center; gap: 12px; min-height: 46px; padding: 0 10px; margin: 1px 0; border-radius: 9px;
    color: var(--on-chrome); text-decoration: none; font: 500 15px/1.2 var(--font-body); border: 0; background: none; width: 100%; text-align: left; cursor: pointer;
}
.drawer-link svg { flex: none; width: 21px; height: 21px; fill: none; stroke: var(--on-chrome-muted); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.drawer-link:active { background: var(--chrome-2); }
.drawer-link.active { background: var(--chrome-3); font-weight: 600; box-shadow: inset 3px 0 0 var(--signal-lit); }
.drawer-link.active svg { stroke: var(--signal-lit); }
.drawer-link .count { margin-left: auto; min-width: 20px; padding: 2px 7px; border-radius: 99px; background: var(--signal-lit); color: var(--chrome); font: 700 11px/16px var(--font-body); text-align: center; }
.drawer-foot { padding: 10px 12px 14px; border-top: 1px solid var(--chrome-3); display: flex; align-items: center; gap: 10px; }
.drawer-user { flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; color: var(--on-chrome); text-decoration: none; }
.avatar { flex: none; width: 34px; height: 34px; border-radius: 50%; background: var(--chrome-3); color: var(--signal-lit); display: flex; align-items: center; justify-content: center; font: 700 14px/1 var(--font-body); }
.avatar svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.drawer-user b { display: block; font: 600 14px/1.2 var(--font-body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.drawer-user small { display: block; font: 400 12px/1.3 var(--font-body); color: var(--on-chrome-muted); }
.drawer-foot .top-btn { color: var(--on-chrome-muted); }

.bottom-nav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 10;
    display: flex; align-items: flex-end; justify-content: space-around;
    background: var(--card); border-top: 1px solid var(--line);
    padding: 6px 4px calc(8px + env(safe-area-inset-bottom));
}
.navlink {
    position: relative; display: flex; flex-direction: column; align-items: center; gap: 3px; border: 0; background: none; font-family: inherit; cursor: pointer;
    min-width: 56px; min-height: 48px; justify-content: flex-end;
    font-size: 11px; color: var(--sub); text-decoration: none;
}
.navlink svg { width: 22px; height: 22px; stroke: var(--sub); fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
/* Active = weight + cobalt icon + a top rule: the colour alone is never the cue. */
.navlink.active { color: var(--ink); font-weight: 600; }
.navlink.active svg { stroke: var(--signal); stroke-width: 2; }
.navlink.active::before { content: ""; position: absolute; top: -7px; left: 22%; right: 22%; height: 3px; border-radius: 0 0 3px 3px; background: var(--signal); }
.navlink.mid { margin-top: -26px; }
.navlink.mid.active::before { display: none; }
.fab {
    width: 54px; height: 54px; border-radius: 16px;
    background: var(--chrome); border: 4px solid var(--bg);
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 10px 18px -8px rgba(16, 23, 39, .55);
}
.fab svg { width: 25px; height: 25px; stroke: var(--signal-lit); fill: none; stroke-width: 2; }
.navlink.mid.active .fab { background: var(--signal); }
.navlink.mid.active .fab svg { stroke: #fff; }

/* ---- boot / loading (index.html) ---- */
.boot { min-height: 100dvh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; }
.boot-ring {
    width: 72px; height: 72px; border-radius: 50%;
    border: 5px solid var(--off); border-top-color: var(--signal);
    animation: boot-spin 1s linear infinite;
}
.boot-name { font-family: var(--font-display); font-size: 22px; font-weight: 600; letter-spacing: .02em; }
.loading-progress-text { font: 500 12px var(--font-mono); color: var(--sub); }
.loading-progress-text:after { content: var(--blazor-load-percentage-text, "memuat…"); }
@keyframes boot-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .boot-ring { animation: none; } .card-tap { transition: none; } .card-tap:active { transform: none; } }

/* ---- error ui ---- */
#blazor-error-ui {
    display: none; position: fixed; bottom: 0; left: 0; right: 0; z-index: 100;
    background: #fcebe9; color: #c02c29; padding: 12px 16px; font-size: 13px;
}
#blazor-error-ui .reload { color: #c02c29; font-weight: 600; margin-left: 6px; }
#blazor-error-ui .dismiss { float: right; cursor: pointer; }


/* ============================================================================
   Instrument-panel hierarchy (design pass 2026-08-28)
   The app is read one-handed, outdoors, in a hurry. Everything used to sit at
   11–15px in roughly one weight, so nothing was findable at arm's length. The
   rule now: ONE number per card is large; every other level steps down clearly.
   ========================================================================= */
.eyebrow {
    font: 600 10px/1 var(--font-body);
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--sub);
}
.card-title { font: 600 14px/1.25 var(--font-body); }

/* The one big number: hours, a clock, a percentage. Tabular so digits do not
   dance while they update. */
.stat {
    font: 700 30px/1 var(--font-display);
    font-variant-numeric: tabular-nums;
    letter-spacing: .01em;
}
.stat-sm {
    font: 600 20px/1 var(--font-display);
    font-variant-numeric: tabular-nums;
}
.stat-unit { font: 600 12px/1 var(--font-body); color: var(--sub); margin-left: 4px; }

/* ---- form fields: one shape, one invalid state ---- */
.field {
    width: 100%;
    padding: 11px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--font-body);
    /* 16px exactly, and declared AFTER any font shorthand: below 16px iOS Safari zooms the page in on
       focus and a standalone PWA never zooms back out, leaving the user inside a magnified form.
       (The shorthand `font: inherit` used to sit under this line and silently reset it to 14px.) */
    font-size: 16px;
}
.field:focus-visible { outline: 3px solid var(--signal-deep); outline-offset: 1px; }

/* Validation speaks on THREE channels — colour, motion and words — because any
   one of them alone is missed: colour by colour-blind users, motion by anyone
   who looks away, text by someone scanning fast. */
.field.invalid,
.card.invalid {
    border-color: var(--danger);
    box-shadow: 0 0 0 3px rgba(201, 79, 61, .14);
}
.field-error {
    display: block;
    font: 600 11px/1.35 var(--font-body);
    color: var(--danger);
    margin-top: 5px;
}
.shake { animation: akm-shake .28s cubic-bezier(.36, .07, .19, .97) both; }

/* An action that is not available yet READS as unavailable — but stays clickable, so tapping it can
   say which field is missing instead of doing nothing (a real `disabled` swallows the click). */
textarea.field {
    resize: vertical;
    min-height: 44px;
    line-height: 1.45;
    overflow-y: hidden;   /* the JS sizes it; a scrollbar inside a 2-row box is the thing being fixed */
}

.btn.off {
    background: var(--line);
    color: var(--sub);
    box-shadow: none;
}
@keyframes akm-shake {
    10%, 90% { transform: translateX(-2px); }
    20%, 80% { transform: translateX(4px); }
    30%, 50%, 70% { transform: translateX(-7px); }
    40%, 60% { transform: translateX(7px); }
}

/* ---- toasts ---- */
/* Top of the screen on purpose: the primary action lives at the bottom under the
   thumb, and a bottom toast would sit on top of the very button it comments on. */
.toast-host {
    position: fixed;
    top: calc(8px + env(safe-area-inset-top));
    left: 10px; right: 10px;
    z-index: 80;
    display: flex;
    flex-direction: column;
    gap: 8px;
    pointer-events: none;
}
.toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    border-radius: 9px;
    background: var(--card);
    border: 1px solid var(--line);
    box-shadow: 0 12px 28px -12px rgba(16, 23, 39, .30);
    font-size: 13px;
    line-height: 1.4;
    animation: akm-toast-in .18s ease-out both;
}
.toast .dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; flex: none; }
.toast.ok { border-color: #c4e2d1; background: #f1f8f4; }
.toast.ok .dot { background: var(--ok); }
.toast.warn { border-color: #f0d9a8; background: #fdf6e7; }
.toast.warn .dot { background: var(--warn-ink); }
.toast.err { border-color: #f2c6c3; background: #fcebe9; }
.toast.err .dot { background: var(--danger); }
.toast b { font-weight: 600; }
@keyframes akm-toast-in { from { opacity: 0; transform: translateY(-8px); } }

@media (prefers-reduced-motion: reduce) {
    .shake, .toast { animation: none; }
}


/* Touch targets: 44px is the floor for anything a thumb must hit (WCAG 2.5.5 / platform HIG).
   Three icon buttons and both tab strips were under it. */
.icon-btn {
    width: 44px; height: 44px; flex: none;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--line); border-radius: 10px;
    background: var(--card); color: var(--sub); cursor: pointer; padding: 0;
}
.tabs { display: flex; background: var(--off); border-radius: 10px; padding: 3px; gap: 2px; margin-bottom: 10px; }
.tabs button {
    flex: 1; min-height: 44px; border: 0; border-radius: 8px; cursor: pointer;
    font: 600 12px var(--font-body); background: transparent; color: var(--sub);
}
.tabs button.on { background: var(--card); color: var(--ink); box-shadow: 0 1px 2px rgba(16,23,39,.08); }

/* The amber "notice" block, previously hardcoded in three pages. */
.card.notice { border-color: #f0d9a8; background: #fdf6e7; color: #7a4604; }
/* Beranda: the announcement a reader must open — the notice's colours, the text keeps its own. */
.card.must-read { display: block; text-decoration: none; color: inherit; border-color: var(--warn-line); background: #fdf6e7; }
/* Beranda: a news banner — the one dark block on the page. */
.news-banner { display: block; text-decoration: none; border-radius: 10px; overflow: hidden; color: #edf0f6; padding: 14px;
    background: linear-gradient(115deg, #101727 0%, #192134 55%, #283043 130%); }
.news-banner-tag { font: 600 9px var(--font-mono); letter-spacing: .12em; color: #9db6ff; }
.news-banner-summary { display: block; font-size: 11px; margin-top: 5px; color: #a5abb8; }

/* A load that failed is NOT an empty result — it gets its own block with a way out. */
.retry { text-align: center; padding: 22px 16px; }
.retry b { display: block; font-family: var(--font-display); font-size: 17px; }

/* Past the ceiling. Its own colour, because "heavier than allowed" is not a bigger version of
   "on track" — it is a different state, and the eye should catch it before the number is read. */

/* ---- utilities: one declaration per class, moved out of inline style="" (UI-16). !important keeps the
   exact precedence an inline style had over component rules. ---- */
.u-align-items-baseline { align-items: baseline !important; }
.u-align-items-center { align-items: center !important; }
.u-align-items-flex-start { align-items: flex-start !important; }
.u-background-night-bg { background: var(--night-bg) !important; }
.u-background-warn-bg { background: var(--warn-bg) !important; }
.u-background-signal { background: var(--signal) !important; }
.u-background-card { background: var(--card) !important; }
.u-background-ink { background: var(--ink) !important; }
.u-background-off { background: var(--off) !important; }
.u-border-1px-solid-line { border: 1px solid var(--line) !important; }
.u-border-color-warn-line { border-color: var(--warn-line) !important; }
.u-border-left-3px-solid-signal { border-left: 3px solid var(--signal) !important; }
.u-border-radius-10px { border-radius: 10px !important; }
.u-border-radius-50 { border-radius: 50% !important; }
.u-border-radius-99px { border-radius: 99px !important; }
.u-border-top-1px-solid-line { border-top: 1px solid var(--line) !important; }
.u-border-top-1px-solid-off { border-top: 1px solid var(--off) !important; }
.u-bottom-2px { bottom: -2px !important; }
.u-color-night-ink { color: var(--night-ink) !important; }
.u-color-warn-deep { color: var(--warn-deep) !important; }
.u-color-warn-ink { color: var(--warn-ink) !important; }
.u-color-accent { color: var(--accent) !important; }
.u-color-danger { color: var(--danger) !important; }
.u-color-inherit { color: inherit !important; }
.u-color-sub { color: var(--sub) !important; }
.u-cursor-pointer { cursor: pointer !important; }
.u-display-block { display: block !important; }
.u-display-flex { display: flex !important; }
.u-display-grid { display: grid !important; }
.u-display-inline-flex { display: inline-flex !important; }
.u-flex-1 { flex: 1 !important; }
.u-flex-none { flex: none !important; }
.u-flex-wrap-wrap { flex-wrap: wrap !important; }
.u-font-600-11px-font-body { font: 600 11px var(--font-body) !important; }
.u-font-family-font-display { font-family: var(--font-display) !important; }
.u-font-inherit { font: inherit !important; }
.u-font-size-10px { font-size: 10px !important; }
.u-font-size-11px { font-size: 11px !important; }
.u-font-size-12px { font-size: 12px !important; }
.u-font-size-13px { font-size: 13px !important; }
.u-font-size-14px { font-size: 14px !important; }
.u-font-size-17px { font-size: 17px !important; }
.u-font-size-20px { font-size: 20px !important; }
.u-font-size-9px { font-size: 9px !important; }
.u-font-weight-400 { font-weight: 400 !important; }
.u-font-weight-600 { font-weight: 600 !important; }
.u-font-weight-700 { font-weight: 700 !important; }
.u-gap-10px { gap: 10px !important; }
.u-gap-18px { gap: 18px !important; }
.u-gap-2px { gap: 2px !important; }
.u-gap-3px { gap: 3px !important; }
.u-gap-4px { gap: 4px !important; }
.u-gap-5px { gap: 5px !important; }
.u-gap-6px { gap: 6px !important; }
.u-gap-8px { gap: 8px !important; }
.u-grid-template-columns-repeat-7-1fr { grid-template-columns: repeat(7,1fr) !important; }
.u-height-5px { height: 5px !important; }
.u-height-6px { height: 6px !important; }
.u-height-8px { height: 8px !important; }
.u-inset-11px { inset: 11px !important; }
.u-justify-content-space-between { justify-content: space-between !important; }
.u-left-50 { left: 50% !important; }
.u-left-5px { left: 5px !important; }
.u-letter-spacing-0 { letter-spacing: 0 !important; }
.u-letter-spacing-03em { letter-spacing: .03em !important; }
.u-line-height-1 { line-height: 1 !important; }
.u-line-height-1-45 { line-height: 1.45 !important; }
.u-line-height-1-5 { line-height: 1.5 !important; }
.u-list-style-none { list-style: none !important; }
.u-margin-0-0-8px { margin: 0 0 8px !important; }
.u-margin-10px-0-0 { margin: 10px 0 0 !important; }
.u-margin-12px-0-0 { margin: 12px 0 0 !important; }
.u-margin-2px-0-0 { margin: 2px 0 0 !important; }
.u-margin-2px-0-6px { margin: 2px 0 6px !important; }
.u-margin-2px-0-8px { margin: 2px 0 8px !important; }
.u-margin-4px-0 { margin: 4px 0 !important; }
.u-margin-4px-0-0 { margin: 4px 0 0 !important; }
.u-margin-4px-0-10px { margin: 4px 0 10px !important; }
.u-margin-6px-0-0 { margin: 6px 0 0 !important; }
.u-margin-6px-0-4px { margin: 6px 0 4px !important; }
.u-margin-8px-0-0 { margin: 8px 0 0 !important; }
.u-margin-bottom-3px { margin-bottom: 3px !important; }
.u-margin-bottom-8px { margin-bottom: 8px !important; }
.u-margin-left-8px { margin-left: 8px !important; }
.u-margin-top-10px { margin-top: 10px !important; }
.u-margin-top-12px { margin-top: 12px !important; }
.u-margin-top-14px { margin-top: 14px !important; }
.u-margin-top-2px { margin-top: 2px !important; }
.u-margin-top-3px { margin-top: 3px !important; }
.u-margin-top-4px { margin-top: 4px !important; }
.u-margin-top-6px { margin-top: 6px !important; }
.u-margin-top-8px { margin-top: 8px !important; }
.u-margin-top-9px { margin-top: 9px !important; }
.u-min-width-0 { min-width: 0 !important; }
.u-opacity-45 { opacity: .45 !important; }
.u-overflow-hidden { overflow: hidden !important; }
.u-padding-0 { padding: 0 !important; }
.u-padding-10px { padding: 10px !important; }
.u-padding-10px-12px { padding: 10px 12px !important; }
.u-padding-22px-16px { padding: 22px 16px !important; }
.u-padding-26px-16px { padding: 26px 16px !important; }
.u-padding-2px-0 { padding: 2px 0 !important; }
.u-padding-6px { padding: 6px !important; }
.u-padding-8px { padding: 8px !important; }
.u-padding-8px-12px { padding: 8px 12px !important; }
.u-padding-8px-14px { padding: 8px 14px !important; }
.u-padding-9px { padding: 9px !important; }
.u-padding-top-12px { padding-top: 12px !important; }
.u-padding-top-9px { padding-top: 9px !important; }
.u-position-absolute { position: absolute !important; }
.u-position-relative { position: relative !important; }
.u-right-4px { right: 4px !important; }
.u-text-align-center { text-align: center !important; }
.u-text-align-left { text-align: left !important; }
.u-text-decoration-none { text-decoration: none !important; }
.u-text-overflow-ellipsis { text-overflow: ellipsis !important; }
.u-text-transform-none { text-transform: none !important; }
.u-top-2px { top: -2px !important; }
.u-top-3px { top: 3px !important; }
.u-white-space-nowrap { white-space: nowrap !important; }
.u-white-space-pre-line { white-space: pre-line !important; }
.u-width-100 { width: 100% !important; }
.u-width-1px { width: 1px !important; }
.u-width-5px { width: 5px !important; }
.u-width-6px { width: 6px !important; }
.u-width-auto { width: auto !important; }
.u-height-18px { height: 18px !important; }
.u-line-height-1-15 { line-height: 1.15 !important; }
.u-margin-left-6px { margin-left: 6px !important; }
.u-margin-top-5px { margin-top: 5px !important; }
.u-opacity-85 { opacity: .85 !important; }
.u-padding-9px-0 { padding: 9px 0 !important; }

/* ---- component rules lifted out of inline styles (UI-16) ---- */
.tone-warn { color: var(--warn-ink); }
.tone-ok { color: var(--ok-ink); }
.tone-ink { color: var(--ink); }
.tone-sub { color: var(--sub); }
.bar-fill { height: 100%; border-radius: 99px; background: var(--signal); }
.bar-fill--flat { border-radius: 0; }
.ring {
    position: relative; width: 150px; height: 150px; margin: 4px auto; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
}
.cal-cell {
    position: relative; min-height: 46px; border-radius: 9px; border: 1px solid var(--line); cursor: pointer;
    padding: 14px 3px 5px; font: inherit; display: flex; align-items: center; justify-content: center;
}
.cal-cell--square { aspect-ratio: 1; }
.cal-cell--today { outline: 2px solid var(--signal); outline-offset: 1px; }
/* --accent is not a defined token: the 'done' colour has always resolved to nothing (border keeps its
   own colour), so the look is kept byte-for-byte rather than "fixed" here. */
.step { padding: 8px 0 8px 16px; border-left: 2px solid var(--line); margin-left: 4px; }
.step--done { border-left: 2px solid var(--accent); }

/* ---- CRM ---- */
/* The "AKM | CRM" lockup: the company's mark (or its name), a rule, the app. Small above a page title, big on the
   login screen. Ink only — the amber stays with what must be done. */
.lockup { display: inline-flex; align-items: center; gap: 8px; color: var(--ink); }
.lockup img { height: 18px; width: auto; display: block; opacity: .9; }
.lockup span { font: 600 17px/1 var(--font-display); letter-spacing: .07em; }
.lockup span:last-child { padding-left: 8px; border-left: 1.5px solid var(--ink); }
.lockup.big { gap: 12px; }
/* The app bar already names the app: inside the shell the page's own lockup would say it twice. Login keeps its own. */
.shell-main .lockup { display: none; }
.lockup.big span { font-size: 32px; }
.lockup.big span:last-child { padding-left: 12px; border-left-width: 2px; }

/* AKM CRM's login head: the app's own mark — the dark tile with the four-dot rail the home screen shows — then the
   name, then one line. */
.login-head { display: flex; flex-direction: column; align-items: center; gap: 14px; margin-bottom: 24px; text-align: center; }
.login-head p { margin: 0; font-size: 13px; }
.app-mark { display: block; width: 76px; height: 76px; border-radius: 18px; }

/* An empty screen: one sentence and one way on, never an illustration. */
.empty > p { margin: 0 0 12px; font-size: 14px; line-height: 1.45; }

/* What the screen says about its own data: shown from what was kept (no signal), or a list the server cut.
   One quiet line each — said, never hidden. */
.snap-note { margin: 0 0 10px; padding: 8px 12px; border-radius: 10px; background: var(--warn-bg); color: var(--warn-deep); font-size: 12px; line-height: 1.4; }
.cut-note { margin: 0 2px 10px; font-size: 12px; line-height: 1.4; color: var(--sub); }
.card .cut-note { margin: 8px 0 0; }

/* Hari ini. The three counts are one line of text, not tiles: the work list under them is the screen. A row is
   two targets — the row opens the ticket, the small button records a visit on it. */
.counts { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 2px 2px 12px; font-size: 13px; color: var(--sub); }
.counts b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.counts .tone-warn b { color: inherit; }
.sec { margin: 16px 2px 7px; font: 600 18px/1.1 var(--font-display); }
.card.list { padding: 0 15px; }
.due-row { display: flex; align-items: center; gap: 10px; border-bottom: 1px solid var(--off); }
.due-row:last-child { border-bottom: 0; }
.due-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; padding: 12px 0; color: inherit; text-decoration: none; }
.due-main > b { font: 600 14px/1.25 var(--font-body); overflow-wrap: anywhere; }
.due-main > span { font-size: 12px; line-height: 1.4; }
.due-main > .due-note { font-size: 13px; overflow-wrap: anywhere; }
.mini {
    flex: none; display: inline-flex; align-items: center; justify-content: center; min-width: 62px; min-height: 44px; padding: 0 12px;
    border: 1px solid var(--line); border-radius: 10px; background: var(--card); color: var(--ink);
    font: 600 13px var(--font-body); text-decoration: none;
}
.hint-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 0 2px; font-size: 12px; color: var(--sub); }
.hint-row .linkish { display: inline-flex; align-items: center; min-height: 44px; }

/* The rail: where a ticket stands. Ink only — passed filled, current ringed, ahead pale. The sentence after it
   says the stage, or how the ticket ended, and is the one part that takes a colour. */
.rail { display: flex; align-items: center; margin-top: 10px; }
.rail-dot { position: relative; z-index: 1; flex: none; width: 10px; height: 10px; border-radius: 50%; background: var(--line); }
.rail-tie { flex: none; width: 18px; height: 2px; background: var(--line); }
.rail-dot.done, .rail-tie.done { background: var(--ink); }
.rail-dot.now { background: var(--ink); box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--ink); }
.rail-text { min-width: 0; margin-left: 13px; font: 600 13px/1.3 var(--font-body); }
.rail.is-goal .rail-text { color: var(--ok-ink); }
.rail.is-fail .rail-text { color: var(--danger); }
.rail.is-cancel .rail-text { color: var(--sub); }
/* On the ticket itself each dot is named; as many columns as the server sent dots. */
.rail-lg { display: flex; margin: 12px -6px 2px; }
.rail-step { position: relative; flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 0 2px; font-size: 11px; line-height: 1.2; color: var(--sub); text-align: center; }
.rail-step::before { content: ""; position: absolute; top: 7px; right: 50%; width: 100%; height: 2px; background: var(--line); }
.rail-step:first-child::before { display: none; }
.rail-step.done::before, .rail-step.now::before { background: var(--ink); }
.rail-step i { position: relative; z-index: 1; width: 16px; height: 16px; border-radius: 50%; background: var(--line); }
.rail-step.done i { background: var(--ink); }
.rail-step.now i { background: var(--ink); box-shadow: 0 0 0 3px var(--card), 0 0 0 5px var(--ink); }
.rail-step.now { color: var(--ink); font-weight: 600; }
.rail-said { margin: 12px 0 0; font: 600 14px/1.35 var(--font-body); }
.rail-said.is-goal { color: var(--ok-ink); }
.rail-said.is-fail { color: var(--danger); }
.rail-said.is-cancel { color: var(--sub); }

/* Dokumen: the rail turned on its side — the deal's six rungs from quotation to payment, in the rail's own ink
   (passed filled — hollow when passed with nothing of its own —, current ringed, ahead pale; a rung reached only in
   part is ringed and half filled). The rupiah sit
   right, in tabular figures, so the column of money reads down the card. Read-only: no row is a target. */
.dl-said { margin: 8px 0 4px; font: 600 14px/1.35 var(--font-body); }
.dl { margin: 10px 0 0; padding: 0; list-style: none; }
.dl-rung { position: relative; display: flex; flex-direction: column; gap: 4px; padding: 0 0 14px 22px; }
.dl-rung::before { content: ""; position: absolute; left: 5px; top: 12px; bottom: -2px; width: 2px; background: var(--line); }
.dl-rung:last-child { padding-bottom: 2px; }
.dl-rung:last-child::before { display: none; }
.dl-rung.done::before { background: var(--ink); }
.dl-rung > i { position: absolute; left: 0; top: 3px; width: 12px; height: 12px; border-radius: 50%; background: var(--line); }
.dl-rung.done > i, .dl-rung.now > i { background: var(--ink); }
.dl-rung.now > i { box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--ink); }
.dl-rung.part > i { background: linear-gradient(90deg, var(--ink) 50%, var(--card) 50%); }
/* passed with nothing of its own (no quotation before the order, no picking list on a job order): the path goes on,
   the dot is hollow — never filled as if a document were there (chain Q2) */
.dl-rung.skip > i { background: var(--card); box-shadow: inset 0 0 0 2px var(--ink); }
.dl-rung.skip .dl-head > b { color: var(--sub); }
.dl-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.dl-head > b { font: 600 14px/1.3 var(--font-body); }
.dl-rung:not(.done):not(.now) .dl-head > b { color: var(--sub); }
.dl-fig { flex: none; font: 600 13px/1.3 var(--font-body); font-variant-numeric: tabular-nums; white-space: nowrap; }
.dl-doc { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; padding: 6px 0 2px; border-top: 1px solid var(--off); }
.dl-doc > div { min-width: 0; display: flex; flex-direction: column; gap: 2px; font-size: 12px; line-height: 1.4; }
.dl-doc .mono { font-size: 13px; overflow-wrap: anywhere; }
.dl-doc .dl-fig { font-weight: 400; color: var(--sub); }
.dl-detail { font-size: 12px; line-height: 1.4; }
.dl-goal { margin: 10px 0 0; font: 600 13px/1.35 var(--font-body); }

/* Tiket: one card per ticket, the whole card opens it. */
.tk { display: block; color: inherit; text-decoration: none; }
.tk:active { border-color: var(--sub); }
.tk > b { display: block; font: 600 15px/1.25 var(--font-body); overflow-wrap: anywhere; }
.tk > .mono { display: block; margin-top: 2px; font-size: 12px; }
.tk-goal { display: block; margin-top: 6px; font-size: 13px; line-height: 1.4; }
.tk-foot { display: flex; justify-content: space-between; gap: 8px; margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--off); font-size: 12px; color: var(--sub); }
.tk-foot .tone-warn { font-weight: 600; }
.stage-filter { min-height: 44px; margin-bottom: 10px; }

/* One ticket. The page is a column at least as tall as the screen (the 30px are the shell's own top and bottom
   breathing room), so its bar rests on the bottom of a short ticket and stays put while a long one scrolls. */
.tk-page { display: flex; flex-direction: column; min-height: calc(100dvh - var(--nav-h) - 30px); }
.tk-page > * { flex-shrink: 0; min-width: 0; }
.topbar .tk-title { font-size: 20px; line-height: 1.15; overflow-wrap: anywhere; }
/* The shell's round back button is 34px; here its hit box is the 44px a thumb needs. */
.back-hit { position: relative; flex: none; display: flex; }
.back-hit > button::after { content: ""; position: absolute; inset: -5px; }
.state-note { margin: 0 2px 10px; font-size: 13px; line-height: 1.45; color: var(--sub); }
.kv { display: flex; flex-direction: column; gap: 2px; }
.kv + .kv { margin-top: 10px; }
.kv > span:first-child { font-size: 12px; color: var(--sub); }
.kv > b { font: 600 15px/1.3 var(--font-body); overflow-wrap: anywhere; }
.kv-foot { margin: 10px 0 0; padding-top: 9px; border-top: 1px solid var(--off); font-size: 12px; }
.tk-line { margin: 0; font-size: 14px; line-height: 1.45; }
.fu-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; padding: 9px 0; }
.fu-row + .fu-row { border-top: 1px solid var(--off); }
.fu-row > div { min-width: 0; display: flex; flex-direction: column; gap: 2px; font-size: 12px; line-height: 1.4; }
.fu-row b { font: 600 14px/1.3 var(--font-body); }
.fu-row > .pill { flex: none; }
/* The history, newest first: a line down the side, a mark per activity. */
.act { position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 4px; margin-left: 5px; padding: 2px 0 14px 16px; border-left: 2px solid var(--line); }
.act::before { content: ""; position: absolute; left: -6px; top: 4px; width: 10px; height: 10px; border-radius: 50%; background: var(--ink); box-shadow: 0 0 0 3px var(--card); }
.act:last-of-type { padding-bottom: 2px; }
.card h2 + .act { margin-top: 8px; }
.act > b { font: 600 13px/1.3 var(--font-body); }
.act > span { font-size: 12px; line-height: 1.4; }
.act > .pill { font-size: 11px; line-height: 1.3; border-radius: 9px; }
.act-note { margin: 0; font-size: 13px; line-height: 1.45; white-space: pre-line; overflow-wrap: anywhere; }
.photo-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 2px; font-size: 12px; }
.photo { flex: none; display: block; width: 56px; height: 56px; overflow: hidden; border-radius: 9px; border: 1px solid var(--line); background: var(--off); }
.photo img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* What may be done with the ticket: one ledge above the bar of tabs, two controls. Its ground runs on under the
   tabs, so nothing of the page shows beside the round button that stands out of them. */
.actbar {
    position: sticky; bottom: 0; z-index: 4; display: flex; gap: 8px;
    margin: auto -14px calc(-1 * (var(--nav-h) + 18px));
    padding: 10px 14px calc(var(--nav-h) + 18px + env(safe-area-inset-bottom));
    background: var(--bg); border-top: 1px solid var(--line);
}
.actbar .btn { flex: 1; display: flex; align-items: center; justify-content: center; width: auto; text-decoration: none; white-space: nowrap; }
.actbar .btn.ghost { flex: none; min-width: 104px; padding: 13px 18px; }

/* The bottom sheet of the CRM screens: a title, what it is about, a body, one button. */
.sheet-backdrop { position: fixed; inset: 0; z-index: 50; display: flex; align-items: flex-end; justify-content: center; }
.sheet-backdrop::before { content: ""; position: absolute; inset: 0; background: var(--ink); opacity: .45; animation: crm-fade-in .18s ease-out both; }
.sheet {
    position: relative; width: 100%; max-width: 520px; max-height: 88dvh; overflow-y: auto;
    padding: 18px 16px calc(18px + env(safe-area-inset-bottom)); border-radius: 18px 18px 0 0;
    background: var(--card); outline: 0; animation: crm-sheet-in .2s ease-out both;
}
.sheet-title { display: block; font: 600 19px/1.2 var(--font-display); }
.sheet-sub { display: block; margin-top: 3px; font-size: 12px; line-height: 1.4; color: var(--sub); overflow-wrap: anywhere; }
.sheet-acts { margin-top: 16px; }
.sheet-row {
    display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; min-height: 52px; padding: 0 2px;
    border: 0; border-top: 1px solid var(--off); background: none; color: var(--ink);
    font: 500 15px var(--font-body); text-align: left; cursor: pointer;
}
.sheet-row:first-of-type { margin-top: 12px; }
.sheet-row::after { content: "›"; color: var(--sub); font-size: 18px; }
.lbl { display: block; margin: 14px 0 5px; font-size: 12px; color: var(--sub); }
.opts { margin-top: 12px; }
.opt {
    display: flex; align-items: center; gap: 11px; width: 100%; min-height: 48px; padding: 8px 12px;
    border: 1px solid var(--line); border-radius: 10px; background: var(--card); color: var(--ink);
    font: 500 14px var(--font-body); text-align: left; cursor: pointer;
}
.opt + .opt { margin-top: 8px; }
.opt > i { flex: none; width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--line); }
.opt.on { border-color: var(--ink); font-weight: 600; }
.opt.on > i { border-color: var(--ink); background: var(--ink); box-shadow: inset 0 0 0 3px var(--card); }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
    min-height: 44px; padding: 0 16px; border: 1px solid var(--line); border-radius: 999px;
    background: var(--card); color: var(--ink); font: 500 14px var(--font-body); cursor: pointer;
}
.chip.on { background: var(--ink); border-color: var(--ink); color: var(--card); }
.chips.invalid .chip { border-color: var(--danger); }
@keyframes crm-sheet-in { from { transform: translateY(28px); opacity: 0; } }
@keyframes crm-fade-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .sheet, .sheet-backdrop::before { animation: none; } }

/* A page opened cold (from the icon, a link, a typed address) has its title focused by the router so a screen reader
   announces it, and the browser then draws its focus ring around the title. Under AKM CRM's bar the title takes
   the focus without the ring; a browser that does not know :has() keeps the ring and loses nothing else. */
.shell:has(> .bottom-nav[aria-label="Menu AKM CRM"]) h1:focus { outline: 0; }

/* Customer. The search is the screen: it stays at the top while the list runs under it, on the page's own ground.
   The list is one card of rows — a name, its code, how many people are known there. The part of a name that was
   typed is underlined in ink: why the row is in the answer, without a colour. */
.search { position: sticky; top: 0; z-index: 3; margin: 0 -14px 4px; padding: 7px 14px; background: var(--bg); }
.search > svg {
    position: absolute; left: 27px; top: 50%; width: 18px; height: 18px; margin-top: -9px;
    fill: none; stroke: var(--sub); stroke-width: 2; stroke-linecap: round; pointer-events: none;
}
.search > .field { min-height: 48px; padding: 11px 46px 11px 40px; border-radius: 9px; -webkit-appearance: none; appearance: none; }
.search > .field::-webkit-search-cancel-button, .search > .field::-webkit-search-decoration { display: none; }
.search-clear {
    position: absolute; right: 16px; top: 50%; width: 44px; height: 44px; margin-top: -22px; padding: 0;
    border: 0; background: none; color: var(--sub); font: 400 24px/1 var(--font-body); cursor: pointer;
}
.party {
    display: flex; align-items: center; gap: 10px; min-height: 56px; padding: 9px 0;
    border-bottom: 1px solid var(--off); color: inherit; text-decoration: none;
}
.party:last-child { border-bottom: 0; }
.party:active { opacity: .6; }
.party::after { content: "›"; flex: none; color: var(--sub); font-size: 18px; }
.party-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.party-main > b { font: 600 15px/1.25 var(--font-body); overflow-wrap: anywhere; }
.party-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 7px; font-size: 12px; line-height: 1.4; color: var(--sub); overflow-wrap: anywhere; }
.topbar .party-meta { margin-top: 3px; }
.party-pics { flex: none; font-size: 12px; color: var(--sub); font-variant-numeric: tabular-nums; }
.hit { background: none; color: inherit; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }

/* One customer: whom to talk to. The number is the one thing on the row that does something — it dials — so it is
   the one thing with a border; a number too long for the row goes under the name, never off the card. */
.pic-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 10px; min-height: 56px; padding: 6px 0; border-top: 1px solid var(--off); }
.card h2 + .pic-row { border-top: 0; }
.pic-who { flex: 1 1 110px; min-width: 0; display: flex; flex-direction: column; gap: 2px; font-size: 12px; line-height: 1.4; }
.pic-who > b { font: 600 14px/1.3 var(--font-body); overflow-wrap: anywhere; }
.tel {
    flex: 0 1 auto; display: inline-flex; align-items: center; gap: 7px; min-height: 44px; max-width: 100%; padding: 6px 12px;
    border: 1px solid var(--line); border-radius: 10px; background: var(--card); color: var(--ink);
    font-size: 13px; line-height: 1.3; text-decoration: none; overflow-wrap: anywhere;
}
.tel:active { border-color: var(--sub); }
.tel > svg { flex: none; width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.tel-text { max-width: 100%; font-size: 13px; line-height: 1.3; overflow-wrap: anywhere; }
/* Another salesman already has an open ticket here: a sentence, as wide as the page, in the pill's own tones. */
.other-note { display: block; margin: 0 0 10px; padding: 9px 12px; border-radius: 10px; font-size: 12px; font-weight: 500; line-height: 1.45; }
.sheet .other-note { margin: 14px 0 0; }

/* The sheets of Customer: a field is a thumb's target; the list of similar names is rows, each with its own way on. */
.sheet .field { min-height: 46px; }
.sheet input[type="date"].field { display: block; -webkit-appearance: none; appearance: none; }
.sheet-lead { margin: 12px 0 2px; font-size: 14px; line-height: 1.45; }
button.mini { cursor: pointer; }

/* Catat kunjungan. Where the phone is, is the first line under the title — a status on every view, never an alarm.
   Then the form in the order it is filled: the target, whom, what was said. Everything else is behind one door
   that says in a sentence what it holds while it is shut, so Simpan is never a guess. */
.gps-line { min-height: 23px; margin: 0 2px 10px; }
.gps-line .pill { border-radius: 9px; line-height: 1.3; }
.visit .field { min-height: 46px; }
.visit .search > .field { min-height: 48px; }
.visit .card > .lbl:first-child { margin-top: 0; }
.target { padding-top: 8px; padding-bottom: 8px; }
.target-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.target-who { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.target-kind { font-size: 12px; color: var(--sub); }
.target-who > b { font: 600 15px/1.3 var(--font-body); overflow-wrap: anywhere; }
.target-row > .linkish { display: inline-flex; align-items: center; justify-content: flex-end; min-width: 44px; min-height: 44px; font-size: 13px; }
.target-note { margin: 2px 0 4px; font-size: 12px; line-height: 1.4; color: var(--sub); }
/* The one chip that is not a person: it adds one. */
.chip.add { border-style: dashed; color: var(--sub); }
.more {
    position: relative; display: flex; flex-direction: column; justify-content: center; gap: 3px; width: 100%; min-height: 56px;
    margin: 0 0 10px; padding: 10px 46px 10px 15px; border: 1px solid var(--line); border-radius: 10px;
    background: var(--card); color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.more > b { font: 600 15px/1.25 var(--font-body); }
.more > span { font-size: 12px; line-height: 1.45; color: var(--sub); overflow-wrap: anywhere; }
.more::after {
    content: ""; position: absolute; right: 19px; top: 50%; width: 8px; height: 8px; margin-top: -7px;
    border-right: 2px solid var(--sub); border-bottom: 2px solid var(--sub); transform: rotate(45deg);
}
.more[aria-expanded="true"] { margin-bottom: 0; border-bottom-color: var(--off); border-radius: 10px 14px 0 0; }
.more[aria-expanded="true"]::after { margin-top: -2px; transform: rotate(-135deg); }
.more-body { margin: 0 0 10px; padding: 0 15px 15px; border: 1px solid var(--line); border-top: 0; border-radius: 0 0 14px 14px; background: var(--card); }
.more-body input[type="date"].field, .more-body input[type="datetime-local"].field { display: block; -webkit-appearance: none; appearance: none; }
/* A chosen photo: seen, how heavy it is, and the way to take it out again. The button under them IS the file
   input — it lies over the label, unseen, so the tap that opens the camera is the thumb's own. */
.shot { display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 6px 0; border-bottom: 1px solid var(--off); font-size: 13px; }
.shot > .muted { flex: 1; min-width: 0; font-variant-numeric: tabular-nums; }
.add-shot { position: relative; margin-top: 10px; }
.add-shot input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.add-shot:focus-within { outline: 3px solid var(--ink); outline-offset: 2px; }
.more-body .cut-note { margin: 10px 0 0; }

/* What waits on this phone, on Hari ini: a visit that has not reached the server is shown as what it is — whose it
   is, what was written, where it stands and why — with its ways on in a row of their own. */
.outbox-row { display: flex; flex-direction: column; gap: 4px; padding: 12px 0; border-bottom: 1px solid var(--off); }
.outbox-row:last-child { border-bottom: 0; }
.outbox-row > b { font: 600 14px/1.25 var(--font-body); overflow-wrap: anywhere; }
.outbox-row > span { font-size: 12px; line-height: 1.4; }
.outbox-notes { margin: 0; font-size: 13px; line-height: 1.45; overflow-wrap: anywhere; }
.outbox-state { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin-top: 2px; font-size: 12px; line-height: 1.4; }
.outbox-state > .pill { flex: none; }
.outbox-acts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }

/* A page title takes focus when the route changes (screen readers announce it); the ring on a heading nobody can
   press is noise, so only controls show one. */
.shell-main h1:focus, .shell-main h1:focus-visible { outline: none; }

/* ---- charts ---- the report kit (BarMeter, LineTrend, ColumnChart). Tokens only; the text under every drawing says the
   same thing as the drawing, so colour is a hint, never the message. */
.ch-meter { display: block; width: 100%; height: 8px; }
.ch-track { fill: var(--off); }
.ch-fill { fill: var(--signal); }
.ch-fill.ok { fill: var(--ok); }
.ch-fill.warn { fill: var(--warn-ink); }
.ch-fill.danger { fill: var(--danger); }

.ch-line-box, .ch-cols { display: block; width: 100%; height: auto; overflow: visible; }
.ch-axis { stroke: var(--line); stroke-width: 1; }
.ch-line { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.ch-line.now { stroke: var(--ink); stroke-width: 2.2; }
.ch-line.before { stroke: var(--sub); stroke-width: 1.6; stroke-dasharray: 4 3; }
.ch-dot.now { fill: var(--ink); }
.ch-dot.before { fill: var(--sub); }
.ch-col { fill: var(--sub); }
.ch-col.on { fill: var(--signal); }
.ch-text { fill: var(--sub); font: 500 10px var(--font-body); }
.ch-text.end { fill: var(--ink); font-weight: 600; }
.ch-spark { display: block; width: 96px; height: 30px; overflow: visible; }
.ch-line.spark { stroke: var(--ink); stroke-width: 1.6; }

/* ---- AKM CRM: Laporan (crm/laporan) — the figure is the signature: big tabular numbers, the percent beside them in
   text, a bar only where a target exists. Everything else stays quiet. ---- */
.rp-step { display: flex; gap: 6px; }
.rp-step .icon-btn { font: 600 22px/1 var(--font-body); color: var(--ink); }
.rp-step .icon-btn:disabled { color: var(--line-strong); cursor: default; }
.rp-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px; }
.rp-head .sec { margin-bottom: 9px; }
.rp-asof { margin: 0 0 10px; font-size: 12px; color: var(--sub); }
.rp-asof b { color: var(--ink); font-variant-numeric: tabular-nums; }
.rp-small { display: block; font-size: 12px; }
.rp-metric { padding: 10px 0 12px; border-top: 1px solid var(--line); }
.rp-perf .rp-asof + .rp-metric { border-top: 0; padding-top: 0; }
.rp-metric-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.rp-metric-label { font-size: 13px; color: var(--sub); }
.rp-pct { font: 600 15px var(--font-display); color: var(--signal); font-variant-numeric: tabular-nums; }
.rp-pct.met { color: var(--ok); }
.rp-figure { margin: 2px 0 7px; overflow-wrap: anywhere; }
.rp-figure > b { font: 600 24px/1.15 var(--font-display); font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.rp-figure .muted { font-size: 13px; }
.rp-delta { display: block; margin-top: 6px; font-size: 12px; color: var(--sub); }
.rp-metric.compact { padding: 6px 0; border-top: 0; }
.rp-metric-row { display: grid; grid-template-columns: 1fr auto 3.2rem; align-items: baseline; gap: 8px; font-size: 13px; }
.rp-metric-row > b { font-variant-numeric: tabular-nums; text-align: right; }
.rp-metric-row .rp-pct { font-size: 13px; }
.rp-metric.compact .ch-meter { margin-top: 4px; height: 5px; }
.rp-win { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; padding-top: 10px; border-top: 1px solid var(--line); }
.rp-win b { font: 600 16px var(--font-display); font-variant-numeric: tabular-nums; }
.rp-trend .chips { margin: 8px 0 10px; }
.rp-legend { display: flex; align-items: center; gap: 6px; margin: 6px 0 0; font-size: 12px; color: var(--sub); }
.rp-key { display: inline-block; width: 18px; height: 0; border-top: 2px solid var(--ink); }
.rp-key.before { margin-left: 10px; border-top: 2px dashed var(--sub); }
.rp-nums { margin-top: 10px; font-size: 13px; }
.rp-nums summary { min-height: 44px; display: flex; align-items: center; color: var(--accent); font-weight: 600; cursor: pointer; }
.rp-nums table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.rp-nums th, .rp-nums td { padding: 5px 0; text-align: right; border-bottom: 1px solid var(--line); }
.rp-nums th:first-child, .rp-nums td:first-child { text-align: left; }
.rp-nums th { font-weight: 600; color: var(--sub); }
.rp-step-list { margin-top: 10px; }
.rp-step-title { display: block; margin-bottom: 4px; font-size: 12px; font-weight: 600; color: var(--sub); }
.rp-step-row { display: grid; grid-template-columns: 7.5rem 1fr 2.5rem; align-items: center; gap: 10px; padding: 4px 0; font-size: 13px; }
.rp-step-row b { text-align: right; font-variant-numeric: tabular-nums; }
.rp-step-row .ch-fill { fill: var(--sub); }
.rp-days { display: flex; margin-top: 8px; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.rp-day {
    flex: 1; min-width: 0; min-height: 52px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    border: 0; border-left: 1px solid var(--line); background: var(--card); color: var(--sub); font: 500 11px var(--font-body); cursor: pointer; padding: 0;
}
.rp-day:first-child { border-left: 0; }
.rp-day b { font: 600 15px var(--font-display); color: var(--ink); font-variant-numeric: tabular-nums; }
.rp-day.on { background: var(--signal-wash); color: var(--signal-deep); box-shadow: inset 0 -3px 0 var(--signal); }
.rp-day:focus-visible { outline: 2px solid var(--signal); outline-offset: -2px; }
.rp-day-title { margin: 14px 0 4px; font: 600 14px var(--font-display); }
.rp-visit { display: flex; flex-direction: column; gap: 2px; padding: 9px 0; border-top: 1px solid var(--line); color: inherit; text-decoration: none; font-size: 13px; }
a.rp-visit { min-height: 44px; }
.rp-team-name { display: block; font: 600 15px var(--font-display); margin-bottom: 2px; }
.rp-team .rp-small { margin-top: 4px; }
.rp-total { border-color: var(--line-strong); background: var(--signal-wash); }
.rp-day .rp-queued { font: 600 10px/1 var(--font-body); font-style: normal; color: var(--warn-ink); }
.rp-queue-note { margin: 6px 0 2px; padding: 8px 10px; border: 1px solid var(--warn-line); border-radius: 8px; background: var(--warn-bg); color: var(--warn-deep); font-size: 12px; }
/* "Customer perlu perhatian" (M2): one row per customer — the status in words beside its dot, the reasons, the facts
   behind them, the order line with its figure in words, and the visit button. Worst first, so the eye starts at the top. */
.rp-att .rp-asof { margin-bottom: 4px; }
.rp-att-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 12px; padding: 12px 0; border-top: 1px solid var(--line); }
.rp-att .rp-asof + .rp-att-row { border-top: 0; padding-top: 6px; }
.rp-att-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rp-att-name { font: 600 15px/1.25 var(--font-display); overflow-wrap: anywhere; }
.rp-att-why { font-size: 13px; color: var(--ink); }
.rp-att-spark { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; text-align: right; }
.rp-att-spark b { font-variant-numeric: tabular-nums; }
.rp-att-acts { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: flex-start; gap: 4px 14px; margin-top: 6px; }
.rp-att-acts .rp-nums { flex: 1 1 10rem; margin-top: 0; }
.rp-status { display: inline-flex; align-items: center; gap: 6px; font: 600 12px var(--font-body); color: var(--sub); }
.rp-dot { flex: none; width: 9px; height: 9px; border-radius: 50%; background: currentColor; }
.rp-status.danger { color: var(--danger); }
.rp-status.danger .rp-dot { box-shadow: 0 0 0 3px var(--off); }
.rp-status.warn { color: var(--warn-ink); }
.rp-status.ok { color: var(--ok); }
.rp-att-team { display: flex; flex-direction: column; gap: 3px; padding: 10px 0; border-top: 1px solid var(--line); }
.rp-att .rp-asof + .rp-att-team { border-top: 0; padding-top: 4px; }
.rp-att-team-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: 13px; }
.rp-att-team-head > b { font: 600 15px var(--font-display); }
.rp-att-team-head b { font-variant-numeric: tabular-nums; }
.rp-att-team-head > span { white-space: nowrap; }
.rp-att-calm { margin-top: 0; }
.rp-att-team .rp-small .rp-status { margin-right: 6px; }
.rp-att-total { border-top: 1px solid var(--line-strong); }
/* Tap-through: a figure, a step row or a Tim figure is a button that opens the rows behind it in a sheet. At rest it
   looks as it did — only a quiet chevron says it opens; pressed, it takes the signal wash. In the sheet the sum leads,
   set like the card's figure, because it IS that figure. */
.rp-open {
    width: 100%; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
    -webkit-tap-highlight-color: transparent; border-radius: 6px;
}
.rp-open:active { background: var(--signal-wash); }
.rp-open:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.rp-figure.rp-open { display: flex; flex-wrap: wrap; align-items: baseline; min-height: 44px; padding: 0; }
.rp-figure.rp-open::after { content: "›"; margin-left: auto; padding-left: 8px; color: var(--sub); font-size: 20px; }
.rp-metric-row.rp-open { grid-template-columns: 1fr auto 3.2rem .7rem; min-height: 44px; padding: 0; }
.rp-metric-row.rp-open::after, .rp-step-row.rp-open::after { content: "›"; color: var(--sub); font-size: 16px; text-align: right; }
.rp-step-row.rp-open { grid-template-columns: 7.5rem 1fr 2.5rem .7rem; min-height: 44px; }
.rp-link {
    min-height: 44px; padding: 0 2px; border: 0; background: none; color: var(--accent); font: 600 13px var(--font-body);
    font-variant-numeric: tabular-nums; cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
}
.rp-drill-sum { display: flex; flex-direction: column; gap: 2px; margin: 14px 0 6px; }
.rp-drill-sum > b { font: 600 26px/1.15 var(--font-display); font-variant-numeric: tabular-nums; letter-spacing: -.01em; overflow-wrap: anywhere; }
.rp-drill-sum > .muted { font-size: 12px; }
.rp-drill-row {
    display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 8px 2px; border-top: 1px solid var(--line); font-size: 13px;
}
.rp-drill-row.rp-open { border-radius: 0; }
.rp-drill-row.rp-open::after { content: "›"; color: var(--sub); font-size: 18px; }
.rp-drill-main { display: flex; flex: 1; flex-direction: column; gap: 2px; min-width: 0; }
.rp-drill-main > b { font-weight: 600; overflow-wrap: anywhere; }
.rp-drill-main > .muted { font-size: 12px; overflow-wrap: anywhere; }
.rp-drill-value { flex: none; font-variant-numeric: tabular-nums; }
.rp-drill-note { margin: 12px 0; font-size: 13px; line-height: 1.45; }
