/* Satusetir app UI — shared shell for the product screens (dummy, no backend).
   Same brand as the marketing site, but tuned for daily operator use:
   larger controls, quieter surfaces, numbers in tabular figures. */

@font-face {
  font-family: "Plus Jakarta Sans";
  src: url("/assets/fonts/plus-jakarta-sans-latin.woff2?v=cd8db90cd950") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --blue-400: #12b8f8;
  --blue-600: #0a5cf0;
  --blue-700: #0847d6;
  --blue-800: #0433b8;
  --green-400: #3ee39b;
  --navy-950: #0b1628;
  --navy-900: #111f36;
  --slate-700: #344054;
  --slate-600: #475467;
  --slate-500: #5b6472;
  --slate-400: #8793a5;
  --slate-300: #cfd6e1;
  --slate-200: #e3e8ef;
  --slate-100: #f1f4f8;
  --paper: #ffffff;
  --ground: #f7f9fc;
  --ok: #067647;
  --ok-soft: #e7f8ee;
  --crit: #c01048;
  --crit-soft: #fdecf1;
  --warn: #b54708;
  --warn-deep: #7a3a09;
  --warn-soft: #fff4e5;
  --radius: 14px;
  --font: "Plus Jakarta Sans", "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;

  /* Aliases. These names are used by rules copied in from the ops stylesheet;
     without them the declarations resolve to nothing and are DROPPED, which is
     how a focus ring and four image borders disappeared silently. */
  --brand: var(--blue-600);
  --brand-100: var(--blue-100, #dbe4fb);
  --line: var(--slate-200);
  --mute: var(--slate-600);
  --ink: var(--navy-950);
  /* blue-600: 5,3:1 on white; blue-400 was 2,3:1 and failed WCAG 1.4.11 (qa-ux 2026-09-29) */
  --focus: 3px solid var(--blue-600);

  /* The type scale (Steph 2026-10-15, batch 2): five sizes on the 4px grid.
     12 caption / chip, 14 body and list title (16 in a phone's inputs),
     16 section heading (700), 28 page title (20 on a phone), 24 hero figure
     (800; 22 at 360px and under). No half-pixel sizes, no vw sizes: a new
     rule takes one of these. */
  --fs-caption: 12px;
  --fs-body: 14px;
  --fs-head: 16px;
  --fs-title: 28px;
  --fs-hero: 24px;
}
@media (max-width: 759px) { :root { --fs-title: 20px; } }
@media (max-width: 360px) { :root { --fs-hero: 22px; } }

/* iOS must not enlarge text on its own when the phone turns sideways. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
/* Three weights only: the browser's bolder would make a bold inside a 700 line 900, and its own 13.33px made a bare control a sixth size. */
b, strong { font-weight: 700; }
input, select, textarea { font-size: var(--fs-body); }
button { font-size: var(--fs-caption); }

* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-head);
  line-height: 1.6;
  color: var(--navy-950);
  background: var(--ground);
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }

/* ---------- No box wider than its column (Steph 2026-10-20) ----------
   Every app page, every width, by construction rather than page by page
   (the phone overflowed again and again: Retur, Pesanan, Restok). Zero
   specificity (:where), so a page's own rule still wins.
   1. Seller text breaks where it must. A grid or flex item is never
      narrower than its min-content, and one word that cannot break (a
      title "Tumbler/Termos/.../1000ml", a SKU code, an order number, a shop
      name with no space) made that the screen and more. "anywhere" breaks
      it and lowers the min-content too (break-word does not). A table in
      a scroller (.dt-wrap, .tbl-scroll) keeps its words whole and scrolls;
      a table with nowhere to scroll breaks like the rest.
   2. A table, even inside its own scroller, still hands its width up as
      min-content to every grid or flex item around it (min-width: auto):
      every box holding one may shrink. fieldset's own min-width:
      min-content is the same trap.
   3. Media never wider than its box.
   Text that must not break (white-space: nowrap: figures, chips) is the
   page's to fit; cmd/api/overflow_hp_test.go walks every page of the router
   at 320, 375, 768 and 1280px with long data and fails the build on anything past the
   edge, text runs included. */
:where(body.app) { overflow-wrap: anywhere; }
:where(body.app) :where(.dt-wrap, .tbl-scroll) :where(table) { overflow-wrap: break-word; }
:where(body.app) :where(fieldset, :has(table, .dt-wrap, .tbl-scroll)) { min-width: 0; }
:where(body.app) :where(img, svg, video, canvas, iframe) { max-width: 100%; }
/* 4. A label that does not fit wraps instead of running off. The shop mark
      at every width: a shop name has no length limit, and one nowrap mark
      (a 60-character TikTok shop name) held the Promo list's name column at
      435px and the table past a 768px and a 1280px screen. On a phone
      status pills and badges too. Nothing changes where they fit; strips
      that scroll (tabs, chips) keep their own nowrap. */
body.app .mk { max-width: 100%; white-space: normal; }
@media screen and (max-width: 759px) {
  body.app .state, body.app .grp-badge, body.app .kurang-chip, body.app .pr-pill, body.app .pill { max-width: 100%; white-space: normal; }
  /* The Pengiriman Kilat chip is a sentence, not a code (0219): it wraps inside its box, on the booking page and Terima & cetak too. */
  body.app .svc-kilat { max-width: 100%; white-space: normal; overflow-wrap: anywhere; }
  body.app .pl-st { flex-wrap: wrap; }
}
a { color: var(--blue-600); }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
  outline: 3px solid var(--blue-400); outline-offset: 2px; border-radius: 8px;
}

/* ---------- auth shell ---------- */
.auth { min-height: 100dvh; display: grid; grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr); }
@media (max-width: 900px) { .auth { grid-template-columns: minmax(0, 1fr); } }

/* brand side */
.side {
  background:
    radial-gradient(700px 380px at 20% 0%, rgba(18, 184, 248, 0.22), transparent 62%),
    linear-gradient(160deg, var(--navy-950), #0b2a6b 92%);
  color: #fff; padding: 48px 56px; display: flex; flex-direction: column; gap: 40px;
}
@media (max-width: 900px) { .side { padding: 22px; gap: 20px; } }
.side .brand { display: inline-flex; align-items: center; gap: 10px; color: #fff; text-decoration: none; font-weight: 700; font-size: var(--fs-hero); letter-spacing: -0.02em; }
.side .brand img { width: 34px; height: 34px; }
.pitch { margin: auto 0; max-width: 30ch; }
.pitch .pitch-title { font-size: var(--fs-title); line-height: 1.1; letter-spacing: -0.035em; margin: 0 0 14px; text-wrap: balance; }
.pitch p { color: #c7d2e3; margin: 0; font-size: var(--fs-head); }
@media (max-width: 900px) { .pitch { display: none; } }

/* form side */
.panel { background: var(--paper); display: flex; align-items: center; justify-content: center; padding: 24px; }
@media (max-width: 900px) {
  /* The brand bar keeps its own height and the form starts under it; a short
     form (Lupa sandi, Cek email Anda) no longer floats mid-screen. */
  .auth { grid-template-rows: auto 1fr; }
  .panel { padding: 28px 20px 40px; align-items: flex-start; }
}
.form-wrap { width: 100%; max-width: 400px; }
.form-wrap .form-title { font-size: var(--fs-title); letter-spacing: -0.03em; margin: 0 0 4px; }
.form-wrap .lede { color: var(--slate-600); margin: 0 0 18px; font-size: var(--fs-head); }

form { display: grid; gap: 4px; }
label { font-size: var(--fs-body); font-weight: 700; color: var(--slate-700); margin-top: 8px; }
input[type="text"], input[type="email"], input[type="password"] {
  font: inherit; font-size: var(--fs-head); width: 100%; min-height: 44px;
  color: var(--navy-950); background: #fff;
  border: 1px solid var(--slate-300); border-radius: 10px; padding: 12px 14px;
}
input::placeholder { color: var(--slate-400); }
input:hover { border-color: var(--slate-400); }
.hint { font-size: var(--fs-caption); color: var(--slate-500); margin: 5px 0 0; }
.hint.error { color: var(--crit); }

.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; width: 100%; font: inherit; font-weight: 700; font-size: var(--fs-head); min-height: 48px; border-radius: 11px; border: 0; cursor: pointer; text-decoration: none; padding: 12px 18px; }
.btn-primary { margin-top: 14px; color: #fff; background: var(--blue-600); box-shadow: 0 10px 22px -12px rgba(10, 92, 240, 0.8); }
.btn-primary:hover { background: var(--blue-700); }
.btn-google { margin-top: 10px; color: var(--navy-950); background: #fff; border: 1px solid var(--slate-300); }
.btn-google:hover { background: var(--slate-100); }
.btn-google svg { width: 18px; height: 18px; }

.row-between { display: flex; align-items: center; min-height: 24px; justify-content: space-between; gap: 12px; margin-top: 14px; font-size: var(--fs-body); }
.row-between .check { margin-top: 0; }
/* Inline text links need vertical padding to clear the 24px target minimum.
   :not(.btn) matters — without it this rule overrides the button's flex layout
   and the icon/label stop centring. */
.form-wrap a:not(.btn), .legal a:not(.btn), .alt a:not(.btn), .check a:not(.btn) { display: inline-block; padding-block: 3px; }
.check { display: inline-flex; align-items: flex-start; gap: 10px; font-size: var(--fs-body); color: var(--slate-600); margin-top: 12px; line-height: 1.5; min-height: 24px; cursor: pointer; }
/* 22px box plus the label's own height keeps the whole control past the 24px minimum. */
.check input { width: 24px; height: 24px; margin-top: 1px; accent-color: var(--blue-600); flex: none; cursor: pointer; }

.divider { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px; margin: 14px 0 0; color: var(--slate-500); font-size: var(--fs-body); }
.divider::before, .divider::after { content: ""; height: 1px; background: var(--slate-200); }

.alt { margin: 18px 0 0; font-size: var(--fs-head); color: var(--slate-600); text-align: center; }
.legal { margin: 18px 0 0; font-size: var(--fs-caption); color: var(--slate-500); text-align: center; }

/* a notice strip above the form, e.g. the dummy-state banner */
.notice { background: var(--ok-soft); color: #044f30; border-radius: 10px; padding: 10px 12px; font-size: var(--fs-body); margin-bottom: 22px; }
.notice.warn { background: #fff4e5; color: #7a3a09; }

/* phone header replacing the brand panel */
.top-brand { display: none; }
@media (max-width: 900px) {
  .top-brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: var(--fs-hero); color: #fff; }
  .top-brand img { width: 30px; height: 30px; }
}

/* ---------- app shell (signed-in screens) ---------- */
body.app { background: var(--ground); }
/* Full-width app shell. Operator tools are read as tables, not as articles: the
   width is where the extra rows and columns go. The 2100px cap only bites on
   ultrawide monitors, where a truly edge-to-edge row stops being scannable. */
.app-wrap { width: 100%; max-width: 2100px; margin: 0 auto; padding-inline: 22px; }
@media (min-width: 1200px) { .app-wrap { padding-inline: 32px; } }
.app-bar { background: var(--paper); border-bottom: 1px solid var(--slate-200); position: sticky; top: 0; z-index: 10; }
/* A link to a heading (a pager's #h-..., Toko's #h-tarif) lands below the
   62px bar, not under it. catalog.css had this for Produk only (QA 2026-10-11). */
:target { scroll-margin-top: 76px; }
.app-bar .app-wrap { display: flex; align-items: center; gap: 22px; min-height: 62px; }
.app-bar .brand { display: inline-flex; align-items: center; gap: 9px; color: var(--navy-950); text-decoration: none; font-weight: 700; font-size: var(--fs-head); letter-spacing: -0.02em; }
/* margin-left keeps the account link at the right edge (the top bar has no
   horizontal nav any more, B1 2026-10-28). */
.who { display: inline-flex; align-items: center; gap: 9px; margin-left: auto; text-decoration: none; color: var(--slate-700); font-weight: 600; font-size: var(--fs-body); }
.avatar { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%; background: var(--navy-950); color: #fff; font-size: var(--fs-caption); font-weight: 700; }
.who-name { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 520px) { .who-name { display: none; } }

.page { padding-block: 26px 60px; }
.page-head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 14px; margin-bottom: 22px; }
.page-head h1 { font-size: var(--fs-title); letter-spacing: -0.03em; margin: 0; }
.page-head .sub { color: var(--slate-500); margin: 4px 0 0; font-size: var(--fs-body); }
.btn-quiet { width: auto; background: var(--paper); border: 1px solid var(--slate-300); color: var(--navy-950); font-size: var(--fs-body); min-height: 42px; padding: 10px 16px; }
.btn-quiet:hover { background: var(--slate-100); }

.kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 18px; }
/* The rail takes 248px from 1080 up, but this grid measures the viewport. At
   1080 the content box is 817px while the grid was still four columns, so a
   150px card had to hold 172px of nowrap rupiah and overflowed into the gap.
   Two columns until the content box is genuinely wide enough for four. */
@media (max-width: 1147px) { .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.kpi { background: var(--paper); border: 1px solid var(--slate-200); border-radius: var(--radius); padding: 16px; display: grid; gap: 2px; }
.kpi .k { font-size: var(--fs-caption); font-weight: 600; color: var(--slate-500); }
.kpi .v { font-size: var(--fs-hero); font-weight: 700; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.kpi .v.warn { color: var(--crit); }
.kpi .d { font-size: var(--fs-caption); color: var(--slate-500); font-weight: 600; }
.kpi .d.up { color: var(--ok); }

.cols { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 16px; align-items: start; }
@media (max-width: 900px) { .cols { grid-template-columns: minmax(0, 1fr); } }
.card { background: var(--paper); border: 1px solid var(--slate-200); border-radius: var(--radius); padding: 18px 20px; }
.card h2 { font-size: var(--fs-head); letter-spacing: -0.01em; margin: 0 0 14px; }

.tasks { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.task { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 12px; align-items: center; border-radius: 12px; padding: 12px 14px; background: var(--ground); font-size: var(--fs-body); }
.task .dot { width: 9px; height: 9px; border-radius: 50%; }
.task.crit { background: var(--crit-soft); } .task.crit .dot { background: var(--crit); }
.task.warn { background: #fff4e5; } .task.warn .dot { background: #b54708; }
.task.ok { background: var(--ok-soft); } .task.ok .dot { background: var(--ok); }
.task .meta { display: block; font-size: var(--fs-caption); color: var(--slate-600); font-weight: 400; }
.act { font-size: var(--fs-body); font-weight: 700; color: var(--blue-700); text-decoration: none; background: #fff; border-radius: 9px; padding: 8px 12px; white-space: nowrap; }
.task .act.done { color: var(--ok); background: transparent; }

.mini { width: 100%; border-collapse: collapse; font-size: var(--fs-body); }
.mini th, .mini td { text-align: left; padding: 10px 0; border-bottom: 1px solid var(--slate-200); font-weight: 600; }
.mini thead th { font-size: var(--fs-caption); letter-spacing: 0.05em; text-transform: uppercase; color: var(--slate-500); font-weight: 700; }
.mini tbody th { font-weight: 700; }
.mini td { text-align: right; font-variant-numeric: tabular-nums; }
.mini td:first-of-type { text-align: center; }
.mini .ch { display: inline-block; font-size: var(--fs-caption); font-weight: 700; color: var(--slate-600); background: var(--slate-100); border-radius: 999px; padding: 2px 8px; margin-left: 6px; }
.mini td { white-space: nowrap; }
/* Columns share a row with no cell padding, so they collide at phone widths. */
.mini th:not(:first-child), .mini td { padding-left: 12px; }
.mini thead th + th { text-align: center; }
.mini thead th:last-child { text-align: right; }
/* secondary figure under a row label, e.g. revenue beneath the shop name */
.mini .sub2 { display: block; font-size: var(--fs-caption); font-weight: 400; color: var(--slate-600); }
.mini tfoot th, .mini tfoot td { border-bottom: 0; padding-top: 13px; font-weight: 700; }

/* ---------- Hari ini dashboard ---------- */

/* Bypass block for the repeated app bar (WCAG 2.4.1). */
.skip { position: absolute; left: -9999px; top: 0; }
.skip:focus { left: 10px; top: 10px; z-index: 40; background: var(--paper); color: var(--navy-950); border: 2px solid var(--blue-600); border-radius: 10px; padding: 10px 14px; font-weight: 700; text-decoration: none; }

/* left: 0: at its static place an absolute box escapes a strip that scrolls (no positioned
   box between them) and a long chip put that place, and the page's width, past the screen. */
.vh { position: absolute; left: 0; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* Money must never break across lines, and always uses lining tabular figures. */
.rp { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* "Data contoh" — said once, in the page head, not on every card. */
.stamp { display: inline-block; margin-left: 8px; font-size: var(--fs-caption); font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--slate-700); background: var(--slate-100); border: 1px solid var(--slate-200); border-radius: 999px; padding: 3px 9px; white-space: nowrap; }

.stack { display: grid; gap: 26px; align-content: start; }
.cols > .stack { gap: 22px; }

.sec-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 14px; margin: 0 0 12px; }
.sec-head h2 { font-size: var(--fs-head); font-weight: 700; letter-spacing: -0.01em; margin: 0; }
/* :not(.btn) so this never reaches a link styled as a button and kills its flex centring. */
.more:not(.btn) { display: inline-block; padding-block: 4px; font-size: var(--fs-body); font-weight: 700; color: var(--blue-700); text-decoration: none; }
.more:not(.btn):hover { text-decoration: underline; }

/* a card whose only child is a full-bleed list */
.card-flush { padding: 8px; }

/* An inline SVG with no intrinsic size would lay out at 300x150 inside a flex button. */
.btn-quiet svg { width: 17px; height: 17px; flex: none; }
/* Scoped to the page head: other screens use .btn-quiet with labels that may need to wrap. */
.page-head .btn-quiet { white-space: nowrap; }

/* --- urgent queue --- */
/* Lead rows carry a time-left flag in the slot the plain .task uses for its dot. */
.task-lead { padding: 13px 14px; align-items: center; }
.task .flag { min-width: 64px; text-align: center; font-size: var(--fs-caption); font-weight: 700; font-variant-numeric: tabular-nums; background: var(--paper); border-radius: 8px; padding: 5px 7px; white-space: nowrap; line-height: 1.35; }
.task.crit .flag { color: var(--crit); }
.task.warn .flag { color: var(--warn-deep); }
.task.ok .flag { color: var(--ok); }
.task .txt b { display: block; }
.act:hover { text-decoration: underline; }
@media (max-width: 560px) {
  /* Drop the action onto its own row so the label keeps a readable measure. */
  .task { grid-template-columns: auto minmax(0, 1fr); row-gap: 9px; align-items: start; }
  .task-lead .flag { min-width: 56px; }
  .act { grid-column: 2; justify-self: start; }
  /* .act.done is a status, not a control — align it with the label above it. */
  .task .act.done { padding-left: 0; }
  .task .dot { margin-top: 7px; }
}

/* --- KPI extras --- */
.kpi .v { white-space: nowrap; }
.kpi .d a { white-space: nowrap; }
.spark { display: block; width: 100%; height: 30px; margin-top: 6px; color: var(--ok); }
.honest { font-size: var(--fs-body); line-height: 1.55; color: var(--slate-600); margin: 12px 0 0; max-width: 78ch; }
@media (max-width: 560px) {
  .kpi { padding: 14px; }
  .kpi .v { font-size: var(--fs-hero); }
  /* Lead figure and the completeness meter each want the full width. */
  .kpi.wide { grid-column: 1 / -1; }
}

/* --- proportion bars (values are always stated in text as well) --- */
.meter, .bar { display: block; height: 6px; border-radius: 999px; background: var(--slate-200); overflow: hidden; margin-top: 6px; }
.meter i, .bar i { display: block; height: 100%; border-radius: 999px; }
.meter i { background: var(--ok); }
.bar i { background: var(--crit); }
.f9 i { width: 9%; }
.f14 i { width: 14%; }
.f30 i { width: 30%; }
.f48 i { width: 48%; }
.f93 i { width: 93%; }

/* --- money leaks --- */
.leak { list-style: none; margin: 0; padding: 0; display: grid; gap: 15px; }
.leak li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 12px; }
.leak .lbl { font-size: var(--fs-head); font-weight: 700; }
.leak .amt { grid-column: 2; grid-row: 1; font-size: var(--fs-head); font-weight: 700; color: var(--crit); }
.leak .meta { grid-column: 1 / -1; font-size: var(--fs-caption); color: var(--slate-600); }
.leak .bar { grid-column: 1 / -1; margin-top: 5px; }

/* --- AI drafts: proposal, reasoning, then an approve step --- */
.draft { border: 1px solid var(--slate-200); border-radius: 12px; padding: 14px; display: grid; gap: 10px; }
.draft + .draft { margin-top: 12px; }
.draft .from { display: block; font-size: var(--fs-caption); font-weight: 700; color: var(--slate-600); margin-bottom: 5px; }
.draft .ask { margin: 0; font-size: var(--fs-body); background: var(--slate-100); border-radius: 10px; padding: 10px 12px; }
.draft .say { margin: 0; font-size: var(--fs-head); background: #eaf1ff; border-radius: 10px; padding: 11px 12px; }
.why { display: flex; align-items: flex-start; gap: 8px; margin: 0; font-size: var(--fs-caption); line-height: 1.5; color: var(--slate-600); }
.why svg { width: 16px; height: 16px; flex: none; margin-top: 2px; }
.acts { display: flex; flex-wrap: wrap; gap: 8px; margin: 2px 0 0; }
/* width/min-height only — display and justify-content stay with .btn. */

.acts .btn { margin-top: 0; }

/* --- restock suggestion with its arithmetic on show --- */
.item-title { font-size: var(--fs-head); font-weight: 700; margin: 0 0 12px; }
.item-title .ch { display: inline-block; font-size: var(--fs-caption); font-weight: 700; color: var(--slate-600); background: var(--slate-100); border-radius: 999px; padding: 2px 8px; margin-left: 6px; vertical-align: 2px; }
.facts { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 9px 14px; margin: 0; font-size: var(--fs-body); }
.facts dt { color: var(--slate-600); }
.facts dd { margin: 0; text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.verdict { background: var(--ok-soft); color: #044f30; border-radius: 10px; padding: 11px 13px; font-size: var(--fs-body); margin: 14px 0 0; }

/* --- navigation under 1080px (Steph 2026-10-15, option A; appnav.html) ---
   No tab bar: the top bar's menu button opens the menu sheet (the sidebar's
   own items and dots, the current page marked, at the bottom where a thumb
   reaches), the avatar opens the account sheet. Both are popovers: Esc, a tap
   outside and Android's back close them, focus goes in and comes back.
   nav.js gives a browser without popover the same through [data-open]; a
   selector with :popover-open is dropped whole by such a browser, so the
   two states are separate rules. From 1080px the sidebar and the account
   dropdown do this and none of it shows. */
.nav-btn, .who-btn, .bar-flag, .nav-sheet, .acct-sheet { display: none; }
.bar-back { display: none; }
@media (max-width: 1079px) {
  .nav-btn { display: grid; place-items: center; flex: none; width: 44px; height: 44px; margin-left: -10px; padding: 0; border: 0; border-radius: 10px;
    background: none; color: var(--navy-950); cursor: pointer; }
  .nav-btn svg { width: 24px; height: 24px; }
  .nav-btn:hover { background: var(--slate-100); }
  .who-wrap { display: none; }
  .who-btn { position: relative; display: inline-flex; align-items: center; gap: 9px; margin-left: auto; min-height: 44px; padding: 0 2px; border: 0;
    background: none; font: inherit; font-size: var(--fs-body); font-weight: 600; color: var(--slate-700); cursor: pointer; }
  .who-btn:hover .avatar { box-shadow: 0 0 0 2px var(--brand-100); }
  .nav-btn:focus-visible, .who-btn:focus-visible, .bar-flag:focus-visible { outline: 2px solid var(--blue-600); outline-offset: -2px; border-radius: 10px; }
}

.nav-sheet { position: fixed; inset: 0 auto 0 0; z-index: 40; width: min(100%, 420px); height: auto; max-width: none; max-height: none; margin: 0;
  padding: env(safe-area-inset-top, 0px) 0 0; border: 0; background: var(--paper); color: var(--navy-950);
  grid-template-rows: auto auto auto; align-content: start; overflow-y: auto; overscroll-behavior: contain; }
.nav-sheet:popover-open { display: grid; animation: sheet-in .18s ease-out; }
.nav-sheet[data-open] { display: grid; }
.nav-sheet::backdrop { background: rgba(11, 22, 40, .45); }
.nav-sheet { grid-template-columns: minmax(0, 1fr); }
.nav-sheet > * { min-width: 0; }
.ns-hd { display: flex; align-items: center; gap: 4px; height: 52px; padding: 0 8px 0 4px; border-bottom: 1px solid var(--slate-200); }
.ns-x { display: grid; place-items: center; flex: none; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 10px;
  background: var(--slate-100); color: var(--navy-950); cursor: pointer; }
.ns-x svg { width: 24px; height: 24px; }
.ns-biz { flex: 1 1 auto; min-width: 0; margin-left: 8px; font-size: var(--fs-head); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nav-sheet nav { align-self: start; }
.nav-sheet ul { list-style: none; margin: 0; padding: 8px 12px calc(28px + env(safe-area-inset-bottom, 0px)); display: grid; gap: 4px; }
.nav-sheet li a { display: grid; grid-template-columns: 24px minmax(0, 1fr) auto; align-items: center; gap: 16px; min-height: 56px; padding: 0 18px 0 14px;
  border-radius: 12px; font-size: var(--fs-head); font-weight: 700; color: var(--navy-950); text-decoration: none; }
.nav-sheet li a svg { width: 24px; height: 24px; color: var(--slate-600); }
.nav-sheet li a:hover { background: var(--slate-50); }
.nav-sheet li a[aria-current] { background: #e8f1ff; color: var(--blue-700); }
.nav-sheet li a[aria-current] svg { color: var(--blue-700); }
/* A parent's children in the sheet (navtree.html nav-sheet): one step in,
   no icon, the label lined up with the parent's, a thin rule; the parent of
   the current child is marked too. */
.nav-sheet ul.nt-kids { display: grid; gap: 2px; margin: 2px 0 4px 25px; padding: 0; border-left: 1px solid var(--slate-200); }
.nav-sheet .nt-kids li a { grid-template-columns: minmax(0, 1fr) auto; min-height: 48px; margin-left: 4px; padding: 0 18px 0 25px; font-weight: 600; }
/* Only the current page is marked (B1): its parent shows nothing more. */
.nav-sheet .ns-hd2 { display: grid; grid-template-columns: 24px minmax(0, 1fr); align-items: center; gap: 16px; min-height: 56px; padding: 0 18px 0 14px; font-size: var(--fs-head); font-weight: 700; color: var(--navy-950); }
.nav-sheet .ns-hd2 svg { width: 24px; height: 24px; color: var(--slate-600); }
.nav-sheet .nt-new { grid-column: -2; justify-self: end; padding: 0 8px; border-radius: 999px; background: #e8f1ff; color: #0847d6; font-size: var(--fs-caption); font-weight: 700; line-height: 20px; white-space: nowrap; }
.ns-dot { grid-column: -2; justify-self: end; width: 9px; height: 9px; border-radius: 50%; background: var(--crit); }
.ns-dot.ns-blue { background: #0a5cf0; } /* Kabar is information, not news that waits on you */

.acct-sheet { position: fixed; inset: auto 0 0 0; z-index: 40; width: 100%; max-width: 480px; height: auto; max-height: calc(100% - 52px); margin: 0 auto;
  padding: 8px 12px calc(28px + env(safe-area-inset-bottom, 0px)); border: 0; border-radius: 20px 20px 0 0; background: var(--paper);
  color: var(--navy-950); box-shadow: 0 -12px 32px -12px rgba(11, 22, 40, .3); overflow-y: auto; overscroll-behavior: contain; }
.acct-sheet:popover-open { display: block; animation: sheet-up .18s ease-out; }
.acct-sheet[data-open] { display: block; box-shadow: 0 0 0 100vmax rgba(11, 22, 40, .45); }
.acct-sheet::backdrop { background: rgba(11, 22, 40, .45); }
.as-grab { width: 40px; height: 5px; margin: 0 auto 10px; border-radius: 3px; background: var(--slate-300); }
.as-who { display: flex; align-items: center; gap: 12px; margin: 0; padding: 4px 14px 12px; border-bottom: 1px solid var(--slate-200); }
.as-who .avatar { flex: none; width: 34px; height: 34px; object-fit: cover; }
.as-who b { min-width: 0; font-size: var(--fs-head); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.acct-sheet ul { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 2px; }
.acct-sheet li a, .acct-sheet li button { display: grid; grid-template-columns: 24px minmax(0, 1fr) auto; align-items: center; gap: 16px; width: 100%;
  min-height: 52px; padding: 0 14px; border: 0; border-radius: 12px; background: none; font: inherit; font-size: var(--fs-head); font-weight: 700;
  color: var(--navy-950); text-align: left; text-decoration: none; cursor: pointer; }
.acct-sheet li svg { width: 22px; height: 22px; color: var(--slate-600); }
.acct-sheet li a:hover, .acct-sheet li button:hover { background: var(--slate-50); }
.acct-sheet .as-out { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--slate-200); }
.acct-sheet .as-out form { margin: 0; }
.acct-sheet .as-out button, .acct-sheet .as-out svg { color: var(--crit); }
.nav-sheet li a:focus-visible, .ns-x:focus-visible, .acct-sheet li a:focus-visible, .acct-sheet li button:focus-visible { outline: 2px solid var(--blue-600); outline-offset: -2px; }
@keyframes sheet-in { from { transform: translateX(-100%); } }
@keyframes sheet-up { from { transform: translateY(100%); } }
@media (prefers-reduced-motion: reduce) {
  .nav-sheet:popover-open, .acct-sheet:popover-open { animation: none; }
}
@media print { .nav-sheet, .acct-sheet { display: none !important; } }

/* ---------- Hari ini: the tiles (Steph 2026-10-15, batch 2) ----------
   ONE tile component: three fixed rows, label (one line) / figure / at most
   one line, each a fixed line height and start-aligned, so the figures of a
   row sit at the same height (to the pixel, scripts/overflow.mjs measures it)
   whether a tile has its line, a link in its place (.t-split: "1 belum ada
   HPP" goes elsewhere, so the box holds two links) or nothing. Four in a row
   from 1200px, two below; the figure is the hero size (24, 22 at 360px), a
   figure of 12 characters or more (.long) 20 on a phone. */
.today { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 20px; }
@media (max-width: 1199px) { .today { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.t-item, .t-main { display: grid; grid-template-rows: auto auto auto; align-content: start; row-gap: 2px; min-width: 0; color: inherit; text-decoration: none; }
.t-main { grid-template-rows: auto auto; }
.t-item { background: var(--paper); border: 1px solid var(--slate-200); border-radius: var(--radius); padding: 14px 16px; }
.t-item:hover { border-color: var(--slate-300); background: #fcfdff; }
.t-item .k, .t-item .v, .t-item .d { display: block; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.t-item .k { font-size: var(--fs-caption); line-height: 18px; font-weight: 600; color: var(--slate-600); }
.t-item .v { font-size: var(--fs-hero); line-height: 32px; font-weight: 700; letter-spacing: -0.035em; font-variant-numeric: tabular-nums; }
.t-item .v.warn { color: var(--crit); }
.t-item .v.muted { color: var(--slate-600); }
/* A long figure shrinks to its tile instead of ending in "…": the tile is the container, n<N> is the figure's
   length (tileView.Fit), 0.6em about what a heavy tabular digit takes. */
.t-item { container-type: inline-size; }
.t-item .v.fit { font-size: min(var(--fs-hero), calc(100cqw / (var(--n) * 0.6))); text-overflow: clip; }
.t-item .v.fit { font-size: round(down, min(var(--fs-hero), calc(100cqw / (var(--n) * 0.6))), 2px); } /* even whole pixels: few distinct sizes on a page, never a fraction */
.t-item .v.n9 { --n: 9; } .t-item .v.n10 { --n: 10; } .t-item .v.n11 { --n: 11; } .t-item .v.n12 { --n: 12; }
.t-item .v.n13 { --n: 13; } .t-item .v.n14 { --n: 14; } .t-item .v.n15 { --n: 15; } .t-item .v.n16 { --n: 16; }
.t-item .v.n17 { --n: 17; } .t-item .v.n18 { --n: 18; } .t-item .v.n19 { --n: 19; } .t-item .v.n20 { --n: 20; }
.t-item .d { font-size: var(--fs-caption); line-height: 18px; font-weight: 600; color: var(--slate-600); font-variant-numeric: tabular-nums; }
.t-item .d.crit { color: var(--crit); }
.t-item .d-s { display: none; }
.t-item .dl.up { color: var(--ok); }
.t-item .dl.down { color: var(--crit); }
.t-split:hover { border-color: var(--slate-200); background: var(--paper); }
.t-main:hover .v { text-decoration: underline; text-decoration-thickness: 1px; }
.t-item .t-link { justify-self: start; max-width: 100%; color: var(--crit); text-decoration: underline; text-underline-offset: 2px; }
.t-item .t-link:hover { color: #8f0b35; }
.t-item .t-link.warn { color: var(--warn-deep); }
@media (max-width: 759px) {
  .today { gap: 8px; margin-bottom: 16px; }
  .t-item { padding: 12px; border-radius: 12px; }
  .t-item .d.dhp:has(.d-s) .d-l { display: none; } /* the anomaly line: short form on every phone */
  .t-item .d.dhp .d-s { display: inline; }
}
@media (max-width: 360px) {
  .t-item { padding: 12px 10px; }
  .t-item .d:has(.d-s) .d-l { display: none; }
  .t-item .d-s { display: inline; }
}
/* Omzet | Laba: ONE tile, two halves with a divider (Steph 2026-10-24). Each half is the standard three rows. */
@media (min-width: 1200px) {
  .today:has(> .t-duo) { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  .today:has(> .t-duo):has(> :nth-child(3)) { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr); }
}
.t-duo { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); padding: 0; }
.t-duo:hover { border-color: var(--slate-200); background: var(--paper); }
.t-duo > .t-pair { display: grid; grid-template-rows: auto auto auto; align-content: start; row-gap: 2px; min-width: 0; padding: 14px 16px; color: inherit; text-decoration: none; container-type: inline-size; }
.t-duo > .t-pair + .t-pair { border-left: 1px solid var(--slate-200); }
.t-duo > a.t-pair:hover { background: #fcfdff; }
@media (max-width: 1199px) { .t-duo { grid-column: 1 / -1; } }
@media (max-width: 759px) { .t-duo > .t-pair { padding: 12px; } }
@media (max-width: 360px) { .t-duo > .t-pair { padding: 12px 10px; } }
.task-t { color: inherit; text-decoration: underline; text-decoration-color: var(--slate-300); text-underline-offset: 3px; }
.task-t:hover { text-decoration-color: currentColor; }

/* ---------- Hari ini: order queue ---------- */
.obar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--slate-200); background: var(--ground); }
.obar-count { font-size: var(--fs-body); font-weight: 700; color: var(--slate-600); }
.obar-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-left: auto; }
.btn-sm { width: auto; min-height: 38px; margin: 0; padding: 9px 14px; font-size: var(--fs-body); border-radius: 9px; }
.btn-sm svg { width: 16px; height: 16px; flex: none; }

.ocheck { display: inline-flex; align-items: center; margin: 0; min-height: 24px; cursor: pointer; }
.ocheck input { width: 24px; height: 24px; margin: 0; accent-color: var(--blue-600); cursor: pointer; }

.orders { list-style: none; margin: 0; padding: 0; }
.order { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto auto; gap: 14px; align-items: center; padding: 13px 16px; border-bottom: 1px solid var(--slate-200); font-size: var(--fs-body); }
.order:last-child { border-bottom: 0; }
.o-main { display: grid; gap: 2px; min-width: 0; }
.o-main b { font-weight: 700; }
.o-main .meta { font-size: var(--fs-caption); color: var(--slate-600); }
/* Each row is its own grid, so the numeric columns need a fixed width to line
   up down the list. */
.o-val { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; min-width: 104px; text-align: right; }
.o-due { font-size: var(--fs-caption); font-weight: 700; border-radius: 999px; padding: 5px 10px; white-space: nowrap; text-align: center; min-width: 72px; color: var(--slate-600); background: var(--slate-100); }
.o-due.crit { color: var(--crit); background: var(--crit-soft); }
.o-due.warn { color: #b54708; background: #fff4e5; }
/* Channel chip. `.tt` was used on 13 TikTok chips across the app but had no rule
   anywhere, so Shopee and TikTok rendered identically and the channel was carried
   by the word alone — in a queue that is scanned, not read. */
/* Wins over the generic .chip in catalog.css / reports.css, which is grey
   for both channels and made Shopee and TikTok Shop indistinguishable. */
.chip.chip-ch, .chip-ch { display: inline-block; font-size: var(--fs-caption); font-weight: 700; color: #8a3d00; background: #fff1e3; border-radius: 999px; padding: 1px 7px; }
.chip.chip-ch.tt, .chip-ch.tt { color: #123f4a; background: #dff1f5; }
/* Tokopedia / TikTok origin chips (0086): an order or listing from the
   Tokopedia storefront of a TikTok Shop connection, in Tokopedia green; its
   .mk badge wears Tokopedia's own mark. */
.chip.chip-ch.tp, .chip-ch.tp { color: #0b5d14; background: #e1f5e3; }
/* Where a product sells: the marketplace's own mark, the full-colour one the
   homepage, Mulai and Toko show (/assets/img/logos/marks, README there: never
   recoloured or faded), then the shop name. A Tokopedia order of a TikTok Shop
   connection wears Tokopedia's (2026-10-15, Steph: the green dot was confusing).
   The channel is spelled out for screen readers in a .vh span. */
.mk { display: inline-flex; align-items: center; gap: 5px; max-width: 100%; font-size: var(--fs-caption); font-weight: 600; color: var(--navy-950);
  background: var(--paper); border: 1px solid var(--slate-200); border-radius: 999px; padding: 2px 9px 2px 6px; overflow-wrap: anywhere; }
.mk::before { content: ""; flex: none; width: 14px; height: 14px; background: var(--mark, none) center / contain no-repeat; }
.mk.shopee { --mark: url("/assets/img/logos/marks/shopee.svg?v=85c043c22b5f"); }
.mk.tiktokshop { --mark: url("/assets/img/logos/marks/tiktok.svg?v=1a560c9eba38"); }
.mk.tiktokshop.tokopedia, .mk.tokopedia { --mark: url("/assets/img/logos/marks/tokopedia.png?v=e4f2f282ffd8"); }
.mk.lazada { --mark: url("/assets/img/logos/marks/lazada.svg?v=0989e73e3da3"); }
/* A shop outside Indonesia: its country code after the name (0249). Plain mono text,
   no chip of its own, so it never reads as a button. */
.rgc { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: var(--fs-caption); font-weight: 700;
  color: var(--slate-600); letter-spacing: .02em; white-space: nowrap; }
.mk.blibli { --mark: url("/assets/img/logos/marks/blibli.svg?v=c5a9e9e41b1d"); }
.mk.off { color: var(--slate-500); border-style: dashed; background: transparent; }
.mks { display: flex; flex-wrap: wrap; gap: 4px 6px; margin-top: 4px; }
/* A TikTok Shop listing (0086, Steph 2026-10-19): one chip per storefront,
   TikTok then Tokopedia, each with the shop. Where buyers cannot see it the
   chip's logo is faded under a slash (Steph approved fading the marks here,
   the one exception to the README rule): amber when the listing shows on the
   other storefront, grey when it shows on neither. The faded logo's tooltip
   shows on hover (title), and inline after the shop name when the logo is
   tapped or focused. */
.mk.duo::before { content: none; }
.mk-f { position: relative; flex: none; width: 14px; height: 14px; background: var(--mark) center / contain no-repeat; }
.mk-f.tiktokshop { --mark: url("/assets/img/logos/marks/tiktok.svg?v=1a560c9eba38"); }
.mk-f.tokopedia { --mark: url("/assets/img/logos/marks/tokopedia.png?v=e4f2f282ffd8"); }
/* A 24px tap target round the 14px logo; the layout keeps 14px. */
.mk-f.no { box-sizing: content-box; background: none; cursor: help; padding: 5px; margin: -5px; }
.mk-f.no::before { content: ""; position: absolute; inset: 5px; background: var(--mark) center / contain no-repeat; opacity: .45; filter: grayscale(1); }
.mk-f.no::after { content: ""; position: absolute; left: calc(50% - 1px); top: 3px; bottom: 3px; width: 2px; border-radius: 1px; background: currentColor; transform: rotate(45deg); }
.mk-f.no:focus-visible { outline: var(--focus); outline-offset: -2px; border-radius: 4px; }
.mk-tip { display: none; font-weight: 400; }
.mk:focus-within .mk-tip { display: inline; }
.mk.mk-gap { color: var(--warn-deep); background: var(--warn-soft); border-color: #f0d9a8; }
.mk.mk-hid { color: var(--slate-600); background: var(--slate-100); border-color: var(--slate-200); }
/* Stock sync on a product row: on (quiet green) or refused somewhere (red). */
.sync-tag { display: inline-block; margin-top: 4px; padding-block: 3px; font-size: var(--fs-caption); font-weight: 600; color: var(--ok); text-decoration: none; }
.sync-tag::before { content: "⇄ "; }
.sync-tag.bad { color: var(--crit); }
/* A product or listing whose shop is still syncing (cmd/api/synclock.go): one line, its edits held. */
.sync-lock { display: block; margin-top: 4px; font-size: var(--fs-body); font-weight: 600; color: #8a4b00; }
.sync-lock-p { margin: 0 0 12px; padding: 10px 12px; border-radius: 8px; background: #fff7e6; font-size: var(--fs-body); font-weight: 600; color: #8a4b00; }
.sync-tag.bad::before { content: "! "; }
.sync-tag:hover { text-decoration: underline; }
.card-foot { margin: 0; padding: 12px 16px; border-top: 1px solid var(--slate-200); font-size: var(--fs-body); color: var(--slate-500); }
/* A card's foot link is one look on every card (Steph 2026-10-19, "unstandard ui link"): dark,
   bold, no underline until hover, like Perlu restok's; tall enough for the 24px target minimum. */
.card-foot a, a.foot-link { display: inline-block; padding-block: 4px; font-weight: 700; color: var(--navy-950); text-decoration: none; }
.card-foot a:hover, a.foot-link:hover { text-decoration: underline; }
.card-foot a:focus-visible, a.foot-link:focus-visible { outline: var(--focus); outline-offset: 2px; border-radius: 4px; }

/* Phones: the row restacks so the money and the deadline stay readable. */
@media (max-width: 700px) {
  .order { grid-template-columns: auto minmax(0, 1fr) auto; row-gap: 10px; }
  .order .o-due { grid-column: 2; }
  .order .act { grid-column: 3; grid-row: 2; }
  .o-val { min-width: 0; }
  .obar-acts { width: 100%; margin-left: 0; }
  .obar-acts .btn-sm { flex: 1 1 auto; }
}

/* Hari ini without checkboxes or courier: goods, value, deadline. */
.orders-lean .order { grid-template-columns: minmax(0, 1fr) auto auto; }
@media (max-width: 700px) {
  .orders-lean .order { grid-template-columns: minmax(0, 1fr) auto; }
  .orders-lean .order .o-val { grid-column: 2; grid-row: 1; }
  .orders-lean .order .o-due { grid-column: 1; justify-self: start; }
}
/* The whole goods-and-number block opens the order: a 44px target, not the
   16px order number (WCAG 2.5.8). */
.o-link { color: inherit; text-decoration: none; min-height: 44px; align-content: center; }
.o-link:hover b { text-decoration: underline; }
.o-link:focus-visible { outline: var(--focus); outline-offset: 2px; border-radius: 6px; }
/* Hari ini: the Uang hilang card (the four leaks the seller controls). */
.hl { list-style: none; margin: 0; padding: 0 16px 8px; display: grid; }
.hl li { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; row-gap: 2px; padding: 10px 0; border-bottom: 1px solid var(--slate-200); font-size: var(--fs-body); }
.hl li:last-child { border-bottom: 0; }
.hl .hl-t { font-weight: 700; min-width: 0; overflow-wrap: anywhere; color: var(--navy-950); text-decoration: none; }
.hl .hl-t:hover { text-decoration: underline; }
.hl .s { grid-column: 1 / -1; display: block; font-size: var(--fs-caption); font-weight: 400; color: var(--slate-600); }
.hl b { white-space: nowrap; color: var(--crit); }
.hl li.zero b, .hl li.zero .hl-t { color: var(--slate-500); font-weight: 600; }
.hl .hl-next { grid-column: 1 / -1; font-size: var(--fs-caption); font-weight: 600; color: var(--blue-700); text-decoration: underline; text-underline-offset: 2px; overflow-wrap: anywhere; }
/* "3 tanpa HPP" under a row's label: still the small line, now a link. */
.tbl a.sub2, .hp-table a.sub2 { color: var(--crit); text-decoration: underline; text-underline-offset: 2px; }
.skuh { margin: 0; padding: 12px 16px 4px; font-size: var(--fs-caption); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--slate-500); }
.skul { list-style: none; margin: 0; padding: 0 16px 8px; display: grid; grid-template-columns: minmax(0, 1fr); }
.skul li { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--slate-200); font-size: var(--fs-body); }
.skul li:last-child { border-bottom: 0; }
.skul .s { display: block; font-size: var(--fs-caption); color: var(--slate-500); }
.skul b { white-space: nowrap; }
.skul b.neg { color: var(--crit); }
/* A row that opens a page reads like Hari ini's order rows (Steph 2026-10-18:
   "make it consistent"): dark name, no blue, no underline until hovered, the
   whole row the link, the name two lines at most. */
.skul li, .hl li { position: relative; }
.skul li a { color: var(--navy-950); font-weight: 700; text-decoration: none; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
/* Laba per SKU's second line: the code and "terjual … · margin …" share the line when both fit and otherwise the
   second goes under the first; the code is the part that gets an ellipsis, the second never breaks (designer #40). */
.skul .pic-t .s2l { display: flex; flex-wrap: wrap; column-gap: 10px; min-width: 0; }
.skul .s-code { min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.skul .s-rest { flex: 0 1 auto; min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 759px) { .skul li a { -webkit-line-clamp: 3; line-clamp: 3; } }
.skul li a::after, .hl .hl-t::after { content: ""; position: absolute; inset: 0; }
.skul li:hover a, .hl li:hover .hl-t { text-decoration: underline; }
.skul li a:focus-visible, .hl .hl-t:focus-visible { outline: none; }
.skul li a:focus-visible::after, .hl .hl-t:focus-visible::after { outline: var(--focus); outline-offset: -2px; }

/* ---------- status tabs ----------
   Used by Pesanan to switch between order states, each carrying its count. */
.tabs { display: flex; flex-wrap: wrap; gap: 4px; border-bottom: 1px solid var(--slate-200); margin-bottom: 12px; }
.tab { display: inline-flex; align-items: center; gap: 7px; padding: 10px 14px; font-size: var(--fs-body); font-weight: 700; color: var(--slate-600); text-decoration: none; border-bottom: 3px solid transparent; margin-bottom: -1px; }
.tab:hover { color: var(--navy-950); }
.tab.current, .tab[aria-current] { color: var(--blue-700); border-bottom-color: var(--blue-600); }
.tab .c { font-size: var(--fs-caption); font-weight: 700; background: var(--slate-100); color: var(--slate-600); border-radius: 999px; padding: 2px 8px; }
.tab.current .c { background: #e8f1ff; color: var(--blue-700); }
.tab.bad { color: var(--crit); }
.tab.bad .c { background: var(--crit-soft); color: var(--crit); }

/* Courier service beside the deadline: in Indonesia the courier sets the cut-off. */
.o-ship { font-size: var(--fs-caption); font-weight: 600; color: var(--slate-600); white-space: nowrap; display: inline-flex; align-items: center; gap: 7px; }

.page-head .sub a { color: var(--blue-600); display: inline-block; padding-block: 3px; }

/* ---------- Hari ini: the work (hari-ini-desktop mockup, batch 2) ----------
   From 1200px two columns: the orders waiting at the left, "Perlu Anda
   bereskan" (three lines, then +N lainnya), the notification strip and the
   money at the right, so the queue starts in the first screen (1280x900).
   Below, one column, the queue first. */
/* One minmax(0, 1fr) track by default: an auto track grows to a no-wrap
   line's full width (a long "Perlu Anda bereskan" title) and the page
   scrolls sideways. */
.work { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; align-items: start; }
.work-main, .work-side { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; min-width: 0; align-content: start; }
/* Below 1200px the two columns are one stack, in the order the right column used to follow the left. */
@media (max-width: 1199px) {
  .hi .work-main, .hi .work-side { display: contents; }
  .hi .work .hp { order: 0; }
  .hi .work #terjual { order: 1; }
  .hi .work #antrean { order: 2; }
  .hi .work .beres { order: 4; }
  .hi .work .notif-card { order: 5; }
  .hi .work #uang-hilang { order: 6; }
}
@media (min-width: 1200px) { .work { grid-template-columns: minmax(0, 1fr) 360px; gap: 20px; } }
@media (min-width: 1400px) { .work { grid-template-columns: minmax(0, 1fr) 400px; } }
/* Nothing urgent and no message: the side column is all there is, full width like the other pages. */
@media (min-width: 1200px) { .work.work-solo { grid-template-columns: minmax(0, 1fr); } }

/* ---------- Hari ini: Terjual hari ini (v2, Steph 2026-10-24) ----------
   One compact tile (three pictures, pcs, SKUs and omzet) first in the work
   column; it opens a popover with the day's SKUs, most pieces first: a bottom
   sheet under 760px, a dialog from there. A browser without popover gets
   [data-open] from nav.js. Type-scale variables only. */
.tsum { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; column-gap: 12px; width: 100%; padding: 12px 14px;
  background: var(--paper); border: 1px solid var(--slate-200); border-radius: var(--radius); font: inherit; color: var(--navy-950); text-align: left; cursor: pointer; }
.tsum:hover { border-color: var(--slate-300); }
.tsum:focus-visible { outline: var(--focus); outline-offset: 2px; }
.tsum-pics { display: flex; }
.tsum-pics .pic { border: 2px solid var(--paper); margin-left: -10px; background: #fff; }
.tsum-pics .pic:first-child { margin-left: 0; }
.tsum-body { display: grid; min-width: 0; }
.tsum-k { font-size: var(--fs-caption); color: var(--slate-500); font-weight: 600; }
.tsum-v { font-size: var(--fs-head); font-weight: 700; }
.tsum-s { font-size: var(--fs-caption); color: var(--slate-600); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tsum-chip { font-weight: 700; color: var(--crit); }
.tsum-go { color: var(--slate-500); font-size: var(--fs-body); white-space: nowrap; }
.ts-pop { display: none; position: fixed; z-index: 40; inset: 0; margin: auto; padding: 0; border: 0; border-radius: 16px; background: var(--paper); color: var(--navy-950);
  width: min(560px, calc(100vw - 32px)); height: auto; max-height: min(80vh, 640px); box-shadow: 0 20px 60px rgba(11, 22, 40, .28); overflow: hidden; flex-direction: column; }
.ts-pop:popover-open { display: flex; }
.ts-pop[data-open] { display: flex; box-shadow: 0 0 0 100vmax rgba(11, 22, 40, .45); }
.ts-pop::backdrop { background: rgba(11, 22, 40, .45); }
.tsd-hd { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 16px 16px 10px; border-bottom: 1px solid var(--slate-200); }
.tsd-hd h2 { margin: 0; font-size: var(--fs-head); }
.tsd-hd p { margin: 2px 0 0; font-size: var(--fs-caption); color: var(--slate-600); }
.tsd-x { flex: none; width: 44px; height: 44px; margin: -8px -8px 0 0; border: 0; background: none; font-size: var(--fs-hero); color: var(--slate-600); cursor: pointer; }
.tsd-x:focus-visible { outline: var(--focus); outline-offset: -2px; border-radius: 10px; }
.tsd-list { list-style: none; margin: 0; padding: 0 16px; overflow-y: auto; overscroll-behavior: contain; }
.tsd-list li { border-bottom: 1px solid var(--slate-200); }
.tsd-list li:last-child { border-bottom: 0; }
.tsd-r { display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; column-gap: 12px; align-items: center; padding: 9px 0; color: var(--navy-950); text-decoration: none; min-width: 0; }
a.tsd-r:hover .tsd-t { text-decoration: underline; }
a.tsd-r:focus-visible { outline: var(--focus); outline-offset: -3px; }
.tsd-n { display: grid; min-width: 0; }
.tsd-t { font-size: var(--fs-body); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tsd-c { display: flex; flex-wrap: wrap; align-items: center; gap: 0 6px; min-width: 0; font-size: var(--fs-caption); color: var(--slate-500); }
.tsd-c code { min-width: 0; font-family: ui-monospace, Menlo, monospace; color: var(--slate-600); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tsd-q { display: grid; justify-items: end; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tsd-q b { font-size: var(--fs-body); }
.tsd-q small { font-weight: 400; color: var(--slate-500); font-size: var(--fs-caption); }
.tsd-o { font-size: var(--fs-caption); color: var(--slate-600); }
.tsd-chip { font-size: var(--fs-caption); font-weight: 700; padding: 0 6px; border-radius: 6px; white-space: nowrap; }
.tsd-chip.crit { color: var(--crit); background: #fde8ef; }
.tsd-chip.warn { color: #8a4b00; background: #fff1d6; }
.tsd-ft { margin: 0; padding: 10px 16px; border-top: 1px solid var(--slate-200); font-size: var(--fs-body); }
@media (max-width: 759px) {
  .ts-pop { inset: auto 0 0 0; width: 100%; max-width: none; margin: 0; max-height: 78vh; border-radius: 16px 16px 0 0; padding-bottom: env(safe-area-inset-bottom, 0px); }
  .ts-pop:popover-open { animation: sheet-up .18s ease-out; }
  .tsd-list { padding: 0 12px; }
}
@media (prefers-reduced-motion: reduce) { .ts-pop:popover-open { animation: none; } }
@media print { .ts-pop { display: none !important; } }

/* The orders waiting: one row each, the whole row the link. Desktop:
   | picture 44 | name ×N (two lines) | amount | deadline |; a phone:
   | picture 56 | name ×N, two lines at most        |
   |            | deadline .................. amount |
   The marketplace is its mark on the picture's corner (.pmk), never the
   shop's name; ×N follows the name and is never cut (the name gives way). */
.qlist { list-style: none; margin: 0; padding: 0; background: var(--paper); border: 1px solid var(--slate-200); border-radius: var(--radius); overflow: hidden; }
.qlist > li + li { border-top: 1px solid var(--slate-200); }

/* Atur ulang jemput (cmd/api/atur_ulang.go, pickup-act.html): after a late
   pickup's cause, a small button, or one line where no button is offered.
   .rs-li is a Hari ini Belum dikirim row: its button or line sits under the
   row's link, not beside it (a button cannot nest in the link, and beside it
   the narrow column squeezed the row's quantity into its amount); .rs-row is
   Siap kirim's chip line. */
.rs-f { margin: 0; }
.rs-note, .rs-state, .rs-line { font-size: var(--fs-caption); font-weight: 400; color: var(--slate-600); }
.rs-state { font-size: var(--fs-body); font-weight: 700; }
.rs-line { margin: 4px 0 0; }
.rs-li > .rs-f, .rs-li > .rs-state, .rs-li > .rs-note { display: block; margin: 0 14px 8px 68px; }
.rs-li > .rs-state { white-space: nowrap; }
.rs-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 4px; }
.rs-row .pickup-chip { margin: 0; }
.rs-row .rs-f { position: relative; z-index: 2; }
.rs-row > .btn-xs { position: relative; z-index: 2; }
.rs-row .btn-xs, .rs-li .btn-xs { position: relative; min-height: 30px; padding: 0 12px; font-size: var(--fs-caption); }
/* 44px to touch, 30px to look at (the row stays as high as its neighbours). */
.rs-row .btn-xs::after, .rs-li .btn-xs::after { content: ""; position: absolute; inset: -8px -4px; }
.q-row { position: relative; display: grid; grid-template-columns: 44px minmax(0, 1fr) auto minmax(136px, auto); align-items: center; column-gap: 12px; min-height: 62px;
  padding: 9px 16px; color: inherit; text-decoration: none; }
.q-row:hover .q-t { text-decoration: underline; }
.q-row:focus-visible { outline: var(--focus); outline-offset: -3px; }
.q-pic { grid-column: 1; position: relative; width: 44px; height: 44px; }
.q-pic .thumb.pic { width: 44px; height: 44px; }
.q-nm { grid-column: 2; display: flex; align-items: flex-end; gap: 4px; min-width: 0; font-size: var(--fs-body); font-weight: 700; line-height: 1.35; }
.q-t, .o-nm .t-clamp { min-width: 0; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; overflow-wrap: anywhere; }
.q-x { flex: none; font-weight: 700; white-space: nowrap; }
.q-amt { grid-column: 3; font-size: var(--fs-body); font-weight: 700; text-align: right; }
/* "Total" names the order's value on a phone, where no column header does. */
.amt-k { display: none; }
.q-b { display: contents; }
.q-amt, .q-due { grid-row: 1; }
.q-due { grid-column: 4; justify-self: end; }
.q-due, .due-hp { font-size: var(--fs-caption); font-weight: 700; line-height: 22px; padding: 0 8px; border-radius: 999px; white-space: nowrap;
  color: var(--slate-600); background: var(--slate-100); }
.q-due.crit, .due-hp.crit { color: var(--crit); background: var(--crit-soft); }
.q-due.warn, .due-hp.warn { color: var(--warn); background: var(--warn-soft); }
.qmore a { display: block; padding: 10px 16px; font-size: var(--fs-body); font-weight: 700; color: var(--blue-700); text-decoration: none; }
.qmore a:hover { text-decoration: underline; }
/* The marketplace's own mark on a row picture's corner (Hari ini, Pesanan's
   phone rows). Full colour, never recoloured (/assets/img/logos/marks). */
.pmk { position: absolute; right: -4px; bottom: -4px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--paper) var(--mark, none) center / 12px no-repeat; box-shadow: 0 0 0 1px var(--slate-200); }
.pmk.shopee { --mark: url("/assets/img/logos/marks/shopee.svg?v=85c043c22b5f"); }
.pmk.tiktokshop { --mark: url("/assets/img/logos/marks/tiktok.svg?v=1a560c9eba38"); }
.pmk.tokopedia, .pmk.tiktokshop.tokopedia { --mark: url("/assets/img/logos/marks/tokopedia.png?v=e4f2f282ffd8"); }
.pmk.lazada { --mark: url("/assets/img/logos/marks/lazada.svg?v=0989e73e3da3"); }
.pmk.blibli { --mark: url("/assets/img/logos/marks/blibli.svg?v=c5a9e9e41b1d"); }
/* The marketplace's mark in place of its name (Pesanan's Toko column; the name is in a .vh span). */
.chlogo { display: inline-block; vertical-align: middle; width: 18px; height: 18px; background: var(--mark, none) center / contain no-repeat; }
.chlogo.shopee { --mark: url("/assets/img/logos/marks/shopee.svg?v=85c043c22b5f"); }
.chlogo.chlogo-sm { width: 16px; height: 16px; margin-right: 6px; }
.chlogo.tiktokshop { --mark: url("/assets/img/logos/marks/tiktok.svg?v=1a560c9eba38"); }
.chlogo.blibli { --mark: url("/assets/img/logos/marks/blibli.svg?v=c5a9e9e41b1d"); }
.chlogo.tokopedia, .chlogo.tiktokshop.tokopedia { --mark: url("/assets/img/logos/marks/tokopedia.png?v=e4f2f282ffd8"); }
@media (max-width: 759px) {
  .q-row { grid-template-columns: 56px minmax(0, 1fr) auto; grid-template-rows: auto auto; align-items: start; row-gap: 6px; padding: 10px 12px; }
  .q-pic { grid-row: 1 / span 2; width: 56px; height: 56px; }
  .q-pic .thumb.pic { width: 56px; height: 56px; }
  .q-pic .pmk { width: 20px; height: 20px; background-size: 14px; }
  .q-nm { grid-column: 2 / span 2; grid-row: 1; }
  /* Deadline left, total right, on one line that wraps (the total under
     the deadline) rather than letting the two collide. */
  .q-b { grid-column: 2 / span 2; grid-row: 2; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 8px; min-width: 0; }
  .q-due { justify-self: auto; }
  .q-amt { margin-left: auto; white-space: nowrap; }
  /* Above the amount, not beside it: the row has no width to spare next to a long deadline chip. */
  .amt-k { display: block; font-size: var(--fs-caption); line-height: 16px; font-weight: 400; color: var(--slate-600); text-align: right; }
  .qmore a { padding: 10px 12px; }
}

/* "Perlu Anda bereskan" (desktop): one line each, a dot, one button; the
   three most urgent, the rest open in place behind "+N lainnya". */
.todo { list-style: none; margin: 0; padding: 0; background: var(--paper); border: 1px solid var(--slate-200); border-radius: var(--radius); overflow: hidden; }
.todo-i { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px; min-height: 52px; padding: 6px 8px 6px 14px;
  font-size: var(--fs-body); font-weight: 700; line-height: 1.35; }
.todo-i + .todo-i { border-top: 1px solid var(--slate-200); }
.todo-t { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.todo-t::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 10px; border-radius: 50%; background: var(--warn); vertical-align: 1px; }
.todo-i.crit .todo-t::before { background: var(--crit); }
.todo-b { display: inline-flex; align-items: center; min-height: 36px; padding: 0 12px; border: 1px solid var(--slate-300); border-radius: 11px;
  background: var(--paper); color: var(--blue-700); font-weight: 700; text-decoration: none; white-space: nowrap; }
.todo-b:hover { border-color: var(--blue-600); }
.todo-b:focus-visible { outline: var(--focus); outline-offset: 2px; }
.todo-bs { display: inline-flex; align-items: center; gap: 8px; }
.todo-bs form { margin: 0; }
.todo-s { min-height: 36px; padding: 0 10px; background: none; border: 0; font: inherit; font-size: var(--fs-caption); color: var(--blue-700); cursor: pointer; text-decoration: underline; white-space: nowrap; }
@media (max-width: 768px) { .todo-s { min-height: 44px; } }
.todo-more > summary { display: inline-flex; align-items: center; min-height: 36px; margin-top: 4px; padding: 0 2px; list-style: none; cursor: pointer;
  font-size: var(--fs-body); font-weight: 700; color: var(--blue-700); }
.todo-more > summary::-webkit-details-marker { display: none; }
.todo-more > summary:hover { text-decoration: underline; }
.todo-more > summary:focus-visible { outline: var(--focus); outline-offset: 2px; border-radius: 6px; }
.todo-more[open] > summary { margin-bottom: 8px; }
.beres > .sec-head { margin-bottom: 8px; }
.hi #antrean > .sec-head { margin-bottom: 8px; }

/* The queue earns a courier column once there is room for it: in Indonesia the
   courier service is what sets the cut-off, so it belongs beside the deadline. */
.orders-wide .order { grid-template-columns: auto minmax(0, 1fr) auto auto auto auto; }
/* Every row is its own grid, so any column that sizes to its own content drags
   the money column out of line with its neighbours. Both variable columns get a
   width wide enough for their longest label: "Anteraja Next-day" and
   "2 hari lagi", which needs 76px against the base pill's 72. */
.orders-wide .o-ship { min-width: 124px; }
.orders-wide .o-due { min-width: 84px; }
@media (max-width: 860px) {
  .orders-wide .order { grid-template-columns: auto minmax(0, 1fr) auto; }
  .orders-wide .o-ship { grid-column: 2; min-width: 0; }
}

/* ---------- left rail ----------------------------------------------------
   Every competitor dashboard that could be verified (BigSeller, Jubelio,
   Forstok, Ginee — docs/design/feature-design-v0.2.html §0) runs a left
   sidebar over a fluid content area, and none uses a centred column. A rail
   also scales to the dozen destinations this product needs, which a row of
   top-level links does not.

   It is fixed rather than a grid column so the page markup did not have to be
   restructured: the body takes a left padding and the sticky top bar, which
   keeps the account chip and the shop switcher, sits inside it. */
.rail { display: none; }

@media (min-width: 1080px) {
  body.app:not(.onb) { padding-left: 248px; }
  .rail {
    display: flex;
    flex-direction: column;
    gap: 22px;
    position: fixed;
    inset: 0 auto 0 0;
    width: 248px;
    z-index: 20;
    padding: 20px 14px;
    overflow-y: auto;
    background: linear-gradient(176deg, var(--navy-950) 0%, #10243f 54%, #16305a 100%);
    color: #eef4fc;
  }
  /* The brand and the destinations live in the rail; the bar keeps the account. */
  /* The rail carries the brand at this width — except on onboarding,
     which has no rail, and was left with an empty top bar. */
  body.app:not(.onb) .app-bar .brand { display: none; }
  .app-bar .app-wrap { min-height: 56px; }
}

.rail .brand {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 6px 8px; color: #fff; text-decoration: none;
  font-weight: 700; font-size: var(--fs-head); letter-spacing: -0.015em;
}
.rail .brand img { width: 28px; height: 28px; }

/* The Beta pill after the wordmark (templates/brand.html, while BILLING_BETA
   is on). Brand blue at low saturation: blue-700 on a pale tint is 6,4:1 on
   the white bar; the dark rail and the sign-in side use a pale blue on a
   faint blue-400 wash (7,2:1 or more). flex: none so it never wraps or
   squeezes the logo; the negative margin trims the link's 9-10px gap. */
.brand .beta {
  flex: none; margin-left: -3px; padding: 1px 7px; border-radius: 999px;
  font-size: var(--fs-caption); line-height: 16px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; white-space: nowrap;
  color: var(--blue-700); background: #e8f1ff; border: 1px solid #c6dafc;
}
.rail .brand .beta,
.side .brand .beta {
  color: #b9e8ff; background: rgba(18, 184, 248, .16); border-color: rgba(18, 184, 248, .4);
}

.rail nav { display: grid; gap: 2px; }
.rail nav a {
  display: grid; grid-template-columns: 21px minmax(0, 1fr) 9px;
  align-items: center; gap: 12px;
  min-height: 42px; padding: 0 12px; border-radius: 10px;
  color: #b9c8de; text-decoration: none; font-weight: 600; font-size: var(--fs-body);
}
.rail nav a svg { width: 20px; height: 20px; }
.rail nav a:hover { background: rgba(255, 255, 255, 0.07); color: #fff; }
.rail nav a.current { background: rgba(255, 255, 255, 0.13); color: #fff; font-weight: 700; }
.rail nav a.current svg { color: var(--green-400); }
.rail nav a.soon { color: #7c8ea9; }
.rail .n {
  font-size: var(--fs-caption); font-weight: 700; font-variant-numeric: tabular-nums;
  background: rgba(255, 255, 255, 0.14); border-radius: 999px; padding: 2px 8px;
}
.rail .n.hot, .rail nav a.current .n.hot { background: #ff8fab; color: #5c0523; }
/* #8fa4c2 clears 4.5:1 on the rail's own navy but only reaches 4,02:1 on the
   lighter ground of the current item, which is exactly where it is read. */
.rail .n.soft { background: transparent; color: #b9c8de; font-weight: 700; }
/* "Status baru" on the Retur item (0116). The white ring carries it on the
   navy rail, where the danger red alone stays under 3:1. */
/* The dot's slot (Steph 2026-10-22, "uneven when the red dot is there"): the
   last column of every row is 9px wide whether or not a dot is in it, and the
   dot is placed in it by column, never by order, so a row with a dot and a row
   without read the same: one height, the label and the chevron in one place.
   A parent's row has the slot, then the chevron (column 4). */
.rail .nav-dot { grid-column: 3; justify-self: end; width: 9px; height: 9px; border-radius: 50%; background: var(--crit); box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6); }
/* A count in place of the dot (Chat: perlu dibalas, 0261). */
.nav-count { grid-column: -2; justify-self: end; align-self: center; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px; background: var(--crit); color: #fff; font-size: var(--fs-caption); font-weight: 700; line-height: 18px; text-align: center; font-variant-numeric: tabular-nums; }
.rail .nav-count { grid-column: 3; box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6); }
/* It is the row's dot (nav-dot / ns-dot), so the row is measured as one with a dot; only its size differs. */
/* Its own width (the 9px dot column would wrap "13" onto two lines): one line, 1-3 characters ("99+"), right-aligned in the slot. */
.rail .nav-dot.nav-count, .ns-dot.nav-count { width: max-content; height: 18px; border-radius: 999px; white-space: nowrap; }

/* A return whose status changed since this person last opened it (0116):
   always next to words ("Status baru") or a visually hidden label. */
.new-dot { display: inline-block; flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--crit); vertical-align: 1px; }
.tab .new-dot { margin-left: -2px; }
/* A row with that news (templates/baru.html): the same red dot with the word
   "Baru", on every list whose tab or menu item has a dot. */
.baru { display: inline-flex; flex: none; align-items: center; gap: 5px; width: fit-content; padding: 0 8px; border-radius: 999px;
  background: var(--crit-soft); color: var(--crit); font-size: var(--fs-caption); font-weight: 700; line-height: 20px; white-space: nowrap; vertical-align: 1px; }
/* News that needs nothing (templates/baru.html, baru-info): calm, no dot. */
.baru.info { background: var(--ground); color: var(--brand); box-shadow: inset 0 0 0 1px var(--line); }
/* A page of the list, or a fold, that holds such a row. */
summary .baru, .pager .baru, a.btn .baru { margin-left: 6px; }

/* Sidebar, compact (B1 round 2, 2026-10-29, Steph's hybrid; templates/navtree.html,
   nav.js). The rail lists the top level only. A parent with children (Pesanan,
   Produk) is the link to its own page plus an opener button; Pemasaran, which
   has no page, is a heading button. The children are in a flyout (.nt-fly,
   white card, position: fixed and placed beside the row by nav.js, because
   the rail and its nav clip what is inside them). The opener draws no chevron
   on a pointer that hovers (the row's hover or focus opens the flyout; the
   button shows only when keyboard focus lands on it) and is a visible 44px
   control on touch. One marker a row; Baru only on the child, in the flyout. */
.rail .nt-fb { position: relative; display: flex; align-items: stretch; width: 100%; height: 42px; border-radius: 10px; font-weight: 600;
  font-size: var(--fs-body); color: #b9c8de; }
.rail nav .nt-lk { display: grid; grid-template-columns: 21px minmax(0, 1fr) 9px; align-items: center; gap: 12px; flex: 1 1 auto; min-width: 0; min-height: 0;
  padding: 0 12px; border-radius: 10px; color: inherit; text-decoration: none; }
.rail nav .nt-lk:hover { background: none; }
.rail .nt-fb svg { width: 20px; height: 20px; }
.rail button.nt-hd { border: 0; background: none; font: inherit; text-align: left; cursor: pointer; }
.rail .nt-cv { position: absolute; top: 0; right: 26px; bottom: 0; display: grid; place-items: center; width: 28px; padding: 0; border: 0; border-radius: 10px;
  background: #1c3558; color: #fff; opacity: 0; cursor: pointer; }
.rail .nt-cv svg { width: 16px; height: 16px; }
.rail .nt-cv:focus-visible { opacity: 1; }
@media (hover: none), (pointer: coarse), (any-hover: none) {
  .rail .nt-cv { position: static; flex: none; align-self: center; width: 44px; height: 44px; opacity: 1; background: none; color: #8fa4c2; }
  .rail nav .nt-fb:has(.nt-cv) .nt-lk { padding-right: 4px; }
}
.rail .nt-fb:hover, .rail .nt-g.is-open .nt-fb { background: rgba(255, 255, 255, 0.07); color: #fff; }
.rail .nt-fb.here { background: rgba(255, 255, 255, 0.13); color: #fff; font-weight: 700; }
.rail .nt-fb.here .nt-lk > svg:first-child { color: var(--green-400); }
.rail .nt-lk:focus-visible, .rail .nt-cv:focus-visible { outline: 2px solid var(--blue-400); outline-offset: -2px; }
.rail .nt-lb { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The flyout: 230px, 40px rows, own markers. Hidden (display: none) until the group is .is-open. */
.rail .nt-fly { display: none; position: fixed; z-index: 30; left: 0; top: 0; width: 230px; padding: 6px; border-radius: 12px;
  background: #fff; color: var(--navy-950); border: 1px solid var(--slate-200); box-shadow: 0 12px 32px rgba(11, 22, 40, 0.28); }
.rail .nt-g.is-open .nt-fly { display: block; }
@media (prefers-reduced-motion: no-preference) { .rail .nt-g.is-open .nt-fly { animation: nt-fly-in .12s ease-out; } }
@keyframes nt-fly-in { from { opacity: 0; transform: translateX(-4px); } }
.rail .nt-fh { margin: 0; padding: 6px 12px 4px; font-size: var(--fs-caption); font-weight: 700; color: var(--slate-500); }
.rail .nt-kids { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.rail nav .nt-fly a { display: flex; align-items: center; gap: 8px; min-height: 40px; padding: 0 12px; border-radius: 8px; color: var(--navy-950);
  font-size: var(--fs-body); font-weight: 600; text-decoration: none; }
.rail nav .nt-fly a:hover { background: var(--slate-100); color: var(--navy-950); }
.rail nav .nt-fly a.current { background: #e8f1ff; color: var(--blue-700); font-weight: 700; }
.rail nav .nt-fly a:focus-visible { outline: 2px solid var(--blue-600); outline-offset: -2px; }
.rail .nt-fly a > span:first-child { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail .nt-fly .nav-dot { flex: none; box-shadow: none; }
/* Baru is information, not news that waits on you: blue, never red (#0847d6 on #e8f1ff, 6,4:1 or better). */
.rail .nt-new { flex: none; padding: 0 7px; border-radius: 999px; background: #e8f1ff; color: #0847d6; font-size: var(--fs-caption); font-weight: 700; line-height: 16px; white-space: nowrap; }
@media (min-width: 1080px) and (max-height: 600px) { .rail { gap: 12px; } }
/* The destinations scroll inside the rail on a short screen; the foot (business,
   Mulai di sini, Bantuan) stays pinned and in view. */
@media (min-width: 1080px) {
  .rail nav { flex: 0 1 auto; min-height: 0; overflow-y: auto; }
  .rail > .brand, .rail > .rail-foot, .rail > .mulai-rail, .rail > .rail-lapor { flex: none; }
}

.rail-foot {
  margin-top: auto; display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-radius: 12px;
  background: rgba(255, 255, 255, 0.07); color: #eef4fc; text-decoration: none;
}
.rail-foot > span { min-width: 0; flex: 1 1 auto; }
.rail-foot b { display: block; font-size: var(--fs-body); font-weight: 700; line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rail-foot span { font-size: var(--fs-caption); color: #9fb2cd; }

/* ---------- form messages ----------
   An error must be findable without hunting: it sits directly above the fields
   it is about, carries a colour AND an icon glyph (colour alone fails for the
   ~8% of men with a colour vision deficiency, WCAG 1.4.1), and is announced by
   role="alert" / role="status" for anyone using a screen reader. */
.msg { margin: 0 0 16px; padding: 11px 13px 11px 38px; border-radius: 10px;
  font-size: var(--fs-body); line-height: 1.45; position: relative; }
.msg::before { position: absolute; left: 13px; top: 11px; font-weight: 700; }
.msg-bad { background: #fce9ec; color: #7c1023; border: 1px solid #f2ccd3; }
.msg-bad::before { content: "!"; }
.msg-ok  { background: #e4f4ec; color: #0b4f34; border: 1px solid #c6e6d5; }
.msg-ok::before { content: "\2713"; }
.msg-warn { background: var(--warn-soft); color: var(--warn-deep); border: 1px solid #f0d9a8; }
.msg-warn::before { content: "!"; }

/* The user chip is the way to the account menu, and so to sign-out, from
   1080px (it used to be href="#"); below, the avatar button opens the account
   sheet (appnav.html). Give it a visible hover and focus state so it reads
   as the control it now is. */
.who:hover { color: var(--slate-900); }
.who:hover .avatar { box-shadow: 0 0 0 2px var(--brand-100); }
.who:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: 999px; }

/* ---------- account dropdown ----------
   Opens on hover for a pointer, and on :focus-within so a keyboard reaches it
   too — a hover-only menu is unusable by tab and invisible on touch. No script:
   the app pages run under a CSP that forbids one, and a menu that needs
   JavaScript to appear is a menu that is missing while the page is still
   loading on a warehouse connection. */
.who-wrap { position: relative; margin-left: auto; }
.who-wrap .who { margin-left: 0; }
.who-caret { width: 15px; height: 15px; color: var(--slate-500); flex: none;
  transition: transform .15s ease; }
.who-wrap:hover .who-caret, .who-wrap:focus-within .who-caret { transform: rotate(180deg); }

.who-pop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  min-width: 268px; padding: 6px;
  background: var(--paper); border: 1px solid var(--slate-200); border-radius: 13px;
  box-shadow: 0 18px 44px -18px rgba(15, 26, 48, .34);
  display: grid; gap: 2px;
  /* Hidden without display:none so the links stay focusable in source order
     and the menu opens the moment one of them takes focus. */
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity .13s ease, transform .13s ease, visibility .13s;
}
.who-wrap:hover .who-pop,
.who-wrap:focus-within .who-pop { opacity: 1; visibility: visible; transform: none; }

/* A gap between the chip and the panel would close the menu as the pointer
   crosses it, so the gap is bridged by a transparent strip. */
.who-pop::before { content: ""; position: absolute; top: -10px; left: 0; right: 0; height: 10px; }

.who-pop a { display: block; padding: 9px 11px; border-radius: 9px;
  color: inherit; text-decoration: none; }
.who-pop a:hover { background: var(--slate-50); }
.who-pop a:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.who-pop b { display: block; font-size: var(--fs-body); font-weight: 700; }

@media (prefers-reduced-motion: reduce) {
  .who-pop, .who-caret { transition: none; }
}
/* Below the rail breakpoint the account sheet takes the dropdown's place
   (the chip is hidden there, appnav.html). */
@media (max-width: 1079px) {
  .who-pop { display: none; }
  /* No dropdown here, so do not show the affordance for one. */
  .who-caret { display: none; }
}
/* Sign-out sits in the same menu, separated because it is the one entry that
   ends something rather than going somewhere. */
.who-out { margin: 4px 0 0; padding-top: 4px; border-top: 1px solid var(--slate-200); }
.who-out button { display: block; width: 100%; text-align: left; font: inherit;
  padding: 9px 11px; border: 0; border-radius: 9px; background: none; color: var(--crit);
  cursor: pointer; }
.who-out button:hover { background: var(--crit-soft); }
.who-out button:focus-visible { outline: 2px solid var(--crit); outline-offset: -2px; }
.who-out b { display: block; font-size: var(--fs-body); font-weight: 700; }

/* ---------- link affordance ----------
   There was no generic `a:hover` in the app sheets, so a dozen link classes
   had no hover state — including the order number and the primary action in
   the order queue. Buttons and things with their own hover opt out. */
a:not([class]):hover,
a.rowact:hover,
a.crumb:hover,
.note-row a:hover,
.page-head .sub a:hover,
.dt th[scope="row"] > a:hover { text-decoration: underline; }
/* A product or order name that opens its page reads as text, like Produk's
   names (.pname): no blue, no underline until hovered (Steph 2026-10-18,
   "make it consistent"). Laporan, Rugi, Uang bocor, Promo, Retur, the order
   page and Hari ini's lists. */
.pic-t > a:not([class]), .dt th[scope="row"] > a:not([class]), .rc-nm > a:not([class]) { color: inherit; text-decoration: none; }
.pic-t > a:not([class]):hover, .rc-nm > a:not([class]):hover { text-decoration: underline; }

.rail .brand:hover, a.rail-foot:hover { background: rgba(255, 255, 255, .06); }

/* Small inline controls. Shared: a table row that edits one field in
   place needs these on every page that has such a table, not only the
   detail pages they were first written for. */
.btn-xs { display: inline-flex; align-items: center; justify-content: center; gap: 7px; width: auto; min-height: 34px; margin: 0; padding: 0 14px; border-radius: 999px; font-size: var(--fs-body); font-weight: 700; white-space: nowrap; overflow-wrap: normal; text-decoration: none; border: 1px solid var(--slate-300); background: var(--paper); color: var(--navy-950); }
.btn-xs.go { background: var(--blue-600); border-color: var(--blue-600); color: #fff; }
.btn-xs:hover { border-color: var(--blue-600); }
.inline-form { display: inline-flex; align-items: center; gap: 6px; margin: 0; }
.inline-form select { font: inherit; font-size: var(--fs-body); min-height: 34px; padding: 0 8px;
  border: 1px solid var(--slate-300); border-radius: 8px; background: var(--paper); color: inherit; }
.inline-form select:disabled { background: var(--slate-50); color: var(--slate-500); cursor: not-allowed; }
.inline-form button[disabled] { opacity: .45; cursor: not-allowed; }

/* The "belum disatukan" banner on Produk (product-join review v0.1). */
.join-banner { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: center; justify-content: space-between; margin: 0 0 16px;
  padding: 12px 16px; border-radius: 12px; background: var(--warn-soft); color: var(--navy-950); font-size: var(--fs-body); }
.join-banner .btn { margin: 0; }
@media (max-width: 759px) { .join-banner .btn { width: 100%; min-height: 44px; } }

/* A page with nothing to do says so once (Retur, overall review v0.1). */
.calm { padding: 18px 18px 16px; }
.calm .calm-h { margin: 0; font-size: var(--fs-head); font-weight: 700; color: var(--navy-950); }

/* ---------- order line with its picture (Pesanan, Picking) ----------------
   The packer matches the parcel to the picture and the code, not to the
   name: two variants of one product share a name. */
.item { display: flex; align-items: flex-start; gap: 10px; }
.thumb { flex: none; width: 40px; height: 40px; border-radius: 8px; object-fit: cover; background: var(--slate-100); border: 1px solid var(--slate-200); }
.thumb-none { display: inline-flex; align-items: center; justify-content: center; font-size: var(--fs-head); font-weight: 700; color: var(--slate-500); }
.item-t { display: flex; flex-direction: column; min-width: 0; line-height: 1.35; }
.item-t .var { font-size: var(--fs-caption); color: var(--slate-600); }
.item-t .code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: var(--fs-caption); color: var(--slate-500); white-space: nowrap; }
.item .x { font-variant-numeric: tabular-nums; white-space: nowrap; }
.pick-note { display: block; margin-top: 4px; font-size: var(--fs-caption); font-weight: 600; color: var(--warn-deep); }

/* ---------- courier service class (0073) -----------------------------------
   Instant and same-day parcels leave first: their badge is the loudest. */
.svc-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 14px; }
.svc-chip { display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--slate-300); background: var(--paper); color: var(--slate-700); font-size: var(--fs-body); font-weight: 700; text-decoration: none; }
.svc-chip b { font-variant-numeric: tabular-nums; }
.svc-chip:hover { border-color: var(--blue-600); }
.svc-chip.on { background: var(--navy-950); border-color: var(--navy-950); color: #fff; }
.svc-badge { display: inline-block; font-size: var(--fs-caption); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  border-radius: 999px; padding: 2px 7px; vertical-align: 1px; white-space: nowrap; }
.svc-instant { color: var(--crit); background: var(--crit-soft); }
.svc-sameday { color: var(--warn-deep); background: var(--warn-soft); }
.svc-nextday { color: var(--blue-700); background: #e8f1ff; }
.svc-kargo, .svc-reguler { color: var(--slate-700); background: var(--slate-100); }
.svc-cod { color: #5b2a86; background: #f3ebfb; } /* Pesanan rows: the buyer pays on delivery */
.svc-sample { color: #8a3b12; background: #fdf0e6; } /* a refundable affiliate sample (0146) */
.svc-drop { color: var(--slate-700); background: var(--slate-100); } /* placed through a dropshipper (0170): plain, not a warning */
.svc-aff { color: #0f5e57; background: #e3f4f1; } /* sold through an affiliate (0159), distinct from the sample chip */
.svc-kilat { color: #9a3412; background: #ffedd5; text-transform: none; letter-spacing: 0; } /* Shopee Pengiriman Kilat: a booking, stock sent to Shopee's warehouse, no buyer yet */
.svc-chip.svc-instant:not(.on) b { color: var(--crit); }
.courier { color: var(--slate-600); }
/* On a phone a chip row is one line that scrolls sideways, the last chip
   cut at the edge as the cue: nine chips on five lines pushed the first
   row past the screen (QA 2026-10-11, 6). */
@media (max-width: 760px) {
  .svc-chips { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin-right: -16px; padding-right: 16px; }
  .svc-chips::-webkit-scrollbar { display: none; }
  .svc-chips > * { flex: none; }
}

/* ---------- no shop connected yet (templates/kosong.html) -------------------
   One block per page that fills from the shops: what will appear here, and the
   one step that fills it. Left-aligned like every other card, not a centred
   splash, so it reads as part of the page. */
.kosong { display: grid; gap: 6px; justify-items: start; padding: 22px 22px 20px; }
.kosong-ikon { display: inline-grid; place-items: center; width: 40px; height: 40px; border-radius: 11px; background: #e8f1ff; color: var(--blue-700); margin-bottom: 6px; }
.kosong-ikon svg { width: 22px; height: 22px; }
.kosong h2 { margin: 0; font-size: var(--fs-head); line-height: 1.35; color: var(--navy-950); text-wrap: balance; }
.kosong p { margin: 0; color: var(--slate-600); font-size: var(--fs-body); max-width: 58ch; }
.kosong-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin-top: 10px; }
.kosong-alt { font-size: var(--fs-body); font-weight: 600; color: var(--slate-600); }
.kosong-ro { margin: 8px 0 0; font-size: var(--fs-body); color: var(--slate-500); }

/* Hari ini on day one: three steps, the first one actionable. */
.panduan { padding: 20px 22px; margin-bottom: 18px; }
.panduan h2 { margin: 0 0 12px; font-size: var(--fs-head); color: var(--navy-950); }
.panduan-langkah { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.panduan-langkah li { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 12px; align-items: start; padding: 12px 0; border-top: 1px solid var(--slate-100); }
.panduan-langkah li:first-child { border-top: 0; padding-top: 4px; }
.pl-n { margin-top: -3px; display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; font-size: var(--fs-body); font-weight: 700; color: var(--slate-500); background: var(--slate-100); }
.panduan-langkah li.now .pl-n { color: #fff; background: var(--blue-600); }
.pl-txt { display: grid; gap: 2px; }
.panduan-langkah li > .btn { align-self: center; }
.pl-txt b { font-size: var(--fs-head); color: var(--navy-950); }
.pl-txt span { font-size: var(--fs-body); color: var(--slate-500); }
.panduan-langkah li:not(.now) .pl-txt b { color: var(--slate-600); }
@media (max-width: 560px) {
  .panduan-langkah li { grid-template-columns: auto minmax(0, 1fr); }
  .panduan-langkah li .btn { grid-column: 2; justify-self: start; }
}

/* Product thumbnails */
/* One picture style for every product, SKU and order line row
   (templates/thumb.html: "thumb" 40px, "thumb-sm" 32px). Two classes, so it
   holds over the older .thumb rules in catalog.css, detail.css and retur.css
   whichever loads last: the size is fixed and a row never jumps. A missing
   picture is the same box with the name's first letter. */
.thumb.pic {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  box-sizing: border-box; width: 40px; height: 40px; border-radius: 8px;
  object-fit: cover; vertical-align: middle; overflow: hidden;
  background: var(--slate-100); border: 1px solid var(--slate-200);
  color: var(--slate-500); font-size: var(--fs-head); font-weight: 700; line-height: 1;
}
.thumb.pic-sm { width: 32px; height: 32px; border-radius: 7px; font-size: var(--fs-body); }
/* The picture beside the name and its sub-lines. */
.pic-row { display: flex; align-items: center; gap: 10px; min-width: 0; }
.pic-t { display: block; min-width: 0; }
.pic-t .meta, .pic-t .s { display: block; margin-top: 2px; }
@media print { .thumb.pic:not(.pic-sm) { width: 36px; height: 36px; } }

/* Back links */
/* Every page below a section's top level opens with one .crumb line back to
   its parent, filters kept (cmd/api/kembali.go). On a phone the top nav is
   hidden and the menu sheet only knows sections, so this line is the way back.
   It is defined here as well as in detail.css so the pages on catalog.css and
   reports.css (a filtered Produk view, Laporan untung per SKU) have it too.
   On touch every link in it is a 40px-tall target; the phone rules carry
   .app so they hold over detail.css, which loads after this sheet. */
.crumb { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: var(--fs-body); color: var(--slate-500); margin: 0 0 8px; }
.crumb a { color: var(--slate-600); display: inline-block; padding-block: 4px; }
.crumb a:first-child { font-weight: 700; }
@media (max-width: 1079px) {
  .app .crumb { margin-top: -8px; margin-bottom: 0; }
  .app .crumb a { display: inline-flex; align-items: center; min-height: 40px; padding-block: 0; }
}
@media print { .crumb { display: none !important; } }

/* The header avatar shows the person's photo when there is one (Steph
   2026-10-09: the top-right picture did not follow the profile). */
img.avatar { object-fit: cover; display: inline-block; }
/* A thin ring, so a photo with a white background still reads as a circle
   on the white top bar. */
img.avatar { box-shadow: 0 0 0 1px rgba(11, 22, 40, .14); }

/* Kata sandi: the current password on its own row, the new one and its
   repeat side by side, the button on its own row at its natural size
   (Steph 2026-10-09: not aligned). */
.acct-sandi .acct-row { grid-column: 1 / -1; }
/* The current password sits in the first column alone, so its box is
   exactly as wide as the two below it (a 50% max-width missed by the gap). */
.acct-sandi .acct-row:not(.acct-go) { grid-column: 1; }
.acct-sandi .acct-row:not(.acct-go) + p { grid-column: 1; }
.acct-sandi .acct-go { margin: 0; }
.acct-sandi .acct-go .btn { width: auto; min-height: 44px; padding: 10px 20px; }
@media (max-width: 620px) { .acct-sandi .acct-row input { max-width: none; } .acct-sandi .acct-go .btn { width: 100%; } }

/* Pesanan batal */
/* The cancel group (orders/cancel.go) as a chip on a row and the order page,
   and the new-order bar segar.js shows (pesanan_baru.go). */
.grp-badge { display: inline-block; margin-left: 6px; font-size: var(--fs-caption); font-weight: 700; border-radius: 999px;
  padding: 2px 8px; white-space: nowrap; vertical-align: 1px; }
td .grp-badge { display: block; width: max-content; max-width: 132px; margin: 6px 0 0; white-space: normal; line-height: 1.3; }
.grp-badge.grp-lg { font-size: var(--fs-body); padding: 4px 10px; margin-left: 8px; }
.grp-sebelum-kirim { color: var(--slate-700); background: var(--slate-100); }
.grp-gagal-kirim { color: var(--warn-deep); background: var(--warn-soft); }
.grp-retur { color: var(--crit); background: var(--crit-soft); }
.svc-chip.grp-gagal-kirim:not(.on), .svc-chip.grp-retur:not(.on), .svc-chip.grp-sebelum-kirim:not(.on) { background: var(--paper); }
.svc-chip.grp-gagal-kirim:not(.on) b { color: var(--warn-deep); }
.svc-chip.grp-retur:not(.on) b { color: var(--crit); }
/* Batal's two sub-reasons that cost the seller (Telat kirim, Stok habis,
   0211): the colour of Uang hilang. */
.grp-bocor { color: var(--crit); background: var(--crit-soft); }
.svc-chip.grp-bocor:not(.on) { background: var(--paper); }
.svc-chip.grp-bocor:not(.on) b { color: var(--crit); }
/* Gagal kirim's sub-reasons (0096): a quieter second row under the groups. */
.grp-reasons { align-items: center; margin-top: -6px; }
.grp-reasons-lbl { font-size: var(--fs-body); font-weight: 700; color: var(--slate-600); }
.grp-reasons .svc-chip { min-height: 32px; padding: 4px 10px; font-size: var(--fs-body); }
/* Why a search found the order, under its number (0096). */
.sub2.match { color: var(--blue-700); font-weight: 600; overflow-wrap: anywhere; }
.kv.batal-kv { grid-template-columns: max-content minmax(0, 1fr); padding-top: 4px; }
.kv.batal-kv dd { text-align: left; font-weight: 400; }
/* New orders since the page loaded (segar.js): one small pill under the bar, the whole pill reloads
   (Steph 2026-10-16: the dark bottom bar with Tampilkan and x was ugly). */
.segar { position: fixed; z-index: 30; left: 50%; top: calc(64px + env(safe-area-inset-top, 0px)); transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px; max-width: calc(100vw - 32px);
  padding: 6px 16px; border: 0; border-radius: 999px; background: var(--blue-600); color: #fff;
  font: inherit; font-size: var(--fs-body); font-weight: 700; white-space: nowrap; cursor: pointer;
  box-shadow: 0 4px 12px rgba(11, 22, 40, 0.18); }
.segar[hidden] { display: none; }
.segar:focus-visible { outline: 3px solid var(--blue-300, #93c5fd); outline-offset: 2px; }
.segar-up { font-size: var(--fs-head); line-height: 1; }
.segar-note { font-weight: 400; font-size: var(--fs-caption); opacity: 0.85; }
.segar-note:not(:empty)::before { content: "· "; }
.segar-note:empty { display: none; }
@media (min-width: 1080px) { body.app:not(.onb) .segar { top: 72px; left: calc(50% + 124px); } }
/* Under 760px the pill sits in the page's flow, first in main: pinned it covered the red line, the section heads and
   the amounts as the page scrolled (Steph's designer, 2026-10-22). */
@media (max-width: 759px) {
  .segar { position: static; transform: none; display: flex; width: fit-content; margin: 0 auto 12px; box-shadow: none; }
}
/* On a phone the chip sits under the order number, where a long reason fits;
   the Status cell's own chip (the card's narrow top-right corner) stays for
   screen readers only, so the card does not say it twice (tabs v3). */
.grp-badge.grp-phone { display: none; }
@media (max-width: 520px) {
  th .grp-badge.grp-phone { display: block; width: max-content; margin: 6px 0 0; }
  .dt-queue .col-st .grp-badge { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
/* On a phone a form card's main button spans the card (Profil's Simpan and
   Ganti kata sandi, Kirim undangan), so the forms on one page end the same
   way. .app outranks detail.css's ".acct-form .btn-primary", which loads
   later. */
@media (max-width: 620px) {
  .acct-sandi .acct-go .btn { width: 100%; }
  .app .acct-form > .btn-primary { justify-self: stretch; width: 100%; }
}

/* Not found (templates/tidak-ada.html, cmd/api/notfound.go): the app shell
   around one short card, why the page is missing, and the way back. */
.gone { max-width: 560px; margin: 32px auto 0; padding: 28px 28px 24px; text-align: center; }
.gone h1 { margin: 0 0 8px; font-size: var(--fs-hero); letter-spacing: -0.02em; }
.gone-why { max-width: 42ch; margin: 0 auto 20px; font-size: var(--fs-head); line-height: 1.5; color: var(--slate-600); }
.gone-acts { justify-content: center; }
.gone-acts .btn { width: auto; min-height: 46px; margin: 0; padding: 10px 18px; font-size: var(--fs-head); }
@media (max-width: 560px) {
  .gone { margin-top: 8px; padding: 22px 18px 18px; }
  .gone-acts { flex-direction: column; }
  .gone-acts .btn { width: 100%; }
}

/* Laporkan masalah's line back to the page it was opened from, under
   1080px only (on a phone it is the bar's back chevron). From 1080px the
   sidebar is always there, so it is hidden. Carries .app to hold over
   detail.css's .crumb. */
.app .crumb.crumb-menu { display: none; }
@media (max-width: 1079px) { .app .crumb.crumb-menu { display: flex; } }

/* Tampil di toko (0109): a listing's storefronts with Nonaktifkan / Aktifkan
   lagi behind a confirm, on the Produk row menu and the Stok page. */
.tampil-l { padding: 8px 0; border-top: 1px solid var(--slate-200); }
.tampil-l:first-child { border-top: 0; padding-top: 0; }
.tampil-t { margin: 0 0 2px; font-size: var(--fs-body); line-height: 1.35; }
.tampil-s { font-size: var(--fs-caption); color: var(--slate-600); }
/* One line per storefront: "TikTok Shop: tampil · Nonaktifkan"; the confirm opens below it. */
.tampil-f { display: flex; flex-wrap: wrap; align-items: center; column-gap: 10px; margin-top: 2px; }
.tampil-now { margin: 0; font-size: var(--fs-body); }
.tampil-c[open] { flex-basis: 100%; }
.tampil-st { flex-basis: 100%; margin: 0; font-size: var(--fs-caption); font-weight: 600; color: var(--slate-600); }
.tampil-st.bad { color: var(--crit); }
.tampil-form { margin: 0; text-align: left; }
.tampil-x { display: inline-flex; align-items: center; width: auto; min-height: 32px; padding: 0; border: 0; background: none; font: inherit; font-size: var(--fs-body); font-weight: 700; color: var(--slate-600); cursor: pointer; text-decoration: underline; }
.tampil-c > summary { display: inline-flex; align-items: center; min-height: 32px; cursor: pointer; list-style: none; font-size: var(--fs-body); font-weight: 700; color: var(--blue-700); }
.tampil-c.off > summary { color: var(--crit); }
.tampil-c > summary::-webkit-details-marker { display: none; }
.tampil-c > summary:focus-visible, .tampil-x:focus-visible { outline: var(--focus); outline-offset: 2px; }
.tampil-cb { margin: 4px 0 2px; padding: 10px 12px; border: 1px solid var(--slate-200); border-radius: 10px; background: #f8fafc; white-space: normal; text-align: left; }
.tampil-c.off .tampil-cb { border-color: #f3c2cf; background: var(--crit-soft); }
.tampil-cb p { margin: 0 0 6px; font-size: var(--fs-body); line-height: 1.4; }
.row-chip { display: inline-block; margin: 4px 6px 0 0; padding: 2px 8px; border-radius: 999px; font-size: var(--fs-caption); font-weight: 600; text-decoration: none;
  background: var(--slate-100); color: var(--navy-950); }
a.row-chip:hover { text-decoration: underline; }
.row-chip.bad { background: var(--crit-soft); color: var(--crit); }
.row-chip.info { background: #e8f0fe; color: var(--blue-700); }
.row-chip.warn { background: var(--warn-soft); color: var(--warn-deep); }
.row-chips { display: flex; flex-wrap: wrap; }
.rowmenu-tampil { margin: 4px 0 0; padding: 6px 10px 2px; border-top: 1px solid var(--slate-200); }
.cod-all { padding: 6px 0 2px; border-top: 1px dashed var(--slate-200); }
.rowmenu-h { margin: 0 0 4px; font-size: var(--fs-caption); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--slate-600); }

/* ---------- pressed (assets/tekan.js) ----------
   A button that sends work to a marketplace answers at once: a spinner and
   "Memproses…", and further presses are ignored until the next page. */
.btn.is-busy { cursor: progress; opacity: 0.85; pointer-events: none; }
.btn.is-busy::before { content: ""; flex: none; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent; animation: btn-putar 0.8s linear infinite; }
@keyframes btn-putar { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .btn.is-busy::before { animation: none; border-right-color: currentColor; opacity: 0.5; }
}

/* A text link that is a seller's next step ("isi HPP"): a 44px tap target on
   a phone without changing how the sentence reads (WCAG 2.5.8). */
@media (max-width: 759px) {
  a.tap { display: inline-flex; align-items: center; min-height: 44px; }
  a.sub2.tap { display: flex; }
}

/* Pager (templates/pager.html, pager.go): the count, Sebelumnya / numbers /
   Berikutnya, and the "per halaman" choice. 44px targets. On a phone the
   numbers give way to "Hal 5 dari 25". */
.pager { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 18px; margin: 16px 0 4px; }
.pager-n { margin: 0; font-size: var(--fs-body); color: var(--slate-600); font-variant-numeric: tabular-nums; }
.pager-go { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.pager-nums { display: flex; align-items: center; gap: 4px; list-style: none; margin: 0; padding: 0; }
.pager-b, .pager-num { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 44px; padding: 0 12px; border: 1px solid var(--slate-300); border-radius: 10px; background: #fff; color: var(--navy-950); font-size: var(--fs-body); font-weight: 600; text-decoration: none; font-variant-numeric: tabular-nums; }
.pager-b:hover, .pager-num:hover { border-color: var(--slate-500); }
.pager-num.current { background: var(--navy-950); border-color: var(--navy-950); color: #fff; }
.pager-gap { display: inline-flex; min-width: 24px; justify-content: center; color: var(--slate-500); }
.pager-hal { display: none; font-size: var(--fs-body); font-weight: 600; color: var(--slate-700); padding: 0 6px; font-variant-numeric: tabular-nums; }
.pager-per { display: flex; align-items: center; gap: 4px; margin: 0; }
.pager-per-k { font-size: var(--fs-body); color: var(--slate-600); margin-right: 4px; }
@media (max-width: 600px) {
  .pager { flex-direction: column; align-items: stretch; }
  .pager-go { flex-wrap: nowrap; justify-content: space-between; }
  .pager-nums { display: none; }
  .pager-hal { display: inline; }
  .pager-per { justify-content: flex-start; }
  /* A Baru chip on Sebelumnya / Berikutnya takes the room of "Hal 1 dari 2". */
  .pager-b { white-space: nowrap; }
  .pager-go:has(.baru) .pager-hal { display: none; }
}

/* Harga beda per toko (harga-toko.html): under a Produk row's price box and on the product form. */
.ht { margin-top: 6px; text-align: left; }
.ht-sum { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 8px; min-height: 44px; cursor: pointer; list-style: none; }
.ht-sum::-webkit-details-marker { display: none; }
.ht-link { font-size: var(--fs-caption); font-weight: 700; color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }
.ht-link::after { content: " ▾"; text-decoration: none; display: inline-block; margin-left: 2px; }
.ht[open] .ht-link::after { content: " ▴"; }
.ht-hint { display: inline-block; font-size: var(--fs-caption); font-weight: 700; color: var(--slate-700); background: var(--slate-100); border-radius: 999px; padding: 2px 8px; }
.ht-sum:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 6px; }
.ht-form { display: grid; gap: 8px; margin-top: 4px; padding: 10px; border: 1px solid var(--slate-200); border-radius: 10px; background: var(--slate-50, #f8fafc); min-width: 0; }
.ht-note, .ht-ok, .ht-msg { margin: 0; font-size: var(--fs-caption); color: var(--slate-600); }
.ht-ok { color: var(--ok, #15803d); font-weight: 700; }
.ht-msg { color: var(--crit); font-weight: 700; }
.ht-row { display: grid; gap: 4px; }
.ht-shop { margin: 0; font-size: var(--fs-caption); font-weight: 700; color: var(--slate-700); }
.ht-in { display: flex; align-items: center; gap: 4px; min-height: 44px; padding: 0 10px; border: 1px solid var(--slate-300); border-radius: 8px; background: var(--paper, #fff); }
.ht-in .pre { font-size: var(--fs-caption); font-weight: 700; color: var(--slate-500); }
.ht-in input { flex: 1; min-width: 0; width: 100%; min-height: 42px; border: 0; padding: 0; background: transparent; font: inherit; font-size: var(--fs-body); font-weight: 700; font-variant-numeric: tabular-nums; text-align: right; color: var(--navy-950); }
.ht-in input:focus { outline: none; }
.ht-in:focus-within { outline: 3px solid var(--blue-400); outline-offset: 1px; border-color: var(--blue-600); }
.ht-in input::placeholder { color: var(--slate-400); font-weight: 600; }
.ht-in.bad { border-color: var(--crit); background: var(--crit-soft); }
.ht-acts { display: flex; flex-wrap: wrap; gap: 8px; }
.ht-confirm { min-height: 44px; padding: 0 14px; border: 1px solid var(--warn-deep); border-radius: 10px; background: var(--paper, #fff); color: var(--warn-deep);
  font: inherit; font-size: var(--fs-body); font-weight: 700; cursor: pointer; text-align: left; }
.ht-confirm:focus-visible { outline: 3px solid var(--blue-400); outline-offset: 2px; }
.ht-go { min-height: 44px; padding: 0 14px; border: 0; border-radius: 10px; background: var(--brand); color: #fff; font: inherit; font-size: var(--fs-body); font-weight: 700; cursor: pointer; justify-self: start; }
.ht-go:focus-visible { outline: 3px solid var(--blue-400); outline-offset: 2px; }
.ht-sec { margin-top: 24px; }
.ht-sec .ht-form { max-width: 420px; }

/* ---------- the business is being deleted (0154) ----------
   The banner rides in rail-foot, the one partial on every app page. Under
   1080px the rail is hidden, so the rail gives up its box (display: contents)
   and shows only the banner, which lands above the top bar. From 1080px it is
   a fixed strip across the content area and the top bar sticks under it. */
.hapus-banner { display: flex; align-items: center; gap: 6px 14px; flex-wrap: wrap;
  padding: 10px 16px; background: var(--warn-soft); color: var(--warn-deep);
  border-bottom: 1px solid #f0d9a8; font-size: var(--fs-body); line-height: 1.4; }
.hapus-banner p { margin: 0; flex: 1 1 220px; }
.hapus-banner a { color: inherit; font-weight: 700; text-decoration: underline; white-space: nowrap;
  min-height: 24px; display: inline-flex; align-items: center; }
.hapus-banner a:focus-visible { outline: 2px solid var(--warn-deep); outline-offset: 2px; border-radius: 4px; }
@media (max-width: 1079px) {
  .rail:has(> .hapus-banner) { display: contents; }
  .rail:has(> .hapus-banner) > :not(.hapus-banner):not(.fb-zone) { display: none; }
}
@media (min-width: 1080px) {
  body.app:has(.rail > .hapus-banner) { padding-top: 44px; }
  body.app:has(.rail > .hapus-banner) .app-bar { top: 44px; }
  .rail > .hapus-banner { position: fixed; top: 0; left: 248px; right: 0; height: 44px; z-index: 21;
    flex-wrap: nowrap; padding: 0 28px; }
  .rail > .hapus-banner p { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}

/* ---------- a new shop's first sync (0164; slim line since batch 3) ----------
   "⟳ Sinkron <toko>" / "⟳ Sinkron 2 toko" on every app page while a first
   sync runs, gone when done (firstsync.go). The whole 28px line links to
   Toko. It rides in rail-foot like the deletion banner and is moved the same
   way: under the top bar below 1080px, a fixed strip over the content area
   from 1080px. One line (ellipsis), rendered by the server. */
.sync-ticker { height: 28px; display: flex; align-items: center; padding: 0 16px;
  background: #eaf2ff; color: var(--blue-800); border-bottom: 1px solid #cfe0fb; font-size: var(--fs-caption); }
.sync-ticker a, .sync-ticker > span { display: flex; align-items: center; gap: 6px; min-width: 0; min-height: 28px; flex: 1 1 auto;
  color: inherit; text-decoration: none; font-weight: 600; }
.sync-ticker a:hover .st-text { text-decoration: underline; }
.sync-ticker a:focus-visible { outline: 2px solid var(--blue-600); outline-offset: -2px; border-radius: 4px; }
.sync-ticker .st-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.sync-ticker .st-ico { flex: none; display: block; animation: st-spin 2.4s linear infinite; }
.sync-ticker.is-warn { background: var(--warn-soft); color: var(--warn-deep); border-bottom-color: #f0d9a8; }
.sync-ticker.is-warn .st-ico { animation: none; }
@keyframes st-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .sync-ticker .st-ico { animation: none; } }
@media (max-width: 1079px) {
  .rail:has(> .sync-ticker) { display: contents; }
  .rail:has(> .sync-ticker) > :not(.sync-ticker):not(.hapus-banner):not(.fb-zone) { display: none; }
}
@media (min-width: 1080px) {
  body.app:has(.rail > .sync-ticker) { padding-top: 28px; }
  body.app:has(.rail > .sync-ticker) .app-bar { top: 28px; }
  .rail > .sync-ticker { position: fixed; top: 0; left: 248px; right: 0; z-index: 21; padding: 0 28px; }
}

/* ---------- the authorization strip (izin.go, Steph 2026-10-21) ----------
   A shop's izin ends within 14 days or has ended: one 44px strip on every
   page (text, Izinkan ulang or Lihat toko, × until tomorrow), placed and moved
   like the first-sync line, whose place it takes. Amber, red at 3 days. */
.izin-ticker { min-height: 44px; display: flex; align-items: center; gap: 4px 12px; padding: 0 16px;
  background: var(--warn-soft); color: var(--warn-deep); border-bottom: 1px solid #f0d9a8; font-size: var(--fs-caption); }
.izin-ticker.is-urgent { background: var(--crit-soft); color: var(--crit); border-bottom-color: #f5c2d0; }
.izin-ticker .it-text { flex: 1 1 auto; min-width: 0; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.izin-ticker .it-form { margin: 0; display: flex; flex: none; }
.izin-ticker .it-act { flex: none; min-height: 32px; padding: 0 12px; border-radius: 8px; border: 1px solid currentColor; background: var(--paper);
  color: inherit; font: inherit; font-weight: 700; text-decoration: none; display: inline-flex; align-items: center; cursor: pointer; white-space: nowrap; }
.izin-ticker .it-ask { flex: none; font-weight: 600; white-space: nowrap; }
.izin-ticker .it-x { flex: none; width: 44px; height: 44px; margin-right: -12px; border: 0; background: none; color: inherit;
  font-size: var(--fs-hero); line-height: 1; cursor: pointer; }
.izin-ticker .it-act:focus-visible, .izin-ticker .it-x:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
@media (max-width: 1079px) {
  .rail:has(> .izin-ticker) { display: contents; }
  .rail:has(> .izin-ticker) > :not(.izin-ticker):not(.hapus-banner):not(.fb-zone) { display: none; }
}
@media (max-width: 759px) {
  /* One slim line like the first-sync one: the text gives way (ellipsis), the
     action and × stay beside it. */
  .izin-ticker { min-height: 36px; gap: 8px; padding: 0 0 0 16px; }
  .izin-ticker .it-act { min-height: 28px; padding: 0 10px; }
  .izin-ticker .it-x { width: 36px; height: 36px; margin: 0; }
}
@media (min-width: 1080px) {
  body.app:has(.rail > .izin-ticker) { padding-top: 44px; }
  body.app:has(.rail > .izin-ticker) .app-bar { top: 44px; }
  .rail > .izin-ticker { position: fixed; top: 0; left: 248px; right: 0; z-index: 21; padding: 0 28px; }
}

/* ---------- Notifikasi (0156): updates from Satusetir ---------- */
/* The account chip's dot: an unread update, beside the avatar. Next to a
   visually hidden label, never alone. */
.who { position: relative; }
.who-dot { position: absolute; left: 24px; top: -1px; width: 10px; height: 10px; border-radius: 50%; background: #0a5cf0; box-shadow: 0 0 0 2px var(--paper); }
.who-pop .nav-dot, .kabar-dot { display: inline-block; width: 8px; height: 8px; margin: 0 0 0 6px; border-radius: 50%; background: #0a5cf0; vertical-align: 2px; }
.kabar-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.kabar { background: var(--paper); border: 1px solid var(--slate-200); border-radius: 14px; padding: 16px 18px; }
.kabar.unread { border-color: #b9cdf7; box-shadow: inset 4px 0 0 var(--blue-600); }
.kabar h2 { margin: 6px 0 6px; font-size: var(--fs-head); line-height: 1.35; letter-spacing: -0.01em; }
.kabar-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 0; font-size: var(--fs-body); color: var(--slate-600); }
.kabar-cat { display: inline-block; font-size: var(--fs-caption); font-weight: 700; border-radius: 999px; padding: 2px 9px; background: var(--slate-100); color: var(--slate-700); }
.kabar-fitur { background: #e4f4ec; color: #0b4f34; }
.kabar-perubahan { background: #e8f1ff; color: var(--blue-800); }
.kabar-pemeliharaan { background: #fdf0dd; color: #8a3a06; }
.kabar-penting { background: var(--crit-soft); color: #9b0c3a; }
.kabar-body { font-size: var(--fs-head); color: var(--slate-700); overflow-wrap: anywhere; }
.kabar-body p { margin: 0 0 10px; }
.kabar-body p:last-child { margin-bottom: 0; }
.kabar-acts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.kabar-acts form { margin: 0; }
.kabar-acts .btn-sm { min-height: 44px; }
.kabar-empty { padding: 18px; }
.kabar-empty p { margin: 0 0 4px; }
.kabar-banner { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 10px 16px; margin: 0 0 16px; padding: 14px 16px; border-radius: 14px; border: 1px solid #f1d3a8; background: #fff8ee; }
.kabar-banner-penting { border-color: #f5c2d1; background: #fff5f8; }
.kabar-banner-text { flex: 1 1 260px; min-width: 0; }
.kabar-banner-text p { margin: 0; }
.kabar-banner-title { margin-top: 6px !important; font-size: var(--fs-head); }
.kabar-banner-line { font-size: var(--fs-body); color: var(--slate-700); margin-top: 2px !important; overflow-wrap: anywhere; }
.kabar-banner a { display: inline-block; margin-top: 6px; padding-block: 4px; font-size: var(--fs-body); font-weight: 700; }
.kabar-banner form { margin: 0; }
.kabar-banner .btn-sm { min-height: 44px; }
.kabar-list, .kabar-empty { max-width: 780px; }
.kabar-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; max-width: 780px; margin: 22px 0 12px; }
.kabar-head h2 { margin: 0; font-size: var(--fs-head); letter-spacing: -0.01em; }
.kabar-head form { margin: 0; }
.kabar-head .btn-sm { min-height: 44px; }

/* ---------- Pemberitahuan di perangkat ini (0161, notif.js) ---------- */
/* The opt-in on Hari ini and Pesanan: shown by the script only. */
.notif-card { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 14px; margin: 0 0 16px; padding: 14px 16px; border-radius: var(--radius); border: 1px solid #b9cdf7; background: #f3f7ff; }
.notif-card[hidden] { display: none; }
.stack > .notif-card { margin: 0; }
.notif-card-icon { flex: none; align-self: flex-start; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 12px; background: var(--paper); color: var(--blue-700); border: 1px solid #d5e2fb; }
.notif-card-icon svg { width: 22px; height: 22px; }
.notif-card-text { flex: 1 1 0; min-width: 0; }
.notif-card-text p { margin: 0; }
.notif-card-title { font-size: var(--fs-head); }
.notif-card-line { font-size: var(--fs-body); color: var(--slate-700); margin-top: 2px !important; overflow-wrap: anywhere; }
.notif-card-line:empty { display: none; }
.notif-card-line a { font-weight: 700; }
.notif-card-acts { display: flex; flex-wrap: wrap; gap: 8px; }
.notif-card-acts .btn-sm, .notif-dev-acts .btn-sm { min-height: 44px; }
.notif-card-acts [hidden], .notif-dev-acts [hidden] { display: none; }
@media (max-width: 520px) {
  .notif-card-acts { flex: 1 1 100%; }
  .notif-card-acts .btn-sm { flex: 1 1 0; }
}
/* Hari ini's "Berikutnya: isi HPP" card (hari_ini_hpp.go): a next step, not an alert. */
.hpp-card { margin: 0 0 16px; padding: 16px 18px; border-radius: var(--radius); border: 1px solid #b9cdf7; background: #f3f7ff; }
.hpp-card h2 { margin: 0 0 4px; font-size: var(--fs-head); letter-spacing: -0.01em; }
.hpp-card p { margin: 0 0 14px; font-size: var(--fs-body); color: var(--slate-700); max-width: 60ch; }
.hpp-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; }
.hpp-acts form { margin: 0; }
.hpp-acts .btn { width: auto; min-height: 44px; margin: 0; padding: 10px 18px; font-size: var(--fs-head); }
@media (max-width: 520px) {
  .hpp-acts form, .hpp-acts .btn { flex: 1 1 100%; }
  .hpp-acts form .btn { width: 100%; }
}
/* The settings section on Pengaturan > Notifikasi. */
.notif-dev { max-width: 780px; }
.notif-dev h2 { margin-bottom: 6px; }
.notif-dev-sub { margin: 0; font-size: var(--fs-body); color: var(--slate-700); }
.notif-dev-state { display: flex; align-items: baseline; gap: 8px; margin: 14px 0 0; font-size: var(--fs-body); font-weight: 700; color: var(--navy-950); }
/* Until notif.js knows the device the card is drawn whole but not shown, so it does not grow (designer #38). */
.notif-dev-state:empty { min-height: 1.5em; }
.notif-dev[data-checking] :is(.notif-dev-acts, .notif-dev-prefs) { visibility: hidden; }
/* The state's dot: green when on, amber when the browser blocks it. Never
   colour alone: the sentence says it. */
.notif-dev-state[data-mode]::before { content: ""; flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--slate-400); transform: translateY(-1px); }
.notif-dev-state[data-mode="on"]::before { background: var(--ok); }
.notif-dev-state[data-mode="blocked"] { color: var(--warn-deep); }
.notif-dev-state[data-mode="blocked"]::before { background: var(--warn); }
.notif-dev-acts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.notif-dev-acts[hidden], .notif-dev-prefs[hidden] { display: none; }
.notif-dev-prefs { margin: 18px 0 0; padding: 0; border: 0; min-width: 0; }
.notif-dev-prefs legend { padding: 0; font-size: var(--fs-body); font-weight: 700; color: var(--navy-950); }
.notif-dev-prefs .check { display: flex; align-items: center; min-height: 44px; margin-top: 0; font-size: var(--fs-body); color: var(--navy-950); }
.notif-dev-prefs .check input { margin-top: 0; }
.notif-dev-prefs legend + .check { margin-top: 4px; }
.notif-dev-sound { padding-top: 4px; border-top: 1px dashed var(--slate-200); margin-top: 8px !important; }
.notif-dev-saved { margin: 10px 0 0; font-size: var(--fs-body); color: var(--slate-600); }
.notif-dev-saved:empty { margin: 0; }
/* The two sounds, each with Coba (2026-10-20): under Bunyikan nada, gone when it is off. */
.notif-dev-nada { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px 12px; max-width: 440px; margin: 4px 0 0 28px; }
.notif-dev-prefs:has(input[name=sound]:not(:checked)) .notif-dev-nada { display: none; }
.notif-dev-nada-row { display: contents; }
.notif-dev-nada-row span { align-self: center; min-width: 0; font-size: var(--fs-body); color: var(--slate-700); }
.notif-dev-nada-row .btn-sm { justify-self: end; min-height: 44px; }

/* Laporkan masalah (0163): the sidebar's beta line under the business card
   (templates/lapor-link.html), and the error page's code (requestid.go). */
/* From 1080px Laporkan lives here, a quiet button in the sidebar's foot
   (Steph 2026-10-15, batch 2: the floating pill covered action buttons). */
.rail-lapor { display: flex; align-items: center; gap: 10px; min-height: 40px; margin-top: 8px; padding: 0 12px; border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 10px; color: #b9c8de; font-size: var(--fs-body); font-weight: 600; text-decoration: none; }
.rail-lapor::before { content: ""; flex: none; width: 18px; height: 18px; background: currentColor;
  -webkit-mask: var(--flag-icon) center / contain no-repeat; mask: var(--flag-icon) center / contain no-repeat; }
.rail-lapor u { color: inherit; text-decoration: none; }
.rail-lapor:hover { background: rgba(255, 255, 255, .07); color: #fff; }
:root { --flag-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M9.6 9.4a2.5 2.5 0 1 1 3.6 2.2c-.8.4-1.2 1-1.2 1.8M12 16.8h.01'/%3E%3C/svg%3E"); }
.rail-lapor:focus-visible { outline: 2px solid var(--blue-400); outline-offset: 1px; }
.gone-code { margin: -8px auto 20px; font-size: var(--fs-body); color: var(--slate-600); }
.gone-code b { font-variant-numeric: tabular-nums; letter-spacing: 0.04em; color: var(--navy-950); }

/* ---------- Email verification (0168, templates/verifikasi.html) ---------- */
.verif-addr { color: var(--navy-950); overflow-wrap: anywhere; }
.verif-note { margin: 0; font-size: var(--fs-body); color: var(--slate-600); }
.verif-alt { margin-top: 20px; border-top: 1px solid var(--slate-200); padding-top: 14px; }
.verif-alt summary { cursor: pointer; font-weight: 700; font-size: var(--fs-body); color: var(--blue-600);
  min-height: 24px; display: list-item; }
.verif-alt summary:focus-visible { outline: 3px solid var(--blue-400); outline-offset: 2px; border-radius: 6px; }
.verif-alt form { margin-top: 6px; }
.verif-wide { width: 100%; margin-top: 12px; }
.verif-out { margin-top: 22px; justify-items: center; }
.verif-out button { font: inherit; font-size: var(--fs-body); font-weight: 700; color: var(--slate-600); background: none;
  border: 0; padding: 6px 10px; min-height: 32px; cursor: pointer; text-decoration: underline; }
.verif-out button:hover { color: var(--navy-950); }
/* The soft mode's banner on every app page (rail-foot): the deletion
   banner's look and placement. */
.verif-banner { display: flex; align-items: center; gap: 6px 14px; flex-wrap: wrap;
  padding: 10px 16px; background: var(--warn-soft); color: var(--warn-deep);
  border-bottom: 1px solid #f0d9a8; font-size: var(--fs-body); line-height: 1.4; }
.verif-banner p { margin: 0; }
.verif-banner form { display: inline; }
.verif-banner a, .verif-banner button { font: inherit; color: inherit; font-weight: 700; text-decoration: underline;
  background: none; border: 0; padding: 0; cursor: pointer; min-height: 24px; white-space: nowrap; }
@media (max-width: 1079px) {
  .rail:has(> .verif-banner) { display: contents; }
  .rail:has(> .verif-banner) > :not(.verif-banner):not(.fb-zone) { display: none; }
}
@media (min-width: 1080px) {
  body.app:has(.rail > .verif-banner) { padding-top: 44px; }
  body.app:has(.rail > .verif-banner) .app-bar { top: 44px; }
  .rail > .verif-banner { position: fixed; top: 0; left: 248px; right: 0; height: 44px; z-index: 21;
    flex-wrap: nowrap; padding: 0 28px; }
}
/* ---------- Confirm WhatsApp + Ganti email (PROPOSAL, kontak.html) ----------
   The WhatsApp line takes the email banner's place and placement, in a calm
   blue: nothing is at risk. The connect block shows the QR from 760px (the
   phone's camera reads it), the button alone below (it opens WhatsApp). */
.wa-banner { background: #eef4ff; color: var(--navy-950); border-bottom-color: #d6e4ff; flex-wrap: nowrap; }
.wa-banner form { margin-left: auto; }
.wa-banner form button { font-weight: 700; color: var(--slate-600); }
.btn.btn-wa { display: inline-flex; align-items: center; justify-content: center; gap: 8px; width: auto; min-height: 44px;
  padding: 10px 18px; background: #128c4a; border-color: #128c4a; color: #fff; font-weight: 700; text-decoration: none; }
.btn.btn-wa:hover { background: #0e743d; }
.btn.btn-wa:focus-visible { outline: 3px solid var(--blue-400); outline-offset: 2px; }
.wa-kode { display: grid; grid-template-columns: 160px minmax(0, 1fr); gap: 16px 20px; align-items: center; }
.wa-qr { width: 160px; height: 160px; padding: 8px; background: #fff; border: 1px solid var(--slate-200); border-radius: 12px; }
.wa-qr svg { display: block; width: 100%; height: 100%; }
.wa-go { display: grid; gap: 8px; justify-items: start; min-width: 0; }
.wa-go p { margin: 0; }
.wa-qr-h { font-weight: 700; color: var(--navy-950); }
.wa-hp-h { display: none; }
.wa-dt-only { display: inline; }
.wa-hp-only { display: none; }
.wa-code { font-size: var(--fs-caption); color: var(--slate-600); }
.wa-code b { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.04em; color: var(--navy-950); }
.wa-wait { display: flex; align-items: center; gap: 8px; font-size: var(--fs-body); color: var(--slate-600); }
.wa-wait.is-late { display: block; color: var(--warn-deep); font-weight: 700; }
.wa-dot { width: 8px; height: 8px; border-radius: 50%; background: #128c4a; animation: wa-pulse 1.2s ease-in-out infinite; }
@keyframes wa-pulse { 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) { .wa-dot { animation: none; } }
.form-wrap .wa-kode { grid-template-columns: minmax(0, 1fr); justify-items: start; margin-top: 4px; }
@media screen and (max-width: 759px) {
  .wa-kode { grid-template-columns: minmax(0, 1fr); }
  .wa-qr, .wa-qr-h, .wa-atau, .wa-dt-only { display: none; }
  .wa-hp-only { display: inline; }
  .wa-hp-h { display: block; }
  .wa-go .btn-wa, .form-wrap .btn-wa { width: 100%; }
}
.kt-card { gap: 12px; }
.kt-card > *, .kt-ganti > * { grid-column: 1 / -1; }
.kt-row { display: flex; align-items: center; justify-content: space-between; gap: 8px 12px; flex-wrap: wrap; min-height: 44px; }
.kt-val { font-weight: 700; color: var(--navy-950); overflow-wrap: anywhere; min-width: 0; }
.kt-act { width: auto; min-height: 44px; }
.kt-wait { margin: 0; font-size: var(--fs-body); color: var(--warn-deep); overflow-wrap: anywhere; }
.kt-btns { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.kt-btns > .btn, .kt-btns > form > .btn { margin: 0; }
.kt-btns form { margin: 0; }
.kt-btns .btn, .kt-act { display: inline-flex; align-items: center; justify-content: center; width: auto; min-height: 44px; padding: 10px 18px; }
.kt-now { margin: 0; font-size: var(--fs-body); color: var(--slate-600); }
.kt-putus summary { list-style: none; display: inline-flex; align-items: center; min-height: 44px; cursor: pointer; }
.kt-putus summary::-webkit-details-marker { display: none; }
.kt-putus[open] summary { display: none; }
.kt-putus .btn-danger { width: auto; min-height: 44px; }
.wa-atau { font-size: var(--fs-caption); color: var(--slate-500); }
.wa-nanti { margin-top: 16px; } .wa-nanti .btn { width: 100%; min-height: 44px; }
.kt-ganti { display: grid; gap: 14px; }

/* Mulai's soft-mode card (0168): text, then a quiet button at its own width. */
.verif-card p { margin: 0; }
.verif-card form { display: flex; margin-top: 10px; }
.verif-card .btn { width: auto; }

/* ---------- Masukan (0174, templates/masukan.html, masukan.go) ----------
   The floating Laporkan button, the one-time feedback card and the sentence
   after a press on either. All three are fixed-position pieces of "fb-zone",
   which rides in rail-foot (the one partial on every app page). From 1080px
   the rail is a real sidebar and a fixed child of it is placed against the
   window anyway. Under 1080px the rail is hidden, so it gives up its box
   and hides everything but the zone (the same trick as the banners above).
   The button is small and quiet: no shadow, no animation, no badge. It
   clears the safe area, and gives way to anything
   that sticks to the bottom of a page (a bulk bar, the picker's selection
   bar), so it never covers a primary button. */
.fb-zone { display: contents; }
.fb, .fb-card, .fb-flash { position: fixed; z-index: 15; right: 16px; }
.fb { bottom: 16px; font: inherit; display: flex; align-items: center; padding: 2px; border-radius: 999px;
  background: var(--paper); border: 1px solid var(--slate-300); color: var(--slate-600); opacity: .88; }
.fb:hover, .fb:focus-within { opacity: 1; border-color: var(--slate-400); }
.fb form { margin: 0; display: flex; }
.fb-go { display: inline-flex; align-items: center; gap: 6px; min-height: 34px; padding: 0 10px 0 12px; border-radius: 999px;
  color: inherit; font-size: var(--fs-body); font-weight: 700; text-decoration: none; }
.fb-go svg { width: 16px; height: 16px; flex: none; }
.fb-go:hover { color: var(--navy-950); }
.fb-x { display: grid; place-items: center; width: 28px; height: 28px; padding: 0; border: 0; border-radius: 50%;
  background: transparent; color: var(--slate-500); cursor: pointer; }
.fb-x svg { width: 14px; height: 14px; }
.fb-x:hover { background: var(--slate-100); color: var(--navy-950); }
/* Pages with something stuck to the bottom: the button steps aside. */
body.qbar-on .fb, body:has(.kq-bulk, .pp-bar, .vf-bar) .fb { display: none; }
/* From 1080px the sidebar's foot has Laporkan masalah (.rail-lapor): no
   floating pill there (batch 2, 2026-10-15: it sat over action buttons). */
@media (min-width: 1080px) { .fb-zone .fb { display: none; } }
@media print { .fb-zone { display: none; } }

.fb-card { bottom: 64px; color: var(--navy-950); width: min(360px, calc(100vw - 32px)); display: grid; gap: 10px; padding: 14px 16px 6px;
  border-radius: 14px; background: var(--paper); border: 1px solid var(--slate-300);
  box-shadow: 0 14px 34px -16px rgba(11, 22, 40, .45); }
.fb-card h2 { margin: 0; font-size: var(--fs-head); line-height: 1.4; font-weight: 700; letter-spacing: -0.01em; }
.fb-err { margin: 0; font-size: var(--fs-body); font-weight: 700; color: var(--crit); }
.fb-scale { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 4px 6px; min-width: 0; margin: 0; padding: 0; border: 0; }
.fb-face { position: relative; display: grid; place-items: center; min-height: 44px; border-radius: 12px;
  border: 1px solid var(--slate-200); background: var(--paper); color: var(--slate-600); cursor: pointer; }
.fb-face svg { width: 30px; height: 30px; }
.fb-face:hover { border-color: var(--blue-600); color: var(--blue-700); }
.fb-face:has(input:checked) { background: #e8f1ff; border-color: var(--blue-600); color: var(--blue-700); }
.fb-face:has(input:focus-visible) { outline: 3px solid var(--blue-400); outline-offset: 2px; }
.fb-ends { grid-column: 1 / -1; display: flex; justify-content: space-between; gap: 8px; margin: 0; font-size: var(--fs-caption); color: var(--slate-600); }
/* The comment box opens once a face is chosen. A browser without :has() shows it at once. */
.fb-more { display: none; gap: 8px; }
.fb-card:has(input[name=skor]:checked) .fb-more { display: grid; }
@supports not selector(:has(*)) { .fb-more { display: grid; } }
.fb-more label { font-size: var(--fs-body); font-weight: 700; line-height: 1.4; }
.fb-more textarea { width: 100%; min-height: 54px; padding: 8px 10px; border: 1px solid var(--slate-300); border-radius: 10px;
  font: inherit; font-size: var(--fs-body); line-height: 1.45; resize: vertical; }
.fb-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 0 14px; }
/* Kirim waits for a face, like the comment box. */
.fb-send { display: none; width: auto; min-height: 44px; margin: 0 4px 0 0; padding: 10px 22px; }
.fb-card:has(input[name=skor]:checked) .fb-send { display: inline-flex; }
@supports not selector(:has(*)) { .fb-send { display: inline-flex; } }
.fb-acts button:not(.fb-send) { min-height: 44px; padding: 0 2px; border: 0; background: none; color: var(--slate-600);
  font: inherit; font-size: var(--fs-body); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.fb-acts button:not(.fb-send):hover { color: var(--navy-950); }

.fb-flash { bottom: 64px; max-width: min(360px, calc(100vw - 32px)); display: flex; flex-wrap: wrap; align-items: center; gap: 2px 14px;
  padding: 10px 14px; border-radius: 12px; background: var(--navy-950); color: #fff; font-size: var(--fs-body); line-height: 1.45;
  animation: fb-out 0s linear 14s forwards; }
.fb-flash p { margin: 0; }
.fb-flash form { margin: 0; }
.fb-flash button { min-height: 36px; padding: 0; border: 0; background: none; color: #fff; font: inherit; font-weight: 700;
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.fb-flash button:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
@keyframes fb-out { to { visibility: hidden; } }

/* Under 1080px (no tab bar since 2026-10-15): everything clears the phone's safe area. */
@media (max-width: 1079px) {
  .rail:has(> .fb-zone) { display: contents; }
  .rail:has(> .fb-zone) > :not(.fb-zone):not(.hapus-banner):not(.sync-ticker):not(.izin-ticker):not(.verif-banner) { display: none; }
  .fb { right: 12px; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
  .fb-card { left: 12px; right: 12px; width: auto; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
  .fb-flash { right: 12px; bottom: calc(66px + env(safe-area-inset-bottom, 0px)); }
  /* The card takes the button's place while it is open. */
  .fb-zone:has(.fb-card) .fb { display: none; }
  /* The last line of a page clears the button. */
  body.app:has(.fb):not(.qbar-on) .page { padding-bottom: 72px; }
}
/* A phone: the flag alone, still a 40px target. */
@media (max-width: 759px) {
  .fb-lbl { display: none; }
  .fb-go { width: 40px; min-height: 40px; padding: 0; justify-content: center; }
  .fb-go svg { width: 20px; height: 20px; }
  .fb-x { width: 32px; height: 32px; }
}

/* ---------- Phone chrome: ONE row (Steph 2026-10-15) ----------
   "Space is gold on a phone": under 760px the only chrome is one 52px row:
   the menu button, the page's own title, Laporkan (a flag) and the account.
   No tab bar since 2026-10-15 (option A, Steph: no logo in the bar): the
   menu button and the avatar open the sheets (appnav.html, above).
   No title block, no date line, no breadcrumb line. Done in this sheet, which
   every app page loads, from the markup each page already has:
   - the page's h1 (in .page-head, or any h1.bar-h) is lifted into the bar,
     one or two lines, its words unchanged for screen readers;
   - a .crumb line becomes the bar's back button: its LAST link (the page one
     level up), drawn as a chevron, its words kept as the link's name; the
     menu button gives way to it (a detail page goes back);
   - .page-head .sub (the explanation under a title) waits for the desktop,
     except a .sub-hp, which says something the page needs (Laporan's shop
     scope, a promo's status);
   - the first-sync ticker and the banners sit under the bar instead of above;
   - Laporkan is the bar's flag, beside the account (the floating button
     waits for the tablet and the desktop).
   From 760px nothing here applies. cmd/api/kepala_hp_test.go holds it. */
@media screen and (max-width: 759px) {
  /* The safety net (Steph 2026-10-15, round 3: "fix permanently and avoid
     this in future"): a phone page never pans sideways, whatever a box in it
     does. clip, not hidden: no scroll box, so the sticky bar, the fixed tab
     sheets and the strips that scroll on their own keep working. A box too
     wide is still a bug: scripts/overflow.mjs measures with this net off. */
  html:has(> body.app), body.app { overflow-x: clip; }
  body.app .app-bar .app-wrap { min-height: 52px; gap: 4px; padding-inline: 4px 8px; }
  body.app .nav-btn { margin-left: 0; }
  /* No logo in the bar (Steph 2026-10-15); onboarding, which has no menu, keeps its mark. */
  body.app:not(.onb) .app-bar .brand { display: none; }
  body.app.onb .app-bar .brand { gap: 0; font-size: 0; min-width: 44px; min-height: 44px; }
  body.app.onb .app-bar .brand img { width: 30px; height: 30px; }
  body.app .app-bar .brand .beta { display: none; }
  body.app .bar-flag { display: grid; place-items: center; flex: none; width: 44px; height: 44px; margin-left: auto; border-radius: 10px; color: var(--slate-600); }
  body.app .bar-flag svg { width: 22px; height: 22px; }
  body.app .who-btn { flex: none; justify-content: center; width: 44px; min-width: 44px; margin-left: 0; padding: 0; }
  body.app .who-btn .avatar { width: 34px; height: 34px; }
  body.app .who-btn .who-name { display: none; }
  body.app .who-btn .who-dot { left: 28px; top: 4px; }
  body.app .page { padding-top: 8px; }

  /* The title, in the bar between the menu button (or the back button) and Laporkan.
     A page's title sits in .page-head, in a detail page's .subj-main, at the
     top of Produk's and Promo's own wrappers, or carries .bar-h. */
  body.app:not(.onb) .page-head h1, body.app:not(.onb) main .subj-main h1, body.app main :is(.kq-wrap, .pr-wrap) > h1:first-child, body.app h1.bar-h {
    position: fixed; z-index: 11; top: 26px; left: 54px; right: 104px; transform: translateY(-50%);
    margin: 0; padding: 0; font-size: var(--fs-title); line-height: 1.2; letter-spacing: -0.02em; font-weight: 700; color: var(--navy-950);
    display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere;
    pointer-events: none; }
  body.app .page-head { gap: 8px; margin-bottom: 0; }
  body.app .page-head:has(.acts, > .btn, > a, > form, > details, .sub-hp) { margin-bottom: 10px; }
  body.app .page-head .sub:not(.sub-hp), body.app main .subj-main > .sub:not(.sub-hp) { display: none; }

  /* The way back: the crumb's last link as a 44px chevron at the bar's left. */
  body.app main .crumb.crumb { position: fixed; z-index: 12; top: 4px; left: 6px; display: block; width: 44px; height: 44px; margin: 0; padding: 0; overflow: hidden; font-size: 0; }
  body.app main .crumb.crumb > * { display: none; }
  body.app main .crumb.crumb > a:last-of-type { display: flex; align-items: center; justify-content: center; width: 44px; height: 44px; min-height: 44px; padding: 0; border-radius: 10px; color: var(--navy-950); }
  body.app main .crumb.crumb > a:last-of-type::before { content: ""; width: 12px; height: 12px; border: solid currentColor; border-width: 0 0 2.5px 2.5px; transform: translateX(3px) rotate(45deg); }
  body.app main .crumb.crumb > a:last-of-type:focus-visible { outline: 2px solid var(--blue-600); outline-offset: -2px; }
  body.app:has(main .crumb) .app-bar .nav-btn { visibility: hidden; }
  /* The same chevron for a sub page that has no .crumb line of its own: its parent comes from
     back_target.go. A page with a crumb keeps that one (it honours ?kembali=). */
  body.app .app-bar .bar-back { position: fixed; z-index: 12; top: 4px; left: 6px; display: flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: 10px; color: var(--navy-950); }
  body.app .app-bar .bar-back::before { content: ""; width: 12px; height: 12px; border: solid currentColor; border-width: 0 0 2.5px 2.5px; transform: translateX(3px) rotate(45deg); }
  body.app .app-bar .bar-back:focus-visible { outline: 2px solid var(--blue-600); outline-offset: -2px; }
  body.app:has(main .crumb) .app-bar .bar-back { display: none; }
  body.app:has(.app-bar .bar-back) .app-bar .nav-btn { visibility: hidden; }

  /* Banners under the bar: the bar is the page's first row. */
  body.app:has(> .rail > :is(.sync-ticker, .izin-ticker, .hapus-banner, .verif-banner)) { display: flex; flex-direction: column; }
  body.app:has(> .rail > :is(.sync-ticker, .izin-ticker, .hapus-banner, .verif-banner)) > * { order: 2; }
  body.app:has(> .rail > :is(.sync-ticker, .izin-ticker, .hapus-banner, .verif-banner)) > :is(.app-bar, .skip) { order: 0; }
  body.app > .rail > :is(.sync-ticker, .izin-ticker, .hapus-banner, .verif-banner) { order: 1; }

  /* Laporkan is the bar's flag (.bar-flag) on every page: the floating
     button gives way. Nothing is fixed to the bottom any more, so a page
     ends a little under its last line, clear of the safe area. */
  body.app .fb-zone .fb { display: none; }
  body.app .page, body.app:has(.fb):not(.qbar-on) .page { padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px)); }

  /* No box wider than the screen: iOS Safari sizes a date box by its own
     content and ignores width: 100% in a grid cell unless the field may shrink
     (the Pesanan, Retur and Laporan filters carry two of them side by side). */
  body.app input, body.app select, body.app textarea { max-width: 100%; }
  body.app .fld, body.app .filters > * { min-width: 0; }
  body.app input[type="date"] { -webkit-appearance: none; appearance: none; min-width: 0; min-height: 44px; }

  /* A page's own buttons under the bar: one short row, at their own size. */
  body.app .page-head .acts .btn, body.app .subj-acts .btn { min-height: 44px; padding: 8px 14px; font-size: var(--fs-body); box-shadow: none; }

  /* Less air everywhere: a detail page's head, cards, section heads, forms. */
  body.app main .subj { gap: 8px; margin-bottom: 10px; }
  body.app .card:not(.card-flush) { padding: 12px 14px; }
  body.app .sec-head { margin-bottom: 6px; }
  body.app .sec-head h2 { font-size: var(--fs-head); }
  body.app .acct-h { margin: 12px 0 6px; }
  body.app .acct-form { gap: 10px; padding: 12px 14px; }
  body.app .acct-form label { margin-top: 0; }


  /* Toko's shop blocks: one tight line per fact. */
  body.app .dt-toko tr { row-gap: 2px; padding: 10px 12px; line-height: 1.4; }
  body.app .dt-toko td.st .state { padding-block: 2px; font-size: var(--fs-caption); }
  body.app .dt-toko td.chk a.s2 { display: inline; margin-left: 6px; }

  /* Status tabs on every page (Pesanan, Retur, ...): one line that scrolls
     sideways, never a block of wrapped rows. */
  body.app .tabs { flex-wrap: nowrap; overflow-x: auto; gap: 4px; margin-inline: -22px; padding-inline: 22px; border-bottom: 0;
    scrollbar-width: none; scroll-padding-inline: 22px; }
  body.app .tabs::-webkit-scrollbar { display: none; }
  body.app .tabs .tab { flex: none; min-height: 44px; padding: 6px 12px; border-radius: 10px; border-bottom: 0; margin-bottom: 0; font-size: var(--fs-body); white-space: nowrap; }
  body.app .tabs .tab.current, body.app .tabs .tab[aria-current] { background: #e8f1ff; }

  /* Pull to refresh (tarik.js, home-screen app only): a circular arrow under
     the 52px bar that comes down and turns with the pull, blue once letting go
     reloads. The browser's own bounce stops only while ours runs. */
  html.tarik-on, html.tarik-on body { overscroll-behavior-y: none; }
  .tarik { position: fixed; top: 52px; left: 50%; z-index: 60; display: grid; place-items: center; width: 40px; height: 40px;
    margin-top: 6px; border-radius: 50%; background: #fff; color: var(--slate-600); box-shadow: 0 2px 10px rgba(11, 22, 40, .18);
    opacity: 0; transform: translate(-50%, 0); pointer-events: none; }
  .tarik svg { width: 22px; height: 22px; }
  .tarik.is-siap, .tarik.is-muat { color: var(--blue-600); }
  .tarik.is-muat svg { animation: tarik-putar .8s linear infinite; }
}
@keyframes tarik-putar { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .tarik.is-muat svg { animation: none; } }
@media screen and (min-width: 760px) { .tarik { display: none; } }

/* ---------- Hari ini on a phone (Steph 2026-10-15) ----------
   Under the bar: ONE red line for what is urgent (.hu, hari-ini.html; two or
   more open in place), then the four figures as small tiles, then the orders
   waiting, one row each like Pesanan. "Perlu Anda bereskan" with its yellow
   items is the desktop's; the notification offer waits under the lists. */
.hu { display: none; }
@media screen and (max-width: 759px) {
  /* The mockup's 16px side gutter (the list cards keep their own border). */
  body.app .hi.app-wrap { padding-inline: 16px; }
  .hu { display: block; margin: 0 0 12px; }
  .hu-line { position: relative; display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 34px 0 12px; border-radius: 12px;
    background: var(--crit-soft); color: var(--ink); text-decoration: none; font-size: var(--fs-body); font-weight: 700; line-height: 1.3; cursor: pointer; list-style: none; }
  .hu-line::-webkit-details-marker { display: none; }
  .hu-line::before { content: "!"; flex: none; display: grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; background: var(--crit); color: #fff; font-size: var(--fs-caption); font-weight: 700; }
  .hu-line::after { content: "›"; position: absolute; right: 14px; top: 50%; transform: translateY(-55%); font-size: var(--fs-hero); line-height: 1; color: var(--crit); }
  .hu-more[open] > .hu-line::after { transform: translateY(-50%) rotate(90deg); }
  .hu-line:focus-visible { outline: var(--focus); outline-offset: 2px; }
  .hu-t { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  .hu-n { flex: none; padding: 0 8px; border-radius: 999px; background: var(--paper); color: var(--crit); font-size: var(--fs-caption); font-weight: 700; }
  .hu-list { list-style: none; margin: 4px 0 0; padding: 0; border: 1px solid var(--slate-200); border-radius: 12px; background: var(--paper); overflow: hidden; }
  .hu-list li + li { border-top: 1px solid var(--slate-200); }
  .hu-list a { display: flex; align-items: center; min-height: 44px; padding: 6px 12px; color: var(--navy-950); font-size: var(--fs-body); font-weight: 700; line-height: 1.35; text-decoration: none; }
  .hi .beres { display: none; }

  /* Sections: a small head, less air between them. */
  .hi .work, .hi .work-main, .hi .work-side { gap: 16px; }
  .hi .sec-head { margin: 0 0 8px; }
  .hi .qlist, .hi .card-flush { border-radius: 12px; }
  .hi .card-foot { padding: 8px 12px; font-size: var(--fs-caption); }

  /* Stock to watch: one row each. Picture, the name on one line, the code
     and the stock on the next; the chip at the right; the whole row the link. */
  .hi .orders-lean .order { position: relative; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto auto; column-gap: 10px; row-gap: 0;
    align-items: center; padding: 6px 12px; font-size: var(--fs-body); }
  .hi .orders-lean .order > .o-main { grid-column: 1; grid-row: 1 / span 2; min-height: 44px; }
  .hi .orders-lean .o-link::after { content: ""; position: absolute; inset: 0; }
  .hi .orders-lean .o-link:focus-visible { outline: none; }
  .hi .orders-lean .o-link:focus-visible::after { outline: var(--focus); outline-offset: -3px; }
  .hi .orders-lean .thumb { width: 36px; height: 36px; }
  .hi .orders-lean .pic-t b, .hi .orders-lean .pic-t .meta { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  .hi .orders-lean .pic-t .meta { margin-top: 0; font-size: var(--fs-caption); }
  /* Stok perlu perhatian: the chip is wide, so it sits under the name instead of
     beside it (beside it the name was cut at "Tumbler Stainless 500…", QA phone sweep 2026-10-16). */
  .hi .orders-lean .order > .o-main { grid-row: 1; }
  .hi .orders-lean .order > .o-due { grid-column: 1; grid-row: 2; justify-self: start; margin: 0 0 6px 46px; min-width: 0; padding: 0 8px; font-size: var(--fs-caption); line-height: 22px; }
  .hi .card-flush:has(> .orders-lean) { padding: 0; overflow: hidden; }

  .hi .hl { padding: 0 12px 4px; }
  .hi .hl li { padding: 8px 0; }
  .hi .skuh { padding: 10px 12px 2px; }
  .hi .skul { padding: 0 12px 4px; }
  .hi .skul li { padding: 6px 0; }

  /* The notification offer, under the lists: one short row. */
  .hi .notif-card { position: relative; gap: 6px 10px; margin: 0; padding: 10px 12px; }
  .hi .notif-card-icon { display: none; }
  .hi .notif-card-title { font-size: var(--fs-body); }
  .hi .notif-card-acts { flex-wrap: nowrap; }
  .hi .notif-card-acts .btn-sm { padding: 6px 12px; font-size: var(--fs-body); }
}

/* The notification offer as a strip under "Perlu Anda bereskan" (desktop,
   hari-ini-desktop mockup): the bell, the title, Nyalakan and a quiet ×
   for Nanti saja (its words kept for screen readers). */
@media (min-width: 760px) {
  .hi .work-side .notif-card { flex-wrap: nowrap; gap: 8px; margin: 0; padding: 8px 8px 8px 12px; border-radius: 12px; }
  .hi .work-side .notif-card-icon { width: 20px; height: 24px; align-self: center; border: 0; background: none; }
  .hi .work-side .notif-card-icon svg { width: 20px; height: 20px; }
  .hi .work-side .notif-card-title { font-size: var(--fs-body); }
  .hi .work-side .notif-card-acts { flex: none; flex-wrap: nowrap; gap: 4px; }
  .hi .work-side .notif-card-acts .btn-sm { min-height: 36px; padding: 0 12px; font-size: var(--fs-body); }
  .hi .work-side .notif-card [data-notif-later] { position: relative; width: 36px; padding: 0; border: 0; background: none; color: transparent; overflow: hidden; white-space: nowrap; }
  .hi .work-side .notif-card [data-notif-later]::after { content: ""; position: absolute; inset: 0; margin: auto; width: 16px; height: 16px; background: var(--slate-600);
    -webkit-mask: var(--x-icon) center / contain no-repeat; mask: var(--x-icon) center / contain no-repeat; }
  .hi .work-side .notif-card [data-notif-later]:hover { background: var(--slate-100); }
}
.hi { --x-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6 6 18'/%3E%3C/svg%3E"); }

/* Hari ini with no orders yet: the one line a first-use page keeps (less text, 2026-10-15). */
.hi-empty { margin: 0; font-size: var(--fs-body); color: var(--slate-600); }

/* Phone tap targets on Hari ini (QA phone sweep 2026-10-16). Links that were
   18-32px high get a 44px hit area without moving anything: the section
   links by a pseudo-element past their box, the money rows and SKU rows by a
   cover over their whole row (as the order rows do). */
@media screen and (max-width: 759px) {
  .sec-head .more, .page-head .sub a { position: relative; }
  .sec-head .more::after, .page-head .sub a::after { content: ""; position: absolute; inset: -8px -6px; }
  .hi .card-foot a { position: relative; }
  .hi .card-foot a::after { content: ""; position: absolute; inset: -9px -6px; }
  .hi .qmore a { min-height: 44px; display: flex; align-items: center; }
}
/* One line per shop a running promotion locks (harga_kunci.go): the mark and
   shop name lead a line of plain text ("[mark] Botolku Official · terkunci
   promo sampai 23 Okt, 18.00"), no pill, so a narrow price cell wraps it as
   one sentence. */
.hk { display: grid; gap: 3px; margin-top: 6px; text-align: left; }
.hk-l { display: block; font-size: var(--fs-caption); line-height: 1.4; color: var(--slate-600); overflow-wrap: anywhere; }
.hk-l .mk { display: inline; background: none; border: 0; border-radius: 0; padding: 0; color: var(--navy-950); }
.hk-l .mk::before { display: inline-block; vertical-align: -2px; margin-right: 4px; }
.hk-l .mk::after { content: " ·"; } /* the dot stays with the shop name when the line wraps */
.hk-l.kept .hk-w { color: var(--warn-deep); font-weight: 600; }

/* Picking di HP on a phone: the page is already where it would move the
   list. Here, not in picking-hp.css: Picking also opens as a dialog on
   Pesanan, which does not load that file. */
@media screen and (max-width: 759px) { .php-start, .php-open { display: none; } }

/* ---------- Hari ini: Perlu restok (rekomendasi restock mockup, 2026-10-19) ----------
   hari-ini.html hi-pesan. Desktop: the card's rows (picture, name, code and when it
   runs out; the order at the right). A phone: one line, the whole line the link. */
.hp-line { display: none; }
.hp .hp-q { font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
.hp .orders-lean .order { grid-template-columns: minmax(0, 1fr) auto; }
.hp-due.crit { color: var(--crit); font-weight: 700; }
.hp-due.warn { color: var(--warn-deep); font-weight: 700; }
.hp-risk { font-weight: 700; }
/* Like Hari ini's other row links: dark, underlined on hover, the line's whole height. */
.hp-risk a { display: inline-flex; align-items: center; min-height: 32px; color: var(--navy-950); text-decoration: none; }
.hp-risk a:hover { text-decoration: underline; }
.hp-risk a:focus-visible { outline: var(--focus); outline-offset: 2px; border-radius: 4px; }
.hp-ask { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 10px; padding: 10px 14px; border: 1px solid #bcd3ff; border-radius: 12px;
  background: #f5f9ff; color: var(--navy-950); font-size: var(--fs-body); font-weight: 700; }
.hp-ask .btn-xs { min-height: 40px; }
.hp-in { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; color: var(--slate-600); }
.hp-in input { width: 64px; min-height: 40px; padding: 0 10px; border: 1px solid var(--slate-300); border-radius: 8px; font: inherit; font-weight: 700;
  color: var(--navy-950); text-align: right; }
@media screen and (max-width: 759px) {
  .hp > .sec-head, .hp > .hp-card { display: none; }
  /* One ticker on a phone: Belum dikirim beats Perlu restok, its first-time ask too; it returns when nothing is late. */
  .hi:has(#hi-kirim) #hi-pesan { display: none; }
  .hp-line { position: relative; display: grid; gap: 2px; align-content: center; min-height: 56px; padding: 8px 34px 8px 14px;
    border: 1px solid var(--slate-200); border-radius: 12px; background: var(--paper); color: var(--ink); text-decoration: none;
    font-size: var(--fs-body); font-weight: 700; line-height: 1.3; }
  .hp-r.warn { color: var(--warn-deep); }
  .hp-line.crit { border-color: #f6c7d5; }
  .hp-line::after { content: "›"; position: absolute; right: 14px; top: 50%; transform: translateY(-55%); font-size: var(--fs-hero); line-height: 1; color: var(--slate-500); }
  .hp-line:focus-visible { outline: var(--focus); outline-offset: 2px; }
  .hp-t { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  .hk .hp-r { display: none; } /* phone: the tile says the cause; one rule, delete it to bring the ticker's second line back */
  .hp-r { color: var(--crit); font-size: var(--fs-caption); font-weight: 700; font-variant-numeric: tabular-nums; }
  .hp-ask { margin-top: 8px; padding: 10px 12px; }
  .hp-ask label { flex: 1 1 100%; }
  .hp-in input, .hp-ask .btn-xs { min-height: 44px; font-size: var(--fs-head); }
}

/* "Barang impor?" (barang-impor.html): the Produk strip, the Toko field. */
.impor-strip { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; padding-left: 38px; }
.impor-strip p { flex: 1 1 320px; margin: 0; }
.impor-acts { display: flex; flex-wrap: wrap; gap: 8px; }
.impor-acts .btn { min-height: 44px; margin: 0; }
.impor-more { margin: -8px 0 16px; font-size: var(--fs-caption); color: var(--slate-500); }
.impor-c, .toko-sub { flex: 1 1 100%; min-width: 0; margin-top: 6px; font-size: var(--fs-caption); font-weight: 400; color: var(--slate-500); }
/* On a phone the name cell is a flex row: the line goes under the name and chip. */
.dt-toko tbody th:has(.impor-c), .dt-toko tbody th:has(.toko-sub) { flex-wrap: wrap; align-content: flex-start; }
/* Its Ubah keeps a 44px touch area without making the line 44px tall: a
   TikTok card read looser than a Shopee one (UI check 2026-10-22 #36). */
.impor-c .impor-edit > summary { margin-block: -10px; }
.impor-done, .impor-ask { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 10px; }
.impor-lbl b { color: var(--slate-700); font-weight: 600; }
.impor-ok { color: var(--ok-deep, var(--slate-600)); font-weight: 600; }
.impor-hint { flex: 1 1 100%; color: var(--warn-deep); font-weight: 600; }
.impor-edit { flex: 0 1 auto; }
.impor-edit[open] { flex: 1 1 100%; }
.impor-edit summary { display: inline-flex; align-items: center; min-height: 44px; padding: 0 4px; color: var(--blue-600); cursor: pointer; font-weight: 600; }
.impor-edit summary:focus-visible { outline: 2px solid var(--blue-600); outline-offset: 2px; }
/* Ya | Tidak: two submit buttons, a tap saves. */
.impor-seg { display: inline-flex; margin: 0; }
.impor-seg button { min-width: 64px; min-height: 44px; padding: 0 14px; border: 1px solid var(--slate-300); background: #fff; color: var(--slate-700);
  font: inherit; font-size: var(--fs-body); font-weight: 700; cursor: pointer; }
.impor-seg button:first-of-type { border-radius: 10px 0 0 10px; }
.impor-seg button:last-of-type { border-radius: 0 10px 10px 0; border-left-width: 0; }
.impor-seg button[aria-pressed="true"] { background: var(--blue-600); border-color: var(--blue-600); color: #fff; }
.impor-seg button:focus-visible { outline: var(--focus); outline-offset: 1px; position: relative; }
/* ---------- Mulai di sini (mulai_di_sini.go, templates/mulai-di-sini.html; mockup) ----------
   The checklist: a head (title, "2 dari 6", a thin bar, Tutup), the steps as
   chips, and ONE strip with the step to do now and its button. Phone: the
   chips wait behind "Semua langkah"; from 760px they are one row. */
.mulai { margin: 0 0 16px; padding: 14px 16px; border-radius: var(--radius); border: 1px solid #b9cdf7; background: #f3f7ff; display: grid; gap: 12px; }
.mulai-head { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; align-items: center; gap: 4px 10px; }
.mulai-head h2 { margin: 0; font-size: var(--fs-head); letter-spacing: -0.01em; }
.mulai-n { font-size: var(--fs-caption); font-weight: 700; color: var(--slate-600); white-space: nowrap; }
.mulai-bar { -webkit-appearance: none; appearance: none; width: 100%; min-width: 40px; height: 6px; border: 0; border-radius: 99px; background: #dbe6fb; overflow: hidden; }
.mulai-bar::-webkit-progress-bar { background: #dbe6fb; border-radius: 99px; }
.mulai-bar::-webkit-progress-value { background: var(--ok); border-radius: 99px; }
.mulai-bar::-moz-progress-bar { background: var(--ok); border-radius: 99px; }
.mulai-x { margin: 0; }
.mulai-x .btn-sm { min-height: 44px; margin: -8px -8px -8px 0; }
.mulai-steps { list-style: none; margin: 0; padding: 0; display: none; gap: 2px; }
.ms { display: grid; grid-template-columns: 24px minmax(0, 1fr); align-items: center; gap: 10px; min-height: 36px; font-size: var(--fs-body); color: var(--slate-700); }
.ms-i { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; font-size: var(--fs-caption); font-weight: 700; color: var(--slate-600); background: var(--paper); border: 1px solid var(--slate-300); }
.ms-i svg { width: 14px; height: 14px; }
.ms.done { color: var(--slate-500); }
.ms.done .ms-i { background: var(--ok); border-color: var(--ok); color: #fff; }
.ms.now { color: var(--navy-950); font-weight: 700; }
.ms.now .ms-i { background: var(--blue-600); border-color: var(--blue-600); color: #fff; }
.mulai-now { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; padding: 12px 14px; border-radius: 12px; background: var(--paper); border: 1px solid #d5e2fb; }
.mulai-now p { margin: 0; flex: 1 1 200px; min-width: 0; display: grid; gap: 2px; font-size: var(--fs-body); }
.mulai-now p span { color: var(--slate-600); font-size: var(--fs-caption); }
.mulai-now .btn-sm { min-height: 44px; }
.ms-b { display: none; }
/* While the first-sync card shows, it is the sync line: say the time once. */
body.app:has(.awal) .sync-ticker { display: none; }
body.app:has(.awal):has(.rail > .sync-ticker) { padding-top: 0; }
body.app:has(.awal):has(.rail > .sync-ticker) .app-bar { top: 0; }
.mulai-all { margin: -4px 0 0; }
.mulai-all summary { cursor: pointer; display: inline-flex; align-items: center; min-height: 44px; font-size: var(--fs-body); font-weight: 700; color: var(--blue-700); list-style: none; }
.mulai-all summary::-webkit-details-marker { display: none; }
.mulai-all[open] summary { font-size: 0; min-height: 0; }
.mulai:has(.mulai-all[open]) .mulai-steps, .mulai-full .mulai-steps, .mulai-open .mulai-steps { display: grid; }
.mulai-full .mulai-all, .mulai-open .mulai-all { display: none; }
/* Where the list shows, the strip does not repeat the step's name. */
.mulai:has(.mulai-all[open]) .mulai-now b, .mulai-full .mulai-now b, .mulai-open .mulai-now b { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
@media (max-width: 759px) {
  .mulai-now .btn-sm { flex: 1 1 100%; }
  .mulai-head h2 { font-size: var(--fs-head); }
}
@media (min-width: 760px) {
  .mulai { padding: 16px 18px; }
  .mulai-head { grid-template-columns: auto auto minmax(80px, 240px) 1fr auto; }
  .mulai-head .mulai-x { grid-column: 5; justify-self: end; }
  .mulai-steps { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 8px; }
  .ms { grid-template-columns: 24px minmax(0, 1fr); align-items: center; padding: 10px 12px; border-radius: 10px; background: rgba(255,255,255,.6); font-size: var(--fs-body); line-height: 1.35; min-height: 52px; }
  .ms.now { padding: 6px 8px 6px 12px; }
  .ms.now .ms-t { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .ms-b { display: inline-flex; min-height: 40px; justify-content: center; text-align: center; line-height: 1.2; white-space: normal; }
  .mulai-full .ms-b { display: none; }
  .mulai-now { display: none; }
  .mulai-full .mulai-now { display: flex; }
  .ms.now { background: var(--paper); box-shadow: inset 0 0 0 2px var(--blue-600); }
  .mulai-all { display: none; }
  .mulai-now { justify-content: flex-end; padding: 10px 12px 10px 16px; }
  .mulai-now p span { font-size: var(--fs-body); color: var(--slate-700); }
  .mulai-full .mulai-steps { grid-auto-flow: row; grid-auto-columns: auto; }
}
/* The sidebar's way back after Tutup: under the business name. */
.mulai-rail { display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 14px; font-size: var(--fs-body); font-weight: 600; color: #cfe0ff; text-decoration: none; }
.mulai-rail:hover { color: #fff; }
.mulai-rail b { margin-left: auto; font-size: var(--fs-caption); color: #9fb3d1; }
/* In the phone's menu sheet (light): the same line, its own colours. */
.nav-sheet .mulai-rail { margin: 4px 14px 14px; padding: 0 14px; border-radius: 12px; background: #f3f7ff; border: 1px solid #b9cdf7; color: var(--blue-700); }
.nav-sheet .mulai-rail:hover { color: var(--blue-800); }
.nav-sheet .mulai-rail b { color: var(--slate-600); }

/* One page's one-time tip: one line, an X that says "Jangan tampilkan lagi". */
.tip { display: flex; align-items: center; gap: 10px; margin: 0 0 14px; padding: 4px 4px 4px 12px; min-height: 44px; border-radius: 12px; background: var(--slate-100); color: var(--slate-700); }
.tip-i { flex: none; width: 18px; height: 18px; color: var(--blue-700); }
.tip p { margin: 0; flex: 1 1 0; min-width: 0; font-size: var(--fs-body); line-height: 1.35; }
.tip form { margin: 0; }
.tip-x { display: inline-flex; align-items: center; gap: 6px; min-width: 44px; min-height: 44px; justify-content: center; padding: 0 10px; border: 0; border-radius: 10px; background: none; color: var(--slate-600); font: inherit; font-size: var(--fs-caption); font-weight: 600; cursor: pointer; }
.tip-x:hover { background: var(--slate-200); color: var(--navy-950); }
.tip-x svg { width: 16px; height: 16px; }
@media (max-width: 759px) { .tip-xt { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); } .tip-x { padding: 0; } }

/* Hari ini while a first sync runs: what is coming in, and the page each fills. */
.awal { padding: 16px 18px; margin: 0 0 16px; display: grid; gap: 10px; }
.awal-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; }
.awal-head h2 { margin: 0; font-size: var(--fs-head); }
.awal-eta { font-size: var(--fs-body); font-weight: 700; color: var(--blue-700); }
.awal .snk-prog { margin: 0; gap: 0; }
.awal .snk-prog li { min-height: 44px; }
.awal .p-s a { display: inline-flex; align-items: center; min-height: 44px; font-weight: 700; white-space: nowrap; }
/* The checklist's foot: "Semua langkah" (phone) and the quiet way out of all guidance. */
.mulai-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0 12px; margin-top: -4px; }
.mulai-foot .mulai-all { margin: 0; }
.mulai-skip { margin: 0 0 0 auto; }
.mulai-skip button { min-height: 44px; padding: 0 2px; border: 0; background: none; font: inherit; font-size: var(--fs-caption); font-weight: 600; color: var(--slate-600); cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
.mulai-skip button:hover { color: var(--navy-950); }
@media (min-width: 760px) { .mulai-foot { margin-top: -8px; } }
.panduan-undo { margin-bottom: 16px; }
.panduan-akun > .kt-row { grid-column: 1 / -1; }

/* A saved-in-place message that sits above what is on screen (inplace.js):
   one line at the bottom, gone after a few seconds. */
.ip-toast { position: fixed; left: 50%; bottom: calc(16px + env(safe-area-inset-bottom)); transform: translateX(-50%); z-index: 60;
  max-width: min(92vw, 520px); padding: 10px 16px; border-radius: 10px; background: var(--ink); color: #fff;
  font-size: var(--fs-body); font-weight: 700; line-height: 1.3; box-shadow: 0 6px 24px rgba(11, 22, 40, .25); }
.ip-toast.bad { background: var(--crit); }
@media (prefers-reduced-motion: no-preference) { .ip-toast { animation: ip-in .18s ease-out; } }
@keyframes ip-in { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }


/* Search box: the one search field (templates/cari-box.html), moved here from catalog.css so any page can use it. */
.cari-bar { position: relative; display: flex; align-items: flex-start; gap: 8px; }
.fld-cari { position: relative; flex: 1 1 auto; max-width: 520px; }
.fld-cari { display: grid; min-width: 0; }
.fld-cari input { box-sizing: border-box; width: 100%; min-height: 44px; margin: 0; padding: 10px 46px 10px 12px; font: inherit; font-size: var(--fs-head); /* under 16px, iOS zooms on focus */
  color: var(--navy-950); background: #fff; border: 1px solid var(--slate-300); border-radius: 10px; text-overflow: ellipsis; }
.fld-cari input:hover { border-color: var(--slate-400); }
.fld-cari input::placeholder { font-size: var(--fs-body); }
.cari-go { position: absolute; top: 0; right: 0; display: grid; place-items: center; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 10px;
  background: none; color: var(--slate-600); cursor: pointer; }
.cari-go svg { width: 20px; height: 20px; }
.cari-go:hover { color: var(--blue-700); }
.cari-go:focus-visible { outline: var(--focus); outline-offset: -2px; }

/* Live search: the list dims a moment while the answer comes (autofilter.js). */
main[aria-busy="true"] table { opacity: .6; transition: opacity .15s .15s; }

/* ---------- Hari ini polish (2026-10-28, docs/mockups/hari-ini-polish/CHANGES.md): strips above the figures, 4px spacing, compact Terjual / Perlu restok ---------- */
/* .mulai is also drawn on the Mulai page, so it stays unscoped; the rest is Hari ini only. */
/* 1. Belum dikirim: the list is the only frame (as Harus dikirim segera) */
.hi .hp-card.card-flush:has(> .qlist) { padding: 0; border: 0; background: transparent; box-shadow: none; border-radius: 0; }
/* 2a. Mulai di sini: one strip, title, bar, current step, links, Tutup */
.mulai { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; padding: 6px 12px; margin: 0 0 12px; }
.mulai-head { display: contents; }
.mulai-head h2 { order: 1; }
.mulai-n { order: 2; }
.mulai-bar { order: 3; flex: 0 0 96px; width: 96px; }
.mulai-steps { display: none !important; }
.mulai-now { order: 4; flex: 1 1 auto; padding: 0; border: 0; background: none; gap: 8px 12px; }
.mulai-now p { margin: 0; flex: 1 1 auto; }
.mulai-now .btn { flex: none; white-space: nowrap; }
.mulai-foot { order: 5; display: flex; gap: 12px; align-items: center; }
.mulai-x { order: 6; margin-left: auto; }
.mulai-x .btn-sm { min-height: 32px; margin: 0; position: relative; }
.mulai-x .btn-sm::after, .mulai-now .btn-sm::after { content: ""; position: absolute; inset: -6px -4px; }
.mulai-now .btn-sm { position: relative; min-height: 32px; }
.mulai-skip button { min-height: 32px; }
.kabar-banner .btn-sm, .mulai .btn-sm { font-size: var(--fs-body); }
@media (min-width: 760px) { .mulai-now { display: flex !important; } }
@media (max-width: 759px) { .mulai-bar { flex: 1 1 40px; width: auto; } .mulai-x { order: 3; margin-left: 0; } .mulai-now { order: 4; flex: 1 1 100%; } .mulai-foot { order: 5; } }
/* 2b. Notifikasi pesanan baru on a phone: the desktop side-column row (already one line with the x), same rules */
@media (max-width: 759px) {
  .hi .notif-card { flex-wrap: nowrap; gap: 8px; padding: 4px 4px 4px 12px; border-radius: 12px; }
  .hi .notif-card-text { flex: 1 1 auto; }
  .hi .notif-card-acts { flex: none; flex-wrap: nowrap; gap: 4px; }
  .hi .notif-card-acts .btn-sm { flex: none; min-height: 36px; padding: 0 12px; position: relative; white-space: nowrap; }
  /* the dismiss x: the button itself is the 44px target (its ::after draws the icon) */
  .hi .notif-card [data-notif-later] { position: relative; width: 44px; min-height: 44px; margin: -4px -4px -4px 0; padding: 0; border: 0; background: none; color: transparent; overflow: hidden; }
  .hi .notif-card [data-notif-later]::after { content: ""; position: absolute; inset: 0; margin: auto; width: 16px; height: 16px; background: var(--slate-600); -webkit-mask: var(--x-icon) center / contain no-repeat; mask: var(--x-icon) center / contain no-repeat; }
}
/* 2c. kabar banner: one row (chip, title, line, link, Tutup) */
.hi .kabar-banner { align-items: center; flex-wrap: nowrap; gap: 8px 12px; margin: 0 0 12px; padding: 6px 8px 6px 12px; border-radius: var(--radius); }
.hi .kabar-banner-text { flex: 1 1 auto; display: flex; flex-wrap: wrap; align-items: center; gap: 2px 8px; }
.hi .kabar-banner-text .kabar-meta { order: 1; margin: 0; }
.hi .kabar-banner-text .kabar-banner-title { order: 2; margin: 0 !important; font-size: var(--fs-body); }
.hi .kabar-banner-text .kabar-banner-line { order: 3; margin: 0 !important; }
.hi .kabar-banner a { order: 4; margin: 0; padding-block: 0; }
.hi .kabar-banner form { flex: none; }
.hi .kabar-banner .btn-sm { min-height: 32px; position: relative; white-space: nowrap; }
.hi .kabar-banner .btn-sm::after { content: ""; position: absolute; inset: -6px -4px; }
@media (max-width: 759px) {
  .hi .kabar-banner { align-items: flex-start; padding: 8px 8px 8px 12px; }
  .hi .kabar-banner-line { display: none; }
  .hi .kabar-banner-text .kabar-banner-title { flex: 1 1 100%; order: 3; }
  .hi .kabar-banner a { order: 2; }
}
/* 2d. HPP card: one row, the count is the title (heading stays for screen readers) */
.hi .hpp-card { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; margin: 0 0 12px; padding: 6px 8px 6px 12px; }
.hi .hpp-card h2 { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); margin: 0; }
.hi .hpp-card p { margin: 0; font-size: var(--fs-body); font-weight: 700; color: var(--ink, inherit); max-width: none; }
.hi .hpp-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.hi .hpp-acts form { margin: 0; }
.hi .hpp-acts .btn { min-height: 32px; padding: 0 12px; font-size: var(--fs-body); box-shadow: none; position: relative; }
.hi .hpp-acts .btn::after { content: ""; position: absolute; inset: -6px -4px; }
@media (max-width: 759px) {
  .hi .hpp-card { flex-direction: column; align-items: stretch; padding: 8px 12px; }
  /* wraps at 320px; 12px between rows keeps the 44px hit areas apart */
  .hi .hpp-acts { width: 100%; gap: 12px 8px; }
  .hi .hpp-acts .btn { flex: 1 1 auto; justify-content: center; padding: 0 6px; white-space: nowrap; }
  .hi .hpp-acts form { flex: 1 1 auto; display: flex; }
  .hi .hpp-acts form .btn { flex: 1; }
}
/* 4. spacing: head and sections 12 / 16 on the 4px scale */
.hi .page-head { margin-bottom: 12px; }
.hi .today { margin-bottom: 12px; }
@media (min-width: 1200px) { .hi .work { gap: 16px; } }
/* 5. Terjual: same type as a tile, one short row */
.hi .tsum { padding: 6px 12px; column-gap: 10px; }
.hi .tsum-pics .pic { width: 28px; height: 28px; }
/* 6. Perlu restok rows: name (two lines at most) on its own line, meta and Pesan N pcs on the next */
.hi .orders-lean .order { grid-template-columns: minmax(0, 1fr) auto; padding: 6px 10px; column-gap: 8px; }
.hi .orders-lean .thumb { width: 32px; height: 32px; }
.hi .orders-lean .pic-row { gap: 8px; }
.hi .orders-lean .pic-t { min-width: 0; padding-right: 0; }
.hi .orders-lean .pic-t b { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.hi .orders-lean .pic-t .meta { white-space: normal; }
.hi .orders-lean .hp-q { font-size: var(--fs-body); font-weight: 700; white-space: normal; width: 56px; line-height: 1.25; text-align: right; }
/* 6b. Belum dikirim: the button beside the row's second line, not a third line */
.hi .rs-li > .rs-f { margin: 0 12px 6px 62px; }
/* 7. no card around the one "Belum ada pesanan" line */
.hi .card:has(> .hi-empty) { border: 0; background: none; padding: 0; box-shadow: none; }

/* ACTION vs WAITING (Steph 2026-10-29), the one rule for Pesanan, Retur and
   what links to them. ACTION: a row the seller must act on has a filled chip
   (amber, red under 24 h or past); only rows under deadline pressure are also tinted
   with a 3px left bar (red, .aksi-crit; never amber) (Steph 2026-10-29: a tint on every open row was noise). WAITING (for the buyer, the courier, the
   marketplace): no tint, grey text, no pill. A page only sets the classes. */
.aksi { --a: var(--warn); --a-soft: var(--warn-soft); }
.aksi.aksi-crit { --a: var(--crit); --a-soft: var(--crit-soft); }
tr.aksi-crit > * { background: var(--a-soft); }
tr.aksi-crit > :first-child { box-shadow: inset 3px 0 0 var(--a); }
li.aksi-crit { background: var(--a-soft); box-shadow: inset 3px 0 0 var(--a); border-radius: 0; }
.st-act, .pill.st-act, .st.st-act, .state.st-act { background: var(--warn); color: #fff; }
.aksi-crit .st-act, .aksi-crit .pill.st-act, .aksi-crit .st.st-act, .aksi-crit .state.st-act { background: var(--crit); }
.wait-st, .pill.wait-st, .st.wait-st, .state.wait-st { background: none; color: var(--slate-600); font-weight: 600; padding: 0; border-radius: 0; }
.od-head.aksi-crit { padding: 10px 14px; background: var(--a-soft); box-shadow: inset 3px 0 0 var(--a); border-radius: 8px; }
.card.aksi-crit { background: var(--a-soft); }
.state.wait-st i { display: none; }
.aksi .todo-b { background: var(--warn); color: #fff; border-color: transparent; }
.aksi-crit .q-due, .aksi-crit .q-due.warn, .aksi-crit .q-due.crit, .aksi-crit .due-hp, .aksi-crit .due-hp.warn, .aksi-crit .due-hp.crit, .aksi-crit .todo-b { background: var(--crit); color: #fff; }

/* Toko on a phone: one card per shop (B5, docs/mockups/toko-mobile). */
/* Toko on a phone: one card per shop (mockup 2026-10-28, docs/mockups/toko-mobile).
   Written to move into app.css as it is: everything is inside the phone query; the
   desktop keeps the table (.dt-toko) untouched. Tokens only (type vars, slate/warn/crit/ok);
   it reuses .chlogo, .state, .btn-xs, .impor-seg. Card slots, in order:
   .tk-hd (mark, name, one chip) · .tk-need (the problem + its one 44px button, 0..2)
   · .tk-facts (one quiet line) · .tk-int (integration rows, label | state | action)
   · .tk-ft (Biaya toko, Integrasi, Hapus toko). */
@media screen and (max-width: 759px) {
  /* B5: the table gives way to the cards on a phone; the cards are not drawn from 760px. */
  body.app .tk-table { display: none; }
  .tk-list { display: grid; gap: 8px; margin: 0 0 12px; padding: 0; list-style: none; }
  .tk { display: grid; gap: 6px; min-width: 0; padding: 10px 12px 0; background: var(--paper); border: 1px solid var(--slate-200); border-radius: 12px; }
  .tk.is-warn { box-shadow: inset 3px 0 0 var(--warn); }
  .tk.is-crit { box-shadow: inset 3px 0 0 var(--crit); }
  .tk > :last-child { margin-bottom: 10px; }
  .tk > .tk-ft:last-child { margin-bottom: 0; }

  /* 1. Header: mark, name (wraps, never cut), ONE chip. */
  .tk-hd { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: start; column-gap: 8px; row-gap: 2px; }
  .tk-hd .chlogo { width: 20px; height: 20px; margin: 1px 0 0; }
  .tk-nm { margin: 0; min-width: 0; font-size: var(--fs-head); font-weight: 700; line-height: 1.3; overflow-wrap: anywhere; }
  .tk-hd .state { padding: 2px 8px; }
  .tk-hd .state i { display: none; }
  .tk-cap { grid-column: 2 / -1; margin: 0; font-size: var(--fs-caption); line-height: 1.4; color: var(--slate-500); overflow-wrap: anywhere; }

  /* 2. The problem slot: its words, then ONE full-width 44px button. */
  .tk-need { display: grid; gap: 8px; min-width: 0; padding: 8px 10px; border-radius: 8px; background: var(--warn-soft); color: var(--warn-deep);
    font-size: var(--fs-body); font-weight: 600; line-height: 1.4; overflow-wrap: anywhere; }
  .tk-need.is-crit { background: var(--crit-soft); color: var(--crit); }
  .tk-need.is-est { background: var(--slate-100); color: var(--slate-700); }
  .tk-need .btn-xs { width: 100%; min-height: 44px; }
  .tk-need .tk-sub { margin: 0; font-size: var(--fs-caption); font-weight: 400; color: var(--slate-600); }
  .tk-need .tk-ask { margin: 0; font-weight: 400; color: var(--slate-600); }
  /* A row that is itself the link (Kesehatan): words left, chevron right, 44px. */
  .tk-need.is-go { padding-block: 0; }
  .tk-need.is-go a { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 44px; color: inherit; text-decoration: none; }
  .tk-need.is-go a::after { content: "›"; font-size: var(--fs-head); font-weight: 400; }
  /* The imported-goods question: words left, Ya | Tidak right. */
  .tk-need.is-task { grid-template-columns: minmax(0, 1fr) auto; align-items: center; row-gap: 2px; }
  .tk-need.is-task .tk-sub { grid-column: 1 / -1; color: var(--warn-deep); font-weight: 600; }

  /* 3. Facts: one quiet line; a part that is empty is not drawn, so no dangling dot. */
  .tk-facts { display: flex; flex-wrap: wrap; align-items: center; column-gap: 12px; margin: 0; padding: 0; list-style: none; font-size: var(--fs-caption); line-height: 1.4; color: var(--slate-600); }
  .tk-facts > li { position: relative; min-width: 0; overflow-wrap: anywhere; }
  .tk-facts a, .tk-facts summary { position: relative; color: var(--blue-700); font-weight: 600; text-decoration: none; cursor: pointer; }
  .tk-facts a::after, .tk-facts summary::after { content: ""; position: absolute; inset: -14px -4px; }
  .tk-facts .is-warn { color: var(--warn); font-weight: 700; }
  .tk-facts .tk-dot { display: inline-block; width: 6px; height: 6px; margin: 0 4px 1px 0; border-radius: 50%; background: var(--ok); vertical-align: middle; }
  .tk-facts .impor-edit { display: inline; }
  .tk-facts .impor-edit > summary { display: inline; min-height: 0; padding: 0; margin: 0; list-style: none; }
  .tk-facts .impor-edit > summary::-webkit-details-marker { display: none; }

  /* 4. Integrations: label | state | action on one grid, so states line up down the card. */
  .tk-int { display: grid; margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--slate-100); }
  .tk-int li { display: grid; grid-template-columns: 4.75rem minmax(0, 1fr) auto; align-items: center; column-gap: 8px; min-height: 36px; padding-block: 2px; font-size: var(--fs-body); line-height: 1.3; }
  .tk-int li + li { border-top: 1px solid var(--slate-100); }
  .tk-int .k { font-weight: 600; color: var(--slate-700); }
  .tk-int .v { min-width: 0; color: var(--slate-600); overflow-wrap: anywhere; }
  .tk-int .v.is-ok { color: var(--ok); font-weight: 600; }
  .tk-int .v.is-warn { color: var(--warn); font-weight: 700; }
  .tk-int .btn-xs { position: relative; min-width: 7.5rem; min-height: 36px; padding: 0 12px; font-size: var(--fs-caption); }
  .tk-int li > :nth-child(3) { justify-self: end; }
  .tk-int .btn-xs::after { content: ""; position: absolute; inset: -4px; }
  .tk-int .ask { font-size: var(--fs-caption); color: var(--slate-500); text-align: right; }
  .tk-int li.is-link { display: block; min-height: 0; padding: 0; }
  .tk-int li.is-link a { display: flex; align-items: center; justify-content: space-between; min-height: 44px; color: var(--slate-600); font-weight: 600; text-decoration: none; }
  .tk-int li.is-link a::after { content: "›"; font-size: var(--fs-head); font-weight: 400; }
  .tk-int li.is-wide .v { grid-column: 2 / -1; }

  /* Narrow phones: the state sits under its label so "Belum terhubung" never breaks inside a word. */
  @media (max-width: 399px) {
    .tk-int li { grid-template-columns: minmax(0, 1fr) auto; row-gap: 0; }
    .tk-int .k, .tk-int .v { grid-column: 1; }
    .tk-int .v { font-size: var(--fs-caption); }
    .tk-int li > :nth-child(3) { grid-column: 2; grid-row: 1 / 3; align-self: center; }
    .tk-int li.is-wide .v { grid-column: 1 / -1; }
  }

  /* 5. Footer: quiet links, Hapus toko alone at the right (wraps to its own line when tight). */
  .tk-ft { display: flex; flex-wrap: wrap; align-items: center; column-gap: 16px; border-top: 1px solid var(--slate-100); font-size: var(--fs-body); }
  .tk-ft a { display: inline-flex; align-items: center; min-height: 44px; color: var(--slate-600); font-weight: 600; text-decoration: none; overflow-wrap: anywhere; }
  .tk-ft a.is-warn { color: var(--warn); }
  .tk-ft a.tk-del { margin-left: auto; padding-inline: 4px; color: var(--crit); }
}

@media screen and (max-width: 759px) {
  .tk-intd > summary { display: flex; align-items: center; gap: 6px; min-height: 44px; border-top: 1px solid var(--slate-100); color: var(--blue-700); font-size: var(--fs-body); font-weight: 600; cursor: pointer; list-style: none; }
  .tk-intd > summary::-webkit-details-marker { display: none; }
  .tk-intd > summary::after { content: "›"; margin-left: auto; font-size: var(--fs-head); font-weight: 400; transition: transform .15s; }
  .tk-intd[open] > summary::after { transform: rotate(90deg); }
  .tk-intd .is-warn { color: var(--warn); font-weight: 700; }
  .tk .tk-intd + .tk-ft, .tk .tk-facts + .tk-ft { margin-top: 0; }
}
@media (min-width: 760px) { .tk-list { display: none; } }

/* Toko table: the integrations are lines of the Izin cell (Steph 2026-10-29). */
@media (min-width: 760px) {
  .dt-toko .izin-int { display: grid; gap: 2px; margin: 6px 0 0; padding: 0; list-style: none; font-size: var(--fs-caption); line-height: 1.4; }
  .dt-toko .izin-int li { display: grid; grid-template-columns: 3.6rem minmax(0, 1fr) auto; align-items: center; gap: 0 8px; min-height: 28px; }
  .dt-toko .izin-int .k { font-weight: 600; color: var(--slate-700); }
  .dt-toko .izin-int .v { color: var(--slate-600); }
  .dt-toko .izin-int .v.is-ok { color: var(--ok); font-weight: 600; }
  .dt-toko .izin-int .v.is-warn { color: var(--warn); font-weight: 700; }
  .dt-toko .izin-int .btn-xs { min-width: 7.5rem; min-height: 28px; padding: 0 10px; font-size: var(--fs-caption); }
  .dt-toko .izin-int form { display: inline; margin: 0; }
  .dt-toko .izin-int .ask { color: var(--slate-500); }
}
@media (min-width: 760px) {
  .dt-toko td.st:has(.izin-int) { min-width: 20rem; }
  .dt-toko .izin-int .v { white-space: nowrap; }
}

/* Count pill (Performa produk): a count, never a score. Neutral, tabular, hidden at zero by the template. */
.pill { display: inline-block; min-width: 20px; padding: 0 6px; border-radius: 10px; background: var(--slate-200, #e2e8f0); color: var(--slate-700, #334155); font-size: var(--fs-caption); font-weight: 700; line-height: 20px; text-align: center; font-variant-numeric: tabular-nums; }
.btn .pill { margin-left: 4px; }
.btn .pill-short { display: none; }
@media (max-width: 699px) { .btn .pill-long { display: none; } .btn .pill-short { display: inline; } }
