/* ============================================================
   ZERSYNC — Global Stylesheet
   ============================================================ */

/* Google Fonts loaded via <link> in HTML to avoid @import waterfall */

:root {
  /* Type scale (2026-10-06, owner): ONE ramp; every on-screen font size is a step of it.
     ≈px at the 15px root: 9 · 10 · 11 · 12 · 13.5 · 15 · 16.5 · 20 · 22.5 · 26.
     Display numerals (shop-floor clock, tile counts) and chart lettering sit outside it. */
  --fs-3xs: 0.6rem;  --fs-2xs: 0.68rem; --fs-xs: 0.75rem; --fs-sm: 0.82rem; --fs-md: 0.9rem;
  --fs-base: 1rem;   --fs-lg: 1.1rem;   --fs-xl: 1.35rem; --fs-2xl: 1.5rem; --fs-3xl: 1.75rem;
  --font-body: 'DM Sans', sans-serif;
  /* Was 'DM Mono' (monospace). Pointed at the body font so the "robotic"
     monospace look is dropped app-wide; .mono now just inherits the normal font. */
  --font-mono: 'DM Sans', sans-serif;
  /* The ZERSYNC name and nothing else: Archivo at 125% width, bold, set in tracked capitals —
     a wordmark, never running text. Only the public and sign-in pages load the font; the
     .brand-type rule falls back to the body face wherever it is not loaded. */
  --font-brand: 'Archivo', 'DM Sans', sans-serif;
  --bg:         #f5f0eb;
  --card:       #ffffff;
  --accent:     #ff6b35;
  --accent-hover:#e85a28;
  --text:       #2a2a3d;
  --text-secondary: #5a5a6e;
  --muted:      #7a7a8e;
  --border:     #e8e0d8;
  --green:      #30a060;
  --green-light:#e8f5e9;
  --red:        #e04040;
  --red-light:  #fdeaea;
  --blue:       #3b82f6;
  --blue-light: #eff6ff;
  --orange:     #f59e0b;
  --orange-light:#fff8e1;
  --shadow-sm:  0 1px 3px rgba(0,0,0,.06);
  --shadow-md:  0 4px 12px rgba(0,0,0,.08);
  --shadow-lg:  0 8px 30px rgba(0,0,0,.10);
  --radius:     10px;
  --radius-sm:  6px;
  --radius-lg:  14px;
  --transition: .2s ease;
  --table-hover: #faf7f4;
  --table-head:  #faf7f4;
  /* Inset panel inside a card (an expanded detail row). Pages had been using it
     with a light-only fallback, so dark mode drew a white strip under light text. */
  --surface-2:   #f8f9fa;
  --sidebar-bg:  #2a2a3d;
  /* Names ~40 inline styles used but no stylesheet ever defined (found by the 2026-09-29
     audit): an undefined var() drew nothing — transparent sticky columns, fill-less
     panels, selected rows that never highlighted — or fell to a light-only fallback
     that was unreadable in dark mode. Each now resolves to the token it was meant as. */
  --surface:     var(--surface-2);
  --surface-alt: var(--surface-2);
  --text-muted:  var(--muted);
  --border-light:var(--border);
  --accent-bg:   color-mix(in srgb, var(--accent) 8%, transparent);
  --warning:     #d97706;              /* every page that used it fell back to this amber */
  --amber:       var(--warning);
  --danger:      var(--red);
  /* Two hues pages kept hard-coding (leave / machine pips, chart series) — named once. */
  --purple:      #8b5cf6;
  --purple-light:rgba(139,92,246,.12);
  --teal:        #0d9488;
  --teal-light:  rgba(13,148,136,.12);
}

[data-theme="dark"] {
  --bg:         #1a1a2e;
  --card:       #242440;
  --text:       #e8e8f0;
  --text-secondary: #a0a0b8;
  --muted:      #6e6e88;
  --border:     #3a3a55;
  --green-light:#1a3a28;
  --red-light:  #3a1a1a;
  --blue-light: #1a2640;
  --orange-light:#2e2810;
  --shadow-sm:  0 1px 3px rgba(0,0,0,.2);
  --shadow-md:  0 4px 12px rgba(0,0,0,.3);
  --shadow-lg:  0 8px 30px rgba(0,0,0,.4);
  --table-hover: #2a2a48;
  --table-head:  #2e2e4a;
  --surface-2:   #1e1e36;
  --sidebar-bg:  #16162a;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-size: 15px; -webkit-font-smoothing: antialiased; }
body {
  font-family: var(--font-body);
  color: var(--text);
  background: var(--bg);
  line-height: 1.6;
  min-height: 100vh;
}
a { color: var(--accent); text-decoration: none; }
/* Not on a .btn: an <a class="btn btn-primary"> would turn its white label orange on its own
   orange fill (a:hover outranks .btn-primary). Buttons own their hover colours. */
a:not(.btn):hover { color: var(--accent-hover); }
img { max-width: 100%; display: block; }

/* --- Typography --- */
h1 { font-size: var(--fs-3xl); font-weight: 700; letter-spacing: -0.02em; }
h2 { font-size: var(--fs-xl); font-weight: 600; letter-spacing: -0.01em; }
h3 { font-size: var(--fs-lg);  font-weight: 600; }
h4 { font-size: var(--fs-base); font-weight: 600; }
.mono { font-family: var(--font-mono); }
.muted { color: var(--muted); }
.text-center { text-align: center; }

/* --- Layout --- */
.container { width: 100%; max-width: 1280px; margin: 0 auto; padding: 0 1.5rem; }
.flex { display: flex; }
.flex-col { flex-direction: column; }
/* Ten call sites across bookings, HR, production and the tutorial mocks already wrote
   `class="flex … flex-wrap"` as though this existed; until 2026-09-25 it did not, so those
   rows — button strips at the foot of a card, a filter row, two chart legends — overflowed
   instead of wrapping. Adding the utility only affects a row that does NOT fit: a row with
   room to spare renders identically. */
.flex-wrap { flex-wrap: wrap; }
.items-center { align-items: center; }
/* Missing until 2026-09-25 while ten pages already wrote them: a `flex items-end` row of
   label+input fields and a button fell back to stretch, so the button grew to the height
   of the whole field (label included) — the "fat buttons" on Disciplinary Cases. */
.items-start { align-items: flex-start; }
.items-end { align-items: flex-end; }
.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
/* Used by 57 files (button rows meant to sit on the right) but never defined until 2026-10-06,
   so every one of those rows sat on the left. */
.justify-end { justify-content: flex-end; }
.gap-xs { gap: 0.35rem; }
.gap-sm { gap: 0.6rem; }
.gap-md { gap: 1rem; }
.gap-lg { gap: 1.5rem; }
.gap-xl { gap: 2rem; }
.w-full { width: 100%; }
.hidden { display: none !important; }
/* watchSave() (shared/utils.js): a Save with nothing to save keeps its place but is not there */
.save-idle { visibility: hidden !important; pointer-events: none; }

/* --- Card --- */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.5rem;
  box-shadow: var(--shadow-sm);
}
.card-lg { padding: 2rem; border-radius: var(--radius-lg); box-shadow: var(--shadow-md); }

/* --- Buttons --- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  padding: 0.6rem 1.2rem; font-family: var(--font-body); font-size: var(--fs-md); font-weight: 500;
  border: none; border-radius: var(--radius-sm); cursor: pointer;
  transition: background var(--transition), transform var(--transition), box-shadow var(--transition);
  white-space: nowrap; line-height: 1.4;
}
.btn:active { transform: scale(0.97); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 30%, transparent); }
.btn-secondary { background: transparent; color: var(--text); border: 1px solid var(--border); }
.btn-secondary:hover:not(:disabled) { background: var(--bg); border-color: var(--muted); }
.btn-danger { background: var(--red); color: #fff; }
.btn-danger:hover:not(:disabled) { background: #c83030; }
.btn-success { background: var(--green); color: #fff; }
.btn-success:hover:not(:disabled) { background: #278a50; }
.btn-sm { padding: 0.35rem 0.75rem; font-size: var(--fs-sm); }
/* The in-row action button (×16 written inline as font-size:.7rem;padding:.2rem .5rem; 7 more
   already wrote class="btn-xs" before it existed). */
.btn-xs { padding: 0.2rem 0.5rem; font-size: var(--fs-2xs); }
.btn-lg { padding: 0.75rem 1.6rem; font-size: var(--fs-base); font-weight: 600; }
.btn-block { width: 100%; }

/* --- Forms --- */
.form-group { display: flex; flex-direction: column; gap: 0.35rem; }
.form-label { font-size: var(--fs-sm); font-weight: 500; color: var(--text-secondary); }

.form-input,
.form-textarea {
  width: 100%; padding: 0.6rem 0.85rem; font-family: var(--font-body); font-size: var(--fs-md);
  color: var(--text); background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-sm); transition: border-color var(--transition), box-shadow var(--transition); outline: none;
}

/* --- Native Select --- */
.form-select {
  width: 100%; padding: 0.6rem 2.2rem 0.6rem 0.85rem;
  font-family: var(--font-body); font-size: var(--fs-md); color: var(--text);
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
  transition: border-color var(--transition), box-shadow var(--transition); outline: none; cursor: pointer;
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237a7a8e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.7rem center; background-size: 16px;
}
/* One height for every single-line control, so a row of mixed fields lines up.
   Without an explicit line-height a text input, a native select and a date/time
   input each take their own "normal" line box and come out 2–3px apart. A plain
   <select class="form-input"> is styled as .form-select for the same reason. */
input.form-input, select.form-input, .form-select, .combo-select-input { line-height: 1.25rem; }
.form-input::-webkit-datetime-edit, .form-input::-webkit-datetime-edit-fields-wrapper { padding: 0; }
select.form-input:not([multiple]):not([size]) {
  padding-right: 2.2rem; cursor: pointer;
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237a7a8e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.7rem center; background-size: 16px;
}
/* Compact in-table selects set their own padding inline; they must leave ≥1.6rem on the right. */
select.form-input.form-select-sm:not([multiple]) { background-size: 14px; background-position: right 0.4rem center; }
.form-select:invalid, .form-select option[value=""] { color: var(--muted); }
.form-select option { color: var(--text); padding: 0.4rem; }
.form-select-sm { padding: 0.3rem 1.8rem 0.3rem 0.5rem; font-size: var(--fs-sm); background-size: 14px; background-position: right 0.4rem center; }

/* --- Combo Select (searchable dropdown) --- */
.combo-select { position: relative; width: 100%; }
.combo-select-input {
  width: 100%; padding: 0.6rem 2.2rem 0.6rem 0.85rem;
  font-family: var(--font-body); font-size: var(--fs-md); color: var(--text);
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
  outline: none; cursor: pointer;
  transition: border-color var(--transition), box-shadow var(--transition);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237a7a8e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.7rem center; background-size: 16px;
}
.combo-select-input::placeholder { color: var(--muted); }
.combo-select-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent); cursor: text; }
.combo-select.error .combo-select-input { border-color: var(--red); box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 10%, transparent); }
.combo-select.combo-disabled .combo-select-input { opacity: 0.55; cursor: not-allowed; background-image: none; }

/* Consistent checkbox rendering app-wide (avoids the OS blue/grey inconsistency).
   Hidden toggle-switch checkboxes set width/height:0 inline, so they are unaffected. */
input[type="checkbox"] { accent-color: var(--accent); width: 16px; height: 16px; cursor: pointer; vertical-align: middle; }
input[type="checkbox"]:disabled { cursor: not-allowed; opacity: 0.5; }
.combo-select-dropdown {
  display: none; position: absolute; top: calc(100% + 4px); left: 0; right: 0;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md); max-height: 200px; overflow-y: auto; z-index: 50;
}
.combo-select.open .combo-select-dropdown { display: block; }
.combo-select-option {
  padding: 0.5rem 0.85rem; font-size: var(--fs-md); color: var(--text); cursor: pointer;
  transition: background var(--transition);
}
.combo-select-option:hover, .combo-select-option.highlighted { background: var(--table-hover); }
.combo-select-option.selected { color: var(--accent); font-weight: 500; }
.combo-select-empty { padding: 0.5rem 0.85rem; font-size: var(--fs-sm); color: var(--muted); font-style: italic; }
.combo-select-sm .combo-select-input { padding: 0.3rem 1.8rem 0.3rem 0.5rem; font-size: var(--fs-sm); background-size: 14px; background-position: right 0.4rem center; }
.combo-select-sm .combo-select-option { padding: 0.35rem 0.5rem; font-size: var(--fs-sm); }
.combo-select-group { padding: 0.4rem 0.85rem 0.2rem; font-size: var(--fs-2xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.02em; color: var(--muted); }
.combo-select-option.placeholder { color: var(--muted); }
.combo-select-option.disabled { color: var(--muted); opacity: 0.6; cursor: default; }
/* A native <select>'s menu (selectMenu, shared/utils.js): the same panel, but body-level and
   fixed, so a modal or a scrolling table never clips it. Above modals and the signing
   overlay, below toasts. Left/top/width/max-height are set from the field's position. */
.combo-select-dropdown.select-menu { display: block; position: fixed; right: auto; max-height: 320px; z-index: 10050; }
/* Long lists: the field itself becomes the search box, as a comboSelect does. */
.select-menu-search { position: fixed; z-index: 10051; margin: 0; box-sizing: border-box; }

/* Multi-select filter — a checkbox dropdown for list pages, so several filters can
   be on at once instead of one exclusive tab at a time. Borrows the combo dropdown
   shell; the trigger is a button (not a search input) because the choice is ticked. */
.filter-multi { position: relative; display: inline-block; }
.filter-multi-btn {
  width: 100%; text-align: left; cursor: pointer;
  padding: 0.35rem 1.8rem 0.35rem 0.6rem;
  font-family: var(--font-body); font-size: var(--fs-sm); color: var(--text);
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
  outline: none; transition: border-color var(--transition), color var(--transition);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237a7a8e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.4rem center; background-size: 14px;
}
.filter-multi-btn:hover { border-color: var(--accent); }
.filter-multi.active .filter-multi-btn { border-color: var(--accent); color: var(--accent); font-weight: 500; }
/* Taller than the combo dropdown it borrows: a filter's options are a short fixed list
   (a document's statuses), and scrolling to reach "Cancelled" hides half the facet. */
.filter-multi-menu { left: 0; right: auto; min-width: 100%; width: max-content; max-width: 300px; max-height: 340px; padding: 0.25rem 0; }
.filter-multi.open .filter-multi-menu { display: block; }
.filter-multi-opt {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.35rem 0.6rem;
  font-size: var(--fs-sm); color: var(--text); cursor: pointer;
  transition: background var(--transition);
}
.filter-multi-opt:hover { background: var(--table-hover); }
.filter-multi-opt input[type="checkbox"],
.filter-multi-opt input[type="radio"] { flex-shrink: 0; }
/* Long option lists (people, categories, locations) get a search field pinned at the top
   of the menu — multiFilter adds it on its own past 10 options. */
.filter-multi { min-width: 9.5rem; }
.filter-multi-search {
  display: block; width: calc(100% - 0.8rem); margin: 0.2rem 0.4rem 0.3rem;
  padding: 0.3rem 0.5rem; font-family: var(--font-body); font-size: var(--fs-sm); color: var(--text);
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm); outline: none;
}
.filter-multi-search:focus { border-color: var(--accent); }
.filter-multi-none { padding: 0.35rem 0.6rem; font-size: var(--fs-sm); color: var(--muted); font-style: italic; }

/* --- Filter bar (MDs/list-filters.md) ---
   Every list's filters sit in ONE .filter-bar, in this order: search · facet dropdowns ·
   date range · Reset filters — then .filter-bar-end (pushed right) for a view switch, the
   currency toggle and the page's primary action. Every control in the bar is the SAME
   compact height, whatever it is (a text field, a native select, a date, a button, a
   segmented switch): a bar of mixed heights reads as a bar of unrelated widgets. */
:root { --ctl-sm: 2rem; }
.filter-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-bottom: 1rem; }
.filter-bar-end { margin-left: auto; display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.filter-bar .form-input,
.filter-bar .form-select,
.filter-bar .combo-select-input,
.filter-bar .filter-multi-btn,
.filter-bar .btn,
.filter-bar .stab {
  height: var(--ctl-sm); padding-top: 0; padding-bottom: 0; font-size: var(--fs-sm); line-height: 1;
}
.filter-bar .form-input { padding-left: 0.6rem; padding-right: 0.6rem; }
.filter-bar select.form-input:not([multiple]), .filter-bar .form-select,
.filter-bar .combo-select-input { padding-right: 1.8rem; background-size: 14px; background-position: right 0.4rem center; }
.filter-bar .btn { padding-left: 0.75rem; padding-right: 0.75rem; }
.filter-bar select.form-input, .filter-bar .form-select { width: auto; }
.filter-bar .combo-select { width: 14rem; max-width: 100%; }
.filter-bar .sub-tabs { margin: 0; flex-wrap: nowrap; }
.filter-bar .stab { padding-left: 0.75rem; padding-right: 0.75rem; display: inline-flex; align-items: center; }
.filter-bar label.filter-check { display: inline-flex; align-items: center; gap: 0.4rem; font-size: var(--fs-sm); color: var(--text-secondary); white-space: nowrap; cursor: pointer; }
/* One search width everywhere; the placeholder says what it searches. */
.filter-search { width: 16rem; max-width: 100%; -webkit-appearance: none; appearance: none; }
.filter-label { font-size: var(--fs-sm); color: var(--muted); white-space: nowrap; }
.filter-dates { display: inline-flex; align-items: center; gap: 0.35rem; }
.filter-bar .filter-dates input[type="date"] { width: auto; }
/* Period stepper: ‹ label › (+ an optional Today). The label keeps one width so the arrows
   do not jump as the period's name changes length. */
.period-step { display: inline-flex; align-items: center; gap: 0.35rem; }
.period-step .btn[data-step="-1"], .period-step .btn[data-step="1"] { font-size: var(--fs-lg); }
.period-step-label { min-width: 7.5rem; text-align: center; font-weight: 600; font-size: var(--fs-md); white-space: nowrap; }
.list-more { text-align: center; margin-top: 1rem; }
/* A list shown as several titled groups (listGroupHTML). */
.list-group { margin-bottom: 1.75rem; }
.list-group-head { margin-bottom: 0.6rem; }
.list-group-note { margin-left: 0.5rem; font-size: var(--fs-sm); font-weight: 400; color: var(--muted); }
.list-group-empty { margin: 0 0 0.25rem; font-size: var(--fs-sm); color: var(--muted); }
.list-group h4 { margin: 1rem 0 0.6rem; }
/* The currency toggle (currencyToggleHTML): small on its own, the bar's height inside one. */
.cur-toggle { margin-bottom: 0.5rem; }
.cur-toggle .btn { font-size: var(--fs-xs); }
.filter-bar .cur-toggle { margin-bottom: 0; }
.filter-bar .cur-toggle .btn { font-size: var(--fs-sm); }
@media (max-width: 768px) {
  .filter-search { width: 100%; flex: 1 1 100%; }
  .filter-bar-end { margin-left: 0; }
  /* A range (label + two dates ≈ 420px) never fits a phone row: it takes its own row, the
     label above, the two dates sharing the width. */
  .filter-dates { flex: 1 1 100%; flex-wrap: wrap; }
  .filter-dates .filter-label { flex: 1 1 100%; }
  .filter-bar .filter-dates input[type="date"] { flex: 1 1 0; min-width: 0; }
}

.form-input:focus, .form-select:focus, .form-textarea:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent);
}
.form-input::placeholder { color: var(--muted); }
.form-textarea { resize: vertical; min-height: 80px; }
.form-input.error, .form-select.error { border-color: var(--red); box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 10%, transparent); }
/* The company code, a square per character with a dash after the fourth (shared/code-boxes.js):
   sign-up and the public site's technical-assistance step. The squares ARE .form-input, so
   border, focus ring and error colour are the field's own; the input they stand for is kept
   as the value and hidden (.code-src). */
.code-boxes { display: flex; align-items: center; gap: .4rem; }
.code-boxes .form-input { flex: 1 1 0; min-width: 0; max-width: 3rem; height: 3.1rem; padding: 0; text-align: center; font-size: var(--fs-xl); font-weight: 600; text-transform: uppercase; }
.code-boxes.error .form-input { border-color: var(--red); }
.code-dash { flex: none; font-weight: 600; color: var(--muted); }
.code-src { display: none; }
/* The "confirm you are a person" widget under the squares (codeChallenge, same file). */
.code-challenge { margin-top: .75rem; min-height: 65px; }
.form-error { font-size: var(--fs-xs); color: var(--red); min-height: 1.2em; }
.form-hint { font-size: var(--fs-xs); color: var(--muted); }

/* --- Input Group (email suffix etc.) --- */
.input-group {
  display: flex; align-items: stretch; border: 1px solid var(--border);
  border-radius: var(--radius-sm); overflow: hidden;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.input-group:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent); }
.input-group .form-input { border: none; border-radius: 0; box-shadow: none; }
.input-group .form-input:focus { box-shadow: none; }
.input-group-suffix {
  display: flex; align-items: center; padding: 0 0.75rem;
  background: var(--bg); color: var(--muted); font-size: var(--fs-sm); font-weight: 500;
  white-space: nowrap; border-left: 1px solid var(--border); user-select: none;
}
.input-group.error { border-color: var(--red); box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 10%, transparent); }

/* --- Badges --- */
.badge {
  display: inline-flex; align-items: center; padding: 0.2rem 0.6rem;
  font-size: var(--fs-xs); font-weight: 600; border-radius: 99px;
  letter-spacing: 0.02em; text-transform: uppercase;
}
.badge-green  { background: var(--green-light); color: var(--green); }
.badge-red    { background: var(--red-light);   color: var(--red); }
.badge-blue   { background: var(--blue-light);  color: var(--blue); }
.badge-orange { background: var(--orange-light); color: var(--orange); }
.badge-purple { background: rgba(139,92,246,0.12); color: #8b5cf6; }
.badge-muted  { background: #f0ece8; color: var(--muted); }

/* --- Tables --- */
.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); }
table { width: 100%; border-collapse: collapse; font-size: var(--fs-md); }
thead { background: var(--table-head); position: sticky; top: 0; z-index: 1; }
th {
  text-align: left; padding: 0.65rem 0.85rem; font-weight: 600; font-size: var(--fs-xs);
  color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em;
  border-bottom: 2px solid var(--border); white-space: nowrap;
}
td { padding: 0.6rem 0.85rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
tbody tr:hover { background: var(--table-hover); }
tbody tr:last-child td { border-bottom: none; }

/* --- Alerts / Toasts --- */
.alert { padding: 0.75rem 1rem; border-radius: var(--radius-sm); font-size: var(--fs-md); font-weight: 500; }
.alert-error   { background: var(--red-light);    color: var(--red); }
.alert-success { background: var(--green-light);  color: var(--green); }
.alert-info    { background: var(--blue-light);   color: var(--blue); }
.alert-warning { background: var(--orange-light); color: var(--orange); }

/* Above every layer: .overlay (1000), the inline z-9999 sheets (revise, charges, CI) and the
   opaque contract-signing screen (.cs-overlay, 10000) — a refusal must never land under the
   form that caused it. */
.toast-container {
  position: fixed; top: 1.5rem; right: 1.5rem; z-index: 10100;
  display: flex; flex-direction: column; gap: 0.5rem; pointer-events: none;
}
.toast {
  padding: 0.7rem 1.2rem; border-radius: var(--radius-sm);
  font-size: var(--fs-md); font-weight: 500; box-shadow: var(--shadow-md);
  pointer-events: auto; animation: toast-in 0.3s ease forwards; max-width: 360px;
}
.toast.out { animation: toast-out 0.25s ease forwards; }
@keyframes toast-in  { from { opacity:0; transform:translateX(30px); } to { opacity:1; transform:translateX(0); } }
@keyframes toast-out { from { opacity:1; transform:translateX(0); } to { opacity:0; transform:translateX(30px); } }

/* --- Overlay / Modal --- */
.overlay {
  position: fixed; inset: 0; background: rgba(42,42,61,.55);
  z-index: 1000;
  display: flex; align-items: center; justify-content: center; animation: fade-in 0.2s ease;
}
.modal {
  background: var(--card); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  width: 90%; max-width: 560px; max-height: 85vh; overflow-y: auto; padding: 2rem;
  animation: slide-up 0.25s ease;
}
/* One overlay replacing another (showOverlay(el, from) in utils.js): no fade, no slide. */
.overlay.overlay-swap, .overlay.overlay-swap > .modal { animation: none; }
/* A modal opened on top of another (stackOverlay(el) in utils.js): the one underneath already
   dims the page, so this layer adds only a little — two full backdrops read as near-black. */
.overlay.overlay-stacked { background: rgba(42,42,61,.28); }
[data-theme="dark"] .overlay.overlay-stacked { background: rgba(10,10,20,.35); }
/* A sheet raised from INSIDE a document overlay (Force & Ship, Edit charges, Prepare Shipment,
   Revise document) sits in front of every overlay — below the contract-signing screen (10000)
   and toasts (10100). Until 2026-09-29 each of these was a hand-built fixed div. */
.overlay.overlay-front { z-index: 9999; }
/* Modal header with a close control in the top-right corner. The X is a plain
   round button, not a .btn — it must read as "dismiss", not as an action beside
   Save. Any modal that wants an X uses these three classes rather than styling
   its own (Working Days was the first; it had the markup and no rules). */
.modal-header {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  margin: -0.5rem 0 1rem;
}
.modal-title { margin: 0; font-size: var(--fs-lg); font-weight: 700; line-height: 1.35; padding-top: 0.35rem; }
.modal-close {
  flex: 0 0 auto; width: 32px; height: 32px; margin-right: -0.5rem;
  border: none; border-radius: 50%; background: transparent; color: var(--muted);
  font-size: var(--fs-xl); line-height: 1; cursor: pointer; font-family: inherit;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .15s, color .15s;
}
.modal-close:hover { background: var(--table-hover); color: var(--text); }
.modal-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The X that modalClose() (utils.js) adds to a modal with no button beside its title: floated
   into the top-right corner, so the title wraps beside it instead of running under it. */
.modal > .modal-close-auto { float: right; position: relative; z-index: 1; margin: -0.75rem -0.75rem 0.25rem 0.75rem; }
.modal-body { min-width: 0; }
@keyframes fade-in { from { opacity:0; } to { opacity:1; } }
@keyframes slide-up { from { opacity:0; transform:translateY(16px); } to { opacity:1; transform:translateY(0); } }

/* --- Sub-tabs: a second level INSIDE one overlay tab ---
   For the one tab that genuinely holds several jobs (today: Payment). Deliberately a
   segmented button group and NOT a second underline strip: two identical tab bars stacked
   read as one broken bar, and the second level has to be visible as subordinate at a
   glance. It is the idiom the product picker already uses (shared/product-picker.js
   productTabsHTML) — this is that control, wired by data attributes and given a count chip.
   Lives here rather than in each page's <style> because three overlays share it, unlike
   .detail-tabs which each page owns (it carries per-page margins).
   Markup + wiring: subTabsHTML / subPanelHTML / wireSubTabs in shared/utils.js. */
.sub-tabs { display: flex; flex-wrap: wrap; margin: 0 0 1.1rem; }
.stab {
  padding: 0.42rem 1rem; border: 1px solid var(--border); background: var(--card);
  color: var(--muted); font-size: var(--fs-sm); font-weight: 600; cursor: pointer;
  margin-left: -1px; transition: background .15s, color .15s, border-color .15s;
}
.stab:first-child { margin-left: 0; border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.stab:last-child  { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.stab:hover { color: var(--text); }
.stab.active {
  position: relative; z-index: 1;
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.stab-mark {
  display: inline-block; margin-left: 0.4rem; padding: 0 5px; border-radius: 9px;
  background: var(--accent); color: #fff; font-size: var(--fs-2xs); font-weight: 700;
  vertical-align: middle;
}
.stab.active .stab-mark { background: rgba(255,255,255,0.3); }
.stab-panel { animation: fade-in 0.15s ease; }
/* The group wraps on a phone, so each button keeps its own rounded ends rather than
   inheriting a corner that is no longer at the end of a row. */
@media (max-width: 768px) {
  .sub-tabs { gap: 0.35rem; }
  .stab { margin-left: 0; border-radius: var(--radius-sm); flex: 1 1 auto; text-align: center; }
}

/* --- Full-screen modal (shop floor / worker screens) ---
   Whole-page sheet with big touch targets: header stays put, body scrolls. */
.overlay-full { background: rgba(42,42,61,.72); }
.modal-full {
  background: var(--bg); border-radius: 0; box-shadow: none;
  width: 100%; max-width: none; height: 100%; max-height: none;
  padding: 0; overflow: hidden; display: flex; flex-direction: column;
  animation: slide-up 0.2s ease;
}
.mf-header {
  flex-shrink: 0; background: var(--card); border-bottom: 1px solid var(--border);
  padding: 1rem 1.5rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.mf-title { font-size: var(--fs-2xl); font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
.mf-subtitle { font-size: var(--fs-base); color: var(--text-secondary); margin-top: 0.2rem; }
.mf-close {
  flex-shrink: 0; width: 48px; height: 48px; border-radius: var(--radius);
  background: transparent; border: 1px solid var(--border); color: var(--text);
  font-size: var(--fs-2xl); line-height: 1; cursor: pointer; transition: background var(--transition);
}
.mf-close:hover { background: var(--bg); }
.mf-body { flex: 1; overflow-y: auto; padding: 1.5rem; }
.mf-inner { max-width: 1000px; margin: 0 auto; display: flex; flex-direction: column; gap: 1rem; }
.mf-clock {
  font-size: 3.4rem; font-weight: 700; letter-spacing: -0.03em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.mf-clock.idle { color: var(--muted); }
.mf-pace { margin-top: 0.35rem; font-size: var(--fs-base); font-style: italic; color: var(--muted); min-height: 1.2em; }
.mf-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0.75rem; }
.btn-xl { padding: 1.15rem 1.5rem; font-size: var(--fs-lg); font-weight: 600; min-height: 68px; }
.row-clickable { cursor: pointer; }
.mf-bar { height: 10px; background: var(--border); border-radius: 5px; overflow: hidden; }
.mf-bar-fill { height: 100%; background: var(--green); border-radius: 5px; transition: width .3s ease; }

/* Station tiles — pick a machine group, then drill into its jobs */
.tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 1rem; }
.tile {
  background: var(--card); border: 1px solid var(--border); border-left: 5px solid var(--border);
  border-radius: var(--radius); padding: 1.25rem; text-align: left; cursor: pointer; width: 100%;
  font-family: var(--font-body); color: var(--text); box-shadow: var(--shadow-sm);
  transition: box-shadow var(--transition), transform var(--transition), border-color var(--transition);
}
.tile:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); border-color: var(--muted); }
.tile.is-running { border-left-color: var(--green); }
.tile-name { font-size: var(--fs-lg); font-weight: 600; line-height: 1.3; }
.tile-count { font-size: 2.6rem; font-weight: 700; letter-spacing: -0.03em; line-height: 1.1; margin-top: 0.5rem; }
.tile-meta { font-size: var(--fs-sm); color: var(--text-secondary); }
@media (max-width: 640px) {
  .mf-title { font-size: var(--fs-lg); }
  .mf-clock { font-size: 2.6rem; }
  .mf-body { padding: 1rem; }
}

/* --- Sidebar --- */
.app-shell { display: flex; min-height: 100vh; }
.sidebar {
  width: 240px; background: var(--sidebar-bg); color: #fff;
  display: flex; flex-direction: column; flex-shrink: 0;
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 100; overflow-y: auto;
}
.sidebar-brand {
  padding: 1.3rem 1.2rem; font-size: var(--fs-lg); font-weight: 700; letter-spacing: -0.02em;
  border-bottom: 1px solid rgba(255,255,255,.08); display: flex; align-items: center; gap: 0.5rem;
}
/* Sections fold. The header is the button; .sidebar-group.collapsed hides the links
   and turns the chevron. See "Collapsed-section state" in sidebar.js.

   Three deliberate tiers, brightest first: the DEPARTMENT NAME is the loudest thing
   in its block — larger and brighter than its own links, sentence case, with a rule
   separating one department from the next. It used to be smaller, dimmer and
   letter-spaced uppercase, which read as an eyebrow label floating above a list
   rather than as the heading the list belongs to. The links sit below it, and the
   quiet uppercase eyebrow treatment now belongs to .sidebar-subsection alone, which
   is what it is actually right for. */
.sidebar-group + .sidebar-group { border-top: 1px solid rgba(255,255,255,.07); }
.sidebar-section {
  padding: 0.85rem 0.9rem 0.45rem 1.2rem; font-size: var(--fs-md); font-weight: 600;
  letter-spacing: -0.01em; color: rgba(255,255,255,.92);
  display: flex; align-items: center; gap: 0.4rem; width: 100%;
  background: none; border: 0; font-family: inherit; text-align: left; cursor: pointer;
  transition: color var(--transition), background var(--transition);
}
.sidebar-section > span:first-child { flex: 1; }
.sidebar-section:hover { color: #fff; background: rgba(255,255,255,.05); }
/* Shut: dimmer than an open heading, so open-vs-shut reads without hunting for the
   chevron — and padded evenly, since there are no links under it to close the gap. */
.sidebar-group.collapsed .sidebar-section { color: rgba(255,255,255,.6); padding-bottom: 0.85rem; }
.sidebar-group.collapsed .sidebar-section:hover { color: rgba(255,255,255,.9); }
.sidebar-chevron {
  width: 15px; height: 15px; flex-shrink: 0; opacity: 0.5;
  transition: transform var(--transition);
}
.sidebar-group.collapsed .sidebar-chevron { transform: rotate(-90deg); }
.sidebar-group.collapsed .sidebar-group-links { display: none; }
/* The rolled-up count only stands in while the section is shut. */
.sidebar-group:not(.collapsed) .sidebar-group-badge { display: none; }
.sidebar-subsection {
  padding: 0.5rem 1.2rem 0.2rem; font-size: var(--fs-3xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.07em; color: rgba(255,255,255,.4);
  margin-top: 0.25rem;
}
.sidebar-link {
  display: flex; align-items: center; gap: 0.6rem; padding: 0.55rem 1.2rem;
  font-size: var(--fs-md); color: rgba(255,255,255,.65);
  transition: background var(--transition), color var(--transition); text-decoration: none;
}
.sidebar-link:hover { background: rgba(255,255,255,.06); color: #fff; }
.sidebar-link.active {
  background: var(--accent); color: #fff; font-weight: 600;
  box-shadow: inset 4px 0 0 rgba(0,0,0,.35);
}
.sidebar-link.active:hover { background: var(--accent); color: #fff; }
.sidebar-link svg { width: 18px; height: 18px; flex-shrink: 0; opacity: 0.7; }
.sidebar-link.active svg { opacity: 1; }
.sidebar-footer {
  margin-top: auto; padding: 1rem 1.2rem; border-top: 1px solid rgba(255,255,255,.08);
  font-size: var(--fs-sm); color: rgba(255,255,255,.45);
}
.sidebar-footer .user-name { color: rgba(255,255,255,.85); font-weight: 500; }
.sidebar-footer .user-dept { font-size: var(--fs-xs); color: rgba(255,255,255,.4); }
.sidebar-logout {
  margin-top: 0; background: none; border: none; color: rgba(255,255,255,.4);
  font-family: var(--font-body); font-size: var(--fs-sm); cursor: pointer; padding: 0.3rem 0;
  transition: color var(--transition);
}
.sidebar-logout:hover { color: var(--red); }

.sidebar-home-link {
  display: flex; align-items: center; gap: 0.6rem;
  margin-top: 0.7rem; padding: 0.5rem 0.6rem;
  border-radius: 8px; border: 1px solid rgba(255,255,255,.08);
  text-decoration: none; color: rgba(255,255,255,.5);
  font-size: var(--fs-xs); font-weight: 500;
  transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.sidebar-home-link:hover {
  background: rgba(255,255,255,.05); color: rgba(255,255,255,.85);
  border-color: rgba(255,255,255,.15);
}
.sidebar-home-logo {
  height: 22px; width: auto; object-fit: contain;
  filter: invert(1); opacity: 0.6; transition: opacity 0.2s;
}
.sidebar-home-link:hover .sidebar-home-logo { opacity: 1; }

/* --- Main Content --- */
/* min-width:0 — `.main-content` is a flex child of `.app-shell`, and a flex item's default
   `min-width:auto` will not let it shrink below its content's min-content width. A page with a
   wide table therefore grew the MAIN column past the window (Staff Expenses' 15 columns: an
   1818px page in a 1400px window), which scrolled the whole page sideways and pushed the right
   end of the filter bar off-screen. With this the column is the window: the filter bar wraps
   inside it and stays visible, and only the wide table scrolls, inside its own `.table-wrap`,
   which is what that wrapper is for. Desktop since 2026-10-05; the phone shell had it first. */
.main-content { flex: 1; margin-left: 240px; padding: 2rem; min-height: 100vh; min-width: 0; }
.page-header { margin-bottom: 1.5rem; }
/* A header carrying actions (title left, buttons right — 37 pages) wraps instead of pushing
   the buttons past a narrow window's edge. */
.page-header.flex { flex-wrap: wrap; gap: 0.75rem; }
.page-title { font-size: var(--fs-2xl); font-weight: 700; letter-spacing: -0.02em; }
.page-subtitle { font-size: var(--fs-md); color: var(--muted); margin-top: 0.25rem; }

/* --- Auth Pages --- */
.auth-page {
  min-height: 100vh; display: flex; align-items: center;
  justify-content: center; background: var(--bg); padding: 1.5rem;
}
.auth-card {
  width: 100%; max-width: 400px; background: var(--card);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: 2.5rem 2rem;
}
.auth-logo { text-align: center; margin-bottom: 1.8rem; }
.auth-logo h1 { font-size: var(--fs-2xl); font-weight: 700; letter-spacing: -0.02em; }
.auth-logo .accent { color: var(--accent); }
/* The ZERSYNC wordmark (--font-brand): the landing name, the 404 header, the sign-in
   greeting. Expanded type reads heavy, so it is tracked out rather than in. */
.wordmark-lg, .site .wordmark, .auth-logo .accent {
  font-family: var(--font-brand); font-stretch: 125%; font-weight: 700; letter-spacing: .06em;
}
.auth-logo p { font-size: var(--fs-sm); color: var(--muted); margin-top: 0.3rem; }
.auth-form { display: flex; flex-direction: column; gap: 1rem; }
/* The EN/TR button at the top of the card: these pages have neither the sidebar nor the public
   site's header, so without it a first-time visitor could not switch language. */
.auth-lang { display: flex; justify-content: flex-end; margin-bottom: .5rem; }
.auth-footer { text-align: center; margin-top: 1.5rem; font-size: var(--fs-sm); color: var(--muted); }
.auth-footer a { font-weight: 500; }

/* --- Spinner --- */
.spinner {
  display: inline-block; width: 18px; height: 18px;
  border: 2px solid rgba(255,255,255,.3); border-top-color: #fff;
  border-radius: 50%; animation: spin 0.6s linear infinite;
}
.spinner-dark { border-color: rgba(0,0,0,.1); border-top-color: var(--accent); }
@keyframes spin { to { transform: rotate(360deg); } }

/* --- Empty State --- */
.empty-state { text-align: center; padding: 3rem 1rem; color: var(--muted); }
.empty-state svg { margin-bottom: 1rem; opacity: 0.4; }
.empty-state p { font-size: var(--fs-base); }

/* --- Theme Toggle ---
   A two-segment control, sun | moon: the raised segment (::before) sits under the theme in
   use, so the state reads at a glance. One markup everywhere — themeToggleHtml() in
   utils.js; the static public pages (index, 404) carry the same button by hand. The icons
   are our own drawings painted through masks, so they take the text colours in both themes
   (SF Symbols are licensed for Apple-platform apps only, never a website). */
.theme-toggle {
  position: relative; display: inline-flex; flex: none; padding: 2px; gap: 2px;
  border: none; border-radius: 999px; background: var(--fill-strong, rgba(120,120,128,.24));
  cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent;
}
.theme-toggle::before {
  content: ''; position: absolute; top: 2px; left: 2px; width: 32px; height: 26px;
  border-radius: 999px; background: var(--card); box-shadow: 0 1px 3px rgba(0,0,0,.18), 0 0 0 .5px rgba(0,0,0,.04);
  transition: transform .25s cubic-bezier(.2, .7, .2, 1);
}
[data-theme="dark"] .theme-toggle::before { transform: translateX(34px); background: #636366; }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.theme-toggle-icon {
  position: relative; width: 32px; height: 26px; background: var(--muted);
  -webkit-mask: var(--icon) center / 16px 16px no-repeat; mask: var(--icon) center / 16px 16px no-repeat;
  transition: background-color .25s;
}
.theme-toggle-icon.sun {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4.6'/%3E%3Cpath d='M12 1.8v2.6M12 19.6v2.6M1.8 12h2.6M19.6 12h2.6M4.8 4.8l1.85 1.85M17.35 17.35l1.85 1.85M4.8 19.2l1.85-1.85M17.35 6.65l1.85-1.85' stroke='%23000' stroke-width='2.2' stroke-linecap='round'/%3E%3C/svg%3E");
}
.theme-toggle-icon.moon {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cmask id='m'%3E%3Crect width='24' height='24' fill='%23fff'/%3E%3Ccircle cx='17.5' cy='6.5' r='7.2'/%3E%3C/mask%3E%3Ccircle cx='12' cy='12' r='9.4' mask='url(%23m)'/%3E%3C/svg%3E");
}
html:not([data-theme="dark"]) .theme-toggle-icon.sun,
[data-theme="dark"] .theme-toggle-icon.moon { background: var(--text); }
.theme-toggle:hover .theme-toggle-icon { background: var(--text-secondary); }
html:not([data-theme="dark"]) .theme-toggle:hover .theme-toggle-icon.sun,
[data-theme="dark"] .theme-toggle:hover .theme-toggle-icon.moon { background: var(--text); }
@media (prefers-reduced-motion: reduce) { .theme-toggle::before { transition: none; } }
/* Sign-in pages: the same control, floating top-right of the window (injected by page.js). */
.auth-theme-toggle { position: fixed; top: 1.2rem; right: 1.2rem; z-index: 10; }

/* --- Dark mode overrides --- */
[data-theme="dark"] .form-select,
[data-theme="dark"] select.form-input:not([multiple]):not([size]),
[data-theme="dark"] .filter-multi-btn,
[data-theme="dark"] .combo-select-input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236e6e88' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
[data-theme="dark"] .badge-muted { background: #2e2e4a; }
[data-theme="dark"] .overlay { background: rgba(10,10,20,.7); }

/* --- Mobile shell ---
   Detection is the viewport width, not the device: at ≤768px (phones, and tablets
   held upright) the sidebar is gone and a fixed top bar with a menu button takes its
   place. Tapping the button turns the SAME #sidebar element into a full-screen menu
   (body.nav-open); picking a link navigates, so the next page loads with it closed.
   A tablet turned sideways gets the desktop sidebar back. Nothing here sniffs the
   user agent — it is CSS state, and sidebar.js only flips the body class. */
.mobile-topbar { display: none; }
:root { --topbar-h: 3.4rem; }
/* The close button lives in the sidebar brand row but only shows on the sheet.
   Declared before the media block so the mobile rule below wins. */
.sidebar-close {
  display: none; width: 44px; height: 44px; border-radius: var(--radius-sm);
  background: transparent; border: none; color: rgba(255,255,255,.7); cursor: pointer;
  align-items: center; justify-content: center; padding: 0; font-size: var(--fs-2xl); line-height: 1;
}
.sidebar-close:active { background: rgba(255,255,255,.1); }

@media (max-width: 768px) {
  .mobile-topbar {
    display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
    position: fixed; top: 0; left: 0; right: 0; height: var(--topbar-h); z-index: 150;
    padding: 0 0.6rem 0 1rem; background: var(--sidebar-bg); color: #fff;
    box-shadow: 0 1px 0 rgba(255,255,255,.08), var(--shadow-md);
  }
  .mobile-topbar-brand { font-size: var(--fs-lg); font-weight: 700; letter-spacing: -0.02em; white-space: nowrap;
    max-width: 55%; overflow: hidden; text-overflow: ellipsis; }
  .mobile-topbar-page {
    flex: 1; min-width: 0; font-size: var(--fs-sm); color: rgba(255,255,255,.55);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: right;
  }
  .mobile-nav-btn {
    flex-shrink: 0; width: 44px; height: 44px; border-radius: var(--radius-sm);
    background: transparent; border: none; color: #fff; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; padding: 0;
  }
  .mobile-nav-btn:active { background: rgba(255,255,255,.1); }
  .mobile-nav-btn svg { width: 24px; height: 24px; }

  /* Sidebar → hidden until opened, then a full-screen sheet over everything. */
  .sidebar { display: none; width: 100%; inset: 0; z-index: 200; }
  body.nav-open .sidebar { display: flex; }
  body.nav-open { overflow: hidden; }
  /* Sticky so the close button stays reachable however far a long menu scrolls. */
  .sidebar-brand {
    padding: 0 0.6rem 0 1.2rem; height: var(--topbar-h); flex-shrink: 0; justify-content: space-between;
    position: sticky; top: 0; z-index: 1; background: var(--sidebar-bg);
  }
  .sidebar-close { display: inline-flex; }
  /* A fold header is a tap target on the sheet, so it gets full row padding. */
  .sidebar-section { padding: 0.95rem 1.2rem 0.5rem; font-size: var(--fs-base); }
  .sidebar-group.collapsed .sidebar-section { padding-bottom: 0.95rem; }
  .sidebar-chevron { width: 20px; height: 20px; }
  .sidebar-subsection { padding: 0.5rem 1.2rem 0.25rem; font-size: var(--fs-2xs); }
  .sidebar-link { padding: 0.85rem 1.2rem; font-size: var(--fs-base); gap: 0.8rem; }
  .sidebar-link svg { width: 20px; height: 20px; }
  .sidebar-footer { padding-bottom: calc(1rem + env(safe-area-inset-bottom)); }

  /* min-width:0 is on the base rule (above) for every width — on a phone it was 721px of
     content inside a 430px screen, every paragraph clipped at the edge. */
  .main-content { margin-left: 0; padding: calc(var(--topbar-h) + 1rem) 1rem 1.5rem; }
  .toast-container { top: calc(var(--topbar-h) + 0.6rem); right: 0.75rem; left: 0.75rem; }
  .toast { max-width: none; }
}

/* ============================================================
   Contract Signing Overlay
   ============================================================ */
.cs-overlay {
  position: fixed; inset: 0; z-index: 10000;
  background: var(--bg); display: flex; flex-direction: column;
}
.cs-modal {
  display: flex; flex-direction: column; height: 100vh; width: 100%;
  max-width: 900px; margin: 0 auto; background: var(--bg);
}
.cs-header {
  padding: 1rem 1.5rem; border-bottom: 1px solid var(--border);
  background: var(--card); flex-shrink: 0;
}
.cs-progress { display: flex; align-items: center; flex-wrap: wrap; gap: 0.25rem; }
.cs-progress-bar {
  margin-top: 0.5rem; height: 4px; background: var(--border);
  border-radius: 2px; overflow: hidden;
}
.cs-progress-fill {
  height: 100%; background: var(--accent); border-radius: 2px;
  transition: width .3s ease;
}
.cs-body {
  flex: 1; overflow-y: auto; padding: 1.5rem;
}
.cs-content {
  background: var(--card); border-radius: var(--radius);
  padding: 2rem; box-shadow: var(--shadow-sm);
  line-height: 1.8; font-size: var(--fs-base);
}
.cs-content h1 { font-size: var(--fs-xl); margin: 1.5rem 0 0.75rem; }
.cs-content h2 { font-size: var(--fs-lg); margin: 1.25rem 0 0.5rem; }
.cs-content h3 { font-size: var(--fs-lg); margin: 1rem 0 0.5rem; }
.cs-content ul, .cs-content ol { padding-left: 1.5rem; margin: 0.5rem 0; }
.cs-content li { margin-bottom: 0.3rem; }
.cs-content hr { border: none; border-top: 2px solid var(--border); margin: 2rem 0; }
.cs-content strong { font-weight: 600; }
.cs-content em { font-style: italic; }
.cs-footer {
  padding: 1rem 1.5rem; border-top: 1px solid var(--border);
  background: var(--card); flex-shrink: 0;
  display: flex; align-items: flex-end; gap: 1rem; flex-wrap: wrap;
}
.cs-sig-section { flex: 1; min-width: 280px; }
.cs-canvas-wrap {
  margin-top: 0.5rem; border: 2px dashed var(--border);
  border-radius: var(--radius-sm); background: #fff; cursor: crosshair;
}
[data-theme="dark"] .cs-canvas-wrap { background: #1e1e36; }
.cs-canvas-wrap canvas { display: block; width: 100%; touch-action: none; }
.cs-sign-btn { white-space: nowrap; align-self: flex-end; }

/* --- Token multi-select chips --- */
.token-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.35rem; }
.token-chip {
  display: inline-flex; align-items: center; gap: 0.25rem;
  padding: 0.2rem 0.6rem; border-radius: 20px; font-size: var(--fs-sm);
  background: var(--blue-light); color: var(--blue); cursor: pointer;
  border: 1px solid transparent; transition: var(--transition);
}
.token-chip.selected { background: var(--blue); color: #fff; }
.token-chip:hover { border-color: var(--blue); }
/* ── Configurable-product structure: runtime configurator (prod-configure) ── */
.cfg-mod { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: .6rem .75rem; margin-bottom: .6rem; background: var(--card); }
.cfg-mod-hd { margin-bottom: .4rem; }
.cfg-row { display: flex; align-items: center; gap: .5rem; margin-top: .4rem; flex-wrap: wrap; }
.cfg-lbl { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .05em; color: var(--muted); min-width: 54px; }
.cfg-counts, .cfg-covers { display: flex; gap: .3rem; flex-wrap: wrap; }
.cfg-count { width: 34px; height: 34px; border: 1px solid var(--border); background: var(--card); border-radius: var(--radius-sm); cursor: pointer; font-family: var(--font-body); }
.cfg-count:hover { border-color: var(--text); }
.cfg-count.sel { background: var(--text); color: #fff; border-color: var(--text); }
.cfg-cover { width: 30px; height: 22px; border: 2px solid var(--border); border-radius: 3px; cursor: pointer; padding: 0; }
.cfg-cover.sel { border-color: var(--text); box-shadow: 0 0 0 1px var(--text); }
.cfg-cells { margin-top: .5rem; display: flex; flex-direction: column; gap: .35rem; }
.cfg-cellrow { display: flex; align-items: center; gap: .3rem; }
.cfg-edge { font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: .05em; color: var(--muted); min-width: 42px; }
.cfg-cell { position: relative; width: 30px; height: 30px; border: 1.5px solid var(--border); border-radius: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: var(--fs-2xs); font-weight: 600; color: #c07010; }
.cfg-cell:hover { border-color: var(--text); }
.cfg-aly { position: absolute; top: -5px; right: -5px; width: 14px; height: 14px; border-radius: 50%; background: #f0a030; color: #fff; font-size: var(--fs-3xs); display: flex; align-items: center; justify-content: center; }
.cfg-popup { position: fixed; z-index: 1000; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-md); padding: .5rem; display: flex; flex-direction: column; gap: .4rem; min-width: 160px; }
.cfg-popup-lbl { font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.cfg-popup-row { display: flex; gap: .35rem; }
.cfg-popup-sw { width: 26px; height: 26px; border: 2px solid transparent; border-radius: 4px; cursor: pointer; }
.cfg-popup-sw:hover { transform: scale(1.1); }
.cfg-popup-sw.sel { border-color: var(--text); }
.cfg-popup-aly { padding: .3rem .5rem; border: 1px solid var(--orange); background: var(--orange-light); color: #c07010; font-size: var(--fs-xs); text-align: center; cursor: pointer; border-radius: 4px; }
.cfg-popup-aly.sel { background: var(--orange); color: #fff; }
.cfg-popup-clr { padding: .25rem .5rem; border: 1px solid var(--border); background: var(--bg); color: var(--muted); font-size: var(--fs-xs); text-align: center; cursor: pointer; border-radius: 4px; }
.cfg-popup-clr:hover { border-color: var(--text); color: var(--text); }

/* ── Configurable-product builder: structure authoring (wh-models) ── */
.bld-sec { border-top: 1px dashed var(--border); margin-top: 1rem; padding-top: 1rem; }
.bld-sec h4 { margin: 0 0 .25rem; }
.bld-chips { display: flex; flex-wrap: wrap; gap: .3rem; align-items: center; }
.bld-chip { display: inline-flex; align-items: center; gap: .3rem; padding: .2rem .5rem; border: 1px solid var(--border); border-radius: 999px; background: var(--bg); font-size: var(--fs-sm); }
.bld-chip button { border: none; background: none; cursor: pointer; color: var(--muted); font-size: var(--fs-sm); line-height: 1; padding: 0; }
.bld-keychecks { display: flex; flex-wrap: wrap; gap: .75rem; }
.bld-slottype { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: .6rem .75rem; margin-bottom: .6rem; }
.bld-combo { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: .5rem .6rem; margin-bottom: .5rem; }
.bld-combo-key { font-size: var(--fs-xs); color: var(--text-secondary); margin-bottom: .4rem; font-family: var(--font-mono); }
.bld-strip { display: flex; align-items: stretch; gap: 0; flex-wrap: wrap; }
.bld-ins { width: 18px; align-self: center; border: none; background: none; color: var(--blue); font-size: var(--fs-lg); cursor: pointer; padding: 0; line-height: 1; }
.bld-ins:hover { color: var(--text); }
.bld-block { position: relative; min-width: 76px; border: 1.5px solid var(--border); border-radius: 6px; padding: .4rem .3rem .35rem; text-align: center; cursor: pointer; background: var(--blue-light); }
.bld-block.spk { background: var(--bg); border-style: dashed; }
.bld-block:hover { border-color: var(--text); }
.bld-block .bb-type { font-size: var(--fs-3xs); text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.bld-block .bb-size { font-size: var(--fs-base); font-weight: 700; }
.bld-block .bb-name { font-size: var(--fs-2xs); color: var(--text-secondary); }
.bld-block .bb-del { position: absolute; top: -7px; right: -7px; width: 16px; height: 16px; border-radius: 50%; border: none; background: var(--red); color: #fff; font-size: var(--fs-2xs); cursor: pointer; line-height: 1; }
.bld-block .bb-outer { position: absolute; top: -7px; left: -3px; font-size: var(--fs-3xs); color: var(--accent); }
.bld-blockedit { display: grid; grid-template-columns: 1fr 1fr; gap: .4rem; margin-top: .5rem; padding: .5rem; border: 1px dashed var(--border); border-radius: var(--radius-sm); }

/* ============================================================
   Shared components — one definition each, used by every page that needs it.
   (Until 2026-09-29 these were per-page <style> strings in page JS, then "Page rules"
   scoped by [data-page]; the owner asked for one shared design, so a class that only one
   page happened to use is now simply a shared component, and near-duplicates — three
   detail-tab sizes, two calendars, two legend dots — became one.)

   Page-specific CSS is the exception and needs a reason written next to it. It is scoped
   with [data-page="<page>"], the page setting document.documentElement.dataset.page at the
   top of its script. Never a <style> string in a page's JS.
   Printed documents are NOT here: they build their own sheet (printBaseCss() in config.js).
   ============================================================ */

/* --- Order timeline (Sales proformas, Purchase orders, both custom-invoice overlays) --- */
.order-row{cursor:pointer;}
.order-row.done{opacity:0.55;}
.order-row:hover td{background:var(--bg);}
.tl{position:relative;padding-left:24px;margin:16px 0;}
.tl::before{content:'';position:absolute;left:8px;top:0;bottom:0;width:2px;background:var(--border);}
.tl-i{position:relative;margin-bottom:14px;padding-left:16px;}
.tl-i::before{content:'';position:absolute;left:-20px;top:4px;width:12px;height:12px;border-radius:50%;border:2px solid var(--border);background:var(--card);z-index:1;}
.tl-i.green::before{background:var(--green);border-color:var(--green);}
.tl-i.blue::before{background:var(--blue);border-color:var(--blue);}
.tl-i.orange::before{background:var(--orange);border-color:var(--orange);}
.tl-i.red::before{background:var(--red);border-color:var(--red);}
.tl-i.accent::before{background:var(--accent);border-color:var(--accent);}
.tl-i.muted::before{background:var(--card);border-color:var(--muted);}
.tl-date{font-size:var(--fs-2xs);color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:0.5px;}
.tl-label{font-size:var(--fs-md);font-weight:600;margin-top:1px;}
.tl-sub{font-size:var(--fs-xs);color:var(--muted);margin-top:1px;}
.tl-link{color:var(--accent);cursor:pointer;text-decoration:none;}
.tl-link:hover{text-decoration:underline;}

/* --- Detail tabs (document overlays; markup = detailTabsHTML in utils.js) — one size everywhere --- */
.detail-tabs{display:flex;gap:0.15rem;flex-wrap:wrap;border-bottom:2px solid var(--border);margin:0 0 1.15rem;}
.dtab{padding:0.7rem 1.4rem;font-family:inherit;font-size:var(--fs-base);border:none;border-bottom:2px solid transparent;margin-bottom:-2px;background:none;cursor:pointer;font-weight:600;color:var(--muted);transition:color 0.15s,border-color 0.15s;}
.dtab.active{color:var(--accent);border-bottom-color:var(--accent);}
.dtab:hover{color:var(--text);}
.dtab-panel{animation:fade-in 0.15s ease;}

/* Scale up the small inline font-sizes used throughout the tab panels so the
   content is easier to read/click. Scoped to .dtab-panel; overrides win via !important. */


/* --- Disciplinary case stages (HR) — the three stages on one numbered rail: done green, the one to work
   now accent, optional/skipped dashed, not reachable yet muted. */
.dc-stage{position:relative;padding:0 0 2rem 3rem;}
.dc-stage:last-child{padding-bottom:.25rem;}
.dc-stage::before{content:'';position:absolute;left:15px;top:38px;bottom:6px;width:2px;background:var(--border);}
.dc-stage:last-child::before{display:none;}
.dc-num{position:absolute;left:0;top:0;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:var(--fs-md);border:2px solid var(--border);background:var(--card);color:var(--muted);}
.dc-stage.done .dc-num{background:var(--green);border-color:var(--green);color:#fff;}
.dc-stage.current .dc-num{background:var(--accent);border-color:var(--accent);color:#fff;}
.dc-stage.optional .dc-num{border-style:dashed;border-color:var(--muted);color:var(--text);}
.dc-stage.skipped .dc-num{border-style:dashed;}
.dc-stage.skipped .dc-title,
.dc-stage.pending .dc-title{color:var(--muted);}
.dc-head{display:flex;justify-content:space-between;align-items:flex-start;gap:.75rem;flex-wrap:wrap;margin-bottom:.75rem;}
.dc-title{margin:0;padding-top:.3rem;font-size:var(--fs-base);font-weight:700;line-height:1.3;}
.dc-state{margin-top:.15rem;font-size:var(--fs-sm);color:var(--muted);}
.dc-stage .table-wrap{margin-bottom:.75rem;}
.dc-stage .table-wrap:last-child{margin-bottom:0;}
.dc-choices{display:flex;gap:.6rem;flex-wrap:wrap;}
.dc-choices .btn-secondary.active{border-color:var(--accent);color:var(--accent);}
.dc-form{display:flex;flex-direction:column;gap:1rem;margin-top:.75rem;padding:1rem 1.1rem;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);}
.dc-form-title{margin:0;font-size:var(--fs-md);font-weight:700;}
.dc-row{display:flex;gap:1rem;align-items:flex-end;flex-wrap:wrap;}
.dc-note{margin:0;font-size:var(--fs-sm);color:var(--muted);}
@media (max-width:768px){
  .dc-stage{padding-left:2.6rem;}
  .dc-form{padding:.85rem;}
}

/* --- Grouped invoice list (Commercial Invoices) --- */
.pi-group{background:var(--card);border:1px solid var(--border);border-radius:var(--radius-lg);margin-bottom:0.75rem;overflow:hidden;}
.pi-group-header{padding:0.75rem 1rem;display:flex;align-items:center;justify-content:space-between;gap:0.5rem;flex-wrap:wrap;}
.pi-group-header:hover{background:var(--bg);}
/* CI register (2026-10-05): the group header is a row with columns under one column-head row
   (.ci-group-head), not a run of badges — MDs/tables-not-pills.md. Same template on both. */
.ci-group-row{display:grid;grid-template-columns:1.2rem minmax(7rem,1.1fr) minmax(9rem,2fr) 7rem 4.5rem 8rem auto;align-items:center;gap:0.5rem;}
.ci-group-row.agg{grid-template-columns:1.2rem minmax(7rem,1.1fr) minmax(9rem,2fr) 7rem 4.5rem 8rem 8rem auto;}
.ci-group-row .num{text-align:right;font-variant-numeric:tabular-nums;}
.ci-group-head{padding:0.25rem 1rem;font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:0.4px;color:var(--muted);}
@media (max-width:768px){.ci-group-row,.ci-group-row.agg{grid-template-columns:1.2rem 1fr 1fr;} .ci-group-head{display:none;} .ci-group-row>.num,.ci-group-row>span:last-child{grid-column:span 3;text-align:left;}}
/* Share bar as a CELL of the row its figure sits in (dashboard, customer detail) — never a
   strip beside the table. The inner div's width is the share; its colour defaults to accent. */
.share-cell{width:30%;min-width:6rem;}
.share-bar{height:8px;background:var(--border);border-radius:4px;overflow:hidden;}
.share-bar>div{height:100%;background:var(--accent);border-radius:4px;}
.ci-rows-container{border-top:1px solid var(--border);}

/* --- Material requirements rows (Purchasing) --- */
.mr-group td{border-top:2px solid var(--border);}
.mr-demand td{background:var(--table-hover, #faf8f6);}
.mr-planned td{opacity:.72;}
.mr-covers{width:auto;min-width:260px;font-size:inherit;}
.mr-covers th,
.mr-covers td{padding:2px 10px 2px 0;border:none;background:none;}

/* --- Booking schedule (Bookings) --- */
.bk-row{cursor:pointer;}
.bk-row.warranty td:first-child{box-shadow:inset 3px 0 0 var(--green);}
.sch-grid{display:grid;grid-template-columns:50px 1fr;border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden;background:var(--card);}
.sch-time{background:var(--bg);padding:3px 6px;font-size:var(--fs-2xs);font-weight:600;color:var(--muted);text-align:right;border-bottom:1px solid var(--border);height:40px;display:flex;align-items:flex-start;justify-content:flex-end;font-family:var(--font-mono);}
.sch-slot{position:relative;border-bottom:1px solid var(--border);height:40px;border-left:1px solid var(--border);}
.sch-slot.now{background:color-mix(in srgb, var(--accent) 4%, transparent);}
.sch-block{position:absolute;left:3px;right:3px;border-radius:4px;padding:2px 6px;font-size:var(--fs-2xs);font-weight:600;overflow:hidden;cursor:pointer;z-index:2;border-left:3px solid;line-height:1.3;}
.sch-block:hover{box-shadow:0 2px 8px rgba(0,0,0,0.15);}
.sch-block.Pending{background:#fff5f0;border-left-color:var(--accent);}
.sch-block.Completed{background:rgba(48,160,96,0.1);border-left-color:var(--green);}
.sch-block.No-show{background:rgba(224,64,64,0.1);border-left-color:var(--red);}
.sch-block.Cancelled{background:var(--bg);border-left-color:var(--muted);opacity:0.5;}
.slot-tech{border:1px solid var(--border);border-radius:var(--radius-lg);padding:0.6rem 0.8rem;margin-bottom:0.5rem;}
.slot-tech.unavail{opacity:0.55;}
.slot-tech-hd{display:flex;justify-content:space-between;align-items:center;margin-bottom:0.35rem;gap:0.5rem;}
.slot-chip{display:inline-block;padding:0.25rem 0.55rem;margin:0 0.25rem 0.25rem 0;border:1px solid var(--accent);color:var(--accent);border-radius:20px;font-size:var(--fs-xs);font-weight:600;cursor:pointer;font-family:var(--font-mono);background:var(--card);}
.slot-chip:hover{background:var(--accent);color:#fff;}
.slot-busy{font-size:var(--fs-2xs);color:var(--muted);}

/* --- Booking types + labour-rate matrix (Booking Config); .inactive stays page-scoped: generic name --- */
.type-block{border-bottom:1px solid var(--border-light);padding:0.15rem 0;}
.type-block:last-child{border-bottom:none;}
.type-row{display:flex;align-items:center;justify-content:space-between;padding:0.35rem 0;font-size:var(--fs-sm);}
.type-row .type-name{flex:1;font-weight:600;}
[data-page="booking-config"] .inactive{opacity:0.45;text-decoration:line-through;}
.subtype-list{padding:0 0 0.4rem 0.9rem;border-left:2px solid var(--border-light);margin-left:0.25rem;}
.subtype-row{display:flex;align-items:center;justify-content:space-between;padding:0.2rem 0;font-size:var(--fs-sm);}
.matrix-group td{background:var(--bg);font-weight:700;text-align:left !important;}
.matrix-table{border-collapse:collapse;font-size:var(--fs-sm);min-width:100%;}
.matrix-table th,
.matrix-table td{border:1px solid var(--border);padding:0.35rem 0.5rem;white-space:nowrap;}
.matrix-table th{background:var(--bg);font-weight:600;text-align:center;}
.matrix-table td:first-child{background:var(--bg);font-weight:600;min-width:130px;}
.matrix-rate{width:90px;text-align:right;font-family:var(--font-mono);border:none;background:transparent;outline:none;font-size:var(--fs-sm);padding:0.15rem 0.25rem;width:100%;box-sizing:border-box;}
.matrix-rate:focus{background:var(--accent-light,color-mix(in srgb, var(--accent) 7%, transparent));border-radius:3px;}

/* --- Stock reservation table (Fulfil from Stock) --- */
.stock-table{width:100%;border-collapse:collapse;font-size:var(--fs-sm);}
.stock-table th{text-align:left;padding:0.45rem 0.6rem;border-bottom:2px solid var(--border);font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:0.5px;color:var(--muted);white-space:nowrap;}
.stock-table td{padding:0.55rem 0.6rem;border-bottom:1px solid var(--border);vertical-align:top;}
.stock-table tr:last-child td{border-bottom:none;}
.stock-table .num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap;}
.stock-table th.num{text-align:right;}
.stock-table .grp{text-align:center;border-bottom:1px solid var(--border);}
.stock-table .grp-start{border-left:1px solid var(--border);}
.stock-table .grp-end{border-right:1px solid var(--border);}
.reservation-row{display:flex;align-items:center;gap:0.5rem;padding:0.15rem 0;font-size:var(--fs-xs);}
.reserve-form{display:flex;align-items:center;gap:0.4rem;}
.reserve-form input[type=number]{width:80px;}
.progress-bar-wrap{background:var(--border);border-radius:2px;height:5px;width:100%;margin-top:0.3rem;overflow:hidden;}
.progress-bar-fill{height:100%;background:var(--accent);transition:width 0.2s;}

/* Simulation (prod-simulation, also embedded by prod-mo-create) — already id-scoped.
   No pills, no robotic font: the whole page reads as plain, data-first text/rows.
   Badges flatten to coloured text; .mono already inherits DM Sans app-wide. */
#simDocs .badge{background:none!important;padding:0!important;border:none!important;border-radius:0!important;text-transform:none!important;letter-spacing:0!important;font-size:inherit!important;font-weight:600!important;display:inline!important}
#simDocs .badge-muted{color:var(--text)!important;font-weight:500!important}
#simDocs .mono{font-family:var(--font-body)!important}
#simDocs svg text{font-family:'DM Sans',sans-serif}
/* Crew-allocation floor board: solid = pinned, dashed = suggestion, dotted = anonymous slot */
#doc-floor .fb-tag{display:inline-block;border:1.5px solid var(--border);border-radius:9px;padding:0 6px;margin:1px 2px;font-size:var(--fs-2xs);line-height:1.6;background:var(--card);cursor:pointer;white-space:nowrap;max-width:120px;overflow:hidden;text-overflow:ellipsis;vertical-align:middle}
#doc-floor .fb-tag.fb-sug{opacity:0.66;border-style:dashed;font-style:italic}
#doc-floor .fb-tag.fb-anon{border-style:dotted;color:var(--muted);cursor:default}


/* --- Table cell alignment --- */
th.r, td.r{text-align:right;}

/* --- Legend dot (calendar keys) --- */
.legend-dot{display:inline-block;width:10px;height:10px;border-radius:3px;vertical-align:middle;margin-right:4px;}

/* --- Month calendar (My Calendar, Warehouse calendar) --- */
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:1px;background:var(--border);border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden;}
.cal-hdr{background:var(--bg);padding:.45rem 0;text-align:center;font-size:var(--fs-3xs);font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;}
.cal-day{background:var(--card);min-height:96px;padding:.4rem .45rem;position:relative;}
.cal-day.empty{background:var(--bg);}
.cal-day.off{background:repeating-linear-gradient(45deg,var(--card),var(--card) 6px,var(--bg) 6px,var(--bg) 12px);}
.cal-day.today{background:color-mix(in srgb, var(--accent) 5%, transparent);}
.cal-day .num{font-size:var(--fs-2xs);font-weight:600;color:var(--muted);display:inline-block;margin-bottom:3px;}
.cal-day .num.empty{color:transparent;}
.cal-day.today .num{background:var(--accent);color:#fff;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-weight:800;}
.cal-pip{font-size:var(--fs-3xs);padding:1px 6px;border-radius:10px;margin-bottom:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600;display:block;background:color-mix(in srgb, var(--blue) 12%, transparent);color:var(--blue);}
.cal-pip.done{opacity:.4;}
.cal-pip.machine{background:rgba(13,148,136,.12);color:#0d9488;}
.cal-pip.wh, .cal-pip.in{background:var(--green-light);color:var(--green);}
.cal-pip.out{background:var(--orange-light);color:#92400e;}
.cal-pip.in, .cal-pip.out{cursor:pointer;transition:opacity .15s;}
.cal-pip.in:hover, .cal-pip.out:hover{opacity:.7;}
/* my-calendar: a day cell opens that day's view (page-specific BEHAVIOUR, so page-scoped). */
[data-page="my-calendar"] .cal-day{cursor:pointer;transition:background .12s;}
[data-page="my-calendar"] .cal-day:hover{background:var(--bg);}
[data-page="my-calendar"] .cal-day.empty{cursor:default;}

/* --- Week / day time grid (My Calendar) --- */
.cal-win{font-size:var(--fs-3xs);font-weight:700;margin-top:3px;font-family:var(--font-body);letter-spacing:.01em;}
.cal-win.work{color:var(--accent);}
.cal-win.off{color:var(--muted);}
.cal-win.leave{color:#8b5cf6;}
.cal-win.holiday{color:var(--red);}
.tg-wrap{border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden;background:var(--card);}
.tg-head{display:grid;border-bottom:1px solid var(--border);}
.tg-head .tg-corner{border-right:1px solid var(--border);}
.tg-hcol{padding:.4rem .3rem;text-align:center;font-size:var(--fs-2xs);font-weight:700;color:var(--muted);border-right:1px solid var(--border);}
.tg-hcol.today{color:var(--accent);}
.tg-hcol .dnum{display:block;font-size:var(--fs-base);color:var(--text);font-weight:800;}
.tg-body{display:grid;position:relative;}
.tg-axis{border-right:1px solid var(--border);position:relative;}
.tg-axis .tg-hour{font-size:var(--fs-3xs);color:var(--muted);text-align:right;padding-right:.3rem;position:absolute;right:0;transform:translateY(-50%);font-family:var(--font-body);}
.tg-col{position:relative;border-right:1px solid var(--border);}
.tg-line{position:absolute;left:0;right:0;border-top:1px solid var(--border);opacity:.6;}
.tg-band{position:absolute;left:0;right:0;background:color-mix(in srgb, var(--accent) 7%, transparent);border-top:1px dashed color-mix(in srgb, var(--accent) 40%, transparent);border-bottom:1px dashed color-mix(in srgb, var(--accent) 40%, transparent);}
.tg-off{position:absolute;top:6px;left:0;right:0;text-align:center;font-size:var(--fs-3xs);font-weight:700;}
.tg-block{position:absolute;left:3px;right:3px;border-radius:5px;padding:2px 6px;font-size:var(--fs-3xs);font-weight:600;overflow:hidden;cursor:pointer;border-left:3px solid var(--blue);background:rgba(59,130,246,.14);color:var(--blue);z-index:2;line-height:1.25;}
.tg-block.machine{border-left-color:#0d9488;background:rgba(13,148,136,.14);color:#0d9488;cursor:default;}
.tg-block.wh{border-left-color:var(--green);background:rgba(48,160,96,.14);color:var(--green);cursor:pointer;}
.tg-block.Completed{border-left-color:var(--green);background:rgba(48,160,96,.14);color:var(--green);}
.tg-leave{position:absolute;left:0;right:0;background:rgba(139,92,246,.16);border-top:2px solid #8b5cf6;color:#8b5cf6;font-size:var(--fs-3xs);font-weight:700;padding:1px 4px;z-index:1;overflow:hidden;}
.tg-block.No-show{border-left-color:var(--red);background:rgba(224,64,64,.12);color:var(--red);}

/* --- Goods In / Goods Out event list (Warehouse calendar) --- */
.ev-card{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:.65rem .9rem;margin-bottom:.4rem;cursor:pointer;transition:border-color .15s;display:grid;grid-template-columns:64px 1fr auto;gap:.75rem;align-items:center;}
.ev-card:hover{border-color:var(--accent);}
.ev-card.done{opacity:.45;}
.ev-date{text-align:center;}
.ev-date .day{font-size:var(--fs-lg);font-weight:800;line-height:1;}
.ev-date .month{font-size:var(--fs-3xs);color:var(--muted);font-weight:600;text-transform:uppercase;}
.ev-date.in .day{color:var(--green);}
.ev-date.out .day{color:var(--orange);}
.tag-in{background:var(--green-light);color:var(--green);font-size:var(--fs-3xs);font-weight:700;padding:2px 7px;border-radius:20px;text-transform:uppercase;}
.tag-out{background:var(--orange-light);color:#92400e;font-size:var(--fs-3xs);font-weight:700;padding:2px 7px;border-radius:20px;text-transform:uppercase;}

/* ============================================================
   THE DESIGN (since 2026-09-29 the only one) — after Apple's current design system:
   the Human Interface Guidelines (Layout, Materials / Liquid Glass, Sidebars, Buttons,
   Segmented controls, Menus) and the WWDC25 session "Get to know the new design system".
   Its subject is LAYOUT — shape, spacing, grouping, layering — not colour: the accent stays
   the company's own (Company Settings) and the status colours stay the app's.

   This section was an opt-in overlay (shared/style-glass.css, scoped html[data-look="glass"]);
   the owner made it the only look and it was folded in here. It still layers ON TOP of the
   rules above, scoped html:not([data-standalone]) — the same specificity the overlay had, so
   the cascade that was audited (six agents, 2026-09-29) is unchanged. Since 2026-10-09 NO page
   opts out: the sign-in pages, the public site and the attendance kiosk are on it too (the
   attribute <html data-standalone> still switches it off, but nothing carries it). See
   MDs/ui-stylesheet.md.

   Rules it follows:
   1. Two layers. Navigation and transient controls (sidebar, phone top bar, menus, toasts)
      are a floating Liquid Glass layer; content (cards, tables, forms) sits on solid grouped
      surfaces beneath. Glass is never used inside the content layer.
   2. Hierarchy through layout and grouping, not decoration: cards and tables lose their
      borders and separate by surface + space.
   3. Three shapes. FIXED radius for dense controls (small buttons, fields, table containers);
      CAPSULE for regular/large buttons and the phone top bar; CONCENTRIC for anything nested —
      inner radius = outer radius − the padding between them, fixed fallback --r-inner.
   4. The sidebar floats --inset from the window edges and its rows float the same inset.
   5. Regular (not clear) glass wherever there is text; Reduce Transparency and Increase
      Contrast are honoured (end of file).
   6. Typography is the rules above, untouched. Printed documents never load this file.
   ============================================================ */

/* ---------- Tokens ---------- */
html:not([data-standalone]) {
  /* Geometry */
  --inset:         10px;                    /* window edge → floating panel */
  --r-panel:       22px;                    /* sidebar, sheets on phone */
  --r-sheet:       26px;                    /* modals */
  --radius-lg:     20px;                    /* cards, grouped containers */
  --radius:        14px;                    /* table containers, tiles */
  --radius-sm:     8px;                     /* small controls, fields' inner parts */
  --r-field:       10px;                    /* text fields / selects (medium control) */
  --r-inner:       8px;                     /* concentric fallback */
  --row-h:         34px;                    /* sidebar row */
  --sidebar-w:     244px;

  /* Surfaces: apple.com's near-white page (#fbfbfd) with white cards defined by a hairline
     and a soft shadow — the owner turned down both the cool systemGray page and the warm
     cream (2026-09-29) for "a nice clean colour". Neutral fills are plain black at low alpha. */
  --bg:            #fbfbfd;
  --card:          #ffffff;
  --surface-2:     #f5f5f7;
  --border:        #e8e8ed;                 /* opaque: some grids paint it as a fill */
  --card-line:     rgba(0,0,0,.06);
  --field-border:  #d2d2d7;
  --fill:          rgba(0,0,0,.05);         /* control tracks, secondary buttons */
  --fill-strong:   rgba(0,0,0,.09);
  --hover:         rgba(0,0,0,.04);
  --table-hover:   rgba(0,0,0,.025);
  --table-head:    #ffffff;                 /* opaque: sticky header cells scroll over rows */

  /* Glass (functional layer) */
  --glass:         rgba(255,255,255,.66);
  --glass-strong:  rgba(255,255,255,.84);
  --glass-edge:    rgba(255,255,255,.75);   /* specular top edge */
  --glass-line:    rgba(0,0,0,.08);
  --glass-blur:    blur(28px) saturate(180%);
  --sidebar-bg:    var(--glass);

  --shadow-sm:     0 0 0 .5px var(--card-line), 0 1px 3px rgba(0,0,0,.04), 0 4px 14px rgba(0,0,0,.03);
  --shadow-md:     0 6px 20px rgba(0,0,0,.08), 0 1px 3px rgba(0,0,0,.05);
  --shadow-lg:     0 24px 60px rgba(0,0,0,.16), 0 4px 12px rgba(0,0,0,.06);
  --transition:    .22s cubic-bezier(.25,.1,.25,1);
}
html:not([data-standalone])[data-theme="dark"] {
  --bg:            #000000;
  --card:          #1c1c1e;
  --surface-2:     #2c2c2e;
  --border:        #38383a;
  --field-border:  #48484a;
  --fill:          rgba(120,120,128,.24);
  --fill-strong:   rgba(120,120,128,.36);
  --hover:         rgba(255,255,255,.06);
  --table-hover:   rgba(255,255,255,.05);
  --table-head:    #1c1c1e;
  --glass:         rgba(40,40,44,.58);
  --glass-strong:  rgba(44,44,48,.86);
  --glass-edge:    rgba(255,255,255,.1);
  --glass-line:    rgba(255,255,255,.1);
  --card-line:     rgba(255,255,255,.06);
  --shadow-sm:     0 0 0 .5px var(--card-line), 0 1px 2px rgba(0,0,0,.5);
  --shadow-md:     0 8px 24px rgba(0,0,0,.5);
  --shadow-lg:     0 24px 64px rgba(0,0,0,.6);
}

html:not([data-standalone]) body { background: var(--bg); }

/* Wells. Pages paint inset panels, group-header bands, read-only fields, calendar off-days
   and row hovers with var(--bg) — visible against a white card when --bg was cream, but
   the Glass page (#fbfbfd) is indistinguishable from white, so every one of them vanished.
   Inside the content layer --bg therefore means "well": Apple's secondary grey (#f5f5f7,
   dark #2c2c2e). The page itself keeps the near-white, because body reads --bg from <html>. */
html:not([data-standalone]) :is(.main-content, .modal:not(.modal-full), .modal-full .card, .cs-content) {
  --bg: var(--surface-2);
}

/* ============================================================
   Navigation layer — the sidebar is an inset, floating glass panel
   ============================================================ */
html:not([data-standalone]) .sidebar {
  width: var(--sidebar-w);
  top: var(--inset); left: var(--inset); bottom: var(--inset);
  border-radius: var(--r-panel);
  background: var(--glass); color: var(--text);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  border: .5px solid var(--glass-line);
  box-shadow: var(--shadow-md), inset 0 1px 0 var(--glass-edge);
  scrollbar-width: thin; scrollbar-color: var(--fill-strong) transparent;
}
/* Content starts at the panel's right edge (plus its own padding), and its top edge lines
   up with the panel's first row rather than the window edge. */
html:not([data-standalone]) .main-content {
  margin-left: calc(var(--sidebar-w) + var(--inset));
  padding: calc(var(--inset) + 1.25rem) 2.25rem 2.5rem;
}
/* No rules between groups: space and the heading carry the grouping. */
html:not([data-standalone]) .sidebar-brand { border-bottom: none; padding: 1.15rem 1.25rem .6rem; }
html:not([data-standalone]) .sidebar-group + .sidebar-group { border-top: none; margin-top: .15rem; }
html:not([data-standalone]) .sidebar-section {
  margin: 0 var(--inset); width: calc(100% - 2 * var(--inset));
  padding: .55rem calc(1.25rem - var(--inset)) .35rem;
  border-radius: calc(var(--r-panel) - var(--inset));
  color: var(--text);
}
html:not([data-standalone]) .sidebar-section:hover { color: var(--text); background: var(--hover); }
html:not([data-standalone]) .sidebar-group.collapsed .sidebar-section { color: var(--text-secondary); padding-bottom: .55rem; }
html:not([data-standalone]) .sidebar-group.collapsed .sidebar-section:hover { color: var(--text); }
html:not([data-standalone]) .sidebar-subsection { color: var(--muted); padding: .55rem 1.25rem .2rem; }
/* Rows: inset by the same --inset as the panel, radius concentric with it. */
html:not([data-standalone]) .sidebar-link {
  min-height: var(--row-h); margin: 1px var(--inset);
  padding: .4rem calc(1.25rem - var(--inset));
  border-radius: calc(var(--r-panel) - var(--inset));
  color: var(--text-secondary);
}
html:not([data-standalone]) .sidebar-link:hover { background: var(--hover); color: var(--text); }
html:not([data-standalone]) .sidebar-link svg { color: var(--accent); opacity: 1; }
html:not([data-standalone]) .sidebar-link.active,
html:not([data-standalone]) .sidebar-link.active:hover { background: var(--accent); color: #fff; box-shadow: none; }
html:not([data-standalone]) .sidebar-link.active svg { color: #fff; }
html:not([data-standalone]) .sidebar-group-links { padding-bottom: .3rem; }
/* Footer: its own grouped block at the foot of the panel, concentric with it. The top margin
   stays `auto` (as in style.css) so the block is pinned to the bottom, not floated up under
   the last open section. */
html:not([data-standalone]) .sidebar-footer {
  margin: auto var(--inset) var(--inset); padding: .85rem .9rem;
  border-top: none; border-radius: calc(var(--r-panel) - var(--inset));
  background: var(--hover); color: var(--muted);
}
html:not([data-standalone]) .sidebar-footer .user-name { color: var(--text); }
html:not([data-standalone]) .sidebar-footer .user-dept { color: var(--muted); }
html:not([data-standalone]) .sidebar-logout { color: var(--muted); }
html:not([data-standalone]) .sidebar-logout:hover { color: var(--red); }
/* The EN/TR pair writes its inactive colours inline for a dark sidebar. */
html:not([data-standalone]) .sidebar-footer .btn-sm[style*="rgba(255,255,255"] {
  color: var(--text-secondary) !important; border-color: var(--field-border) !important;
}
html:not([data-standalone]) .sidebar-home-link {
  border: none; background: var(--card); color: var(--muted);
  border-radius: var(--r-inner);            /* concentric value goes negative here → fallback */
}
html:not([data-standalone]) .sidebar-home-link:hover { background: var(--card); color: var(--text); }
html:not([data-standalone]):not([data-theme="dark"]) .sidebar-home-logo { filter: none; }
html:not([data-standalone]) .sidebar-close { color: var(--text-secondary); border-radius: 999px; }
html:not([data-standalone]) .sidebar-close:active { background: var(--fill); }

/* ---------- Menus & popovers: regular glass, rows concentric inside ---------- */
html:not([data-standalone]) .combo-select-dropdown,
html:not([data-standalone]) .cfg-popup {
  --menu-pad: 5px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  border: .5px solid var(--glass-line); border-radius: 14px;
  box-shadow: var(--shadow-lg), inset 0 1px 0 var(--glass-edge);
  padding: var(--menu-pad);
}
html:not([data-standalone]) .combo-select-option,
html:not([data-standalone]) .filter-multi-opt { border-radius: calc(14px - 5px); }
html:not([data-standalone]) .combo-select-option:hover,
html:not([data-standalone]) .combo-select-option.highlighted { background: var(--accent); color: #fff; }
html:not([data-standalone]) .combo-select-option.disabled:hover { background: none; color: var(--muted); }
html:not([data-standalone]) .filter-multi-opt:hover { background: var(--hover); }

/* ---------- Toasts: floating glass, clear of the window edge ---------- */
html:not([data-standalone]) .toast-container { top: calc(var(--inset) + .5rem); right: calc(var(--inset) + .5rem); }
html:not([data-standalone]) .toast {
  border-radius: 16px; padding: .8rem 1.15rem;
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  border: .5px solid var(--glass-line);
  box-shadow: var(--shadow-lg), inset 0 1px 0 var(--glass-edge);
}
html:not([data-standalone]) .toast.alert-info    { background: color-mix(in srgb, var(--glass-strong) 82%, var(--blue));   color: var(--text); }
html:not([data-standalone]) .toast.alert-success { background: color-mix(in srgb, var(--glass-strong) 82%, var(--green));  color: var(--text); }
html:not([data-standalone]) .toast.alert-error   { background: color-mix(in srgb, var(--glass-strong) 80%, var(--red));    color: var(--text); }
html:not([data-standalone]) .toast.alert-warning { background: color-mix(in srgb, var(--glass-strong) 80%, var(--orange)); color: var(--text); }

/* ============================================================
   Content layer — solid grouped surfaces, separated by space
   ============================================================ */
html:not([data-standalone]) .page-header { margin-bottom: 1.75rem; }
html:not([data-standalone]) .card {
  border-color: transparent; border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
}
html:not([data-standalone]) .card-lg { border-radius: 26px; box-shadow: var(--shadow-md); }
html:not([data-standalone])[data-theme="dark"] .card { border-color: rgba(255,255,255,.04); }

/* Tables: a standalone table is its own grouped container (no border, surface + shadow);
   a table already inside a card drops the container so there is one group, not two. */
html:not([data-standalone]) .table-wrap {
  border-color: transparent; border-radius: var(--radius);
  background: var(--card); box-shadow: var(--shadow-sm);
}
html:not([data-standalone]) .card .table-wrap,
html:not([data-standalone]) .modal .table-wrap {
  border-color: var(--border); box-shadow: none; border-radius: var(--r-inner);
}
html:not([data-standalone]) thead { background: var(--table-head); }
/* Pinned header = a "hard" scroll edge: one hairline, not a 2px rule. */
html:not([data-standalone]) th { border-bottom-width: 1px; padding-top: .7rem; padding-bottom: .7rem; }
html:not([data-standalone]) td { padding-top: .7rem; padding-bottom: .7rem; }

/* ---------- Controls ----------
   Desktop density, so macOS sizing: small buttons are fixed-radius rectangles, regular and
   large ones capsules. Fields are medium controls — fixed radius. */
html:not([data-standalone]) .btn { border-radius: 999px; padding-left: 1.3rem; padding-right: 1.3rem; }
html:not([data-standalone]) .btn-sm { border-radius: var(--radius-sm); padding-left: .8rem; padding-right: .8rem; }
html:not([data-standalone]) .btn-primary:hover:not(:disabled) { background: var(--accent-hover); box-shadow: none; }
/* Secondary = a grey-filled button, not an outline (no decoration). */
html:not([data-standalone]) .btn-secondary { background: var(--fill); border-color: transparent; color: var(--text); }
html:not([data-standalone]) .btn-secondary:hover:not(:disabled) { background: var(--fill-strong); border-color: transparent; }
/* A .btn with no variant (the filter / tab buttons on ~20 list pages) otherwise falls to the
   browser's own button face — light grey with black text, unreadable on the dark page. */
html:not([data-standalone]) .btn:not(.btn-primary, .btn-secondary, .btn-danger, .btn-success) { background: var(--fill); color: var(--text); }
html:not([data-standalone]) .btn:not(.btn-primary, .btn-secondary, .btn-danger, .btn-success):hover:not(:disabled) { background: var(--fill-strong); }
/* Large buttons keep their own width (the shop-floor action buttons). */
html:not([data-standalone]) .btn-lg { padding-left: 1.6rem; padding-right: 1.6rem; }
html:not([data-standalone]) .btn-xl { padding-left: 1.5rem; padding-right: 1.5rem; }
/* After the hover rules and as specific as them, so a hovered focused button keeps its ring. */
html:not([data-standalone]) .btn:focus-visible:not(:disabled) { outline: none; box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 35%, transparent); }

html:not([data-standalone]) .form-input,
html:not([data-standalone]) .form-textarea,
html:not([data-standalone]) .form-select,
html:not([data-standalone]) .combo-select-input,
html:not([data-standalone]) .filter-multi-btn,
html:not([data-standalone]) .input-group { border-color: var(--field-border); border-radius: var(--r-field); }
html:not([data-standalone]) .input-group .form-input { border-radius: 0; }
html:not([data-standalone]) .input-group-suffix { background: var(--fill); border-left-color: var(--field-border); }
html:not([data-standalone]) .form-input:focus,
html:not([data-standalone]) .form-select:focus,
html:not([data-standalone]) .form-textarea:focus,
html:not([data-standalone]) .combo-select-input:focus,
html:not([data-standalone]) .input-group:focus-within {
  border-color: var(--accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 22%, transparent);
}
/* Validation: the rules above out-rank style.css's `.error` states, so restate them. */
html:not([data-standalone]) :is(.form-input, .form-select, .input-group).error,
html:not([data-standalone]) .combo-select.error .combo-select-input { border-color: var(--red); }
html:not([data-standalone]) :is(.form-input, .form-select).error:focus,
html:not([data-standalone]) .input-group.error:focus-within,
html:not([data-standalone]) .combo-select.error .combo-select-input:focus {
  border-color: var(--red); box-shadow: 0 0 0 4px color-mix(in srgb, var(--red) 20%, transparent);
}
/* An input inside a group: the GROUP draws the ring, never the inner field. */
html:not([data-standalone]) .input-group .form-input:focus { box-shadow: none; }
html:not([data-standalone]) .form-group { gap: .4rem; }
html:not([data-standalone]) .badge-muted { background: var(--fill); }
html:not([data-standalone]) .alert { border-radius: 12px; }

/* ---------- Segmented controls: sub-tabs and the document detail tabs ----------
   A second-level choice is a track with a thumb, not an underline strip or a row of
   filled buttons. Thumb radius is concentric with the track (12 − 3 = 9). */
html:not([data-standalone]) .sub-tabs,
html:not([data-standalone]) .detail-tabs {
  width: fit-content; max-width: 100%; gap: 2px; padding: 3px;
  background: var(--fill); border: none; border-radius: 12px;
}
html:not([data-standalone]) .stab,
html:not([data-standalone]) .dtab {
  margin: 0; border: none; border-radius: 9px; background: transparent; color: var(--text-secondary);
}
html:not([data-standalone]) .stab:first-child,
html:not([data-standalone]) .stab:last-child { border-radius: 9px; }
html:not([data-standalone]) .stab:hover,
html:not([data-standalone]) .dtab:hover { color: var(--text); }
html:not([data-standalone]) .stab.active,
html:not([data-standalone]) .dtab.active {
  background: var(--card); color: var(--text); border: none;
  box-shadow: 0 1px 3px rgba(0,0,0,.12), 0 0 0 .5px rgba(0,0,0,.04);
}
html:not([data-standalone])[data-theme="dark"] .stab.active,
html:not([data-standalone])[data-theme="dark"] .dtab.active { background: #636366; }
/* In a filter bar the TRACK is the bar's control height, so the thumb sits inside it. */
html:not([data-standalone]) .filter-bar .sub-tabs { padding: 2px; }
html:not([data-standalone]) .filter-bar .stab { height: calc(var(--ctl-sm) - 4px); }
/* style.css whitens the count chip for an accent-filled segment; the thumb here is light. */
html:not([data-standalone]) .stab.active .stab-mark { background: var(--accent); }
/* Sub-tabs INSIDE a detail-tab panel (the PO / order Payment tab): two identical tracks
   stacked read as one broken control, so the second level drops the track and marks its
   choice with a plain fill — visibly subordinate (the rule style.css states for .sub-tabs). */
html:not([data-standalone]) .dtab-panel .sub-tabs { background: transparent; padding: 0; gap: .3rem; }
html:not([data-standalone]) .dtab-panel .stab.active { background: var(--fill); box-shadow: none; }

/* ---------- Modals: dimmed + blurred behind, large sheet in front ---------- */
html:not([data-standalone]) .overlay {
  background: rgba(0,0,0,.22);
  -webkit-backdrop-filter: blur(8px) saturate(120%); backdrop-filter: blur(8px) saturate(120%);
}
html:not([data-standalone])[data-theme="dark"] .overlay { background: rgba(0,0,0,.5); }
html:not([data-standalone]) .overlay.overlay-stacked { background: rgba(0,0,0,.1); -webkit-backdrop-filter: none; backdrop-filter: none; }
/* The full-screen sheet is opaque: blurring what it covers only costs the tablet GPU. */
html:not([data-standalone]) .overlay-full { background: rgba(0,0,0,.4); -webkit-backdrop-filter: none; backdrop-filter: none; }
html:not([data-standalone]) .modal { border-radius: var(--r-sheet); box-shadow: var(--shadow-lg), 0 0 0 .5px var(--glass-line); }
html:not([data-standalone]) .modal-full { border-radius: 0; }
html:not([data-standalone]) .modal-close { background: var(--fill); width: 30px; height: 30px; }
/* Sections stacked inside a sheet are white on white: a hairline, not a shadow, parts them. */
html:not([data-standalone]) .modal .card { border-color: var(--border); box-shadow: none; }
html:not([data-standalone]) .modal-close:hover { background: var(--fill-strong); }

/* ---------- Shop floor: a hairline header bar; tiles as grouped cards ----------
   The header is a flex sibling of the scrolling body, not over it — nothing passes beneath,
   so it is a solid bar, not glass. */
html:not([data-standalone]) .mf-header { border-bottom-color: var(--glass-line); }
html:not([data-standalone]) .mf-close { border-radius: 999px; border-color: transparent; background: var(--fill); }
html:not([data-standalone]) .tile { border-color: transparent; border-left-color: var(--fill-strong); border-radius: var(--radius-lg); }
html:not([data-standalone]) .tile.is-running,
html:not([data-standalone]) .tile.is-running:hover { border-left-color: var(--green); }
html:not([data-standalone]) .tile:hover { border-color: transparent; border-left-color: var(--fill-strong); }
html:not([data-standalone]) .tile.is-running:hover { border-left-color: var(--green); }
/* A card carrying a coloured stripe (inline border-left) keeps a tighter corner, or the
   20px radius bends the stripe into a crescent. */
html:not([data-standalone]) .card[style*="border-left"] { border-radius: var(--radius-sm); }

/* ---------- Sign in, request access, pending (on this design since 2026-10-09) ----------
   The card is a sheet, like a modal: the sheet radius and a hairline instead of a border. */
html:not([data-standalone]) .auth-card { border-radius: var(--r-sheet); box-shadow: var(--shadow-lg), 0 0 0 .5px var(--glass-line); }

/* ---------- Contract signing ---------- */
html:not([data-standalone]) .cs-header,
html:not([data-standalone]) .cs-footer { border-color: var(--glass-line); }
html:not([data-standalone]) .cs-content { border-radius: var(--radius-lg); }
html:not([data-standalone])[data-theme="dark"] .cs-canvas-wrap { background: #2c2c2e; }

/* ---------- Page rules that draw their own containers ---------- */
html:not([data-standalone]) .pi-group { border-color: transparent; box-shadow: var(--shadow-sm); }
html:not([data-standalone]) .sch-block.Pending { background: color-mix(in srgb, var(--accent) 8%, var(--card)); }
/* Demand sub-rows are tinted with --table-hover, which Glass makes near-invisible. */
html:not([data-standalone]) .mr-demand td { background: var(--surface-2); }

/* ============================================================
   Phone (≤768px): the top bar is a floating capsule with extra margin from the screen
   edge (WWDC25: "use a capsule with extra margin near the screen edge"); the menu opens
   as a sheet inset by the same margin.
   ============================================================ */
@media (max-width: 768px) {
  html:not([data-standalone]) { --topbar-h: 3.1rem; }
  html:not([data-standalone]) .mobile-topbar {
    top: calc(var(--inset) + env(safe-area-inset-top)); left: var(--inset); right: var(--inset);
    border-radius: 999px; padding: 0 .35rem 0 1.1rem;
    background: var(--glass); color: var(--text);
    -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
    border: .5px solid var(--glass-line);
    box-shadow: var(--shadow-md), inset 0 1px 0 var(--glass-edge);
  }
  html:not([data-standalone]) .mobile-topbar-page { color: var(--muted); }
  html:not([data-standalone]) .mobile-nav-btn { color: var(--accent); border-radius: 999px; }
  html:not([data-standalone]) .mobile-nav-btn:active { background: var(--fill); }
  html:not([data-standalone]) .sidebar {
    width: auto; inset: var(--inset); border-radius: var(--r-panel);
    background: var(--glass-strong);
  }
  /* The brand row is sticky (style.css), so it must be opaque enough that the menu scrolling
     under it does not show through the name and the close button. */
  html:not([data-standalone]) .sidebar-brand {
    padding: 0 .5rem 0 1.25rem; border-radius: var(--r-panel) var(--r-panel) 0 0;
    background: var(--glass-strong); -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  }
  /* Tap targets: 44px rows on the phone sheet (the desktop Glass paddings out-rank style.css's
     mobile ones, so they are restated here). */
  html:not([data-standalone]) .sidebar-link { min-height: 44px; padding-top: .6rem; padding-bottom: .6rem; }
  html:not([data-standalone]) .sidebar-section,
  html:not([data-standalone]) .sidebar-group.collapsed .sidebar-section { min-height: 44px; padding-top: .75rem; padding-bottom: .75rem; }
  /* Document tabs scroll sideways on a phone rather than folding into a multi-row block. */
  html:not([data-standalone]) .detail-tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  html:not([data-standalone]) .dtab { flex: 0 0 auto; white-space: nowrap; }
  html:not([data-standalone]) .main-content {
    margin-left: 0;
    padding: calc(var(--topbar-h) + 2 * var(--inset) + .75rem) 1rem 1.5rem;
  }
  html:not([data-standalone]) .toast-container { top: calc(var(--topbar-h) + 2 * var(--inset)); left: var(--inset); right: var(--inset); }
}

/* ---------- Accessibility: Reduce Transparency / Increase Contrast ---------- */
/* Both selectors in each block: the dark token block above is more specific than the light
   one, so a light-only override would lose in dark mode. */
@media (prefers-reduced-transparency: reduce) {
  html:not([data-standalone]), html:not([data-standalone])[data-theme="dark"] { --glass: var(--card); --glass-strong: var(--card); }
}
@media (prefers-contrast: more) {
  html:not([data-standalone]), html:not([data-standalone])[data-theme="dark"] {
    --glass: var(--card); --glass-strong: var(--card); --glass-line: var(--text);
    --border: var(--muted); --card-line: var(--muted);
  }
}

/* ============================================================
   PUBLIC SITE — the pages a visitor sees before signing in: index.html and 404.html.

   Two things live here: the ERP's own pre-sign-in pages (index.html, 404.html) and the
   product website (site/*.html, served at zersync.com — home, product, pricing, security,
   contact; MDs/public-site-design.md §4). All of them load this file and use the app's
   components (.btn, .hairline, .theme-toggle); what is below is only what the app has no
   equivalent for. Scoped .site — the <body> class of every public page — because the names
   are generic. Type is the app's ramp; the hero headline (.display) sits outside it, as the
   shop-floor display numerals do.
   ============================================================ */
/* Before sign-in the product speaks, not a tenant: the accent is the ZERSYNC orange, pinned
   here as a literal, never the company accent_color — config.js writes that onto <html> on
   the auth pages; declaring the token on <body> outranks it for everything inside. Same in
   both themes (it reads as fill AND as text on light and dark). --accent-bg is re-derived
   because the :root one was computed from the company colour. */
:is(.site, .auth-page) {
  --accent: #ff6b35; --accent-hover: #e85a28;
  --accent-bg: color-mix(in srgb, var(--accent) 8%, transparent);
}
.site .page { max-width: 1120px; margin: 0 auto; padding: 0 1.5rem; }
.site .display { font-size: clamp(2.4rem, 5.4vw, 3.6rem); font-weight: 700; line-height: 1.05; letter-spacing: -0.035em; }
.site .lede { font-size: var(--fs-lg); line-height: 1.55; color: var(--text-secondary); }

/* --- Header (404.html): a floating glass capsule, inset from the window like the phone top bar --- */
.site .page-head {
  position: sticky; top: var(--inset); z-index: 100;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin-top: var(--inset); padding: .4rem .4rem .4rem 1.25rem; border-radius: 999px;
  background: var(--glass); -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  border: .5px solid var(--glass-line); box-shadow: var(--shadow-md), inset 0 1px 0 var(--glass-edge);
}
/* The capsule gets out of the way going down the page and comes back going up (site.js sets
   .head-away; never while the phone menu is open). */
.site .page-head { transition: transform .3s ease, opacity .3s ease; }
.site .page-head.head-away:not(.nav-open) { transform: translateY(calc(-100% - var(--inset) - 1rem)); opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .site .page-head { transition: none; } }
/* Concentric: a button inside the capsule is a capsule too. */
.site .page-head .btn { border-radius: 999px; }
.site .wordmark { font-size: var(--fs-lg); color: var(--text); }
.site .wordmark:hover { color: var(--text); }
/* The running dog, before the name in the capsule (same mask recipe as .landing-mark, in the
   name's own colour). On the product site only — the markup is in site/*.html. Dropped at
   phone width: with it the capsule is ~360px of content and the theme toggle spills out of
   a 375px screen. */
.site .page-head .wordmark { display: inline-flex; align-items: center; gap: .55rem; }
.site .nav-dog {
  width: 36px; flex: none; aspect-ratio: 756 / 478; background: currentColor;
  -webkit-mask: url(../intro-assets/zerapps_logo.svg) 47.76% 48.72% / 135.45% auto no-repeat;
          mask: url(../intro-assets/zerapps_logo.svg) 47.76% 48.72% / 135.45% auto no-repeat;
}
@media (max-width: 480px) { .site .nav-dog { display: none; } }
.site .site-tools { display: flex; align-items: center; gap: .6rem; }

/* --- Landing (index.html) --- */
.site .landing { min-height: 100vh; display: flex; flex-direction: column; justify-content: center; padding: 5rem 0; }
/* The name and, opposite it, the same language + theme toggles as the 404 header. */
.site .landing-top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 3rem; }
.site .wordmark-lg { font-size: var(--fs-2xl); }
.site .landing .display { max-width: 20ch; margin-bottom: 1rem; }
.site .landing .lede { max-width: 54ch; margin-bottom: 3rem; }
.site .landing .hairline { max-width: 560px; margin-bottom: 3rem; }
/* The right half: the running dog in the text colour (same mask recipe and same size as
   .nf-mark below — a mark, not a poster; 460px was too big). Logo-led on purpose — no
   invented illustration. Dropped under 900px, where the copy needs the full width. */
.site .landing-hero { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 3rem; }
.site .landing-mark {
  width: clamp(176px, 20vw, 248px); justify-self: end; aspect-ratio: 756 / 478; background: var(--text);
  -webkit-mask: url(../intro-assets/zerapps_logo.svg) 47.76% 48.72% / 135.45% auto no-repeat;
          mask: url(../intro-assets/zerapps_logo.svg) 47.76% 48.72% / 135.45% auto no-repeat;
  animation: nf-in .9s .15s cubic-bezier(.2, .7, .2, 1) both;
}
@media (max-width: 900px) {
  .site .landing-hero { grid-template-columns: 1fr; }
  .site .landing-mark { display: none; }
}

/* --- Not found (404.html): the logo, the type, the white space — nothing invented ---
   The logo is painted through a mask so it takes var(--text) in both themes (the file is ink
   on transparent). The numbers crop the 1024-unit artboard to the drawing (x 128, y 266,
   756 × 478). The url is relative to THIS file, so it resolves at any depth the 404 is served. */
.site .nf { min-height: 100vh; display: flex; flex-direction: column; }
.site .nf-main { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 4rem 0; }
.site .nf-mark {
  width: clamp(176px, 20vw, 248px); aspect-ratio: 756 / 478; margin-bottom: 3rem; background: var(--text);
  -webkit-mask: url(../intro-assets/zerapps_logo.svg) 47.76% 48.72% / 135.45% auto no-repeat;
          mask: url(../intro-assets/zerapps_logo.svg) 47.76% 48.72% / 135.45% auto no-repeat;
}
.site .nf-main .display { margin-bottom: 1rem; }
.site .nf-main .lede { max-width: 42ch; }
.site .nf-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: .75rem; margin-top: 2rem; }
.site .nf-foot { display: flex; justify-content: space-between; gap: 1.5rem; padding: 1.1rem 0 1.5rem; border-top: 1px solid var(--border); font-size: var(--fs-sm); color: var(--muted); }
.site .nf-foot span:last-child { color: var(--text); text-align: right; overflow-wrap: anywhere; }
.site .nf-main > * { animation: nf-in .7s cubic-bezier(.2, .7, .2, 1) both; }
.site .nf-main > :nth-child(2) { animation-delay: .08s; }
.site .nf-main > :nth-child(3) { animation-delay: .14s; }
.site .nf-main > :nth-child(4) { animation-delay: .2s; }
@keyframes nf-in { from { opacity: 0; transform: translateY(8px); } }
@media (prefers-reduced-motion: reduce) { .site :is(.nf-main > *, .landing-mark) { animation: none; } }
/* Enter system + Learn more side by side (index.html, 2026-10-13). */
.site .landing-actions { display: flex; flex-wrap: wrap; gap: .75rem; }

/* --- The product site (site/*.html, served at zersync.com — MDs/public-site-design.md §4) ---
   Every page: the same header capsule as the 404 with the page links in it, a hero (the home
   page's has the dog; an inner page's is the headline and lede alone), then sections that are
   rows and tables (tables-not-pills): a module per row, a plan per row, a document per row.
   The form uses the app's form-group / form-input / alert; the Turnstile widget sits in its
   own row. */
/* The section links, inside the capsule: the site is ONE long page and these scroll it. The
   section on screen is marked aria-current by site/site.js, which is also what styles it. */
html:has(.saas) { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html:has(.saas) { scroll-behavior: auto; } }
.site .site-nav { display: flex; align-items: center; gap: .15rem; margin-right: auto; }
.site .site-nav a { padding: .35rem .8rem; border-radius: 999px; font-size: var(--fs-sm); font-weight: 500; color: var(--text-secondary); white-space: nowrap; }
.site .site-nav a:hover { color: var(--text); }
.site .site-nav a[aria-current] { color: var(--text); background: color-mix(in srgb, var(--text) 7%, transparent); }
/* Sign in is a button in the tools on a desk and a line of the menu on a phone; Menu is the
   reverse. Both exist in the markup so neither needs script to be reachable. */
.site .site-nav .nav-signin, .site .nav-btn { display: none; }
/* The intro (hero + the strip under it) is wider than the column the sections read in: it
   reaches up to 80px into each side margin when the window has them, and not at all once the
   column fills the window (owner, 2026-10-13). */
.site .saas { --intro-out: clamp(0px, (100vw - 1120px) / 2 - 1.5rem, 80px); }
.site .saas :is(.hero, .strip) { margin-inline: calc(-1 * var(--intro-out)); }
/* The hero is the tallest thing on the page — it nearly fills the first screen — so the three
   statements under it start the second screen with room around them. The room is white space:
   the type and the screenshot are only a touch larger than elsewhere (owner, 2026-10-13). */
.site .saas .hero { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4rem; min-height: min(86vh, 860px); padding: 6rem 0 5rem; }
.site .saas .hero .display { max-width: 18ch; margin-bottom: 1.25rem; font-size: clamp(2.4rem, 5.4vw, 3.8rem); }
.site .saas .hero .lede { max-width: 54ch; margin-bottom: 2.5rem; font-size: 1.15rem; }
.site .hero-actions { display: flex; flex-wrap: wrap; gap: .75rem; }
.site .sec { padding: 3rem 0; border-top: 1px solid var(--border); }
.site .sec h2 { font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.02em; margin: 0 0 .5rem; }
.site .sec > .lede { margin-bottom: 1.5rem; max-width: 64ch; }
.site .notice { padding: 1.1rem 1.35rem; border: 1px solid var(--border); border-radius: 14px; background: color-mix(in srgb, var(--text) 4%, transparent); margin-bottom: 1.75rem; }
.site .notice p { margin: 0; }
.site .notice p + p { margin-top: .5rem; }
.site .notice-sub { color: var(--text-secondary); font-size: var(--fs-sm); }
/* The privacy page (site/legal.html) — the one page of running text on the site, so the one
   place that needs a reading measure and paragraph spacing; everything else is the shared .sec. */
.site .legal main { max-width: 68ch; padding-bottom: 3rem; }
.site .legal-head { padding: 4rem 0 2.5rem; }
.site .legal-head .display { margin-bottom: 1rem; }
.site .legal-head .lede { margin-bottom: .75rem; }
.site .legal .sec { padding: 2rem 0; }
.site .legal .sec h3 { font-size: var(--fs-md); font-weight: 600; margin: 1.25rem 0 .35rem; }
.site .legal .sec p { margin: 0 0 .75rem; line-height: 1.6; color: var(--text-secondary); }
.site .legal-back { margin: 1rem 0 0; }
.site .ask-legal { margin: .75rem 0 0; }
/* The first-visit cookie note: the header capsule's material, pinned to the bottom edge. */
.site .cookie-note {
  position: fixed; left: 50%; bottom: var(--inset); transform: translateX(-50%); z-index: 90;
  display: flex; align-items: center; gap: 1rem; width: max-content; max-width: calc(100vw - 2rem);
  padding: .45rem .45rem .45rem 1.25rem; border-radius: 999px; font-size: var(--fs-sm);
  background: var(--glass); -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  border: .5px solid var(--glass-line); box-shadow: var(--shadow-md), inset 0 1px 0 var(--glass-edge);
}
.site .cookie-note p { margin: 0; }
.site .cookie-note a { text-decoration: underline; white-space: nowrap; }
.site .cookie-note .btn { border-radius: 999px; flex: none; }
@media (max-width: 520px) { .site .cookie-note { border-radius: 18px; padding: .7rem .7rem .7rem 1rem; } }
/* The contact section (owner, 2026-10-13: "clean and glass … step by step … moving and
   pressing questions"): the notice on the left, and on the right ONE glass card that asks a
   question at a time — the first ones answered by pressing an option, then the details, then
   the message. It reuses the plan finder's question, option and footer rules. The running dog
   stands still behind the card's top edge (owner: "keep the dog not moving") so the glass has
   something to blur; nothing invented.
   Without script every step is simply listed. */
.site .ask-wrap { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 520px); gap: 2rem 3.5rem; align-items: start; padding-top: 2.5rem; }
.site .ask-intro .lede { margin: 0 0 1rem; max-width: 46ch; }
.site .ask-intro p { max-width: 46ch; }
.site .ask-stage { position: relative; }
.site .ask-stage::before {
  content: ""; position: absolute; top: -3.1rem; right: 2rem; width: 170px; aspect-ratio: 756 / 478; background: var(--navy);
  -webkit-mask: url(../intro-assets/zerapps_logo.svg) 47.76% 48.72% / 135.45% auto no-repeat;
          mask: url(../intro-assets/zerapps_logo.svg) 47.76% 48.72% / 135.45% auto no-repeat;
}
.site .ask {
  position: relative; padding: 1.75rem; border-radius: 28px;
  background: var(--glass); -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  border: .5px solid var(--glass-line); box-shadow: var(--shadow-lg), inset 0 1px 0 var(--glass-edge);
}
/* The steps of the path, numbered: done filled, current ringed. */
.site .ask-rail { list-style: none; display: flex; align-items: center; gap: 1.75rem; margin: 0; padding: 0; }
.site .ask-rail li { position: relative; display: flex; align-items: center; justify-content: center; width: 1.75rem; height: 1.75rem; border-radius: 50%; font-size: var(--fs-sm); font-weight: 700; color: var(--muted); background: color-mix(in srgb, var(--text) 7%, transparent); }
.site .ask-rail li + li::before { content: ""; position: absolute; right: calc(100% + .35rem); width: 1.05rem; height: 2px; border-radius: 2px; background: color-mix(in srgb, var(--text) 12%, transparent); }
.site .ask-rail li.done { background: var(--navy); color: var(--card); }
.site .ask-rail li.done + li::before { background: var(--navy); }
.site .ask-rail li.on { background: var(--card); color: var(--text); box-shadow: 0 0 0 2px var(--navy); }
.site .ask-steps { min-height: 22.5rem; }
.js .site .ask-step:not(.on) { display: none; }
html:not(.js) .site .ask-step + .ask-step { margin-top: 1.75rem; }
/* A step slides in from the side it was reached from, and its options arrive one after another. */
.js .site .ask-step.on { animation: ask-in .38s cubic-bezier(.2, .7, .2, 1) both; }
.js .site .ask.back .ask-step.on { animation-name: ask-back; }
.js .site .ask-step.on .ask-opt { animation: dept-in .4s cubic-bezier(.2, .7, .2, 1) both; animation-delay: calc(80ms + var(--n, 0) * 55ms); }
@keyframes ask-in { from { opacity: 0; transform: translateX(26px); } }
@keyframes ask-back { from { opacity: 0; transform: translateX(-26px); } }
.site .ask-opt { display: flex; flex-direction: column; gap: .15rem; width: 100%; }
.site .ask-opt strong { font-weight: 600; }
.site .ask-opt span { font-size: var(--fs-sm); color: var(--text-secondary); }
.site .ask-opt.on span { color: inherit; }
.site .ask-opt:active { transform: scale(.98); }
.site .ask-fields { display: grid; grid-template-columns: 1fr 1fr; gap: .9rem 1rem; }
.site .ask .form-group { margin: 0; }
.site .ask .form-hint { display: block; margin-top: .35rem; font-size: var(--fs-sm); color: var(--muted); }
.site .ask-turnstile { margin-top: 1rem; min-height: 65px; }
.site .ask .alert { margin-top: 1rem; }
/* The step's heading and hint follow what was pressed first (data-kind, set by site.js). */
.site .ask:not([data-kind="question"]) .for-question, .site .ask:not([data-kind="support"]) .for-support,
.site .ask:is([data-kind="question"], [data-kind="support"]) .for-access { display: none; }
.site .ask-done { text-align: center; padding: 3.5rem 0 1rem; }
.site .ask-done .ico { border-radius: 50%; width: 3.4rem; height: 3.4rem; margin-bottom: 1.1rem; }
.site .ask-done .ico .i { width: 1.6rem; height: 1.6rem; }
.site .ask-done p { margin: 0 0 1.5rem; color: var(--text-secondary); }
.site .ask-done .btn { border-radius: 999px; }
@media (prefers-reduced-motion: reduce) {
  .js .site .ask-step.on, .js .site .ask-step.on .ask-opt { animation: none; }
}
/* The honeypot: off-screen, never display:none (a filler reads display:none as "skip"). */
.site .hp { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.site .site-foot { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem 1.5rem; padding: 1.25rem 0 2rem; border-top: 1px solid var(--border); font-size: var(--fs-sm); color: var(--muted); }
.site .site-foot .wordmark { font-size: var(--fs-md); }
/* The dog again, sitting beside the name in the footer (the running one is in the header
   capsule — .nav-dog). The sitting one is a raster (intro-assets/zerapps_sitting_logo.png, black on
   transparent) cropped to the drawing, so dark mode inverts it rather than masking it. */
.site .foot-brand { display: inline-flex; align-items: flex-end; gap: .6rem; }
.site .sit-dog { width: 34px; height: 36px; flex: none; background: url(../intro-assets/zerapps_sitting_logo.png) -29px -10px / 96px auto no-repeat; }
[data-theme="dark"] .site .sit-dog { filter: invert(1); }
.site .sec-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 2rem; margin-bottom: 1.5rem; }
.site .sec-head .lede { margin-bottom: 0; max-width: 64ch; }
.site .foot-nav { display: flex; flex-wrap: wrap; gap: .35rem 1.25rem; }
.site .foot-nav a { color: var(--text-secondary); }
.site .foot-legal { flex: 0 0 100%; margin: 0; padding-top: .9rem; border-top: 1px solid var(--border); font-size: var(--fs-xs); }
.site .foot-legal a { color: var(--muted); }
/* The small print under the plans. */
/* No width cap: a note that fits the column on one line stays on one line (owner, 2026-10-13:
   "do not bend text like this"); it wraps only where the column itself ends. */
.site .table-note { margin: .9rem 0 0; font-size: var(--fs-sm); color: var(--muted); }
.site .table-note + .notice { margin-top: 1.75rem; }
/* ---- Colour, icons, previews, price cards (owner, 2026-10-13: "much nicer price cards like
   most SaaS apps … a little more colour … graphs … icons") ----
   The one place cards are the right shape and tables-not-pills is set aside: three plans a
   visitor compares side by side. Everything else on the site stays rows and tables. No
   library: the site's CSP allows no third-party script, and none of this needs one. */
/* A module's hue. Literal here and nowhere else — these are the website's, not the app's
   status colours, and must read the same on white and on black. */
/* ORANGE IS FOR ONE OR TWO BUTTONS (owner, 2026-10-13). On the website the accent paints the
   primary buttons and the answer just picked in the plan finder — nothing else. Every other
   emphasis (links, the leading card, the suggested plan) is --navy: the document navy on
   light, a pale slate on dark, where navy itself would sink into the page. */
.site { --navy: #1f2f47; }
[data-theme="dark"] .site { --navy: #a9bbd6; }
.site .saas a:not(.btn) { color: var(--navy); }
.site .saas a:not(.btn):hover { color: var(--text); }
.site .saas .wordmark, .site .saas .site-nav a { color: inherit; }
.site { --h-sales: var(--navy); --h-purchasing: #3b82f6; --h-production: #8b5cf6; --h-warehouse: #0d9488; --h-accounts: #22a565; --h-hr: #ec4899; --h-bookings: #f59e0b; }
.site .h-sales { --h: var(--h-sales); } .site .h-purchasing { --h: var(--h-purchasing); } .site .h-production { --h: var(--h-production); }
.site .h-warehouse { --h: var(--h-warehouse); } .site .h-accounts { --h: var(--h-accounts); } .site .h-hr { --h: var(--h-hr); } .site .h-bookings { --h: var(--h-bookings); }
.site .i { width: 1.25rem; height: 1.25rem; flex: none; }
/* Feature tiles: a coloured icon, a name, a line (modules; how it works). */
.site .feats { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 1rem; margin-bottom: 1.5rem; }
.site .feats-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.site .feat { padding: 1.35rem; border: 1px solid var(--border); border-radius: 18px; background: var(--card); transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease; }
.site .feat:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: color-mix(in srgb, var(--text) 18%, transparent); }
.site .feat h3 { margin: .9rem 0 .35rem; font-size: var(--fs-base); font-weight: 700; }
.site .feat p { margin: 0; font-size: var(--fs-md); line-height: 1.5; color: var(--text-secondary); }
.site .ico { display: inline-flex; align-items: center; justify-content: center; width: 2.6rem; height: 2.6rem; border-radius: 12px; color: var(--h); background: color-mix(in srgb, var(--h) 14%, transparent); }
/* A screen preview: a window frame around a drawn chart. Sample figures, and the caption says
   so — these are illustrations of the screens, not photographs of a company's data. */
.site .shot { margin: 0; border: 1px solid var(--border); border-radius: 18px; background: var(--card); box-shadow: var(--shadow-md); overflow: hidden; }
.site .shot-bar { display: flex; align-items: center; gap: .4rem; padding: .7rem .9rem; border-bottom: 1px solid var(--border); font-size: var(--fs-sm); font-weight: 600; color: var(--text-secondary); }
.site .shot-bar i { width: .6rem; height: .6rem; border-radius: 50%; background: var(--border); }
.site .shot-bar i:nth-child(1) { background: #ff5f57; } .site .shot-bar i:nth-child(2) { background: #febc2e; } .site .shot-bar i:nth-child(3) { background: #28c840; }
.site .shot-bar span { margin-left: .5rem; }
.site .shot > img { display: block; width: 100%; height: auto; }
.site .shot svg { display: block; width: 100%; height: auto; padding: .5rem; font-family: inherit; }
.site .shot figcaption { padding: .55rem .9rem .7rem; border-top: 1px solid var(--border); font-size: var(--fs-xs); color: var(--muted); }
.site .shot .t { font-size: 11px; fill: var(--muted); }
.site .shot .k { font-size: 13px; font-weight: 700; fill: var(--text); }
.site .shot .g { stroke: var(--border); stroke-width: 1; }
.site .shot .in { fill: var(--h-accounts); } .site .shot .out { fill: var(--navy); }
.site .shot .ln { fill: none; stroke: var(--h-purchasing); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.site .shot .dot { fill: var(--card); stroke: var(--h-purchasing); stroke-width: 2.5; }
.site .shot .lane { fill: color-mix(in srgb, var(--text) 5%, transparent); }
.site .shot .blk.a { fill: var(--h-sales); } .site .shot .blk.b { fill: var(--h-purchasing); } .site .shot .blk.c { fill: var(--h-production); } .site .shot .blk.d { fill: var(--h-warehouse); }
.site .shot .now { stroke: var(--text); stroke-width: 1.5; stroke-dasharray: 4 4; opacity: .55; }
.site .shot .free { fill: color-mix(in srgb, var(--h-warehouse) 28%, transparent); } .site .shot .res { fill: var(--h-warehouse); }
.site .hero-shot { width: min(660px, 47vw); }
/* The hero's screens are a stack of windows: the front one square to the page, the next
   three fanned out behind it from the bottom-left corner — each a step up and to the right and a
   degree and a half further round, like a hand of cards. The stack keeps its right-hand room
   as padding, so the fan never leaves the column (--fan scales it down on a phone). All share
   one grid cell, so the stack is exactly as tall as one window. A click on a window behind
   brings it to the front, a click on the front one deals the next (site.js); z-index changes
   part-way through the move, so a window passes the others instead of jumping. */
.site .deck { --fan: 1; display: grid; width: min(800px, 55vw); padding: calc(66px * var(--fan)) calc(64px * var(--fan)) 0 0; }
.site .deck .shot { --n: 0; grid-area: 1 / 1; z-index: calc(4 - var(--n)); transform-origin: 0 100%; transform: translate(calc(10px * var(--n) * var(--fan)), calc(-22px * var(--n) * var(--fan))) rotate(calc(1.5deg * var(--n) * var(--fan))); transition: transform .6s cubic-bezier(.2, .7, .2, 1), opacity .4s ease, z-index 0s .22s, box-shadow .3s ease; }
.site .deck .shot[data-pos="1"] { --n: 1; }
.site .deck .shot[data-pos="2"] { --n: 2; }
.site .deck .shot[data-pos="3"] { --n: 3; }
/* Only three windows show behind the front one. The rest of the stack waits unseen in the
   last place, so a window fades in there on its way forward and out there on its way back. */
.site .deck .shot:is([data-pos="4"], [data-pos="5"], [data-pos="6"], [data-pos="7"]) { --n: 3; z-index: 0; opacity: 0; pointer-events: none; }
.site .deck .shot:not([data-pos="0"]) { box-shadow: var(--shadow-sm); }
.js .site .deck .shot { cursor: pointer; }
.site .deck:focus-visible { outline: 2px solid var(--navy); outline-offset: 6px; border-radius: 18px; }
@media (prefers-reduced-motion: reduce) { .site .deck .shot { transition: none; } }
.site .shots { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; }
/* Bars and blocks grow in when the preview scrolls into view (.in comes from site.js). */
.js .site .shot:not(.in) :is(.b, .hb, .blk) { transform: scale(0); }
.site .shot .b { transform-box: fill-box; transform-origin: bottom; transition: transform .7s cubic-bezier(.2, .7, .2, 1); }
.site .shot :is(.hb, .blk) { transform-box: fill-box; transform-origin: left; transition: transform .7s cubic-bezier(.2, .7, .2, 1); }
/* Sections' pieces rise in once. Hidden only when script is running (html.js, set by
   first-paint.js), so a page without script is simply all there. */
.js .site .reveal { opacity: 0; transform: translateY(14px); }
.js .site .reveal.in { opacity: 1; transform: none; transition: opacity .6s ease, transform .6s cubic-bezier(.2, .7, .2, 1), box-shadow .2s ease, border-color .2s ease; }
@media (prefers-reduced-motion: reduce) {
  .js .site .reveal, .js .site .shot:not(.in) :is(.b, .hb, .blk) { opacity: 1; transform: none; }
  .site .shot :is(.b, .hb, .blk), .site :is(.feat, .plan) { transition: none; }
}
/* Three things worth knowing before the first section, under the hero: three statements in
   type and white space, nothing else. No icons — a tinted icon tile beside each made it read
   as a stock template — and no rules either: hairlines round and between small type made it a
   boxed table cell row (owner, 2026-10-13, twice). The first section's top border closes it.
   The space around the row does the work; the titles are one step up from a section title. */
.site .strip { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4rem; padding: 2.5rem 0 6.5rem; text-align: center; }
.site .strip .i { display: block; width: 1.9rem; height: 1.9rem; margin: 0 auto 1rem; color: var(--text-secondary); }
.site .strip strong { display: block; font-size: var(--fs-2xl); font-weight: 700; line-height: 1.2; letter-spacing: -0.02em; }
.site .strip span { display: block; margin-top: .55rem; text-wrap: balance; font-size: var(--fs-base); line-height: 1.5; color: var(--text-secondary); }
/* The department explorer: a department per tab on the left; pointing at one (or tapping it)
   shows everything it does on the right, in its hue (a colour edge only ever goes all the way
   round a box — never one side or one corner), the items arriving one after another.
   Without script every panel is simply listed. */
.site .depts { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 1.25rem; align-items: start; }
.site .dept-tabs { display: grid; gap: .35rem; }
.site .dept-panels { margin-top: .75rem; }
.site .dept-tab { display: flex; align-items: center; gap: .8rem; width: 100%; padding: .6rem .75rem; border: 1px solid transparent; border-radius: 14px; background: none; font: inherit; font-size: var(--fs-base); font-weight: 600; color: var(--text-secondary); text-align: left; cursor: pointer; transition: background .15s ease, color .15s ease; }
.site .dept-tab .ico { width: 2.3rem; height: 2.3rem; border-radius: 10px; transition: background .15s ease, color .15s ease; }
.site .dept-tab.on { background: var(--card); border-color: var(--border); color: var(--text); box-shadow: var(--shadow-md); }
.site .dept-tab.on .ico { background: var(--h); color: var(--card); }
.site .dept-panel { padding: 1.75rem 2rem 2rem; border: 1px solid var(--border); border-radius: 22px; background: var(--card); }
/* Every panel sits in the same cell, so the cell is always as tall as the longest department
   and switching never moves the page below it; the ones not chosen are only hidden. Each box
   is top-aligned at its own height: the top never moves, the bottom follows the list. */
.js .site .dept-panels { display: grid; align-items: start; }
.js .site .dept-panel { grid-area: 1 / 1; margin: 0; }
.js .site .dept-panel:not(.on) { visibility: hidden; }
/* Without JS the panels stack down the page and need a gap; with it they overlap, and that gap
   would drop every panel but the first 1rem below it. */
html:not(.js) .site .dept-panel + .dept-panel { margin-top: 1rem; }
.site .dept-panel h3 { margin: 0 0 .4rem; font-size: var(--fs-2xl); font-weight: 700; letter-spacing: -0.02em; }
.site .dept-panel > p { margin: 0 0 1.5rem; max-width: 62ch; color: var(--text-secondary); line-height: 1.5; }
.site .dept-panel ul { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .6rem 1.5rem; }
.site .dept-panel li { display: flex; align-items: flex-start; gap: .65rem; padding: .7rem .9rem; border-radius: 12px; background: color-mix(in srgb, var(--h) 7%, transparent); font-size: var(--fs-md); font-weight: 500; line-height: 1.35; }
.site .dept-panel li .i { width: 1.1rem; height: 1.1rem; margin-top: .1rem; color: var(--h); }
.js .site .dept-panel.on li { animation: dept-in .35s cubic-bezier(.2, .7, .2, 1) both; animation-delay: calc(var(--n, 0) * 28ms); }
@keyframes dept-in { from { opacity: 0; transform: translateY(8px); } }
@media (prefers-reduced-motion: reduce) { .js .site .dept-panel.on li { animation: none; } }
/* The gallery: the real screens and the real printed pages (site/shots/*.png, invented
   company; a document has one image per language) as one row that runs the full width of
   the window and slides sideways. The one in the middle is lit, the rest stand back; a click
   on it opens the viewer, which leaves by its X. site.js moves it (arrows, the Screens /
   Documents switch, drag, a slow advance with a pause button); without script it is a plain
   sideways scroller with every caption shown. A slide is a tenth shorter than its image and
   shows it from the top at full width; the viewer shows the whole of it. */
.site .gal { --gh: clamp(280px, 58vh, 680px); width: 100vw; margin: 2rem 0 0 calc(50% - 50vw); }
body.site:has(.gal) { overflow-x: clip; }
.site .gal-track { position: relative; display: flex; align-items: center; gap: clamp(1rem, 3vw, 2.5rem); padding: 1.5rem 0 5.5rem; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scrollbar-width: none; cursor: grab; }
.site .gal-track::-webkit-scrollbar { display: none; }
.site .gal-track::before, .site .gal-track::after { content: ''; flex: none; width: 50vw; }
.site .gal-track.drag { scroll-snap-type: none; cursor: grabbing; }
.site .gal-slide { position: relative; flex: none; margin: 0; scroll-snap-align: center; transition: opacity .45s ease, transform .45s cubic-bezier(.2, .7, .2, 1); }
.site .gal-slide.wide { width: min(92vw, calc(var(--gh) * 1.6)); aspect-ratio: 1440 / 810; }
.site .gal-slide.tall { width: min(78vw, calc(var(--gh) * .7067)); aspect-ratio: 1270 / 1617; }
.site .gal-slide.land { width: min(92vw, calc(var(--gh) * 1.415)); aspect-ratio: 1797 / 1143; }
.js .site .gal-slide:not(.on) { opacity: .4; transform: scale(.9); }
.site .gal-open { display: block; width: 100%; height: 100%; padding: 0; border: 1px solid var(--border); border-radius: 14px; background: #fff; overflow: hidden; box-shadow: var(--shadow-md); cursor: inherit; transition: box-shadow .45s ease; }
.site .gal-slide.on .gal-open { box-shadow: 0 30px 70px rgba(0, 0, 0, .18); cursor: zoom-in; }
.site .gal-open img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top; pointer-events: none; user-select: none; }
.site .gal-slide figcaption { position: absolute; top: calc(100% + 1rem); left: 50%; width: max-content; max-width: min(86vw, 40rem); transform: translateX(-50%); text-align: center; transition: opacity .3s ease; }
.js .site .gal-slide:not(.on) figcaption { opacity: 0; }
.site .gal-slide strong { display: block; font-size: var(--fs-base); }
.site .gal-slide figcaption span { display: block; font-size: var(--fs-md); color: var(--text-secondary); }
.site .gal-bar { display: none; align-items: center; justify-content: center; flex-wrap: wrap; gap: .75rem; padding: 0 1.5rem; }
.js .site .gal-bar { display: flex; }
.site .gal-bar .bill-switch { margin-bottom: 0; }
.site .gal-nav { display: inline-flex; align-items: center; justify-content: center; width: 2.75rem; height: 2.75rem; padding: 0; border: 1px solid var(--border); border-radius: 50%; background: var(--card); color: var(--text); cursor: pointer; transition: background .15s ease; }
.site .gal-nav:hover { background: color-mix(in srgb, var(--text) 6%, var(--card)); }
.site .gal-play.on .ic-play, .site .gal-play:not(.on) .ic-pause { display: none; }
.site .gal-count { min-width: 4.5rem; text-align: center; font-size: var(--fs-md); font-variant-numeric: tabular-nums; color: var(--text-secondary); }
@media (prefers-reduced-motion: reduce) { .site .gal-slide, .site .gal-open, .site .gal-slide figcaption { transition: none; } }
/* The viewer: a screen (or a landscape sheet) gets the width of the window, a portrait page
   the width it reads at. */
.site .viewer { max-width: 1560px; width: 96%; max-height: 94vh; }
.site .viewer.tall { max-width: 900px; }
.site .viewer img { display: block; width: 100%; height: auto; border: 1px solid var(--border); border-radius: 8px; background: #fff; }
/* The band: the ONE section that leaves the column. Every other section starts on the same
   left edge under a hairline, and a page of those reads as a list (owner, 2026-10-13: "we need
   a section to break the rails"). This one is a flat navy field the full width of the window,
   its heading centred and a step larger, its rows reaching into the margins as the hero does.
   The field is painted by a spread shadow clipped to the section's own height, so nothing is
   moved and nothing overflows. Inside it the tokens are re-declared, so whatever sits in it
   inverts without a rule of its own. Since 2026-10-14 the band is the gallery ("What the day
   looks like") — the owner dropped "Who it is for" as a placeholder and gave its field to the
   screens, as the cinematic section. On dark the page is
   already dark, so the field is a lifted tone of it instead. Flat colour, no gradient. */
.site .sec.band {
  --bg: #1f2f47; --card: #2d405f; --text: #fff; --text-secondary: rgba(255, 255, 255, .74); --muted: rgba(255, 255, 255, .56); --border: rgba(255, 255, 255, .24);
  margin-inline: calc(-1 * var(--intro-out)); padding: 5.5rem 0 6rem; border-top: 0; text-align: center;
  color: var(--text); background: var(--bg); box-shadow: 0 0 0 100vmax var(--bg); clip-path: inset(0 -100vmax);
}
[data-theme="dark"] .site .sec.band { --bg: #1b2434; --card: #2a364b; --text: #f2f4f8; }
.site .sec.band + .sec { border-top: 0; }
/* The field: Pricing on the same flat navy, the full width of the window (owner, 2026-10-14 —
   the gallery was tried as the navy section and sent back: "I much prefer that being white").
   Unlike .band the tokens are NOT re-declared on the section: the price cards stay the page's
   own white cards, and only what sits directly on the navy (heading, lede, switch, notes)
   inverts. */
.site .sec.field { --field: #1f2f47; padding-bottom: 5rem; border-top: 0; background: var(--field); box-shadow: 0 0 0 100vmax var(--field); clip-path: inset(0 -100vmax); }
[data-theme="dark"] .site .sec.field { --field: #1b2434; }
.site .sec.field > :not(.plan-cards) { --card: #2d405f; --text: #fff; --text-secondary: rgba(255, 255, 255, .74); --muted: rgba(255, 255, 255, .56); --border: rgba(255, 255, 255, .24); color: var(--text); }
.site .sec.field + .sec { border-top: 0; }
/* The switch on the navy: a visible track, and the period in force is a white pill with navy
   words — on the field's own tones the pressed side was lost (owner, 2026-10-14). */
.site .sec.field .bill-switch { background: rgba(255, 255, 255, .16); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22); }
.site .sec.field .bill-switch button { color: rgba(255, 255, 255, .86); }
.site .sec.field .bill-switch button[aria-pressed="true"] { background: #fff; color: #1f2f47; }
.site .sec.field .bill-switch em { color: #1f2f47; background: #8fe3b0; }
.site .sec.band h2 { font-size: clamp(1.9rem, 3.4vw, 2.6rem); line-height: 1.1; letter-spacing: -0.03em; margin-bottom: .9rem; }
.site .sec.band > .lede { margin-inline: auto; max-width: 52ch; text-wrap: balance; }
/* Questions: the answer opens under its question. */
.site .qas { max-width: 820px; border-top: 1px solid var(--border); }
.site .qa { border-bottom: 1px solid var(--border); }
.site .qa summary { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 1.05rem 0; font-weight: 600; cursor: pointer; list-style: none; }
.site .qa summary::-webkit-details-marker { display: none; }
.site .qa summary::after { content: "+"; flex: none; font-size: var(--fs-xl); font-weight: 400; line-height: 1; color: var(--navy); transition: transform .2s ease; }
.site .qa[open] summary::after { transform: rotate(45deg); }
.site .qa p { margin: 0 0 1.1rem; max-width: 68ch; color: var(--text-secondary); line-height: 1.55; }
/* The plan finder: "Is this my size?" on each card opens a modal that asks seven questions,
   one at a time, and names a plan. It leaves by its X only (modal-exit rule). */
html .site .btn.btn-navy, html .site .btn.btn-navy:hover:not(:disabled) { background: var(--navy); border-color: var(--navy); color: var(--card); }
html .site .btn.btn-navy:hover:not(:disabled) { opacity: .88; }
html .site .btn.btn-navy:disabled { opacity: .35; }
.site .finder { max-width: 560px; }
.site .finder-bar { height: 6px; border-radius: 999px; background: color-mix(in srgb, var(--text) 8%, transparent); overflow: hidden; }
.site .finder-bar i { display: block; height: 100%; border-radius: 999px; background: var(--navy); transition: width .3s ease; }
.site .finder-step { margin: .75rem 0 .35rem; font-size: var(--fs-sm); color: var(--muted); }
.site .finder-q { margin: 0 0 1.1rem; font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.02em; line-height: 1.25; }
.site .finder-opts { display: grid; gap: .6rem; }
.site .finder-opt { padding: .9rem 1.1rem; border: 1px solid var(--border); border-radius: 14px; background: var(--card); font: inherit; font-size: var(--fs-base); font-weight: 500; color: var(--text); text-align: left; cursor: pointer; transition: border-color .15s ease, background .15s ease, transform .15s ease; }
.site .finder-opt:hover { border-color: var(--navy); transform: translateX(3px); }
/* The answer just picked fills with the accent for a beat, then the next question arrives. */
.site .finder-opt.on { border-color: var(--accent); background: var(--accent); color: #fff; }
.site .finder-foot { display: flex; justify-content: space-between; align-items: center; gap: .75rem; margin-top: 1.5rem; }
.site .finder-foot .btn { border-radius: 999px; }
.site .finder-res { margin-top: 1.1rem; padding: 1.4rem; border: 1px solid var(--navy); border-radius: 18px; background: color-mix(in srgb, var(--navy) 6%, transparent); }
.site .finder-res small { display: block; font-size: var(--fs-sm); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--navy); }
.site .finder-res strong { display: block; margin: .3rem 0 .15rem; font-size: 2.4rem; line-height: 1.1; letter-spacing: -0.03em; }
.site .finder-res span { display: block; font-weight: 600; }
.site .finder-res em { display: block; margin-top: .15rem; font-style: normal; font-size: var(--fs-md); color: var(--text-secondary); }
.site .finder-why { margin: 1.1rem 0 0; font-size: var(--fs-md); line-height: 1.5; color: var(--text-secondary); }
/* Monthly / yearly: one switch above the cards; site.js repaints the prices. */
.site .bill-switch { display: inline-flex; gap: .2rem; padding: .25rem; margin-bottom: 1.5rem; border-radius: 999px; background: color-mix(in srgb, var(--text) 6%, transparent); }
.site .bill-switch button { display: inline-flex; align-items: center; gap: .5rem; padding: .5rem 1.1rem; border: 0; border-radius: 999px; background: none; font: inherit; font-size: var(--fs-md); font-weight: 600; color: var(--text-secondary); cursor: pointer; }
.site .bill-switch button[aria-pressed="true"] { background: var(--card); color: var(--text); box-shadow: var(--shadow-md); }
.site .bill-switch em { padding: .1rem .5rem; border-radius: 999px; font-style: normal; font-size: var(--fs-xs); color: var(--h-accounts); background: color-mix(in srgb, var(--h-accounts) 14%, transparent); }
/* The price cards. Large leads (.plan-lead — the "Most popular" one; owner, 2026-10-14): a navy edge all the way round, a flat navy tint, and
   the one filled (orange) button.
   Flat colour only — no gradients anywhere on the site (owner, 2026-10-13). */
/* Four cards — Small, Medium, Large, Business (owner, 2026-10-14). The row is the one part of
   Pricing that leaves the column, reaching into the side margins so four cards keep a healthy
   width; under 1181px they sit two by two, at ≤900px in one column. */
.site .saas { --plans-out: clamp(0px, (100vw - 1120px) / 2 - 1.5rem, 150px); }
.site .plan-cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.5rem; align-items: stretch; margin: 3.25rem calc(-1 * var(--plans-out)) 0; }
@media (max-width: 1180px) { .site .plan-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-inline: 0; } }
/* Four across: the leading card stands a little larger and forward, the others turn away
   from it. `rotate` / `scale` (not transform) so the reveal keeps working. Cards in two
   rows or one column lie flat. */
@media (min-width: 1181px) {
  /* Cards grow from their bottom edge — up and sideways, never down; the room they grow into
     is the margin above. */
  .site .plan-cards { perspective: 1800px; }
  .site .plan { transform-origin: 50% 100%; }
  .site .plan:has(~ .plan-lead) { rotate: y -4deg; }
  .site .plan-lead ~ .plan { rotate: y 4deg; }
  .site .plan-lead { scale: 1.04; z-index: 1; box-shadow: var(--shadow-md); }
  /* Point at a card and it takes the leading card's place: it faces front, grows and wears its
     marking (navy edge, tint, the orange button); the leading card gives all of that up
     meanwhile, and the cards to the left and right of the pointed one turn away from it. */
  .site .plan-cards:has(.plan:hover) .plan-lead:not(:hover) { scale: 1; z-index: auto; box-shadow: none; border-color: var(--border); background: var(--card); }
  html .site .plan-cards:has(.plan:hover) .plan-lead:not(:hover) a.btn { background: var(--fill); color: var(--text); }
  .site .plan-cards .plan:has(~ .plan:hover) { rotate: y -4deg; }
  .site .plan-cards .plan:hover ~ .plan { rotate: y 4deg; }
  .site .plan-cards .plan:hover { rotate: none; scale: 1.04; z-index: 1; transform: rotateX(calc(var(--py, 0) * -4deg)) rotateY(calc(var(--px, 0) * 7deg)); border-color: var(--navy); background: color-mix(in srgb, var(--navy) 5%, var(--card)); }
  html .site .plan-cards .plan:hover a.btn { background: var(--accent); color: #fff; }
  html .site .plan-cards .plan:hover a.btn:hover { background: var(--accent-hover); }
  .site .plan, .js .site .plan.reveal.in { transition: opacity .6s ease, transform .6s cubic-bezier(.2, .7, .2, 1), rotate .35s ease, scale .35s ease, box-shadow .2s ease, border-color .2s ease, background-color .2s ease; }
  /* The pointed card leans towards the pointer (--px / --py from site.js); a short transition so
     it follows the hand instead of trailing it. */
  .js .site .plan-cards .plan.reveal.in:hover { transition: transform .18s ease-out, rotate .35s ease, scale .35s ease, box-shadow .2s ease, border-color .2s ease, background-color .2s ease; }
}
@media (min-width: 1181px) and (prefers-reduced-motion: reduce) { .site .plan, .js .site .plan.reveal.in { transition: none; } }
/* The struck-through year sits above the yearly figure, not beside it: four across, a card is
   too narrow for both on one line. */
.site .plan .was { display: block; margin: 0 0 .3rem; }
.site .plan .was:empty { display: none; }
/* The "Most popular" label (owner, 2026-10-14) — on Large, the leading card:
   a small orange capsule (the accent — owner, 2026-10-14) at the middle of the card's top edge,
   astride it (owner chose this over the corner). A first, tilted outlined stamp was sent
   back as cheap. It stays on Large whichever card is pointed at. */
.site .plan-stamp { position: absolute; top: 0; left: 50%; translate: -50% -50%; padding: .28rem .8rem; border-radius: 999px; background: var(--accent); color: #fff; font-size: var(--fs-xs); font-weight: 600; letter-spacing: .04em; line-height: 1.3; white-space: nowrap; }
.site .plan { position: relative; display: flex; flex-direction: column; padding: 1.75rem; border: 1px solid var(--border); border-radius: 22px; background: var(--card); transition: transform .2s ease, box-shadow .2s ease; }
.site .plan:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.site .plan-lead { border-color: var(--navy); background: color-mix(in srgb, var(--navy) 5%, var(--card)); }
.site .plan h3 { margin: 0; font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.02em; }
.site .plan-sub { margin: .3rem 0 0; min-height: 2.6em; font-size: var(--fs-md); line-height: 1.3; color: var(--text-secondary); }
.site .plan-price { margin: 1.4rem 0 1.5rem; padding-bottom: 1.4rem; border-bottom: 1px solid var(--border); }
.site .amount { font-size: 3.1rem; font-weight: 700; line-height: 1; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; color: var(--text); }
/* Yearly only: twelve months at the monthly price, struck through, in front of the eleven
   the year actually costs. Empty (and so absent) on Monthly. */
.site .was { margin-right: .6rem; font-size: var(--fs-xl); font-weight: 600; color: var(--muted); text-decoration-thickness: 2px; font-variant-numeric: tabular-nums; }
.site .was:empty { display: none; }
.site .per { margin-left: .5rem; font-size: var(--fs-md); color: var(--muted); }
.site .whole { margin: .7rem 0 0; font-size: var(--fs-md); font-weight: 600; color: var(--text); }
.site .also { margin: .3rem 0 0; min-height: 2.6em; font-size: var(--fs-sm); line-height: 1.3; color: var(--text-secondary); }
.site .plan-fit { margin: 0 0 .75rem; font-size: var(--fs-xs); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.site .plan ul { list-style: none; margin: 0 0 1.75rem; padding: 0; display: grid; gap: .7rem; }
.site .plan li { display: flex; gap: .65rem; align-items: flex-start; font-size: var(--fs-md); line-height: 1.4; }
.site .plan li .i { width: 1.1rem; height: 1.1rem; margin-top: .12rem; color: var(--navy); }
/* A line that differs from plan to plan is bold; one that is the same in all three is not. */
.site .plan li .dif { font-weight: 700; }
.site .plan-ask { margin: auto 0 .9rem; padding: 0; border: 0; background: none; font: inherit; font-size: var(--fs-md); font-weight: 600; color: var(--navy); text-align: left; cursor: pointer; display: none; }
.js .site .plan-ask { display: block; }
.js .site .plan-ask + .btn { margin-top: 0; }
.site .plan-ask:hover { text-decoration: underline; }
.site .plan .btn { margin-top: auto; justify-content: center; text-align: center; border-radius: 999px; }
@media (max-width: 900px) {
  .site .saas .hero { grid-template-columns: 1fr; min-height: 0; gap: 3rem; padding: 3.5rem 0 3rem; }
  .site .ask-wrap { grid-template-columns: 1fr; padding-top: 1.5rem; }
  .site .ask-stage { margin-top: 2.5rem; }
  /* The page links leave the capsule and become a sheet under it, opened by Menu
     (site/site.js toggles .nav-open). Solid --card, not glass: a backdrop-filter inside the
     capsule's own backdrop-filter samples the capsule, not the page. */
  .site .page-head { position: sticky; }
  .site .nav-btn { display: inline-flex; }
  .site .site-tools .signin { display: none; }
  .site .site-nav { display: none; }
  .site .page-head.nav-open .site-nav {
    display: flex; flex-direction: column; align-items: stretch; gap: 0;
    position: absolute; top: calc(100% + 8px); left: 0; right: 0; margin: 0; padding: .5rem;
    background: var(--card); border: 1px solid var(--border); border-radius: 20px; box-shadow: var(--shadow-md);
  }
  .site .page-head.nav-open .site-nav a { padding: .8rem 1rem; border-radius: 14px; font-size: var(--fs-base); }
  .site .page-head.nav-open .site-nav .nav-signin { display: block; margin-top: .35rem; border-top: 1px solid var(--border); border-radius: 0 0 14px 14px; }
  .site .hero-shot { width: 100%; max-width: 560px; }
  .site .deck { --fan: .55; width: 100%; max-width: 600px; }
  .site .strip { grid-template-columns: 1fr; gap: 2rem; padding: 1.5rem 0 4rem; }
  .site .plan-cards, .site .shots, .site .feats-2 { grid-template-columns: 1fr; }
  .site .plan-cards { margin-top: 1.5rem; }
  .site #pricing .sec-head { flex-direction: column; align-items: flex-start; gap: 1rem; }
  .site .sec.band { padding: 3.5rem 0 4rem; text-align: left; }
  .site .sec.band > .lede { margin-inline: 0; }
  /* The gallery's controls on a phone: the Screens / Documents switch on its own line, the
     arrows, the count and pause under it. */
  .js .site .gal-bar { display: grid; grid-template-columns: repeat(4, auto); }
  .site .gal-bar .bill-switch { grid-column: 1 / -1; justify-self: center; order: -1; }
  /* The explorer on a phone: the departments become one row that scrolls sideways. */
  .site .depts { grid-template-columns: 1fr; }
  .site .dept-panels { margin-top: 0; }
  .site .dept-tabs { display: flex; overflow-x: auto; gap: .4rem; padding-bottom: .25rem; scrollbar-width: none; }
  .site .dept-tab { width: auto; flex: none; white-space: nowrap; }
  .site .dept-panel { padding: 1.35rem 1.1rem 1.5rem; }
  .site .dept-panel ul { grid-template-columns: 1fr; }
  .site .plan-sub, .site .also { min-height: 0; }
}
/* An in-page link (#contact from the hero) lands below the sticky header capsule, not under it. */
/* The capsule is away after a jump down the page, so a section lands near the top. */
.site .sec { scroll-margin-top: 1rem; }
/* Pricing: heading and switch share one line, so the cards start high on the screen (owner,
   2026-10-14). The cards keep their full height. */
.site #pricing { padding-top: 4.5rem; }
.site #pricing .sec-head { margin-bottom: 1rem; }
.site #pricing .sec-head .bill-switch { flex: none; margin-bottom: 0; }

@media (max-width: 768px) {
  .site .page { padding: 0 1rem; }
  .site .landing { padding: 3.5rem 0; }
  .site .nf-main { padding: 3rem 0; }
  .site .nf-mark { margin-bottom: 2rem; }
  .site .nf-actions { width: 100%; }
  .site .nf-actions .btn { width: 100%; }
  .site .ask { padding: 1.25rem; border-radius: 22px; }
  .site .ask-fields { grid-template-columns: 1fr; }
  .site .ask-steps { min-height: 0; }
  .site .ask-rail { gap: 1.4rem; }
  .site .ask-rail li + li::before { width: .7rem; }
}

/* ============================================================
   ATTENDANCE KIOSK (attendance/kiosk.html) — a wall screen, always dark.
   The page pins data-theme="dark" on <html>: it is read from across a corridor and its result
   screens flood the whole display with a status colour. data-page="kiosk" (on <html>) fills
   the window and stops it scrolling.
   ============================================================ */
[data-page="kiosk"], [data-page="kiosk"] body { height: 100%; }
[data-page="kiosk"] body { overflow: hidden; }
.k-shell { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.25rem; padding: 1.5rem; }
.k-top { text-align: center; }
/* The company's logo on a white plate: logos are drawn for paper, and a dark one would vanish
   on the kiosk's dark background. With no logo uploaded, the name stands alone. */
.k-brand { display: flex; justify-content: center; margin-bottom: .75rem; min-height: 1px; }
.k-brand img { max-height: 72px; max-width: min(60vw, 320px); background: #fff; padding: .5rem .9rem; border-radius: 12px; }
.k-brand span { font-size: 1.4rem; font-weight: 700; opacity: .9; }
.k-clock { font-size: clamp(3rem, 10vw, 6rem); font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: -0.03em; }
.k-date { font-size: var(--fs-lg); color: var(--text-secondary); margin-top: .35rem; }
.k-label { font-size: var(--fs-md); color: var(--muted); margin-top: .25rem; }
.k-frame {
  position: relative; width: min(92vw, 560px); aspect-ratio: 4 / 3; overflow: hidden;
  border-radius: var(--r-sheet); background: var(--card); box-shadow: var(--shadow-lg), 0 0 0 .5px var(--glass-line);
}
.k-frame video { width: 100%; height: 100%; object-fit: cover; transform: scaleX(-1); }
.k-status { font-size: 1.25rem; text-align: center; min-height: 1.6em; }
.k-status.warn { color: var(--orange); }
.k-result { position: fixed; inset: 0; display: none; flex-direction: column; align-items: center; justify-content: center; gap: .75rem; text-align: center; padding: 2rem; color: #fff; }
.k-result.show { display: flex; }
.k-result .k-name { font-size: clamp(2.2rem, 7vw, 4.5rem); font-weight: 700; letter-spacing: -0.02em; }
.k-result .k-what { font-size: clamp(1.6rem, 5vw, 3rem); font-variant-numeric: tabular-nums; }
.k-result .k-sub { font-size: 1.15rem; opacity: .9; max-width: 36rem; }
.k-result.green { background: var(--green); }
.k-result.orange { background: var(--orange); }
.k-result.red { background: var(--red); }
.k-result.neutral { background: color-mix(in srgb, var(--blue) 22%, var(--card)); }
.k-result.refused { background: var(--surface-2); }
.k-cover { position: fixed; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1rem; text-align: center; padding: 2rem; background: var(--bg); }
.k-cover h1 { font-size: clamp(1.6rem, 5vw, 2.6rem); margin: 0; }
.k-cover p { color: var(--text-secondary); max-width: 34rem; margin: 0; font-size: var(--fs-lg); }
.k-signin { position: fixed; right: 1rem; bottom: .75rem; font-size: var(--fs-sm); color: var(--muted); }

/* ============================================================
   SHARED VOCABULARY — the classes page JS uses INSTEAD of inline style="…" (2026-10-05).

   The owner's rule: the design is shared; a page does its own thing only when it must.
   Page templates used to spell the same few things out by hand hundreds of times (an
   accent section label ×29, a mini-table header cell ×41, a total row's top rule ×27, a
   hand-built on/off switch ×11, …). Each now has ONE definition here.

   Why this block is LAST: the design layer above styles bare th/td with
   html:not([data-standalone]) th (specificity 0,1,2). A class that sets a cell's padding
   must out-rank that, so cell components are written `table .x th` / `table td.x`
   (0,1,2 or more) and, being later in the file, win the tie. Utilities set properties
   the design layer never touches, so a single class is enough.

   Rules for using it (MDs/ui-stylesheet.md §3):
   - A class reproduces what the inline style said — same typography (font size, weight,
     case, letter-spacing) exactly; spacing may snap to the nearest step of the scale
     below (never more than 0.25rem off).
   - Colours are tokens (var(--red) …), never hex; see the token block at the top.
   - One class attribute per element: merge into the existing class="…", never add a
     second one (the browser ignores the second).
   - Genuinely one-off layout (a specific column width, a computed position, a value
     from data) stays inline. That is not a failure of the rule.
   ============================================================ */

/* --- Section label: the small accent caps title over a block (×29) --- */
.section-label {
  font-size: var(--fs-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--accent); margin-bottom: 0.4rem;
}

/* --- Field note: the muted line under a value or field (addresses, explanations) (×20) --- */
.field-note { font-size: var(--fs-sm); color: var(--muted); margin-top: 0.25rem; }

/* --- Well: an inset panel inside a card or sheet (inside content --bg is the well grey) --- */
.well { background: var(--bg); border-radius: var(--radius-sm); padding: 0.6rem 0.75rem; }

/* --- Mini table: a compact table inside a panel or overlay tab (×41 header cells) ---
   Keeps the global th's caps/size; only alignment, padding, colour and weight as the
   inline cells had them. Cells that held numbers add .r (right-aligned). */
table.mini-table { width: 100%; border-collapse: collapse; font-size: var(--fs-xs); }
table.mini-table th { text-align: left; padding: 0.3rem 0.5rem; color: var(--muted); font-weight: 600; }
table.mini-table th.r, table.mini-table td.r { text-align: right; }

/* --- Table states --- */
table td.empty-cell { text-align: center; padding: 1.5rem; }      /* "Nothing here yet" row (×22) */
.total-rule, table .total-rule > td { border-top: 2px solid var(--border); }   /* total / subtotal line (×27), add .fw-600/.fw-700 */

/* --- Switch: the on/off control pages built by hand (×11) ---
   <label class="flex items-center gap-sm cursor-pointer">
     <span class="switch"><input type="checkbox" …><span class="switch-track"></span></span> Label
   </label>
   The look follows :checked, so the template no longer computes colours or the knob position. */
.switch { position: relative; display: inline-block; width: 36px; height: 20px; flex-shrink: 0; }
.switch input { opacity: 0; width: 0; height: 0; position: absolute; }
.switch-track { position: absolute; inset: 0; background: var(--border); border-radius: 20px; transition: background .2s; cursor: pointer; }
.switch-track::after {
  content: ''; position: absolute; height: 16px; width: 16px; left: 2px; top: 2px;
  background: #fff; border-radius: 50%; transition: transform .2s; box-shadow: 0 1px 3px rgba(0,0,0,.25);
}
.switch input:checked + .switch-track { background: var(--accent); }
.switch input:checked + .switch-track::after { transform: translateX(16px); }
.switch input:focus-visible + .switch-track { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent); }
.switch input:disabled + .switch-track { opacity: .5; cursor: not-allowed; }

/* --- Legend item: a swatch + label pair in a chart / calendar key --- */
.legend-item { display: inline-flex; align-items: center; gap: 5px; margin-right: 14px; white-space: nowrap; }

/* ============================================================
   Vocabulary, round 2 (2026-10-06) — the patterns the seven conversion agents each found
   repeated in their own modules and asked to have defined once.
   ============================================================ */

/* --- Extra-small button in the design layer: keep its compact padding and dense-control corner --- */
html:not([data-standalone]) .btn.btn-xs { padding-left: .5rem; padding-right: .5rem; border-radius: var(--radius-sm); }

/* --- Form grids (two / three / four equal columns); add a .gap-* utility --- */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; }
.grid-4 { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; }

/* --- Section divider: a hairline that starts a new block inside a card or sheet --- */
.section-divider { border-top: 1px solid var(--border); margin-top: 1rem; padding-top: 1rem; }
.hairline { height: 1px; background: var(--border); }

/* --- Mini table, round 2: data cells and the header row's rule (×31 cells, ×7 rows) --- */
table.mini-table td { padding: 0.35rem 0.5rem; }
table.mini-table thead tr { border-bottom: 2px solid var(--border); }

/* --- Smaller empty-table cell (1rem instead of 1.5rem) --- */
table td.empty-cell.sm { padding: 1rem; }

/* --- Row states --- */
.row-overdue { background: color-mix(in srgb, var(--red) 5%, transparent); }

/* --- Sticky first column of a wide matrix / ledger (opaque so cells scroll beneath it) --- */
table .sticky-col { position: sticky; left: 0; z-index: 2; background: var(--card); }

/* --- Stripe: a coloured left rule marking a card or note (notice, warning, status) ---
   .stripe on its own is orange; add .stripe-green/-red/-blue/-purple/-accent for another colour.
   On a .card it must beat the design layer's transparent card border (0,2,1), hence the
   second selector. .callout is the tinted note version: stripe + 8% tint + padding. */
.stripe, html:not([data-standalone]) .card.stripe { border-left: 3px solid var(--stripe-c, var(--orange)); }
html:not([data-standalone]) .card.stripe { border-radius: var(--radius-sm); }
.stripe-green  { --stripe-c: var(--green); }
.stripe-red    { --stripe-c: var(--red); }
.stripe-blue   { --stripe-c: var(--blue); }
.stripe-purple { --stripe-c: var(--purple); }
.stripe-accent { --stripe-c: var(--accent); }
.stripe-warning{ --stripe-c: var(--warning); }
.callout {
  border-left: 3px solid var(--stripe-c, var(--orange)); border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--stripe-c, var(--orange)) 8%, transparent);
  padding: 0.5rem 0.75rem;
}
/* .note-box is the neutral one: a grey box for an announcement that is neither a warning nor an
   error (the company-code steps on sign-in and the public site). */
.note-box {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--text) 5%, transparent);
  padding: 0.6rem 0.8rem; margin-bottom: 1rem;
  font-size: var(--fs-sm); color: var(--text-secondary); line-height: 1.45;
}

/* ============================================================
   UTILITIES — last in the file on purpose: a single-purpose class must be able to adjust a
   component it is combined with (e.g. class="section-divider mt-0"). Values are the ones the
   inline styles had. The older base utilities (.muted .text-sm .text-xs .text-center .flex …
   .gap-* .justify-* .w-full .hidden) stay near the top of the file where they always were.
   ============================================================ */
/* --- Spacing scale (margins) --- */
.m-0  { margin: 0; }
.mb-0 { margin-bottom: 0; }      .mt-0 { margin-top: 0; }
.mb-xs{ margin-bottom: .25rem; } .mt-xs{ margin-top: .25rem; }
.mb-sm{ margin-bottom: .5rem; }  .mt-sm{ margin-top: .5rem; }
.mb-md{ margin-bottom: .75rem; } .mt-md{ margin-top: .75rem; }
.mb-lg{ margin-bottom: 1rem; }   .mt-lg{ margin-top: 1rem; }
.mb-xl{ margin-bottom: 1.5rem; } .mt-xl{ margin-top: 1.5rem; }
.ml-xs{ margin-left: .25rem; }   .ml-sm{ margin-left: .5rem; }   .ml-auto{ margin-left: auto; }
.mr-xs{ margin-right: .25rem; }  .mr-sm{ margin-right: .5rem; }

/* --- Text utilities (values as the inline styles had them) --- */
.text-right { text-align: right; }
.text-left  { text-align: left; }
.num        { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tabular    { font-variant-numeric: tabular-nums; }
.nowrap     { white-space: nowrap; }
.pre-line   { white-space: pre-line; }
.fw-400 { font-weight: 400; } .fw-500 { font-weight: 500; } .fw-600 { font-weight: 600; } .fw-700 { font-weight: 700; } .fw-800 { font-weight: 800; }
.text-red    { color: var(--red); }
.text-green  { color: var(--green); }
.text-orange { color: var(--orange); }
.text-warning{ color: var(--warning); }
.text-blue   { color: var(--blue); }
.text-purple { color: var(--purple); }
.text-teal   { color: var(--teal); }
.text-accent { color: var(--accent); }
.text-body   { color: var(--text); }
.text-secondary { color: var(--text-secondary); }
/* .muted, .text-sm (.85rem), .text-xs (.75rem), .text-center already exist above. */

/* --- Layout utilities --- */
.flex-1        { flex: 1; }
.flex-1-0      { flex: 1; min-width: 0; }
.shrink-0      { flex-shrink: 0; }
.cursor-pointer{ cursor: pointer; }
.resize-v      { resize: vertical; }
.scroll-y      { overflow-y: auto; }
/* .flex .flex-col .flex-wrap .items-* .justify-* .gap-* .w-full .hidden exist above. */

/* --- Small structural utilities --- */
.block    { display: block; }               /* e.g. a span.form-error that must sit on its own line */
.italic   { font-style: italic; }
.va-top   { vertical-align: top; }
.w-min    { width: 1%; white-space: nowrap; } /* shrink-to-fit column (actions) */
.is-inactive { opacity: .55; }              /* an inactive / archived row or item */
.scroll-x { overflow-x: auto; }

/* --- Type scale utilities: .text-<step> sets the font size to that step of the ramp --- */
.text-3xs { font-size: var(--fs-3xs); }  .text-2xs { font-size: var(--fs-2xs); }
.text-xs  { font-size: var(--fs-xs); }   .text-sm  { font-size: var(--fs-sm); }
.text-md  { font-size: var(--fs-md); }   .text-base{ font-size: var(--fs-base); }
.text-lg  { font-size: var(--fs-lg); }   .text-xl  { font-size: var(--fs-xl); }
.text-2xl { font-size: var(--fs-2xl); }  .text-3xl { font-size: var(--fs-3xl); }

/* --- Document overlays read one notch larger (2026-10-06) ---
   The detail-tab panels of every document overlay (sales orders, purchase orders, custom
   invoices, disciplinary cases) are dense working screens; the Sales overlay had made its tab
   text easier to read with a page hack that scaled inline font sizes up. That hack is gone:
   ONE shared rule now lifts the small steps inside any .dtab-panel, so pages and the shared
   helpers rendered inside these panels write normal ramp classes everywhere. */
.dtab-panel .text-3xs { font-size: var(--fs-xs); }
.dtab-panel .text-2xs { font-size: var(--fs-sm); }
.dtab-panel .text-xs  { font-size: var(--fs-md); }
.dtab-panel .text-sm  { font-size: var(--fs-md); }
.dtab-panel .text-md  { font-size: var(--fs-base); }
.dtab-panel table.mini-table { font-size: var(--fs-md); }   /* mini tables inside a panel step up with the text around them */
