/* TGT Work: the one stylesheet of every page.

   It has four parts, in this order (redesign W1, docs/superpowers/specs/2026-10-26-tgt-work-redesign-map.md §5):
   1. The W1 foundation: tokens, base, the shells, the shared components and the legacy aliases (owned by W1 only).
   2. Legacy shared rules that more than one area's pages use, restyled by the tokens (owned by W1).
   3. One fenced section per wave, between "===== Wn ... (owned by Wn) =====" and "===== end Wn =====": the rules of
      that wave's pages, moved here unchanged. A wave edits only inside its own fence and never touches parts 1, 2, 4.
   4. The W1 tail: print and reduced motion, last so that they win.

   The look is the owner's approved "dashboard look" (Oct 2026): a grey-green canvas with white cards (radius 18, a
   1px line), the deep factory green of the hero for the one live thing per screen, brand green for start, amber as
   the one "now" accent, status pills in words, Sarabun for every Thai and Latin role (R-UX-25, 27 Oct 2569), and
   Noto Sans Myanmar for Burmese. Every colour that means something comes with words. */

/* ===== W1 foundation (owned by W1) ===== */

/* --- 1.1 Tokens (§2.1) --------------------------------------------------------------------------------------- */
:root {
  /* Surfaces and text */
  --canvas: #e7e9e6; /* the grey desk the cards sit on, a touch of green */
  --card: #ffffff;
  --ink: #141816;
  --muted: #5c6661; /* AA on canvas (4.87:1), soft grey (5.38:1), and white cards (5.95:1). */
  --muted-2: #5c6661; /* muted words straight on the canvas or on the soft grey (4.9:1 there) */
  --line: #e3e7e4;
  --line-strong: #c5ccc8; /* a dashed separator, the edge of a quiet box */
  --ctl-line: #8c958f; /* the edge of a field or an outline button: 3:1 on white */
  --soft: #f2f4f2;

  /* Brand: the official colours of TGT Metalworks (logo pack, guide p3; R-UX-18) */
  --hero: #154b40; /* PMS 567 C: the one dark surface; white on it 9.9:1 */
  --hero-2: #0c6854; /* where the hero's gradient starts: the brand */
  --brand: #0c6854; /* PMS 336 C, the green of the logo: 6.72:1 against white, white on it 6.72:1 */
  --brand-deep: #0a5747; /* the brand pressed, and the end of the app bar's gradient: white on it 8.5:1 */
  --amber: #faa819; /* PMS 2010 C, the yellow of the logo: the one "now" accent, never words on white */
  --amber-deep: #dc831a; /* PMS 7565 C: amber's shade, for a pressed amber edge; never words on white either */

  /* Status: each always next to its words */
  --late: #b42318;
  --late-bg: #fdecea;
  --warn: #8a5a00;
  --warn-bg: #fff3d1;
  --ok: #1f7a3d;
  --ok-bg: #e5f3e9;
  --idle: #5d6762;
  --idle-bg: #eceeec;

  /* Focus rings only (blue is no action colour any more: D2) */
  --focus: #1d4ed8;
  --selection: #cfe6da;
  --scrollbar: #b3bcb7;

  /* Radii, type, sizes */
  --r-card: 18px;
  --r-ctl: 12px;
  --r-pill: 999px;
  --font-display: "Sarabun", "Noto Sans Myanmar", "Noto Sans Thai", system-ui, sans-serif;
  --font: "Sarabun", "Noto Sans Myanmar", "Noto Sans Thai", system-ui, sans-serif;
  --btn-h: 48px; /* a phone; 40 on a desk, 64 on the floor */
  --btn-h-big: 64px;
  --body-fs: 17px;
  --body-lh: 1.6; /* room for Thai tone marks at the larger Sarabun body size */
  --btn-fs: var(--body-fs);
  --btn-lh: 1.4;
  --btn-fw: 600;
  --side-w: 248px;
  --bar-h: 56px;
  /* The bar at the bottom of a phone (_shell/tabbar.html) as it is drawn in Thai: 70px (measured at 360 and 390 for
     every demo account), never less (.app-shell .m-tabbar below); taller in Burmese and English (:lang below). Its
     raised scan button stands 15px above it: whatever sits right above the bar keeps --tabbar-rise clear of it. */
  --tabbar-h: 70px;
  --tabbar-rise: 16px;
  --pop-shadow: 0 12px 32px rgba(18, 38, 30, 0.18), 0 2px 6px rgba(18, 38, 30, 0.08);

  /* LINE's own green, kept for the buttons that go to LINE (R-UX-7, the owner's ruling) */
  --line-green: #06c755;
  --line-green-press: #048b3b;

  /* Legacy aliases: the names the pages of before the redesign use, so that every one of them takes the new look
     with no change of its own (§2.1). A wave that rebuilds its pages moves to the new names. */
  --bg: var(--canvas);
  --surface: var(--card);
  --ink-2: var(--muted-2); /* legacy muted words sit on a card or straight on the canvas: 4.8:1 or more on both */
  --ink-3: #8a938e; /* chevrons and separators */
  --go: var(--brand); /* start */
  --go-press: var(--brand-deep);
  --send: var(--hero); /* hand off, confirm, save (R-UX-1) */
  --send-press: #113c33;
  --help: var(--warn); /* ask for help */
  --help-line: var(--amber);
  --help-bg: var(--warn-bg);
  --today: var(--warn); /* due today */
  --today-bg: var(--warn-bg);
  --chip-bg: var(--soft);
  --row-press: var(--soft);
  --run-bg: #f1f7f3; /* the row, or the option, that is in use */
  --run-soft: var(--ok-bg); /* the clock chip and the status of a step that is running */
  --run-ink: var(--ok);
  --run-deep: #155d2f;
  --app-bg: var(--canvas);
  --brand-amber: var(--amber);
  --font-head: var(--font-display);
}
:root:lang(my) {
  --font: "Noto Sans Myanmar", "Sarabun", "Noto Sans Thai", system-ui, sans-serif;
  --font-display: "Noto Sans Myanmar", "Sarabun", "Noto Sans Thai", system-ui, sans-serif;
  --btn-lh: 1.6;
}
/* Burmese lines are taller (line-height 1.8), and English labels of the bar take two lines: the bar is 77px there. */
:root:lang(my), :root:lang(en) { --tabbar-h: 77px; }

/* The dark tokens are written but not switched on before the trial (D9, R-UX-6): nothing sets data-theme="dark". */
:root[data-theme="dark"] {
  --canvas: #0f1311; --card: #181d1b; --ink: #e8ece9; --muted: #98a39d; --muted-2: #a8b2ad; --line: #29302d;
  --line-strong: #3a4541; --ctl-line: #5b6762; --soft: #202624; --hero: #0b1a14; --hero-2: #17402f;
  --late: #ff8a7a; --late-bg: #3a1d1a; --warn: #f3c96a; --warn-bg: #3a2f14; --ok: #7fd197; --ok-bg: #18301f;
  --idle: #a8b2ad; --idle-bg: #262d2a; --selection: #2b4a3c;
  color-scheme: dark;
}

/* --- 1.2 Base ------------------------------------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
* { scrollbar-width: thin; scrollbar-color: var(--scrollbar) transparent; }
::selection { background: var(--selection); color: var(--ink); }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
[x-cloak] { display: none !important; } /* Alpine hides these until it has started */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--body-fs);
  line-height: var(--body-lh);
  font-variant-numeric: tabular-nums;
}
/* Burmese stacks marks above and below the line and keeps its established spacing. */
body:lang(my) { line-height: 1.8; }
@media (min-width: 1024px) {
  :root { --btn-h: 40px; --body-fs: 16px; }
}
a { color: var(--brand); text-decoration-thickness: 1.5px; text-underline-offset: 3px; }
h1, h2, h3 { text-wrap: balance; }
button, input, select, textarea, ::file-selector-button { font-family: var(--font); }
code, kbd, samp, pre { font-family: var(--font); }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* The icon sheet (home/_icons.html) is an <svg hidden>: [hidden] hides an HTML element but not an SVG one. */
svg[hidden] { display: none; }

/* --- 1.3 Icons: one stroke set (home/_icons.html), used as {{ icon("name") }} (.m-ico is the mobile home's) ------ */
.ico {
  flex: none; width: 20px; height: 20px;
  fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.ico-sm { width: 16px; height: 16px; }
.ico-lg { width: 28px; height: 28px; }

/* --- 1.4 Buttons (D2: one action vocabulary). Use on <button> and on <a>. -------------------------------------
   primary = hero dark, for commit (save, confirm, hand off, open); go = brand green, for start; help = amber outline;
   outline = secondary; text = quiet; danger = late-red outline; line = LINE's own green. One primary per screen. */
.btn {
  -webkit-appearance: none; appearance: none; display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: var(--btn-h); margin: 0; padding: 6px 18px;
  border-radius: var(--r-ctl); border: 2px solid transparent;
  font: inherit; font-weight: var(--btn-fw); font-size: var(--btn-fs); line-height: var(--btn-lh); text-align: center;
  text-decoration: none; cursor: pointer;
  transition: background-color 150ms ease-out, border-color 150ms ease-out, transform 120ms ease-out;
}
.btn:active { transform: scale(0.985); }
.btn[disabled] { cursor: default; opacity: 0.55; transform: none; }
.btn.is-off { cursor: default; opacity: 0.55; pointer-events: none; }
.btn .ico { width: 18px; height: 18px; }
.btn-big { min-height: var(--btn-h-big); font-size: 20px; }
.btn-primary { background: var(--hero); color: #ffffff; }
.btn-primary:hover { background: #18564a; }
.btn-primary:active { background: var(--send-press); }
.btn-go { background: var(--go); color: #ffffff; }
.btn-go:hover { background: #0b604e; }
.btn-go:active { background: var(--go-press); }
/* Legacy: hand off and confirm (.btn-send) are the primary (R-UX-1), an outline (.btn-plain) is .btn-outline. */
.btn-send { background: var(--send); color: #ffffff; }
.btn-send:hover { background: #18564a; }
.btn-send:active { background: var(--send-press); }
.btn-help { background: var(--help-bg); border-color: var(--help-line); color: var(--help); }
.btn-help:active { background: #ffe9ad; border-color: var(--amber-deep); }
.btn-outline, .btn-plain { background: var(--card); border-color: var(--ctl-line); color: var(--ink); }
.btn-outline:hover, .btn-plain:hover { background: var(--soft); }
.btn-text { min-height: 48px; background: transparent; color: var(--ink-2); font-weight: 600; font-size: 16px; }
.btn-text:hover { color: var(--ink); background: var(--soft); }
.btn-danger { background: var(--card); border-color: var(--late); color: var(--late); }
.btn-danger:hover { background: var(--late-bg); }
/* QC's stamp on an item (the first piece passed, a repair passed): an outline in the green of the floor with green words
   and a tick before them, on white, so that the dock's filled button stays the one main button of the screen. */
.btn-stamp { background: var(--surface); border-color: var(--go); color: var(--go); }
.btn-stamp:active { background: var(--run-bg); }
/* A button that goes to LINE: LINE's green with bold white words, never under 48px (R-UX-7). */
.btn-line { background: var(--line-green); border-color: var(--line-green); color: #fff; font-size: 19px; font-weight: 700; min-height: max(48px, var(--btn-h)); }
.btn-line:active { background: var(--line-green-press); border-color: var(--line-green-press); }
/* A button inside a table row or a toolbar, and a square one for an icon alone (its words in .sr-only) */
.btn-sm { min-width: 0; min-height: 44px; padding: 6px 14px; font-size: 15px; }
.btn-icon { width: 44px; min-width: 44px; min-height: 44px; padding: 0; }
/* A button as wide as its text, for forms and page headers on a wide screen */
.btn-auto { width: auto; min-width: 160px; }
@media (min-width: 1024px) {
  .btn-sm { min-height: 40px; font-size: 14px; border-radius: 10px; }
  .btn-icon { width: 40px; min-width: 40px; min-height: 40px; }
  .btn-auto { min-width: 0; }
}
/* The floor and the mobile home keep their gloved sizes: 64px, bold 18px words (owner, 22 Oct 2026). */
:where(.is-floor, .sf-screen, .m-home) { --btn-h: 64px; --btn-h-big: 66px; --btn-fs: 18px; --btn-fw: 700; }

/* --- 1.5 The app shell (§1.1): one DOM, desk and phone switched at 1024 px ---------------------------------------- */
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 100; padding: 10px 16px; border-radius: var(--r-ctl);
  background: var(--hero); color: #ffffff; font-weight: 600; text-decoration: none;
}
.skip-link:focus { top: 8px; }
.app-shell { min-height: 100vh; min-height: 100dvh; }
.app-main { min-width: 0; }

/* Phone: the white app bar (56px) with a green rule: the full-colour logo (R-UX-26), or a back chevron and a
   title on a task page; a station device's station in the logo's place. Its right end is kept for the bell and the
   account button (.app-top, R-UX-16), which sit on it. */
.app-bar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; gap: 6px; min-height: calc(var(--bar-h) + env(safe-area-inset-top));
  padding: env(safe-area-inset-top) max(10px, env(safe-area-inset-right)) 0 max(14px, env(safe-area-inset-left));
  border-bottom: 3px solid var(--brand); background: var(--card); color: var(--ink);
}
.app-bar :focus-visible { outline-color: var(--focus); }
/* The logo is used as it is, with its clear space around it (the guide's usage page). */
.app-brand {
  display: inline-flex; align-items: center; min-height: 44px; margin-right: auto; padding: 4px 2px; color: inherit;
  text-decoration: none;
}
.app-logo { display: block; width: auto; height: 24px; }
.app-bar-back {
  display: inline-flex; align-items: center; gap: 2px; min-height: 44px; margin-left: -8px; padding: 0 10px 0 4px;
  border-radius: var(--r-ctl); color: inherit; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.app-bar-back .ico { width: 24px; height: 24px; }
.is-task .app-bar-back ~ .app-brand { display: none; } /* a task page says where back leads, not the name of the app */
.app-bar-title {
  flex: 1; min-width: 0; margin: 0; overflow: hidden; font-family: var(--font-display); font-size: 18px; font-weight: 700;
  text-overflow: ellipsis; white-space: nowrap;
}
/* A station device's station: in the logo's place on a list page, its name alone, on two lines when it must (UX-5). */
.app-bar-chip {
  flex: 0 1 auto; min-width: 0; padding: 4px 12px; border-radius: 12px; background: var(--soft);
  font-size: 14px; font-weight: 600; line-height: 1.3; overflow-wrap: break-word;
}
.app-bar-chip > [aria-hidden] { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.is-device.is-list > .app-bar > .app-brand { display: none; }
.is-device.is-list > .app-bar > .app-bar-chip { margin-right: auto; }
.app-bar .side-nav { display: none; }
.app-bar-bell {
  position: relative; display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px;
  border-radius: var(--r-pill); color: inherit;
}
.app-bar-bell .ico { width: 22px; height: 22px; }
.app-bar-badge {
  position: absolute; top: 2px; right: 0; display: grid; place-items: center; min-width: 20px; height: 20px;
  padding: 0 5px; border: 2px solid #ffffff; border-radius: 10px; background: var(--late); color: #ffffff;
  font-size: 11px; font-weight: 700; line-height: 1;
}
/* The bar at the bottom (_shell/tabbar.html, in the look of the mobile home's .m-tabbar) is never shorter than
   --tabbar-h, so that what is laid out against it can count on the token: the room the shell keeps under a page, a
   dock, a toast. */
.app-shell .m-tabbar { min-height: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); }
/* Room at the bottom for the bar that is fixed there, its raised scan button included; a sticky dock of a floor list
   page sits right on top of the bar, its buttons --tabbar-rise clear of the scan button (whose ring overlaps only the
   dock's own white foot). */
@media (max-width: 1023.98px) {
  .app-shell { position: relative; }
  .app-shell > .app-bar { padding-right: calc(58px + max(8px, env(safe-area-inset-right))); }
  .app-shell.has-bell > .app-bar { padding-right: calc(106px + max(8px, env(safe-area-inset-right))); }
  .app-shell.has-tabbar { padding-bottom: calc(var(--tabbar-h) + var(--tabbar-rise) + env(safe-area-inset-bottom)); }
  .app-shell.has-tabbar .sf-dock {
    bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); padding-bottom: calc(12px + var(--tabbar-rise));
  }
  .app-shell.has-tabbar .sf-screen {
    min-height: calc(100vh - var(--bar-h) - var(--tabbar-h));
    min-height: calc(100dvh - var(--bar-h) - var(--tabbar-h) - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  }
  .is-home > .app-bar { display: none; } /* the mobile home draws its own green header (home/_mobile.html) */
  .me-logout { padding: 8px 16px 24px; }
  .me-logout .logout-form { max-width: 560px; margin: 0 auto; }
  /* A floor task page names its job in the app bar (back, the job number): its own header is left to a screen reader
     until W2 gives the job its hero (UX-3), and its back link, which the app bar has, goes. */
  .is-task .sf-top {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0);
    border: 0; white-space: nowrap;
  }
  .is-task .sf-top .sf-back { display: none; }
  /* A station device's task page names its job and its station: the way back is its chevron alone there, a 44px
     square. */
  .is-device.is-task .app-bar-back { justify-content: center; min-width: 44px; padding: 0; }
  .is-device.is-task .app-bar-title { flex: 0 0 auto; }
  .is-device.is-task .app-bar-back > span {
    position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }
}

/* Desk: the white column of the side menu on the left, as tall as the window and sticky: the logo on top, the menu
   under it with a scroll of its own. The page beside it, under a slim row with the bell and the account button
   (.app-top). The shell paints the column's white down the whole page, so that it never ends under a long page. */
@media (min-width: 1024px) {
  .app-shell {
    display: grid; grid-template-columns: var(--side-w) minmax(0, 1fr); align-items: start;
    background: linear-gradient(90deg, var(--card) 0 calc(var(--side-w) - 1px), var(--line) calc(var(--side-w) - 1px) var(--side-w), transparent var(--side-w));
  }
  .app-bar {
    grid-column: 1; grid-row: 1 / span 3; position: sticky; top: 0; flex-direction: column; align-items: stretch;
    gap: 4px; height: 100vh; height: 100dvh; min-height: 0; padding: 18px 12px 14px; overflow: hidden;
    border-right: 1px solid var(--line); border-bottom: 0; background: var(--card); color: var(--ink);
  }
  .app-bar :focus-visible { outline-color: var(--focus); }
  .app-bar .app-brand { flex: none; align-self: flex-start; margin: 0 0 14px; padding: 6px 10px; }
  .app-bar .app-logo { height: 32px; }
  /* The column has the menu, so the phone's parts of the app bar go; the print bar keeps its way back. */
  .app-bar :is(.app-bar-back, .app-bar-title, .app-bar-chip, .app-bar-bell) { display: none; }
  .is-task .app-bar-back ~ .app-brand, .is-device.is-list > .app-bar > .app-brand { display: inline-flex; }
  .app-bar .side-nav { display: grid; flex: 1 1 auto; align-content: start; min-height: 0; overflow-y: auto; overscroll-behavior: contain; margin: 0 -6px; padding: 0 6px 8px; }
  .app-main { grid-column: 2; grid-row: 2; }
  .app-shell > .m-tabbar, .me-logout { display: none; }
}

/* The side menu: rows of 44px with an icon, the current page the dark hero pill, a red count where something waits. */
.side-nav { display: grid; gap: 14px; }
.nav-group ul { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
.nav-group-title {
  display: flex; align-items: center; justify-content: space-between; margin: 0 0 4px; padding: 0 10px;
  color: var(--ink-2); font-size: 12px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
}
.side-nav a {
  display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 8px 10px;
  border-radius: 10px; color: var(--ink); font-size: 14px; font-weight: 500; text-decoration: none; overflow-wrap: anywhere;
}
.side-nav a .ico { opacity: 0.75; }
.side-nav a:hover { background: var(--soft); }
.side-nav a[aria-current="page"] { background: var(--hero); color: #ffffff; font-weight: 700; }
.side-nav a[aria-current="page"] .ico { opacity: 1; }
.side-nav-label { flex: 1; min-width: 0; }
.side-nav-badge {
  flex: none; min-width: 22px; padding: 1px 7px; border-radius: var(--r-pill); background: var(--late); color: #ffffff;
  font-size: 12px; font-weight: 700; line-height: 1.5; text-align: center;
}
@media (min-width: 1024px) { .side-nav a { min-height: 40px; padding: 6px 10px; } } /* a mouse's target (§5: 40 on a desk) */
.nav-fold > summary { min-height: 40px; cursor: pointer; list-style: none; }
.nav-fold > summary::-webkit-details-marker { display: none; }
.nav-fold-mark { transition: transform 150ms ease-out; }
.nav-fold[open] .nav-fold-mark { transform: rotate(180deg); }

/* The row of sibling pages under the app bar on a phone (D4): chips that scroll sideways, the current one dark. */
.section-switch {
  display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none;
  padding: 12px max(16px, env(safe-area-inset-right)) 2px max(16px, env(safe-area-inset-left));
}
.section-switch::-webkit-scrollbar { display: none; }
.section-switch a {
  flex: none; display: inline-flex; align-items: center; min-height: 44px; padding: 0 16px;
  border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--card); color: var(--ink);
  font-size: 14px; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.section-switch a[aria-current="page"] { border-color: var(--hero); background: var(--hero); color: #ffffff; }
@media (min-width: 1024px) { .section-switch { display: none; } } /* the side menu lists the same pages there */

/* The language switch (_lang_switcher.html): a row for each language, its round flag and its name in its own script,
   a tick on the page's (R-UX-16). The compact picker of the way in and the paper is the page's flag and language in a
   pill, over the same rows. */
.lang-switch { display: grid; gap: 2px; margin: 0; }
.lang-switch button {
  -webkit-appearance: none; appearance: none;
  display: flex; align-items: center; gap: 12px; width: 100%; min-width: 44px; min-height: 44px; padding: 0 12px;
  border: 0; border-radius: 10px; background: transparent; color: var(--ink);
  font: inherit; font-size: 15px; font-weight: 600; line-height: 1.3; text-align: left; cursor: pointer;
}
.lang-switch button:hover { background: var(--soft); }
.lang-switch button[aria-current="true"] { color: var(--brand-deep); }
.lang-name { flex: 1; min-width: 0; }
.lang-check { flex: none; width: 20px; height: 20px; color: var(--brand); stroke-width: 2.5; }
/* A flag of the icon set: round in its own drawing, and clipped round here too, so no corner of a band ever shows. */
.flag { flex: none; width: 24px; height: 24px; border-radius: 50%; clip-path: circle(50%); }
.lang-picker { position: relative; }
.lang-picker-button {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 12px 0 8px;
  border: 1px solid rgba(255, 255, 255, 0.36); border-radius: var(--r-pill); background: rgba(255, 255, 255, 0.12);
  color: inherit; font-size: 15px; font-weight: 600; cursor: pointer; list-style: none; white-space: nowrap;
  -webkit-user-select: none; user-select: none;
}
.lang-picker-button::-webkit-details-marker { display: none; }
.lang-picker-button .flag { width: 22px; height: 22px; }
.lang-picker-mark { transition: transform 150ms ease-out; }
.lang-picker[open] .lang-picker-mark { transform: rotate(180deg); }
.lang-picker[open] > summary::before { content: ""; position: fixed; inset: 0; z-index: 39; cursor: default; }
.lang-picker-panel {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 40; min-width: 216px; padding: 6px;
  border-radius: 14px; background: var(--card); box-shadow: var(--pop-shadow); color: var(--ink);
}

/* The bell and the account button (_shell/account.html, R-UX-16): on a phone they sit on the right of the white app
   bar (fixed with it; over the mobile home's own header there, which scrolls); on a desk they are a slim row over the
   page, on the right. The account button opens the account menu: a card under it on a desk, a sheet from the bottom
   on a phone. The button's own layer (summary::before) lies under the open menu over the whole screen, so that a
   press anywhere else closes it, with no script; on a phone it dims the page. */
.app-top { display: flex; align-items: center; gap: 4px; }
.acct { position: relative; }
.acct > summary { list-style: none; cursor: pointer; -webkit-user-select: none; user-select: none; }
.acct > summary::-webkit-details-marker { display: none; }
.acct[open] > summary::before { content: ""; position: fixed; inset: 0; z-index: 1; cursor: default; }
.acct-button { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; border-radius: var(--r-pill); }
.acct-avatar { display: grid; flex: none; place-items: center; width: 36px; height: 36px; border-radius: 50%; }
.acct-avatar .ico { width: 20px; height: 20px; }
.acct-mark { transition: transform 150ms ease-out; }
.acct[open] .acct-mark { transform: rotate(180deg); }
.acct-menu { z-index: 2; display: grid; gap: 2px; background: var(--card); color: var(--ink); }
.acct-who { margin: 0; overflow-wrap: break-word; }
.acct-head { display: flex; align-items: center; gap: 8px; margin: 0; color: var(--muted-2); font-size: 13px; font-weight: 600; }
.acct-row {
  -webkit-appearance: none; appearance: none;
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 44px; margin: 0; padding: 0 12px;
  border: 0; border-radius: 10px; background: transparent; color: var(--ink);
  font: inherit; font-size: 15px; font-weight: 500; line-height: 1.3; text-align: left; text-decoration: none; cursor: pointer;
}
.acct-row:hover { background: var(--soft); }
.acct-row > .ico { color: var(--muted-2); }
.acct-row-end { margin-left: auto; }
.acct-row[aria-current="page"] { font-weight: 700; }
.acct-row[aria-current="page"] > .ico { color: var(--brand); }
.acct-lang > summary { list-style: none; }
.acct-lang > summary::-webkit-details-marker { display: none; }
.acct-menu .logout-form { margin: 4px 0 0; padding-top: 4px; border-top: 1px solid var(--line); }
@media (max-width: 1023.98px) {
  .app-top {
    position: fixed; top: 0; right: 0; z-index: 31; height: calc(var(--bar-h) + env(safe-area-inset-top));
    padding: env(safe-area-inset-top) max(8px, env(safe-area-inset-right)) 0 0; color: var(--ink);
  }
  /* The mobile home's header scrolls away with the page: there the buttons sit on its first row and go with it, in the
     space beside the logo reserved by home/_mobile.html. */
  .is-home > .app-top {
    position: absolute; top: calc(10px + env(safe-area-inset-top)); right: max(20px, env(safe-area-inset-right));
    height: 48px; padding: 0;
  }
  .app-top > .app-bar-bell:focus-visible, .app-top .acct-button:focus-visible { outline-color: var(--focus); }
  .acct-button { justify-content: center; width: 44px; }
  .acct-avatar { border: 1.5px solid var(--brand); background: var(--soft); color: var(--brand-deep); }
  .acct.is-current .acct-avatar, .acct[open] .acct-avatar { border-color: var(--brand); background: var(--brand); color: #ffffff; }
  .acct-label { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .acct-mark { display: none; }
  .acct[open] > summary::before { background: rgba(18, 38, 30, 0.45); }
  :root:has(.acct[open]) { overflow: hidden; } /* the page under the sheet stays where it is */
  .acct-menu {
    position: fixed; right: 0; bottom: 0; left: 0; max-height: 85vh; max-height: 85dvh; overflow-y: auto;
    overscroll-behavior: contain;
    padding: 18px max(16px, env(safe-area-inset-right)) calc(16px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
    border-radius: 22px 22px 0 0; box-shadow: 0 -12px 32px rgba(18, 38, 30, 0.2);
  }
  .acct-who { padding: 0 12px 10px; font-family: var(--font-display); font-size: 19px; font-weight: 700; line-height: 1.35; }
  .acct-head { padding: 8px 12px 4px; }
  .acct-lang > summary { display: none; } /* no submenu on a phone: the languages are listed in the sheet */
  .acct-menu .lang-switch { margin-bottom: 6px; }
  .acct-menu .lang-switch button { min-height: 56px; font-size: 17px; }
  .acct-menu .flag { width: 28px; height: 28px; }
  .acct-menu .acct-row { min-height: 52px; font-size: 16px; }
  .acct-menu .acct-row > .ico { margin-inline: 4px; } /* in the column of the flags */
  .acct-menu .logout-form { margin-top: 6px; padding-top: 6px; }
}
@media (min-width: 1024px) {
  .app-top {
    grid-column: 2; grid-row: 1; position: relative; z-index: 40; justify-content: flex-end; gap: 8px;
    padding: 8px 28px 0; color: var(--ink);
  }
  .app-top + .app-main > .admin, .app-top + .section-switch + .app-main > .admin { padding-top: 4px; }
  .app-bar-bell { width: 40px; height: 40px; }
  .app-bar-bell:hover { background: var(--card); }
  .app-bar-badge { border-color: var(--canvas); }
  .acct-button {
    max-width: 320px; min-height: 42px; padding: 3px 12px 3px 3px; border: 1px solid var(--line); background: var(--card);
    color: var(--ink); font-size: 14px; font-weight: 600;
  }
  .acct-button:hover, .acct[open] > .acct-button { border-color: var(--ctl-line); }
  .acct-avatar { width: 34px; height: 34px; background: var(--soft); color: var(--muted-2); }
  .acct.is-current .acct-avatar { background: var(--hero); color: #ffffff; }
  .acct-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .acct-menu {
    position: absolute; top: calc(100% + 8px); right: 0; min-width: 248px; padding: 6px;
    border-radius: 14px; box-shadow: var(--pop-shadow);
  }
  .acct-who, .acct-lang-head { display: none; }
  .acct-menu > .acct-head { padding: 6px 12px 4px; } /* a device's menu: the languages under their heading */
  .acct-lang { position: relative; }
  .acct-lang[open] > summary { background: var(--soft); font-weight: 600; }
  .acct-lang[open] > summary .acct-row-end { color: var(--ink); }
  .acct-flyout {
    position: absolute; top: -6px; right: calc(100% + 10px); min-width: 216px; padding: 6px;
    border-radius: 14px; background: var(--card); box-shadow: var(--pop-shadow);
  }
}

/* The no-signal bar of the floor (from .sf-offline), for every shell: in sight while the buttons are off. */
.offline-bar {
  position: sticky; top: 0; z-index: 10; margin: 0; padding: 10px 16px;
  border-bottom: 1px solid var(--amber); background: var(--warn-bg); color: var(--warn); font-weight: 600;
}
@media (max-width: 1023.98px) { .app-shell .offline-bar { top: calc(var(--bar-h) + env(safe-area-inset-top)); } }

/* The fixed strip of the fake LINE's pages of a local trial (dev/*) */
.dev-banner {
  position: sticky; top: 0; z-index: 35; margin: 0; padding: 8px 16px; background: var(--hero); color: #ffffff;
  font-size: 14px; font-weight: 600; text-align: center;
}

/* --- 1.6 The shells with no menu: auth (the way in), dev, print -------------------------------------------------- */
/* One content-sized card and its legal footer, centred as a group on an uninterrupted canvas.
   The corner controls stay in flow. The stage balances their 44px height plus edge spacing below the group,
   and falls back to 24px below the controls when content is too tall to centre. */
.auth-shell {
  --btn-h: 48px; --auth-edge: 16px;
  position: relative; display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh;
  background: var(--canvas);
}
.auth-shell::before { content: ""; position: absolute; top: 0; right: 0; left: 0; height: 4px; background: var(--brand); z-index: 60; }
.auth-tools {
  display: flex; flex: none; justify-content: flex-end;
  padding: max(var(--auth-edge), env(safe-area-inset-top)) max(var(--auth-edge), env(safe-area-inset-right)) 0 max(var(--auth-edge), env(safe-area-inset-left));
}
.auth-tools .lang-picker-button { display: flex; min-height: 44px; border-color: var(--ctl-line); background: var(--card); color: var(--ink); }
.auth-tools .lang-picker-button:hover { background: var(--soft); }
.auth-tools :focus-visible { outline-color: var(--focus); }
.auth-stage {
  display: flex; flex: 1 0 auto; flex-direction: column; justify-content: center; min-width: 0;
  padding: 24px max(16px, env(safe-area-inset-right)) calc(24px + var(--auth-edge) + 44px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
}
.auth-group { width: 100%; max-width: 420px; min-width: 0; margin: 0 auto; }
.auth-main {
  padding: 24px; border-radius: var(--r-card); background: var(--card);
  box-shadow: 0 8px 28px rgba(18, 38, 30, 0.08), 0 2px 6px rgba(18, 38, 30, 0.04);
}
.auth-band {
  margin-bottom: 24px; padding-bottom: 24px; border-bottom: 1px solid var(--line);
  background: var(--card); color: var(--ink); text-align: center;
}
.auth-band :focus-visible { outline-color: var(--focus); }
.auth-band .app-brand { flex-direction: column; align-items: center; gap: 0; width: 100%; margin: 0; padding: 0; }
.auth-band .app-logo { width: 192px; max-width: 100%; height: auto; }
.auth-product-name { margin-top: 12px; color: var(--hero); font-family: var(--font-display); font-size: 28px; font-weight: 700; line-height: 1.3; }
.auth-tagline { margin-top: 4px; color: var(--muted-2); font-size: 16px; font-weight: 400; line-height: 1.6; }
.auth-tagline:lang(my) { line-height: 1.8; }
.auth-main > .page-narrow { display: flex; flex-direction: column; min-width: 0; max-width: none; margin: 0; padding: 0; }
.auth-footer { margin-top: 24px; color: var(--muted-2); font-size: 14px; line-height: 1.7; text-align: center; }
.auth-footer p { margin: 0; text-wrap: balance; }
@media (min-width: 1024px) {
  .auth-shell { --auth-edge: 24px; }
  .auth-main { padding: 32px; }
}
/* Keep LINE's recognisable green, with AA text and a visible control edge (owner's login polish, 27 Oct 2569).
   White on #06c755 was only 2.26:1. Ink is 7.94:1; the pressed brand green uses white at 8.51:1. */
.auth-shell .btn-line { color: #141816; border-color: var(--brand-deep); }
.auth-shell .btn-line:active { background: var(--brand-deep); color: #ffffff; }
.auth-shell input:not([type="hidden"]), .auth-shell select, .auth-shell .btn { min-height: 48px; }
.auth-shell .btn-big { min-height: var(--btn-h-big); }
.print-shell { min-height: 100vh; }
/* The paper's bar: a slim white toolbar with its 1px line (UX-14), so that the paper's own dark print button stays the
   one dark thing on the screen: back in ink, the logo in its colours, the language picker. */
.print-bar {
  display: flex; align-items: center; gap: 10px; min-height: var(--bar-h); padding: 0 max(12px, env(safe-area-inset-right)) 0 max(12px, env(safe-area-inset-left));
  border-bottom: 1px solid var(--line); background: var(--card); color: var(--ink);
}
.print-bar .app-brand { margin-right: auto; padding: 4px 2px; }
.print-bar .lang-picker-button { border-color: var(--line); background: var(--card); color: var(--ink); }
.print-bar .lang-picker-button:hover { border-color: var(--ctl-line); }

/* --- 1.7 Page structure (§2.2) ------------------------------------------------------------------------------- */
/* A page with one short form or one message (login, errors, scan) */
.page-narrow { max-width: 460px; margin: 0 auto; padding: 24px 16px 40px; }
.page-narrow h1 { margin: 8px 0 16px; font-family: var(--font-head); font-size: 24px; line-height: 1.35; }
.stack { display: grid; gap: 16px; }

/* Admin and office pages (templates/admin/, templates/office/): the wide column of a desk, beside the side menu */
.admin { max-width: 1120px; margin: 0 auto; padding: 8px 16px 48px; }
@media (min-width: 1024px) { .app-main > .admin { max-width: 1280px; margin: 0; padding: 20px 28px 48px; } }
.admin h1 { margin: 12px 0 16px; font-family: var(--font-head); font-size: 24px; line-height: 1.35; }
/* A section heading of the page: any component's own heading (a card's, a sheet's, a form section's) wins over it. */
:where(.admin) h2 { margin: 24px 0 12px; font-family: var(--font-head); font-size: 19px; }

/* The head of a page: a crumb back up, the title, a line under it, at most two actions on the right */
.page-head {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 8px 16px; margin: 4px 0 16px;
}
.page-head h1 { margin: 12px 0; }
.page-head-main { display: grid; gap: 2px; min-width: 0; flex: 1 1 320px; }
.page-head .page-title, .page-title {
  margin: 0; font-family: var(--font-display); font-size: 26px; font-weight: 700; line-height: 1.25; letter-spacing: -0.01em;
}
.page-sub { margin: 0; color: var(--muted-2); font-size: 14px; }
.page-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.page-actions .btn { width: auto; }
.crumb {
  display: inline-flex; align-items: center; gap: 2px; justify-self: start; min-height: 44px; color: var(--muted-2);
  font-size: 13px; font-weight: 600; text-decoration: none;
}
.crumb:hover { color: var(--ink); }

/* Containers. Elevation is the 1px line alone (no shadow under it); cards are never nested. */
.card { display: grid; gap: 12px; min-width: 0; padding: 16px 18px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); }
.card + .card { margin-top: 16px; }
.card-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px; }
.card-head h2, .card-head h3 { margin: 0; font-family: var(--font-display); font-size: 17px; font-weight: 700; }
.card-head .page-sub, .card-sub { color: var(--muted); font-size: 13px; }
.card-body { display: grid; gap: 10px; min-width: 0; }
.card-foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px;
  margin: 4px -18px -16px; padding: 12px 18px; border-top: 1px solid var(--line);
}
.card-flush { padding: 0; overflow: hidden; }
.grid-2 { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); gap: 16px; align-items: start; }
.split { display: grid; grid-template-columns: minmax(260px, 320px) minmax(0, 1fr); gap: 16px; align-items: start; }
@media (max-width: 979.98px) { .grid-2, .split { grid-template-columns: minmax(0, 1fr); } }

/* --- 1.8 Numbers -------------------------------------------------------------------------------------------- */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); gap: 12px; margin: 0 0 16px; }
.kpi {
  display: grid; align-content: start; gap: 2px; min-width: 0; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); color: var(--ink); text-decoration: none;
}
a.kpi { transition: border-color 150ms ease-out; }
a.kpi:hover { border-color: var(--ctl-line); }
a.kpi.is-active { border-color: var(--hero); box-shadow: inset 0 0 0 1px var(--hero); }
.kpi-label { color: var(--muted); font-size: 13px; font-weight: 600; }
.kpi-value { font-family: var(--font-display); font-size: 30px; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
.kpi-note { color: var(--muted); font-size: 12px; }
.kpi-hero { border-color: transparent; background: linear-gradient(150deg, var(--hero-2), var(--hero) 70%); color: #ffffff; }
.kpi-hero .kpi-label, .kpi-hero .kpi-note { color: rgba(255, 255, 255, 0.78); }
.kpi.is-late .kpi-value { color: var(--late); }
.kpi.is-warn .kpi-value { color: var(--warn); }
@media (max-width: 420px) { .kpi-value { font-size: 26px; } }
/* The dark card of the one live thing on a screen (the running job, the bottleneck, the status of a link) */
.hero-card {
  display: grid; gap: 8px; min-width: 0; padding: 16px 18px; border-radius: var(--r-card);
  background: linear-gradient(150deg, var(--hero-2), var(--hero) 70%); color: #ffffff;
}
.hero-card :focus-visible { outline-color: #ffffff; }
.hero-card .page-sub, .hero-card .muted { color: rgba(255, 255, 255, 0.78); }
.mini-tile { display: grid; gap: 1px; min-width: 0; padding: 10px 12px; border-radius: var(--r-ctl); background: var(--soft); }
.mini-tile b { font-family: var(--font-display); font-size: 20px; font-variant-numeric: tabular-nums; }
.mini-tile span { color: var(--muted-2); font-size: 12px; }
.kv { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); gap: 12px 16px; margin: 0; }
.kv > div { display: grid; gap: 2px; min-width: 0; }
.kv dt, .kv-label { color: var(--muted); font-size: 12px; font-weight: 600; }
.kv dd, .kv-value { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
@media (max-width: 719.98px) { .kv { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* --- 1.9 Status: the one vocabulary (pills always carry words) --------------------------------------------------- */
.pill {
  display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px; border-radius: var(--r-pill);
  font-family: var(--font); font-size: 13px; font-weight: 600; line-height: 1.5; white-space: nowrap;
}
:is(h1, h2) :is(.pill, .st) { margin-left: 4px; vertical-align: middle; font-family: var(--font); letter-spacing: 0; }
.pill-late { background: var(--late-bg); color: var(--late); }
.pill-warn { background: var(--warn-bg); color: var(--warn); }
.pill-ok { background: var(--ok-bg); color: var(--ok); }
.pill-dark { background: var(--hero); color: #ffffff; }
.pill-soft { background: var(--soft); color: var(--muted-2); box-shadow: inset 0 0 0 1px var(--line); }
.pill-idle { background: var(--idle-bg); color: var(--idle); }
/* A pill whose words are a sentence in some language wraps within its line (UX-2): the mark of a changed QT is one, so
   a Burmese job page keeps to the phone's width and the QT list's status is never cut. Words break where the script
   breaks them; a word is cut only when it alone is wider than the line. On one line it is still a pill (12px is half
   its height); on two it is a rounded box, not a bubble. */
.pill-wrap, .pill[data-qt-change] { max-width: 100%; border-radius: 12px; white-space: normal; overflow-wrap: break-word; }
.st { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: 13px; white-space: nowrap; }
.st::before { content: ""; flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--line-strong); }
.st-run::before { background: var(--ok); }
.st-wait::before { background: var(--amber); }
.st-late::before { background: var(--late); }
.tag {
  display: inline-block; padding: 1px 8px; border-radius: 8px; background: var(--soft); color: var(--ink);
  font-size: 12px; font-weight: 600; white-space: nowrap;
}
.chip {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 14px;
  border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--card); color: var(--ink);
  font-size: 14px; font-weight: 600; text-decoration: none; white-space: nowrap;
}
a.chip:hover { border-color: var(--ctl-line); }
.chip[aria-current], .chip.is-on { border-color: var(--hero); background: var(--hero); color: #ffffff; }
.chip-count { font-variant-numeric: tabular-nums; }
.id { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.page-title .id, h1 .id { font-family: var(--font-display); }
/* Legacy pill words: a word of the drawings (.badge) */
.badge {
  display: inline-block; margin-left: 8px; padding: 0 10px; border-radius: var(--r-pill);
  background: var(--soft); box-shadow: inset 0 0 0 1px var(--line); color: var(--ink);
  font-size: 13px; font-weight: 600; line-height: 1.7; white-space: nowrap;
}

/* --- 1.10 Bars, timelines, steps --------------------------------------------------------------------------- */
.bar-track { height: 8px; overflow: hidden; border-radius: var(--r-pill); background: var(--soft); }
.bar-fill { height: 100%; border-radius: var(--r-pill); background: var(--brand); }
.hbars { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.hbars li, .hbars a { display: grid; grid-template-columns: minmax(0, 9em) minmax(0, 1fr) auto; gap: 10px; align-items: center; color: inherit; text-decoration: none; }
.hbars a { min-height: 40px; border-radius: 8px; }
.hbars a:hover { background: var(--soft); }
.heat td { text-align: center; font-variant-numeric: tabular-nums; }
.heat .is-0 { color: var(--muted); }
.heat .is-1 { background: var(--ok-bg); }
.heat .is-2 { background: var(--warn-bg); }
.heat .is-3 { background: var(--late-bg); color: var(--late); font-weight: 700; }
.legend { display: flex; flex-wrap: wrap; gap: 6px 14px; color: var(--muted); font-size: 12px; }
.legend i { display: inline-block; width: 10px; height: 10px; margin-right: 6px; border-radius: 3px; vertical-align: -1px; }
.timeline { display: grid; margin: 0; padding: 0; list-style: none; }
.timeline-step {
  display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; gap: 10px; align-items: center;
  padding: 10px 0; border-bottom: 1px solid var(--line);
}
.timeline-step:last-child { border-bottom: 0; }
.timeline-dot {
  display: grid; place-items: center; width: 24px; height: 24px; border: 2px solid var(--line-strong); border-radius: 50%;
  color: var(--muted); font-size: 12px; font-weight: 700;
}
.timeline-step.is-done .timeline-dot { border-color: var(--brand); background: var(--brand); color: #ffffff; }
.timeline-step.is-now .timeline-dot { border-color: var(--hero); background: var(--hero); color: #ffffff; }
.timeline-step.is-now { font-weight: 600; }
.timeline-step.is-todo { color: var(--muted); }
.steps-mini { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; color: var(--muted); font-size: 13px; }
.steps-mini-dots { display: inline-flex; gap: 4px; }
.steps-mini-dots i { width: 8px; height: 8px; border-radius: 50%; background: var(--line-strong); }
.steps-mini-dots i.is-done { background: var(--brand); }
.steps-mini-dots i.is-now { background: var(--amber); }

/* --- 1.11 Lists and tables ------------------------------------------------------------------------------------ */
.list { display: grid; margin: 0; padding: 0; list-style: none; }
.list > li + li { border-top: 1px solid var(--line); }
.list-row {
  display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 10px 4px;
  color: var(--ink); text-decoration: none;
}
.list-row:hover { background: var(--soft); }
.card-flush .list-row { padding-inline: 18px; } /* a flush card has no padding of its own: the row keeps the card's edge */
.list-row-main { display: grid; flex: 1; gap: 2px; min-width: 0; }
.list-row-title { font-weight: 600; overflow-wrap: anywhere; }
.list-row-meta { color: var(--muted); font-size: 13px; overflow-wrap: anywhere; }
.list-row-trail { display: inline-flex; flex: none; align-items: center; gap: 6px; }
.list-row-chev { color: var(--ink-3); }
/* A desk table that becomes rows under 720px: each cell says its label (data-label), the first cell's link takes the row. */
.card-table { width: 100%; border-collapse: collapse; }
.card-table th, .card-table td { padding: 10px 12px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
.card-table thead th { color: var(--muted); font-size: 12px; font-weight: 600; white-space: nowrap; }
.card-table tbody tr:last-child > * { border-bottom: 0; }
.card-table tbody tr { position: relative; }
.card-table tbody tr:hover > * { background: var(--soft); }
.card-table .row-link { color: inherit; font-weight: 700; text-decoration: none; }
.card-table .row-link::after { content: ""; position: absolute; inset: 0; }
.card-table .num { text-align: right; white-space: nowrap; }
@media (max-width: 719.98px) {
  .card-table, .card-table tbody { display: block; }
  .card-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .card-table tbody tr { display: grid; gap: 4px 12px; padding: 12px 4px; border-bottom: 1px solid var(--line); }
  .card-table tbody tr:last-child { border-bottom: 0; }
  .card-table tbody :is(th, td) { display: block; padding: 0; border: 0; }
  .card-table tbody :is(th, td)[data-label]::before {
    content: attr(data-label); display: block; color: var(--muted); font-size: 12px; font-weight: 600;
  }
}
.toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; min-width: 0; }
.search {
  display: flex; flex: 1 1 260px; align-items: center; gap: 8px; max-width: 440px; min-width: 0; min-height: 44px;
  padding: 0 12px; border: 1.5px solid var(--ctl-line); border-radius: var(--r-ctl); background: var(--card);
}
.search input { flex: 1; min-width: 0; min-height: 40px; border: 0; background: transparent; color: var(--ink); font: inherit; }
.search input:focus { outline: 0; }
.search:focus-within { outline: 3px solid var(--focus); outline-offset: 2px; }
.filter-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.filter-menu > summary { list-style: none; cursor: pointer; }
.filter-menu > summary::-webkit-details-marker { display: none; }
.month-switch { display: inline-flex; align-items: center; gap: 4px; }
.month-switch b { min-width: 7em; font-family: var(--font-display); font-size: 17px; text-align: center; }
.month-switch .btn { width: 44px; min-width: 44px; padding: 0; }
.empty-state {
  display: grid; justify-items: center; gap: 6px; padding: 28px 16px; color: var(--muted-2); text-align: center;
}
.empty-state-ico { display: grid; place-items: center; width: 52px; height: 52px; border-radius: 50%; background: var(--soft); color: var(--muted-2); }
.empty-state-title { margin: 4px 0 0; color: var(--ink); font-weight: 700; }
.empty-state-body { max-width: 46ch; margin: 0 0 6px; font-size: 14px; }

/* --- 1.12 Messages ------------------------------------------------------------------------------------------- */
.callout {
  display: flex; align-items: flex-start; gap: 10px; margin: 0 0 16px; padding: 12px 14px;
  border-radius: 14px; background: var(--soft); color: var(--ink);
}
.callout > .ico { margin-top: 2px; }
.callout-body { flex: 1; min-width: 0; }
.callout-body > p { margin: 0; }
.callout-body > * + * { margin-top: 8px; }
.callout-info { background: #eef2f0; }
.callout-warn { background: var(--warn-bg); color: var(--warn); }
.callout-ok { background: var(--ok-bg); color: var(--run-deep); }
.callout-error { background: var(--late-bg); color: var(--late); }
.callout-ro { background: var(--idle-bg); color: var(--idle); }
.toast {
  position: fixed; left: 50%; z-index: 60; /* above the bar at the bottom, clear of its raised scan button */
  bottom: calc(var(--tabbar-h) + var(--tabbar-rise) + 12px + env(safe-area-inset-bottom));
  display: flex; align-items: center; gap: 12px; max-width: min(520px, calc(100vw - 32px)); padding: 12px 16px;
  border-radius: 14px; background: var(--hero); box-shadow: var(--pop-shadow); color: #ffffff; transform: translateX(-50%);
}
@media (min-width: 1024px) { .toast { bottom: 24px; } }
.status-card {
  display: grid; justify-items: center; gap: 8px; width: 100%; max-width: 34rem; margin-inline: auto; padding: 12px 0 4px;
  text-align: center;
}
.status-card-ring { display: grid; place-items: center; width: 72px; height: 72px; border-radius: 50%; }
.status-card-ok .status-card-ring { background: var(--ok-bg); color: var(--ok); }
.status-card-info .status-card-ring { background: var(--soft); color: var(--brand); }
.status-card-warn .status-card-ring { background: var(--warn-bg); color: var(--warn); }
.status-card-error .status-card-ring { background: var(--late-bg); color: var(--late); }
.status-card-title { margin: 6px 0 0; font-family: var(--font-display); font-size: 22px; line-height: 1.3; }
.status-card-body { max-width: 42ch; margin: 0; color: var(--muted-2); } /* 4.9:1 on the canvas (an error page) */
.status-card-actions { display: grid; gap: 8px; width: 100%; margin-top: 12px; }
.status-page { padding-top: 32px; }
.app-main .status-card { padding: 28px 20px 20px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); }

/* --- 1.13 The bar of a task page, menus, sheets -------------------------------------------------------------- */
.action-bar {
  display: grid; gap: 8px; margin: 16px 0 0; padding: 12px 16px;
  border-top: 1px solid var(--line); background: var(--card);
}
.action-bar-sum { margin: 0; color: var(--muted); font-size: 14px; }
.action-bar-acts { display: flex; flex-wrap: wrap; gap: 8px; }
@media (max-width: 1023.98px) {
  /* On a phone the buttons share one row as long as their words fit it (P6: the help button beside the primary), and
     the primary (a button, or the form that holds it) takes the larger part of the room left; they stack only when
     the words are too long for one row. */
  .action-bar-acts > * { flex: 1 1 auto; min-width: 0; }
  .action-bar-acts > .btn { width: auto; }
  .action-bar-acts > :is(.btn-primary, .btn-go, .btn-send, :has(> :is(.btn-primary, .btn-go, .btn-send))) {
    flex-grow: 2;
  }
  .is-task .action-bar {
    position: sticky; bottom: 0; z-index: 20; margin: 0;
    padding: 10px max(16px, env(safe-area-inset-right)) calc(10px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
    box-shadow: 0 -4px 16px rgba(18, 38, 30, 0.06);
  }
}
@media (min-width: 1024px) {
  /* The foot of the page's content (spec §1.1 app·task): the summary on the left, the buttons on the right of one row
     while they fit, right under the page (its column keeps 48 px at its foot, of which the bar takes 32). */
  .action-bar {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px;
    max-width: 1280px; margin: 0 28px 32px; padding: 12px 18px; border: 1px solid var(--line); border-radius: var(--r-card);
  }
  .admin + .action-bar { margin-top: -32px; }
  .action-bar-acts { justify-content: flex-end; margin-left: auto; }
  .action-bar-acts > * { flex: none; }
  .action-bar-acts > .btn { width: auto; }
}
.overflow-menu { position: relative; }
.overflow-menu > summary { list-style: none; cursor: pointer; }
.overflow-menu > summary::-webkit-details-marker { display: none; }
.overflow-menu-panel {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 40; display: grid; min-width: 220px; padding: 6px;
  border: 1px solid var(--line); border-radius: 14px; background: var(--card); box-shadow: var(--pop-shadow);
}
.overflow-menu-panel > :is(a, button) {
  display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 12px; border: 0; border-radius: 10px;
  background: transparent; color: var(--ink); font: inherit; font-weight: 500; text-align: left; text-decoration: none; cursor: pointer;
}
.overflow-menu-panel > :is(a, button):hover { background: var(--soft); }
dialog.sheet {
  width: min(560px, 100vw); max-width: 100vw; max-height: 90dvh; margin: auto auto 0; padding: 0;
  border: 0; border-radius: 22px 22px 0 0; background: var(--card); color: var(--ink); box-shadow: var(--pop-shadow);
}
dialog.sheet::backdrop { background: rgba(18, 38, 30, 0.45); }
@media (min-width: 720px) { dialog.sheet { margin: auto; border-radius: var(--r-card); } }
.sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px 0 20px; }
.sheet-title { margin: 0; font-family: var(--font-display); font-size: 19px; }
.sheet-close { margin: 0; }
.sheet-body { display: grid; gap: 14px; padding: 12px 20px calc(20px + env(safe-area-inset-bottom)); }
.sheet-confirm .sheet-body { text-align: center; }
.danger-zone {
  display: grid; gap: 10px; margin-top: 24px; padding: 16px 18px; border: 1px solid var(--late-bg); border-radius: var(--r-card);
  background: var(--card);
}
.danger-zone h2 { margin: 0; color: var(--late); font-size: 17px; }

/* --- 1.14 Forms ---------------------------------------------------------------------------------------------- */
.field { display: grid; gap: 6px; min-width: 0; font-weight: 600; }
.field input, .field select, .field textarea {
  width: 100%; min-width: 0; /* W0: a field keeps to its track, so iOS never pushes it past the edge of a row */
  min-height: 48px; padding: 0 14px;
  border: 1.5px solid var(--ctl-line); border-radius: var(--r-ctl);
  background: var(--surface); color: var(--ink);
  font: inherit; font-weight: 500;
}
.field textarea { padding: 10px 14px; resize: vertical; } /* the rest of its look comes from the rule for .field input above */
.field input[type="file"] { padding: 10px 14px; }
.field-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 16px; }
@media (max-width: 639.98px) { .field-grid { grid-template-columns: minmax(0, 1fr); } }
.form-section { display: grid; gap: 14px; min-width: 0; margin: 0 0 16px; padding: 16px 18px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); }
.form-section > h2 { margin: 0; font-family: var(--font-display); font-size: 17px; }
/* A message about the form, in words as well as colour */
.form-error { margin: 0 0 16px; padding: 12px 14px; border-radius: 14px; background: var(--late-bg); color: var(--late); font-weight: 600; }
.seg { display: inline-flex; flex-wrap: wrap; gap: 4px; padding: 4px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--card); }
.seg label { position: relative; }
.seg input { position: absolute; opacity: 0; pointer-events: none; }
.seg span { display: inline-flex; align-items: center; min-height: 44px; padding: 0 16px; border-radius: var(--r-pill); color: var(--muted); font-weight: 600; cursor: pointer; }
.seg input:checked + span { background: var(--hero); color: #ffffff; }
.seg input:focus-visible + span { outline: 3px solid var(--focus); outline-offset: 2px; }
/* Targets (§5): 44px on a phone, 40px on a desk, for the crumb, a chip and a segment (after their rules) */
@media (min-width: 1024px) { .crumb, .chip, .seg span { min-height: 40px; } }
.toggle-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.toggle-chips label { position: relative; }
.toggle-chips input { position: absolute; opacity: 0; pointer-events: none; }
.toggle-chips span {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 14px; border: 1.5px solid var(--ctl-line);
  border-radius: var(--r-pill); background: var(--card); font-weight: 600; cursor: pointer;
}
.toggle-chips input:checked + span { border-color: var(--brand); background: var(--ok-bg); color: var(--brand-deep); }
.toggle-chips input:focus-visible + span { outline: 3px solid var(--focus); outline-offset: 2px; }
.switch { position: relative; display: inline-flex; align-items: center; gap: 10px; min-height: 44px; font-weight: 600; cursor: pointer; }
.switch input { position: absolute; opacity: 0; pointer-events: none; }
.switch-track { position: relative; flex: none; width: 46px; height: 28px; border-radius: var(--r-pill); background: var(--line-strong); transition: background-color 150ms ease-out; }
.switch-track::after { content: ""; position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: #ffffff; transition: transform 150ms ease-out; }
.switch input:checked + .switch-track { background: var(--brand); }
.switch input:checked + .switch-track::after { transform: translateX(18px); }
.switch input:focus-visible + .switch-track { outline: 3px solid var(--focus); outline-offset: 2px; }
.choice-cards { display: grid; gap: 10px; }
.choice-cards label {
  display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 2px 12px; align-items: start; min-height: 56px; padding: 12px 14px;
  border: 1.5px solid var(--ctl-line); border-radius: 14px; background: var(--card); cursor: pointer;
}
.choice-cards input { width: 20px; height: 20px; margin: 2px 0 0; accent-color: var(--brand); }
.choice-cards label:has(input:checked) { border-color: var(--brand); background: var(--run-bg); }
.choice-cards .consequence-line { grid-column: 2; color: var(--muted); font-size: 13px; }
.qty-stepper { display: inline-flex; align-items: stretch; border: 1.5px solid var(--ctl-line); border-radius: var(--r-ctl); background: var(--card); }
.qty-stepper button { width: 48px; border: 0; background: transparent; color: var(--ink); cursor: pointer; }
.qty-stepper input { width: 5em; min-height: 48px; border: 0; border-inline: 1px solid var(--line); background: transparent; color: var(--ink); font: inherit; font-weight: 700; text-align: center; }
.reason-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.photo-pick, .file-field {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px; min-height: 56px; padding: 10px 14px;
  border: 1.5px dashed var(--ctl-line); border-radius: 14px; background: var(--card);
}
.photo-pick input, .file-field input { max-width: 100%; }
/* The rows of a route that a form edits (office/_route_rows.html): numbered, a locked step quiet behind a dashed edge,
   the tools of a row (up, down, remove) in reach of a thumb. */
.step-editor .editor-no {
  display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: var(--soft);
  color: var(--muted-2); font-size: 13px; font-weight: 700;
}
.step-editor .editor-row-locked .editor-no { background: transparent; box-shadow: inset 0 0 0 1.5px var(--line-strong); }
.step-editor .editor-row :is(input, select) { border-color: var(--ctl-line); border-radius: var(--r-ctl); }
.step-editor .editor-fixed { border-radius: var(--r-ctl); background: var(--soft); }

/* --- 1.15 Cards of one purpose ------------------------------------------------------------------------------ */
.auth-card { max-width: 460px; margin: 0 auto; padding: 24px 20px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); }
.one-time-link { display: grid; justify-items: start; gap: 12px; }
.one-time-link .qr { justify-self: center; }
.confirm-card { display: grid; justify-items: center; gap: 8px; padding: 24px 16px; text-align: center; }
.confirm-card b { font-family: var(--font-display); font-size: 30px; line-height: 1.2; overflow-wrap: anywhere; }
.scanner { display: grid; gap: 12px; }
.scanner video, .scanner-view { width: 100%; aspect-ratio: 1; border-radius: var(--r-card); background: var(--hero); object-fit: cover; }

/* ===== end W1 foundation ===== */

/* ===== W1 legacy shared rules (owned by W1) =====
   The classes that the pages of before the redesign share across areas (tables, forms, cards, chips, the route
   editor, the status words, the number cards), restyled by the tokens above. A wave that rebuilds its pages moves to
   the components of the foundation; until then these keep every untouched page coherent. */

/* The legacy boxes that ask for attention (.notice-*) and the empty line of a list (.empty), restyled in place as the
   callout and a quiet empty box (§2.2): the words say what is wrong; the tint only agrees, with no coloured edge. */
.notice { margin: 0 0 16px; padding: 12px 14px; border: 0; border-radius: 14px; background: var(--soft); }
.notice-warn { background: var(--warn-bg); color: var(--warn); }
.notice-ok { background: var(--ok-bg); color: var(--run-deep); }
.notice-late { background: var(--late-bg); color: var(--late); }
.empty {
  margin: 8px 0 16px; padding: 18px 16px; border: 1px dashed var(--line-strong); border-radius: 14px;
  color: var(--muted-2); text-align: center;
}
.empty a { color: var(--brand); font-weight: 600; text-underline-offset: 3px; }

/* R-UX-25: paper inherits the same Sarabun/Myanmar type tokens as the screens.
   Its explicit pt sizes and A4 dimensions below stay independent of the screen body scale. */
.workorder {
  /* PCF005 is always Thai/English, even inside a Burmese viewer's shell. Its .wo-my text keeps Myanmar first. */
  --font: "Sarabun", "Noto Sans Myanmar", "Noto Sans Thai", system-ui, sans-serif;
  --font-display: var(--font);
  --font-head: var(--font);
}
/* The paper sits in the middle of a wide screen and at the left of a narrow one, whose browser scrolls to all of it:
   auto margins centre it only where there is room. So a browser that does not know the stages' `align-items: safe
   center` (W0) keeps that behaviour too, where a plain `center` would cut off the left of the sheet again. */
.workorder-stage > .workorder, .ngreg-stage > .ngreg { margin-inline: auto; }

/* Small labels in a row, such as the roles and stations of a user */
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.notice .chips { margin-top: 8px; }
.chips li {
  padding: 2px 10px; border: 1px solid var(--line-strong); border-radius: 999px;
  background: var(--surface); color: var(--ink); font-size: 15px; line-height: 1.5;
}

/* A table of records; the wrapper lets a narrow screen scroll the table instead of the page. It is the containing block
   of what is positioned inside it (the .sr-only words of a button), so that those scroll with the table and never make
   the page wider (B-P3-1). */
.table-wrap {
  position: relative; overflow-x: auto; border: 1px solid var(--line); border-radius: 14px; background: var(--surface);
}
.data-table { width: 100%; border-collapse: collapse; }
.data-table th, .data-table td {
  padding: 10px 14px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top;
}
.data-table thead th {
  background: var(--soft); color: var(--ink-2); font-size: 13px; font-weight: 600; white-space: nowrap;
}
.data-table tbody tr:last-child > * { border-bottom: 0; }
.data-table tbody th { font-weight: 600; }
.data-table a { color: var(--send); text-underline-offset: 3px; }
.data-table .is-off th a, .data-table .is-off td { color: var(--ink-2); }
.status { font-weight: 600; white-space: nowrap; }
.status-on { color: var(--go); }
.status-off { color: var(--ink-2); }

/* A form of several fields, with groups of checkboxes */
.form-card { max-width: 720px; }
.check-group {
  min-width: 0; margin: 0; padding: 10px 14px 12px;
  border: 1.5px solid var(--line-strong); border-radius: 12px; background: var(--surface);
}
.check-group legend { padding: 0 6px; font-weight: 600; }
.check-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 0 16px; }
.check { display: flex; align-items: center; gap: 10px; min-height: 44px; font-weight: 500; cursor: pointer; }
.check input { flex: none; width: 22px; height: 22px; margin: 0; accent-color: var(--brand); }
.field-hint { color: var(--ink-2); font-size: 14px; font-weight: 500; }
.unit-name { color: var(--ink-2); font-weight: 500; } /* the unit of the item, beside the label of its quantity */
.field-error { display: block; margin: 0; color: var(--late); font-weight: 600; }
.field [aria-invalid="true"] { border-color: var(--late); }
.readonly { margin: 0; font-weight: 500; }
.readonly-label { margin-right: 8px; font-weight: 600; }
.form-actions { display: flex; flex-wrap: wrap; gap: 12px; }
.lead { max-width: 720px; margin: 0 0 16px; color: var(--ink-2); }
.hint { margin: 0; color: var(--ink-2); font-size: 15px; }
.setup-card, .detail-card {
  margin: 0 0 16px; padding: 14px 16px 16px;
  border: 1px solid var(--line); border-radius: var(--r-card); background: var(--surface);
}
.setup-card h2, .detail-card h2 { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin: 0 0 12px; }
.setup-card h3, .detail-card h3 { margin: 18px 0 8px; color: var(--ink-2); font-size: 16px; }
.code {
  padding: 1px 8px; border-radius: 6px; background: var(--bg); color: var(--ink-2);
  font-family: var(--font); font-size: 14px; font-weight: 500;
}
.row-form {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr)); gap: 10px 12px; align-items: end;
  margin: 0;
}
.row-form > * { min-width: 0; } /* W0: a track never grows past the row for what a field asks */
.row-form .field-error { grid-column: 1 / -1; }

/* Links that filter a list: a row of buttons, the one in use filled */
.filter-bar { display: flex; flex-wrap: wrap; gap: 6px 8px; margin: 0 0 14px; }
.filter-bar a {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 14px;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--surface); color: var(--ink); font-weight: 600; text-decoration: none;
}
.filter-bar a[aria-current="page"] { border-color: var(--hero); background: var(--hero); color: #ffffff; }

/* A job: its facts side by side, its items and its route */
.detail-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px 24px; margin: 0 0 16px; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--surface);
}
.detail-grid dt { color: var(--ink-2); font-size: 14px; font-weight: 600; }
.detail-grid dd { margin: 0; font-weight: 500; overflow-wrap: anywhere; }
.detail-grid dd.notes { white-space: pre-line; } /* what was typed keeps its line breaks */
.data-table .num { text-align: right; white-space: nowrap; }
.status-running { color: var(--go); }
.status-waiting { color: var(--help); }
.status-pending, .status-done, .status-cancelled { color: var(--ink-2); }
.detail-card .chips { margin-bottom: 4px; }
.admin h1 .status { margin-left: 8px; font-size: 16px; vertical-align: middle; }
.admin h1 .sf-chip { margin-left: 8px; vertical-align: middle; } /* the due chip beside the status of a job */
.admin h1 .sf-badges { display: inline-flex; margin-left: 8px; vertical-align: middle; } /* ... and its badges */
.data-table .sf-chip { margin-left: 6px; vertical-align: middle; } /* ... and beside a due date in a table */
.detail-grid dd .sf-chip { margin-left: 6px; vertical-align: middle; }

/* The forms that open a job and change its route: rows that can be added, removed and moved */
.form-wide { max-width: 860px; }
.editor { --tools-w: 140px; display: grid; gap: 10px; margin-top: 4px; } /* three 44px buttons and their gaps, so that the head row lines up */
.editor-row { display: grid; align-items: center; gap: 8px; }
.editor-row-station { grid-template-columns: 28px minmax(0, 1fr) var(--tools-w); }
.editor-row input, .editor-row select {
  min-width: 0; min-height: 48px; padding: 0 12px;
  border: 1.5px solid var(--line-strong); border-radius: 10px;
  background: var(--surface); color: var(--ink); font: inherit; font-weight: 500;
}
.editor-no { color: var(--ink-2); font-weight: 600; text-align: center; }
/* A step of a standard route that cannot be changed (design first, QC and shipping last): a lock and no tools */
.editor-row-locked { grid-template-columns: 28px minmax(0, 1fr); }
.editor-fixed {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; min-height: 48px; padding: 6px 12px;
  border: 1.5px dashed var(--line-strong); border-radius: 10px; background: var(--bg); color: var(--ink);
}
.editor-fixed .row-icon { flex: none; color: var(--ink-2); }
.editor-fixed-name { font-weight: 600; }
.editor-fixed-note { color: var(--ink-2); font-size: 15px; }
.row-tools { display: flex; gap: 4px; }
.icon-btn {
  -webkit-appearance: none; appearance: none; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin: 0; padding: 0;
  border: 1.5px solid var(--line-strong); border-radius: 10px; background: var(--surface); color: var(--ink); cursor: pointer;
}
.icon-btn[disabled] { opacity: 0.4; cursor: default; }
.row-icon { width: 20px; height: 20px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.calendar-nav { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 12px; } /* earlier, today, later */

/* The executive overview (templates/office/overview.html): every number is a card that links to the jobs it counts. The
   words sit in the card under the number, so that the colour of the late and today cards only agrees with them. */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 12px; margin: 0 0 8px; padding: 0; list-style: none; }
.stat-grid-small { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.stat {
  display: grid; align-content: space-between; gap: 4px; height: 100%; min-height: 104px; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: var(--r-card); background: var(--surface); color: var(--ink); text-decoration: none;
}
a.stat:hover { border-color: var(--line-strong); }
.stat-num { font-family: var(--font-head); font-size: 38px; font-weight: 700; line-height: 1.1; }
.stat-label { color: var(--ink-2); font-size: 15px; font-weight: 600; }
.stat-grid-small .stat { min-height: 0; }
.stat-grid-small .stat-num { font-size: 28px; }
.stat-late { border-color: var(--late); background: var(--late-bg); }
.stat-late :is(.stat-num, .stat-label) { color: var(--late); }
.stat-today { border-color: var(--help-line); background: var(--today-bg); }
.stat-today :is(.stat-num, .stat-label) { color: var(--today); }
.stat-none :is(.stat-num, .stat-label) { color: var(--ink-2); }

/* The history of a job and the audit page: when, who, what. The small words after the action say where, and which file. */
.history-table .col-time { white-space: nowrap; color: var(--ink-2); }
.history-table .col-what .hint { display: inline; margin-left: 6px; }
.oa-link { display: grid; gap: 10px; justify-items: start; margin: 0; }
.oa-link a[data-oa-link] { color: var(--send); font-weight: 700; overflow-wrap: anywhere; text-underline-offset: 3px; }
.oa-link .qr svg { width: 200px; }
.oa-link a[data-oa-link]:not(.btn) { display: inline-flex; align-items: center; min-height: 44px; }
/* ===== end W1 legacy shared ===== */

/* ===== W2 floor+home (owned by W2) ===== */

/* The staff phone pages of the redesign (W2): the shop floor (templates/floor/), the homes (home/_mobile.html, the
   station home, the office home), "me", the bell's list and the scanner (templates/home/). They are drawn from the W1
   components (page-head, card, kpi, hero-card, pill, callout, action-bar, list-row, empty-state, status-card); the
   rules here are what those pages add. The floor keeps its gloved sizes: every main button is 64px or more. */

/* ===== The shop-floor screens (templates/floor/) ===== */

.sf-screen {
  display: flex; flex-direction: column; max-width: 640px; margin: 0 auto;
  min-height: calc(100vh - 57px); min-height: calc(100dvh - 57px); /* the screen less the app bar */
  background: var(--bg);
  /* Every main button of the floor (start, hand off, report a problem, confirm, send, QC's stamp) is 64px or more, for a
     gloved thumb on a phone or a shared tablet (owner, 22 Oct 2026). A text button stays 48px. */
  --btn-h: 64px;
  --btn-h-big: 66px;
}
@media (min-width: 1024px) { .sf-screen { max-width: 760px; min-height: 100vh; } }
/* The reset weighs nothing (:where), so that any class of the screen wins over it. */
:where(.sf-screen) :where(h1, h2, p) { margin: 0; }
/* Burmese stacks marks above and below the line, so the tight lines of the floor (drawn for Thai) get more room */
.sf-screen:lang(my) :is(.sf-hero-no, .sf-head-no, .sf-head-title, .sf-chip, .sf-status, .sf-step, .sf-dest-to, .sf-dest-last, .sf-dock-dest, .sf-notice-title, .sf-qc-state, .sf-qc-hint, .sf-row-no, .sf-clock) { line-height: 1.7; }

/* A floor page: the cards one under the other on the canvas, with the phone's gutters. */
.sf-page {
  display: grid; gap: 14px; align-content: start;
  padding: 14px max(16px, env(safe-area-inset-right)) 20px max(16px, env(safe-area-inset-left));
}
.sf-page > .card + .card, .sf-page > .callout { margin-top: 0; margin-bottom: 0; } /* the gap of the page spaces them */
/* A secondary link in the head of a floor page: an outline the height of a thumb, never a main button. */
.sf-head-link {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 14px;
  border: 1.5px solid var(--ctl-line); border-radius: var(--r-ctl); background: var(--card); color: var(--ink);
  font-size: 15px; font-weight: 600; text-decoration: none;
}
.sf-head-link:hover { background: var(--soft); }
@media (max-width: 1023.98px) { .sf-desk-only { display: none; } } /* the bar at the bottom has the scan there */
/* The small button of a page head keeps a desk's 40px and more (W1's is 36 there). */
.alerts-page .page-actions .btn-sm { min-height: 44px; }
.sf-page .page-head { margin: 0; }
/* A block of a floor page is the floor's card: white, the 1px line, radius 18, never a card inside a card. */
.sf-block {
  display: grid; gap: 12px; min-width: 0; padding: 16px 18px;
  border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card);
}
.sf-label {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin: 0;
  color: var(--muted-2); font-size: 15px; font-weight: 600; line-height: 1.4;
}
.sf-label-count { color: var(--muted); font-size: 14px; font-weight: 500; }
.sf-note { margin: 0; color: var(--muted-2); font-size: 14px; }
.sf-empty { margin: 0; padding: 14px 16px; border: 1px dashed var(--line-strong); border-radius: 14px; color: var(--muted-2); font-size: 15px; }
.sf-count {
  display: inline-flex; align-items: center; justify-content: center; min-width: 26px; height: 26px; padding: 0 8px;
  border-radius: var(--r-pill); background: var(--soft); color: var(--ink); font-size: 14px; font-weight: 700;
}

/* What is inside a main button: its icon and its words (and, while the form is on its way, the saving words) */
.sf-btn-in { display: inline-flex; align-items: center; justify-content: center; gap: 10px; }
.sf-ico { flex: none; width: 24px; height: 24px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.sf-ico.sm { width: 20px; height: 20px; }
.sf-spin { flex: none; width: 22px; height: 22px; border: 3px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: sf-rot 800ms linear infinite; }
@keyframes sf-rot { to { transform: rotate(360deg); } }

/* How a job stands against its due date, in words as well as colour (due_chip; the office pages draw it too). */
.sf-chip {
  display: inline-flex; align-items: center; gap: 6px; min-height: 28px; padding: 4px 10px; border-radius: var(--r-pill);
  font-size: 14px; font-weight: 600; line-height: 1.3; white-space: nowrap;
}
.sf-chip.late { color: var(--late); background: var(--late-bg); }
.sf-chip.today { color: var(--today); background: var(--today-bg); }
.sf-chip.ok { color: var(--muted-2); background: var(--soft); }
.sf-chip.run { color: var(--run-ink); background: var(--run-soft); }
.sf-chip.p-open { color: var(--warn); background: var(--warn-bg); }
.sf-chip.p-acknowledged { color: var(--run-ink); background: var(--run-soft); }
.sf-chip.p-closed, .sf-chip.p-void { color: var(--muted-2); background: var(--soft); }

/* A word on a job (job_badges), such as the sheet being awaited: a soft filled pill in the tone of what it says, never a
   grey outline that looks like a filter to tap. A word that holds shipping or is late is red, one that waits amber,
   one that only informs soft; a rush job is the dark pill with its reason under the word, once. The words never change. */
.sf-badges { display: flex; flex-wrap: wrap; gap: 6px; }
.sf-badge {
  display: inline-flex; align-items: center; min-height: 28px; padding: 2px 10px; border: 1.5px solid var(--ink-2);
  border-radius: 14px; background: var(--chip-bg); color: var(--ink); font-size: 14px; font-weight: 600; line-height: 1.3;
}
.sf-badge-rush { flex-direction: column; align-items: flex-start; max-width: 100%; font-weight: 800; }
.sf-badge-why { font-weight: 600; overflow-wrap: break-word; }
.sf-badge-behind_plan, .sf-badge-release_late { border-color: var(--late); background: var(--late-bg); color: var(--late); }
.sf-badge-release_today { border-color: var(--today); background: var(--today-bg); color: var(--today); }
.sf-badges .sf-badge { border-color: transparent; border-radius: var(--r-pill); background: var(--soft); color: var(--muted-2); }
.sf-badges .sf-badge-rework_open, .sf-badges .sf-badge-recheck, .sf-badges .sf-badge-undecided,
.sf-badges .sf-badge-behind_plan, .sf-badges .sf-badge-release_late { background: var(--late-bg); color: var(--late); }
.sf-badges .sf-badge-waiting_sheet, .sf-badges .sf-badge-release_today { background: var(--warn-bg); color: var(--warn); }
.sf-badges .sf-badge-rush { border-radius: 14px; background: var(--hero); color: #ffffff; }
.sf-badges .sf-badge-rush .sf-badge-why { color: rgba(255, 255, 255, 0.82); }
.hero-card .sf-badges .sf-badge-rush { background: #ffffff; color: var(--hero); } /* the dark pill on the dark card */
.hero-card .sf-badges .sf-badge-rush .sf-badge-why { color: var(--muted-2); }
/* The planned finish of a step in a queue row: what it is, then when, in words */
.sf-row-plan { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.sf-plan-at { font-weight: 600; color: var(--ink); }

/* Where a job is on its route (steps_mini), on the dark card: a white dot done, the amber dot of now, the rest faint. */
.hero-card .steps-mini { color: rgba(255, 255, 255, 0.86); font-size: 14px; }
.hero-card .steps-mini-dots i { background: rgba(255, 255, 255, 0.28); }
.hero-card .steps-mini-dots i.is-done { background: #ffffff; }
.hero-card .steps-mini-dots i.is-now { background: var(--amber); }

/* The working-time clock of a running step, labelled so that a clock that stands at lunch is not read as a freeze. */
.sf-clock { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; font-weight: 600; }
.sf-clock-n { font-family: var(--font-display); font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.sf-clock-note { margin: 0; color: rgba(255, 255, 255, 0.72); font-size: 13px; }

/* --- the queue (floor/queue.html) --- */
/* The person's stations, a tap away: the one shown is dark, each other one is a button that chooses it. */
.sf-switch { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; }
.sf-switch-item {
  -webkit-appearance: none; appearance: none; display: inline-flex; align-items: center; min-height: 44px; padding: 0 16px;
  border: 1px solid var(--ctl-line); border-radius: var(--r-pill); background: var(--card); color: var(--ink);
  font: inherit; font-size: 15px; font-weight: 600; cursor: pointer;
}
.sf-switch-form { margin: 0; }
.sf-switch-item[aria-current="page"] { border-color: var(--hero); background: var(--hero); color: #ffffff; cursor: default; }
.sf-switch-item[disabled] { opacity: 0.55; cursor: default; }
.sf-switch-busy { display: inline-flex; align-items: center; gap: 8px; color: var(--muted-2); font-size: 14px; }
.sf-switch-busy .sf-spin { width: 18px; height: 18px; }
/* The three numbers that filter the list: small, in one row (a second one only on a phone too narrow for it), each its
   words then its count, a thumb high, so that the running card and the first waiting job are on the first screen of a
   360 px phone in Burmese (W2 UX gate, UX-1). A tap filters the list and brings it into view (queue.html, showDue),
   under the app bar. */
.sf-kpis { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; }
.sf-kpis .kpi {
  display: inline-flex; flex: 1 1 auto; align-items: center; justify-content: center; gap: 8px; min-height: 44px;
  padding: 4px 12px; border-radius: var(--r-pill);
}
.sf-kpis .kpi-label { color: var(--ink-2); font-size: 14px; white-space: nowrap; }
.sf-kpis .kpi-value { font-size: 18px; line-height: 1.2; }
.sf-waiting { scroll-margin-top: calc(var(--bar-h, 56px) + 12px); }
/* The running jobs, in the one dark card: each a whole-row link in a few lines, its number with its clock, one line of
   what it is, and its words folded into one pill beside its planned finish; the job page has the rest (UX-1). */
.sf-hero-title { font-size: 14px; font-weight: 600; color: rgba(255, 255, 255, 0.78); }
.sf-run-list { display: grid; margin: 0; padding: 0; list-style: none; }
.sf-run-list > li + li { border-top: 1px solid rgba(255, 255, 255, 0.16); }
.sf-run { color: #ffffff; }
.sf-run .sf-row-meta { color: rgba(255, 255, 255, 0.8); }
.sf-run .sf-plan-at { color: #ffffff; }
.sf-run-top { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0 12px; justify-self: stretch; }
.sf-run .sf-clock { gap: 0 8px; color: rgba(255, 255, 255, 0.86); font-size: 14px; } /* beside the number where it fits */
.sf-run .sf-clock-n { color: #ffffff; font-size: 18px; }
.sf-run-what { justify-self: stretch; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; overflow-wrap: normal; }
.sf-run-tags { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; justify-self: stretch; min-width: 0; }
.sf-badges.sf-badges-folded { flex-wrap: nowrap; min-width: 0; max-width: 100%; margin: 0; }
.sf-badges-folded .sf-badge { flex: none; white-space: nowrap; }
.sf-badges-folded .sf-badge:first-child { display: block; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; line-height: 24px; }
.sf-running .sf-ico.sm { color: rgba(255, 255, 255, 0.7); }
/* The waiting jobs: one card, the rows running on under one another, each a whole-row link with its number in line */
.sf-card-title {
  display: flex; align-items: center; gap: 8px; margin: 0; padding: 14px 16px 10px;
  font-family: var(--font-display); font-size: 17px; font-weight: 700;
}
.sf-list { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--line); }
.sf-list > li + li { border-top: 1px solid var(--line); }
.sf-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4px 12px; min-height: 64px;
  padding: 12px 16px; color: inherit; text-decoration: none;
}
.sf-list .sf-row { grid-template-columns: auto minmax(0, 1fr) auto; }
.sf-row:active { background: var(--row-press); }
.sf-run.sf-row { padding: 10px 0; }
.sf-run.sf-row:active { background: rgba(255, 255, 255, 0.06); }
.sf-row > .sf-ico { color: var(--ink-3); }
.sf-row-pos {
  display: grid; place-items: center; align-self: start; width: 28px; height: 28px; margin-top: 2px; border-radius: 50%;
  background: var(--soft); color: var(--muted-2); font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.sf-row-main { display: grid; gap: 3px; min-width: 0; justify-items: start; }
.sf-row-top { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.sf-row-no { font-family: var(--font-display); font-size: 19px; font-weight: 700; line-height: 1.3; }
.sf-row-meta { font-size: 15px; color: var(--muted-2); overflow-wrap: anywhere; }
.sf-row .sf-badges { margin: 2px 0; }
.sf-filter-none { margin: 0; padding: 14px 16px; border-top: 1px solid var(--line); color: var(--muted-2); }
.sf-waiting .empty-state { padding-top: 18px; }

/* --- a job (floor/job.html): the dark card first, then cards in the order of the work --- */
.sf-hero { gap: 6px; }
.sf-hero-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; }
.sf-hero-no { font-family: var(--font-display); font-size: 28px; font-weight: 700; line-height: 1.2; letter-spacing: -0.01em; }
.sf-hero-kind { color: rgba(255, 255, 255, 0.78); font-size: 14px; }
.sf-cust { font-size: 17px; font-weight: 600; overflow-wrap: anywhere; }
.sf-hero-meta { display: flex; flex-wrap: wrap; gap: 2px 12px; color: rgba(255, 255, 255, 0.82); font-size: 14px; overflow-wrap: anywhere; }
.sf-cancel-reason { white-space: pre-line; } /* what was typed keeps its line breaks */
.sf-hero .steps-mini { margin-top: 4px; }
.sf-hero-clock {
  display: flex; margin-top: 6px; padding: 10px 14px; border-radius: 14px; background: rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.86);
  justify-content: space-between;
}
.sf-hero-clock .sf-clock-n { color: #ffffff; font-size: 30px; line-height: 1.15; }
/* QC's to-do: the first piece of each flagged item, before the items */
.sf-checklist { display: grid; margin: 0; padding: 0; list-style: none; }
.sf-checklist > li { display: grid; gap: 8px; padding: 12px 0; border-top: 1px solid var(--line); }
.sf-checklist > li:first-child { border-top: 0; padding-top: 4px; }
.sf-check-name { font-weight: 700; overflow-wrap: anywhere; }
.sf-qc { display: grid; gap: 8px; }
.sf-qc form { margin: 0; }
.sf-qc-state { display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 600; color: var(--warn); }
.sf-qc-state.is-passed { color: var(--run-ink); }
.sf-qc-hint { font-size: 15px; color: var(--muted-2); }
.sf-recheck-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px; }
.sf-recheck-actions form { margin: 0; }
/* The items */
.sf-items { margin: 0; padding: 0; list-style: none; }
.sf-items li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px 12px; padding: 10px 0; border-top: 1px solid var(--line); }
.sf-items li:first-child { border-top: 0; padding-top: 0; }
.sf-items li:last-child { padding-bottom: 0; }
.sf-qty { font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
.sf-item { display: grid; gap: 2px; min-width: 0; justify-items: start; overflow-wrap: anywhere; }
.sf-item-name { font-weight: 600; }
.sf-item-sub { font-size: 15px; color: var(--muted-2); }
.sf-item-spec { display: flex; flex-wrap: wrap; gap: 0 12px; }
.sf-item-tag { margin-top: 4px; padding: 0 10px; border-radius: var(--r-pill); background: var(--ok-bg); color: var(--ok); font-size: 14px; font-weight: 600; line-height: 1.6; }
.sf-special-text { margin: 0; font-size: 17px; font-weight: 600; overflow-wrap: anywhere; white-space: pre-line; } /* the customer's special requirements, as typed (WO-2) */
.sf-rev { font-weight: 600; }
/* The drawings: one whole-row link each */
.sf-files { overflow: hidden; }
.sf-file-list { display: grid; margin: 0 -18px -16px; padding: 0; list-style: none; }
.sf-file-list > li { border-top: 1px solid var(--line); }
.sf-drawing {
  display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 10px 18px; color: var(--ink); text-decoration: none;
}
.sf-drawing:active { background: var(--row-press); }
.sf-drawing > .sf-ico:first-child { color: var(--brand); }
.sf-drawing > .sf-ico.sm { color: var(--ink-3); }
.sf-drawing-name { display: grid; flex: 1; min-width: 0; overflow-wrap: anywhere; }
.sf-drawing-act { font-weight: 700; }
.sf-drawing-what { font-size: 14px; color: var(--muted-2); } /* the type and the item, under "view drawing" */
/* The route, last: the steps done are ticked, the step the job is at is the dark one */
.sf-route { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0; padding: 0; list-style: none; }
.sf-step {
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 12px;
  border: 1.5px solid var(--line-strong); border-radius: 10px; background: var(--card); color: var(--muted-2);
  font-size: 15px; font-weight: 600;
}
.sf-step.done { border-color: transparent; background: var(--soft); }
.sf-step.now { border-color: var(--hero); background: var(--hero); color: #ffffff; }
.sf-step.cancelled { border-style: dashed; text-decoration: line-through; } /* struck through; the page says it in words too */
.sf-here { display: inline-flex; align-items: center; gap: 4px; font-weight: 500; }
.sf-sep { display: inline-flex; color: var(--ink-3); }
/* The reports and what holds shipping: rows between lines, never cards inside the card */
.sf-problems { display: grid; margin: 0; padding: 0; list-style: none; }
.sf-problem { padding: 12px 0; border-top: 1px solid var(--line); }
.sf-problem:first-child { border-top: 0; padding-top: 2px; }
.sf-problem-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 10px; }
.sf-problem-type { font-weight: 600; overflow-wrap: anywhere; }
.sf-problem-meta { margin-top: 2px; font-size: 14px; color: var(--muted-2); }
.sf-problem-reply { margin-top: 10px; padding: 10px 12px; border-radius: 12px; background: var(--run-bg); }
.sf-problem-reply-label { margin-bottom: 2px; font-size: 14px; font-weight: 600; color: var(--run-ink); }
.sf-problem-text { white-space: pre-line; overflow-wrap: anywhere; } /* what was typed keeps its line breaks */
.sf-note + .sf-problems { margin-top: 4px; } /* the list of what holds shipping, under its sentence */
/* The machine of the work, in the bar right above the start button (map P6; W2 UX gate, UX-3). With a machine from last
   time it is one line (the name it will record, and the way to change it) that opens into the options; with none the
   options are open under a line that asks. The options are a seg: each whole option is its radio, filled when chosen,
   three in a row on a phone, so that the bar stays short while it asks. */
.sf-machine > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 48px;
  list-style: none; cursor: pointer;
}
.sf-machine > summary::-webkit-details-marker { display: none; }
.sf-machine[open] > summary { margin-bottom: 8px; }
.sf-machine-now, .sf-machine-one { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; margin: 0; overflow-wrap: anywhere; }
.sf-machine-label { color: var(--muted-2); font-size: 15px; font-weight: 600; }
.sf-machine-name { font-weight: 700; }
.sf-label .sf-machine-name { color: var(--ink); font-size: 17px; text-align: right; }
.sf-machine-ask { color: var(--warn); font-size: 15px; font-weight: 600; }
.sf-machine-change { color: var(--brand); font-size: 15px; font-weight: 700; text-align: right; text-decoration: underline; text-underline-offset: 3px; }
.sf-machine-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 140px), 1fr)); gap: 8px; margin-top: 10px; }
.sf-machine-opt {
  display: flex; align-items: center; gap: 10px; min-height: 56px; padding: 8px 12px;
  border: 2px solid var(--line-strong); border-radius: var(--r-ctl); font-weight: 600; cursor: pointer;
}
.sf-machine-opt input { flex: none; width: 22px; height: 22px; margin: 0; accent-color: var(--go); }
.sf-machine-opt:has(input:checked) { border-color: var(--go); background: var(--run-bg); }
.sf-machine-opt:has(input:focus-visible) { outline: 3px solid var(--focus); outline-offset: 2px; }
.sf-bar .sf-machines { display: grid; gap: 8px; min-width: 0; }
.sf-bar .sf-machine-list { grid-template-columns: repeat(auto-fill, minmax(min(100%, 96px), 1fr)); margin-top: 0; }
.sf-bar .sf-machine-opt { position: relative; justify-content: center; padding: 6px 8px; text-align: center; line-height: 1.3; }
.sf-bar .sf-machine-opt input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.sf-bar .sf-machine > summary { min-height: 44px; }

/* What a press came to, and what stands in the way of a release. It says so in words; the colour only agrees. */
.sf-notice { margin: 0; padding: 12px 14px; border-radius: 14px; font-size: 16px; }
.sf-notice-warn { background: var(--warn-bg); color: var(--warn); font-weight: 600; }
.sf-notice-ok { display: grid; gap: 2px; background: var(--ok-bg); color: var(--run-deep); }
.sf-notice-title { display: flex; align-items: center; gap: 8px; margin-bottom: 2px; font-family: var(--font-display); font-size: 19px; font-weight: 700; }
.sf-notice-note { font-size: 14px; }
.sf-missing { margin: -6px 0 0; padding: 0 0 0 38px; font-size: 15px; color: var(--ink); }
.sf-missing li + li { margin-top: 4px; }

/* The bar at the bottom of a floor task page (the W1 action bar, kept in sight on a phone): the status in a line, then
   the one main button with the smaller help beside it. In Burmese the long words of help go under the main button,
   still 64px. */
.sf-bar { gap: 6px; }
.sf-bar form { margin: 0; }
.sf-status { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin: 0; color: var(--muted-2); font-size: 14px; font-weight: 600; }
.sf-status.run { color: var(--run-ink); }
.sf-status-link { /* a held shipping step, QC's first pieces left: the bar leads to the list, a thumb high */
  display: inline-flex; align-items: center; min-height: 44px; color: var(--warn); text-decoration: underline;
}
.sf-bar .action-bar-acts { align-items: stretch; }
.sf-bar .action-bar-acts > .sf-start, .sf-bar .action-bar-acts > .sf-main { flex: 1 1 56%; min-width: 0; }
/* The help is the smaller one: its icon over its words, so that "report a problem / ask for help" keeps whole words
   in two lines beside the main button on a 360 px phone. */
.sf-bar .action-bar-acts > .sf-help { flex: 1 1 36%; min-width: 0; padding: 6px 8px; font-size: 14px; line-height: 1.25; }
.sf-help .sf-btn-in { flex-direction: column; gap: 2px; }
.sf-screen:lang(my) .sf-bar .action-bar-acts > .sf-help { flex-basis: 100%; font-size: 15px; line-height: 1.6; }
.sf-screen:lang(my) .sf-help .sf-btn-in { flex-direction: row; gap: 8px; }
.sf-start { display: grid; }
.sf-why-off { margin: 0; color: var(--warn); font-size: 14px; font-weight: 600; text-align: center; }
/* The bar sits at the foot of the screen, also under a short page (the screen is a column as tall as the window), so
   that what floats right above it (the undo toast) never lies on it. */
.sf-screen > .sf-bar { margin-top: auto; }
@media (min-width: 1024px) {
  /* A floor page keeps its bar in sight on a desk too (a tablet on its side is one): at the foot of the column. */
  .sf-screen .action-bar { position: sticky; bottom: 0; z-index: 20; margin: auto 16px 16px; box-shadow: var(--pop-shadow); }
  .sf-bar .action-bar-acts > .btn { width: auto; }
}
/* The start that can still be taken back, for 300 seconds: a toast right above the bar at every width, over the bar's
   height (--sf-bar-h, measured by floor/job.html) and on a desk over the 16px under the bar as well, so that it never
   lies on the hand-off or on help (W2 review, I-2: on a desk it lay on the middle of the hand-off button). On a desk it
   stands over the bar's column, the side menu left out. */
.sf-undo { gap: 4px; padding: 6px 8px 6px 14px; }
.sf-undo form { margin: 0; }
.sf-undo .btn-text { min-height: 48px; color: #ffffff; }
.sf-undo .btn-text:hover { background: rgba(255, 255, 255, 0.12); color: #ffffff; }
.sf-screen .sf-undo { bottom: calc(var(--sf-bar-h, 150px) + 12px); }
/* As wide as its words, up to 360px: left at the middle, it was held to half the screen, five Burmese lines (UX-9). */
.sf-undo { width: max-content; max-width: min(360px, calc(100vw - 32px)); }
@media (min-width: 1024px) {
  .sf-screen .sf-undo { bottom: calc(var(--sf-bar-h, 150px) + 16px + 12px); left: calc(var(--side-w) + (100% - var(--side-w)) / 2); }
}

/* --- the head of a floor task page that has no dark card (the hand-off, the report): the job, once --- */
.sf-head { display: grid; gap: 2px; }
.sf-head-no, .sf-head-title { font-family: var(--font-display); font-size: 24px; font-weight: 700; line-height: 1.3; }
.sf-head-sub, .sf-top-sub { margin: 0; color: var(--muted-2); font-size: 15px; overflow-wrap: anywhere; }
.sf-head-sub .id { color: var(--ink); }

/* --- the hand-off confirm (floor/handoff_confirm.html): where the whole job goes, large, in the middle --- */
.sf-body-fill { display: flex; flex-direction: column; flex: 1; gap: 14px; }
.sf-unchecked-box { margin: 0; }
.sf-unchecked-box .callout-body { display: grid; gap: 8px; }
.sf-unchecked-box .sf-label { color: inherit; }
.sf-unchecked { margin: 0; padding: 0 0 0 22px; color: var(--ink); font-size: 17px; font-weight: 600; }
.sf-unchecked li + li { margin-top: 4px; }
.sf-dest {
  flex: 1 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  padding: 24px 16px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); text-align: center;
}
.sf-dest-job { margin-bottom: 6px; color: var(--muted-2); font-size: 15px; overflow-wrap: anywhere; }
.sf-dest-job .id { color: var(--ink); }
.sf-dest-hint { font-size: 16px; font-weight: 600; color: var(--muted-2); }
.sf-dest-from {
  max-width: 100%; padding: 4px 12px; border-radius: 10px; background: var(--soft);
  font-size: 17px; font-weight: 600; color: var(--muted-2); overflow-wrap: anywhere;
}
.sf-dest-arrow { display: flex; color: var(--ink-3); }
.sf-dest-arrow .sf-ico { width: 32px; height: 32px; }
.sf-dest-to {
  max-width: 100%; font-family: var(--font-display); font-size: 36px; font-weight: 700; line-height: 1.2;
  color: var(--ink); overflow-wrap: anywhere;
}
.sf-dest-last { max-width: 26ch; font-family: var(--font-display); font-size: 22px; font-weight: 700; line-height: 1.35; }
.sf-dock-dest {
  display: flex; align-items: center; gap: 8px; min-width: 0; margin: 0;
  font-family: var(--font-display); font-size: 20px; font-weight: 700; line-height: 1.3; overflow-wrap: anywhere;
}
.sf-dock-dest .sf-ico { flex: none; color: var(--ink-3); }

/* --- the problem report (floor/problem_new.html, problem_sent.html): the stacked form of the round-2 mockup, one big
   option for each topic, an optional note, an optional photo; the bar says who it goes to, and why it waits. --- */
.sf-form { display: flex; flex: 1; flex-direction: column; margin: 0; }
.sf-opts { display: grid; gap: 10px; margin-top: 10px; }
.sf-opt { /* a soft option inside the form's card, not a card in a card; the 2px line comes when it is picked (UX-7) */
  display: flex; align-items: center; gap: 12px; min-height: 58px; padding: 10px 14px;
  border: 2px solid transparent; border-radius: 14px; background: var(--soft);
  font-size: 17px; font-weight: 500; cursor: pointer;
}
/* The radio button is the dot: a ring that fills in when the topic is chosen. The option says so with its colour too. */
.sf-opt input {
  -webkit-appearance: none; appearance: none; flex: none; width: 22px; height: 22px; margin: 0;
  border: 2px solid var(--ink-3); border-radius: 50%; background: transparent;
}
.sf-opt input:checked { border: 7px solid var(--warn); }
.sf-opt:has(input:checked) { border-color: var(--amber); background: var(--warn-bg); }
.sf-opt:has(input:focus-visible) { outline: 3px solid var(--focus); outline-offset: 2px; }
.sf-field-label { margin-top: 16px; }
.sf-field-label.sf-first { margin-top: 0; }
.sf-text {
  display: block; width: 100%; min-height: 88px; margin-top: 8px; padding: 12px 14px;
  border: 1.5px solid var(--ctl-line); border-radius: var(--r-ctl); background: var(--card); color: var(--ink);
  font: inherit; font-size: 16px; resize: none;
}
.sf-select, .sf-input {
  display: block; width: 100%; min-height: var(--btn-h); margin-top: 8px; padding: 0 14px;
  border: 1.5px solid var(--ctl-line); border-radius: var(--r-ctl); background: var(--card); color: var(--ink);
  font: inherit; font-size: 17px;
}
.sf-fixed { margin: 8px 0 0; padding: 14px; border-radius: var(--r-ctl); background: var(--soft); font-size: 17px; font-weight: 600; overflow-wrap: anywhere; }
.sf-ng-qty { display: flex; align-items: center; gap: 12px; }
.sf-ng-qty .sf-input { flex: 1; min-width: 0; }
.sf-unit { flex: none; max-width: 40%; margin-top: 8px; font-size: 17px; font-weight: 600; color: var(--muted-2); overflow-wrap: anywhere; }
.sf-hint { margin: 6px 0 0; font-size: 14px; color: var(--muted-2); }
.sf-photo { display: grid; gap: 8px; margin-top: 14px; }
.sf-photo .btn:has(input:focus-visible) { outline: 3px solid var(--focus); outline-offset: 2px; } /* the input is hidden, so its button shows the focus */
.sf-photo-state {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 12px;
  color: var(--run-ink); font-weight: 600;
}
.sf-confirm-hint { margin: 0; color: var(--muted-2); font-size: 15px; }
.sf-to-role { color: var(--ink); font-family: var(--font-display); font-size: 18px; font-weight: 700; line-height: 1.3; }
.sf-screen:lang(my) :is(.sf-to-role, .sf-done .status-card-title) { line-height: 1.7; }
/* After a report is saved: the status card (W1), who it went to, the way back to the job and the way home */
.sf-done { padding: 22px 18px 18px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); }
.sf-done .status-card-actions { gap: 10px; }
.sf-sent-to { margin: 0 0 4px; }

/* --- the choice of station (floor/pick_station.html): a big button for each, the one used last marked --- */
.sf-pick { display: grid; gap: 10px; margin: 0; padding: 0; list-style: none; }
.sf-pick form { margin: 0; }
.sf-pick-btn { justify-content: space-between; text-align: left; }
.sf-pick-btn .sf-btn-in { flex: 1; justify-content: space-between; flex-wrap: wrap; gap: 6px 10px; }
.sf-pick-name { flex: 1 1 auto; }

/* ===== The mobile home (home/_mobile.html): the approved look, kept; the settings group and the month's card added ===== */
.m-home { min-height: 100vh; min-height: 100dvh; background: var(--app-bg); color: var(--ink); }
.m-ico {
  flex: none; width: 24px; height: 24px;
  fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}

.m-hero {
  position: relative; overflow: hidden;
  /* 72px: room for the 48px the first card climbs; the sides keep clear of the notch and the rounded corners */
  padding: 10px max(20px, env(safe-area-inset-right)) 72px
    max(20px, env(safe-area-inset-left));
  background: linear-gradient(150deg, var(--hero-2) 0%, var(--hero) 70%); /* the approved green hero below the light logo bar */
  color: #ffffff;
}
.m-hero::before { /* the arc of the logo, in its amber, held inside the header and well clear of the logo */
  content: ""; position: absolute; top: -120px; right: -96px; width: 280px; height: 280px;
  border: 34px solid var(--amber); border-radius: 50%; opacity: 0.28; pointer-events: none;
}
.m-hero > * { position: relative; }
.m-hero-bar {
  display: flex; align-items: center; gap: 12px; min-height: calc(71px + env(safe-area-inset-top));
  padding: calc(10px + env(safe-area-inset-top)) calc(104px + max(20px, env(safe-area-inset-right))) 10px
    max(20px, env(safe-area-inset-left));
  border-bottom: 3px solid var(--brand); background: var(--card); color: var(--ink);
}
/* R-UX-26: the full-colour logo, unaltered on white, with clear space beside the account controls. */
.m-brand { display: flex; align-items: center; margin: 0; padding: 6px 12px 6px 0; }
.m-brand img { display: block; width: auto; height: 26px; }
.m-hero .m-greet {
  margin: 16px 0 2px; color: #ffffff;
  font-family: var(--font-head); font-size: 26px; font-weight: 700; line-height: 1.3; letter-spacing: -0.01em;
}
.m-who { margin: 0; color: #ffffff; font-size: 15px; font-weight: 500; overflow-wrap: anywhere; } /* R-UX-26: at least 5:1, including over the decorative arc */
.m-hero :focus-visible { outline-color: #ffffff; } /* the blue ring would be lost on the green */

.m-body {
  position: relative; display: grid; gap: 14px; margin-top: -48px;
  padding: 0 max(16px, env(safe-area-inset-right)) 20px max(16px, env(safe-area-inset-left));
}
.m-card, .m-tiles {
  border-radius: 18px; background: var(--surface);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.06);
  box-shadow: 0 8px 24px color-mix(in srgb, var(--hero) 10%, transparent),
    0 1px 3px color-mix(in srgb, var(--hero) 8%, transparent); /* the shadow of the green, where color-mix is known */
}
.m-card { min-width: 0; padding: 16px; }
.m-home .m-card-title {
  margin: 0 0 10px; color: var(--brand); font-family: var(--font-head); font-size: 16px; font-weight: 700;
  line-height: 1.4;
}
.m-job { display: grid; gap: 2px; margin: 0 0 12px; color: var(--ink); text-decoration: none; }
.m-job-no {
  font-family: var(--font-head); font-size: 22px; font-weight: 700; line-height: 1.3; overflow-wrap: anywhere;
}
.m-job-meta { color: var(--ink-2); font-size: 15px; overflow-wrap: anywhere; }
.m-clock {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px;
  margin: 0 0 12px; padding: 10px 14px; border-radius: 12px;
  background: var(--run-soft); color: var(--run-deep); font-weight: 600;
}
.m-clock-n { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }
.m-actions { display: grid; gap: 10px; }
.m-btn { min-height: 64px; }
.m-empty { margin: 0; color: var(--ink-2); font-weight: 600; }

.m-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.m-stat {
  display: grid; align-content: start; gap: 4px; min-width: 0; min-height: 84px; padding: 10px 10px 12px;
  border-radius: 14px; background: var(--app-bg); color: var(--ink); text-decoration: none;
  transition: transform 120ms ease-out;
}
.m-stat:active { transform: scale(0.97); }
.m-stat-n {
  font-family: var(--font-head); font-size: 28px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums;
}
.m-stat-label { color: var(--ink-2); font-size: 13px; font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; }
.m-stat-late { background: var(--late-bg); }
.m-stat-late .m-stat-n { color: var(--late); }
.m-stat-warn { background: var(--today-bg); }
.m-stat-warn .m-stat-n { color: var(--today); }

.m-tiles {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px 6px;
  margin: 0; padding: 18px 8px 16px; list-style: none;
}
.m-tile {
  display: grid; justify-items: center; align-content: start; gap: 6px; min-width: 0;
  color: var(--ink); font-size: 13px; font-weight: 500; line-height: 1.3; text-align: center; text-decoration: none;
}
.m-tile-ico {
  position: relative; display: grid; place-items: center; width: 54px; height: 54px; border-radius: 16px;
  transition: transform 120ms ease-out;
}
.m-tile:active .m-tile-ico { transform: scale(0.94); }
.m-tile-ico .m-ico { width: 26px; height: 26px; }
/* The tints of the buttons: the brand's green for a page of work, a neutral slate for a page to look at. Amber is the
   "now" of the app only, and blue no colour of an action any more (D2), so no button wears either. */
.m-tone-g { background: var(--soft); background: color-mix(in srgb, var(--brand) 12%, var(--card)); color: var(--brand); }
.m-tone-s { background: var(--chip-bg); color: var(--ink-2); }
.m-badge {
  position: absolute; top: -7px; right: -9px; display: grid; place-items: center;
  min-width: 24px; height: 24px; padding: 0 6px; border: 2px solid #ffffff; border-radius: 12px;
  background: var(--late); color: #ffffff; font-size: 12px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}
/* The settings group of an admin's phone home (R-UX-12): a card of its own after the buttons of the work, in four
   columns as they are; its words are short words of their own, and a long name (FlowAccount) may wrap. */
.m-admin .m-card-title { margin-bottom: 14px; }
.m-admin-tiles { /* four columns, as the buttons above it (UX-11); a long name of one word (FlowAccount) may break */
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px 6px; margin: 0; padding: 0 0 2px; list-style: none;
}
.m-admin-tiles .m-tile-label { overflow-wrap: anywhere; }
/* The number of the month, apart from the numbers of today, under the month it counts */
.m-month .m-stats { grid-template-columns: minmax(0, 1fr); }
.m-month .m-stat { min-height: 0; grid-template-columns: auto minmax(0, 1fr); align-items: center; column-gap: 12px; }

.m-tabbar { /* the places it has share it in equal parts (five, or three), so that none of them is empty */
  position: fixed; right: 0; bottom: 0; left: 0; z-index: 20;
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); align-items: end;
  padding: 6px max(4px, env(safe-area-inset-right)) calc(6px + env(safe-area-inset-bottom))
    max(4px, env(safe-area-inset-left));
  border-top: 1px solid var(--line); background: var(--surface);
}
.m-tab {
  display: grid; justify-items: center; align-content: end; gap: 2px; min-width: 0; min-height: 52px; padding: 4px 2px;
  color: var(--ink-2); font-size: 13px; font-weight: 600; line-height: 1.25; text-align: center; text-decoration: none;
}
.m-tab > span:last-child {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; overflow-wrap: anywhere;
}
.m-tab[aria-current="page"] { color: var(--brand); }
.m-scan { color: var(--brand); }
.m-scan-ring {
  display: grid; place-items: center; width: 58px; height: 58px; margin-top: -26px; /* raised out of the bar */
  border: 4px solid var(--surface); border-radius: 50%; background: var(--brand); color: #ffffff;
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.22);
  box-shadow: 0 6px 14px color-mix(in srgb, var(--brand) 30%, transparent);
}
.m-scan-ring .m-ico { width: 26px; height: 26px; }
.m-home-always { padding-bottom: calc(96px + env(safe-area-inset-bottom)); } /* the bar is drawn at every width there */

/* One home for each width: from 1024 px the desk (the numbers and what waits, beside the side menu), under it the
   mobile home over the whole width of the screen, and room at the bottom for the bar that is fixed there. The station
   home is drawn at every width (m-home-always). */
@media (min-width: 1024px) {
  .m-home:not(.m-home-always) { display: none; }
}
@media (max-width: 1023.98px) {
  .desk-home { display: none; }
  .home-page .admin { max-width: none; padding: 0; }
  .m-home { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
}
.m-hero .m-greet:lang(my), .m-home .m-card-title:lang(my), .m-stat-label:lang(my), .m-tile:lang(my),
.m-tab:lang(my) { line-height: 1.8; }
.m-word { white-space: nowrap; }
.m-stats-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* ===== The office home on a desk (office/home.html, P1): the numbers of the phone as tiles, and what waits now ===== */
@media (min-width: 1024px) { .desk-home { display: grid; gap: 16px; } }
.desk-home .page-head { margin: 4px 0 0; }
.desk-home .kpi-row { margin: 0; }
.sf-now .list { margin: 0 -18px -16px; }
.sf-now .list-row { padding: 12px 18px; }
.sf-now .list-row-trail .pill { font-size: 14px; }
.desk-work .m-job { margin: 0; }

/* ===== "Me" (home/me.html, P5 settings): who the account is, its language, its LINE, the menu as rows ===== */
.me-page { max-width: 560px; }
.me-page .page-head { margin-bottom: 14px; }
.me-page .card + .card, .me-page .card + .me-menu { margin-top: 14px; }
.me-roles { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; }
.me-roles .pill { font-size: 14px; }
.me-page .me-label { margin: 0; color: var(--muted-2); font-family: var(--font); font-size: 14px; font-weight: 600; } /* not .admin h2's */
.me-lang { display: flex; flex-wrap: wrap; gap: 4px; margin: 0; padding: 4px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--soft); }
.me-lang button {
  -webkit-appearance: none; appearance: none; flex: 1 1 0; min-width: 0; min-height: 44px; padding: 0 12px;
  border: 0; border-radius: var(--r-pill); background: transparent; color: var(--muted-2);
  font: inherit; font-size: 15px; font-weight: 700; cursor: pointer;
}
.me-lang button[aria-pressed="true"] { background: var(--hero); color: #ffffff; }
.me-lang button:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
/* The LINE row (R-P5-16): where the account stands, in one line; the OA's green button and "check again" under it. */
.me-line { display: grid; gap: 10px; }
.me-line-state { display: flex; align-items: flex-start; gap: 8px; margin: 0; font-size: 15px; font-weight: 600; overflow-wrap: anywhere; }
.me-line-state.is-ok { color: var(--muted-2); font-weight: 500; } /* quiet: nothing to do */
.me-line-state.is-ok .ico { flex: none; width: 20px; height: 20px; margin-top: 2px; color: var(--ok); }
.me-line-acts { display: grid; gap: 8px; }
.me-line-acts form { margin: 0; }
.me-line-acts .btn { width: 100%; }
.me-line-hint { margin: 0; color: var(--muted-2); font-size: 14px; }
.me-line-busy { display: inline-flex; align-items: center; gap: 8px; } /* "check again" on its way to LINE */
.me-line-busy .sf-spin { width: 18px; height: 18px; }
.me-menu { margin-top: 14px; }
.me-menu > h2 { margin: 0 0 8px; color: var(--muted-2); font-family: var(--font); font-size: 14px; font-weight: 600; }
.me-page .side-nav { gap: 12px; }
.me-page .nav-group { padding: 6px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); }
.me-page .nav-group-title { margin: 6px 0 2px; }
.me-page .side-nav a { min-height: 52px; padding: 8px 12px; font-size: 16px; }
.me-page .side-nav a .ico { width: 22px; height: 22px; color: var(--brand); opacity: 1; }
.me-page .side-nav a[aria-current="page"] .ico { color: #ffffff; }

/* ===== Scan (home/scan.html, R-UX-4): the camera in the page, and the job number typed, always ===== */
.scan-page { display: grid; gap: 14px; max-width: 560px; }
.scan-page .page-head { margin: 0; }
.scanner { padding: 14px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); }
.scan-view { position: relative; overflow: hidden; border-radius: 14px; background: var(--hero); aspect-ratio: 4 / 3; }
.scan-view video { display: block; width: 100%; height: 100%; object-fit: cover; }
/* The square to hold the QR in, in the middle of the picture (a short box on a phone, so the typed number stays in sight) */
.scan-frame {
  position: absolute; top: 50%; left: 50%; width: 58%; aspect-ratio: 1; transform: translate(-50%, -50%);
  border: 3px solid rgba(255, 255, 255, 0.9); border-radius: 18px; pointer-events: none;
}
.scan-idle { position: absolute; inset: 0; display: grid; place-items: center; padding: 16px; }
.scan-wait { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 10px; color: #ffffff; font-weight: 600; }
.scan-idle .btn { width: auto; min-width: 200px; }
.scan-hint { margin: 0; color: var(--muted-2); font-size: 15px; }
.scan-state { margin: 0; font-weight: 600; }
.scan-state.is-bad { color: var(--late); }
.scan-state.is-ok { color: var(--run-ink); }
.scan-state.is-warn { color: var(--warn); }
/* A camera that cannot read leads to the typed number: the line is a link the height of a thumb (W2 review, m4). */
.scan-to-typed { display: inline-flex; align-items: center; min-height: 44px; color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.scan-fallback { display: grid; gap: 12px; }
.scan-fallback .btn { width: 100%; }
.scan-form-hint { font-weight: 500; } /* the form of a job number, after what was wrong with the one typed */
/* A desk: the camera no wider than it needs (it filled the column, about 950 px, and pushed the typed number out of the
   first screen), with the typed number under it, where the camera's lines say it is (UX-10). */
@media (min-width: 1024px) { .app-main > .scan-page { max-width: 520px; } }

/* ===== The bell's list (home/alerts.html, P2d feed): rows by day, each row one link ===== */
.alerts-page { max-width: 560px; }
.alerts-page .page-head { margin-bottom: 14px; }
.alerts-note { margin: 0 0 14px; }
.alerts-friend { display: grid; gap: 12px; }
.alerts-friend > p { margin: 0; font-weight: 600; }
.alerts-friend form { margin: 0; }
.alerts-seen { margin: 0; }
.alert-list { margin: 0; padding: 0; list-style: none; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); overflow: hidden; }
.alert-day { margin: 0; padding: 12px 16px 6px; background: var(--soft); color: var(--muted-2); font-size: 13px; font-weight: 700; }
.alert-row { border-top: 1px solid var(--line); }
.alert-open { min-height: 56px; padding: 12px 16px; align-items: flex-start; }
.alert-open:hover { background: var(--soft); }
.alert-ico { position: relative; display: grid; flex: none; place-items: center; width: 36px; height: 36px; border-radius: 12px; background: var(--soft); color: var(--muted-2); }
.alert-ico.is-problem { background: var(--warn-bg); color: var(--warn); }
.alert-ico.is-late { background: var(--late-bg); color: var(--late); }
.alert-dot { position: absolute; top: -3px; right: -3px; width: 12px; height: 12px; border: 2px solid var(--card); border-radius: 50%; background: var(--late); }
.alert-title { overflow-wrap: break-word; } /* its job number (.id) stays whole */
.alert-meta { display: flex; flex-wrap: wrap; gap: 2px 8px; }
.alert-time { font-variant-numeric: tabular-nums; }
.alert-state { margin-top: 4px; }
.alert-status {
  display: inline-block; max-width: 100%; padding: 2px 10px; border-radius: 8px;
  background: var(--chip-bg); color: var(--ink-2); font-size: 14px; font-weight: 600; overflow-wrap: anywhere;
}
.alert-status[data-status="sent"] { background: var(--run-soft); color: var(--run-deep); }
.alert-status[data-status="not_friend"], .alert-status[data-status="not_bound"], .alert-status[data-status="quota"],
.alert-status[data-status="folded"] { background: var(--today-bg); color: var(--today); }
.alert-status[data-status="failed"] { background: var(--late-bg); color: var(--late); }
/* A due date and an earliest delivery are each one piece that goes to the next line whole, never broken from its time */
.alert-when { display: inline-block; max-width: 100%; font-variant-numeric: tabular-nums; }
.alert-new { /* soft: the red dot on the icon says "unseen"; red words on every row said "late" (W2 UX gate, UX-6) */
  display: inline-block; padding: 0 8px; border-radius: 6px; background: var(--soft); color: var(--ink);
  font-size: 14px; font-weight: 700; white-space: nowrap; vertical-align: 1px;
}

/* ===== The marks of a job's QT on the office pages (W3's pages draw them; the rules stay here as they were) ===== */
/* A job opened without a QT (plan 4, Task 11): a word in a dashed outline, neutral on purpose. */
.sf-badge-noqt { border-style: dashed; border-color: var(--ink-2); background: var(--surface); color: var(--ink-2); }
/* A job whose QT changed after it was opened (plan 4, Task 12; Q24): brown while the QT only changed, red once
   FlowAccount rejected or deleted it. */
.sf-badge-qtchanged { border-color: var(--today); background: var(--today-bg); color: var(--today); }
.sf-badge-qtgone { border-color: var(--late); background: var(--late-bg); color: var(--late); }
/* A QT published before the cut-over day (R-P4-27): a quiet word in a dashed outline. */
.sf-badge-before { border-style: dashed; border-color: var(--line-strong); background: var(--surface); color: var(--ink-2); }
.sf-badge-typed { border-color: var(--help-line); background: var(--help-bg); color: var(--help); }
.sf-badge-removed { border-color: var(--late); background: var(--late-bg); color: var(--late); }
.sf-badge-qtline { border-color: var(--line-strong); background: var(--surface); color: var(--ink-2); }
.sf-badge-linked { border-color: var(--go); background: var(--run-soft); color: var(--run-deep); }
/* ===== end W2 ===== */

/* ===== W3 office-jobs+qt+print-workorder (owned by W3) ===== */

/* The release to production on a job's page: one line for each of the four checks, with what is missing under it */
.release-checks { margin: 0 0 16px; padding: 0; list-style: none; }
.release-check {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; padding: 10px 0; border-bottom: 1px solid var(--line);
}
.release-check:last-child { border-bottom: 0; }
.release-what { font-weight: 500; }
.release-state { color: var(--ink-2); font-size: 15px; }
.release-check[data-state="todo"] .release-what, .release-check[data-state="todo"] .release-state { color: var(--ink); font-weight: 700; }
.release-missing { flex-basis: 100%; }
.release-sheet { margin: 0 0 8px; }
.release-form { max-width: 520px; margin-top: 12px; }
.release-form .hint { margin-bottom: 0; }
.release-sheet-forms { max-width: 520px; margin-top: 12px; } /* one form for each sheet status, side by side */
.release-own-check { margin: 12px 0 0; color: var(--run-ink); font-weight: 600; } /* this account checked the files */
.release-blocked { margin-top: 12px; } /* why this account cannot release, where the button would be */
/* Why the work order cannot be printed yet, said where its button would be */
.print-blocked { align-self: center; color: var(--ink-2); font-weight: 600; }
/* One item of the items editor: its fields in a grid, then the buttons that move it */
.item-card { display: grid; gap: 10px; padding: 12px; border: 1px solid var(--line); border-radius: 12px; background: var(--bg); }
.item-fields { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 10px 12px; align-items: end; }
.item-f-part, .item-f-material { grid-column: span 4; }
.item-f-desc { grid-column: span 8; }
.item-f-thickness { grid-column: span 2; }
.item-f-qty, .item-f-unit { grid-column: span 3; }
.item-f-ops, .item-f-note { grid-column: span 6; }
.item-f-qc, .item-f-no-material { grid-column: 1 / -1; }
/* Each field keeps to its track, and its input to the field, whatever room the input asks for (a number input asks for
   some 20 characters): at 1280 px the thickness ran under the operations and the quantity under the unit. */
.item-fields > * { min-width: 0; }
.item-fields .field { grid-template-columns: minmax(0, 1fr); }
.item-fields .field input { width: 100%; min-width: 0; }
.item-card .row-tools { justify-content: flex-end; }
.drawing-table td { overflow-wrap: anywhere; } /* a long file name wraps instead of widening the table */
/* Its one column may be narrower than its fields would like (a file field, a long item name), and the fields keep to it,
   so that the page never scrolls sideways at 360 px (B-P3-2). */
.drawing-form {
  grid-template-columns: minmax(0, 1fr); max-width: 520px; margin-top: 20px; padding-top: 4px;
  border-top: 1px dashed var(--line-strong);
}
.drawing-form .field { min-width: 0; }
.drawing-form .field :is(input, select) { min-width: 0; max-width: 100%; }
.drawing-form h3 { margin: 12px 0 0; }
.drawing-copy { max-width: 520px; margin-top: 20px; } /* the form that brings over the drawings of the round before */
.pending-list { margin: 8px 0 0; padding-left: 20px; } /* the same on the office page */
.pending-list li + li { margin-top: 4px; }
.move-back-form { max-width: 520px; margin-top: 12px; }
.move-back-plan { margin: 10px 0 0; font-weight: 600; } /* what the move back will do, or why it cannot be done yet */

/* The quotations to open (templates/office/qt_list.html) and the page of one (qt_detail.html). The tables are the other
   office lists' and scroll sideways inside their own frame on a phone, never the page. The status of a QT is in words,
   coloured to agree: green when a job can be opened from it, the brown of a warning while it waits for approval or its
   status is unknown, the red of being late when it was not approved or was deleted; the reason it cannot be opened is
   under it. A job that only typed the QT's number, and a line FlowAccount dropped, wear a badge that says so. */
.qt-pulled { margin: 0 0 14px; }
.qt-tools { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 16px; margin: 0 0 16px; }
.qt-search { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 12px; flex: 1 1 420px; min-width: 0; margin: 0; }
.qt-search .field { flex: 1 1 260px; min-width: 0; }
.qt-search .field input { width: 100%; min-width: 0; }
.qt-status-open { color: var(--go); }
.qt-status-awaiting, .qt-status-unknown { color: var(--help); }
.qt-status-rejected, .qt-status-deleted { color: var(--late); }
.qt-why { display: block; max-width: 22rem; margin-top: 2px; }
.qt-table th[scope="row"] a, .qt-table .qt-date { white-space: nowrap; }
.qt-wait-table th[scope="row"] .sf-badge { display: flex; width: max-content; max-width: 16rem; margin-top: 6px; }
.qt-table tr.is-done .qt-progress { color: var(--run-ink); font-weight: 600; }
.qt-typed p { margin: 0; }
.qt-typed .chips a { color: var(--send); font-weight: 700; text-underline-offset: 3px; }
.qt-grand { font-weight: 700; }
/* The lines: the text of each (the header of its row), what it splits into under it, the quantities, and for the picker a
   box to tick and the quantity to open. The box sits in a 44 px target. A line that more was opened of than the QT has
   says so in a word beside the number, in red. A width goes on the wrapper inside a cell, never on the cell itself. */
.qt-lines-table tbody th.qt-item { font-weight: 500; }
.qt-item-body { min-width: 18rem; max-width: 34rem; }
.qt-text { display: block; overflow-wrap: anywhere; }
.qt-split { display: flex; flex-wrap: wrap; gap: 2px 16px; margin: 6px 0 0; font-size: 14px; }
.qt-split div { display: flex; flex-wrap: wrap; gap: 0 6px; }
.qt-split dt { color: var(--ink-2); font-weight: 500; }
.qt-split dd { margin: 0; font-weight: 700; overflow-wrap: anywhere; }
.qt-lines-table .sf-badge { margin-top: 6px; }
.qt-line-warn { margin: 6px 0 0; color: var(--help); font-size: 14px; font-weight: 600; }
.qt-lines-table tr.is-removed > * { background: var(--bg); }
.qt-lines-table tr.is-removed .qt-text { color: var(--ink-2); }
.qt-lines-table .qt-over { color: var(--late); font-weight: 700; }
.qt-over-word { font-size: 14px; }
.qt-jobs a { white-space: nowrap; }
.data-table .qt-tick-col { width: 52px; padding-left: 8px; padding-right: 0; }
.qt-tick { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; cursor: pointer; }
.qt-tick input { width: 22px; height: 22px; margin: 0; accent-color: var(--send); }
.qt-qty {
  width: 7.5rem; min-height: 44px; padding: 0 10px;
  border: 1.5px solid var(--line-strong); border-radius: 10px;
  background: var(--surface); color: var(--ink); font: inherit; font-weight: 600; text-align: right;
}
.qt-pick-actions { margin-top: 14px; }

/* The work order (templates/print/workorder.html, PCF005): one A4 portrait sheet for each article.workorder, black and
   white and measured in mm, after the approved mock-up. The page box is a named one that only the sheet uses, so that
   printing any other page keeps the printer's own paper size. The sheet keeps inks of its own (--wo-*), those of the
   mock-up. On the screen the sheets stand one under the other on the page. */
@page workorder { size: A4; margin: 0 }
/* The bar over the paper: its title and the one print button, as wide as the sheet on a desk (redesign W3, P8). */
.wo-head { max-width: calc(210mm + 48px); margin: 0 auto; padding: 16px 24px 0; }
@media (max-width: 719.98px) { .wo-head { padding: 12px 16px 0; } }
.wo-head .page-title { font-size: 22px; }
/* The way back to the job on a desk too: the foundation hides .app-bar-back from 1024 px, where the side menu is the
   way, and the bar over the paper has no menu; its desk margin under the name of the app lifts the name off the
   middle of the bar. Scoped to the work order (a foundation fix is in the W3 report). */
@media (min-width: 1024px) {
  .print-shell:has(.workorder-stage) .print-bar .app-bar-back { display: inline-flex; }
  .print-shell:has(.workorder-stage) .print-bar .app-brand { margin-bottom: 0; }
}
.workorder-stage { display: flex; flex-direction: column; align-items: safe center; gap: 28px; padding: 16px 24px 48px; overflow-x: auto; }
@media (max-width: 719.98px) { .workorder-stage { gap: 16px; padding: 12px 16px 32px; } }
/* Fitted to the width of a phone: the stage works out --wo-fit (1 on a desk, where the sheet fits as it is). */
.workorder-stage .workorder { zoom: var(--wo-fit, 1); }
.workorder {
  page: workorder;
  --wo-ink: #111214; --wo-ink-2: #44474c; --wo-ink-3: #6b6f75; --wo-hair: #8e9298; --wo-tint: #eff0ec;
  flex: none; display: flex; flex-direction: column; gap: 3mm;
  width: 210mm; min-height: 297mm; padding: 9mm 10mm 8mm;
  background: #ffffff; color: var(--wo-ink); box-shadow: 0 1px 2px rgba(0, 0, 0, .08), 0 8px 24px rgba(0, 0, 0, .10);
  font-family: var(--font); font-size: 8.6pt; line-height: 1.35; font-variant-numeric: tabular-nums;
  -webkit-print-color-adjust: exact; print-color-adjust: exact;
}
.workorder .wo-my, .workorder :lang(my) { font-family: "Noto Sans Myanmar", var(--font); }
.wo-lbl { display: block; font-size: 6.6pt; color: var(--wo-ink-2); line-height: 1.2; letter-spacing: 0.01em; }
.wo-lbl i { font-style: normal; color: var(--wo-ink-3); }
.wo-lbl-next { margin-top: 0.8mm; }
.wo-val { font-weight: 500; font-size: 9.4pt; }
.wo-none { color: var(--wo-ink-3); }
.wo-co, .wo-title h2, .wo-title span, .wo-trial, .wo-no { white-space: nowrap; }

/* The head of every sheet: the company and the title, and the box with the job number and its QR (27 mm) */
.wo-hd { display: grid; grid-template-columns: 1fr auto; gap: 4mm; align-items: stretch; }
.wo-hd-left { display: flex; flex-direction: column; justify-content: space-between; padding-bottom: 0.6mm; }
.wo-brand { display: flex; align-items: center; gap: 3mm; }
.wo-brand img { width: auto; height: 8.4mm; }
.wo-co { color: var(--wo-ink-2); font-size: 7pt; }
.wo-title { display: flex; align-items: baseline; gap: 3mm; }
.wo-title h2 { margin: 0; font-family: var(--font-head); font-size: 20pt; font-weight: 700; line-height: 1; letter-spacing: -0.01em; }
.wo-title span { color: var(--wo-ink-2); font-size: 8pt; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; }
.wo-trial { display: inline-block; padding: 0.4mm 1.8mm; border: 0.35mm solid var(--wo-ink); font-size: 7pt; font-weight: 700; }
.wo-box { display: grid; grid-template-columns: auto 27mm; gap: 3.4mm; align-items: center; padding: 2.4mm 2.8mm; border: 0.5mm solid var(--wo-ink); }
.wo-no { font-family: var(--font-head); font-size: 20pt; font-weight: 700; line-height: 1.05; }
.wo-scan { margin-top: 1.4mm; color: var(--wo-ink-2); font-size: 7pt; line-height: 1.45; }
.wo-scan b { color: var(--wo-ink); font-weight: 600; }
.wo-qr { width: 27mm; background: #ffffff; }
.wo-qr svg { display: block; width: 27mm; height: auto; shape-rendering: crispEdges; }
.wo-rule { border-top: 0.6mm solid var(--wo-ink); }
.wo-banner { display: flex; align-items: center; gap: 3mm; padding: 1.8mm 3mm; background: var(--wo-ink); color: #ffffff; font-size: 10pt; font-weight: 700; }
.wo-banner span { color: #d4d6d9; font-size: 8pt; font-weight: 500; }

/* The facts of the job, four to a row, the due date in reverse; and the reason of a remake job */
.wo-info { display: grid; grid-template-columns: 1.55fr 1fr 1fr 1.25fr; border: 0.3mm solid var(--wo-ink); }
.wo-info > div { min-height: 10.5mm; padding: 1.3mm 2mm 1.5mm; border-right: 0.2mm solid var(--wo-hair); border-bottom: 0.2mm solid var(--wo-hair); }
.wo-info > div:nth-child(4n) { border-right: 0; }
.wo-info > div:nth-last-child(-n+4) { border-bottom: 0; }
.wo-reason { grid-template-columns: 1fr 1fr 1fr 1.25fr; }
.wo-due { background: var(--wo-ink); color: #ffffff; }
.wo-due .wo-lbl, .wo-due .wo-lbl i { color: #d4d6d9; }
.wo-due .wo-val { font-family: var(--font-head); font-size: 13pt; font-weight: 700; line-height: 1.1; }

/* A section heading, with its hint on the right */
.wo-sec { display: flex; align-items: baseline; justify-content: space-between; gap: 3mm; margin: 0 0 1.2mm; }
.wo-sec h3 { margin: 0; font-size: 9.6pt; font-weight: 700; }
.wo-sec h3 i { margin-left: 1.4mm; color: var(--wo-ink-3); font-size: 7pt; font-style: normal; font-weight: 500; }
.wo-hint { color: var(--wo-ink-2); font-size: 7pt; }

/* The route: the steps in order, nothing to sign. A step away from the factory is grey, and so is the end of a remake
   job's route (where its pieces go), which is no station. */
.wo-route { display: flex; align-items: stretch; border: 0.3mm solid var(--wo-ink); }
.wo-step { position: relative; display: flex; flex: 1; flex-direction: column; gap: 0.3mm; padding: 1.4mm 1.6mm 1.5mm; }
.wo-step + .wo-step { border-left: 0.2mm solid var(--wo-hair); }
.wo-step + .wo-step::before {
  content: ""; position: absolute; top: 50%; left: -1.25mm; width: 2.2mm; height: 2.2mm; margin-top: -1.1mm;
  border-top: 0.25mm solid var(--wo-ink-2); border-right: 0.25mm solid var(--wo-ink-2); background: #ffffff; transform: rotate(45deg);
}
.wo-n { color: var(--wo-ink-3); font-size: 6.6pt; font-weight: 600; }
.wo-step b { font-size: 8.8pt; font-weight: 700; line-height: 1.15; }
.wo-step small { color: var(--wo-ink-2); font-size: 6.4pt; font-weight: 500; line-height: 1.25; }
.wo-step-out, .wo-step-end { background: var(--wo-tint); }

/* The items. The column widths are those of the mock-up. */
.wo-items { width: 100%; border: 0.3mm solid var(--wo-ink); border-collapse: collapse; }
.wo-items th {
  padding: 1mm 1.4mm; border: 0.2mm solid var(--wo-hair); background: var(--wo-tint);
  font-size: 6.9pt; font-weight: 600; line-height: 1.2; text-align: left; vertical-align: bottom;
}
.wo-items th i { display: block; color: var(--wo-ink-3); font-size: 6pt; font-style: normal; font-weight: 500; }
.wo-items td { height: 6.8mm; padding: 1mm 1.4mm; border: 0.2mm solid var(--wo-hair); vertical-align: middle; }
.wo-items .wo-num { text-align: right; }
.wo-items .wo-c { text-align: center; }
.wo-items .wo-part { font-weight: 600; }
.wo-items tfoot td { height: 5.6mm; background: var(--wo-tint); font-size: 7.6pt; font-weight: 600; }
.wo-items tfoot .wo-noprice { color: var(--wo-ink-2); font-weight: 500; }
.wo-col-no { width: 6mm; }
.wo-col-rev { width: 9mm; }
.wo-col-mat { width: 15mm; }
.wo-col-thick { width: 11mm; }
.wo-col-qty { width: 13mm; }
.wo-col-ops { width: 38mm; }
.wo-col-note { width: 19mm; }
.wo-fa { display: inline-block; padding: 0 1.2mm; border: 0.3mm solid var(--wo-ink); font-size: 6.4pt; font-weight: 700; line-height: 1.5; white-space: nowrap; }
.wo-remark { padding: 1.2mm 2mm 1.4mm; border: 0.3mm solid var(--wo-ink); }
.wo-items + .wo-remark { border-top: 0; }
.wo-remark .wo-val { font-size: 8.6pt; white-space: pre-line; }
.wo-cont { margin: 1.2mm 0 0; font-size: 7.6pt; font-weight: 600; text-align: right; } /* the job goes on on the next sheet (WO-3) */

/* The drawings (first sheet) beside the release and the linked PR (last sheet); either alone takes the whole width */
.wo-rel { display: grid; grid-template-columns: 1.15fr 1fr; border: 0.3mm solid var(--wo-ink); }
.wo-rel > div { padding: 1.5mm 2mm 1.7mm; }
.wo-rel > div + div { border-left: 0.2mm solid var(--wo-hair); }
.wo-rel > div:only-child { grid-column: 1 / -1; }
.wo-files { display: flex; flex-wrap: wrap; gap: 0.8mm 3mm; margin-top: 0.8mm; font-size: 8pt; }
.wo-files > span { white-space: normal; } /* a type of drawing may break between its Rev chips (WO-4)... */
.wo-rev { display: inline-block; margin-left: 0.6mm; padding: 0 1mm; border: 0.25mm solid var(--wo-ink-2); font-size: 7pt; line-height: 1.4; white-space: nowrap; } /* ...never inside one */

/* The last sheet: what to do with a defective piece (Thai and Burmese), and the room for the QC PASS stamp */
.wo-pair { display: grid; grid-template-columns: 1fr 52mm; gap: 3mm; }
.wo-howto { padding: 1.8mm 2.4mm 2mm; border: 0.6mm solid var(--wo-ink); }
.wo-howto h3 { margin: 0 0 1.2mm; font-size: 9.6pt; font-weight: 700; }
.wo-howto h3 .wo-my { margin-left: 1.6mm; color: var(--wo-ink-2); font-size: 7.4pt; font-weight: 400; }
.wo-howto ol { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2.4mm; margin: 0; padding: 0; list-style: none; }
.wo-howto li { display: grid; grid-template-columns: 5.4mm 1fr; gap: 1.4mm; align-items: start; font-size: 8pt; line-height: 1.3; }
.wo-howto li .wo-my { display: block; margin-top: 0.4mm; color: var(--wo-ink-2); font-size: 6.6pt; line-height: 1.55; }
.wo-k {
  display: flex; align-items: center; justify-content: center; width: 5.4mm; height: 5.4mm; border-radius: 50%;
  background: var(--wo-ink); color: #ffffff; font-size: 8pt; font-weight: 700;
}
.wo-fine { margin-top: 1.6mm; color: var(--wo-ink-2); font-size: 6.8pt; }
.wo-fine .wo-my { display: block; line-height: 1.55; }
.wo-qc { display: flex; flex-direction: column; gap: 1.2mm; padding: 1.6mm 2mm; border: 0.3mm solid var(--wo-ink); }
.wo-qc h3 { margin: 0; font-size: 9.2pt; font-weight: 700; }
.wo-qc .wo-fine { margin-top: 0; font-size: 6.6pt; line-height: 1.35; }
.wo-stamp {
  display: flex; flex: 1; align-items: center; justify-content: center; min-height: 18mm; border: 0.3mm dashed var(--wo-ink-2);
  color: var(--wo-ink-3); font-size: 7pt; text-align: center;
}
.wo-bottom { display: flex; flex-direction: column; gap: 3mm; margin-top: auto; }
.wo-ft { display: flex; justify-content: space-between; gap: 4mm; padding-top: 1.4mm; border-top: 0.2mm solid var(--wo-hair); color: var(--wo-ink-2); font-size: 6.6pt; }
.wo-ft b { color: var(--wo-ink); font-weight: 600; }

@media (max-width: 640px) {
  .item-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .item-f-part, .item-f-desc, .item-f-ops, .item-f-note { grid-column: 1 / -1; }
  .item-f-material, .item-f-thickness, .item-f-qty, .item-f-unit { grid-column: span 1; }
}

/* The open-a-job form filled in from a QT (plan 4, Task 9): the QT it comes from under the title, its number as text
   where the box would be (it cannot be changed), and on each item row the line of the QT it comes from, what is left
   to open of that line, and in the red of being late, in words, when the rows of the line come to more than that. */
.qt-from a { color: var(--send); font-weight: 700; text-underline-offset: 3px; }
.qt-locked-no {
  display: flex; align-items: center; min-height: 52px; margin: 0; padding: 0 14px;
  border: 1.5px dashed var(--line-strong); border-radius: 12px; background: var(--bg); font-weight: 700;
}
.item-qt { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin: 0; font-size: 14px; }
.item-qt-left { color: var(--ink-2); font-weight: 500; }
.item-qt-over { color: var(--late); font-weight: 700; }

/* Linking a job to a QT (plan 4, Task 10). On a job's page, the #qt section names the QT the job is linked to and the
   line each item comes from. The link page lists the QTs to choose from (the table of the QTs to open, with the QT the
   job is linked to now marked), then pairs each item of the job with a line of the chosen QT: the item on the left, the
   choice of line on the right, one under the other on a narrow screen, and in the red of being late, in words, when the
   items of a line come to more than it may hold. The edit form of a linked job shows its QT number as text, with why. */
.qt-linked-to { margin: 0 0 8px; font-weight: 500; }
.qt-linked-to a, .qt-link-now a, .qt-link-back a { color: var(--send); font-weight: 700; text-underline-offset: 3px; }
.qt-item-lines { display: grid; gap: 4px; margin: 0 0 12px; padding: 0 0 0 20px; color: var(--ink-2); }
.qt-link-now { margin: 0 0 16px; font-weight: 500; }
.qt-link-back { margin: -4px 0 16px; }
.qt-link-table tr.is-current > * { background: var(--run-bg); }
.qt-pairs { padding-bottom: 6px; }
.qt-pair-list { margin: 0; padding: 0; list-style: none; }
.qt-pair {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 8px 20px; align-items: start;
  padding: 12px 0; border-bottom: 1px solid var(--line);
}
.qt-pair:last-child { border-bottom: 0; }
.qt-pair-what { display: grid; gap: 2px; min-width: 0; align-self: center; }
.qt-pair-name { font-weight: 700; overflow-wrap: anywhere; }
.qt-pair-desc { color: var(--ink-2); font-size: 14px; overflow-wrap: anywhere; }
.qt-pair-qty { font-variant-numeric: tabular-nums; font-weight: 500; }
.qt-pair-choice { display: grid; gap: 4px; min-width: 0; }
.qt-pair-select {
  width: 100%; min-width: 0; min-height: 52px; padding: 0 14px;
  border: 1.5px solid var(--line-strong); border-radius: 12px; background: var(--surface); color: var(--ink);
  font: inherit; font-weight: 500;
}
.qt-pair-over { color: var(--late); font-size: 14px; font-weight: 700; }
.qt-link-form .qt-over-reason textarea { width: 100%; }
@media (max-width: 640px) {
  .qt-pair { grid-template-columns: minmax(0, 1fr); }
}

/* Linking a job to a QT, review round 1: a long QT or part number breaks inside the #qt section instead of making the
   page wider than a phone; the QT a job is linked to now is named in words on its row of the list to choose from; the
   hint under a locked QT number links to the page that links another. */
.qt-linked-to { overflow-wrap: anywhere; }
.qt-item-lines { min-width: 0; }
.qt-item-lines li { overflow-wrap: anywhere; }
.qt-link-table th[scope="row"] .sf-badge { margin-left: 6px; vertical-align: middle; }
.qt-locked-hint a { color: var(--send); font-weight: 700; text-underline-offset: 3px; }
.admin h1 .sf-badge-noqt { margin-left: 8px; vertical-align: middle; } /* beside the status and badges of a job */
.data-table .sf-badge-noqt { margin-left: 6px; vertical-align: middle; }
.qt-no-reason, .qt-suggest { margin: 0 0 10px; overflow-wrap: anywhere; }
.qt-no-reason .readonly-label { color: var(--ink-2); }
.qt-no-reason-text { white-space: pre-line; }
.admin h1 :is(.sf-badge-qtchanged, .sf-badge-qtgone) { margin-left: 8px; vertical-align: middle; }
.qt-change { margin: 0 0 14px; padding: 0 0 14px; border-bottom: 1px solid var(--line); }
.qt-change > p { margin: 0 0 10px; overflow-wrap: anywhere; }
.qt-change-mark { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
.qt-ack-form { margin: 0; }
.qt-changed .chips a { color: var(--send); font-weight: 700; text-underline-offset: 3px; white-space: nowrap; }
.qt-changed-table td .status { margin-left: 8px; }
.admin h1 .sf-badge-before { margin-left: 8px; vertical-align: middle; }
.qt-unacked { display: block; max-width: 22rem; margin-top: 4px; color: var(--today); font-size: 14px; font-weight: 600; }
.qt-unacked a, .qt-unacked-notice .chips a {
  color: var(--send); font-weight: 700; text-underline-offset: 3px; white-space: nowrap;
}
.qt-unacked-notice p { margin: 0; }

/* Plan 4, final fix wave (FIX-2). The change of a job's QT says, under its hint, what the QT says now where it is not
   the job (its customer, and the lines taken out, or with less than the job holds on them or another unit), then links
   the QT's page. On the mobile home a word of a button is drawn whole, so that its lines end only at a space (W7), and
   four numbers are laid out two by two rather than three and one alone (W8). */
.qt-change-lines { display: grid; gap: 4px; margin: 0 0 10px; padding-left: 20px; overflow-wrap: anywhere; }
.qt-change-see a { color: var(--send); font-weight: 700; text-underline-offset: 3px; }

/* Plan 4, final follow-up (FIX-4). The list of the QTs to open says under its search, in the grey of a hint, that the QTs
   dated before the cut-over day are not counted (R-P4-27), close to the tools it names and apart from the table. */
.qt-cutover-note { max-width: 72ch; margin: -4px 0 16px; }

/* Plan 4, last follow-up (FIX-5). Under what changed on a job's QT, the lines the QT can still open more of are a note
   in grey, apart from the changes: they say nothing changed on the line. The list of all the QTs (?all=1) says that it
   shows only the newest in the place and grey of the cut-over note (which that list never has). */
.qt-change-left {
  display: grid; gap: 4px; margin: 0 0 10px; padding-left: 20px; color: var(--ink-2); overflow-wrap: anywhere;
}
.qt-all-capped { max-width: 72ch; margin: -4px 0 16px; }

/* --- Redesign W3: what the pages of this fence share (.w3 is the root of each of them) ---------------------------
   The head of a page whose title holds its marks (a job's page: the number, then its status, due and badges, all in
   the one <h1>): the title in the display face, the marks as pills beside it. The due chip and the badges are the
   floor's macros (floor/_bits.html); on these pages they wear the one pill vocabulary of the redesign, whatever the
   floor's own look of them is, so the head reads as the approved draft's: tone by meaning, words always. */
/* User-entered names, references, units and notes may be arbitrarily long. Only .id system numbers stay nowrap. */
.w3 { min-width: 0; overflow-wrap: anywhere; }
.w3 :is(.page-head-main, .detail-grid > div, .field, .qt-split > div) { min-width: 0; }
.w3 .detail-grid dd { min-width: 0; overflow-wrap: anywhere; }
.w3 :is(.pill, .sf-chip, .sf-badge, .qt-status) { max-width: 100%; white-space: normal; }
.w3 .page-head { align-items: flex-start; }
.w3 .page-head-main > h1 {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin: 2px 0 0;
  font-family: var(--font-display); font-size: 26px; font-weight: 700; line-height: 1.25; letter-spacing: -0.01em;
}
.w3 .page-head-main > h1 > .id { margin-right: 4px; font-size: 30px; line-height: 1.15; }
.w3 h1 :is(.status, .pill, .sf-chip, .sf-badges) { margin: 0; font-size: 13px; vertical-align: baseline; }
.w3 .sf-chip, .w3 .sf-badge {
  display: inline-flex; align-items: center; gap: 6px; min-height: 0; padding: 2px 10px; border: 0;
  border-radius: var(--r-pill); font-family: var(--font); font-size: 13px; font-weight: 600; line-height: 1.5;
}
.w3 .sf-chip { white-space: normal; }
.w3 h1 :is(.pill, .sf-chip, .sf-badge) { max-width: 100%; white-space: normal; }
.w3 .sf-chip.ok { background: var(--soft); color: var(--muted-2); box-shadow: inset 0 0 0 1px var(--line); }
.w3 .sf-badges { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.w3 .sf-badge { background: var(--soft); color: var(--muted-2); box-shadow: inset 0 0 0 1px var(--line); }
.w3 :is(.sf-badge-behind_plan, .sf-badge-release_late, .sf-badge-removed, .sf-badge-qtgone, .sf-badge-rework_open, .sf-badge-recheck, .sf-badge-undecided) { background: var(--late-bg); color: var(--late); box-shadow: none; }
.w3 :is(.sf-badge-release_today, .sf-badge-waiting_sheet, .sf-badge-qtchanged) { background: var(--warn-bg); color: var(--warn); box-shadow: none; }
.w3 :is(.sf-badge-scrapped, .sf-badge-cancelled) { background: var(--idle-bg); color: var(--idle); box-shadow: none; }
/* The rush mark is the dark pill of the draft, with the reason it was typed with after the word, once. */
.w3 .sf-badge-rush { flex-direction: row; flex-wrap: wrap; max-width: 100%; background: var(--hero); color: #ffffff; box-shadow: none; white-space: normal; }
.w3 .sf-badge-why { font-weight: 500; opacity: 0.85; overflow-wrap: anywhere; }
.w3 .sf-badge-why::before { content: "\00B7"; margin-right: 6px; }
.w3 .page-sub { font-size: 14px; }
.w3 .notice { margin: 0 0 12px; }
.w3 .id { white-space: nowrap; }
/* A link that is an ID (a job, a QT) keeps the ID's weight and never breaks inside. */
.w3 a.id { color: var(--ink); text-decoration-color: var(--brand); }
/* A fold for what only some readers need (how the times are counted, the older history). */
.w3 .jd-fold > summary {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; color: var(--muted-2); font-size: 14px;
  font-weight: 600; cursor: pointer; list-style: none;
}
.w3 .jd-fold > summary::-webkit-details-marker { display: none; }
.w3 .jd-fold[open] > summary { color: var(--ink); }
@media (min-width: 1024px) { .w3 .jd-fold > summary { min-height: 40px; } }

/* --- A job's page (office/job_detail.html, P4) -------------------------------------------------------------------
   The head, then two columns on a desk: the step the job is at, the viewer's next step and the items on the left; the
   facts, the route, the QT and the history on the right. A phone uses the DOM order, what the job is and waits for
   first, with no visual reordering of its sections. */
.jd-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; align-items: start; }
.jd-col { display: grid; gap: 16px; align-content: start; min-width: 0; }
.jd-part { min-width: 0; }
@media (min-width: 1024px) { .jd-grid { grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); } }
/* Phone visual order follows the document, with the hero, next action and items first. */
@media (max-width: 1023.98px) { .jd-col { display: contents; } }
.jd-cancelled { display: grid; gap: 8px; margin: 0; }
.jd-cancelled :is(h2, p) { margin: 0; }
.jd-cancelled h2 { font-size: 18px; }
.jd :is(.detail-card, .card) { display: grid; gap: 12px; min-width: 0; margin: 0; padding: 16px 18px; }
.jd :is(.detail-card > h2, .card-head h2, .jd-card-title, .jd-section-head h2) {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 0;
  font-family: var(--font-display); font-size: 18px; font-weight: 700; line-height: 1.3;
}
.jd :is(.detail-card, .card) > .hint, .jd .notice { margin: 0; }
.jd .jd-section-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; }
.jd .jd-section-head .btn, .jd .form-actions .btn { width: auto; }
.jd .form-actions { gap: 8px; }
.jd .jd-your-move { font-family: var(--font); font-size: 13px; }

/* The step the job is at: the dark card, the station big, its state a pill, the time it has run or waited. */
.jd-now { gap: 6px; padding: 18px 20px; }
.jd-now-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; }
.jd-now-station { margin: 0; color: #ffffff; font-family: var(--font-display); font-size: 24px; font-weight: 700; line-height: 1.25; }
.jd-now-state {
  display: inline-flex; align-items: center; gap: 6px; padding: 2px 12px; border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.14); color: #ffffff; font-size: 14px; font-weight: 600; white-space: nowrap;
}
.jd-now-state.is-run::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--amber); }
.jd-now-time { margin: 0; color: rgba(255, 255, 255, 0.86); font-size: 15px; }
.jd-now-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; margin-top: 4px; color: rgba(255, 255, 255, 0.78); font-size: 13px; }
.jd-now .steps-mini { color: inherit; }
.jd-now .steps-mini-dots i { background: rgba(255, 255, 255, 0.28); }
.jd-now .steps-mini-dots i.is-done { background: #9fd8b4; }
.jd-now .steps-mini-dots i.is-now { background: var(--amber); }

/* The facts: two columns of label and value; a note or a reason takes the whole width. */
.jd .detail-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px; margin: 0; padding: 0; border: 0; border-radius: 0;
  background: none;
}
.jd .detail-grid > div { display: grid; gap: 2px; min-width: 0; }
.jd .detail-grid dt { color: var(--muted); font-size: 12px; font-weight: 600; }
.jd .detail-grid dd { font-weight: 600; }
.jd .detail-grid .jd-wide { grid-column: 1 / -1; }
.jd .detail-grid dd.notes { font-weight: 500; }

/* The plan: its two times as tiles, a job that cannot make its due date as a late callout, the rush apart below. */
.jd .plan-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); gap: 10px; margin: 0; padding: 0; list-style: none; }
.jd .plan-facts li { display: grid; gap: 2px; min-width: 0; padding: 10px 12px; border-radius: var(--r-ctl); background: var(--soft); font-weight: 600; }
.jd .plan-facts .plan-label { margin: 0; color: var(--muted-2); font-size: 12px; font-weight: 600; }
.jd .plan-facts .plan-at { font-size: 16px; }
.jd .plan-late { margin: 0; padding: 10px 14px; border: 0; border-radius: 14px; background: var(--late-bg); color: var(--late); font-weight: 600; }
.jd .plan-actions { margin: 0; }
.jd .plan-actions form { margin: 0; }
.jd .plan-rush { display: grid; gap: 8px; justify-items: start; }
.jd .plan-facts ~ .plan-rush, .jd .plan-actions ~ .plan-rush { padding-top: 12px; border-top: 1px dashed var(--line-strong); }
.jd .plan-rush-now { margin: 0; font-weight: 700; overflow-wrap: anywhere; }
.jd .plan-status { font-family: var(--font); font-size: 13px; }

/* The release: each check a row with its mark, its words and its state in a pill; what is missing under it. The sheet
   status is a pair of small buttons, the one the job has pressed (filled); the actions of design in a row. */
.jd .release-checks { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }
.jd .release-check {
  display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; align-items: center; gap: 2px 10px; padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.jd .release-check:last-child { border-bottom: 0; }
.jd .release-mark { display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; background: var(--warn-bg); color: var(--warn); }
.jd .release-check[data-state="ok"] .release-mark { background: var(--ok-bg); color: var(--ok); }
.jd .release-what { font-weight: 600; }
.jd .release-check[data-state="todo"] .release-what { font-weight: 700; }
.jd .release-state { font-size: 12px; }
.jd .release-missing { grid-column: 2 / -1; font-size: 14px; }
.jd .release-sheet-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; }
.jd .release-sheet { margin: 0; }
.jd .release-sheet-forms { display: flex; flex-wrap: wrap; gap: 6px; max-width: none; margin: 0; }
.jd .release-sheet-forms form { margin: 0; }
.jd .release-sheet-forms .btn[aria-pressed="true"] { border-color: var(--brand); background: var(--ok-bg); color: var(--brand-deep); opacity: 1; }
.jd .release-actions { display: grid; gap: 10px; padding: 12px 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.jd .release-actions .release-form, .jd .release-skip { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; max-width: none; margin: 0; }
.jd .release-actions :is(.release-form, .release-skip) > .hint { order: 2; flex: 1 1 260px; margin: 0; font-size: 14px; }
.jd .release-actions .release-form .form-actions { flex: none; }
.jd .release-own-check, .jd .release-blocked { display: inline-flex; align-items: center; gap: 6px; margin: 0; }

/* The items: a table on a desk; on a phone each item a row of its own, its name and quantity on top. */
.jd-items { table-layout: auto; }
.jd-items thead th { white-space: normal; vertical-align: bottom; }
.jd-items tbody th { font-weight: 400; }
.jd-item-name { display: block; font-weight: 700; overflow-wrap: anywhere; }
.jd-item-part { display: block; margin-top: 2px; color: var(--muted-2); font-size: 13px; font-weight: 600; }
.jd-items .col-spec { color: var(--muted-2); font-size: 14px; overflow-wrap: anywhere; }
.jd .jd-items .col-qty { white-space: normal; overflow-wrap: anywhere; }
.jd-items .jd-qty-n { font-size: 16px; font-weight: 700; }
.jd-items .col-note { font-size: 14px; overflow-wrap: anywhere; }
.jd-items .col-qc:not(:empty) { color: var(--ok); font-weight: 700; }
@media (max-width: 719.98px) {
  .jd-items tbody tr { grid-template-columns: minmax(0, 1fr) minmax(0, .4fr); grid-template-areas: "name qty" "spec spec" "note note" "qc qc"; gap: 2px 12px; padding: 12px 0; }
  .jd-items tbody th { grid-area: name; }
  .jd-items .col-qty { grid-area: qty; text-align: right; }
  .jd-items .col-spec { grid-area: spec; }
  .jd-items .col-note { grid-area: note; }
  .jd-items .col-qc { grid-area: qc; }
  .jd-items tbody :is(th, td):empty { display: none; }
  .jd-items .col-qc[data-label]::before { display: inline; margin-right: 6px; content: attr(data-label) ":"; }
}

/* The route as a timeline, at every width (it sits in the narrow column of a desk): a dot for each step (ticked when
   done, dark at the step the job is at), its station and state, and under them the time it waited, was worked and the
   planned finish, each with its label. A line joins the dots. */
.jd-route, .jd-route tbody { display: block; width: 100%; border: 0; }
.jd-route thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.jd-route tbody tr {
  position: relative; display: grid; grid-template-columns: 28px repeat(3, minmax(0, 1fr)); align-items: start;
  grid-template-areas: "dot station station status" ". wait work plan"; gap: 4px 10px; padding: 10px 0;
}
.jd-route tbody tr:not(:last-child)::after {
  content: ""; position: absolute; top: 40px; bottom: -8px; left: 13px; width: 2px; border-radius: 1px; background: var(--line);
}
.jd-route tbody :is(th, td) { display: block; min-width: 0; padding: 0; border: 0; background: none; font-size: 14px; }
.jd-route tbody th { grid-area: dot; }
.jd-route .col-station { grid-area: station; align-self: center; font-size: 15px; font-weight: 600; overflow-wrap: anywhere; }
.jd-route .col-status { grid-area: status; align-self: center; justify-self: end; }
.jd-route .col-wait { grid-area: wait; }
.jd-route .col-work { grid-area: work; }
.jd-route .col-plan { grid-area: plan; }
.jd-route :is(.col-wait, .col-work, .col-plan) { color: var(--ink); }
.jd-route :is(.col-wait, .col-work, .col-plan)[data-label]::before { content: attr(data-label); display: block; color: var(--muted); font-size: 12px; font-weight: 600; }
.jd-route .col-outside .hint { display: none; } /* its label says it is time outside */
/* Burmese words are long (a month is a word of ten letters): each time is a line of its own under the station, its
   label on the left and the time on the right, rather than three narrow columns that break a date into pieces. */
.jd-route:lang(my) tbody tr {
  grid-template-columns: 28px minmax(0, 1fr) auto; grid-template-areas: "dot station status" ". wait wait" ". work work" ". plan plan";
}
.jd-route:lang(my) :is(.col-wait, .col-work, .col-plan) { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 0 12px; }
.jd-route:lang(my) :is(.col-wait, .col-work, .col-plan)[data-label]::before { display: inline; }
.jd-dot {
  position: relative; z-index: 1; display: grid; place-items: center; width: 28px; height: 28px; border: 2px solid var(--line-strong);
  border-radius: 50%; background: var(--card); color: var(--muted-2); font-size: 12px; font-weight: 700;
}
.jd-step.is-done .jd-dot { border-color: var(--brand); background: var(--brand); color: #ffffff; }
.jd-step.is-current .jd-dot { border-color: var(--hero); background: var(--hero); color: #ffffff; }
.jd-step.is-current .col-station { font-weight: 700; }
.jd-step.is-cancelled .col-station { color: var(--muted); text-decoration: line-through; }

/* The history: one entry under the other at every width (the narrow column of a desk): when and who on top, what was
   done and why under them. */
.jd-history, .jd-history tbody { display: block; width: 100%; border: 0; }
.jd-history thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.jd-history tbody tr {
  display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "time who" "what what" "reason reason";
  gap: 2px 10px; padding: 10px 0; border-bottom: 1px solid var(--line);
}
.jd-history tbody tr:last-child { border-bottom: 0; }
.jd-history tbody td { display: block; min-width: 0; padding: 0; border: 0; overflow-wrap: anywhere; }
.jd-history .col-time { grid-area: time; color: var(--muted); font-size: 13px; }
.jd-history .col-who { grid-area: who; color: var(--muted-2); font-size: 13px; font-weight: 600; text-align: right; }
.jd-history .col-what { grid-area: what; font-weight: 600; }
.jd-history .col-what .hint { display: inline; font-size: 14px; font-weight: 500; }
.jd-history .col-reason { grid-area: reason; color: var(--muted-2); font-size: 14px; }
.jd-history .col-reason:empty { display: none; }
.jd-history-more { display: grid; gap: 0; }

/* The NG cases: one case under the other at every width (eight facts do not fit a column), each fact with its label. */
.jd-ng, .jd-ng tbody { display: block; width: 100%; }
.jd-ng thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.jd-ng tbody tr { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 140px), 1fr)); gap: 6px 12px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.jd-ng tbody tr:last-child { border-bottom: 0; }
.jd .jd-ng .num { white-space: normal; }
.jd-ng tbody :is(th, td) { display: block; min-width: 0; padding: 0; border: 0; text-align: left; }
.jd-ng tbody th { grid-column: 1 / -1; }
.jd-ng tbody td[data-label]::before { content: attr(data-label); display: block; color: var(--muted); font-size: 12px; font-weight: 600; }
.jd-ng .jd-ng-open { grid-column: 1 / -1; }
.jd-ng .jd-ng-open .btn { width: auto; justify-content: flex-start; padding-left: 0; }
.jd .jd-links { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.jd .jd-links li { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.jd .pending-list { margin: 0; }

/* The drawings: a table on a desk, a row of its own for each file on a phone (the foundation's card table). */
.jd-drawings .jd-rev { font-weight: 700; }
.jd-drawings .jd-latest { margin-left: 8px; }
.jd-drawings .jd-file a { display: inline-flex; align-items: flex-start; gap: 6px; min-height: 44px; padding: 10px 0; color: var(--brand); font-weight: 600; overflow-wrap: anywhere; }
.jd-drawings .jd-file a .ico { margin-top: 3px; }
@media (min-width: 1024px) { .jd-drawings .jd-file a { min-height: 40px; padding: 8px 0; } }
.jd .drawing-copy { max-width: none; margin: 0; }

/* The ⋯ menu of the head, and the sheets it opens. A danger item is in the red of a danger button. */
.jd-menu .overflow-menu-panel { min-width: 240px; }
.jd-menu .overflow-menu-panel > :is(a, button) .ico { color: var(--muted-2); }
.jd-menu .jd-menu-item.is-danger, .jd-menu .jd-menu-item.is-danger .ico { color: var(--late); }
.jd dialog.sheet .detail-card { display: grid; gap: 12px; padding: 0; border: 0; border-radius: 0; background: none; }
.jd dialog.sheet .move-back-plan { margin: 0; }
.jd .sheet-body .form-actions .btn { width: 100%; }
.jd .sheet-confirm .sheet-body { justify-items: center; }
.jd .sheet-confirm .sheet-body > :is(form, .notice) { width: 100%; text-align: left; }
.jd .jd-confirm-ring { display: grid; place-items: center; width: 64px; height: 64px; border-radius: 50%; background: var(--late-bg); color: var(--late); }
.jd .jd-confirm-text { max-width: 44ch; margin: 0; color: var(--muted-2); font-size: 15px; }
.jd .jd-confirm-keep { width: 100%; margin: 0; }
.jd .jd-confirm-keep .btn { width: 100%; }


/* The crumb of a job's page is the way up on a desk; a phone has the back chevron of its bar. A mouse's 40px. */
.w3 .crumb { min-height: 40px; }
@media (max-width: 1023.98px) { .w3 .crumb { display: none; } } /* a phone has the back chevron of its bar */
/* Why the work order cannot be printed yet: a quiet line of its own under the buttons of the head. */
.jd .print-blocked { display: inline-flex; flex-basis: 100%; justify-content: flex-end; align-items: center; gap: 6px; color: var(--muted-2); font-size: 13px; font-weight: 600; }
@media (max-width: 1023.98px) { .jd .print-blocked { justify-content: flex-start; } }
/* An ID that is a link in a row (a remake job, the job of an NG case) is a target a thumb can hit. */
.jd :is(.jd-ng, .jd-links) a.id { display: inline-flex; align-items: center; min-height: 44px; }
.jd .qt-change-see a { display: inline-flex; align-items: center; min-height: 44px; }
@media (min-width: 1024px) {
  .jd :is(.jd-ng, .jd-links) a.id, .jd .qt-change-see a { min-height: 40px; }
  .jd-now { padding: 14px 18px; }
  .jd-now-station { font-size: 22px; }
}
/* The drawings: one file under the other at every width (the foundation's card table of a phone), its Rev and mark on
   top, its type, item and time as labelled facts, the file a link of its own. */
.jd-drawings, .jd-drawings tbody { display: block; width: 100%; }
.jd-drawings thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.jd-drawings tbody tr { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 130px), 1fr)); gap: 6px 12px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.jd-drawings tbody tr:last-child { border-bottom: 0; }
.jd-drawings tbody :is(th, td) { display: block; min-width: 0; padding: 0; border: 0; text-align: left; }
.jd-drawings tbody th, .jd-drawings .jd-file { grid-column: 1 / -1; }
.jd-drawings tbody td[data-label]::before { content: attr(data-label); display: block; color: var(--muted); font-size: 12px; font-weight: 600; }
/* A long status (a Burmese one) breaks inside its pill rather than push a phone's page sideways. */
.jd :is(.detail-card > h2, .qt-change-mark, .qt-linked-to) :is(.pill, .status) { max-width: 100%; white-space: normal; }
@media (min-width: 1024px) { .jd .page-actions { justify-content: flex-end; } }
/* R-WO-2: print stays visible beside the menu on phones; long labels can wrap. */
@media (max-width: 719.98px) {
  .jd-head .page-actions { width: 100%; flex-wrap: nowrap; margin: 0; }
  .jd-head .page-actions > .btn { min-width: 0; white-space: normal; }
  .jd-head .jd-menu { margin-left: auto; flex-shrink: 0; }
}
/* The one primary of a job's page: in its section on a desk, in the sticky bar of the task on a phone. */
@media (max-width: 1023.98px) { .jd .jd-primary-in { display: none; } }
@media (min-width: 1024px) { .action-bar:has(.jd-primary-bar) { display: none; } }
/* --- The job list (office/jobs.html, P2) ---------------------------------------------------------------------------
   Four number tiles that filter the open jobs, then one card: the search and the status chips with their counts, and
   the jobs. A desk reads a table whose whole row opens the job, its number column first and its type a quiet tag; under
   720 px each job is a row that wraps: its number (and marks) on a line of its own, the customer and the type, then the
   due date and where the job is side by side. */
.jl .kpi-row { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 719.98px) { .jl .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.jl .kpi { min-height: 44px; }
@media (max-width: 719.98px) { .jl .kpi { padding: 10px 12px; } .jl .kpi-value { font-size: 22px; } }
.jl .jl-toolbar { min-width: 0; }
.jl .filter-chips { min-width: 0; flex-wrap: wrap; }
.jl .jobs-table .status { white-space: normal; }
.jl-card { min-width: 0; gap: 0; padding: 0; overflow: hidden; }
.jl-toolbar { padding: 14px 18px; border-bottom: 1px solid var(--line); }
.jl .search .ico { color: var(--muted-2); }
.jl .filter-chips .chip { min-height: 44px; }
@media (min-width: 1024px) { .jl .filter-chips .chip { min-height: 40px; } }
.jl .chip-count {
  display: inline-grid; place-items: center; min-width: 22px; margin-left: 2px; padding: 0 6px; border-radius: var(--r-pill);
  background: var(--soft); color: var(--muted-2); font-size: 12px; line-height: 1.6;
}
.jl .chip[aria-current] .chip-count { background: rgba(255, 255, 255, 0.18); color: #ffffff; }
.jobs-table thead th { padding: 10px 14px; }
.jobs-table tbody :is(th, td) { padding: 12px 14px; vertical-align: middle; }
.jobs-table tbody th { font-weight: 400; }
.jobs-table .row-link .id { font-size: 15px; }
.jobs-table th .sf-badges { display: flex; margin-top: 6px; }
.jobs-table td:nth-of-type(1) { overflow-wrap: anywhere; }
/* The number column first (wide enough for its marks on one line), the type a quiet narrow one. The list of open jobs
   has no status column (every job in it is open). */
.jobs-table thead th:nth-child(1) { width: 20%; }
.jobs-table thead th:nth-child(2) { width: 20%; }
.jobs-table thead th:nth-child(3) { width: 13%; }
.jobs-table thead th:nth-child(4) { width: 17%; }
.jobs-table thead th:nth-child(5) { width: 16%; }
.jobs-table.is-open thead th:nth-child(1) { width: 23%; }
.jobs-table.is-open thead th:nth-child(2) { width: 22%; }
.jobs-table.is-open thead th:nth-child(3) { width: 14%; }
.jobs-table.is-open thead th:nth-child(4) { width: 20%; }
.jobs-table.is-open thead th:nth-child(5) { width: auto; }
@media (min-width: 720px) {
  .jobs-table th :is(.sf-badge, [data-qt-mark]) { white-space: nowrap; }
  .jobs-table th .sf-badges + [data-qt-mark] { margin-top: 6px; }
}
.jl-type { white-space: normal; color: var(--muted-2); font-weight: 600; }
.jl-group { display: block; margin-top: 4px; color: var(--muted-2); font-size: 13px; overflow-wrap: anywhere; }
.jobs-table td:nth-of-type(3) time { white-space: nowrap; margin-right: 6px; }
.jl-station { font-weight: 600; margin-right: 4px; }
.jl .sf-badge-why { display: none; } /* the reason of a rush is on the job's page */
.jobs-table .hint { display: block; margin-top: 2px; font-size: 13px; overflow-wrap: anywhere; }
.jl-foot { margin: 0; padding: 12px 18px; border-top: 1px solid var(--line); color: var(--muted-2); font-size: 13px; }
@media (max-width: 719.98px) {
  .jobs-table tbody tr { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; padding: 12px 16px; }
  .jobs-table tbody tr::before { content: ""; order: 3; flex-basis: 100%; height: 0; } /* a new line before the due date */
  .jobs-table tbody :is(th, td) { padding: 0; }
  .jobs-table tbody th { order: 1; flex: 1 1 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
  .jobs-table th .sf-badges { margin-top: 0; }
  .jobs-table .row-link .id { font-size: 17px; }
  .jobs-table tbody td:nth-of-type(1) { order: 2; flex: 0 1 auto; color: var(--muted-2); font-size: 14px; }
  .jobs-table tbody td:nth-of-type(2) { order: 2; width: auto; }
  .jl-group { display: inline; margin: 0 0 0 4px; }
  .jobs-table tbody td:nth-of-type(3) { order: 4; }
  .jobs-table tbody td:nth-of-type(4) { order: 4; }
  .jobs-table tbody td:nth-of-type(5) { order: 5; flex: 1 1 100%; }
  .jobs-table tbody td:nth-of-type(5):not(:has(.hint, .pill:not(.pill-soft))) { display: none; }
}
/* --- The job form (office/job_form.html, P5) --------------------------------------------------------------------
   The head with the way up, then the form in sections, each a card: the type (a segmented control) and its group, the
   customer with the QT and PO numbers side by side (one under the other on a phone) and the due date, the items, the
   route, the notes; the one save in the action bar at the foot of the form, kept in sight at the bottom of a phone.
   Each item is a row that says what it is and opens for its fields. */
.jf .page-head-main > .lead { max-width: none; margin: 0; color: var(--muted-2); font-size: 14px; }
.jf .page-head-main > .lead a { font-weight: 700; }
.jf-form { display: grid; max-width: 880px; }
.jf .form-section { gap: 14px; }
.jf .form-section > h2, .jf-section-head h2 { margin: 0; font-family: var(--font-display); font-size: 18px; font-weight: 700; }
.jf-section-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px; }
.jf .form-section > .hint { margin: 0; font-size: 14px; }
.jf-seg { justify-self: start; max-width: 100%; }
.jf .seg span { min-height: 44px; }
@media (min-width: 1024px) { .jf .seg span { min-height: 40px; } }
.jf-group, .jf-group-new, .jf .qt-source { display: grid; gap: 14px; min-width: 0; }
.jf-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 639.98px) { .jf-grid-3 { grid-template-columns: minmax(0, 1fr); } }
@media (min-width: 640px) { .jf-due { max-width: 320px; } }
.jf-items { gap: 10px; margin: 0; }
.jf .item-card { gap: 0; padding: 0; border: 1px solid var(--line); border-radius: 14px; background: var(--card); }
.jf .item-card.is-open { border-color: var(--ctl-line); }
.item-head { display: flex; align-items: center; gap: 6px; padding: 4px 6px 4px 4px; }
.item-toggle {
  -webkit-appearance: none; appearance: none; display: flex; flex: 1; align-items: center; gap: 10px; min-width: 0;
  min-height: 56px; margin: 0; padding: 6px 8px; border: 0; border-radius: 10px; background: none; color: inherit;
  font: inherit; text-align: left; cursor: pointer;
}
.item-toggle:hover { background: var(--soft); }
.item-no {
  display: grid; flex: none; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: var(--soft);
  color: var(--muted-2); font-size: 13px; font-weight: 700;
}
.item-sum { display: grid; flex: 1; gap: 1px; min-width: 0; }
.item-sum > .sf-chip { justify-self: start; }
.item-sum-name { font-weight: 700; overflow-wrap: anywhere; }
.item-sum-meta { color: var(--muted-2); font-size: 14px; overflow-wrap: anywhere; }
.item-sum-meta:empty { display: none; }
.item-chev { display: grid; flex: none; place-items: center; color: var(--muted-2); transition: transform 150ms ease-out; }
.item-chev.is-open { transform: rotate(180deg); }
.jf .item-head .row-tools { flex: none; }
@media (max-width: 719.98px) {
  .item-head { flex-wrap: wrap; }
  .item-toggle { flex: 1 1 100%; }
  .jf .item-head .row-tools { margin-left: auto; }
  .jf .item-card:not(.is-open) .item-head .row-tools { display: none; }
}
@media (min-width: 1024px) { .jf .step-editor .btn-sm { min-height: 40px; } }
.jf .page-head-main > .lead a { display: inline-flex; align-items: center; min-height: 44px; }
@media (min-width: 1024px) { .jf .page-head-main > .lead a { min-height: 40px; } }
.jf .item-qt { padding: 0 12px 10px 50px; }
.jf .item-qt .sf-badge { background: var(--soft); color: var(--muted-2); box-shadow: inset 0 0 0 1px var(--line); }
.jf .item-body { padding: 12px 14px 14px; border-top: 1px dashed var(--line); }
.jf .action-bar { gap: 6px; }
.jf .action-bar-acts > .btn-text { flex: 0 0 auto; }
.jf .action-bar-acts > .btn-primary { flex: 1 1 auto; }
@media (max-width: 1023.98px) { .jf .action-bar { margin: 0 -16px; } }
@media (min-width: 1024px) {
  .jf .action-bar { grid-template-columns: minmax(0, 1fr) auto; align-items: center; max-width: none; margin: 0; }
  .jf .action-bar-acts > .btn-primary { flex: none; min-width: 200px; }
}
.jf-locked { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; }
.jf-locked li { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 6px 12px; border-radius: var(--r-ctl); background: var(--soft); }
.jf-locked-name { font-weight: 600; }
/* --- A QT's page (office/qt_detail.html, P4 pane) -------------------------------------------------------------------
   The head, the facts, then the lines in one card with the bar of the picker at its foot. Each line is a card of its
   own at every width (ten columns do not fit beside the menu): the box at its left, what the line is and the quantity
   to open on top (side by side on a desk), then what the QT has, what the jobs opened, what is left, the jobs and the
   price, each with its label, in one row on a desk and two on a phone. The price is in the line, in the words of the
   line, so that a transport line is seen and left unticked (R-UX-9). Rules that touch a cell set no min- or
   max-width (the cells of the QT tables never take one: tests/test_qt_pages.py). */
.qd > .card, .qd > form, .qd > .notice, .qd form > .card { margin: 0 0 16px; }
.qd form > .card:last-of-type { margin-bottom: 0; }
.qd .detail-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); gap: 12px 16px; margin: 0; padding: 0; border: 0; background: none; }
.qd .detail-grid > div { display: grid; gap: 2px; }
.qd .detail-grid dt { color: var(--muted); font-size: 12px; font-weight: 600; }
.qd .detail-grid dd { font-weight: 600; }
.qd .detail-grid .qd-wide { grid-column: 1 / -1; }
@media (max-width: 719.98px) { :is(.qd, .qlink) .detail-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* A phone keeps the facts short, so that the lines to pick start high: the customer and the date are in the head's
   line already, the total stands for the amounts before and of VAT (a desk shows them all), and how far the QT is
   opened takes the width of the card. */
@media (max-width: 719.98px) {
  .qd .detail-grid :is(.qd-in-head, .qd-money-part) { display: none; }
  .qd .detail-grid .qd-progress { grid-column: 1 / -1; }
}
.qd .page-title .status { font-size: 13px; }
.qd-lines { display: grid; gap: 0; }
.qd-lines > h2 { margin: 0; padding: 16px 18px 6px; font-family: var(--font-display); font-size: 18px; font-weight: 700; }
.qd .qt-lines-wrap { overflow: visible; border: 0; border-radius: 0; background: none; }
.qd .qt-lines-table, .qd .qt-lines-table tbody { display: block; width: 100%; }
.qd .qt-lines-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.qd .qt-lines-table tbody tr {
  position: relative; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 10px 14px;
  padding: 14px 18px 14px 64px; border-top: 1px solid var(--line);
}
.qd .qt-lines-table:not(:has(.qt-tick-col)) tbody tr { padding-left: 18px; }
.qd .qt-lines-table .num { white-space: normal; }
.qd .qt-lines-table tbody :is(th, td) { display: block; padding: 0; border: 0; background: none; text-align: left; overflow-wrap: anywhere; }
.qd .qt-lines-table .qt-tick-col { position: absolute; top: 10px; left: 10px; width: 44px; }
.qd .qt-lines-table .qt-seq { grid-column: 1 / -1; color: var(--muted); font-size: 13px; font-weight: 600; }
.qd .qt-lines-table .qt-item { grid-column: span 4; font-weight: 500; }
.qd .qt-lines-table .qt-pick { grid-column: span 2; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.qd .qt-lines-table:not(:has(.qt-pick)) .qt-item { grid-column: 1 / -1; }
.qd .qt-item-body { min-width: 0; max-width: none; }
.qd .qt-text { font-size: 16px; font-weight: 600; }
.qd .qt-lines-table td[data-label]::before { content: attr(data-label); display: block; width: 100%; color: var(--muted); font-size: 12px; font-weight: 600; }
.qd .qt-lines-table .qt-price { color: var(--ink); font-weight: 700; }
.qd .qt-lines-table tr.is-done :is(.qt-text, td) { color: var(--muted-2); }
.qd .qt-lines-table tr.is-removed { background: var(--soft); }
.qt-stepper { display: inline-flex; align-items: stretch; overflow: hidden; vertical-align: middle; }
.qt-stepper .qt-step {
  -webkit-appearance: none; appearance: none; display: grid; flex: none; place-items: center; width: 44px; margin: 0; padding: 0;
  border: 0; background: transparent; color: var(--ink); cursor: pointer;
}
.qt-stepper .qt-step:hover { background: var(--soft); }
.qt-stepper .qt-qty { width: 6em; min-height: 44px; border: 0; border-inline: 1px solid var(--line); border-radius: 0; text-align: center; }
.qd .qt-pick .unit-name { font-weight: 600; }
.qd .action-bar { margin: 0; }
@media (min-width: 1024px) {
  .qd .action-bar { grid-template-columns: minmax(0, 1fr) auto; align-items: center; max-width: none; margin: 16px 0 0; }
  .qt-stepper .qt-step { width: 40px; }
  .qt-stepper .qt-qty { min-height: 40px; }
}
@media (max-width: 719.98px) {
  .qd .qt-lines-table tbody tr { grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 12px 16px 14px 58px; }
  .qd .qt-lines-table:not(:has(.qt-tick-col)) tbody tr { padding-left: 16px; }
  .qd .qt-lines-table .qt-tick-col { left: 6px; }
  .qd .qt-lines-table :is(.qt-item, .qt-pick) { grid-column: 1 / -1; }
}
@media (max-width: 1023.98px) { .qd .action-bar { margin: 0 -16px; } }
/* --- What the QT pages share: a QT's status is a pill of its group, in words (redesign W3) ------------------------- */
.w3 .qt-status {
  display: inline-flex; align-items: center; padding: 2px 10px; border-radius: var(--r-pill); background: var(--soft);
  color: var(--muted-2); font-size: 13px; font-weight: 600; line-height: 1.5; white-space: normal;
}
.w3 .qt-status-open { background: var(--ok-bg); color: var(--ok); }
.w3 :is(.qt-status-awaiting, .qt-status-unknown) { background: var(--warn-bg); color: var(--warn); }
.w3 :is(.qt-status-rejected, .qt-status-deleted) { background: var(--late-bg); color: var(--late); }
/* The search of a W3 list: the foundation's search box, its input free of the look of a form field. */
.w3 .search input { min-height: 44px; padding: 0; border: 0; border-radius: 0; background: transparent; }
@media (min-width: 1024px) { .w3 .search input { min-height: 40px; } }
/* The link that opens a row (a job, a QT) is a target a thumb can hit, whatever the stretched link around it. */
.w3 :is(.jobs-table .row-link, .ql-link, .qlink-pick, .ql-changed a, .qd .qt-jobs a, .qlink .qt-link-head a.id) { display: inline-flex; align-items: center; min-height: 44px; }
@media (min-width: 1024px) { .w3 :is(.jobs-table .row-link, .ql-link, .qlink-pick, .ql-changed a, .qd .qt-jobs a, .qlink .qt-link-head a.id) { min-height: 40px; } }
/* The bar of a W3 form: the way out as wide as its words beside the one save; kept in sight at the foot of the
   window on a desk too (a long form), with a soft shadow over what scrolls under it. */
.w3 .action-bar-acts > .btn-text { flex: 0 0 auto; width: auto; }
@media (min-width: 1024px) {
  .w3 :is(.jf-form, .qt-pick, .qt-link-form) .action-bar { position: sticky; bottom: 16px; z-index: 20; box-shadow: var(--pop-shadow); }
}
.w3 .qt-search { align-items: center; }
.w3 .qt-search .field { gap: 0; }
.w3 .qt-search .search { max-width: none; }

/* --- The QTs to open (office/qt_list.html, P2) ---------------------------------------------------------------------
   The head with when the data came and the pull, the changed QTs in a card of their own, then one card: the search and
   the views, the quiet notes, and the QTs: a table whose whole row opens the QT on a desk, a row that wraps on a phone
   (the number and its status on top, the customer, then the date and how far it is opened, with a bar). */
.ql .page-actions form { margin: 0; }
.ql-pull { display: inline-flex; align-items: center; gap: 8px; }
.ql > .notice { margin: 0 0 12px; }
.ql-changed { gap: 10px; margin: 0 0 16px; }
.ql-changed > h2 { margin: 0; font-family: var(--font-display); font-size: 18px; font-weight: 700; }
.ql-changed .table-wrap { border: 0; border-radius: 0; }
.ql-card { gap: 0; padding: 0; overflow: hidden; }
.ql .qt-tools { align-items: center; margin: 0; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.ql-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.ql-chips .btn-plain { min-width: 0; border-width: 1px; border-color: var(--line); border-radius: var(--r-pill); }
.w3 .qt-search .btn { flex: none; min-width: 0; }
.w3 .qt-search .field { flex: 1 1 180px; }
.ql .qt-unacked { display: block; margin-top: 4px; text-align: left; }
@media (max-width: 719.98px) {
  .ql-changed .table-wrap { overflow: visible; }
  .ql-changed .qt-changed-table, .ql-changed .qt-changed-table tbody { display: block; }
  .ql-changed .qt-changed-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .ql-changed .qt-changed-table tbody tr { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; padding: 10px 0; border-bottom: 1px solid var(--line); }
  .ql-changed .qt-changed-table tbody tr:last-child { border-bottom: 0; }
  .ql-changed .qt-changed-table tbody :is(th, td) { display: block; padding: 0; border: 0; }
  .ql-changed .qt-changed-table tbody td:nth-of-type(1) { display: flex; flex-wrap: wrap; gap: 6px; }
  .ql-changed .qt-changed-table .qt-jobs { flex: 1 1 100%; }
}
.ql-changed .pill, .ql-changed .qt-status { white-space: normal; }
.ql-chips .chip { min-height: 44px; }
@media (min-width: 1024px) { .ql-chips .chip { min-height: 40px; } }
.ql .chip-count {
  display: inline-grid; place-items: center; min-width: 22px; margin-left: 2px; padding: 0 6px; border-radius: var(--r-pill);
  background: var(--warn-bg); color: var(--warn); font-size: 12px; line-height: 1.6;
}
.ql :is(.qt-cutover-note, .qt-all-capped) { max-width: none; margin: 0; padding: 10px 18px; border-bottom: 1px solid var(--line); font-size: 14px; }
.ql .qt-wait-table { width: 100%; }
.ql .qt-wait-table thead th { padding: 10px 14px; }
.ql .qt-wait-table tbody :is(th, td) { padding: 12px 14px; vertical-align: middle; }
.ql .qt-wait-table tbody tr { position: relative; }
.ql .qt-wait-table tbody tr:hover > * { background: var(--soft); }
.ql .ql-link { color: var(--ink); font-size: 15px; text-decoration: none; }
.ql .ql-link::after { content: ""; position: absolute; inset: 0; } /* the whole row opens the QT */
.ql .qt-unacked a, .ql .qt-why { position: relative; z-index: 1; }
.ql .qt-unacked { max-width: none; }
.ql .qt-progress { color: var(--muted-2); font-size: 14px; }
.ql .qt-table tr.is-done .qt-progress { color: var(--ok); }
.ql-meter { display: block; width: 100%; height: 6px; margin-top: 6px; border: 0; border-radius: var(--r-pill); background: var(--soft); }
.ql-meter::-webkit-meter-bar { height: 6px; border: 0; border-radius: var(--r-pill); background: var(--soft); }
.ql-meter::-webkit-meter-optimum-value, .ql-meter::-webkit-meter-suboptimum-value, .ql-meter::-webkit-meter-even-less-good-value { border-radius: var(--r-pill); background: var(--brand); }
.ql-meter::-moz-meter-bar { border-radius: var(--r-pill); background: var(--brand); }
.ql .ql-total { font-weight: 700; }
.ql .ql-customer { font-weight: 600; overflow-wrap: anywhere; }
.ql-project { display: block; margin-top: 2px; color: var(--muted-2); font-size: 13px; font-weight: 400; }
/* The number column wide enough for its badge, the customer (and the project) the widest of the others. */
.ql .qt-wait-table thead th:nth-child(1) { width: 17%; }
.ql .qt-wait-table thead th:nth-child(2) { width: 10%; }
.ql .qt-wait-table thead th:nth-child(4) { width: 19%; }
.ql .qt-wait-table thead th:nth-child(5) { width: 16%; }
@media (max-width: 719.98px) {
  .ql .qt-wait-table, .ql .qt-wait-table tbody { display: block; }
  .ql .qt-wait-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .ql .qt-wait-table tbody tr { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); }
  .ql .qt-wait-table tbody :is(th, td) { display: block; padding: 0; border: 0; }
  .ql .qt-wait-table tbody th { order: 1; flex: 1 1 55%; }
  /* The status pill beside the number; why it cannot be opened and the jobs with a change to acknowledge are lines
     of their own under the customer. */
  .ql .qt-wait-table tbody td.ql-status { display: contents; }
  .ql .ql-status > .qt-status { order: 2; flex: none; }
  .ql .ql-status > :is(.qt-why, .qt-unacked) { order: 4; flex: 1 1 100%; margin: 0; text-align: left; }
  .ql .ql-customer { order: 3; flex: 1 1 100%; }
  .ql-project { font-size: 14px; }
  .ql .qt-date { order: 5; color: var(--muted-2); font-size: 14px; }
  .ql .qt-progress { order: 6; flex: 1 1 140px; }
  .ql .ql-total { order: 7; }
}

/* --- Linking a job to a QT (office/qt_link.html, P2 to choose, P5 to pair) -------------------------------------------
   The QT whose number the job typed first, with its one press; the QTs to choose from (rows on a phone); with a QT
   chosen, its facts, then each item of the job beside the line it takes, and the one save in the bar of the form. */
.qlink > :is(.card, form, .notice, .qt-link-now) { margin: 0 0 16px; }
.qlink-suggest { grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px 16px; background: var(--warn-bg); border-color: transparent; }
.qlink-suggest-text { margin: 0; color: var(--warn); font-weight: 600; overflow-wrap: anywhere; }
@media (max-width: 719.98px) { .qlink-suggest { grid-template-columns: minmax(0, 1fr); } }
.qlink .qt-link-now { font-weight: 600; }
.qlink .qt-link-choose { gap: 12px; padding: 0; overflow: hidden; }
.qlink .qt-link-choose > h2 { margin: 0; padding: 16px 18px 0; font-family: var(--font-display); font-size: 18px; font-weight: 700; }
.qlink .qt-tools { margin: 0; padding: 0 18px 12px; border-bottom: 1px solid var(--line); }
.qlink .qt-link-table { width: 100%; }
.qlink .qt-link-table tbody :is(th, td) { padding: 12px 14px; vertical-align: middle; }
.qlink .qt-link-table tbody tr { position: relative; }
.qlink .qt-link-table tbody tr:hover > * { background: var(--soft); }
.qlink .qlink-pick { color: var(--ink); font-size: 15px; text-decoration: none; }
.qlink .qlink-pick::after { content: ""; position: absolute; inset: 0; }
@media (max-width: 719.98px) {
  .qlink .qt-link-table, .qlink .qt-link-table tbody { display: block; }
  .qlink .qt-link-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .qlink .qt-link-table tbody tr { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); }
  .qlink .qt-link-table tbody :is(th, td) { display: block; padding: 0; border: 0; }
  .qlink .qt-link-table tbody th { order: 1; flex: 1 1 55%; }
  .qlink .qlink-status { order: 2; }
  .qlink .qlink-customer { order: 3; flex: 1 1 100%; font-weight: 600; }
  .qlink .qlink-project { order: 4; flex: 1 1 100%; color: var(--muted-2); font-size: 14px; }
  .qlink .qt-link-table .qt-date { order: 5; color: var(--muted-2); font-size: 14px; }
  .qlink .qt-link-table .qt-progress { order: 6; color: var(--muted-2); font-size: 14px; }
}
.qlink .detail-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); gap: 12px 16px; margin: 0; padding: 0; border: 0; background: none; }
.qlink .detail-grid > div { display: grid; gap: 2px; }
.qlink .detail-grid dt { color: var(--muted); font-size: 12px; font-weight: 600; }
.qlink .detail-grid dd { font-weight: 600; }
.qlink .qt-link-back { margin: 0; }
.qlink .qt-link-back a { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; font-weight: 600; }
.qlink .qt-pairs { min-width: 0; margin: 0; padding: 0; border: 0; }
.qlink .qt-pairs legend { margin: 0 0 6px; padding: 0; font-family: var(--font-display); font-size: 18px; font-weight: 700; }
.qlink .action-bar-acts > .btn-text { flex: 0 0 auto; }
.qlink .action-bar-acts > .btn-primary { flex: 1 1 auto; }
@media (max-width: 1023.98px) { .qlink .action-bar { margin: 0 -16px; } }
@media (min-width: 1024px) {
  .qlink .action-bar { max-width: none; margin: 0; }
  .qlink .action-bar-acts > .btn-primary { flex: none; min-width: 200px; }
}
@media (max-width: 1023.98px) {
  .w3 .action-bar-acts > .btn-primary { width: auto; flex: 1 1 0; min-width: 0; }
}
@media print {
  .workorder-stage { display: block; padding: 0; overflow: visible; }
  .workorder { height: 297mm; min-height: 0; box-shadow: none; break-after: page; }
  .workorder-stage .workorder { zoom: 1; }
  .workorder:last-child { break-after: auto; }
}
/* ===== end W3 ===== */

/* ===== W4 plan+calendar (owned by W4) ===== */

/* The planner's pages (redesign W4): the box of plans to confirm, the dates of a plan, the order of a queue, the
   calendar of overtime, the workload and the jobs overview. A count beside a heading or a station is a small grey pill. */
.count-pill {
  display: inline-flex; align-items: center; justify-content: center; min-width: 24px; height: 22px; padding: 0 7px;
  border-radius: var(--r-pill); background: var(--soft); color: var(--muted-2); font-family: var(--font); font-size: 13px;
  font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1;
}
/* The due chip of the floor (floor/_bits.html) keeps to one line there; in the planner's lists its words may wrap, which
   Burmese needs to stay inside a column. */
:is(.jo-table, .queue-table, .wl-jobs, .plan-card-due) .sf-chip { white-space: normal; }
/* The line under a card's title is a paragraph: no margins of its own inside the head. */
:is(.wl-buckets, .wl-card, .cal-card) .card-head > p { margin: 0; }

/* The production plan on the job page (job_detail.html #plan, W3's page; these rules stay here, where they were born)
   and the words of a time of the plan (.plan-label, .plan-at) on the planner's pages and the job page; the floor's
   queue has its own (.sf-row-plan, .sf-plan-at, W2). The status is a word in the heading: the brown of "waiting"
   while it asks the planner for something, the green of "go" once it is confirmed. A job that cannot make its due
   date says so in the red of being overdue (.plan-late), with the earliest delivery. */
.plan-status { font-size: 16px; color: var(--help); }
.plan-status[data-plan-status="confirmed"] { color: var(--go); }
.plan-facts { display: grid; gap: 4px; margin: 0 0 12px; padding: 0; list-style: none; }
.plan-label { margin-right: 4px; color: var(--ink-2); font-weight: 600; }
.plan-at { font-weight: 700; }
.plan-late {
  margin: 0 0 12px; padding: 10px 14px; border: 1.5px solid var(--late); border-radius: 12px;
  background: var(--late-bg); color: var(--late); font-weight: 600;
}
.plan-late strong { font-weight: 800; }
.plan-actions { align-items: center; margin-top: 4px; }
.plan-actions form { margin: 0; }
/* Rush, in the same section (job_detail.html #plan). Under the plan, when the job has one, with a rule between; alone in
   the section when it has none. Its state is words (the job's badge says the same at the top of the page). */
.plan-facts ~ .plan-rush { margin-top: 16px; padding-top: 16px; border-top: 1px dashed var(--line-strong); }
.plan-rush-now { margin: 0 0 12px; font-weight: 800; overflow-wrap: anywhere; }
.plan-rush-form { max-width: 520px; }

/* --- The dates of a plan (templates/office/plan_edit.html, redesign P5, a task page) -----------------------------
   Two tiles (the time to deliver by; the earliest delivery of a job that cannot make its due date, in the red of
   being late), then every step of the route as a row of the timeline: the dot (a tick once done), the station and its
   state, and the date and time field of a step that has not started. On a desk the field is the last column of its
   row; under 720 px it has a line of its own, across the row after the dot, so that it is never cut off. The field
   takes the width of its box and never more: iOS gives a date field a width of its own unless its look is reset. A
   date that has already passed may be saved (P24): its field says so under it, quietly, in the brown of a warning.
   The save is the one primary, in the bar at the end of the form: kept in sight at the foot of a phone (the shell's
   rule for a task page), edge to edge like the shell's own bar; a bar of its own under the steps on a desk. */
.plan-tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); gap: 10px;
  max-width: 820px; margin: 0 0 16px;
}
.plan-tiles .mini-tile { padding: 12px 14px; }
.plan-tiles .mini-tile span { font-size: 13px; font-weight: 600; }
.plan-tiles .mini-tile b { font-size: 17px; line-height: 1.4; }
.plan-tiles .mini-tile.is-late { background: var(--late-bg); }
.plan-tiles .mini-tile.is-late :is(span, b) { color: var(--late); }
.plan-form { max-width: 820px; margin: 0; }
.plan-steps-card { gap: 4px; }
.plan-step { grid-template-columns: 28px minmax(0, 1fr) minmax(220px, 260px); gap: 8px 12px; padding: 12px 0; }
.plan-step-main { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; min-width: 0; }
.plan-step.is-editable { color: var(--ink); }
.plan-step .timeline-dot { font-size: 13px; }
.plan-step-name { font-weight: 700; overflow-wrap: anywhere; }
.plan-step:not(.is-editable) .plan-step-name { color: var(--muted-2); }
.plan-step-field { display: grid; gap: 4px; min-width: 0; }
.plan-step-field input[type="datetime-local"] {
  -webkit-appearance: none; appearance: none; display: block; box-sizing: border-box; width: 100%; min-width: 0;
  min-height: 48px; margin: 0; padding: 0 12px;
  border: 1.5px solid var(--ctl-line); border-radius: var(--r-ctl); background: var(--card); color: var(--ink);
  font: inherit; font-weight: 600; font-variant-numeric: tabular-nums;
}
.plan-step-field input::-webkit-date-and-time-value { min-height: 1.5em; text-align: left; }
.plan-step-field input[aria-invalid="true"] { border-color: var(--late); background: var(--late-bg); }
.plan-step-time { color: var(--muted-2); font-weight: 600; font-variant-numeric: tabular-nums; }
.plan-past { display: block; color: var(--warn); font-size: 13px; font-weight: 600; }
@media (min-width: 1024px) {
  .plan-step-field input[type="datetime-local"] { min-height: 40px; }
  .plan-form > .action-bar { max-width: none; margin: 16px 0 0; }
  .plan-edit-head .crumb { min-height: 40px; }
}
@media (max-width: 1023.98px) {
  .plan-form > .action-bar { margin-inline: -16px; }
  .plan-form .action-bar-acts { flex-wrap: nowrap; }
  .plan-form .action-bar-acts > .btn-text { flex: 0 0 auto; width: auto; }
  .plan-form .action-bar-acts > .btn-primary { flex: 1 1 auto; width: auto; min-width: 0; }
  .plan-edit-head .crumb { display: none; } /* the app bar's back chevron says the way back */
}
@media (max-width: 719.98px) {
  .plan-step { grid-template-columns: 28px minmax(0, 1fr); }
  .plan-step-field { grid-column: 2 / -1; }
}
/* --- The order of a queue (templates/office/queue_edit.html, redesign P2c, an ordered list) -----------------------
   The stations as chips with the number waiting (a row that scrolls sideways on a phone, its current chip brought into
   view), then the jobs being worked on, then the jobs waiting in the floor's order: the place, the job, its marks, the
   due date and the planned finish, and the two move buttons at the end of the row. Under 720 px a row is three
   columns, the place, the job and the buttons, so the buttons never leave the screen. A rush job is pinned on top: the
   amber of "now" behind it and a lock with the words, in place of the buttons. The row a move just changed is green.
   From 720 px up each table sits in a frame of its own (.queue-scroll) that scrolls sideways, should a table ever be
   wider than its card, instead of the page; the room the customer and the items ask for is for a wide desk only, so
   that at 1024-1279 px (a laptop at 125 %, an iPad across) every column, the buttons too, fits in the card. */
.queue-stations { position: relative; display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px; }
.queue-stations a {
  display: inline-flex; flex: none; align-items: center; gap: 8px; min-height: 40px; padding: 0 8px 0 14px;
  border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--card); color: var(--ink);
  font-size: 14px; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.queue-stations a:hover { border-color: var(--ctl-line); }
.queue-stations a[aria-current="page"] { border-color: var(--hero); background: var(--hero); color: #ffffff; }
.queue-stations a[aria-current="page"] .count-pill { background: rgba(255, 255, 255, 0.16); color: #ffffff; }
.queue-card .card-head h2 { display: inline-flex; align-items: center; gap: 8px; }
.queue-help > summary {
  display: inline-flex; align-items: center; gap: 6px; min-height: 40px; color: var(--muted-2); font-size: 14px;
  font-weight: 600; cursor: pointer; list-style: none;
}
.queue-help > summary::-webkit-details-marker { display: none; }
.queue-help[open] > summary { color: var(--ink); }
.queue-help p { max-width: 68ch; margin: 0 0 4px; color: var(--muted-2); font-size: 14px; }
.queue-none { margin: 0; color: var(--muted-2); font-size: 14px; }
.queue-table { width: 100%; border-collapse: collapse; }
.queue-table th, .queue-table td { padding: 10px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: middle; }
.queue-table thead th { color: var(--muted); font-size: 13px; font-weight: 600; line-height: 1.35; vertical-align: bottom; }
.queue-table tbody tr:last-child > * { border-bottom: 0; }
.queue-table .col-place {
  width: 3em; color: var(--muted-2); font-family: var(--font-display); font-size: 17px; font-weight: 700; text-align: center;
}
.queue-table thead .col-place { font-family: var(--font); font-size: 13px; }
.queue-table .col-job { white-space: nowrap; }
.queue-table .col-job a {
  display: inline-flex; align-items: center; min-height: 40px; color: var(--ink); text-decoration-color: var(--line-strong);
}
.queue-table .col-job a:hover { text-decoration-color: currentColor; }
.queue-item { overflow-wrap: anywhere; }
.queue-more { color: var(--muted); font-size: 13px; }
.queue-table .col-items .sf-badges { margin-top: 4px; }
.queue-table :is(.col-due, .col-plan) time { white-space: nowrap; }
.queue-table .col-due time { margin-right: 4px; }
.queue-table .col-plan .plan-label { display: none; } /* the head of the column says it on a desk */
.queue-table .col-move { width: 1%; white-space: nowrap; }
.queue-move { display: flex; gap: 6px; }
.queue-move form { margin: 0; }
.queue-move .icon-btn { width: 40px; height: 40px; border-color: var(--ctl-line); border-radius: var(--r-ctl); }
.queue-move .icon-btn:not([disabled]):hover { background: var(--soft); }
.queue-pin {
  display: inline-flex; align-items: center; gap: 6px; max-width: 9em; color: var(--warn); font-size: 13px;
  font-weight: 600; line-height: 1.35; white-space: normal;
}
.queue-table tr.is-rush > * { background: var(--warn-bg); }
.queue-table tbody tr:target > * { background: var(--run-bg); } /* the row that was just changed */
@media (min-width: 720px) {
  .queue-scroll { min-width: 0; overflow-x: auto; }
}
@media (min-width: 720px) and (max-width: 1279.98px) {
  .queue-table :is(th, td) { padding-inline: 6px; }
}
@media (min-width: 1280px) {
  .queue-table .col-cust { min-width: 8em; }
  .queue-table .col-items { min-width: 10em; }
}
@media (max-width: 1023.98px) {
  .queue-stations {
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin-inline: -16px; padding: 2px 16px 4px;
  }
  .queue-stations::-webkit-scrollbar { display: none; }
  .queue-stations a { min-height: 44px; }
  .queue-move .icon-btn { width: 44px; height: 44px; min-height: 44px; }
  .queue-help > summary { min-height: 44px; }
  .queue-table .col-job a { min-height: 44px; }
}
@media (max-width: 719.98px) {
  .queue-table, .queue-table tbody { display: block; }
  .queue-table thead {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .queue-table tbody tr {
    display: grid; grid-template-columns: minmax(0, 1fr); gap: 2px 12px; padding: 12px 0; border-bottom: 1px solid var(--line);
  }
  .queue-table tbody tr:last-child { border-bottom: 0; }
  .queue-table tbody :is(th, td) { display: block; padding: 0; border: 0; background: none; }
  .queue-waiting tbody tr { grid-template-columns: 2.25em minmax(0, 1fr) auto; align-items: start; }
  .queue-waiting .col-place { grid-column: 1; grid-row: 1 / span 5; width: auto; padding-top: 1px; text-align: left; }
  .queue-waiting .col-move { grid-column: 3; grid-row: 1 / span 5; align-self: center; width: auto; }
  .queue-waiting tbody :is(th, td):not(.col-place):not(.col-move) { grid-column: 2; }
  .queue-move { flex-direction: column; gap: 8px; }
  .queue-pin { flex-direction: column; max-width: 5.5em; text-align: center; }
  .queue-table .col-cust { color: var(--muted-2); font-size: 14px; }
  .queue-table .col-due, .queue-table .col-plan { font-size: 14px; }
  .queue-table .col-plan { color: var(--muted-2); }
  .queue-table .col-plan .plan-label { display: inline; }
  .queue-table tr.is-rush { margin: 0 -18px; padding: 12px 18px; background: var(--warn-bg); }
  .queue-table tbody tr:target { background: var(--run-bg); }
}
/* --- The calendar of overtime and worked days (templates/office/calendar.html, redesign P8, a board) --------------
   A grid of the days and one of the weekly rules: a column for the whole shop and one for each station. A cell is a
   small button: the dark pill "OT" when overtime is set there, a dashed pill when the station has it from the whole
   shop or a rule (the words for a screen reader are .ot-via, kept out of sight), a quiet "+" when there is none; on a
   rest day the button of a worked day above it, its words always there: a quiet "+" while the day is not worked there,
   the green pill with the tick once it is, dashed when the place works it with the whole shop. A rest day's row is
   grey and today's is the amber of "now". At a desk the columns share the card's width (fixed layout), with a floor
   under which the frame scrolls sideways instead (1024-1279 px); the column of days is always kept on the left, and
   from 1280 px, where every column is in sight, the heads stay on top while the page scrolls. Under 1024 px one place
   is shown at a time, picked from a row of chips that stays under the app bar. The warning of what a press does to
   worked time sits above each grid.
   The answer to a press opens at the row it changed (#day-...) or at the card of the weekly rules (#rules): it lands
   below what stays on top of the page: the heads of the grid from 1280 px, which are --cal-head-h tall (two lines of
   a station's name; three in Burmese, whose names are longer; a name that needs more makes them taller than the
   room kept for them), and, on a phone, the app bar and the row of place chips (--cal-chips-h: a chip of 44 px with
   8 px above and below). */
.cal { --cal-head-h: 3.5rem; --cal-chips-h: 60px; }
.cal:lang(my) { --cal-head-h: 4.5rem; }
.cal-grid tbody tr, .cal-card { scroll-margin-top: 12px; }
.cal-nav { display: flex; flex-wrap: wrap; gap: 8px; }
.cal-nav .btn { width: auto; min-height: 40px; }
.cal-help { margin: -4px 0 16px; }
.cal-help > summary {
  display: inline-flex; align-items: center; gap: 6px; min-height: 40px; color: var(--muted-2); font-size: 14px;
  font-weight: 600; cursor: pointer; list-style: none;
}
.cal-help > summary::-webkit-details-marker { display: none; }
.cal-help[open] > summary { color: var(--ink); }
.cal-help p { max-width: 72ch; margin: 4px 0 8px; color: var(--muted-2); font-size: 14px; }
.cal-cols { display: none; }
.cal-card { gap: 14px; }
.cal-card .callout { margin: 0; }
.cal-legend { margin: 0; padding: 0; font-size: 13px; list-style: none; }
.cal-legend li { display: inline-flex; align-items: center; gap: 6px; }
.cal-swatch {
  display: inline-flex; flex: none; align-items: center; justify-content: center; gap: 2px; min-width: 30px;
  height: 22px; padding: 0 6px; white-space: nowrap;
  border: 1.5px solid var(--line-strong); border-radius: 8px; color: var(--ctl-line); font-size: 13px; font-weight: 700;
}
.cal-swatch .ico { width: 14px; height: 14px; }
.cal-scroll { position: relative; min-width: 0; }
.cal-grid { width: 100%; border-collapse: separate; border-spacing: 0; }
.cal-grid th, .cal-grid td { padding: 4px; border-bottom: 1px solid var(--line); text-align: center; vertical-align: middle; }
.cal-grid thead th {
  padding: 6px 4px 8px; background: var(--card); color: var(--muted-2); font-size: 13px; font-weight: 600;
  line-height: 1.3; vertical-align: bottom; overflow-wrap: anywhere;
}
.cal-grid th:first-child {
  position: sticky; left: 0; z-index: 1; padding: 6px 10px 6px 2px; background: var(--card); color: var(--ink);
  font-weight: 600; line-height: 1.35; text-align: left; overflow-wrap: anywhere;
}
.cal-grid thead th:first-child { z-index: 3; color: var(--muted-2); }
/* Burmese: "anywhere" broke a syllable, its vowel sign starting the next line. The template marks where each syllable
   starts (U+200B), and a head breaks there only. */
.cal-grid:lang(my) thead th { overflow-wrap: normal; font-size: 12.5px; }
.cal-grid tbody tr:last-child > * { border-bottom: 0; }
.cal-grid tbody th time { white-space: nowrap; }
.cal-grid tbody th .pill { margin-top: 2px; }
.cal-wd { color: var(--muted-2); font-weight: 500; }
.cal-grid tr.is-day-off > * { background: var(--soft); }
.cal-grid tr.is-today > * { background: var(--warn-bg); }
.cal-grid tbody tr:target > * { background: var(--run-bg); } /* the row that was just changed */
.cal-grid form { margin: 0; }
.cal-toggle {
  -webkit-appearance: none; appearance: none; display: inline-flex; align-items: center; justify-content: center;
  width: 100%; min-width: 40px; max-width: 56px; min-height: 40px; margin: 0 auto; padding: 0 6px;
  border: 1.5px solid transparent; border-radius: var(--r-ctl); background: transparent; color: var(--ctl-line);
  font: inherit; font-size: 13px; font-weight: 700; line-height: 1.2; cursor: pointer;
  transition: background-color 150ms ease-out, color 150ms ease-out;
}
.cal-toggle:hover { background: var(--soft); color: var(--ink); }
.cal-toggle.is-on, .cal-swatch.is-on { border-color: var(--hero); background: var(--hero); color: #ffffff; }
.cal-toggle.is-via, .cal-swatch.is-via { border-color: var(--ctl-line); border-style: dashed; color: var(--muted-2); }
/* A worked-day button that is off has a faint edge, so that its "+" and its words read as one button where a narrow
   column puts the words under the "+" (1024-1279 px, or more places than twelve). */
.cal-work {
  flex-wrap: wrap; align-content: center; gap: 0 2px; border-color: var(--line); color: var(--muted-2); font-size: 13px;
  overflow-wrap: anywhere;
}
.cal-work .ico { width: 14px; height: 14px; }
.cal-toggle.cal-work { max-width: 76px; padding: 2px; }
.cal-work.is-on, .cal-swatch.cal-work.is-on { border-color: var(--ok); background: var(--ok-bg); color: var(--ok); }
.cal-work.is-via, .cal-swatch.cal-work.is-via {
  border-color: var(--ok); border-style: dashed; background: transparent; color: var(--ok);
}
.cal-rest { display: grid; gap: 4px; }
.cal-grid .ot-via {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}
.cal-grid .rule-note { display: block; color: var(--muted-2); font-size: 13px; font-weight: 500; line-height: 1.35; }
@media (min-width: 1024px) {
  .cal-scroll { overflow-x: auto; }
  .cal-grid { table-layout: fixed; width: 100%; min-width: 52rem; }
  .cal-grid thead th:first-child { width: 8.5rem; }
  .cal-grid thead th { padding-inline: 2px; } /* the room of a narrow column goes to the words of its head */
  .cal-grid td { padding-inline: 1px; }
}
@media (min-width: 1280px) {
  .cal-scroll { overflow: visible; }
  .cal-grid thead th { position: sticky; top: 0; z-index: 2; height: var(--cal-head-h); }
  .cal-grid tbody tr { scroll-margin-top: calc(var(--cal-head-h) + 8px); }
}
@media (max-width: 1023.98px) {
  .cal-grid tbody tr, .cal-card {
    scroll-margin-top: calc(var(--bar-h) + env(safe-area-inset-top) + var(--cal-chips-h) + 8px);
  }
  .cal-grid .cal-hide { display: none; }
  .cal-cols {
    position: sticky; top: calc(var(--bar-h) + env(safe-area-inset-top)); z-index: 5; display: flex; gap: 8px;
    overflow-x: auto; margin: 0 -16px 12px; padding: 8px 16px; background: var(--canvas); scrollbar-width: none;
  }
  .cal-cols::-webkit-scrollbar { display: none; }
  .cal-cols .chip { flex: none; min-height: 44px; font: inherit; font-size: 14px; font-weight: 600; cursor: pointer; }
  .cal-scroll { overflow-x: auto; }
  .cal-grid th:first-child { width: 42%; }
  .cal-toggle { min-width: 44px; max-width: 120px; min-height: 44px; }
  .cal-toggle.cal-work { max-width: 120px; }
  .cal-help > summary { min-height: 44px; }
  .cal-nav .btn { min-width: 44px; min-height: 44px; padding: 0 12px; }
  .cal-nav .btn span { /* the arrows say it on a phone; the words stay for a screen reader */
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0);
    white-space: nowrap; border: 0;
  }
}
/* --- The jobs overview (templates/office/jobs_overview.html, redesign P2) ------------------------------------------
   Four counts that are filters, then one card: the four filter menus, each a button that says what it filters and what
   is chosen (dark once it narrows the list) and opens its links below the bar of menus, across its width (so that the
   long list of stations never runs off the screen, whichever menu it belongs to), then the table of the jobs, whose
   whole row opens the job. The plan column stacks the marks of the plan, the planned time, "plan not confirmed" and the
   earliest delivery of a job that cannot make its due date, every one in words as well as colour. Under 720 px a job is
   one row: the number and the due chip, the customer, the step, the times, the plan. The list filtered to the jobs
   whose plan waits (?plan=inbox, which has no menu) says so above the table, with the way back. From 720 px up the
   table sits in a frame of its own (.jo-scroll) that scrolls sideways, should it ever be wider than the card, instead
   of the page; the room the customer, the step and the plan ask for is for a wide desk only, so that at 1024-1279 px (a
   laptop at 125 %, an iPad across) every column, the plan too, fits in the card. */
.jo-kpis { margin-bottom: 16px; }
.jo-card { gap: 14px; }
.jo-filters { position: relative; display: flex; flex-wrap: wrap; gap: 8px; }
.jo-menu-button {
  display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 0 12px 0 14px;
  border: 1px solid var(--ctl-line); border-radius: var(--r-pill); background: var(--card); color: var(--ink);
  font-size: 14px; cursor: pointer; list-style: none; -webkit-user-select: none; user-select: none;
}
.jo-menu-button::-webkit-details-marker { display: none; }
.jo-menu-button:hover { background: var(--soft); }
.jo-menu-label { color: var(--muted-2); font-weight: 500; }
.jo-menu-value { font-weight: 700; }
.jo-menu-mark { transition: transform 150ms ease-out; }
.jo-menu[open] .jo-menu-mark { transform: rotate(180deg); }
.jo-menu.is-on .jo-menu-button { border-color: var(--hero); background: var(--hero); color: #ffffff; }
.jo-menu.is-on .jo-menu-label { color: rgba(255, 255, 255, 0.78); }
.jo-menu-panel {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 40;
  padding: 8px; border: 1px solid var(--line); border-radius: 14px; background: var(--card); box-shadow: var(--pop-shadow);
}
.jo-menu-panel .filter-bar { margin: 0; }
.jo-menu-panel .filter-bar a { min-height: 40px; }
.overview-filtered {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; padding: 10px 14px; border-radius: 14px;
  background: var(--soft);
}
.overview-filter-line { display: flex; flex-wrap: wrap; gap: 0 10px; margin: 0; color: var(--muted-2); }
.overview-filter-line b { color: var(--ink); }
.overview-filtered > a { display: inline-flex; align-items: center; min-height: 40px; color: var(--brand); font-weight: 600; }
.jo-table { font-size: 14px; }
.jo-table thead th { font-size: 13px; white-space: normal; line-height: 1.35; vertical-align: bottom; }
.jo-table .jo-job { white-space: nowrap; }
.jo-table .row-link { display: inline-flex; align-items: center; min-height: 40px; }
.jo-table tbody :is(th, td) { vertical-align: middle; }
.jo-table .jo-step .st { margin-left: 2px; }
.jo-table .jo-in { white-space: nowrap; }
.jo-table:lang(th) .jo-since time { white-space: nowrap; }
.jo-table .jo-since time { color: var(--muted-2); }
.jo-table .col-plan { min-width: 8.5em; }
.jo-table .col-plan > * + * { margin-top: 6px; }
.jo-table .col-plan .pill { white-space: normal; }
.jo-table .plan-line { margin: 0; }
.jo-table .plan-late { margin: 0; padding: 6px 10px; font-size: 13px; }
.jo-none { color: var(--muted); }
.jo-foot { margin: 0; color: var(--muted-2); font-size: 13px; }
@media (min-width: 720px) {
  .jo-scroll { min-width: 0; overflow-x: auto; }
  .jo-table tbody tr:hover > * { background: var(--soft); }
  .jo-table [data-label]::before { content: none; }
}
@media (min-width: 720px) and (max-width: 1279.98px) {
  .jo-table :is(th, td) { padding-inline: 6px; }
}
@media (min-width: 1280px) {
  .jo-table .jo-cust { min-width: 9em; }
  .jo-table .jo-step { min-width: 8em; }
  .jo-table .col-plan { min-width: 13em; }
}
@media (max-width: 1023.98px) {
  .jo-menu-button { min-height: 44px; }
  .jo-menu-panel .filter-bar a { min-height: 44px; }
  .overview-filtered > a { min-height: 44px; }
}
@media (max-width: 719.98px) {
  .jo-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .jo-kpis .kpi { padding: 10px 12px; }
  .jo-filters { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .jo-menu-button {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "label mark" "value mark";
    align-items: center; gap: 0 6px; width: 100%; padding: 6px 10px 6px 12px; border-radius: var(--r-ctl); line-height: 1.3;
  }
  .jo-menu-label { grid-area: label; font-size: 13px; overflow-wrap: anywhere; }
  .jo-menu-value { grid-area: value; overflow-wrap: anywhere; }
  .jo-menu-mark { grid-area: mark; }
  .jo-menu[open] { grid-column: 1 / -1; }
  .jo-menu-panel { position: static; margin-top: 6px; box-shadow: none; }
  .jo-table tbody tr {
    grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "job due" "cust cust" "step step" "since in" "plan plan";
    gap: 4px 12px;
  }
  .jo-table .jo-job { grid-area: job; }
  .jo-table .jo-due { grid-area: due; justify-self: end; }
  .jo-table .jo-cust { grid-area: cust; min-width: 0; color: var(--muted-2); }
  .jo-table .jo-step { grid-area: step; min-width: 0; }
  .jo-table .jo-since { grid-area: since; }
  .jo-table .jo-in { grid-area: in; justify-self: end; text-align: right; }
  .jo-table .col-plan { grid-area: plan; min-width: 0; }
  .jo-table .row-link { min-height: 44px; }
  .jo-table [data-label]::before { font-size: 13px; }
}
/* --- The box of plans to confirm (templates/office/plan_inbox.html, redesign P2b: bucketed cards) ------------------
   The jobs that cannot make their due date first, under a heading of their own, then the others. A job is a card: its
   number in the display face (never broken), the customer, the plan's status and the rush mark, the due date on the
   right; a line in red for a job that cannot make its due date; where it is and the time the box is sorted by; and
   its two actions, the confirm stamp (one press) and the quiet link to edit the dates. Under 720 px the facts go two to
   a row and the actions side by side under a dashed line. */
.plan-inbox-links .btn { min-height: 40px; }
.plan-bucket { display: grid; gap: 10px; margin: 0 0 24px; }
.plan-bucket-head { display: grid; gap: 2px; padding: 0 2px; }
.plan-bucket-head h2 {
  display: inline-flex; align-items: center; gap: 8px; margin: 0; font-family: var(--font-display); font-size: 18px;
}
.plan-bucket.is-late .plan-bucket-head h2 { color: var(--late); }
.plan-bucket-head p { margin: 0; color: var(--muted-2); font-size: 13px; }
.plan-bucket > .plan-card + .plan-card { margin-top: 0; }
.plan-card { gap: 12px; padding: 14px 18px; }
.plan-card-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 16px; }
.plan-card-id { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; min-width: 0; }
.plan-jobno {
  display: inline-flex; align-items: center; min-height: 40px; color: var(--ink); font-family: var(--font-display);
  font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums; text-decoration: none; white-space: nowrap;
}
.plan-jobno:hover { text-decoration: underline; text-underline-offset: 3px; }
.plan-card-cust { font-weight: 600; overflow-wrap: anywhere; }
.plan-card-id .sf-badges { margin: 0; }
.plan-card-due {
  display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin: 0; color: var(--muted-2);
  font-size: 14px; font-weight: 600;
}
.plan-card-due time { white-space: nowrap; }
.plan-card-late .plan-late {
  display: flex; align-items: flex-start; gap: 8px; width: auto; margin: 0; padding: 8px 12px; border: 0;
  border-radius: var(--r-ctl); font-size: 14px;
}
.plan-card-late .plan-late .ico { margin-top: 3px; }
.plan-card-body { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px 24px; }
.plan-card-facts { display: grid; grid-template-columns: minmax(8em, auto) minmax(0, 1fr); gap: 8px 28px; margin: 0; }
.plan-card-facts > div { display: grid; align-content: start; gap: 2px; min-width: 0; }
.plan-card-facts dt { color: var(--muted); font-size: 13px; font-weight: 600; }
.plan-card-facts dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
.plan-card-facts .plan-label { margin-right: 4px; color: var(--muted-2); font-weight: 500; }
.plan-card-facts .plan-at { font-weight: 700; white-space: nowrap; }
.plan-card-facts .sf-badges { display: flex; margin-top: 6px; }
.plan-card-acts { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; }
.plan-card-acts form { margin: 0; }
.plan-card-acts .btn { width: auto; min-height: 40px; }
@media (min-width: 720px) { .plan-card-acts .btn { white-space: nowrap; } }
.plan-btn-in { display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 1023.98px) {
  .plan-inbox-links { display: none; } /* the row of sibling pages under the app bar has them */
  .plan-card-acts .btn { min-height: 44px; }
  .plan-jobno { min-height: 44px; }
}
@media (max-width: 719.98px) {
  .plan-card { padding: 12px 14px; }
  .plan-card-body { grid-template-columns: minmax(0, 1fr); }
  .plan-card-facts { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .plan-card-acts {
    display: grid; grid-template-columns: 1fr 1fr; padding-top: 10px; border-top: 1px dashed var(--line-strong);
  }
  .plan-card-acts > :only-child { grid-column: 1 / -1; }
  .plan-card-acts .btn { width: 100%; }
}
/* --- The workload (templates/office/workload.html, redesign P8, a board) -------------------------------------------
   The design desk is the dark hero card, the one live thing of the page (the shop plans around it): how many jobs wait
   for design or are in design, the rough backlog and the people, the two numbers of the month. Beside it, its four
   boxes of when those jobs have to be released, each a link to its list (late in red, today in amber). Then the grid
   of every station by working day: a number with jobs behind it is a link a thumb can hit, toned from pale to the
   brand green by how many jobs it holds; a zero is quiet; the column of jobs behind their plan is red; today's column
   is the amber of "now" in its head and its cells. The station column stays in sight while the days scroll sideways
   inside the grid's own frame, so the page never does. The list of a number is under the grid. */
.wl-top { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); gap: 16px; margin: 0 0 16px; }
.wl-top > .card + .card { margin-top: 0; }
.wl-design { align-content: start; gap: 10px; }
.wl-design .wl-design-title {
  display: flex; align-items: center; gap: 8px; margin: 0; color: rgba(255, 255, 255, 0.82); font-family: var(--font);
  font-size: 14px; font-weight: 600;
}
.wl-design-now { margin: 0; font-family: var(--font-display); font-size: 24px; font-weight: 700; line-height: 1.3; }
.wl-design-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.wl-fact {
  margin: 0; padding: 10px 12px; border-radius: 14px; background: rgba(255, 255, 255, 0.1); font-size: 14px;
  font-weight: 600; line-height: 1.4;
}
.wl-design-month { margin: 0; color: rgba(255, 255, 255, 0.82); font-size: 13px; }
.wl-buckets { align-content: start; }
.wl-bucket-list { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 0; padding: 0; list-style: none; }
.wl-bucket {
  display: grid; align-content: start; gap: 2px; height: 100%; min-height: 84px; padding: 12px; border-radius: 14px;
  background: var(--soft); color: var(--ink); text-decoration: none; transition: box-shadow 150ms ease-out;
}
.wl-bucket b { font-family: var(--font-display); font-size: 28px; font-weight: 700; line-height: 1.1; }
.wl-bucket span { font-size: 13px; font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; }
a.wl-bucket:hover { box-shadow: inset 0 0 0 1.5px var(--ctl-line); }
.wl-bucket.is-late { background: var(--late-bg); color: var(--late); }
.wl-bucket.is-today { background: var(--warn-bg); color: var(--warn); }
.wl-bucket.is-none { color: var(--muted-2); }
.wl-bucket[aria-current="true"] { box-shadow: inset 0 0 0 2px var(--hero); }
.wl-card { gap: 12px; }
.wl-wrap { border: 0; border-radius: 0; background: transparent; }
.workload-table { width: 100%; border-collapse: separate; border-spacing: 0; }
.workload-table th, .workload-table td { padding: 3px; border-bottom: 1px solid var(--line); text-align: center; vertical-align: middle; }
.workload-table tbody tr:last-child > * { border-bottom: 0; }
.workload-table thead th { padding: 6px 3px 8px; color: var(--muted-2); font-size: 13px; font-weight: 600; line-height: 1.3; vertical-align: bottom; }
.workload-table .col-station {
  position: sticky; left: 0; z-index: 1; min-width: 7.5em; padding: 3px 12px 3px 2px; background: var(--card);
  color: var(--ink); text-align: left; font-weight: 600; overflow-wrap: anywhere; box-shadow: inset -1px 0 0 var(--line);
}
.workload-table thead .col-station { z-index: 2; color: var(--muted-2); }
.workload-table tr.is-design > * { border-bottom: 2px solid var(--line-strong); }
.workload-table tr.is-design .col-station { font-weight: 700; }
.workload-table .col-overdue { border-right: 1px dashed var(--line-strong); }
.workload-table thead .col-overdue { color: var(--late); }
.workload-weekday { display: block; font-weight: 500; }
.workload-date { display: block; color: var(--ink); font-size: 14px; font-weight: 700; }
.workload-today { display: block; margin-top: 2px; color: var(--today); font-size: 13px; font-weight: 700; }
/* Burmese month names are long single words: a little smaller, and a narrower station column, so that the ten days
   still fit beside the side menu at 1280 px. */
.workload-table:lang(my) .workload-date { font-size: 13px; font-weight: 600; }
.workload-table:lang(my) .col-station { min-width: 6em; }
.workload-table thead th.is-today { background: var(--today-bg); }
.workload-table td.is-today { background: var(--today-bg); }
.workload-count {
  display: inline-flex; align-items: center; justify-content: center; width: 100%; min-width: 44px; min-height: 40px;
  padding: 0 6px; border-radius: 10px; color: var(--ink); font-family: var(--font-display); font-size: 16px;
  font-weight: 700; font-variant-numeric: tabular-nums; text-decoration: none;
}
.workload-count:hover { box-shadow: inset 0 0 0 1.5px var(--ctl-line); }
.workload-count.wl-c1 { background: var(--soft); }
.workload-count.wl-c2 { background: var(--selection); }
.workload-count.wl-c3 { background: var(--brand); color: #ffffff; }
.workload-table .col-overdue .workload-count { background: var(--late-bg); color: var(--late); }
.workload-table .workload-count[aria-current="true"] { box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--hero); }
.workload-none { color: var(--muted-2); font-size: 13px; font-weight: 400; }
.wl-legend { margin: 0; padding: 0; font-size: 13px; list-style: none; }
.wl-legend li { display: inline-flex; align-items: center; }
.wl-legend i { width: 14px; height: 14px; border-radius: 4px; box-shadow: inset 0 0 0 1px var(--line-strong); }
.wl-legend .wl-sw-1 { background: var(--soft); }
.wl-legend .wl-sw-2 { background: var(--selection); }
.wl-legend .wl-sw-3 { background: var(--brand); box-shadow: none; }
.wl-legend .wl-sw-late { background: var(--late-bg); }
.wl-legend .wl-sw-today { background: var(--today-bg); }
.wl-list { scroll-margin-top: 12px; }
.wl-jobs thead th { font-size: 13px; }
.wl-jobs .wl-job { white-space: nowrap; }
.wl-jobs .row-link { display: inline-flex; align-items: center; min-height: 40px; }
.wl-jobs .wl-time time, .wl-jobs .wl-due time { white-space: nowrap; }
.wl-jobs .wl-due time { margin-right: 4px; }
@media (min-width: 720px) {
  .wl-jobs [data-label]::before { content: none; }
  .wl-jobs tbody tr:hover > * { background: var(--soft); }
}
@media (max-width: 1023.98px) {
  .wl-top { grid-template-columns: minmax(0, 1fr); }
  .workload-count { min-height: 44px; }
}
@media (max-width: 719.98px) {
  .wl-bucket-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .wl-design-now { font-size: 21px; }
  .wl-wrap { margin-inline: -18px; padding-inline: 18px; }
  .workload-table .col-station { min-width: 6.5em; max-width: 8em; }
  .wl-jobs tbody tr { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "job due" "cust cust" "time time"; }
  .wl-jobs .wl-job { grid-area: job; }
  .wl-jobs .wl-due { grid-area: due; justify-self: end; text-align: right; }
  .wl-jobs .wl-cust { grid-area: cust; color: var(--muted-2); }
  .wl-jobs .wl-time { grid-area: time; }
  .wl-jobs .wl-due::before { content: none; }
  .wl-jobs .row-link { min-height: 44px; }
}
/* ===== end W4 ===== */

/* ===== W5 quality+ng+overview+print-ng (owned by W5) ===== */

/* Each clipped card owns a shrinkable track; only its table scrolls, never its filters or the page. */
:is(.ng-card, .problem-list-card, .ov-follow, .audit-card) { grid-template-columns: minmax(0, 1fr); }
.w5-table-scroll { min-width: 0; max-width: 100%; overflow-x: auto; border: 0; border-radius: 0; background: transparent; }

/* The words of a report's status and of a recheck where another page still draws them as text (the NG table of the
   office job page): kept from before the redesign until that page draws them as pills. */
:is(.problem-list-card, .case-grid, .ng-card) .status-open { color: var(--help); }
:is(.problem-list-card, .case-grid, .ng-card) .status-acknowledged { color: var(--ink); }
:is(.problem-list-card, .case-grid, .ng-card) .status-closed, :is(.problem-list-card, .case-grid, .ng-card) .status-void { color: var(--ink-2); }
:is(.problem-list-card, .case-grid, .ng-card) .status-passed { color: var(--go); }
:is(.problem-list-card, .case-grid, .ng-card) .status-failed { color: var(--late); }
:is(.problem-list-card, .case-grid, .ng-card) .next-sub { display: block; margin-top: 2px; color: var(--ink-2); font-size: 14px; font-weight: 500; }

/* --- The problem inbox (templates/office/problems.html, redesign P2): the four views as numbers that filter (on a phone
   a row of chips), then the reports in one card: a table on a desk, and under 720 px a card per report with the job
   number and what it waits for on its first line, so that nothing the receiver decides by is behind a sideways scroll.
   A link inside a row (the remake job, the case a failed recheck came from) stays its own target above the row's. --- */
.problem-views { margin: 0 0 16px; }
.problem-views .kpi-note-late { color: var(--late); font-weight: 600; }
.problem-list :is(th, td):first-child { padding-left: 18px; }
.problem-list :is(th, td):last-child { padding-right: 18px; }
.problem-list .col-job { white-space: nowrap; }
.problem-list .col-time { white-space: normal; }
.problem-list .row-link { display: inline-flex; align-items: flex-start; min-height: 40px; font-size: 15px; }
@media (max-width: 1023.98px) { .problem-list .row-link { min-height: 44px; } }
.problem-topic { display: block; font-weight: 600; overflow-wrap: break-word; }
.problem-defect, .problem-sub, .problem-origin { display: block; margin-top: 2px; color: var(--muted); font-size: 13px; }
.problem-origin { position: relative; z-index: 1; color: var(--brand); font-weight: 600; }
@media (max-width: 1023.98px) { .problem-origin { display: inline-flex; align-items: center; min-height: 44px; } }
.problem-pills { display: inline-flex; flex-wrap: wrap; gap: 6px; }
/* A pill of what a report waits for may be long (Burmese): it wraps inside its cell, the job number never does. */
:is(.problem-pills, .case-pills, .case-timeline) .pill { display: inline-block; white-space: normal; border-radius: 12px; }
:is(.problem-list, .case-head) .age { color: var(--muted-2); } /* 4.9:1 on a card and on the canvas alike */
:is(.problem-list-card, .ng-card) .card-table-foot { margin: 0; padding: 12px 18px; border-top: 1px solid var(--line); color: var(--muted); font-size: 13px; }
@media (max-width: 719.98px) {
  /* The numbers that filter a list become one row of chips on a phone (the inbox's views, the register's numbers):
     the label and the count, the current one dark. */
  :is(.problem-views, .ng-numbers-row).kpi-chips {
    display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; margin: 0 -16px 12px; padding: 2px 16px;
  }
  :is(.problem-views, .ng-numbers-row).kpi-chips::-webkit-scrollbar { display: none; }
  :is(.problem-views, .ng-numbers-row).kpi-chips .kpi {
    flex: none; display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 12px;
    border-color: var(--line); border-radius: var(--r-pill); background: var(--card); color: var(--ink);
  }
  :is(.problem-views, .ng-numbers-row).kpi-chips .kpi-label { color: var(--ink); font-size: 14px; }
  :is(.problem-views, .ng-numbers-row).kpi-chips .kpi-value { font-size: 17px; }
  :is(.problem-views, .ng-numbers-row).kpi-chips .kpi-note { display: none; }
  :is(.problem-views, .ng-numbers-row).kpi-chips a.kpi.is-active { border-color: var(--hero); background: var(--hero); box-shadow: none; }
  :is(.problem-views, .ng-numbers-row).kpi-chips a.kpi.is-active :is(.kpi-label, .kpi-value) { color: #ffffff; }
  .problem-list tbody tr {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 4px 12px; padding: 14px 16px;
    grid-template-areas: "job next" "what what" "found when";
  }
  .problem-list tbody :is(th, td):first-child, .problem-list tbody :is(th, td):last-child { padding: 0; }
  .problem-list [data-field="job"] { grid-area: job; align-self: center; }
  .problem-list [data-field="next"] { grid-area: next; justify-self: end; text-align: right; }
  .problem-list [data-field="next"] .problem-pills { justify-content: flex-end; }
  .problem-list [data-field="what"] { grid-area: what; }
  .problem-list [data-field="found"] { grid-area: found; color: var(--muted); font-size: 13px; }
  .problem-list [data-field="when"] { grid-area: when; color: var(--muted); font-size: 13px; text-align: right; white-space: normal; }
}

/* --- The page of a report (templates/office/problem_detail.html, redesign P4): the head (job · item, where and when,
   what it waits for), then the card of what to do now with its one primary in a bar that a phone keeps in sight while
   the card is on screen, the facts and what happened beside it on a desk (under it on a phone), the answer, and the
   rare presses in sheets from the menu (⋯). Each part a press comes back to keeps clear of the sticky app bar. --- */
.case-page [id] { scroll-margin-top: 16px; }
@media (max-width: 1023.98px) {
  .case-page [id] { scroll-margin-top: calc(var(--bar-h) + 16px); }
  .case-head .crumb { display: none; } /* a phone has the back chevron in its app bar */
}
.case-head .page-head {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "main actions" "pills pills";
  align-items: start; gap: 6px 16px; margin-bottom: 10px;
}
.case-head .page-head-main { grid-area: main; }
.case-head .page-actions { grid-area: actions; flex-wrap: nowrap; }
.case-head .page-actions .btn-outline:not(.btn-icon) { width: auto; }
.case-pills { grid-area: pills; display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
@media (max-width: 1023.98px) {
  .case-head .page-head { grid-template-areas: "main main" "pills actions"; align-items: center; }
  /* With the receive button the actions take a row of their own, so that the pills keep their width. */
  .case-head .page-head.has-ack { grid-template-areas: "main main" "pills pills" "actions actions"; }
  .case-head .page-head.has-ack .page-actions { justify-content: flex-end; }
}
.case-hint { margin: -2px 0 12px; font-size: 14px; }
.case-notice { margin: 0 0 12px; }
.case-notice a { color: inherit; font-weight: 700; }
.case-more .overflow-menu-panel { min-width: 240px; }
.case-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; align-items: start; }
.case-grid > .card + .card, .case-side > .card + .card { margin-top: 0; }
.case-side { display: grid; gap: 16px; min-width: 0; }
@media (min-width: 980px) {
  /* The side spans the rows of the left column; the last row takes what the side needs more, so that the cards of
     the left column stay together at the top. */
  .case-grid { grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); grid-template-rows: auto 1fr; }
  .case-grid > :not(.case-side) { grid-column: 1; }
  .case-grid > .case-side { grid-column: 2; grid-row: 1 / span 2; }
}
.case-action { gap: 12px; }
.case-action > .card-head h2 { font-size: 19px; }
.case-lead { margin: 0; color: var(--muted-2); font-size: 14px; }
.case-fieldset { display: grid; gap: 10px; min-width: 0; margin: 0; padding: 0; border: 0; }
.case-fieldset > legend { margin: 0 0 6px; padding: 0; font-size: 15px; font-weight: 700; }
.case-fields-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); align-items: end; gap: 12px; }
.case-fields-grid .case-field-item { grid-column: 1 / -1; }
@media (min-width: 1024px) {
  /* On a desk the three fields are one row, so that the decision and its button are in the first screen. */
  .case-fields-grid { grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.7fr) minmax(0, 1.2fr); }
  .case-fields-grid .case-field-item { grid-column: auto; }
}
.case-fields-save { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 12px; margin-top: 4px; }
.case-fields-save .btn { width: auto; padding-inline: 10px; }
.case-fields-save .hint { flex: 1 1 220px; font-size: 13px; }
.case-decide { display: grid; gap: 14px; }
/* The decisions are cards: the whole card chooses, the one chosen is the green of go, and the line under the name says
   what the decision leads to (a warning, in words and amber, when it short-ships the job). */
.case-page .decision-choices { display: grid; gap: 8px; }
@media (min-width: 560px) { .case-page .decision-choices { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.case-page .decision-choice {
  display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; align-content: start; align-items: center;
  gap: 4px 10px; min-height: 56px; padding: 12px 14px; border: 1.5px solid var(--ctl-line); border-radius: 14px;
  background: var(--card); cursor: pointer;
}
.case-page .decision-choice:hover { background: var(--soft); }
.case-page .decision-choice:has(input:checked) { border-color: var(--brand); background: var(--run-bg); box-shadow: inset 0 0 0 1px var(--brand); }
.case-page .decision-choice:has(input:focus-visible) { outline: 3px solid var(--focus); outline-offset: 2px; }
.case-page .decision-choice input { width: 20px; height: 20px; margin: 0; accent-color: var(--brand); }
.case-page .decision-name { font-weight: 700; }
.case-page .decision-choice .pill { grid-column: 3; }
.case-page .consequence { grid-column: 2 / -1; color: var(--muted); font-size: 13px; line-height: 1.5; }
.case-page .consequence-warn { color: var(--warn); font-weight: 600; }
.case-remake { padding: 12px 14px; border-radius: 14px; background: var(--soft); }
.case-remake > legend { float: left; width: 100%; margin: 0 0 4px; } /* inside the box, not on its edge */
.case-remake > legend + * { clear: both; }
.case-decided { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin: 0; }
.case-decided-label { color: var(--muted); font-size: 13px; font-weight: 600; }
.case-decided b { font-family: var(--font-display); font-size: 19px; }
.case-decided-when { color: var(--muted); font-size: 13px; }
.case-links { margin: 0; }
.case-links .btn { display: inline-flex; width: auto; }
.case-head .crumb { min-height: 40px; }
.case-fields-save .btn, .case-links .btn { min-height: 40px; }
@media (max-width: 1023.98px) { .case-fields-save .btn, .case-links .btn { min-height: 44px; } }
/* A link among the facts is a target of its own: as tall as a button. */
.case-facts dd a { display: inline-flex; align-items: center; min-height: 40px; }
@media (max-width: 1023.98px) { .case-facts dd a { min-height: 44px; } }
.case-close .field-error { margin-bottom: 8px; }
/* The bar of the card: its foot on a desk, and on a phone the sticky bar of the task page (W1), kept in sight while the
   card is on screen. The close button of a case sits in it as a part of its own (#close). */
.case-action .action-bar { margin: 4px -18px -16px; border: 0; border-top: 1px solid var(--line); border-radius: 0 0 var(--r-card) var(--r-card); }
.case-action .action-bar-acts > * { flex: 1 1 0; min-width: 0; }
.case-action .action-bar-acts > .case-close, .case-action .action-bar-acts > .case-close form { display: grid; }
@media (min-width: 1024px) {
  /* On a desk too the bar stays in sight while its card is on screen: a long decision (Burmese, a remake route)
     keeps its button at hand. */
  .case-action .action-bar { position: sticky; bottom: 0; z-index: 5; max-width: none; margin: 4px -18px -16px; padding: 12px 18px; }
  .case-action .action-bar-acts > * { flex: none; }
  .case-action .action-bar-acts .case-close .btn { width: auto; }
}
.case-action.is-ended .card-head { align-items: center; }
/* The sheets of the case (and of the register's NCR number): the title keeps to its head, whatever .admin h2 says. */
:is(.case-sheet, .ncr-sheet) .sheet-head > .sheet-title { margin: 0; }
.case-sheet-form { gap: 14px; }
.case-sheet .sheet-body > .hint { font-size: 14px; }
.case-sheet .decision-choices { grid-template-columns: minmax(0, 1fr); }
/* The save of a sheet stays in sight while a long sheet scrolls (the change of a decision, with its route). */
:is(.case-sheet, .ncr-sheet) .sheet-actions {
  position: sticky; bottom: 0; z-index: 1; display: flex; justify-content: flex-end;
  gap: 8px; margin: 0 -20px calc(-20px - env(safe-area-inset-bottom));
  padding: 10px 20px calc(20px + env(safe-area-inset-bottom)); background: var(--card);
}
:is(.case-sheet, .ncr-sheet) .sheet-actions .btn { width: auto; }
@media (max-width: 719.98px) { :is(.case-sheet, .ncr-sheet) .sheet-actions .btn { width: 100%; } }
/* The facts, the note and the photo, and what happened */
.case-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.case-facts > div { align-content: start; }
.case-job-link { font-weight: 700; }
.case-note, .case-photo { display: grid; gap: 6px; padding-top: 12px; border-top: 1px solid var(--line); }
.case-note h3, .case-photo h3 { margin: 0; color: var(--muted-2); font-size: 14px; }
.case-missing { margin: 0; padding-top: 12px; border-top: 1px solid var(--line); color: var(--muted); font-size: 14px; }
.problem-text { margin: 0; white-space: pre-line; overflow-wrap: anywhere; } /* what was typed keeps its line breaks */
.problem-photo { display: block; max-width: 100%; max-height: 420px; border: 1px solid var(--line); border-radius: 12px; }
.case-timeline .timeline-step { grid-template-columns: 28px minmax(0, 1fr); }
.case-timeline .timeline-dot .ico { width: 14px; height: 14px; }
.case-timeline .timeline-main { display: grid; gap: 2px; min-width: 0; }
.case-timeline .timeline-what { font-weight: 600; }
.case-timeline .timeline-meta { color: var(--muted); font-size: 13px; }
.case-timeline .is-now .timeline-dot { border-color: var(--amber); background: var(--warn-bg); }
/* The answer */
.case-reply-card, .case-answer { gap: 12px; }
.case-reply-now { display: grid; gap: 4px; padding: 10px 12px; border-radius: 12px; background: var(--soft); }
.case-reply-label { margin: 0; color: var(--muted-2); font-size: 13px; font-weight: 600; }
.case-reply { display: grid; gap: 10px; }
.case-reply-foot { display: flex; justify-content: flex-end; }
.case-reply-foot .btn { width: auto; }

/* --- The NG register (templates/office/ng_register.html, redesign P2): the numbers of the month on top, each a link to
   the rows it counts, then one card: the month switch and the filters (they apply as they change; a filter in use is a
   chip that takes itself away), and the cases as a table that fits a desk and becomes a card per case below 1280 px (1600 in Burmese).
   The NCR number of a case is written in a sheet that its row opens. The words of a status or a result sit on their
   pills. A row that was just written is lit by the address (#case-<id>). --- */
.ng-hint { max-width: 760px; margin: -6px 0 14px; font-size: 14px; } /* the NCR rule, for whoever may write the number */
.ng-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; }
.ng-head .page-actions .btn { width: auto; }
.ng-actions-desk { display: flex; flex-wrap: wrap; gap: 8px; }
.ng-more { display: none; }
@media (max-width: 719.98px) {
  .ng-actions-desk { display: none; }
  .ng-more { display: block; }
}
.ng-numbers-row { margin-bottom: 16px; }
.ng-numbers-row a.kpi.kpi-hero.is-active { box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.72); }
.ng-toolbar {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 18px; padding: 14px 18px;
  border-bottom: 1px solid var(--line);
}
.ng-toolbar .month-switch { flex: none; }
.ng-toolbar .month-switch .btn { min-height: 40px; }
.ng-filters {
  display: grid; flex: 1 1 520px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
  gap: 8px 10px; min-width: 0; margin: 0;
}
.ng-filter { display: grid; gap: 4px; min-width: 0; color: var(--muted); font-size: 12px; font-weight: 600; }
.ng-filter select {
  width: 100%; min-width: 0; min-height: 40px; padding: 0 10px; border: 1.5px solid var(--ctl-line);
  border-radius: var(--r-ctl); background: var(--card); color: var(--ink); font: inherit; font-size: 14px; font-weight: 500;
}
.ng-filtered {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; padding: 10px 18px;
  border-bottom: 1px solid var(--line); background: var(--soft);
}
.ng-filter-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin: 0; color: var(--muted-2); font-size: 14px; }
.ng-filter-line b { color: var(--ink); }
.ng-chip { min-height: 36px; padding: 0 10px 0 12px; }
.ng-clear { font-weight: 600; text-underline-offset: 3px; }
/* Long text wraps at word boundaries (B7); only identifiers stay whole. The scroll frame is the fallback. */
.ng-table { font-size: 14px; }
.ng-table th, .ng-table td { padding: 10px; overflow-wrap: break-word; }
.ng-table :is(th, td):first-child { padding-left: 18px; }
.ng-table :is(th, td):last-child { padding-right: 18px; }
.ng-table thead th { white-space: normal; vertical-align: bottom; }
.ng-table [data-field="job"] .id { white-space: nowrap; }
.ng-table [data-field="qty"] { white-space: normal; }
.ng-table :is([data-field="item"], [data-field="cause"]) { min-width: 0; }
.ng-table .pill { display: inline-block; max-width: 100%; white-space: normal; }
.ng-table [data-field="job"] .pill, .ng-table [data-field="rework"] .pill { display: block; width: fit-content; margin-top: 4px; }
.ng-table [data-field="job"] a { display: inline-flex; align-items: center; min-height: 40px; }
@media (max-width: 1023.98px) { .ng-table [data-field="job"] a { min-height: 44px; } }
.ng-table .is-off :is(td, th) { color: var(--muted); }
.ng-table tbody tr { scroll-margin-top: 16px; }
.ng-table tbody tr:focus-within > * { background: var(--run-bg); }
.ng-table tbody tr:target > * { background: var(--run-soft); }
.ng-when { white-space: normal; }
.ng-sub .ng-date { white-space: nowrap; }
.ng-when span, .ng-sub { display: block; color: var(--muted); font-size: 13px; }
.ng-ncr-no { display: block; font-weight: 700; }
.ncr-needed { display: inline-block; white-space: normal; } /* a case the customer found that has no NCR number yet (R3) */
.ng-card .ncr-open { width: auto; min-height: 44px; margin-top: 6px; }
.ng-card .ncr-open span { white-space: nowrap; }
.ncr-saved { margin: 8px 0 0; padding: 8px 10px; font-size: 14px; } /* what was saved, on the row it was saved on */
.ncr-form { display: grid; gap: 14px; }
@media (max-width: 719.98px) {
  .ng-toolbar { padding: 12px 16px; }
  .ng-toolbar .month-switch { width: 100%; justify-content: space-between; }
  .ng-filters { flex-basis: 100%; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ng-filtered { padding: 10px 16px; }
}
@media (max-width: 1279.98px) {
  .ng-table, .ng-table tbody { display: block; }
  .ng-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .ng-table tbody tr { border-bottom: 1px solid var(--line); }
  .ng-table tbody tr:last-child { border-bottom: 0; }
  .ng-table tbody :is(th, td) { display: block; border: 0; }
  .ng-table tbody :is(th, td)[data-label]::before { content: attr(data-label); display: block; color: var(--muted); font-size: 12px; font-weight: 600; }
  /* Each case is a card: what it is on top, then where and why, what was decided and became of it, and the NCR. The
     head of the table stays for a screen reader (W1's card-table), and the cells that need it say their label. */
  .ng-table tbody tr {
    display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 8px 12px; padding: 14px 16px;
    grid-template-areas:
      "job job job status status status"
      "item item item item qty qty"
      "found found found cause cause cause"
      "decision decision decision rework rework rework"
      "date date date date date date"
      "ncr ncr ncr ncr ncr ncr";
  }
  .ng-table tbody :is(th, td)[data-field] { min-width: 0; padding: 0; white-space: normal; text-align: left; }
  .card-table.ng-table tbody :is(th, td):is([data-field="job"], [data-field="item"], [data-field="qty"], [data-field="status"], [data-field="date"])::before { display: none; }
  .ng-table [data-field="job"] { grid-area: job; font-size: 16px; }
  .ng-table [data-field="status"] { grid-area: status; justify-self: end; text-align: right; }
  .ng-table [data-field="item"] { grid-area: item; font-weight: 600; }
  .ng-table [data-field="qty"] { grid-area: qty; justify-self: end; font-weight: 600; }
  .ng-table [data-field="found"] { grid-area: found; }
  .ng-table [data-field="cause"] { grid-area: cause; }
  .ng-table [data-field="decision"] { grid-area: decision; }
  .ng-table [data-field="rework"] { grid-area: rework; }
  .ng-table [data-field="date"] { grid-area: date; color: var(--muted); font-size: 13px; }
  .ng-table [data-field="date"] span { display: inline; }
  .ng-table tbody td[data-field="ncr"] {
    grid-area: ncr; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; padding-top: 10px;
    border-top: 1px dashed var(--line-strong);
  }
  .card-table.ng-table tbody td[data-field="ncr"]::before { flex-basis: 100%; }
  .ng-table td[data-field="ncr"] .ncr-saved { flex-basis: 100%; }
  .ng-table tbody tr:target { background: var(--run-soft); }
  .ng-table tbody tr:hover > *, .ng-table tbody tr:focus-within > *, .ng-table tbody tr:target > * { background: none; }
  .ng-card .ncr-open { width: auto; margin: 0 0 0 auto; }
}


@media (min-width: 1280px) and (max-width: 1599.98px) {
  .ng-table:lang(my), .ng-table:lang(my) tbody { display: block; }
  .ng-table:lang(my) thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .ng-table:lang(my) tbody tr { border-bottom: 1px solid var(--line); }
  .ng-table:lang(my) tbody tr:last-child { border-bottom: 0; }
  .ng-table:lang(my) tbody :is(th, td) { display: block; border: 0; }
  .ng-table:lang(my) tbody :is(th, td)[data-label]::before { content: attr(data-label); display: block; color: var(--muted); font-size: 12px; font-weight: 600; }
  /* Each case is a card: what it is on top, then where and why, what was decided and became of it, and the NCR. The
     head of the table stays for a screen reader (W1's card-table), and the cells that need it say their label. */
  .ng-table:lang(my) tbody tr {
    display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 8px 12px; padding: 14px 16px;
    grid-template-areas:
      "job job job status status status"
      "item item item item qty qty"
      "found found found cause cause cause"
      "decision decision decision rework rework rework"
      "date date date date date date"
      "ncr ncr ncr ncr ncr ncr";
  }
  .ng-table:lang(my) tbody :is(th, td)[data-field] { min-width: 0; padding: 0; white-space: normal; text-align: left; }
  .card-table.ng-table:lang(my) tbody :is(th, td):is([data-field="job"], [data-field="item"], [data-field="qty"], [data-field="status"], [data-field="date"])::before { display: none; }
  .ng-table:lang(my) [data-field="job"] { grid-area: job; font-size: 16px; }
  .ng-table:lang(my) [data-field="status"] { grid-area: status; justify-self: end; text-align: right; }
  .ng-table:lang(my) [data-field="item"] { grid-area: item; font-weight: 600; }
  .ng-table:lang(my) [data-field="qty"] { grid-area: qty; justify-self: end; font-weight: 600; }
  .ng-table:lang(my) [data-field="found"] { grid-area: found; }
  .ng-table:lang(my) [data-field="cause"] { grid-area: cause; }
  .ng-table:lang(my) [data-field="decision"] { grid-area: decision; }
  .ng-table:lang(my) [data-field="rework"] { grid-area: rework; }
  .ng-table:lang(my) [data-field="date"] { grid-area: date; color: var(--muted); font-size: 13px; }
  .ng-table:lang(my) [data-field="date"] span { display: inline; }
  .ng-table:lang(my) tbody td[data-field="ncr"] {
    grid-area: ncr; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; padding-top: 10px;
    border-top: 1px dashed var(--line-strong);
  }
  .card-table.ng-table:lang(my) tbody td[data-field="ncr"]::before { flex-basis: 100%; }
  .ng-table:lang(my) td[data-field="ncr"] .ncr-saved { flex-basis: 100%; }
  .ng-table:lang(my) tbody tr:target { background: var(--run-soft); }
  .ng-table:lang(my) tbody tr:hover > *, .ng-table:lang(my) tbody tr:focus-within > *, .ng-table:lang(my) tbody tr:target > * { background: none; }
  .ng-card:lang(my) .ncr-open { width: auto; margin: 0 0 0 auto; }
}

/* --- The executive overview (templates/office/overview.html, redesign P1): four numbers (the late jobs the one dark
   hero), the jobs to follow up (late, then due today) in the first screen of a phone, then the stations and the quality
   of the month as bars that link to their lists. A bar is a <progress> drawn in the palette, so that no page carries a
   style of its own; the longest bar of a list is dark, the others quiet. --- */
.ov-kpis { margin: 0 0 16px; }
@media (max-width: 719.98px) { .ov-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; } }
.ov-follow { margin: 0 0 16px; }
.ov-card-head { padding: 16px 18px 8px; }
.ov-follow-table :is(th, td):first-child { padding-left: 18px; }
.ov-follow-table :is(th, td):last-child { padding-right: 18px; }
.ov-follow-table .row-link { display: inline-flex; align-items: flex-start; min-height: 40px; font-size: 15px; }
@media (max-width: 1023.98px) { .ov-follow-table .row-link { min-height: 44px; } }
.ov-card-foot .btn { min-height: 40px; }
.ov-card-foot { display: flex; align-items: center; justify-content: flex-end; gap: 4px 12px; padding: 4px 8px; border-top: 1px solid var(--line); }
.ov-shown { margin-right: auto; padding-left: 10px; color: var(--muted); font-size: 13px; }
.ov-card-foot .btn { gap: 2px; }
@media (max-width: 1023.98px) { .ov-card-foot .btn { min-height: 44px; } }
@media (max-width: 719.98px) {
  .ov-follow-table tbody tr {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 2px 12px; padding: 12px 16px;
    grid-template-areas: "job due" "customer customer" "step step";
  }
  .ov-follow-table tbody :is(th, td):first-child, .ov-follow-table tbody :is(th, td):last-child { padding: 0; }
  .ov-follow-table [data-field="job"] { grid-area: job; align-self: center; }
  .ov-follow-table [data-field="due"] { grid-area: due; justify-self: end; text-align: right; }
  .ov-follow-table [data-field="due"] .pill { white-space: normal; border-radius: 12px; }
  .ov-follow-table [data-field="customer"] { grid-area: customer; }
  .ov-follow-table [data-field="step"] { grid-area: step; color: var(--muted); font-size: 13px; }
}
.ov-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; align-items: start; }
@media (min-width: 980px) { .ov-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.ov-grid > .card + .card { margin-top: 0; }
.ov-bars { --bar-top: var(--hero-2); --bar-rest: #c9d3ce; gap: 2px; }
.ov-bars li { display: block; }
.ov-bars a { grid-template-columns: minmax(0, 9em) minmax(0, 1fr) 2.5em; min-height: 40px; padding: 0 6px; }
.ov-bar-label { font-size: 14px; overflow-wrap: anywhere; }
.ov-bar-num { font-family: var(--font-display); font-size: 16px; font-variant-numeric: tabular-nums; text-align: right; }
.ov-bar {
  -webkit-appearance: none; appearance: none; display: block; width: 100%; height: 10px; margin: 0; border: 0;
  border-radius: var(--r-pill); background: var(--soft); color: var(--bar-rest); overflow: hidden;
}
.ov-bar::-webkit-progress-bar { border-radius: var(--r-pill); background: var(--soft); }
.ov-bar::-webkit-progress-value { border-radius: var(--r-pill); background: var(--bar-rest); }
.ov-bar::-moz-progress-bar { border-radius: var(--r-pill); background: var(--bar-rest); }
.ov-bar.is-top::-webkit-progress-value { background: var(--bar-top); }
.ov-bar.is-top::-moz-progress-bar { background: var(--bar-top); }
@media (max-width: 1023.98px) { .ov-bars a { min-height: 44px; } }
.ov-quality h3, .ov-units h3 { margin: 4px 0 0; color: var(--muted-2); font-size: 14px; }
.ov-quality-nums { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.ov-quality-nums a.mini-tile { align-content: start; min-height: 64px; color: var(--ink); text-decoration: none; }
.ov-quality-nums a.mini-tile:hover { background: var(--line); }
.ov-units ul { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 4px 0 0; padding: 0; list-style: none; }
.ov-units b { font-family: var(--font-display); font-size: 18px; }
.ov-none { margin: 0; color: var(--muted); }

/* --- The audit page (templates/admin/audit.html, redesign P2d, the feed): one table whose groups are the Bangkok days,
   the newest first; each row the time, what was done (its words, or its code), who (the name and the role, the system
   for the server's own command, never the reporter of a problem), what it was about, and the reason. Under 720 px each
   row is a card of three lines. --- */
.audit-table { font-size: 14px; }
.audit-table :is(th, td):first-child { padding-left: 18px; }
.audit-table :is(th, td):last-child { padding-right: 18px; }
.audit-table .audit-day > th {
  padding: 10px 18px; border-bottom: 1px solid var(--line); background: var(--soft);
  font-family: var(--font-display); font-size: 15px; font-weight: 700;
}
.audit-table tbody tr.audit-day:hover > * { background: var(--soft); }
.audit-time { color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.audit-what { font-weight: 600; overflow-wrap: anywhere; }
.audit-code { overflow-wrap: anywhere; }
.audit-who { min-width: 10em; }
.audit-entity { color: var(--muted); white-space: normal; }
.audit-entity a { display: inline-flex; align-items: flex-start; min-height: 40px; color: var(--brand); }
.audit-reason { color: var(--muted-2); overflow-wrap: anywhere; }
@media (max-width: 719.98px) {
  .audit-table tbody tr[data-action] {
    grid-template-columns: auto minmax(0, 1fr); gap: 2px 12px; padding: 10px 16px;
    grid-template-areas: "time what" ". who" ". entity" ". reason";
  }
  .audit-table tbody tr.audit-day { padding: 0; }
  .audit-table tbody tr.audit-day > th { padding: 10px 16px; }
  .audit-table tbody :is(th, td):first-child, .audit-table tbody :is(th, td):last-child { padding-left: 0; padding-right: 0; }
  .audit-table .audit-time { grid-area: time; }
  .audit-table .audit-what { grid-area: what; }
  .audit-table .audit-who { grid-area: who; min-width: 0; color: var(--muted-2); font-size: 13px; }
  .audit-table .audit-entity { grid-area: entity; font-size: 13px; }
  .audit-table .audit-reason { grid-area: reason; font-size: 13px; }
  .audit-table .audit-reason:empty { display: none; }
}

/* The NG register to print (templates/print/ng_register.html, QCF014): one table on A4 landscape, black and white and
   measured in mm. Its page box is a named one that only the register uses, as the work order's is, so that printing any
   other page keeps the printer's own paper size. The head of the table and its footer repeat on every printed page. */
@page ngregister { size: A4 landscape; margin: 10mm }
/* The toolbar over the paper (not printed): the title and the print button; the shell's bar above it has the way back.
   On a screen narrower than the sheet, the page's script zooms the sheet to the width (pinch to zoom in); it prints at
   its own size. */
.ngreg-bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px;
  max-width: 297mm; margin: 0 auto; padding: 16px 16px 0;
}
.ngreg-bar-title { margin: 0; font-family: var(--font-display); font-size: 22px; line-height: 1.3; }
.ngreg-bar .btn { width: auto; }
.ngreg-stage { display: flex; flex-direction: column; align-items: safe center; padding: 16px 16px 48px; overflow-x: auto; }
.ngreg {
  page: ngregister;
  --ng-ink: #111214; --ng-ink-2: #44474c; --ng-hair: #8e9298; --ng-tint: #eff0ec;
  flex: none; width: 297mm; min-height: 210mm; padding: 10mm;
  background: #ffffff; color: var(--ng-ink); box-shadow: 0 1px 2px rgba(0, 0, 0, .08), 0 8px 24px rgba(0, 0, 0, .10);
  font-family: var(--font); font-size: 7.6pt; line-height: 1.35; font-variant-numeric: tabular-nums;
  -webkit-print-color-adjust: exact; print-color-adjust: exact;
}
.ngreg:lang(my) { line-height: 1.7; }
.ngreg-hd { display: flex; align-items: center; gap: 4mm; padding-bottom: 2.4mm; border-bottom: 0.6mm solid var(--ng-ink); }
.ngreg-hd img { width: auto; height: 8.4mm; }
.ngreg-hd h2 { margin: 0; font-family: var(--font-head); font-size: 16pt; font-weight: 700; line-height: 1.2; }
.ngreg-trial { display: inline-block; padding: 0.4mm 1.8mm; border: 0.35mm solid var(--ng-ink); font-size: 7pt; font-weight: 700; white-space: nowrap; }
.ngreg-month { margin-left: auto; color: var(--ng-ink-2); font-size: 9pt; white-space: nowrap; }
.ngreg-month b { margin-left: 1mm; color: var(--ng-ink); font-family: var(--font-head); font-size: 14pt; }
.ngreg-filters { display: flex; flex-wrap: wrap; gap: 0 4mm; margin: 2mm 0 0; color: var(--ng-ink-2); font-size: 7.4pt; }
.ngreg-filters b { color: var(--ng-ink); }
.ngreg-table { width: 100%; margin-top: 3mm; border-collapse: collapse; table-layout: fixed; }
.ngreg-table thead { display: table-header-group; }
.ngreg-table tfoot { display: table-footer-group; }
.ngreg-table tr { break-inside: avoid; }
.ngreg-table th, .ngreg-table td {
  padding: 1mm 1.3mm; border: 0.2mm solid var(--ng-hair); text-align: left; vertical-align: top; overflow-wrap: anywhere;
}
.ngreg-table thead th { background: var(--ng-tint); font-size: 7pt; font-weight: 600; line-height: 1.2; vertical-align: bottom; }
.ngreg-table tbody th { font-weight: 600; }
.ngreg-table td span, .ngreg-table tbody th span { display: block; color: var(--ng-ink-2); font-size: 6.6pt; }
.ngreg-table .ngreg-num { text-align: right; }
.ngreg-table tfoot td { padding: 1.6mm 0 0; border: 0; }
.ngreg-table td.ngreg-none { padding: 5mm; border: 0.2mm solid var(--ng-hair); color: var(--ng-ink-2); text-align: center; }
.ngreg-ft { display: flex; justify-content: space-between; gap: 4mm; color: var(--ng-ink-2); font-size: 6.6pt; }
.ngreg-ft b { color: var(--ng-ink); font-weight: 600; }
.ngc-date { width: 7.5%; }
.ngc-job { width: 8%; }
.ngc-item { width: 9.5%; }
.ngc-qty { width: 7.5%; }
.ngc-found { width: 9%; }
.ngc-cause { width: 9%; }
.ngc-decision { width: 7.5%; }
.ngc-decided { width: 7.5%; }
.ngc-rework { width: 9%; }
.ngc-recheck { width: 6.5%; }
.ngc-pdf003 { width: 5.5%; }
.ngc-ncr { width: 6%; }
.ngc-status { width: 7.5%; }
@media print {
  .ngreg-stage { display: block; padding: 0; overflow: visible; }
  .ngreg { width: auto; min-height: 0; padding: 0; box-shadow: none; zoom: 1 !important; }
}
@media (max-width: 1023.98px) {
  .ng-toolbar .month-switch .btn, .ng-filter select, .audit-table .audit-entity a { min-height: 44px; }
}
.ngreg-bar .ngreg-back { display: none; }
@media (min-width: 1024px) { .ngreg-bar .ngreg-back { display: inline-flex; margin-left: auto; } }
.ngreg-table [data-field="rework"] { overflow-wrap: normal; white-space: nowrap; }
/* ===== end W5 ===== */

/* ===== W6 admin+setup (owned by W6) ===== */
/* The admin and setup pages (templates/admin/, device_setup.html; redesign W6). Every list is rows that open a page of
   their own (P3); a form is cards of fields with one save in the bar at its foot, kept in sight on a phone (P5); the
   status pages put the one live thing in the dark hero card (P4); a one-time link is a QR, a countdown, Share and Copy
   (P7). The W1 components carry the look: these rules only place them, and keep the hooks the pages of plan 5 had. */

/* --- shared: titles in cards, muted words, the bar of a form in a card, the help fold ----------------------------- */
/* Every W6 page wraps its content in .setup-page: the office pages share <main class="admin"> and stay untouched. */
.setup-page .card-title { margin: 0; font-family: var(--font-display); font-size: 17px; font-weight: 700; }
.setup-page .muted { color: var(--muted-2); }
.setup-page .page-head .page-actions .pill { font-size: 14px; }
/* A crumb up is a desk's way back (40px for a mouse); a phone's task page has the back chevron of its green bar. */
.setup-page .crumb { min-height: 40px; }
@media (max-width: 1023.98px) { .is-task .setup-page .crumb { display: none; } }
/* A small button keeps a mouse's 40px on a desk and a thumb's 44px on a phone. */
@media (min-width: 1024px) { .setup-page .btn-sm { min-height: 40px; } }
/* The bar of a form that sits in a card: the card's foot, its own line above it; sticky at the bottom of a phone. */
.setup-page .card .action-bar, .setup-page form.card > .action-bar {
  max-width: none; margin: 8px -18px -16px; padding: 12px 18px;
  border: 0; border-top: 1px solid var(--line); border-radius: 0 0 var(--r-card) var(--r-card); background: var(--card);
}
.setup-page .card-flush .action-bar { margin: 0; }
.setup-page .user-form > .action-bar { max-width: none; margin: 0; }
@media (max-width: 1023.98px) {
  .is-task .setup-page .card .action-bar { margin: 8px -18px -16px; padding: 10px 18px calc(10px + env(safe-area-inset-bottom)); }
  .is-task .setup-page .card-flush .action-bar { margin: 0; }
  .is-task .setup-page .user-form > .action-bar { margin: 0 -16px; padding-inline: 16px; border-radius: 0; }
}
/* On a desk a long form keeps its save in sight too: the bar sticks to the bottom of the window while its form shows. */
@media (min-width: 1024px) {
  .setup-page .user-form > .action-bar { position: sticky; bottom: 16px; z-index: 5; box-shadow: var(--pop-shadow); }
  .setup-page .card .action-bar { position: sticky; bottom: 0; z-index: 5; }
}
/* A card whose bar sticks may not clip (W1's card-flush does, for its corners): the order mode's card. */
.setup-page .card-flush.reorder { overflow: visible; }
/* The forms of one row read best at a column's width on a desk. */
.setup-page :is(.cat-form, .station-card, .machines-card, .machine-card, .doc-edit, .buffer-card, .fa-cutover, .holiday-add-card) { max-width: 760px; }
.setup-page .action-bar .btn-text { flex: 0 0 auto; }
/* The help of a page, folded under one quiet row (P3: explanations move behind a fold). */
.help-fold { margin: 16px 0 0; border: 1px solid var(--line); border-radius: 14px; background: var(--card); }
.help-fold > summary {
  display: flex; align-items: center; gap: 8px; min-height: 48px; padding: 4px 14px;
  color: var(--muted-2); font-weight: 600; cursor: pointer; list-style: none;
}
.help-fold > summary::-webkit-details-marker { display: none; }
.help-fold > summary > span { flex: 1; }
.help-fold-mark { transition: transform 150ms ease-out; }
.help-fold[open] .help-fold-mark { transform: rotate(180deg); }
.help-fold-body { display: grid; gap: 8px; padding: 0 14px 14px; color: var(--muted-2); font-size: 14px; }
.help-fold-body p { max-width: 72ch; margin: 0; }

/* --- the catalogues: problem topics, causes (P3) ----------------------------------------------------------------- */
.cat-card .card-head { padding: 12px 8px 4px 18px; }
.cat-head { align-items: center; }
.setup-page .cat-head-title { margin: 0; color: var(--muted); font-family: var(--font); font-size: 13px; font-weight: 600; }
.cat-head .btn { width: auto; }
.cat-list .list-row, .machine-rows .list-row { padding: 10px 16px 10px 18px; }
.cat-row .list-row-meta span + span { margin-left: 0; }
.cause-rev { margin-bottom: 16px; }
/* The list says the Rev rule in one line that opens to it (UX-11); the views that change the list show it in full. */
.help-fold.cause-rev-fold { margin: 0 0 16px; border-color: transparent; background: var(--warn-bg); }
.cause-rev-fold > summary { color: var(--warn); }
.cause-rev-fold .help-fold-body { color: var(--warn); }
/* The form of one row: its fields, then the other two names in a fold that says what is in it while it is closed. */
.cat-form, .station-form, .machine-form, .doc-form, .buffer-form { display: grid; gap: 16px; min-width: 0; }
.other-names-box { display: grid; gap: 6px; min-width: 0; }
.other-names { border: 1px solid var(--line); border-radius: var(--r-ctl); background: var(--card); }
.other-names > summary {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 2px 10px;
  min-height: 52px; padding: 8px 14px; cursor: pointer; list-style: none;
}
.other-names > summary::-webkit-details-marker { display: none; }
.other-names-title { font-weight: 600; }
.other-names-preview { grid-column: 1; color: var(--muted); font-size: 14px; overflow-wrap: anywhere; }
.other-names-mark { grid-column: 2; grid-row: 1 / span 2; transition: transform 150ms ease-out; }
.other-names[open] .other-names-mark { transform: rotate(180deg); }
.other-names[open] > summary { border-bottom: 1px solid var(--line); }
.other-names-fields { display: grid; gap: 14px; padding: 14px; }
.setup-page .field > label { font-weight: 600; }
.switch-field { gap: 4px; }
.switch.is-locked { cursor: default; color: var(--muted-2); }
.switch-track.is-on { background: var(--brand); opacity: 0.55; }
.switch-track.is-on::after { transform: translateX(18px); }
.setup-page .field-error { margin: 0; }

/* --- the order mode (P2c): the place, the name, and up and down always in sight ------------------------------------ */
.reorder-hint { margin: 0; padding: 14px 18px 4px; color: var(--muted-2); font-size: 14px; }
.reorder-list { display: grid; margin: 0; padding: 4px 0; list-style: none; }
.reorder-row {
  display: grid; grid-template-columns: 32px minmax(0, 1fr) auto auto; align-items: center; gap: 8px;
  min-height: 60px; padding: 6px 12px 6px 16px; border-top: 1px solid var(--line);
}
.reorder-row:first-child { border-top: 0; }
.reorder-no {
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; background: var(--soft);
  color: var(--muted-2); font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.reorder-name { display: grid; min-width: 0; }
.reorder-title { font-weight: 600; overflow-wrap: anywhere; }
.reorder-meta { color: var(--muted); font-size: 13px; overflow-wrap: anywhere; }
.reorder-row .btn-icon { width: 44px; min-width: 44px; min-height: 44px; }
.reorder.is-busy .reorder-list { opacity: 0.6; pointer-events: none; }
.reorder-failed { margin: 8px 16px; }

/* --- the stations (P3 as a table, a page each) ------------------------------------------------------------------ */
.buffer-card { grid-template-columns: minmax(0, 1fr) auto; align-items: center; margin-bottom: 16px; }
.buffer-fact { display: grid; gap: 2px; min-width: 0; }
.setup-page .buffer-title { margin: 0; color: var(--muted); font-family: var(--font); font-size: 13px; font-weight: 600; }
.buffer-value { margin: 0; font-family: var(--font-display); font-size: 24px; font-weight: 700; line-height: 1.2; }
.buffer-card .buffer-edit { width: auto; }
.buffer-card > .buffer-form { grid-column: 1 / -1; }
.stations-table .setup-name { font-weight: 700; }
.stations-table .station-machines { color: var(--muted-2); font-size: 14px; }
.machine-name.is-off { color: var(--muted); }
.stations-table .station-std { white-space: nowrap; font-variant-numeric: tabular-nums; }
.stations-table .station-state { text-align: right; white-space: nowrap; }
.station-chev { display: inline-flex; vertical-align: middle; margin-left: 6px; }
.card-table tbody tr.is-off .setup-name, .card-table tbody tr.is-off .device-name { color: var(--muted-2); }
.setup-page .card-table tbody tr:target > * { background: var(--ok-bg); }
.stations-table .row-link { display: inline-flex; align-items: center; min-width: 44px; min-height: 44px; }
.stations-table .station-machines .muted { font-size: 14px; }
/* A desk: the cells of a row on one middle line, the 44px link of the name with them (UX-15). */
@media (min-width: 720px) { .stations-table tbody :is(th, td), .devices-table tbody :is(th, td) { vertical-align: middle; } }
/* A phone: the name and the standard time on the first line, the machines under them, the chevron at the end. */
@media (max-width: 719.98px) {
  .stations-table tbody tr {
    grid-template-columns: minmax(0, 1fr) auto auto; grid-template-areas: "name std state" "machines machines state";
    align-items: center; gap: 0 10px; padding: 8px 12px 8px 16px;
  }
  .stations-table tbody th { grid-area: name; }
  .stations-table .station-std { grid-area: std; color: var(--muted-2); font-size: 14px; }
  .stations-table .station-machines { grid-area: machines; font-size: 13px; }
  .stations-table .station-state { grid-area: state; }
  .stations-table tbody td.station-machines[data-label]::before, .stations-table tbody td.station-std[data-label]::before { content: none; }
  .stations-table .station-machines:has(> .muted) { display: none; }
}
.station-card { margin-bottom: 16px; }
.machines-card .card-head { padding: 14px 8px 6px 18px; align-items: center; }
.machines-head h2 { display: flex; align-items: center; gap: 8px; }
.machines-head .btn { width: auto; }
.machines-foot { margin: 0; padding: 12px 18px; }

/* --- the user list (P2) ----------------------------------------------------------------------------------------- */
.users-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 420px) {
  .users-kpis { gap: 8px; }
  .users-kpis .kpi { padding: 12px; }
  .users-kpis .kpi-label { font-size: 12px; }
}
/* What needs looking after: one row that counts it, opening onto the boxes of plan 5. */
.attention { margin: 0 0 16px; border-radius: 14px; background: var(--warn-bg); color: var(--warn); }
.attention > summary {
  display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 6px 14px; font-weight: 700; cursor: pointer;
  list-style: none;
}
.attention > summary::-webkit-details-marker { display: none; }
.attention > summary > span { flex: 1; }
.attention-mark { transition: transform 150ms ease-out; }
.attention[open] .attention-mark { transform: rotate(180deg); }
.attention-body { display: grid; gap: 10px; padding: 0 10px 10px; }
.attention-body .notice { margin: 0; background: var(--card); }
.users-toolbar { margin: 0 0 12px; }
.users-toolbar .search { flex: 1 1 260px; }
.users-toolbar .search .ico { color: var(--muted); }
.users-toolbar .search input { min-height: 44px; }
.users-toolbar .filter-chips { flex-wrap: wrap; }
.users-toolbar .chip { min-height: 44px; }
.users-toolbar .chip .ico { margin-right: -4px; }
.users-table .col-name a {
  display: inline-flex; align-items: center; min-height: 44px; color: var(--ink); font-weight: 700; text-decoration: none;
  overflow-wrap: anywhere;
}
.users-table tbody th, .users-table tbody td { vertical-align: middle; }
.users-table .col-name a::after { content: ""; position: absolute; inset: 0; }
.users-table .col-name a:focus-visible { outline: 0; }
.users-table tbody tr:has(.col-name a:focus-visible) > * { box-shadow: inset 0 0 0 3px var(--focus); }
.users-table tbody tr.is-off .col-name a { color: var(--muted-2); }
.users-table .chips li { font-size: 13px; }
.users-table .chips-station li { background: var(--soft); }
.table-foot { margin: 0; padding: 10px 18px 12px; border-top: 1px solid var(--line); color: var(--muted); font-size: 13px; }
@media (max-width: 719.98px) {
  .users-table tbody tr {
    grid-template-columns: minmax(0, 1fr); grid-template-areas: "name" "line" "roles" "stations" "status";
    gap: 6px 12px; padding: 12px 16px;
  }
  .users-table .col-name { grid-area: name; align-self: center; }
  .users-table .col-line { grid-area: line; align-self: center; }
  .users-table .col-roles { grid-area: roles; }
  .users-table .col-stations { grid-area: stations; }
  .users-table .col-status { grid-area: status; }
  .users-table tbody tr:not(.is-off) .col-status, .users-table .col-roles:has(> .muted), .users-table .col-stations:has(> .muted) { display: none; }
}
/* The LINE word of an account: a word in the colour that agrees with it (the fake LINE's pages use it too), and on the
   user list and the user form a pill of that tone. */
.line-state { margin: 0; font-weight: 600; }
.line-state[data-line-state="unbound"] { color: var(--ink-2); }
.line-state[data-line-state="bound_friend"] { color: var(--go); }
.line-state[data-line-state="bound_not_friend"] { color: var(--help); }
:is(.col-line, .line-card) .line-state {
  display: inline-flex; align-items: center; padding: 2px 10px; border-radius: var(--r-pill);
  background: var(--ok-bg); color: var(--ok); font-size: 13px; line-height: 1.5;
}
:is(.col-line, .line-card) .line-state[data-line-state="unbound"] { background: var(--idle-bg); color: var(--idle); }
:is(.col-line, .line-card) .line-state[data-line-state="bound_not_friend"] { background: var(--warn-bg); color: var(--warn); }
:is(.col-line, .line-card) .line-state[data-line-state="bound_unknown"] { background: var(--soft); color: var(--muted-2); }
.card-table .is-off .col-line .line-state { background: var(--idle-bg); color: var(--idle); }
/* The list of the people to follow up marks the holders of a role that gets alerts beside their name (m6). */
.users-table .col-name .line-alerted { margin-left: 6px; vertical-align: middle; }
/* (Plan 5: the LINE word of a row stays on one line, as the status word beside it does.) */
.col-line .line-state { white-space: nowrap; }

/* --- the user form (P5) ----------------------------------------------------------------------------------------- */
.user-form { display: grid; gap: 16px; max-width: 760px; }
.user-form .form-section { margin: 0; }
.user-form fieldset.form-section { min-width: 0; }
.user-form fieldset.form-section > legend {
  float: left; width: 100%; margin: 0 0 12px; padding: 0; font-family: var(--font-display); font-size: 17px; font-weight: 700;
}
.user-form fieldset.form-section > legend + * { clear: both; }
.user-form .seg { flex-wrap: wrap; }
.user-form .seg label { flex: 1 1 auto; }
.user-form .seg span { justify-content: center; width: 100%; min-height: 44px; }
.user-form .toggle-chips input:checked + span::before {
  content: ""; flex: none; width: 10px; height: 6px; margin: -3px 2px 0 0;
  border-left: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(-45deg);
}
.user-status { margin-top: 0; }
.user-status h2 { font-family: var(--font-display); }
.seg-danger input[value="0"]:checked + span { background: var(--late); }
.user-line-jump { min-height: 44px; padding-inline: 14px; text-decoration: none; }
@media (min-width: 1024px) { .user-line-jump { min-height: 40px; } }
/* A desk: the account's LINE beside its form, in sight while the form scrolls (the form comes first to read). */
@media (min-width: 1100px) {
  .user-page { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 16px; align-items: start; }
  .user-page > .user-form { grid-column: 1; grid-row: 1; }
  .user-page > .line-card { position: sticky; top: 16px; grid-column: 2; grid-row: 1; margin: 0; }
}
.line-card { display: grid; gap: 12px; justify-items: start; max-width: 760px; margin: 16px 0; }
.line-card h2 { margin: 0; font-family: var(--font-display); font-size: 17px; }
.line-card .notice { justify-self: stretch; margin: 0; }
.line-card .readonly { color: var(--muted-2); }
.line-form { margin: 0; }
.line-unbind { display: grid; gap: 12px; justify-items: start; justify-self: stretch; padding-top: 12px; border-top: 1px solid var(--line); }
.line-unbind-ask { display: grid; gap: 12px; margin: 0; }
.line-unbind-ask p { margin: 0; font-weight: 600; }
.line-unbind-ask .form-actions { margin: 0; }
/* A phone: the LINE card of an open account that has something to do with LINE comes first, right under the head
   (UX-1); a desk keeps it in its column beside the form (above). The form's bar stays at the form's foot. */
@media (max-width: 1099.98px) {
  .user-page.is-line-first { display: flex; flex-direction: column; }
  .user-page.is-line-first > .line-card { order: -1; margin: 0 0 16px; }
}
.user-line-jump.btn { gap: 4px; }
/* A link that is out: until when it works, then the new link behind a question that says the old one dies (I1). */
.line-invite-out { margin: 0; color: var(--ink-2); font-weight: 600; }
.line-again { display: grid; gap: 12px; justify-items: start; justify-self: stretch; }
.line-again > summary { list-style: none; cursor: pointer; }
.line-again > summary::-webkit-details-marker { display: none; }
.line-again[open] > summary { border-color: var(--line-strong); color: var(--muted-2); }
.line-again-ask { display: grid; gap: 12px; justify-items: start; justify-self: stretch; margin: 0; }
.line-again-ask p { margin: 0; font-weight: 600; }

/* --- the QR of a link, folded (the OA's link on the user form and the LINE page) --------------------------------- */
.qr { display: inline-block; padding: 8px; border: 1px solid var(--line-strong); border-radius: 12px; background: #ffffff; }
.qr svg { display: block; width: 240px; max-width: 100%; height: auto; shape-rendering: crispEdges; }
.qr-fold > summary {
  display: inline-flex; align-items: center; min-height: 44px; color: var(--brand); font-weight: 600; cursor: pointer;
}
.qr-wrap { padding-top: 8px; }
.oa-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.oa-actions .btn { width: auto; }

/* --- the one-time link: a LINE invite, a device's setup link (P7) -------------------------------------------------- */
.otl-layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; align-items: start; }
.otl-layout > .card + .card { margin-top: 0; } /* the grid's gap spaces them: side by side, both start at one line (UX-15) */
@media (min-width: 980px) { .otl-layout { grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); } }
.otl-who { gap: 10px; }
.otl-name { margin: 0; font-family: var(--font-display); font-size: 22px; font-weight: 700; line-height: 1.3; overflow-wrap: anywhere; }
.line-invite-who { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 16px; margin: 0; }
.line-invite-who dt { color: var(--muted); font-size: 13px; font-weight: 600; }
.line-invite-who dd { margin: 0; }
.otl-who .readonly { display: flex; gap: 8px; }
.otl-who .readonly-label { min-width: 5em; color: var(--muted); font-size: 13px; }
.otl-steps { display: grid; gap: 8px; margin: 4px 0 0; padding-left: 22px; }
.one-time-link { justify-items: stretch; gap: 14px; }
.one-time-link .otl-qr { justify-self: center; }
.one-time-link .otl-qr svg { width: 220px; }
.otl-left { justify-self: center; margin: 0; }
.otl-left .pill { font-size: 14px; }
.otl-field input.link-box { font-family: var(--font); font-size: 14px; }
/* iOS zooms into a field of under 16px when it takes the focus (UX-16). */
@media (max-width: 1023.98px) { .otl-field input.link-box { font-size: 16px; } }
.otl-copy-failed { margin: 0; color: var(--late); font-weight: 600; }
.otl-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); gap: 8px; }
.otl-hint { margin: 0; color: var(--muted-2); font-size: 14px; }
.otl-next-box { display: grid; gap: 8px; margin-top: 16px; }
.otl-next { padding: 12px 16px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); }
.otl-all-bound { display: flex; align-items: center; gap: 8px; margin: 0; color: var(--ok); font-weight: 600; }
.otl-next-end { margin: 0; color: var(--ink-2); font-weight: 600; }
.otl-next-end a { display: inline-flex; align-items: center; min-height: 44px; color: var(--brand-deep); font-weight: 700; text-underline-offset: 3px; }
.otl-next-box .otl-back { justify-self: start; }

/* --- the document templates (P3) --------------------------------------------------------------------------------- */
.doc-dar { margin-bottom: 16px; }
.doc-card + .doc-card { margin-top: 12px; }
.doc-row { padding: 12px 16px 12px 18px; }
.doc-footer { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; }
.doc-footer-label { color: var(--muted-2); font-size: 13px; font-weight: 600; }
.footer-code, .footer-preview { color: var(--ink); font-size: 15px; font-weight: 600; } /* the footer a form prints */
.doc-now, .doc-preview { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin: 0; }
.doc-preview { padding: 10px 12px; border-radius: var(--r-ctl); background: var(--soft); }

/* --- the holidays (P3) --------------------------------------------------------------------------------------------- */
.holidays-card { gap: 4px; }
.holiday-month { margin: 12px 0 0; color: var(--muted); font-family: var(--font); font-size: 13px; font-weight: 700; }
.holiday-months > .holiday-month:first-child { margin-top: 4px; }
.holiday-row { display: flex; align-items: center; gap: 8px; min-height: 52px; }
.holiday-date { display: flex; flex: 1; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; min-width: 0; }
.holiday-date time { font-weight: 700; font-variant-numeric: tabular-nums; }
.holiday-weekday { color: var(--muted); font-size: 14px; }
.holiday-remove { color: var(--muted-2); }
.holiday-add { display: grid; gap: 14px; }
.holiday-add-card { margin-bottom: 16px; }
.past-box { margin-top: 16px; border: 1px solid var(--line); border-radius: 14px; background: var(--card); }
.past-box > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 48px; padding: 4px 14px;
  font-weight: 600; cursor: pointer; list-style: none;
}
.past-box > summary::-webkit-details-marker { display: none; }
.past-box[open] .past-box-mark { transform: rotate(180deg); }
.past-box .holiday-months { padding: 0 14px 8px; }

/* --- the devices (P3) ----------------------------------------------------------------------------------------------- */
.devices-card { margin-bottom: 16px; }
.devices-table .device-name { font-weight: 700; }
.devices-table .col-act { text-align: right; }
.devices-table .device-revoke { width: auto; color: var(--late); }
.add-device { max-width: 760px; }
@media (max-width: 719.98px) {
  .devices-table tbody tr {
    grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "name name act" "station lang act" "state state state";
    align-items: center; gap: 2px 10px;
  }
  .devices-table .device-name { grid-area: name; }
  .devices-table .col-station { grid-area: station; color: var(--muted-2); }
  .devices-table tbody td:nth-child(3) { grid-area: lang; color: var(--muted-2); }
  .devices-table .col-state { grid-area: state; margin-top: 4px; }
  .devices-table .col-act { grid-area: act; }
  /* A long state (the Burmese "waiting, the link works until ...") wraps inside the card (UX-5). */
  .devices-card .pill { white-space: normal; max-width: 100%; }
}
/* The rows of a W6 table on a phone keep the card's gutter. */
@media (max-width: 719.98px) { .setup-page .card-table tbody tr { padding-inline: 16px; } }

/* --- the FlowAccount link (P4 status): the status in the dark hero card --------------------------------------------- */
.fa-status { margin-bottom: 16px; }
.fa-status > p { margin: 0; }
.fa-state { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
.fa-state .pill { font-size: 14px; }
.fa-mode { color: rgba(255, 255, 255, 0.86); font-weight: 600; }
.fa-auto, .fa-plain { font-size: 16px; }
.fa-next { color: rgba(255, 255, 255, 0.86); font-weight: 600; }
.fa-hero-hint { color: rgba(255, 255, 255, 0.72); font-size: 14px; }
.fa-pull { display: flex; flex-wrap: wrap; gap: 10px; margin: 6px 0 2px; }
.fa-pull form { margin: 0; }
.fa-status .btn-primary { background: #ffffff; color: var(--hero); }
.fa-status .btn-primary:hover { background: #e9f1ec; }
.fa-status .btn-outline { border-color: rgba(255, 255, 255, 0.6); background: transparent; color: #ffffff; }
.fa-status .btn-outline:hover { background: rgba(255, 255, 255, 0.1); }
.fa-pulling { display: inline-flex; align-items: center; gap: 10px; }
.fa-setup > summary {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; color: #ffffff; font-weight: 600; cursor: pointer;
  list-style: none;
}
.fa-setup > summary::-webkit-details-marker, .line-setup > summary::-webkit-details-marker { display: none; }
.fa-setup[open] .fa-setup-mark, .line-setup[open] .fa-setup-mark { transform: rotate(180deg); }
.fa-setup-hint { margin: 0; color: rgba(255, 255, 255, 0.86); overflow-wrap: anywhere; }
@media (max-width: 640px) { .fa-pull form, .fa-pull .btn { width: 100%; } }
.fa-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.fa-kpi-last .kpi-note { margin-top: 6px; }
@media (max-width: 420px) { .fa-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } .fa-kpi-last { grid-column: 1 / -1; } }
.fa-facts-card { margin-bottom: 16px; }
.fa-facts { display: grid; gap: 8px; margin: 0; }
.fa-facts > div { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; }
.fa-facts dt { min-width: 9em; color: var(--muted); font-weight: 600; }
.fa-facts dd { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin: 0; }
.fa-cutover { max-width: 760px; margin-bottom: 16px; }
.fa-cutover .hint { margin: 0; }
.fa-cutover-form { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 10px 12px; }
.fa-cutover-form .field-error { grid-column: 1 / -1; }
@media (max-width: 480px) { .fa-cutover-form { grid-template-columns: minmax(0, 1fr); } }
.fa-runs-head { padding: 14px 18px 6px; }
.fa-runs .col-time { white-space: nowrap; font-variant-numeric: tabular-nums; }
.fa-runs .code { overflow-wrap: anywhere; }
.fa-error-label { color: var(--muted); font-size: 14px; font-weight: 600; } /* the words before an error code */
.fa-partial-note { color: var(--muted-2); font-size: 14px; font-weight: 600; }

/* --- the LINE link (P4 status): the two sides as tiles and the month's messages as a bar, in the dark hero ---------- */
.setup-card.line-link {
  display: grid; gap: 12px; max-width: 900px; margin-bottom: 16px; padding: 16px 18px;
  border: 0; background: linear-gradient(150deg, var(--hero-2), var(--hero) 70%); color: #ffffff;
}
.line-link :focus-visible { outline-color: #ffffff; }
.line-link a { color: #ffffff; }
.line-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); gap: 10px; margin: 0; padding: 0; list-style: none; }
.line-tile {
  display: grid; grid-template-columns: 12px minmax(0, 1fr); align-items: start; gap: 10px;
  padding: 12px 14px; border-radius: 14px; background: rgba(255, 255, 255, 0.08);
}
.line-mark { width: 12px; height: 12px; margin-top: 6px; border-radius: 50%; background: var(--idle-bg); }
.line-tile[data-state="connected"] .line-mark { background: #7fd197; }
.line-tile[data-state="not_connected"] .line-mark { background: var(--amber); }
.line-tile[data-state="fake"] .line-mark { background: #c5ccc8; }
.line-tile[data-state="unusable"] .line-mark, .line-tile[data-state="refused"] .line-mark { background: #ff8a7a; }
.line-status { margin: 0; font-size: 16px; font-weight: 600; }
.line-quota-now { display: grid; gap: 8px; }
.line-guard { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }
.line-guard[data-guard="stopped"] { color: #ffb4a8; }
.line-guard[data-guard="refused"] { color: rgba(255, 255, 255, 0.78); }
.line-bar { height: 10px; background: rgba(255, 255, 255, 0.16); }
.line-bar .bar-fill { background: #7fd197; }
.line-bar.is-warn .bar-fill { background: var(--amber); }
.line-bar.is-late .bar-fill { background: #ff8a7a; }
.line-today { margin: 0; color: rgba(255, 255, 255, 0.78); font-variant-numeric: tabular-nums; }
.line-link .notice { margin: 0; }
.line-setup > summary { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; font-weight: 600; cursor: pointer; list-style: none; }
.line-setup > summary::after {
  content: ""; width: 7px; height: 7px; margin-left: 4px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
}
.line-setup[open] > summary::after { transform: rotate(-135deg) translateY(-2px); }
.line-setup-hint { margin: 0; color: rgba(255, 255, 255, 0.86); overflow-wrap: anywhere; }
.line-token-hint { overflow-wrap: anywhere; }
.line-link .fa-facts { padding-top: 10px; border-top: 1px solid rgba(255, 255, 255, 0.16); }
.line-link .fa-facts dt { color: rgba(255, 255, 255, 0.72); }
.line-link .code { background: rgba(255, 255, 255, 0.14); color: #ffffff; }
.line-error-since { color: rgba(255, 255, 255, 0.78); font-size: 14px; }
/* The people to follow up, and the counts of the friends of the OA with the button that checks them again. */
.line-friends, .line-month { display: grid; gap: 12px; max-width: 900px; }
/* The people to follow up, counted under the hero, each a way to its list (UX-2). */
.line-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 900px; }
@media (max-width: 420px) { .line-kpis { gap: 8px; } .line-kpis .kpi { padding: 12px; } }
.line-follow { scroll-margin-top: 72px; }
.line-friends > h2, .line-month > h2 { margin: 0; font-family: var(--font-display); font-size: 17px; }
.line-friends .notice { margin: 0; }
.line-check { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px 16px; }
.line-check-counts { display: grid; gap: 2px; }
.line-check p { margin: 0; }
.line-bound { font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; }
.line-unknown { color: var(--warn); font-weight: 600; }
.line-recheck { margin: 0; }
.line-recheck-hint { grid-column: 1 / -1; }
@media (max-width: 560px) { .line-check { grid-template-columns: minmax(0, 1fr); } .line-recheck .btn { width: 100%; } }
.line-follow { display: grid; gap: 6px; padding-top: 12px; border-top: 1px solid var(--line); }
.line-follow h3 { margin: 0; color: var(--ink); font-size: 16px; }
.line-people { margin: 0; padding: 0; list-style: none; }
.line-people > li {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; padding: 8px 0; border-top: 1px solid var(--line);
}
.line-people > li:first-child { border-top: 0; }
.line-people > li > a { color: var(--ink); font-weight: 700; text-underline-offset: 3px; overflow-wrap: anywhere; }
.line-people .chips li { font-size: 13px; }
.line-row-act { margin: 0 0 0 auto; }
.line-row-act .btn, .btn.line-row-act { width: auto; }
.line-invited { white-space: normal; } /* "link sent · works until ..." wraps in a narrow row */
.line-people-next { margin: 0; }
.line-friends .oa-link { display: grid; gap: 8px; justify-items: start; margin: 0; padding-top: 12px; border-top: 1px solid var(--line); }
.line-counts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); gap: 8px;
  margin: 0; padding: 0; list-style: none; font-variant-numeric: tabular-nums;
}
.line-counts > li { padding: 10px 12px; border-radius: var(--r-ctl); background: var(--soft); font-weight: 600; }
.line-quota { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }
.line-quota .hint { font-weight: 500; }
.line-month .hint { margin: 0; }
.line-months-wrap { max-width: 420px; border: 0; border-radius: 0; background: transparent; } /* no box in the card (UX-12) */
.line-months caption { padding: 10px 14px 8px; font-weight: 600; text-align: left; }
.line-months .num { font-variant-numeric: tabular-nums; }
[data-quota-low] > p { margin: 0; }
[data-quota-low] > p + p { margin-top: 6px; }

/* --- when someone leaves (plan 5 L23; admin/_gaps.html, users.html, user_form.html) -------------------------------- */
.gap-list { display: grid; gap: 6px; margin: 8px 0 0; padding-left: 20px; }
.gap-list > li { overflow-wrap: anywhere; }
.gap-note, .gap-fix { margin: 10px 0 0; }
.gap-fix a { color: var(--brand-deep); font-weight: 700; text-underline-offset: 3px; }
.gap-row-fix {
  display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; padding: 0 2px;
  color: var(--brand-deep); font-weight: 700; white-space: nowrap; vertical-align: middle;
}
.gap-row-fix::after {
  content: ""; width: 6px; height: 6px; margin-left: 6px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(-45deg);
}
.gap-list .gap-names { margin-top: 6px; }
.gap-line-off { font-weight: 600; max-width: 70ch; }
.chip-note { font-weight: 700; }
.gap-confirm-actions { margin: 14px 0 0; }
.resign-steps {
  max-width: 760px; margin: 16px 0 0; border: 1px solid var(--line); border-radius: 14px; background: var(--card);
}
.resign-steps > summary {
  display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 6px 16px;
  font-weight: 600; cursor: pointer; list-style: none;
}
.resign-steps > summary::-webkit-details-marker { display: none; }
.resign-steps > summary::before {
  content: ""; flex: none; width: 8px; height: 8px;
  border-right: 2px solid var(--ink-2); border-bottom: 2px solid var(--ink-2); transform: rotate(-45deg);
  transition: transform 120ms ease-out;
}
.resign-steps[open] > summary::before { transform: rotate(45deg); }
.resign-steps ol { display: grid; gap: 6px; max-width: 70ch; margin: 0; padding: 0 16px 14px 42px; }
/* Plan 5 post-review: a chip of the bar of vacant roles that carries its note may take two lines on a phone. */
.chips li.chip-with-note { border-radius: 8px; }
/* Plan 5 post-review: the links of the LINE page are as tall as a thumb needs. */
.line-people > li > a { display: inline-flex; align-items: center; min-height: 44px; }
.gap-fix a { display: inline-flex; align-items: center; min-height: 44px; }

/* --- a device opening its setup link (device_setup.html, P7 confirm) ------------------------------------------------ */
.device-setup .confirm-card { gap: 12px; padding: 8px 0 0; }
.confirm-ring {
  display: grid; place-items: center; width: 72px; height: 72px; border-radius: 50%; background: var(--ok-bg); color: var(--brand);
}
.confirm-title { margin: 0; font-family: var(--font-display); font-size: 24px; font-weight: 700; line-height: 1.35; overflow-wrap: anywhere; }
.confirm-note { margin: 0 0 8px; color: var(--muted-2); }
.confirm-form { width: 100%; margin: 0; }
.line-profile { display: flex; align-items: center; gap: 10px; min-width: 0; }
.line-profile-text { min-width: 0; }
.line-avatar { width: 36px; height: 36px; flex: 0 0 36px; border-radius: 50%; object-fit: cover; }
.line-avatar-fallback { display: inline-flex; align-items: center; justify-content: center; background: var(--soft); color: var(--ink-2); font-size: 14px; font-weight: 600; }
.line-profile-name { display: block; max-width: 24rem; overflow-wrap: anywhere; white-space: normal; }
@media print {
  .line-avatar, .line-profile-name, [data-admin-bind] { display: none !important; }
}

/* ===== end W6 ===== */

/* ===== W7 auth+dev (owned by W7) ===== */

/* Burmese has no spaces between its words: a line breaks only where the browser finds the end of a word, and a word
   too long for its line breaks only then, never inside a syllable at will (UX-3: no overflow-wrap: anywhere here).
   The three properties are inherited by everything on the page. */
:is(.login-page, .invite-page, .dev-line):lang(my) { word-break: normal; line-break: normal; overflow-wrap: break-word; }

/* --- The login page (login.html, P7 auth): LINE first, the admin's password folded under it ---------------------- */
.login-page h1 { margin-bottom: 20px; }
.login-notice { margin: 0 0 16px; }
.login-line { display: grid; gap: 10px; margin: 0; }
.login-line .btn .ico { width: 22px; height: 22px; }
.login-trial { display: flex; align-items: flex-start; gap: 6px; font-size: 14px; }
.login-trial .ico { flex: none; margin-top: 3px; }
/* A browser logged in to another account: the logout its words ask for, before the LINE button */
.login-logout { margin: 0 0 12px; }
/* A bind of an invite that did not finish (invite_retry): a status card and its one line, and the quiet way home */
.login-reopen { padding-bottom: 4px; }
.login-reopen .status-card-body { color: var(--ink-2); font-size: 17px; text-wrap: balance; }
/* The titles of the status cards of these pages, in Burmese: room for the marks above and below a line (OE-2) */
:is(.login-reopen, .invite-done-head, .invite-dead) .status-card-title:lang(my) { line-height: 1.55; }
/* The fold of the admin's password, and the one of how to come in next time on the done page: a row with a chevron
   that turns, as tall as a thumb needs */
.login-alt { margin-top: 28px; border-top: 1px solid var(--line); }
.invite-next summary, .login-alt summary {
  display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 8px 0;
  color: var(--ink-2); font-weight: 600; cursor: pointer; list-style: none;
}
.invite-next summary::-webkit-details-marker, .login-alt summary::-webkit-details-marker { display: none; }
.invite-next summary::before, .login-alt summary::before {
  content: ""; flex: none; width: 8px; height: 8px; margin: 0 2px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(-45deg);
  transition: transform 120ms ease-out;
}
.invite-next[open] summary::before, .login-alt[open] summary::before { transform: rotate(45deg); }
.login-alt summary:hover, .login-alt[open] summary, .invite-next summary:hover, .invite-next[open] summary { color: var(--ink); }
.login-alt[open] summary { margin-bottom: 8px; }
/* A refused password: what went wrong, and what to do, together above the form */
.login-refused { display: grid; gap: 6px; margin: 0 0 14px; }
.login-refused .form-error { margin: 0; }

/* --- The invite pages (invite.html, invite_done.html, invite_dead.html; P7 onboarding) -------------------------- */
.invite-page h1 { margin-bottom: 14px; }
/* A link that cannot be used here: why, first, and its one way on */
.invite-blocked { margin: 0 0 12px; }
.invite-way-on { margin: 0 0 20px; }
/* Whose account the link is for: its roles or its stations as pills, on a quiet panel of the card */
.invite-who { display: grid; gap: 10px; margin: 0 0 22px; padding: 12px 14px; border-radius: 14px; background: var(--soft); }
.invite-who > div { display: grid; gap: 6px; min-width: 0; }
.invite-who dt { color: var(--muted-2); font-size: 13px; font-weight: 600; }
.invite-who dd { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; font-weight: 600; }
.invite-who .pill { background: var(--card); color: var(--ink); font-size: 14px; white-space: normal; }
/* The numbered steps. A step's head is its number in a dot (a tick once done) beside its title; what to do in it is
   under the head, as wide as the card, so that a button keeps its words on one line in Burmese on a 360px phone
   (UX-2). The step to take now has the hero's dark dot, a done one the brand's green with the words that say so. */
.invite-steps { display: grid; margin: 0; padding: 0; list-style: none; }
.invite-step { display: grid; gap: 12px; min-width: 0; padding: 18px 0; }
.invite-step:first-child { padding-top: 2px; }
.invite-step:last-child { padding-bottom: 0; }
.invite-step + .invite-step { border-top: 1px solid var(--line); }
.invite-step-head { display: flex; align-items: center; gap: 12px; min-width: 0; }
.invite-step-dot {
  flex: none; display: grid; place-items: center; width: 32px; height: 32px; border: 2px solid var(--line-strong);
  border-radius: 50%; background: var(--card); color: var(--muted-2);
  font-family: var(--font-display); font-size: 15px; font-weight: 700; line-height: 1;
}
.invite-step.is-now .invite-step-dot { border-color: var(--hero); background: var(--hero); color: #ffffff; }
.invite-step.is-done .invite-step-dot { border-color: var(--brand); background: var(--brand); color: #ffffff; }
.invite-step-title {
  flex: 1; min-width: 0; margin: 0; font-family: var(--font-display); font-size: 18px; font-weight: 700; line-height: 1.4;
}
.invite-step-title:lang(my) { line-height: 1.7; }
.invite-step.is-todo .invite-step-title { color: var(--muted-2); }
.invite-step-body { display: grid; gap: 10px; min-width: 0; }
.invite-step-body form { margin: 0; }
/* Words that need two lines on a button break where the two lines balance (UX-9) */
.invite-step .btn { text-wrap: balance; }
/* The OA's step while it waits (invite_done.html): why, then the link and the way back from LINE as one group */
.invite-friend-why { margin: 0; font-weight: 600; }
.invite-oa-bridge { display: grid; gap: 8px; }
.invite-oa-bridge > .hint { margin-top: 4px; }
/* ... and once it is a friend, a quiet link that opens the OA in LINE */
.invite-oa-open {
  display: inline-flex; align-items: center; justify-self: start; gap: 8px; min-height: 44px;
  color: var(--brand); font-weight: 600; text-underline-offset: 3px;
}
/* The head of the done page: the page's own title while the OA's step waits (not the tick of a page that is all
   done), the tick in its ring once nothing waits */
.invite-done-title { margin: 8px 0 18px; }
.invite-done-head { margin: 0 0 20px; padding-top: 4px; }
/* How to come in next time (invite_done.html): folded under the way home, the words and the address to copy */
.invite-next { margin-top: 4px; }
.invite-next[open] summary { margin-bottom: 6px; }
.invite-next > .hint { margin-bottom: 10px; }
/* The address of the site, to copy: the address on the quiet grey with its button beside it, or under it when a
   phone has no room for both on one line */
.invite-copy { display: flex; flex-wrap: wrap; align-items: stretch; gap: 8px; min-width: 0; }
.invite-copy-text {
  display: flex; align-items: center; flex: 1 1 15em; min-width: 0; min-height: var(--btn-h); padding: 6px 12px;
  border-radius: var(--r-ctl); background: var(--soft); font-size: 15px; font-weight: 600; overflow-wrap: break-word;
  -webkit-user-select: all; user-select: all;
}
.invite-copy .btn { flex: none; width: auto; }
.invite-dead .status-card { padding-top: 8px; }
.invite-dead .status-card-body { color: var(--ink-2); text-wrap: balance; }

/* --- The fake LINE of a local trial (dev/*, the dev shell) ---------------------------------------------------------- */
/* A direct shell child reserves its actual wrapped height and notch padding. Sticky keeps the trial warning
   visible while scrolling without a fixed-height spacer; the corner controls must not apply the top inset twice. */
.auth-shell.is-dev .auth-tools { padding-top: var(--auth-edge); }
.is-dev .dev-banner {
  position: sticky; top: 0; z-index: 50; flex: none;
  display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 40px; margin: 0;
  padding: calc(6px + env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) 6px max(16px, env(safe-area-inset-left));
  border-bottom: 1px solid var(--amber); background: var(--warn-bg); color: var(--warn);
  font-size: 14px; font-weight: 700; text-align: center;
}
.dev-line-head { display: grid; gap: 4px; margin: 0 0 16px; }
.dev-line-head h1 { margin: 0; }
.dev-line-sub { margin: 0; color: var(--muted-2); font-size: 14px; }
/* The two pages a person moves between (add the OA, what was received), and the way back to the app */
.dev-line-switch { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 18px; }
.dev-line-switch .chip { min-height: 44px; }
.dev-line-home {
  display: inline-flex; align-items: center; gap: 4px; min-height: 44px; margin-left: auto; padding: 0 4px;
  color: var(--ink-2); font-weight: 600; text-decoration: none;
}
.dev-line-home:hover { color: var(--ink); }
/* The lists, grouped (office, floor, others; not friends yet, friends) */
.dev-line-group + .dev-line-group { margin-top: 18px; }
.dev-line-group-title { margin: 0 0 2px; color: var(--muted-2); font-family: var(--font); font-size: 13px; font-weight: 700; }
.dev-line-form { display: grid; gap: 4px; margin: 0; }
/* A row of the consent page is one button: whose LINE it is, its friendship, and the chevron */
.dev-line-row {
  -webkit-appearance: none; appearance: none;
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 56px; margin: 0; padding: 10px 6px;
  border: 0; border-radius: 12px; background: transparent; color: var(--ink);
  font: inherit; text-align: left; cursor: pointer; transition: background-color 150ms ease-out;
}
.dev-line-row:hover { background: var(--soft); }
.dev-line-row:active { background: var(--line); }
.dev-line-row-main { display: grid; flex: 1; gap: 4px; min-width: 0; }
.dev-line-who { margin: 0; font-weight: 700; overflow-wrap: break-word; }
.dev-line-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin: 0; color: var(--muted); font-size: 13px; }
.dev-line-chev { color: var(--ink-3); }
.dev-line-check {
  display: inline-flex; align-items: center; gap: 10px; justify-self: start; min-height: 44px; margin: 0 0 6px 6px;
  font-weight: 600; cursor: pointer;
}
.dev-line-check input { width: 22px; height: 22px; margin: 0; accent-color: var(--line-green); }
.dev-line-more { display: grid; gap: 8px; margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line); }
.dev-line-more .dev-line-check { margin-left: 0; }
/* A row of the friend page: whose LINE it is and its friendship, with the button that adds the OA at its end */
.dev-line-entry {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px;
  min-height: 56px; padding: 10px 6px;
}
.dev-line-item-main { display: grid; flex: 1 1 200px; gap: 4px; min-width: 0; }
.dev-line-entry .btn { width: auto; }
/* The inbox: each fake LINE's messages as the bubbles of a chat, as wide as the card, a link of this site as a button
   in its bubble */
.dev-line-box + .dev-line-box { margin-top: 22px; }
.dev-line-box h2 { margin: 0 0 8px; color: var(--muted-2); font-family: var(--font); font-size: 14px; font-weight: 700; }
.dev-line-messages { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.dev-line-messages > li { min-width: 0; }
.dev-line-messages pre {
  margin: 0; padding: 10px 12px; border-radius: 6px 18px 18px 18px; background: var(--soft);
  font: inherit; white-space: pre-wrap; overflow-wrap: break-word;
}
/* (an outline button as wide as its address and no wider than the bubble, so that a long address breaks inside it,
   between the site and the page: the <wbr> of dev/line_inbox.html) */
.dev-line-link {
  display: inline-block; width: auto; max-width: 100%; margin: 6px 0 2px; padding: 9px 14px;
  color: var(--brand-deep); font-weight: 700; text-align: left; overflow-wrap: break-word;
}
/* ===== end W7 ===== */

/* ===== W1 tail (owned by W1): print and reduced motion, last so that they win ===== */

/* Printed, a page is its paper or its content alone: no shell, no buttons that print it. */
@media print {
  .no-print, .skip-link, .app-bar, .app-top, .section-switch, .app-shell > .m-tabbar, .action-bar, .print-bar, .auth-band, .me-logout { display: none !important; }
  body { background: #ffffff; }
  .app-shell { display: block; min-height: 0; padding: 0; }
  .app-main > .admin { max-width: none; padding: 0; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 1ms !important; animation-delay: 0ms !important; transition: none !important; }
  .sf-spin { animation: none; } /* a spinner that never stops would only flicker at 1ms; the words say it is saving */
}
/* ===== end W1 tail ===== */

/* ===== R-UX-22 workflow navigation and settings hub ===== */
.m-workflow .m-tiles { margin: 12px 0 0; padding: 0; box-shadow: none; border-radius: 0; }
.m-workflow .m-admin-tiles { grid-template-columns: minmax(0, 1fr); }
.m-workflow .m-admin-tiles .m-tile { display: flex; align-items: center; gap: 12px; text-align: start; }
.settings-hub { display: grid; gap: 24px; }
.settings-group h2 { margin: 0 0 12px; font-size: 18px; }
.settings-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: 12px; padding: 0; margin: 0; list-style: none; }
.settings-card { display: flex; align-items: center; gap: 12px; min-height: 88px; height: 100%; padding: 16px; color: var(--ink); text-decoration: none; }
.settings-card:hover { border-color: var(--brand); }
.settings-card-body { display: grid; gap: 4px; flex: 1; min-width: 0; }
.settings-card-title { font-weight: 700; }
.settings-card-status { color: var(--ink-2); font-size: 14px; }
/* ===== end R-UX-22 ===== */

/* ===== RP reports (owned by RP) ===== */
.reports-page { min-width: 0; overflow-wrap: anywhere; }
.reports-page .page-head { align-items: flex-start; }
.reports-page .page-actions { flex-wrap: wrap; }
.reports-page .rp-period { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 12px 20px; margin-block: 20px 8px; }
.reports-page .rp-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.reports-page .rp-chips a { display: inline-flex; align-items: center; min-height: 44px; padding: 8px 14px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--card); color: var(--ink); text-decoration: none; }
.reports-page .rp-chips a[aria-current] { background: var(--brand); border-color: var(--brand); color: white; font-weight: 700; }
.reports-page .rp-chips a:hover { border-color: var(--brand); }
.reports-page .rp-custom { min-width: 0; flex: 1 1 240px; }
.reports-page .rp-custom summary { min-height: 44px; padding-block: 10px; cursor: pointer; color: var(--brand); font-weight: 600; }
.reports-page .rp-custom form { display: flex; flex-wrap: wrap; align-items: end; gap: 12px; padding-block: 8px; }
.reports-page .rp-custom label { display: grid; flex: 1 1 140px; gap: 6px; min-width: 0; }
.reports-page .rp-custom input { width: 100%; min-width: 0; min-height: 44px; }
.reports-page .rp-period-note, .reports-page .rp-muted { color: var(--muted); font-size: 13px; }
.reports-page .rp-period-note { margin-block: 8px 20px; }
.reports-page .rp-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); gap: 12px; margin-block: 20px 24px; }
.reports-page .rp-metric { min-width: 0; }
.reports-page .rp-metric .kpi { height: 100%; box-sizing: border-box; }
.reports-page .kpi-value { font-size: clamp(24px, 3vw, 36px); white-space: normal; }
.reports-page .rp-summary-kpis .rp-metric:first-child { grid-column: span 2; }
.reports-page .rp-note, .reports-page .rp-population, .reports-page .rp-insufficient, .reports-page .rp-cell-note { display: block; }
.reports-page .rp-population, .reports-page .rp-cell-note { font-size: 12px; }
.reports-page .rp-cell-note { color: var(--muted); margin-top: 4px; }
.reports-page .rp-table-card { margin-block: 24px; min-width: 0; }
.reports-page .rp-table-card h2 { margin: 0 0 16px; font-size: 18px; }
.reports-page .card-table { table-layout: fixed; font-variant-numeric: tabular-nums; }
.reports-page .card-table th, .reports-page .card-table td { overflow-wrap: anywhere; }
.reports-page .card-table thead th { white-space: normal; }
.reports-page .pill { max-width: 100%; white-space: normal; }
.reports-page .rp-chart { border-top: 3px solid var(--brand); }
.reports-page .rp-report-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.reports-page .rp-report-cards .card { padding: 4px 12px; margin: 0; }
.reports-page .list-row { flex-wrap: wrap; }
.reports-page .list-row-trail { white-space: normal; max-width: 100%; }
.reports-page .rp-feature-note { margin-block: -8px 24px; }
.reports-page .rp-caveats { margin-top: 28px; }
.reports-page .rp-caveats .callout { background: var(--soft); color: var(--muted); }
.reports-page .rp-caveats ul { margin: 8px 0 0; padding-inline-start: 20px; }
.reports-page .rp-caveats li + li { margin-top: 6px; }
.reports-page.reports-print { max-width: 1100px; margin: 24px auto; padding: 24px; background: white; }
.reports-page .rp-print-heading { border-bottom: 1px solid var(--line); margin-bottom: 24px; }
.reports-page .rp-print-heading h1 { font-size: 26px; }
.reports-page .rp-print-heading p { margin-block: 6px; }
.reports-page .rp-print-actions { margin-bottom: 20px; }
@media (max-width: 719.98px) {
  .reports-page .page-actions { flex-wrap: nowrap; gap: 8px; max-width: 100%; }
  .reports-page .page-actions .btn { width: auto; min-width: 0; min-height: 44px; padding: 6px 10px; font-size: 14px; }
  .reports-page .page-head { margin-bottom: 8px; }
  .reports-page .rp-period { gap: 0 12px; margin-block: 8px 0; }
  .reports-page .rp-chips { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px; width: 100%; }
  .reports-page .rp-chips a { justify-content: center; padding: 4px; font-size: 13px; }
  .reports-page .rp-period-note, .reports-page .rp-muted { margin-block: 4px 8px; }
  .reports-page .card-table tbody a { display: inline-flex; align-items: center; min-height: 44px; }
  .reports-page .rp-kpis, .reports-page .rp-report-cards { grid-template-columns: minmax(0, 1fr); }
  .reports-page .rp-summary-kpis .rp-metric:first-child { grid-column: auto; }
  .reports-page .rp-table-card { padding: 16px; }
  .reports-page .card-table tbody tr { gap: 8px; }
  .reports-page .card-table tbody :is(th, td)[data-label]::before { display: block; margin: 0 0 2px; }
  .reports-page .rp-custom { flex-basis: 100%; }
  .reports-page.reports-print { margin: 0; padding: 16px; }
}
@page reports { size: A4 landscape; margin: 12mm; }
@media print {
  .reports-page.reports-print { page: reports; max-width: none; margin: 0; padding: 0; color: black; font-size: 9pt; }
  .reports-page.reports-print .rp-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
  .reports-page.reports-print .kpi { background: white; color: black; box-shadow: none; border: 1px solid #aaa; break-inside: avoid; }
  .reports-page.reports-print .kpi-value { font-size: 20pt; }
  .reports-page.reports-print .card { box-shadow: none; border: 0; padding: 0; }
  .reports-page.reports-print .card-table { display: table; font-size: 8pt; }
  .reports-page.reports-print .card-table thead { position: static; display: table-header-group; clip-path: none; width: auto; height: auto; overflow: visible; }
  .reports-page.reports-print .card-table tbody { display: table-row-group; }
  .reports-page.reports-print .card-table tbody tr { display: table-row; break-inside: avoid; }
  .reports-page.reports-print .card-table :is(th, td) { display: table-cell; padding: 6px; border-bottom: 1px solid #ccc; }
  .reports-page.reports-print .card-table [data-label]::before { display: none; }
  .reports-page.reports-print .rp-table-card h2 { break-after: avoid; }
  .reports-page.reports-print .rp-caveats .callout { background: white; color: black; }
  .reports-page.reports-print .rp-report-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  .section-switch.rp-sections { display: flex; flex-wrap: wrap; grid-column: 2; grid-row: 2; padding: 12px 28px; min-width: 0; }
  .section-switch.rp-sections a { white-space: normal; padding-block: 8px; }
  .section-switch.rp-sections + .app-main { grid-row: 3; }
}
/* ===== end RP ===== */

/* ===== Trial controls (R-TR-1) ===== */
.trial-page { max-width: 760px; }
.trial-page .trial-path { overflow-wrap: anywhere; }
.trial-page .detail-grid { display: block; padding: 0; margin: 0; background: none; border: 0; }
.trial-page .detail-grid > div { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px; padding-block: 8px; }
.trial-page .detail-grid > div + div { border-top: 1px solid var(--line); }
.trial-page .detail-grid dd { font-variant-numeric: tabular-nums; font-weight: 700; }
.trial-page ul { margin: 0; padding-inline-start: 24px; }
.trial-page li + li { margin-top: 8px; }
.trial-page .btn-danger:active { background: var(--late-bg); }
/* ===== end Trial controls ===== */

/* ===== Executive phase (a) ===== */
.exec-completeness > summary { min-height: 44px; padding-block: 10px; color: var(--brand-deep); font-size: 14px; cursor: pointer; }
.exec-meeting-print .rp-print-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.exec-strip { display: flex; flex-wrap: wrap; gap: 8px 20px; padding: 16px 0; border-block: 1px solid var(--line); }
.exec-strip a { min-height: 44px; max-width: 100%; color: var(--brand-deep); overflow-wrap: anywhere; }
.exec-strip small { display: block; color: var(--muted); }
.exec-kpis { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; margin-block: 24px 12px; }
.exec-kpi { min-width: 0; padding: 18px; background: var(--card); border: 1px solid var(--line); border-radius: var(--r-card); }
.exec-kpi h2 { font-size: 16px; margin: 0 0 16px; }
.exec-kpi h2 a { display: block; min-height: 44px; color: var(--brand-deep); }
.exec-kpi p { margin: 6px 0; font-size: 13px; }
.exec-kpi .exec-value { font-size: clamp(22px, 2.5vw, 32px); font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.4; }
.exec-kpi.exec-bad { border-color: var(--late); background: var(--late-bg); }
.exec-kpi.exec-bad .exec-status { color: var(--late); font-weight: 700; }
.exec-kpi.exec-small, .exec-kpi.exec-collecting { color: var(--ink-2); }
.exec-kpi summary, .exec-targets summary { min-height: 44px; padding-block: 10px; cursor: pointer; }
.exec-bars { list-style: none; padding: 0; display: grid; gap: 16px; }
.exec-bars li { display: grid; grid-template-columns: minmax(0, 1fr) minmax(60px, 2fr) minmax(0, 1fr); gap: 16px; align-items: center; }
.exec-bars progress { width: 100%; height: 14px; accent-color: var(--brand); }
.exec-exception-list { padding-inline-start: 20px; }
.exec-exception-list a { display: inline-block; min-height: 44px; padding-block: 8px; }
.exec-targets { margin-block: 24px; max-width: 720px; }
.exec-targets form { display: grid; gap: 16px; }
.exec-targets label { display: grid; gap: 6px; }
.exec-targets input { min-height: 44px; min-width: 0; width: 100%; }
.exec-meeting { margin-block: 32px; }
.exec-meeting-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; }
.exec-meeting-facts dd { margin: 4px 0 0; font-size: 24px; font-weight: 700; }
.exec-meeting-facts dt { color: var(--ink-2); }
@media (max-width: 1100px) { .exec-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 719.98px) {
  .exec-kpis { grid-template-columns: minmax(0, 1fr); }
  .exec-bars li { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .exec-bars li + li { margin-top: 8px; }
  .exec-strip a { flex: 1 1 140px; }
  .exec-meeting-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .exec-targets { padding: 16px; }
  .exec-meeting-print { padding: 16px; }
}
@media print {
  .exec-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .exec-kpi, .exec-meeting-facts > div { break-inside: avoid; }
  .exec-kpi { background: white !important; color: black; }
  .exec-meeting h3 { break-after: avoid; }
  .exec-meeting-facts { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .exec-meeting { margin-block: 12px; }
}
.exec-strip .exec-stale { color: var(--late); }
.exec-strip .exec-pull-warning { color: var(--warn); }
/* ===== end Executive phase (a) ===== */
