/* ==========================================================================
   Phoenix Boss — framework (boss.css)
   Rules: tokens only (no raw colors here), logical properties only,
   [dir="rtl"] only inside .icon-mirror, every component in both themes
   through the tokens, hit areas >= 44 px, text >= 14 px (labels 13, tab
   labels 12 — CONVENTIONS §8). Class names are the fixed vocabulary
   (docs/tasks/T-20260910-01, step 3). Propose a new class in chat first.
   ========================================================================== */

/* ---------- 0. base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; font-size: 100%; overscroll-behavior-y: contain; }   /* the viewport takes this rule from the root element only (never from body): it turns off the browser's own pull-to-reload, so .ptr gets the gesture (measured on the owner's Android, 2026-09-18) */
body {
  margin: 0;
  background: var(--bg);
  color: var(--t1);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  min-height: 100dvh;
}
/* Arabic typography (D-X): Plex Arabic face first, no letter-spacing, taller lines, no kashida */
:lang(ar) { font-family: var(--font-ar); letter-spacing: 0; line-height: var(--lh-ar); text-justify: none; }
h1, h2, h3, p { margin: 0; }
img, svg { display: block; max-width: 100%; }
/* icon defaults apply to icon classes only — never to chart SVGs (ApexCharts draws its own text and shapes) */
.icon, .icon-sm, .list-icon, .list-chev, .chev { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.icon.is-fill, .icon-sm.is-fill { fill: currentColor; stroke: none; }
/* no browser tap highlight; a soft pressed wash that follows the element's corners instead */
a, button, [role="button"], .tile, .list-row, .alert-row, .tab, .chip, .switch { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
:focus:not(:focus-visible) { outline: none; }
.tile:active, .list-row:active, .alert-row:active, .day-selector .pill-btn:active, .freshness:active, .audit-strip a:active { background-color: var(--pressed); }
.tab:active .tab-icon { background-color: var(--pressed); }
.btn:active, .chip:active, .segmented button:active, .btn-icon:active, .sheet-close:active, .th-sort:active, .day-selector .step:active { opacity: 0.8; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }
a { color: var(--acc-text); text-decoration: none; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
::placeholder { color: var(--t3); }

[hidden] { display: none !important; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* Numbers, codes, phones, emails: always LTR, isolated from the surrounding bidi run (D-Q) */
.num { direction: ltr; unicode-bidi: isolate; font-variant-numeric: tabular-nums; }
.tabular { font-variant-numeric: tabular-nums; }
/* Only directional icons mirror in RTL (list in CONVENTIONS §8) */
[dir="rtl"] .icon-mirror { transform: scaleX(-1); }
.icon { width: 20px; height: 20px; flex: none; }
.icon-sm { width: 16px; height: 16px; flex: none; }

/* ---------- 1. layout ---------- */
.stack { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); }
.stack-sm { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); }
.cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.cluster.is-between { justify-content: space-between; }   /* a line with its item at the far end (the report's range line and its chip) */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
@media (max-width: 359px) { .grid-2 { grid-template-columns: 1fr; } }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); }
/* three money values side by side (cash box): content-sized, and a value that does not fit moves to the next line — at any width and
   any text size (T-20260926-02: fixed columns overflowed at 393 px × 130 %) */
.grid-3:has(> .kv) { display: flex; flex-wrap: wrap; justify-content: space-between; }
.screen {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-3);
  padding-inline: calc(var(--sp-4) + var(--safe-s)) calc(var(--sp-4) + var(--safe-e));
  padding-block: var(--sp-4) var(--sp-6);
  max-width: var(--content-max); margin-inline: auto; width: 100%;
}
/* the shell banners inside the page (T-20260926-01, finding (h) of T-20260918-01): the banner screen keeps no bottom padding and the next
   screen (or the screen inside the next .ptr) starts 12 px below it = the gap between cards */
.screen.is-banners { padding-block-end: 0; }
.screen.is-banners + .screen, .screen.is-banners + .ptr > .screen { padding-block-start: var(--sp-3); }
.section { display: grid; gap: var(--sp-3); margin-block-start: var(--sp-3); }
.section-title {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-label); font-weight: var(--fw-semibold); color: var(--t3);
  letter-spacing: 0.06em; text-transform: uppercase;
}
:lang(ar) .section-title { letter-spacing: 0; text-transform: none; }
.section-title::before, .section-title::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.spacer { flex: 1; }
.text-2 { color: var(--t2); }
.text-3 { color: var(--t3); }
.support { font-size: var(--fs-support); color: var(--t3); }
/* an inline mark inside a line of text (the offline mark of a report: the hub's rows, the viewer's header line, the hub's legend) */
.list-meta .icon-sm, .support .icon-sm { display: inline-block; vertical-align: -3px; }
.support .icon-sm { width: 14px; height: 14px; }
.label { font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--t2); }
.title { font-size: var(--fs-title); font-weight: var(--fw-semibold); line-height: var(--lh-tight); }

/* ---------- 2. shell ---------- */
/* minmax(0, 1fr): the one column never grows to its content's minimum width (the header row with the full wordmark would otherwise widen
   the page instead of letting brand.fit step down — measured 402 px at a 320 px viewport, T-20260918-01) */
.app { min-height: 100dvh; display: grid; grid-template-rows: auto 1fr auto; grid-template-columns: minmax(0, 1fr); background: var(--bg); }
.app-main { min-width: 0; }
.app-header {
  position: sticky; top: var(--kit-top, 0px); z-index: var(--z-header);
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding-block: calc(var(--sp-2) + var(--safe-t)) var(--sp-2);
  padding-inline: calc(var(--sp-4) + var(--safe-s)) calc(var(--sp-4) + var(--safe-e));
  background: var(--bg);
}
.app-header-inner { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); width: 100%; max-width: var(--content-max); margin-inline: auto; min-height: var(--tap); min-width: 0; }
/* the brand is a logo (owner, 2026-09-18): the English wordmark in both languages (markup lang="en"), always mark -> text from left to
   right, and always at the left side of its header row — a row that holds the brand is laid out left to right; the other items of that
   row keep the page's direction inside (Arabic: right to left). A header row without the brand mirrors as usual. */
.app-header-inner:has(> .brand) { direction: ltr; }
:lang(ar) .app-header-inner:has(> .brand) > :not(.brand) { direction: rtl; }
.brand { display: flex; align-items: center; gap: var(--sp-2); font-family: var(--font); font-weight: var(--fw-semibold); font-size: var(--fs-section); white-space: nowrap; color: var(--t1); min-width: 0; direction: ltr; unicode-bidi: isolate; }
/* the wordmark fits the real space (owner, 2026-09-18): brand.fit (app js/shell.js, kit boss-kit.js) measures the visible label and sets
   data-fit = full ("Phoenix Boss") | short ("Boss") | mark (the gold mark alone); a clipped label steps down. The full name stays as
   visually hidden text at short and mark, so the brand keeps its accessible name; .brand-text-short is aria-hidden. */
.brand .brand-text, .brand .brand-text-short { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.brand .brand-text-short { display: none; }
.brand[data-fit="short"] .brand-text-short { display: block; }
.brand[data-fit="mark"] { flex-shrink: 0; }   /* the mark keeps its 24 px and never slides under the next item (result review r1b #5) */
.brand[data-fit="short"] .brand-text, .brand[data-fit="mark"] .brand-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* 2026-10-16 (T-20261015-01 D2): the mark is the sprite symbol i-brand (<svg class="brand-mark"><use href="icons.svg#i-brand"/></svg>), a filled shape */
.brand-mark { width: 24px; height: 24px; flex: none; color: var(--acc-text); fill: currentColor; stroke: none; }   /* --acc-text: 3:1 on the light page (the owner, 2026-10-16) */
.brand.is-hero .brand-mark { width: 40px; height: 40px; }
/* S2 Sign in: the brand alone at the top of the page, centred, the full wordmark (T-20260926-01; the page is 320 px wide at least) */
.brand.is-hero { justify-self: center; margin-block: var(--sp-6) var(--sp-4); }
/* branch name as the switcher trigger: a 44 px button with a chevron */
.branch-switch { display: inline-flex; align-items: center; gap: var(--sp-1); min-height: var(--tap); padding-inline: var(--sp-1); font-size: var(--fs-title); font-weight: var(--fw-semibold); color: var(--t1); line-height: var(--lh-tight); max-width: 100%; min-width: 0; flex: 1 1 auto; }
/* the header at 320 px (T-20260926-01, finding (e)): the branch name is cut with an ellipsis on one line, and the chip keeps its width, so
   brand + switcher + chip share one row at 320 / 360 px and 130 % text */
.branch-switch > span:not(.presence):not(.visually-hidden) { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-header-inner > .freshness, .app-header-inner > .btn-icon { flex: none; }   /* the chip and the help button (T-20261021-01) keep their width */
.branch-switch .icon { color: var(--t3); }
.branch-switch .presence { margin-inline-end: var(--sp-1); }
/* the report viewer's title block in the header row (T-20261003-02 D2 (h)): the back button, then the report's name at the section size and a
   support line "branch · mark" under it, both cut with an ellipsis. One row item, so in Arabic the back button sits at the start (right) side
   of its block while the brand stays at the left (the header row rule above) */
.header-title { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; column-gap: var(--sp-1); flex: 1 1 auto; min-width: 0; }
.header-title > .btn-icon { grid-row: span 2; }
.header-title:not(:has(> .support)) > .btn-icon { grid-row: auto; }   /* a title block without its second line (S12, T-20261008-01) */
.header-title > h1, .header-title > .support { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.header-title > h1 { font-size: var(--fs-section); font-weight: var(--fw-semibold); line-height: var(--lh-tight); }

.day-selector {
  display: inline-flex; align-items: center; gap: 0;
  min-height: var(--tap); padding-inline: 2px; max-width: 100%;
  border-radius: var(--r-pill); background: var(--card-2); border: 1px solid var(--line);
  color: var(--t1); font-size: var(--fs-body); box-shadow: var(--shadow-card); white-space: nowrap;
}
.day-selector .pill-btn { display: inline-flex; align-items: center; gap: var(--sp-1); min-height: var(--tap); padding-inline: var(--sp-2) var(--sp-1); border-radius: var(--r-pill); }
.day-selector b { font-weight: var(--fw-semibold); }
.day-selector .sep { color: var(--t3); padding-inline: 2px; }
.day-selector .pill-btn .icon { width: 18px; height: 18px; color: var(--acc-text); }
.day-selector .step { display: grid; place-items: center; width: 32px; height: 36px; border-radius: 50%; color: var(--t2); }
.day-selector .step:disabled { color: var(--line); cursor: default; }
.day-selector .step .icon { width: 18px; height: 18px; }
/* the day selector as the first row of a screen (S5, week 5 — T-20260929-01 D5): content-sized and centred, not stretched by the grid */
.screen > .day-selector { justify-self: center; }
/* the Branch tab's day row with the help button (T-20261021-01 H2.1, stop 1): the pair centred; on a narrow phone or with a large text the
   button goes under the selector, centred too */
.screen > .cluster:has(> .day-selector) { justify-self: center; justify-content: center; }

.tabbar {
  position: sticky; bottom: 0; z-index: var(--z-tabbar);
  /* one column per visible tab (owner, 2026-09-26, T-20260926-01): a tab hidden for lack of permission leaves no gap; five tabs = five equal columns */
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  background: var(--card-2); border-block-start: 1px solid var(--line);
  padding-block: var(--sp-2) calc(var(--sp-2) + var(--safe-b));
  padding-inline: calc(var(--sp-1) + var(--safe-s)) calc(var(--sp-1) + var(--safe-e));
}
.tab { display: grid; justify-items: center; align-content: center; gap: 3px; min-height: var(--tap); font-size: var(--fs-nav); font-weight: var(--fw-medium); color: var(--t3); text-decoration: none; }
.tab .tab-icon { position: relative; width: 52px; height: 30px; display: grid; place-items: center; border-radius: var(--r-pill); transition: background-color var(--dur-fast) var(--ease); }
.tab .tab-icon .icon { width: 24px; height: 24px; }
.tab.is-active { color: var(--acc-text); }
.tab.is-active .tab-icon .icon { stroke-width: 2.2; }
.tab .badge { position: absolute; top: -3px; inset-inline-start: calc(50% + 5px); }

.sheet-backdrop { position: fixed; inset: 0; background: var(--scrim); z-index: calc(var(--z-sheet) - 1); }
.sheet {
  position: fixed; inset-inline: 0; bottom: 0; z-index: var(--z-sheet);
  max-height: 90dvh; display: grid; grid-template-rows: auto auto minmax(0, 1fr) auto;
  background: var(--card-2); border-radius: var(--r-card) var(--r-card) 0 0;
  box-shadow: var(--shadow-raised); border-block-start: 1px solid var(--line);
  padding-inline: var(--safe-s) var(--safe-e);
}
.sheet-handle { width: 36px; height: 4px; border-radius: 2px; background: var(--line); margin: var(--sp-2) auto 0; }
.sheet-title { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4) 0; font-size: var(--fs-section); font-weight: var(--fw-semibold); }
.sheet-close { display: grid; place-items: center; width: var(--tap); height: var(--tap); margin-inline-end: calc(var(--sp-2) * -1); border-radius: 50%; color: var(--t2); }
.sheet-body { overflow: auto; padding: var(--sp-3) var(--sp-4); display: grid; grid-auto-rows: max-content; gap: var(--sp-3); align-content: start; overscroll-behavior: contain; }
/* grid-auto-rows: max-content (T-20261003-02 D2 (b)): a row keeps its content height, so a long list scrolls inside the body — without it the
   rows shrank to the body's height and the last rows could not be reached (measured at 360 px: 32 rows, scrollHeight 509 = clientHeight 509
   before, 1,640 > 509 after; a 3-row sheet unchanged at 405 px) */
.sheet-actions { display: grid; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4) calc(var(--sp-4) + var(--safe-b)); border-block-start: 1px solid var(--line); background: var(--card-2); }
.branch-switcher { display: grid; gap: var(--sp-2); }
.branch-switcher .list-row .money { font-weight: var(--fw-semibold); }

/* ---------- 3. data ---------- */
.kv { display: grid; gap: 2px; min-width: 0; }
.kv .v .money-cur, .kpi .v .money-cur { font-size: var(--fs-label); }
/* a money value wider than its box wraps the currency label onto its own line instead of overflowing (D-X: wrap, never clip) */
.kv .v.money, .kpi .v.money { flex-wrap: wrap; row-gap: 0; column-gap: 4px; white-space: normal; }
.kv .v.money .money-val, .kpi .v.money .money-val { white-space: nowrap; }
.kv .k { font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--t2); }
.kv .v { font-size: var(--fs-kpi-sm); font-weight: var(--fw-semibold); line-height: var(--lh-tight); white-space: nowrap; font-variant-numeric: tabular-nums; }
.kv .v.num { justify-self: start; }   /* an LTR count sits at the page's start side of its column in RTL too (2026-09-30) */
/* a body-size support note in a value slot ("after close"; T-20260926-02) */
.kv .v.is-note { font-size: var(--fs-body); font-weight: var(--fw-regular); color: var(--t3); white-space: normal; }

.kpi { grid-template-columns: minmax(0, 1fr); background: var(--card); border: 1px solid var(--line); border-radius: var(--r-card); padding: var(--sp-4); display: grid; gap: var(--sp-1); box-shadow: var(--shadow-card); min-width: 0; }
.kpi .k { font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--t2); }
.kpi .v { font-size: var(--fs-kpi); font-weight: var(--fw-semibold); line-height: var(--lh-tight); white-space: nowrap; font-variant-numeric: tabular-nums; }
.kpi .d { font-size: var(--fs-support); color: var(--t3); }
.kpi-sm .v { font-size: var(--fs-kpi-sm); }
.kpi .money .money-cur { font-size: var(--fs-label); }
/* the tile is px-sized and the text scales with the phone's font size: a tile narrower than 7rem of text takes the small KPI size
   (a rem in a container query follows the root font size — 112 px at 100 %, 145.6 px at 130 %; T-20260926-02, 130 % finding (a)) */
.kpi { container-type: inline-size; }
@container (max-width: 7rem) { .kpi .v { font-size: var(--fs-kpi-sm); } }
/* a value of 10 or more characters (100,000.00 and up) is 127 px at 24 px: in a tile narrower than 8rem it takes the small size too
   (owner, 2026-09-26: shrink long values only; the app and boss-kit.js set .is-long) */
@container (max-width: 8rem) { .kpi .v.is-long { font-size: var(--fs-kpi-sm); } }
/* a text value of a tile (a name: Top product, Top captain, Top type) wraps and stops after two lines with "…"; each name takes its own direction
   (2026-10-04, T-20261003-03, the owner's staging check: a 60-character product name widened the page by 357 px at 320 px; after: no page
   overflow at 320 / 360 px and 360 px × 130 %, EN and AR). The owner's second look (2026-10-04): a name takes the small KPI size in every tile,
   so Top category, Top subcategory, Top product, Top captain and Top cashier match, and a short two-word name stays on one line (measured at
   360 px: "Kofta plate" 2 lines at 24 px → 1 line at 18 px; "Fresh orange juice" 3 → 2) */
.kpi .v:not(.money):not(.num) { font-size: var(--fs-kpi-sm); white-space: normal; overflow-wrap: anywhere; unicode-bidi: plaintext; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }

.totals-bar {
  /* flex with wrap (the .grid-3 form): a value that does not fit goes to the next line (393 px × 130 %: the grid of three ran 48–60 px
     over, measured 2026-09-30, T-20260930-01 step 2); with room the three values share one line as before */
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--sp-2) var(--sp-3);
  background: var(--card-2); border: 1px solid var(--line); border-radius: var(--r-card);
  padding: var(--sp-3) var(--sp-4); box-shadow: var(--shadow-card);
}
.totals-bar .kv .v { font-size: var(--fs-totals); }
.totals-bar .meta { grid-column: 1 / -1; width: 0; min-width: 100%; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2); font-size: var(--fs-support); color: var(--t2); } /* width 0 + min-width 100%: a spanning row must not widen the content-sized columns */
@media (max-width: 379px) { .totals-bar .kv:first-child { flex-basis: 100%; } }
.totals-bar.is-sticky { position: sticky; top: calc(var(--kit-top, 0px) + var(--tap) + var(--sp-4) + var(--safe-t)); z-index: var(--z-sticky); }

/* audit strip: quiet counters with count and value; loud only when flagged (D-I) */
.audit-strip { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); padding-inline: var(--sp-1); font-size: var(--fs-support); color: var(--t2); font-variant-numeric: tabular-nums; }
.audit-strip a, .audit-strip > span { display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding-block: 6px; color: inherit; }   /* a span item: no link target yet (week 4) */
.card > .audit-strip { padding: 0; }
.audit-strip .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--bad); flex: none; }
.audit-strip .money { font-size: inherit; }
.audit-strip .money .money-cur { font-size: var(--fs-label); }
.audit-strip .is-flagged { color: var(--warn-text); font-weight: var(--fw-semibold); }
.audit-strip .is-flagged .icon-sm { width: 15px; height: 15px; }

/* branch tile (D-J) */
.tile { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); background: var(--card); border: 1px solid var(--line); border-radius: var(--r-card); padding: var(--sp-4); padding-inline-end: calc(var(--sp-4) + 18px); box-shadow: var(--shadow-card); color: inherit; text-decoration: none; }
.tile .top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.tile .nm { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-section); font-weight: var(--fw-semibold); min-width: 0; }
.tile .nm span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tile .sub { font-size: var(--fs-support); color: var(--t2); margin-block-start: -4px; }
.tile .row { display: grid; grid-template-columns: repeat(3, max-content); justify-content: space-between; gap: var(--sp-2) var(--sp-3); margin-block-start: var(--sp-1); }
/* the three values on two lines when the tile is narrow: measured by the tile's own width in rem, so a larger text size wraps too
   (2026-09-30, T-20260930-01 step 2 — the 130 % finding (b): the row ran 5–9 px over at 360 px and 75–80 px at 360 px × 130 %) */
.tile:not(.is-compact) { container-type: inline-size; }
@container (max-width: 18rem) { .tile .row { grid-template-columns: 1fr 1fr; } .tile .row .kv:first-child { grid-column: 1 / -1; } }
.tile .foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-1) var(--sp-2); font-size: var(--fs-support); color: var(--t3); }
.tile .chev { position: absolute; inset-inline-end: 12px; top: 16px; width: 18px; height: 18px; color: var(--t3); }
.tile.is-compact { grid-template-columns: auto minmax(0, 1fr) auto auto auto; align-items: center; gap: var(--sp-2) var(--sp-3); padding-block: var(--sp-3); padding-inline-end: var(--sp-4); min-height: 56px; }
.tile.is-compact .sub { grid-column: 2 / -1; }
.tile.is-compact .nm { font-size: var(--fs-body); }
.tile.is-compact .sub { margin: 0; }
.tile.is-compact .money { font-weight: var(--fw-semibold); }
.tile.is-compact .chev { position: static; }

.presence { width: 9px; height: 9px; border-radius: 50%; flex: none; background: var(--idle); }
.presence.is-on { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-soft); }
.presence.is-off { background: var(--bad); box-shadow: 0 0 0 3px var(--bad-soft); }
.presence.is-idle { background: var(--idle); }

.trend { display: inline-flex; align-items: center; gap: 4px; font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.trend.is-up { color: var(--ok-text); }
.trend.is-down { color: var(--bad-text); }
.trend.is-flat { color: var(--t2); }
.trend .trend-ctx { font-weight: var(--fw-regular); color: var(--t3); }

/* bidi-safe money (D-Q) */
.money { display: inline-flex; align-items: baseline; gap: 4px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.money .money-cur { font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--t2); }
.money .money-val { direction: ltr; unicode-bidi: isolate; letter-spacing: -0.01em; }
:lang(ar) .money .money-cur { order: 2; }
.money.is-neg .money-val { color: var(--bad-text); }
.money.is-pos .money-val { color: var(--ok-text); }

.card { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); background: var(--card); border: 1px solid var(--line); border-radius: var(--r-card); padding: var(--sp-4); box-shadow: var(--shadow-card); min-width: 0; }
.card-title { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-2); font-size: var(--fs-section); font-weight: var(--fw-semibold); }
.card-title .sub { font-size: var(--fs-support); color: var(--t3); font-weight: var(--fw-regular); }
.card.is-callout { border-color: var(--acc); background: var(--acc-soft); }
/* a card whose list runs edge to edge: title keeps the padding, the list keeps the bottom corners */
.card.is-flush { padding: 0; gap: 0; }
.card.is-flush > .card-title { padding: var(--sp-4) var(--sp-4) var(--sp-2); }
.card.is-flush > .list { border: 0; box-shadow: none; border-radius: 0; }
/* the corners of a flush card belong to its first and last child, whatever that child is (2026-10-03, T-20261003-02, the owner's staging
   check): the old rule rounded only the list's bottom corners and assumed a .card-title above it, so a card without a title (the Reports
   hub) showed a square top — the child's own background painted over the card's round corner */
.card.is-flush > :first-child { border-start-start-radius: var(--r-card); border-start-end-radius: var(--r-card); }
.card.is-flush > :last-child { border-end-start-radius: var(--r-card); border-end-end-radius: var(--r-card); }
.card.is-flush > .support { padding: 0 var(--sp-4) var(--sp-4); }   /* a support line ("No sales yet") in a flush card keeps the card padding */
.card.is-callout .steps { display: grid; gap: var(--sp-2); }
.card.is-callout img { inline-size: 100%; border-radius: var(--r-ctl); }   /* S12's two iOS pictures, a direct child of .steps after their row; never mirrored (2026-10-17, T-20261016-01 D5) */
.card.is-callout .steps > div { display: flex; align-items: center; gap: var(--sp-2); min-height: 28px; }
.card.is-callout .n { width: 22px; height: 22px; border-radius: 50%; background: var(--acc); color: var(--acc-on); display: grid; place-items: center; font-size: var(--fs-label); font-weight: var(--fw-semibold); flex: none; }
.card.is-callout .n.is-done { background: var(--ok); color: var(--card); }
.card.is-callout .n .icon-sm { width: 12px; height: 12px; }   /* the check of a done step (the kit's inline style removed, 2026-09-30) */
.steps > .cluster { flex-wrap: nowrap; align-items: flex-start; }   /* a numbered step row: the text wraps beside its number (T-20261008-01, S9 blocked card) */
.steps > .cluster > .pill { flex: none; }

/* freshness chip (D-W) */
.freshness { display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding-inline: 10px; margin-block: 6px; border-radius: var(--r-pill); border: 1px solid var(--line); background: var(--card); color: var(--t2); font-size: var(--fs-support); font-weight: var(--fw-medium); white-space: nowrap; }
.freshness .icon-sm { width: 14px; height: 14px; }
.freshness .presence { width: 8px; height: 8px; box-shadow: none; }
.freshness.is-fresh .presence { background: var(--ok); }
.freshness.is-aging { color: var(--warn-text); border-color: var(--warn); }
.freshness.is-aging .presence { background: var(--warn); }
.freshness.is-stale .presence { background: var(--idle); }

/* tables: sticky header, sticky first column, numeric cells, pinned totals */
.table-scroll { overflow: auto; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); box-shadow: var(--shadow-card); max-height: 70dvh; overscroll-behavior: auto; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
.table-scroll::-webkit-scrollbar { width: 4px; height: 4px; }
.table-scroll::-webkit-scrollbar-thumb { background: var(--line); border-radius: 2px; }
.table-scroll::-webkit-scrollbar-track { background: transparent; margin: var(--r-card); }
.table-scroll::-webkit-scrollbar-corner { background: transparent; }   /* the square where the two bars meet sat outside the round corner */
/* Chromium 121+ ignores every ::-webkit-scrollbar rule above (the 4 px bar and the track margin that keeps it inside the round corners) as
   soon as scrollbar-width or scrollbar-color is set — the bar then ran into the corners (the owner's staging check, 2026-10-03,
   T-20261003-02). The two standard properties stay for the engines without the webkit pseudo-elements only */
@supports selector(::-webkit-scrollbar) { .table-scroll { scrollbar-width: auto; scrollbar-color: auto; } }
.chip-row { scrollbar-width: none; }
.table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: var(--fs-body); }
.table th, .table td { text-align: start; padding: var(--sp-3) var(--sp-3); border-block-end: 1px solid var(--line); white-space: nowrap; vertical-align: middle; height: var(--tap); }
.table th { position: sticky; top: 0; z-index: 2; background: var(--card-2); font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--t2); }
.table .is-num { text-align: end; font-variant-numeric: tabular-nums; }
.table td.is-num { direction: ltr; unicode-bidi: isolate; }
.table .th-sort { display: inline-flex; align-items: center; gap: 4px; min-height: 28px; color: var(--t1); font-weight: var(--fw-medium); }
.table .th-sort .icon-sm { width: 12px; height: 12px; color: var(--t3); }
.table .th-sort.is-asc .icon-sm, .table .th-sort.is-desc .icon-sm { color: var(--acc-text); }
.table .th-sort.is-desc .icon-sm { transform: rotate(180deg); }
.table .is-sticky-col { position: sticky; inset-inline-start: 0; z-index: 1; background: var(--card); border-inline-end: 1px solid var(--line); }
.table th.is-sticky-col { z-index: 3; background: var(--card-2); }
.table .table-totals td { position: sticky; bottom: 0; z-index: 2; background: var(--card-2); font-weight: var(--fw-semibold); border-block-start: 1px solid var(--line); border-block-end: 0; }
.table .table-totals td.is-sticky-col { z-index: 3; }
.table-foot { display: flex; align-items: center; justify-content: center; gap: var(--sp-2); padding: var(--sp-2); font-size: var(--fs-support); color: var(--t3); }
/* T-20261003-02 D2 (h): the report viewer's table is capped lower than the default (the KPI strip and the chart sit above it); a negative money
   cell carries the true minus and --bad-text without a word — the column header is the word (CONVENTIONS §9, the exception to D-U) */
.table-scroll.is-capped { max-block-size: 60dvh; }
/* T-20261008-02 D1 (CUT-LIST 2026-09-30 (b)): a summary table whose first column is a label — the label wraps its words, the number columns
   keep one line, so a four-column table fits 360 px without a sideways scroll (/more/timing's two summary tables) */
.table.is-wrap th:first-child, .table.is-wrap td:first-child { white-space: normal; }
.table td.is-neg { color: var(--bad-text); }
/* T-20261003-03 D2 (b): a sub-row under its main row (the payment rows of a person on By captain / By cashier): the label in --t2 and the
   support size, indented at the start; its value sits in the first number column, end-aligned as the numbers above it (start-aligned in a
   spanning cell it ran out of view in Arabic at 360 px × 130 %); not a tap target, so the row takes its content height */
.table tr.is-sub td { height: auto; padding-block: var(--sp-2); font-size: var(--fs-support); color: var(--t2); }
.table tr.is-sub td.is-sticky-col { padding-inline-start: var(--sp-6); }
/* T-20261003-03 D2 (a), (c): the drill link of a report row fills its sticky cell (the 44 px hit area), its chevron after the text */
.table td > a { display: flex; align-items: center; gap: var(--sp-1); min-height: var(--tap); margin-block: calc(-1 * var(--sp-3)); font-weight: var(--fw-medium); inline-size: max-content; max-inline-size: 11rem; white-space: normal; }
.table td > a .icon-sm { width: 14px; height: 14px; flex: none; }
/* a name in the sticky column (a person, a product) takes its own width up to 9rem and wraps after it: measured on the kit, a long name made
   the sticky column 239 px of a 267 px table at 320 px (304 px at 360 px × 130 %) and pushed every number out of view */
/* a sub-row's label keeps the page direction ("Cash · Paid" / "نقدي · المحصل"); only the method name is isolated (r1b Minor 3) */
.table td.is-sticky-col > bdi, .table tr.is-sub td.is-sticky-col > span { display: block; inline-size: max-content; max-inline-size: 9rem; white-space: normal; }

/* lists */
.list { display: grid; background: var(--card); border: 1px solid var(--line); border-radius: var(--r-card); box-shadow: var(--shadow-card); overflow: hidden; }
.list-row { display: flex; align-items: center; gap: var(--sp-3); min-height: 48px; padding: var(--sp-2) var(--sp-4); border-block-end: 1px solid var(--line); color: inherit; text-decoration: none; }
.list-row:last-child { border-block-end: 0; }
.list-row .list-icon { width: 22px; height: 22px; color: var(--t2); flex: none; }
.list-row .list-main { flex: 1; min-width: 0; display: grid; gap: 1px; }
.list-row .list-sub { font-size: var(--fs-support); color: var(--t3); }
.list-row .list-meta { font-size: var(--fs-support); color: var(--t2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.list-row .list-meta.is-warn { color: var(--warn-text); font-weight: var(--fw-medium); }
.list-row .list-chev { width: 18px; height: 18px; color: var(--t3); flex: none; }
.list-row.is-danger { color: var(--bad-text); font-weight: var(--fw-medium); }
.list-row .rank { width: 22px; font-size: var(--fs-support); color: var(--t3); font-variant-numeric: tabular-nums; flex: none; }
.list-row.is-more .list-main { color: var(--acc-text); font-weight: var(--fw-medium); }   /* the "Show all N" row */
button.list-row { inline-size: 100%; text-align: start; }   /* T-20261004-02 D5: a row that acts in place ("Show all N" on S5) — measured: the button centred its text */
.list-row.is-bare { padding-inline: 0; border: 0; min-height: 36px; }   /* a row inside a card: no side padding, no border */
.list-row b { font-weight: var(--fw-semibold); }   /* a facts list's subtotal row (T-20261003-03 D2 (d)): the type scale's maximum weight */
/* a two-line row with a fixed end column (the open checks, owner's choice R2 of 2026-09-27): line 1 = the title and the money, line 2 = the
   people and the time; each text line is cut with an ellipsis, so the money and the time always sit at the same edge */
.list-row.is-grid { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; column-gap: var(--sp-3); row-gap: 2px; align-items: baseline; }
.list-row.is-grid > .list-icon { grid-row: 1 / span 2; align-self: center; }
.list-row.is-grid > .list-sub { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the title line: the check (its own span) keeps its room, the flag pill after it shrinks with an ellipsis — a long pill never hides itself
   or the check (the owner's picture of 2026-09-27: "Table 9…" with the "changed after print" pill gone) */
.list-row.is-grid > .list-title { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 6px; min-width: 0; font-weight: var(--fw-medium); white-space: nowrap; }
.list-row.is-grid > .list-title > span:first-child { flex: none; }
/* 2026-10-03 (T-20261003-03 D2 (g), S5 finding (a)): the pill moves to its own line when it does not fit beside the check, and its words break
   there — measured on the kit: before, "مطبوعة" / "printed" read "…" at 320 px × 130 % (and "changed after print" at 320 / 360 px); after, every
   word shows at 320 / 360 / 393 px, 100 % and 130 %, EN and AR, with no page overflow */
.list-row.is-grid > .list-title > .pill { min-width: 0; display: block; white-space: normal; line-height: var(--lh-tight); padding-block: 3px; }
.list-row.is-grid > .money, .list-row.is-grid > .list-meta { justify-self: end; }
/* T-20261004-02 D5: an open-order row as a link to S8 — its chevron in a fourth column beside both lines (measured: in three columns it fell to a third line) */
.list-row.is-grid.is-nav { grid-template-columns: 22px minmax(0, 1fr) auto 18px; }
.list-row.is-grid.is-nav > .list-chev { grid-column: 4; grid-row: 1 / span 2; align-self: center; }
/* a trailing money value may wrap between its label and its value at a large text size (130 % finding (c)); the value itself never breaks */
.list-row > .money { flex-wrap: wrap; justify-content: flex-end; row-gap: 0; white-space: normal; }
.list-row > .money .money-val { white-space: nowrap; }
.day-group { position: sticky; top: calc(var(--kit-top, 0px) + var(--tap) + var(--sp-4) + var(--safe-t)); z-index: var(--z-sticky); display: flex; justify-content: space-between; gap: var(--sp-2); padding-block: var(--sp-2); background: var(--bg); font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--t2); }

/* alert rows (UX review E10) */
.alert-row { display: grid; grid-template-columns: 8px 24px minmax(0, 1fr) auto; gap: var(--sp-1) var(--sp-3); align-items: start; padding: var(--sp-3) var(--sp-4); min-height: var(--tap); border-block-end: 1px solid var(--line); color: inherit; text-decoration: none; }
.alert-row:last-child { border-block-end: 0; }
.alert-row .unread { width: 8px; height: 8px; border-radius: 50%; background: var(--acc-text); margin-block-start: 6px; visibility: hidden; }
.alert-row.is-unread .unread { visibility: visible; }
.alert-row .sev { width: 24px; height: 24px; border-radius: 8px; display: grid; place-items: center; }
.alert-row .sev .icon-sm { width: 15px; height: 15px; }
.alert-row.is-high .sev { background: var(--bad-soft); color: var(--bad-text); }
.alert-row.is-medium .sev { background: var(--warn-soft); color: var(--warn-text); }
.alert-row.is-info .sev { background: var(--fill); color: var(--t2); }
.alert-row .body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2px; min-width: 0; }   /* T-20261006-03 step 8: a long name inside an isolate no longer widens the column over the time (measured 230 px in a 174 px column) */
.alert-row .ttl { font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--t1); }
.alert-row.is-unread .ttl { font-weight: var(--fw-semibold); }
.alert-row .txt { font-size: var(--fs-support); color: var(--t2); }
.alert-row .meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); font-size: var(--fs-support); color: var(--t3); }
.alert-row .time { font-size: var(--fs-support); color: var(--t2); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* chart container: the drawing comes from ApexCharts with the shared options */
.chart { position: relative; min-height: 180px; }
.chart.is-donut { min-height: 200px; }
/* two donut cards side by side share their rows (title, chart, legend, support line): a title on two lines no longer pushes one donut
   lower than the other (the owner's staging check, 2026-09-27) */
.grid-2:has(> .card > .chart.is-donut + .chart-legend) { grid-template-rows: repeat(4, auto); }
.grid-2:has(> .card > .chart.is-donut + .chart-legend) > .card { grid-row: span 4; grid-template-rows: subgrid; }
.chart-legend { display: grid; gap: 6px; font-size: var(--fs-support); }
.chart-legend > div { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.chart-legend .l { display: flex; align-items: center; gap: var(--sp-2); color: var(--t2); }
.chart-legend .sw { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.chart-legend .n { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.sw-1 { background: var(--c1); } .sw-2 { background: var(--c2); } .sw-3 { background: var(--c3); }
.sw-4 { background: var(--c4); } .sw-5 { background: var(--c5); } .sw-6 { background: var(--c6); }

/* ---------- 4. state ---------- */
.banner { display: flex; align-items: center; gap: var(--sp-3); min-height: 40px; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-ctl); font-size: var(--fs-support); font-weight: var(--fw-medium); }
.banner .presence { width: 8px; height: 8px; box-shadow: none; }
.banner .icon-sm { flex: none; }
.banner .link { color: inherit; font-weight: var(--fw-semibold); text-decoration: underline; text-underline-offset: 2px; min-height: 32px; display: inline-flex; align-items: center; }
.banner.is-live { background: var(--ok-soft); color: var(--ok-text); }
.banner.is-live .presence { background: var(--ok); }
.banner.is-stale { background: var(--warn-soft); color: var(--warn-text); }
.banner.is-stale .presence { background: var(--warn); }
.banner.is-offline { background: var(--bad-soft); color: var(--bad-text); }
.banner.is-offline .presence { background: var(--bad); }
.banner.is-update { background: var(--acc-soft); color: var(--acc-text); }
.banner.is-busy { background: var(--fill); color: var(--t2); }

/* pull-to-refresh (T-20260918-01 D7; owner's yes: new kit component). .ptr wraps the page content and hosts the indicator; it is not a
   scroll container — the document scrolls, so the gesture starts only at the page's own top (app js/shell.js ptr.attach). JS sets the
   state classes (.is-pulling, .is-ready, .is-refreshing) and two custom properties through the CSSOM: --ptr-y (the pull distance, px) and
   --ptr-p (the progress 0…1, turns the icon). The content moves down by the pull distance and the pill sits centred in the gap above
   it (no translateX / left / right); the three texts are resources and the state shows one. */
.ptr { position: relative; }
.ptr > :not(.ptr-indicator) { transition: transform var(--dur) var(--ease); }
.ptr.is-pulling > :not(.ptr-indicator), .ptr.is-refreshing > :not(.ptr-indicator) { transform: translateY(var(--ptr-y, 0px)); }
.ptr.is-pulling > :not(.ptr-indicator) { transition: none; }
.ptr-indicator {
  position: absolute; top: 0; inset-inline: 0; margin-inline: auto; width: max-content; z-index: var(--z-sticky);
  display: flex; align-items: center; gap: var(--sp-2); min-height: 32px; padding-inline: var(--sp-3);
  border-radius: var(--r-pill); border: 1px solid var(--line); background: var(--card-2); box-shadow: var(--shadow-raised);
  color: var(--t2); font-size: var(--fs-support); font-weight: var(--fw-medium); white-space: nowrap;
  transform: translateY(calc((var(--ptr-y, 0px) - 100%) / 2)); opacity: 0; visibility: hidden; pointer-events: none;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease), visibility var(--dur);
}
.ptr-indicator .icon-sm { color: var(--acc-text); transform: rotate(calc(var(--ptr-p, 0) * 270deg)); }
.ptr.is-pulling .ptr-indicator, .ptr.is-refreshing .ptr-indicator { opacity: 1; visibility: visible; }
.ptr.is-pulling .ptr-indicator { transition: none; }
.ptr.is-refreshing .ptr-indicator .icon-sm { animation: boss-spin 0.8s linear infinite; }
@keyframes boss-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.ptr-indicator .ptr-release, .ptr-indicator .ptr-busy { display: none; }
.ptr.is-ready .ptr-indicator .ptr-pull, .ptr.is-refreshing .ptr-indicator .ptr-pull, .ptr.is-refreshing .ptr-indicator .ptr-release { display: none; }
.ptr.is-ready:not(.is-refreshing) .ptr-indicator .ptr-release, .ptr.is-refreshing .ptr-indicator .ptr-busy { display: inline; }
@media (prefers-reduced-motion: reduce) { .ptr-indicator { transition: none; } .ptr-indicator .icon-sm { transform: none; } .ptr.is-refreshing .ptr-indicator .icon-sm { animation: none; } }

.skeleton { position: relative; overflow: hidden; background: var(--skeleton); border-radius: var(--r-ctl); min-height: 16px; }
.skeleton::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, var(--skeleton-hi), transparent); opacity: 0.85; animation: boss-shimmer 1.4s infinite; }
@keyframes boss-shimmer { from { transform: translate(-100%, 0); } to { transform: translate(100%, 0); } }
@media (prefers-reduced-motion: reduce) { .skeleton::after { animation: none; } }
.skeleton.is-tile { min-height: 132px; border-radius: var(--r-card); }
.skeleton.is-kpi { min-height: 84px; border-radius: var(--r-card); }
.skeleton.is-chart { min-height: 180px; border-radius: var(--r-card); }
.skeleton.is-row { min-height: 48px; border-radius: 0; }
.skeleton.is-text { min-height: 14px; max-width: 60%; }
.loading-note { font-size: var(--fs-support); color: var(--t3); text-align: center; }

.empty-state { display: grid; justify-items: center; gap: var(--sp-2); padding: var(--sp-6) var(--sp-4); text-align: center; background: var(--card); border: 1px solid var(--line); border-radius: var(--r-card); }
.empty-state .icon { width: 32px; height: 32px; color: var(--t3); }
.empty-state .ttl { font-size: var(--fs-section); font-weight: var(--fw-semibold); }
.empty-state .txt { font-size: var(--fs-body); color: var(--t2); max-width: 32ch; }
.empty-state .btn { margin-block-start: var(--sp-2); }
.empty-state.is-error .icon { color: var(--bad-text); }
.empty-state.is-denied .icon, .empty-state.is-expired .icon { color: var(--t2); }
.empty-state.is-needs-live .icon { color: var(--warn-text); }
.empty-state.is-full { min-height: 60dvh; align-content: center; border: 0; background: transparent; }
/* an empty state inside a card (S5's "Needs the branch online" cards, week 5 — T-20260929-01 D6): the card is the box, so no second border */
.card > .empty-state { border: 0; background: transparent; padding-block: var(--sp-3) var(--sp-2); }

/* T-20261008-02 (the owner's phone check, R7 yes 2026-10-10): + var(--sp-3) — the tab bar is about 65 px high, so the toast sat 3 px above it; now about 15 px */
.toast { position: fixed; inset-inline: var(--sp-4); bottom: calc(var(--tap) + var(--sp-6) + var(--sp-3) + var(--safe-b)); z-index: var(--z-toast); display: flex; align-items: center; gap: var(--sp-3); min-height: var(--tap); padding: var(--sp-2) var(--sp-4); border-radius: var(--r-ctl); background: var(--toast-bg); color: var(--toast-text); font-size: var(--fs-body); font-weight: var(--fw-medium); box-shadow: var(--shadow-raised); max-width: calc(var(--content-max) - var(--sp-8)); margin-inline: auto; }
body:has(.toast:not([hidden])) .screen:not(.is-banners) { padding-block-end: calc(var(--sp-8) + var(--tap) + var(--sp-4)); }
.toast .link { color: var(--toast-link); font-weight: var(--fw-semibold); margin-inline-start: auto; min-height: 32px; display: inline-flex; align-items: center; }

.pill { display: inline-flex; align-items: center; gap: 4px; min-height: 24px; padding-inline: 8px; border-radius: var(--r-pill); background: var(--fill); color: var(--t2); font-size: var(--fs-label); font-weight: var(--fw-medium); white-space: nowrap; }
.pill.is-ok { background: var(--ok-soft); color: var(--ok-text); }
.pill.is-warn { background: var(--warn-soft); color: var(--warn-text); }
.pill.is-bad { background: var(--bad-soft); color: var(--bad-text); }
.pill .icon-sm { width: 12px; height: 12px; }
.badge { display: inline-flex; align-items: center; justify-content: center; gap: 3px; min-width: 18px; height: 18px; padding-inline: 5px; border-radius: var(--r-pill); background: var(--bad); color: var(--bad-on); font-size: var(--fs-micro); font-weight: var(--fw-semibold); line-height: 1; font-variant-numeric: tabular-nums; }
.badge.has-icon { height: 20px; min-width: 20px; padding-inline: 6px; font-size: var(--fs-nav); }
.badge.has-icon .icon-sm { width: 12px; height: 12px; }

/* ---------- 5. controls ---------- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); min-height: var(--tap); padding-inline: var(--sp-5); border-radius: var(--r-ctl); border: 1px solid transparent; font-size: 0.9375rem; font-weight: var(--fw-semibold); white-space: nowrap; transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
.btn-primary { background: var(--acc); color: var(--acc-on); }
.btn-secondary { background: transparent; color: var(--acc-text); border-color: var(--line); }
.btn-ghost { background: transparent; color: var(--acc-text); }
.btn-danger { background: var(--bad); color: var(--bad-on); }
.btn-ghost.is-danger { color: var(--bad-text); }   /* T-20261008-02 D1: a quiet destructive action inside a row (S11 "Remove" on another phone) */
.btn-block { width: 100%; }
.btn:disabled { opacity: 0.5; cursor: default; }
.btn .icon { width: 18px; height: 18px; }
.btn-icon { display: grid; place-items: center; width: var(--tap); height: var(--tap); border-radius: 50%; color: var(--t2); }

.segmented { display: inline-flex; background: var(--fill); border-radius: var(--r-ctl); padding: 3px; gap: 2px; max-width: 100%; }
.segmented button { flex: 1; min-height: 38px; padding-inline: var(--sp-3); border-radius: 9px; font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--t2); white-space: nowrap; transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
.segmented button[aria-pressed="true"] { background: var(--fill-on); color: var(--t1); box-shadow: var(--shadow-card), inset 0 0 0 1px var(--line); font-weight: var(--fw-semibold); }
.segmented.is-block { display: flex; }

.chip { display: inline-flex; align-items: center; gap: 4px; min-height: 32px; padding-inline: var(--sp-3); border-radius: var(--r-pill); background: var(--fill); color: var(--t2); font-size: var(--fs-label); font-weight: var(--fw-medium); white-space: nowrap; border: 1px solid transparent; }
.chip.is-active { background: var(--acc-soft); color: var(--acc-text); border-color: var(--acc); }
.chip.is-late { background: var(--warn-soft); color: var(--warn-text); }
.chip.is-attention { background: var(--bad-soft); color: var(--bad-text); }
.chip .icon-sm { width: 14px; height: 14px; }
.chip-row { display: flex; gap: var(--sp-2); overflow-x: auto; padding-block: 2px; scrollbar-width: none; }
.chip-row::-webkit-scrollbar { display: none; }
.chip-row .chip { flex: none; }

.switch { position: relative; width: 46px; height: 28px; flex: none; border-radius: var(--r-pill); background: var(--idle); transition: background-color var(--dur-fast) var(--ease); }
.switch::after { content: ""; position: absolute; top: 4px; inset-inline-start: 4px; width: 20px; height: 20px; border-radius: 50%; background: var(--switch-knob); transition: inset-inline-start var(--dur-fast) var(--ease); }
.switch[aria-checked="true"] { background: var(--ok); }
.switch[aria-checked="true"]::after { inset-inline-start: 22px; background: var(--switch-knob-on); }
.switch:disabled { opacity: 0.5; }

.field { display: grid; gap: var(--sp-1); }
.field .field-label { font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--t2); }
.input, .select { min-height: var(--tap); padding-inline: var(--sp-3); border-radius: var(--r-ctl); border: 1px solid var(--line); background: var(--card); color: var(--t1); font-size: var(--fs-body); width: 100%; }
.input:focus, .select:focus { border-color: var(--acc-text); outline: 2px solid var(--focus); outline-offset: 0; }
.input.is-ltr { direction: ltr; text-align: start; unicode-bidi: isolate; }
.field .hint { font-size: var(--fs-support); color: var(--t3); }
.field.is-error .input { border-color: var(--bad); }
.field.is-error .hint { color: var(--bad-text); display: inline-flex; align-items: center; gap: 4px; }
.search { position: relative; }
.search .icon-sm { position: absolute; inset-inline-start: var(--sp-3); top: 50%; transform: translate(0, -50%); color: var(--t3); }
.search .input { padding-inline-start: calc(var(--sp-3) + 24px); }

.period-picker { display: grid; gap: var(--sp-2); }
.period-picker .range { display: grid; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); gap: var(--sp-2); }
/* iOS WebKit gives a date or time input a wide intrinsic size, and a grid item does not shrink below its content: both fields of the custom
   range and of quiet hours ran past the sheet on iOS 18.5 (2026-10-17, T-20261016-01 M6, the owner's yes, R7). The field and the input may
   shrink to their column, and every date or time input drops WebKit's own control look, which keeps its own width and its own grey look —
   one look for all of them (the four single "Go to date" fields too: the owner's answer of the result review, 2026-10-17); the tap still
   opens the iOS picker, and Chromium keeps its size and its picker icon (checked at 390 px). */
.period-picker .range > .field, .period-picker .range .input { min-inline-size: 0; }
.input[type="date"], .input[type="time"] { -webkit-appearance: none; appearance: none; }
/* two date fields side by side when both fit, one under the other when not (T-20261003-02 D2 (c)): a native date field needs about 150 px at
   the 16 px root (9.4rem), so no column is narrower than the field; the rem form follows the text scale. Measured: 1fr 1fr overflowed at
   320 px (EN: the second field ended at 324 px; AR: it started at -19 px) and at 360 px x 130 %; this rule gives one column at 320 px and at
   360 px x 130 %, two columns at 360 and 393 px, both languages, no page overflow */


/* hit areas: small visible controls get an invisible 44 px tap area (D-Y) */
.chip, .freshness, .audit-strip a, .switch, .th-sort, .day-selector .step, .banner .link, .toast .link { position: relative; }
.chip::before, .freshness::before, .audit-strip a::before, .banner .link::before, .toast .link::before { content: ""; position: absolute; inset-block: -6px; inset-inline: 0; }
.th-sort::before { content: ""; position: absolute; inset-block: -8px; inset-inline: 0; }
.segmented button { position: relative; }
.segmented button::before { content: ""; position: absolute; inset-block: -3px; inset-inline: 0; }
.switch::before { content: ""; position: absolute; inset-block: -8px; inset-inline: -4px; }
.day-selector .step::before { content: ""; position: absolute; inset-block: -4px; inset-inline: -2px; }

/* ---------- 6. help (T-20261021-01 H2.1, the help-docs track; the owner's yes at stop 1) ----------
   .help      the text of one help section (the help build allows only these tags: h2, h3, p, ul, ol, li, strong, a, bdi, span, div, dl, dt,
              dd, table, thead, tbody, tr, th, td, figure, figcaption, svg, use — and the kit's class names); it is the page's own grid
   .help-card a number card: a .card whose fields are one dl of dt / dd rows (a .kv value is 18 px and one line, so the card does not use it)
   .help-rows a table of 3 columns or more (2026-10-22, the owner's choice at stop 3: "Rows as cards"): one dl per row, each cell a dt (the
              column title) / dd pair, so a phone never scrolls sideways; a table of 2 columns stays a .table
   .help-note the "Different from the ERP?" block and the help's other notes: an i-info icon + text on --fill (neutral: the status colors
              stay reserved and gold stays chrome — CONVENTIONS §8) */
.help { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); }
.help h2 { font-size: var(--fs-section); font-weight: var(--fw-semibold); line-height: var(--lh-tight); margin-block-start: var(--sp-3); }
.help h3 { font-size: var(--fs-body); font-weight: var(--fw-semibold); }
.help > :first-child { margin-block-start: 0; }
.help ul, .help ol { margin: 0; padding-inline-start: var(--sp-5); display: grid; gap: var(--sp-1); }
.help li::marker { color: var(--t3); }
.help strong { font-weight: var(--fw-semibold); }
/* a link inside a line of text is underlined (color is never the only mark); a link row (.list-row) keeps its own look */
.help p a, .help li a, .help dd a, .help-note a { text-decoration: underline; text-underline-offset: 2px; font-weight: var(--fw-medium); }
/* an icon inside a line of text ("Tap ? at the top", the cloud and bolt marks): in the line, not on its own line (svg is a block in section 0) */
.help :is(p, li, dd, td) > .icon-sm { display: inline-block; vertical-align: -3px; }
.help .num { white-space: nowrap; }   /* a time, a count or a percent stays on one line ("10:00 ص"; T-20261021-01 review H3 r1b Minor 7) */
.help figure { margin: 0; display: grid; gap: var(--sp-2); }
.help figcaption { font-size: var(--fs-support); color: var(--t3); }
.help .table th, .help .table td { white-space: normal; }   /* a help table holds words: every column wraps */
.help-card { gap: var(--sp-3); }
.help-card dl { margin: 0; display: grid; gap: var(--sp-3); }
.help-card dl > div { display: grid; gap: 2px; }
.help-card dt { font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--t2); }
.help-card dd { margin: 0; }
.help-rows { display: grid; gap: var(--sp-2); }
.help-rows > dl { margin: 0; display: grid; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); background: var(--card); border: 1px solid var(--line); border-radius: var(--r-ctl); }
.help-rows > dl > div { display: grid; gap: 2px; min-width: 0; }
.help-rows dt { font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--t2); }
.help-rows dd { margin: 0; overflow-wrap: anywhere; }
/* an anchor target (/help/<section>#<card>) stops under the sticky header, not behind it */
.help [id] { scroll-margin-block-start: calc(var(--kit-top, 0px) + var(--tap) + var(--sp-4) + var(--safe-t) + var(--sp-3)); }
.help-note { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-2); align-items: start; padding: var(--sp-3); border-radius: var(--r-ctl); background: var(--fill); color: var(--t1); }
.help-note > .icon-sm { margin-block-start: 2px; color: var(--t2); }
.help-note > div { display: grid; gap: var(--sp-1); min-width: 0; }

/* ---------- 7. helpers used by the kit pages only ---------- */
.frame-note { font-size: var(--fs-support); color: var(--t3); }
