﻿/* ═══════════════════════════════════════════════════════════════════════════
   Admin Panel Styles — Ordinex
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Layout: fixed 236px sidebar + content column (redesign v2) ──────────── */
body { min-height: 100dvh; }

.admin-shell { display: flex; min-height: 100dvh; }

/* Sidebar — AdminSidebar.dc.html: brand lockup, org chip, section nav
   (active = soft yellow wash + left bar in light, solid yellow pill in
   dark — see .admin-section-btn.active below), Settings, user chip footer.
   Chrome (2026-08-05 all-white pass) — white rail in light, the original
   obsidian rail in dark; only the brand mark (--mark-bg) stays fixed. */
.admin-sidebar {
  width: 236px; flex-shrink: 0;
  position: sticky; top: 0;
  height: 100dvh;
  display: flex; flex-direction: column;
  background: var(--chrome-bg-1);
  border-right: 1px solid var(--chrome-border);
  z-index: 110;
}

.admin-side-brand {
  display: flex; align-items: center; gap: 11px;
  padding: calc(18px + env(safe-area-inset-top)) 18px 20px;
}

.admin-side-org {
  display: flex; align-items: center; gap: 9px;
  margin: 2px 12px 10px;
  padding: 9px 10px;
  border-radius: 9px;
  background: var(--chrome-surface);
  border: 1px solid var(--chrome-border);
}
.admin-side-org-ic {
  width: 26px; height: 26px; flex-shrink: 0;
  border-radius: 6px;
  background: var(--chrome-surface-3);
  /* 2026-08-05 all-white pass: the sidebar now themes (white in light), so
     this glyph needs the ink-safe token — plain --accent is 1.56:1 on a
     light chip and fails outright. --accent-ink aliases back to --accent
     in dark, so dark is unaffected. */
  color: var(--accent-ink);
  display: flex; align-items: center; justify-content: center;
}
.admin-side-org-ic svg { width: 15px; height: 15px; }
.admin-side-org-txt  { min-width: 0; }
.admin-side-org-name {
  display: block;
  font-size: 12px; font-weight: 700; color: var(--chrome-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.admin-side-org-sub { display: block; font-size: 10px; font-weight: 500; color: var(--chrome-text-dim); }

.admin-side-nav {
  flex: 1;
  padding: 6px 12px;
  display: flex; flex-direction: column; gap: 2px;
  overflow-y: auto;
}
.admin-side-div { height: 1px; background: var(--chrome-border); margin: 8px 4px; flex-shrink: 0; }

.admin-side-foot { padding: 12px; border-top: 1px solid var(--chrome-border); position: relative; }
.admin-side-user {
  display: flex; align-items: center; gap: 11px;
  width: 100%;
  padding: 8px 10px;
  border: none; border-radius: 10px;
  background: var(--chrome-surface);
  cursor: pointer; text-align: left;
  font-family: var(--font);
  transition: background var(--t-fast) var(--ease-out);
}
.admin-side-user:hover { background: var(--chrome-surface-2); }
.admin-side-avatar {
  width: 32px; height: 32px; flex-shrink: 0;
  border-radius: 8px;
  background: var(--chrome-surface-3);
  color: var(--chrome-text);
  font-family: var(--display); font-size: 12px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.admin-side-user-txt  { flex: 1; min-width: 0; }
.admin-side-user-name {
  display: block;
  font-size: 12.5px; font-weight: 700; color: var(--chrome-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.admin-side-user-role { display: block; font-size: 10.5px; font-weight: 500; color: var(--chrome-text-dim); }
.admin-side-chev { width: 15px; height: 15px; color: var(--chrome-text-dim); flex-shrink: 0; }

.admin-user-menu {
  position: absolute;
  left: 12px; right: 12px;
  bottom: calc(100% + 6px);
  background: var(--surface-flat-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  padding: 6px;
  box-shadow: var(--shadow-lg);
  display: none;
  z-index: 5;
}
.admin-user-menu.open { display: block; }
.admin-user-menu-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: none; border-radius: 8px;
  background: transparent;
  color: var(--text);
  font-family: var(--font); font-size: 13px; font-weight: 600;
  cursor: pointer; text-align: left;
}
.admin-user-menu-item svg { width: 16px; height: 16px; color: var(--text-muted); }
.admin-user-menu-item:hover { background: var(--surface-flat-3); }
.admin-user-menu-item--danger,
.admin-user-menu-item--danger svg { color: var(--error); }
/* The bell's list (review B1): the user menu's look, hung under the bell.
   Fixed, with top/right set by toggleAttnMenu, so a phone never pushes it off-screen. */
.admin-attn-menu {
  position: fixed; left: auto; bottom: auto;
  width: 320px; max-width: calc(100vw - 32px);
  z-index: 120;
}
.admin-attn-menu .admin-user-menu-item { justify-content: space-between; gap: 12px; min-height: 44px; }
.admin-attn-where { flex: none; font-weight: 500; color: var(--text-muted); }
.admin-attn-none { padding: 12px 10px; font-size: 13px; color: var(--text-muted); }
/* Help & videos / Text support are links in the account rows (review A5). */
a.admin-side-action { text-decoration: none; }
@media (max-width: 1023px) { .admin-side-action { min-height: 44px; } }

/* Content column */
.admin-content { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* Mobile burger — hidden on desktop. Triggers the (chrome) sidebar, and
   floats over the PAGE (not the rail itself, which is off-screen until
   opened) — so in light, the rail's translucent chrome-surface wash would
   nearly vanish here. Solid white FAB + real shadow instead, the same
   "floating chip on the page" treatment cards/modals already use. Dark
   pins the original chrome-surface/no-shadow look below, unchanged. */
.admin-burger {
  display: none;
  position: fixed;
  top: calc(10px + env(safe-area-inset-top)); left: 12px;
  z-index: 120;
  width: 40px; height: 40px;
  border-radius: 10px;
  background: var(--surface-flat);
  border: 1px solid var(--chrome-border-strong);
  color: var(--chrome-text);
  box-shadow: var(--shadow-sm);
  align-items: center; justify-content: center;
  cursor: pointer;
}
.admin-burger svg { width: 20px; height: 20px; }
[data-theme="dark"] .admin-burger { background: var(--chrome-surface); box-shadow: none; }

.admin-side-backdrop {
  position: fixed; inset: 0;
  background: rgba(6, 7, 10, 0.6);
  backdrop-filter: blur(3px);
  opacity: 0; pointer-events: none;
  transition: opacity var(--t-med) var(--ease-out);
  z-index: 105;
}
.admin-side-backdrop.show { opacity: 1; pointer-events: auto; }

@media (max-width: 1023px) {
  .admin-sidebar {
    position: fixed; left: 0; top: 0; bottom: 0;
    transform: translateX(-100%);
    transition: transform var(--t-med) var(--ease-out);
    box-shadow: var(--shadow-lg);
  }
  .admin-sidebar.open { transform: translateX(0); }
  .admin-burger { display: flex; }
  /* body-qualified so it outranks the base .admin-content-head padding
     SHORTHAND defined later in the file (same specificity = last wins, and
     the 2026-08-05 chrome rewrite silently ate this reserve — the burger
     then sat on top of every page title on mobile). */
  body .admin-content-head { padding-left: 64px; }
}

.admin-back-btn,
.admin-logout-btn {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--text-muted);
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  padding: 6px 12px;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
  white-space: nowrap;
}
.admin-back-btn:hover,
.admin-logout-btn:hover {
  background: var(--surface-flat-2);
  border-color: var(--border-strong);
  color: var(--text);
}

/* Settings — fixed icon button in the header, deliberately NOT one of the
   nav tabs: configured once in a while, not a daily-driver surface, so it
   shouldn't compete for space with Projects/Deliveries/etc. */
.admin-icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--text-muted);
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
}
.admin-icon-btn svg { width: 18px; height: 18px; }
.admin-icon-btn:hover {
  background: var(--surface-flat-2);
  border-color: var(--border-strong);
  color: var(--text);
}

/* ── Sidebar section nav (Level 1) ────────────────────────────────────────── */
/* Active item, light (2026-08-05 all-white pass, default): soft yellow wash
   + 3px left bar + full-ink text — the approved mockup's nav-active read on
   a white rail. Dark keeps the pre-existing solid yellow pill exactly (the
   reference's original signature move), via the [data-theme="dark"]
   override below. Inactive items are quiet; hover lifts to --chrome-surface.
   The 3px border-left is reserved on every state (transparent when
   inactive/dark) so nothing shifts horizontally on hover or theme toggle. */
.admin-section-btn {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 12px 10px 9px;
  background: transparent;
  border: none;
  border-left: 3px solid transparent;
  border-radius: 9px;
  color: var(--chrome-text-muted);
  font-family: var(--font);
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  text-align: left;
  white-space: nowrap;
  flex-shrink: 0;
  transition: background 0.12s, color 0.12s;
  -webkit-tap-highlight-color: transparent;
}
.admin-section-btn .anav-icon { width: 18px; height: 18px; stroke-width: 1.85px; flex-shrink: 0; }
.admin-section-btn span:not(.anav-icon) { flex: 1; }
.admin-section-btn:hover { background: var(--chrome-surface); color: var(--chrome-text); }
.admin-section-btn.active {
  /* Narwal split: structure is PURPLE (this nav), action stays orange. */
  background: var(--brand-orange-soft);
  border-left-color: var(--brand-orange-ink);
  color: var(--chrome-text);
}
[data-theme="dark"] .admin-section-btn.active {
  background: var(--brand-orange);
  border-left-color: transparent;
  color: var(--on-brand-orange);
}
/* Sidebar section badge (redesign v2 correction — model: yellow "3" pill on
   Site). Rolls up every visible tab-row badge in that section (00-shell.js
   _syncSectionBadges) — real pending counts, not decoration. */
.anav-side-badge {
  flex: none;
  min-width: 19px; height: 19px; padding: 0 6px;
  border-radius: 10px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 11px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.anav-side-badge[hidden] { display: none; }
/* Only dark's solid-pill active state needs the badge to invert (dark badge
   on a yellow button); light's soft-wash active state leaves the badge at
   its normal yellow-pill look, which already reads fine on the wash. */
[data-theme="dark"] .admin-section-btn.active .anav-side-badge { background: var(--on-brand-orange); color: var(--brand-orange); }

/* ── Tab row (Level 2) — lives in the sticky content head ─────────────────── */
.admin-nav-wrap {
  display: flex;
  gap: 2px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.admin-nav-wrap::-webkit-scrollbar { display: none; }

/* Edge fades + chevron: shown (via JS toggling .show) when tabs overflow
   off-screen — the scrollbar is hidden, so this is the only affordance. */
.anav-fade {
  position: absolute;
  bottom: 0;
  height: 42px; /* tab-row height — anchored to .admin-content-head */
  width: 44px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.18s var(--ease-out);
  z-index: 3;
}
.anav-fade.show { opacity: 1; }
.anav-fade-l { left: 0;  background: linear-gradient(90deg,  var(--chrome-bg) 25%, transparent); }
.anav-fade-r { right: 0; background: linear-gradient(270deg, var(--chrome-bg) 25%, transparent); }
.anav-fade::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 7px;
  height: 7px;
  /* 2026-08-05: was a fixed #8893b2 (only ~3.06:1 on white — marginal),
     back when this fade only ever sat on obsidian chrome. Now themed: ink
     in light (chrome-text-dim, ~4.6:1), the original blue-gray pinned back
     for dark below so dark stays pixel-identical. */
  border-right: 2px solid var(--chrome-text-dim);
  border-top: 2px solid var(--chrome-text-dim);
}
[data-theme="dark"] .anav-fade::after { border-right-color: #8893b2; border-top-color: #8893b2; }
.anav-fade-l::after { left: 10px;  transform: translateY(-50%) rotate(-135deg); }
.anav-fade-r::after { right: 10px; transform: translateY(-50%) rotate(45deg); }

.anav-group { display: none; flex-shrink: 0; }
.anav-group.active { display: flex; }
.anav-row { display: flex; gap: 2px; }

/* Tabs are text-only in the reference row (icons stay in the markup for the
   tooltip initializer, hidden here): active = yellow text + 2px underline. */
.admin-tab {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 14px;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--chrome-text-muted);
  cursor: pointer;
  font-family: var(--font);
  transition: color 0.12s, border-color 0.12s;
  -webkit-tap-highlight-color: transparent;
  white-space: nowrap;
  flex-shrink: 0;
}
.admin-tab .anav-icon { display: none; }
.admin-tab:hover { color: var(--chrome-text); }
.admin-tab.active {
  /* Narwal split: the active tab is STRUCTURE — purple ink, both themes. */
  color: var(--brand-orange-ink);
  border-bottom-color: var(--brand-orange-ink);
}
.admin-tab.admin-tab-link { opacity: 0.65; }
.admin-tab.admin-tab-link:hover { opacity: 1; }

/* Pending-count badge — inline chip after the label (signal, not danger). */
.anav-badge {
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  background: var(--accent);
  color: var(--on-accent);
  border-radius: 9px;
  font-size: 10.5px;
  font-weight: 800;
  line-height: 18px;
  text-align: center;
}

/* ── Estimating items hidden (kept in HTML for future use) ── */
[data-tab="prices"],
.admin-tab-link { display: none !important; }

.anav-icon {
  width: 18px;
  height: 18px;
  stroke-width: 1.85px;
  /* Lucide injects an <svg> that inherits these via the carried-over class. */
}
.anav-icon svg { width: 100%; height: 100%; }
.anav-lbl {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1.3;
}

/* ── Content head: section title + tab row, sticky over the scrolling main.
   Chrome (2026-08-05 all-white pass) — white in light, obsidian in dark
   (this bar and the job-workspace head below share the class; both are
   chrome per the light-theme spec). ── */
.admin-content-head {
  position: sticky;
  top: 0;
  z-index: 95;
  background: var(--chrome-bg);
  padding: calc(16px + env(safe-area-inset-top)) 30px 0;
  border-bottom: 1px solid var(--chrome-border);
}
.admin-content-title {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
}
.admin-content-title-left { min-width: 0; }
.admin-content-h1 {
  margin: 0;
  font-family: var(--display);
  font-size: 22px; font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--chrome-text);
}
.admin-content-sub { margin-top: 2px; font-size: 12.5px; font-weight: 500; color: var(--chrome-text-muted); }
/* Change Orders & RFIs only: where the contract value lives (review A11). On a
   phone the header is a grid, so the line takes the row under the subtitle. */
@media (max-width: 760px) {
  #adminNavShell .admin-content-sub.admin-content-hint { grid-column: 2 / -1; grid-row: 3; }
}
/* A link inside a sentence, glove-sized: the padding grows the tap area and
   the negative margin gives the line its height back. */
.cw-linkbtn.cw-linkbtn--tap { padding-block: 12px; margin-block: -12px; }

/* Right slot (redesign v2 correction): bell + per-tab CTA. Empty/hidden
   elements collapse to nothing, so tabs without a CTA just show the bell. */
.admin-content-title-right {
  display: flex; align-items: center; gap: 10px;
  flex-shrink: 0;
  padding-top: 1px;
}
/* .admin-theme-toggle (sun/moon, light-theme phase T1) shares this exact
   chrome-header button treatment with the bell. */
.admin-header-bell, .admin-theme-toggle {
  position: relative;
  width: 36px; height: 36px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-md);
  border: 1px solid var(--chrome-border);
  background: var(--chrome-surface);
  color: var(--chrome-text-muted);
  cursor: pointer;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.admin-header-bell:hover, .admin-theme-toggle:hover { color: var(--chrome-text); border-color: var(--chrome-border-strong); }
.admin-header-bell svg, .admin-theme-toggle svg { width: 17px; height: 17px; stroke-width: 1.85px; }
.admin-header-bell-count {
  position: absolute; top: -3px; right: -3px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 8px;
  /* Attention count is SHOCK ORANGE (Narwal v2), not the purple accent. */
  background: var(--brand-orange);
  color: var(--on-brand-orange);
  font-size: 10px; font-weight: 700; line-height: 16px;
  text-align: center;
  box-shadow: 0 0 0 2px var(--chrome-bg);
}
.admin-header-bell-count[hidden] { display: none; }
.admin-tab-cta {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 15px;
  border: none; border-radius: var(--r-md);
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font);
  font-size: 13px; font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-fast);
}
.admin-tab-cta:hover { background: var(--accent-bright); }
.admin-tab-cta svg { width: 15px; height: 15px; stroke-width: 2px; }
.admin-tab-cta[hidden] { display: none; }
/* Trial countdown (app review A4): amber from 4 days left, red from 2 and
   after the end. A link to Billing, sized like the header buttons. */
.admin-trial-badge {
  display: inline-flex; align-items: center; min-height: 36px; padding: 0 12px;
  border-radius: var(--r-md); border: 1px solid var(--warning-border);
  background: var(--warning-soft); color: var(--warning-ink);
  font-size: 12.5px; font-weight: 700; white-space: nowrap; text-decoration: none;
}
.admin-trial-badge:hover { border-color: var(--warning-ink); }
.admin-trial-badge--urgent { background: var(--error-soft); color: var(--error-ink); border-color: var(--error); }
.admin-trial-badge--urgent:hover { border-color: var(--error-ink); }
@media (max-width: 720px) {
  .admin-trial-badge { min-height: 44px; }
  .admin-trial-badge .atb-pre { display: none; }
}
/* The phone header is a grid (G1B, redesign-tokens.css): with the badge the
   right-hand group no longer fits row 1 and pushed the bell and CTA off
   screen. It takes a row of its own under the subtitle instead. */
@media (max-width: 760px) {
  #adminNavShell .admin-content-title:has(.admin-trial-badge:not([hidden])) .admin-content-title-right {
    grid-column: 1 / -1; grid-row: 3; justify-content: flex-end; flex-wrap: wrap; row-gap: 8px; margin-top: 6px;
  }
}
/* Status line under a Settings / Billing button (app review B2). */
.cw-btn-msg { grid-column: 1 / -1; font-size: 12px; color: var(--text-muted); }
.cw-btn-msg:empty { display: none; }
.cw-btn-msg--err { color: var(--error-ink); }
#billingActionsWrap:empty { display: none; }   /* complimentary / no billing row: nothing to act on */
/* Settings → Seats & logins has two tiles (A8/A12); the phone rule for
   .st-roles assumed three and left an empty third column. */
.cw-card > #settingsRolesWrap { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Job checkboxes on a foreman invite (A3) — the Assign Projects rows, boxed. */
.invite-projects { border: 1px solid var(--border); border-radius: var(--r-md); }
/* The invite sheet has no .admin-modal-body: with the job list it outgrew its
   70vh box and the flex column squashed the inputs. It scrolls as one piece
   now, the Send button pinned at the bottom. */
#inviteModal .admin-modal { overflow-y: auto; }
#inviteModal .admin-modal > * { flex-shrink: 0; }
#inviteModal .adm-sheet-footer { position: sticky; bottom: 0; }
.invite-projects .assign-project-item { padding: 12px 14px; min-height: 44px; box-sizing: border-box; }
/* Pending invites on Crew → Foremen & admins (A12). */
.fm-invites { margin-bottom: var(--block-gap); }
.fm-inv-acts { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
@media (max-width: 860px) {
  .fm-inv-acts { justify-content: flex-start; }
  .fm-inv-acts .cw-mini { height: 44px; padding: 0 14px; font-size: 13px; }
}

@media (max-width: 720px) {
  .admin-tab-cta span, .admin-tab-cta { font-size: 12.5px; padding: 8px 12px; }
}

/* ── Main ─────────────────────────────────────────────────────────────────── */
.admin-main {
  width: 100%;
  max-width: 1200px;
  padding: 22px 30px 44px;
}

.admin-panel { display: none; }
.admin-panel.active { display: block; animation: admin-panel-in 0.28s var(--ease-out); }
/* Quiet entrance on tab switch — a short fade+lift so the panel arrives with
   intent instead of snapping. Operate-mode restraint: no bounce, nothing on
   the critical path. Covered by the blanket prefers-reduced-motion rule in
   styles.css (admin.html loads it first). */
@keyframes admin-panel-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Section headers ──────────────────────────────────────────────────────── */
.admin-section-header {
  margin-bottom: var(--space-7);
}

.admin-section-title {
  font-family: var(--display);   /* Archivo — the brand "stamped in steel" tier */
  font-size: 25px;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.12;
  color: var(--text);
}

.admin-section-sub {
  font-size: 13.5px;
  color: var(--text-muted);
  margin-top: var(--space-2);
  line-height: 1.55;
  max-width: 68ch;
}

.admin-link {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--border-strong);
  text-underline-offset: 3px;
  transition: text-decoration-color var(--t-fast) var(--ease-out);
}
.admin-link:hover { text-decoration-color: var(--accent); }

/* ── Cards ────────────────────────────────────────────────────────────────── */
/* Cards lift off the page with a soft shadow + a hairline top-edge highlight
   (--inner-hi) — the difference between a flat "boxed" admin and a modern
   product surface. Softer radius (--r-xl) and roomier padding read premium. */
.admin-card {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: var(--space-6);
  margin-bottom: var(--space-6);
  box-shadow: var(--shadow-sm), var(--inner-hi);
}
/* Phone: the 30px page gutter plus the 24px card padding left a 253px column
   on a 375px phone — a third of the screen was empty border (2026-11-04).
   Placed after .admin-card so it wins at the same specificity. */
@media (max-width: 640px) {
  .admin-main { padding: 14px 12px 40px; }
  .admin-card { padding: 16px 14px; margin-bottom: 16px; }
  .cw-stack > .admin-card { margin-bottom: 0; }   /* the stack's gap already spaces them */
}

.admin-card-title {
  font-size: var(--text-title);
  font-weight: 700;
  color: var(--text);
  margin-bottom: var(--space-4);
  letter-spacing: -0.01em;
}

/* ── Tables / lists ───────────────────────────────────────────────────────── */
.admin-table-wrap {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow: hidden;
  margin-bottom: var(--space-6);
  box-shadow: var(--shadow-sm), var(--inner-hi);
}

.admin-loading {
  padding: var(--space-7) var(--space-5);
  text-align: center;
  color: var(--text-muted);
  font-size: 14px;
}

.admin-table-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
  transition: background var(--t-fast) var(--ease-out);
}
.admin-table-row:last-child { border-bottom: none; }
/* White-alpha hover wash vanishes on a light row (T2 light sweep) — same
   alpha, dark-ink polarity for light; dark pinned at file end. */
.admin-table-row:hover { background: rgba(10, 11, 14, 0.025); }

.admin-table-cell { flex: 1; min-width: 0; }

.admin-cell-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  letter-spacing: -0.005em;
}

.admin-cell-meta {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.admin-badge {
  font-size: 12px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  white-space: nowrap;
  flex-shrink: 0;
}
.admin-badge-active  { background: rgba(34,197,94,0.12); color: #22c55e; }
.admin-badge-inactive { background: rgba(239,68,68,0.12); color: #ef4444; }

/* ── Buttons ──────────────────────────────────────────────────────────────── */
.admin-btn-primary {
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 9px;
  color: var(--on-accent);
  font-family: var(--display);
  font-size: 13px;
  font-weight: 800;
  padding: 9px 15px;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out);
  white-space: nowrap;
  flex-shrink: 0;
  letter-spacing: -0.005em;
}
.admin-btn-primary:hover { background: var(--accent-bright); border-color: var(--accent-bright); }
.admin-btn-primary:active { transform: scale(0.98); }
.admin-btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }

.admin-btn-ghost {
  background: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  color: var(--text-muted);
  font-family: var(--font);
  font-size: 14px;
  font-weight: 500;
  padding: 10px 20px;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
  white-space: nowrap;
}
.admin-btn-ghost:hover { background: var(--border); color: var(--text); }

/* Was referenced by 15+ buttons (modal Cancels, Rates & Prices) but never
   defined — they rendered with the browser's default white styling. */
.admin-btn-secondary {
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  color: var(--text-muted);
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  padding: 8px 16px;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
  white-space: nowrap;
}
.admin-btn-secondary:hover {
  background: var(--surface-flat-2);
  color: var(--text);
}

.admin-btn-icon {
  background: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  padding: 6px 14px;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
  white-space: nowrap;
  flex-shrink: 0;
}
.admin-btn-icon:hover { background: var(--border); color: var(--text); border-color: var(--border-strong); }

.admin-btn-danger {
  background: none;
  border: 1px solid rgba(239,68,68,0.35);
  border-radius: var(--r-sm);
  color: #ef4444;
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  padding: 6px 12px;
  cursor: pointer;
  transition: background var(--t-fast);
  white-space: nowrap;
  flex-shrink: 0;
}
.admin-btn-danger:hover { background: rgba(239,68,68,0.1); }

/* ── Inline row ───────────────────────────────────────────────────────────── */
.admin-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.admin-input {
  flex: 1;
  min-width: 0;
}

.admin-form-error {
  color: var(--error);
  font-size: 13px;
  min-height: 18px;
  margin-top: 6px;
}

/* ── Toggle (active/inactive) ─────────────────────────────────────────────── */
.admin-toggle {
  position: relative;
  width: 42px;
  height: 24px;
  flex-shrink: 0;
}
.admin-toggle input { opacity: 0; width: 0; height: 0; }
.admin-toggle-track {
  position: absolute;
  inset: 0;
  background: var(--border-strong);
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: background var(--t-fast);
}
.admin-toggle input:checked + .admin-toggle-track { background: var(--accent); }
.admin-toggle-track::before {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  transition: transform var(--t-fast) var(--ease-out);
}
.admin-toggle input:checked + .admin-toggle-track::before { transform: translateX(18px); }

/* ── Modal ────────────────────────────────────────────────────────────────── */
.admin-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  z-index: 800;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0;
}
@media (min-width: 520px) {
  .admin-modal-overlay { align-items: center; padding: 24px; }
}

.admin-modal {
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  border-radius: 20px 20px 0 0;
  width: 100%;
  max-width: 480px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-card);
}
@media (min-width: 520px) {
  .admin-modal { border-radius: var(--r-xl); max-height: 70vh; }
}

.admin-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
  font-size: var(--text-title);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
  flex-shrink: 0;
}
/* h3-based modal titles inherit the same tier instead of a browser-default size */
.admin-modal-title { font-size: var(--text-title); font-weight: 700; letter-spacing: -0.01em; margin: 0; color: var(--text); }

.admin-modal-body {
  flex: 1;
  overflow-y: auto;
  padding: 12px 0;
}

.admin-modal-footer {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

/* ── Money privacy: blur $ figures until revealed (per-device) ───────────── */
.tm-money { transition: filter .12s ease; }
body.tm-private .tm-money {
  filter: blur(7px);
  cursor: pointer;
  user-select: none; -webkit-user-select: none;
}
body.tm-private .tm-money:hover { filter: blur(5px); }

/* ── Collapsible sections inside the Schedule task modal ─────────────────── */
.sch-acc {
  /* Same dark-ink/light-alpha mirror as the row hairlines above — dark pin
     at file end restores the exact white-alpha lift. */
  background: rgba(10, 11, 14, 0.03);
  border: 1px solid var(--border, #2a2a2a);
  border-radius: 8px;
  padding: 9px 11px;
}
.sch-acc[open] { padding-bottom: 11px; }
.sch-acc > summary {
  cursor: pointer;
  list-style: none;
  font-size: 12px;
  font-weight: 600;
  color: var(--text, #eee);
  display: flex;
  align-items: center;
  gap: 7px;
  user-select: none;
}
.sch-acc > summary::-webkit-details-marker { display: none; }
.sch-acc > summary::before {
  content: '▸';
  color: var(--text-dim, #888);
  transition: transform .15s ease;
}
.sch-acc[open] > summary::before { transform: rotate(90deg); }
.sch-acc .sch-acc-hint { font-weight: 400; color: var(--text-dim, #888); }

/* ── Project checkboxes in assign modal ──────────────────────────────────── */
.assign-project-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.assign-project-item:last-child { border-bottom: none; }
.assign-project-item input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--accent); flex-shrink: 0; }
.assign-project-label { font-size: 14px; color: var(--text); line-height: 1.4; }
/* A building nested under its mother (sub-projects, 2026-08-04) — indented,
   lighter. The mother's own row above it is a group toggle, not a checkbox
   for herself, when she has buildings (see _toggleMotherBuildings). */
.assign-building-item { padding-left: 44px; }
.assign-building-item .assign-project-label { color: var(--text-dim); font-size: 13px; }

/* ── Empty state ──────────────────────────────────────────────────────────── */
/* One component lift raises every silent "No X yet" table across the panel:
   the brand's authored isometric inbox illustration (assets/illustrations/,
   with the yellow arc motif) + generous space, so an empty table reads as an
   intentional, on-brand state — not an unfinished screen or a generic icon.
   Context-specific empties override --empty-art (see below). */
.admin-empty {
  padding: 44px 20px;
  text-align: center;
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1.5;
  --empty-art: url("/assets/illustrations/empty-inbox.svg");
}
.admin-empty::before {
  content: "";
  display: block;
  width: 148px;
  height: 92px;
  margin: 0 auto 14px;
  background: var(--empty-art) center / contain no-repeat;
  opacity: 0.92;
}
/* The --docs/--project/--done context modifiers were removed 2026-08-11: all
   62 .admin-empty call sites use the bare class, so they only ever rendered
   the default art above. The .ox-empty--docs/--project modifiers further down
   are the live ones — that is the component call sites actually reach for. */
/* Opt-out for empties that already render their own icon, or sit in tight
   inline contexts where the glyph would crowd. */
.admin-empty--bare::before { display: none; }
.admin-empty--bare { padding: 20px; }
/* Retry under a failed load (app review B7) — glove-sized. */
.admin-empty-retry { margin-top: 12px; min-height: 44px; padding: 0 18px; }
/* "How this works" — a long help paragraph folded under its one-line gist
   (app review P7). Native <details>; the summary is a glove-sized target. */
.help-more { margin-top: 2px; }
.help-more > summary { cursor: pointer; width: fit-content; padding: 4px 0; font-weight: 600; color: var(--accent-2); }
.help-more[open] > summary { margin-bottom: 2px; }
@media (pointer: coarse), (max-width: 860px) { .help-more > summary { padding: 13px 0; } }
/* Optional richer empty: a Lucide icon the call site provides + a hint line. */
.admin-empty-rich { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.admin-empty-rich .admin-empty-hint { font-size: 12.5px; color: var(--text-dim); }

/* ── Delivery cards ───────────────────────────────────────────────────────── */
.delivery-card {
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  padding: 16px 18px;
  margin-bottom: 12px;
}

.delivery-card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.delivery-status-pill {
  font-size: 12px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  white-space: nowrap;
  flex-shrink: 0;
}

.delivery-item-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-bottom: 10px;
  background: var(--surface-flat-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 2px 10px;
}

/* One item per line: label left, qty right */
.delivery-item-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 13px;
  color: var(--text);
  padding: 5px 0;
  border-bottom: 1px solid var(--border);
}
.delivery-item-row:last-child { border-bottom: none; }
.delivery-item-label { color: var(--text-muted); flex: 1; }
.delivery-item-row strong { font-weight: 700; white-space: nowrap; }

/* Other Materials free-text */
.delivery-item-other {
  font-size: 13px;
  color: var(--text-muted);
  padding: 6px 2px;
  line-height: 1.5;
}
.delivery-item-other span { color: var(--text); }

/* ── Submissions Tab ─────────────────────────────────────────────────────── */
.admin-filters {
  display: flex;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  flex-wrap: wrap;
}

.admin-select {
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  color: var(--text);
  border-radius: var(--r-md);
  padding: 8px 12px;
  font-size: 13px;
  font-family: var(--font);
  min-width: 180px;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out);
}
.admin-select:hover  { background: var(--surface-flat-2); }
.admin-select:focus  { outline: none; border-color: var(--focus); }

.sub-type-icon {
  font-size: 18px;
  flex-shrink: 0;
  width: 24px;
  text-align: center;
  opacity: 0.92;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
}
.sub-type-icon svg { width: 18px; height: 18px; }
/* Lucide icons injected into section/queue headers (replaced old emoji) */
.doc-section-icon svg { width: 18px; height: 18px; }
.doc-queue-icon svg { width: 16px; height: 16px; }
.doc-section-icon, .doc-queue-icon {
  display: inline-flex; align-items: center; justify-content: center;
}

.admin-role-badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 20px;
  background: rgba(245,158,11,0.15);
  color: var(--accent, #F89010);
  border: 1px solid rgba(245,158,11,0.3);
  margin-left: 8px;
  vertical-align: middle;
}

.sub-no-pdf {
  font-size: 12px;
  color: var(--text-dim);
  padding: 6px 12px;
}

/* ── Reports (By Project) — materials summary ────────────────────────────── */
.proj-report-prompt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  padding: 56px 20px;
  max-width: 380px;
  margin: 0 auto;
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1.5;
}
.proj-report-prompt svg { width: 42px; height: 42px; color: var(--text-dim); stroke-width: 1.4; }

/* KPI strip */
.pr2-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 12px;
  margin-bottom: 14px;
}
.pr2-kpi {
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  position: relative;
  overflow: hidden;
}
.pr2-kpi::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--accent);
}
.pr2-kpi--blue::before  { background: #3b82f6; }
.pr2-kpi--green::before { background: #22c55e; }
.pr2-kpi-label {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--text-muted); margin-bottom: 6px;
}
.pr2-kpi-value {
  font-family: var(--display); font-size: 26px; font-weight: 800; color: var(--text);
  line-height: 1.05; letter-spacing: -0.02em;
}
.pr2-kpi-sub { font-size: 12px; color: var(--text-muted); margin-top: 4px; }

/* Delivery-status card + segmented bar */
.pr2-status {
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  margin-bottom: 14px;
}
.pr2-status-head {
  display: flex; justify-content: space-between; align-items: center;
  gap: 12px; margin-bottom: 11px; flex-wrap: wrap;
}
.pr2-status-title {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--text-muted);
}
.pr2-status-next {
  font-size: 12px; color: var(--text-muted);
  display: inline-flex; align-items: center; gap: 6px;
}
.pr2-status-next b { color: var(--text); font-weight: 700; }
.pr2-bar {
  display: flex; height: 10px; border-radius: 6px; overflow: hidden;
  background: var(--surface-flat-3);
}
.pr2-bar-seg { height: 100%; min-width: 2px; }
.pr2-status-legend { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 12px; }
.pr2-leg { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text); }
.pr2-leg-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.pr2-leg b { font-weight: 700; }
.pr2-leg span { color: var(--text-muted); }

/* Materials sections — responsive card grid */
.pr2-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 12px;
}
.pr2-sec {
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  overflow: hidden;
  display: flex; flex-direction: column;
}
.pr2-sec--wide { grid-column: 1 / -1; }
.pr2-sec-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 11px 14px; background: var(--surface-flat-2);
  border-bottom: 1px solid var(--border);
}
.pr2-sec-title {
  font-size: 12px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--text);
  display: flex; align-items: center; gap: 9px;
}
.pr2-sec-title::before {
  content: ''; width: 8px; height: 8px; border-radius: 2px;
  background: var(--accent); flex: none;
}
.pr2-sec-chip {
  font-size: 11px; font-weight: 700; color: var(--text-muted);
  background: var(--surface-flat-3); border-radius: 20px; padding: 2px 9px;
  white-space: nowrap;
}
.pr2-sec-body { padding: 3px 14px 8px; }
.pr2-row {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 8px 0; font-size: 13.5px; border-bottom: 1px solid var(--border-subtle);
}
.pr2-row:last-child { border-bottom: none; }
.pr2-row span { color: var(--text-muted); }
.pr2-row strong { font-weight: 700; font-size: 14px; color: var(--text); white-space: nowrap; }
.pr2-other {
  font-size: 13px; color: var(--text); padding: 7px 0;
  border-bottom: 1px solid var(--border-subtle); line-height: 1.5;
}
.pr2-other:last-child { border-bottom: none; }

/* Section accent colours */
.pr2-sec--s10 .pr2-sec-title::before     { background: #818cf8; }
.pr2-sec--s15 .pr2-sec-title::before     { background: #38bdf8; }
.pr2-sec--s20 .pr2-sec-title::before     { background: #34d399; }
.pr2-sec--s25 .pr2-sec-title::before     { background: #fbbf24; }
.pr2-sec--s30 .pr2-sec-title::before     { background: #f472b6; }
.pr2-sec--special .pr2-sec-title::before { background: #a78bfa; }
.pr2-sec--mat .pr2-sec-title::before     { background: var(--accent); }
.pr2-sec--other .pr2-sec-title::before   { background: var(--text-dim); }

/* Footer actions */
.pr2-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 16px; }
.pr2-copy-btn {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13px; font-weight: 600; cursor: pointer;
  padding: 8px 14px; border-radius: var(--r-md);
  background: var(--surface-flat-2); border: 1px solid var(--border-strong);
  color: var(--text); transition: background .12s, border-color .12s;
}
.pr2-copy-btn:hover { background: var(--surface-flat-3); border-color: var(--text-dim); }
.pr2-copy-btn svg { width: 15px; height: 15px; }
.pr2-copy-btn.is-done { color: var(--success-ink); border-color: rgba(34,197,94,.4); }

.delivery-card-notes {
  font-size: 13px;
  color: var(--text-muted);
  font-style: italic;
  margin-bottom: 10px;
}

.delivery-card-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  border-top: 1px solid var(--border);
  padding-top: 12px;
  margin-top: 4px;
}

.delivery-status-select {
  flex: 1;
  background: var(--surface-flat-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  color: var(--text);
  font-family: var(--font);
  font-size: 13px;
  padding: 8px 12px;
  cursor: pointer;
}

/* ── Worker Cards ────────────────────────────────────────────────────────── */
.wcard-group-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-muted);
  margin-bottom: 10px;
}

/* Inactive workers read quiet, not broken: dimmed, solid border — a page
   of dashed boxes shouted louder than the active roster it sat under. */
.wcard--inactive { opacity: .62; }

/* Assign Foremans modal list */
.wassign-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 50vh;
  overflow-y: auto;
}
.wassign-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.wassign-row:hover { background: var(--surface-3); border-color: var(--border-strong); }
.wassign-row input[type=checkbox] {
  width: 18px;
  height: 18px;
  accent-color: #a855f7;
  cursor: pointer;
}
.wassign-name {
  flex: 1;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.wassign-role {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--accent-ink);
  background: rgba(91,141,238,0.15);
  border-radius: 4px;
  padding: 2px 6px;
}

/* ── Cert drag-and-drop zone ─────────────────────────────────────────────── */
.cert-drop-zone {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 2;
  min-width: 200px;
  padding: 9px 14px;
  border: 2px dashed var(--border-strong);
  border-radius: 10px;
  background: var(--surface-2);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
  user-select: none;
}
.cert-drop-zone:hover,
.cert-drop-zone--over {
  border-color: var(--accent);
  background: rgba(91,141,238,0.07);
}
.cert-drop-zone--chosen {
  border-color: #10b981;
  border-style: solid;
  background: rgba(16,185,129,0.07);
}
.cert-drop-icon { font-size: 16px; flex-shrink: 0; }
.cert-drop-label {
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cert-drop-zone--chosen .cert-drop-label { color: var(--text); font-weight: 600; }

.site-pname { text-transform: none; font-weight: 500; letter-spacing: 0; }
.ec-group-name { display: flex; align-items: baseline; gap: 4px; min-width: 0; }
.ec-group-pname { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ec-group-n, .ec-group-sub { flex: none; }
.ec-pick { max-width: 100%; min-width: 0; }
/* Transfer queue: a long site name wraps; both codes stay readable. */
.eq-move-site { overflow-wrap: anywhere; }

/* Manage modal — rental rate row. Info-tinted (cost information, not a
   warning): the two inputs are one value in two units, so they share a group. */
.eq-rate-row {
  margin-bottom: 16px;
  padding: 12px 14px;
  background: rgba(90,169,240,0.08);
  border: 1px solid rgba(90,169,240,0.3);
  border-radius: 8px;
}
.eq-rate-row .admin-label { color: var(--info); margin-bottom: 6px; }
.eq-rate-hint { font-size: 12px; color: var(--text-muted); margin-bottom: 10px; }
.eq-rate-inputs { display: flex; gap: 10px; flex-wrap: wrap; }
.eq-rate-field { position: relative; flex: 1; min-width: 140px; max-width: 200px; }
.eq-rate-field--28 { min-width: 160px; max-width: 220px; }
.eq-rate-cur, .eq-rate-unit {
  position: absolute; top: 50%; transform: translateY(-50%);
  color: var(--text-dim); font-weight: 600; pointer-events: none;
}
.eq-rate-cur  { left: 10px; }
.eq-rate-unit { right: 10px; font-size: 11px; }
.eq-rate-input {
  width: 100%;
  box-sizing: border-box;
  padding: 8px 44px 8px 24px;
  font-size: 14px;
  font-weight: 700;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--surface-2);
  color: var(--text);
  text-align: right;
  outline: none;
}
.eq-rate-input--28 { padding-right: 60px; }
.eq-rate-input:focus { border-color: var(--focus); }
.eq-rate-or { display: flex; align-items: center; color: var(--text-dim); font-size: 12px; font-weight: 600; }
.eq-rate-note { margin-top: 8px; font-size: 11px; color: var(--text-muted); line-height: 1.4; }

/* Delete danger button */
.admin-btn-danger {
  padding: 8px 14px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  background: transparent;
  border: 1px solid rgba(220,50,50,0.4);
  /* #e05555 is a one-off red (not --error/--error-bright) that fails AA as
     text on white (~3.2:1) — rewired to --error-ink; dark pinned below to
     keep this exact shade (T2 light sweep, 2026-08-05). */
  color: var(--error-ink);
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.admin-btn-danger:hover { background: rgba(220,50,50,0.12); }

/* ── Manage Item Modal qty grid ─────────────────────────────────────────── */
.iqm-grid {
  display: flex;
  flex-direction: column;
  gap: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  max-height: 360px;
  overflow-y: auto;
}

.iqm-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.iqm-row:last-child { border-bottom: none; }
.iqm-row:nth-child(even) { background: var(--surface-2); }

.iqm-site {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  letter-spacing: 0.04em;
  min-width: 70px;
}
/* "on site since …" under the site code — the allocation's start date. */
.iqm-since {
  display: block;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--text-dim);
}

.iqm-controls {
  display: flex;
  align-items: center;
  gap: 6px;
}

.iqm-step {
  width: 30px;
  height: 30px;
  border-radius: 6px;
  border: 1px solid var(--border-strong);
  background: var(--surface-flat);
  color: var(--text);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.1s;
}
.iqm-step:hover { background: var(--accent); color: var(--on-accent, #0a0b0e); border-color: var(--accent); }

.iqm-qty {
  width: 52px;
  text-align: center;
  font-size: 14px;
  font-weight: 700;
  padding: 5px 4px;
  border-radius: 6px;
  border: 1px solid var(--border-strong);
  background: var(--bg-0);
  color: var(--text);
}

.eq-modal-field { margin-bottom: 14px; }

.admin-label {
  display: block;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.admin-input {
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  padding: 9px 12px;
  outline: none;
  transition: border-color 0.15s;
}
.admin-input:focus { border-color: var(--focus); }

.admin-modal-footer {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  padding: 16px 20px;
  border-top: 1px solid var(--border);
}
.admin-btn-ghost {
  padding: 8px 16px;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  color: var(--text-muted);
  font-family: var(--font);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: color 0.12s, border-color 0.12s;
}
.admin-btn-ghost:hover { color: var(--text); border-color: var(--text-muted); }

/* ── Document sections ──────────────────────────────────────────────────── */
.doc-section {
  margin-bottom: 28px;
}
.doc-section-hdr {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  background: var(--surface-2);
  border-radius: 10px 10px 0 0;
  border: 1px solid var(--border);
  border-bottom: none;
}
.doc-section-icon { font-size: 18px; }
.doc-section-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  flex: 1;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}
.doc-section-count {
  background: var(--accent);
  color: var(--on-accent, #0a0b0e);
  font-size: 11px;
  font-weight: 700;
  border-radius: 20px;
  padding: 2px 8px;
  min-width: 24px;
  text-align: center;
}

/* List rows (non-photo types) */
.doc-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border: 1px solid var(--border);
  border-top: none;
  background: var(--surface-flat);
}
.doc-row:last-child { border-radius: 0 0 10px 10px; }
.doc-row-info { flex: 1; min-width: 0; }
.doc-row-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.doc-row-meta {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 2px;
}

/* Photo grid */
.doc-photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
  padding: 14px;
  border: 1px solid var(--border);
  border-top: none;
  border-radius: 0 0 10px 10px;
  background: var(--surface-flat);
}
.doc-photo-card {
  position: relative;
  background: var(--surface-2);
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--border);
  display: flex;
  flex-direction: column;
}
.doc-photo-thumb-wrap {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--surface-3, #111);
}
.doc-photo-thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.2s;
}
.doc-photo-thumb-wrap:hover .doc-photo-thumb { transform: scale(1.04); }
.doc-photo-info {
  padding: 8px 8px 4px;
  flex: 1;
}
.doc-photo-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.doc-photo-meta {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 2px;
}
.doc-photo-del {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: rgba(0,0,0,0.55);
  border: none;
  color: #fff;
  font-size: 13px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.15s;
  backdrop-filter: blur(4px);
}
.doc-photo-card:hover .doc-photo-del { opacity: 1; }

/* Edit button on a photo card — sits left of the delete button. */
.doc-photo-edit {
  position: absolute;
  top: 6px;
  right: 38px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: rgba(0,0,0,0.55);
  border: none;
  color: #fff;
  font-size: 12px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.15s;
  backdrop-filter: blur(4px);
}
.doc-photo-card:hover .doc-photo-edit { opacity: 1; }

/* ── Document upload notes textarea ─────────────────────────────────────── */
.doc-notes-input {
  width: 100%;
  resize: vertical;
  min-height: 72px;
  font-family: var(--font);
  font-size: 13px;
  line-height: 1.5;
  box-sizing: border-box;
}

.field-optional {
  font-size: 12px;
  font-weight: 400;
  color: var(--text-muted);
}

/* ── Document row enhancements ──────────────────────────────────────────── */
.doc-proj-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 12px;
  background: rgba(248,144,16,0.1);
  color: var(--accent-ink);
  border: 1px solid rgba(248,144,16,0.2);
  white-space: nowrap;
  margin-right: 2px;
}

.doc-row-notes {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 5px;
  line-height: 1.55;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ── Small action button (project row) ───────────────────────────────────── */
.admin-btn-sm {
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 600;
  font-family: var(--font);
  color: var(--text-muted);
  background: var(--surface-2, #1d1f26);
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
  white-space: nowrap;
}
.admin-btn-sm:hover { background: var(--border); color: var(--text); }

/* ── Crew modal rows ─────────────────────────────────────────────────────── */
.crew-modal-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
  gap: 12px;
}
.crew-modal-row:last-child { border-bottom: none; }
.crew-modal-info { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; }
.crew-modal-name { font-size: 14px; font-weight: 600; color: var(--text); }
.crew-modal-trade {
  font-size: 11px;
  color: var(--text-muted);
  background: var(--surface-2, #1d1f26);
  border: 1px solid var(--border);
  border-radius: 99px;
  padding: 2px 8px;
}

/* ── Prices Tab ──────────────────────────────────────────────────────────── */

/* Column templates — applied to both header and data rows */
.prices-grid-block      { grid-template-columns: 1fr 105px 105px 115px 80px 58px; }
.prices-grid-labor      { grid-template-columns: 1fr 130px 58px; }
.prices-grid-materials  { grid-template-columns: 1fr 58px 105px 105px 110px 58px; }
.prices-grid-surcharges { grid-template-columns: 1fr 90px 90px 58px; }
.prices-grid-bsv        { grid-template-columns: 1fr 54px 100px 90px 130px 90px 58px; }

/* Header row */
.prices-header {
  display: grid;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Data rows */
.prices-row {
  display: grid;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-top: none;
  background: var(--surface-flat);
  transition: background var(--t-fast);
}
.prices-row:hover { background: var(--surface-2); }
.prices-row:last-child { border-radius: 0 0 var(--r-sm) var(--r-sm); }

/* Editing state */
.prices-row--editing       { background: var(--surface-2); }
.prices-row--editing:hover { background: var(--surface-2); }

/* Cell: item name */
.prices-name {
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Cell: numeric value */
.prices-val {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Cell: unit badge (e.g. "ea", "LF", "yd3") */
.prices-unit-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: var(--r-pill);
  background: var(--surface-flat-3);
  color: var(--text-muted);
  border: 1px solid var(--border-strong);
  white-space: nowrap;
  text-align: center;
  justify-self: start;
}

/* Cell: applies-to label (surcharges) */
.prices-applies {
  font-size: 12px;
  color: var(--text-muted);
  text-align: center;
  white-space: nowrap;
}

/* Inline edit inputs */
.prices-input {
  width: 100%;
  min-width: 0;
  background: var(--bg-0);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  color: var(--text);
  font-family: var(--font);
  font-size: 13px;
  padding: 5px 8px;
  text-align: right;
  outline: none;
  box-sizing: border-box;
  transition: border-color var(--t-fast);
}
.prices-input:focus { border-color: var(--focus); }

/* Save / Cancel actions inside an editing row */
.prices-edit-actions {
  display: flex;
  gap: 5px;
  justify-content: flex-end;
  align-items: center;
}

.prices-save-btn {
  padding: 5px 11px !important;
  font-size: 12px !important;
}

/* Percentage input wrapper (surcharge edit) */
.prices-pct-wrap {
  display: flex;
  align-items: center;
  gap: 4px;
}

.prices-pct-sign {
  font-size: 13px;
  color: var(--text-muted);
  flex-shrink: 0;
}

/* ── Invite User modal (#inviteModal) — .adm-lbl/.adm-inp/.adm-sheet-footer
   are the only 3 survivors of a larger Tenders/GC modal system removed
   2026-08-06 (dead code sweep, T2 fence 2026-08-05 confirmed no other
   call site in js/ or *.html). Were hardcoded dark-only before any theme
   existed — tokenized here; dark pinned at file end to the exact original
   value (T2 light sweep, 2026-08-05). ────────────────────────────────── */
.adm-lbl {
  display: block;
  font-size: 11px; font-weight: 600;
  color: var(--text-muted); letter-spacing: .06em; text-transform: uppercase;
  margin-bottom: 6px;
}

/* Inputs */
.adm-inp {
  width: 100%; box-sizing: border-box;
  background: var(--surface-flat-2);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  color: var(--text); font-family: inherit; font-size: 14px;
  padding: 10px 13px; outline: none;
  transition: border-color .15s, box-shadow .15s;
  appearance: none; -webkit-appearance: none;
}
.adm-inp:focus {
  border-color: var(--focus);
  box-shadow: 0 0 0 3px var(--focus-ring);
}
.adm-inp::placeholder { color: var(--text-dim); }

/* Footer */
.adm-sheet-footer {
  display: flex; gap: 10px; justify-content: flex-end;
  padding: 14px 22px 18px;
  /* rgba(255,255,255,.07) IS --border's exact dark value — plain token,
     no dark pin needed. */
  border-top: 1px solid var(--border);
}

/* ── Document upload: drop zone ─────────────────────────────────────────────── */
.doc-drop-zone {
  border: 2px dashed var(--border-strong);
  border-radius: var(--r-lg);
  padding: 28px 20px 24px;
  text-align: center;
  cursor: default;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.doc-drop-zone.doc-drop-over {
  border-color: var(--accent);
  background: rgba(59,91,200,.07);
}
.doc-drop-icon { font-size: 32px; line-height: 1; margin-bottom: 8px; }
.doc-drop-text { font-size: 14px; font-weight: 600; color: var(--text); margin-bottom: 4px; }
.doc-drop-sub  { font-size: 12px; color: var(--text-muted); margin-bottom: 14px; }
.doc-drop-btns { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.doc-pick-btn  { cursor: pointer; font-size: 13px; padding: 7px 16px; }

/* ── Document queue ──────────────────────────────────────────────────────────── */
.doc-queue {
  margin-top: 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.doc-queue-hdr {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 14px;
  background: var(--surface-flat-2);
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
}
.doc-queue-clear {
  background: none; border: none; color: var(--text-dim);
  font-size: 11px; cursor: pointer; padding: 0; text-decoration: underline;
}
.doc-queue-clear:hover { color: var(--error); }
.doc-queue-item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 14px; border-bottom: 1px solid var(--border); font-size: 13px;
}
.doc-queue-item:last-child { border-bottom: none; }
.doc-queue-icon { font-size: 18px; flex-shrink: 0; }
.doc-queue-name {
  flex: 1; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; color: var(--text);
}
.doc-queue-size { font-size: 11px; color: var(--text-muted); flex-shrink: 0; }
.doc-queue-remove {
  background: none; border: none; color: var(--text-dim);
  font-size: 16px; line-height: 1; cursor: pointer; padding: 2px 4px;
  flex-shrink: 0; border-radius: 4px;
  transition: background var(--t-fast), color var(--t-fast);
}
.doc-queue-remove:hover { background: rgba(239,68,68,.12); color: var(--error-ink); }

/* Hide the native number-input spinner on inputs marked .no-spin (used by the
   rental-rate field where a /day suffix sits at the right edge of the input). */
.no-spin::-webkit-outer-spin-button,
.no-spin::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.no-spin { -moz-appearance: textfield; appearance: textfield; }

.dash-filter-select {
  padding: 8px 28px 8px 12px; font-size: 13px; font-weight: 500;
  /* --bg-input was never a real token (always fell through to the literal
     fallback in both themes) — this select (live in the Schedule tab) was
     rendering hardcoded near-black regardless of theme. Points at the real
     input-surface token now (T2 light sweep, 2026-08-05). */
  background: var(--surface-flat-2); color: var(--text);
  border: 1px solid var(--border, #2a2a2a); border-radius: 8px;
  cursor: pointer; max-width: 220px;
}

/* Foremans/People tab — role change <select> (js/admin/10-foremans.js).
   Same --bg-input bug as .dash-filter-select above: the token was never
   real, so this always rendered hardcoded near-black. Colors moved out of
   the inline style into this class so dark can be pinned (an inline style
   can't be targeted by a [data-theme] selector — it always wins over any
   external rule for the same property). T2 light sweep, 2026-08-05. */
.role-select { background: var(--surface-flat-2); color: var(--text); border: 1px solid var(--border); }

/* Schedule/Gantt toolbar pills (js/schedule.js) — Lock/Editing toggle, Undo,
   PDF export, Today. Backgrounds are low-alpha washes (rgba(...,.08-.22))
   that already read fine on a light surface (same formula as .ox-badge--*
   elsewhere) so they stay inline; only the TEXT color — chosen pale for
   readability against near-black — needed a light-safe twin. Dark pinned
   to the exact original pale shade (T2 light sweep, 2026-08-05).
   REGRESSION FIX (review round 2): every one of these is also
   `.admin-btn-sm`, whose own `:hover { color: var(--text) }` is a 2-class
   compound selector (specificity 0,2,0) — a bare single-class
   `.sched-pill--ok` (0,1,0) loses to it on hover in EVERY theme,
   deterministically (specificity beats source order outright; the base,
   non-hover state only "worked" before because of where in the file the
   rule sat). Every selector below is written as the SAME compound
   `.admin-btn-sm.sched-pill--X` (0,2,0 — ties the base hover rule, wins by
   being later in the file) plus its own explicit `:hover` twin
   (0,3,0 — unambiguously higher, no source-order dependency left at all). */
.admin-btn-sm.sched-pill--ok,
.admin-btn-sm.sched-pill--ok:hover   { color: var(--success-ink); }
.admin-btn-sm.sched-pill--warn,
.admin-btn-sm.sched-pill--warn:hover { color: var(--warning-ink); }
.admin-btn-sm.sched-pill--info,
.admin-btn-sm.sched-pill--info:hover { color: var(--info-ink); }
/* "Today" button: white-alpha bg + light-gray text — both fail on light
   (bg vanishes, text washes out), so both are replaced here. */
.admin-btn-sm.sched-pill--mu,
.admin-btn-sm.sched-pill--mu:hover   { background: var(--surface-flat-3); color: var(--text-muted); }

/* Schedule task modal — dependency-row and stage-row inputs (js/schedule.js
   #schDepsList / #schStagesList). background was var(--bg-input,#222) —
   never a real token, same bug as .dash-filter-select/.role-select above. */
.sched-input { background: var(--surface-flat-2); }
/* Stage card wrapper — was a bare white-alpha .03 lift, invisible on a
   light modal. Dark-ink mirror at the same alpha; dark pinned below. */
.sched-stage-card { background: rgba(10, 11, 14, 0.03); }

/* ── Schedule / Gantt ──────────────────────────────────────────────────────── */
/* Give the Gantt the full CONTENT column: lift .admin-main's 1200px cap while
   the Schedule tab is active. The old 96vw/viewport-centred breakout predates
   the fixed sidebar and shoved the panel underneath it. Browsers without
   :has() simply keep the 1200px column — still correct, just narrower. */
.admin-main:has(> #tab-schedule.active) { max-width: none; }
.gantt-toolbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 12px;
}
.gantt-zooms { display: inline-flex; border: 1px solid var(--border, #333); border-radius: 8px; overflow: hidden; }
.gantt-zoom {
  border: none; background: transparent; color: var(--text-dim, #9aa);
  padding: 6px 14px; font-size: 13px; font-weight: 600; cursor: pointer;
}
.gantt-zoom.active { background: var(--accent, #F89010); color: var(--on-accent, #0a0b0e); }

/* Schedule undo toast — transient confirmation bottom-centre */
.sch-toast {
  position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%) translateY(12px);
  background: var(--surface-flat-3, #23252c); color: var(--text, #eee);
  border: 1px solid var(--border-strong, rgba(255,255,255,0.1));
  box-shadow: var(--shadow-lg);
  padding: 11px 18px; border-radius: var(--r-pill, 999px);
  font-size: 13px; font-weight: 600; z-index: 9999;
  opacity: 0; pointer-events: none; transition: opacity var(--t-med) var(--ease-out), transform var(--t-med) var(--ease-out);
}
.sch-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.gantt-legend { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
/* Scoped view (job workspace, cleanup round) — count note for the tasks this
   filtered board is hiding (no project tag, so they only ever show on the
   global Schedule). Same small-muted-note weight as .jc-hint elsewhere. */
.gantt-scope-note { font-size: 12.5px; color: var(--text-muted); margin: -4px 0 12px; }
.gantt-leg { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--text-dim, #9aa); }
.gantt-leg i { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }

.gantt-scroll {
  overflow: auto; max-height: 80vh;
  border: 1px solid var(--border, #2a2a2a); border-radius: 10px;
  background: var(--surface, #131316);
}
.gantt-grid { position: relative; }

.gantt-head { display: flex; position: sticky; top: 0; z-index: 6; }
.gantt-corner {
  position: sticky; left: 0; z-index: 7; flex: 0 0 auto;
  background: var(--surface-2, #1b1b20); border-right: 1px solid var(--border, #2a2a2a);
  border-bottom: 1px solid var(--border, #2a2a2a);
  font-size: 11px; font-weight: 700; color: var(--text-dim, #9aa);
  display: flex; align-items: center; padding: 0 12px; text-transform: uppercase; letter-spacing: .04em;
}
.gantt-head-time { position: relative; height: 44px; background: var(--surface-2, #1b1b20); border-bottom: 1px solid var(--border, #2a2a2a); }
.gantt-months { position: absolute; inset: 0 0 auto 0; height: 22px; }
.gantt-month {
  position: absolute; top: 0; height: 22px; line-height: 22px;
  font-size: 11px; font-weight: 700; color: var(--text, #eee);
  border-left: 1px solid var(--border, #2a2a2a); padding-left: 6px;
  text-transform: uppercase; letter-spacing: .03em; white-space: nowrap; overflow: hidden;
}
.gantt-ticks { position: absolute; left: 0; right: 0; top: 22px; height: 22px; }
.gantt-tick {
  position: absolute; top: 0; height: 22px; line-height: 22px; text-align: center;
  font-size: 10px; color: var(--text-dim, #888);
}
/* Gantt hairlines/washes below were tuned for the obsidian gantt-scroll
   background and vanish on the new light one (T2 light sweep) — each
   converted to the dark-ink mirror, dark pinned at file end. Alphas raised
   2026-08-24 (Renan: task rows and week lines were too faint to follow). */
.gantt-tick--wk { border-left: 1px solid rgba(10,11,14,0.35); }

.gantt-row { display: flex; }
.gantt-row:nth-child(even) .gantt-track { background: rgba(10,11,14,0.02); }
.gantt-label {
  position: sticky; left: 0; z-index: 4; flex: 0 0 auto;
  background: var(--surface-2, #1b1b20);
  border-right: 1px solid var(--border, #2a2a2a); border-bottom: 1px solid rgba(10,11,14,0.18);
  padding: 5px 10px; display: flex; flex-direction: column; justify-content: center; overflow: hidden;
}
.gantt-label-title { font-size: 13px; font-weight: 600; line-height: 1.25; color: var(--text, #eee); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gantt-label-sub { font-size: 10.5px; line-height: 1.25; color: var(--text-dim, #888); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gantt-track {
  position: relative; flex: 0 0 auto; border-bottom: 1px solid rgba(10,11,14,0.18);
  /* Layer 1: Sunday shading (we don't work Sundays). Range starts on a Monday,
     so Sunday is day-index 6 of each 7-day week — shift the band by 6 days.
     Layer 2: weekly gridlines. */
  background-image:
    repeating-linear-gradient(to right, rgba(90,100,130,0.10) 0, rgba(90,100,130,0.10) var(--d), transparent var(--d), transparent var(--wk)),
    repeating-linear-gradient(to right, transparent 0, transparent calc(var(--wk) - 1px), rgba(10,11,14,0.22) var(--wk));
  background-position: calc(6 * var(--d)) 0, 0 0;
}
.gantt-label-dep { font-size: 10px; color: var(--warning-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Manual reorder arrows (custom sort mode) */
.gantt-reorder { position: absolute; top: 50%; right: 4px; transform: translateY(-50%); display: flex; flex-direction: column; gap: 1px; }
.gantt-reorder button {
  border: none; background: var(--surface-flat-3, #2a2a30); color: var(--text-dim, #9aa);
  width: 18px; height: 13px; line-height: 1; font-size: 8px; cursor: pointer; border-radius: 3px; padding: 0;
}
.gantt-reorder button:hover { background: var(--accent, #F89010); color: var(--on-accent, #0a0b0e); }
/* Saved-schedule selector group */
.gantt-sched { display: inline-flex; align-items: center; gap: 6px; }
.gantt-sched select { max-width: 220px; }
.gantt-arrows { position: absolute; top: 0; z-index: 2; pointer-events: none; overflow: visible; }
/* Dependency connector: light gray-blue read fine on the dark gantt-scroll
   bg but nearly vanish on the new light one (3:1 non-text UI floor fails at
   ~2.3:1) — darkened for light, dark pinned at file end to the exact
   original (T2 light sweep, 2026-08-05). */
.gantt-arrows path { fill: none; stroke: rgba(70,78,95,0.75); stroke-width: 1.5; }
.gantt-arrowhead { fill: rgba(70,78,95,0.85); }
.gantt-bar {
  position: absolute; top: 7px; height: calc(100% - 14px); min-height: 22px;
  border-radius: 6px; cursor: grab; touch-action: none; overflow: hidden;
  box-shadow: 0 1px 3px rgba(0,0,0,0.4); display: flex; align-items: center;
  user-select: none;
}
.gantt-bar.dragging { cursor: grabbing; opacity: .9; box-shadow: 0 3px 10px rgba(0,0,0,0.6); }
.gantt-bar-fill { position: absolute; left: 0; top: 0; bottom: 0; background: rgba(0,0,0,0.28); }
.gantt-bar-txt {
  position: relative; z-index: 1; padding: 0 9px; font-size: 11.5px; font-weight: 600;
  color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-shadow: 0 1px 1px rgba(0,0,0,0.4);
}
.gantt-bar-h { position: absolute; top: 0; bottom: 0; width: 8px; z-index: 2; cursor: ew-resize; }
.gantt-bar-h--l { left: 0; }
.gantt-bar-h--r { right: 0; }
.gantt-today { position: absolute; top: 0; bottom: 0; width: 2px; background: #ef4444; z-index: 3; pointer-events: none; }
/* Split task (stop & continue): transparent container holding coloured period
   pieces, with a dashed connector across the pauses. */
.gantt-bar--split { background: transparent !important; box-shadow: none; overflow: visible; display: block; }
.gantt-seg {
  position: absolute; top: 0; bottom: 0; border-radius: 6px; overflow: hidden;
  box-shadow: 0 1px 3px rgba(0,0,0,0.4); display: flex; align-items: center;
}
.gantt-seg-link {
  position: absolute; top: 50%; left: 0; height: 0; z-index: 0;
  border-top: 1.5px dashed var(--text-dim, #8a8d96); transform: translateY(-0.75px);
}
.gantt-today::before {
  content: '▼'; position: absolute; top: -2px; left: -5px; font-size: 10px; color: #ef4444;
}
@media (max-width: 640px) {
  .gantt-toolbar { gap: 8px; }
  .gantt-legend { width: 100%; order: 5; }
}
/* Generic dashboard card */
.dash-card {
  background: var(--surface-flat, #161819);
  border: 1px solid var(--border, #2a2a2a);
  border-radius: 12px;
  padding: 18px 20px;
  margin-bottom: 16px;
  box-shadow: var(--shadow-sm);
}

/* ── Loading skeletons (shimmer) — premium loading state for the dashboard ── */
@keyframes dash-shimmer { 0% { background-position: -450px 0; } 100% { background-position: 450px 0; } }
.dash-skel {
  /* Live loading shimmer (Today dashboard, js/admin/99-today.js) — white-
     alpha shimmer is nearly invisible on a light card; dark-ink mirror for
     light, dark pinned at file end (T2 light sweep, 2026-08-05). */
  background: linear-gradient(90deg, rgba(10,11,14,0.04) 25%, rgba(10,11,14,0.09) 37%, rgba(10,11,14,0.04) 63%);
  background-size: 900px 100%;
  animation: dash-shimmer 1.4s linear infinite;
  border-radius: var(--r-sm);
  display: block;
}
.dash-card-hdr {
  display: flex; flex-wrap: wrap; justify-content: space-between;
  align-items: baseline; gap: 10px;
  margin-bottom: 14px;
}
.dash-card-title { margin: 0; font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
.dash-card-sub  { font-size: 12px; color: var(--text-muted, #888); font-weight: 500; }

/* ── Company Settings modal ───────────────────────────────────────────────── */
.settings-logo-row { display: flex; align-items: center; gap: 16px; }
.settings-logo-preview {
  width: 64px; height: 64px; flex: none;
  background: var(--surface-flat-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
.settings-logo-preview img { width: 100%; height: 100%; object-fit: contain; }
.settings-logo-preview span { font-size: 10.5px; color: var(--text-dim); text-align: center; padding: 4px; }
.settings-color-row { display: flex; align-items: center; gap: 8px; }
.settings-color-swatch {
  width: 34px; height: 34px; flex: none;
  padding: 0; border: 1px solid var(--border); border-radius: var(--r-sm, 6px);
  background: none; cursor: pointer;
}

/* ── Forms builder (Fase B, FB2) ──────────────────────────────────────────── */
.fb-row { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.fb-row-icon { font-size: 20px; flex: none; }
.fb-row-main { flex: 1; min-width: 0; }
.fb-row-title { font-weight: 700; font-size: 14.5px; }
.fb-row-sub { font-size: 12.5px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-badge { flex: none; font-size: 11px; font-weight: 700; border-radius: 999px; padding: 3px 10px; }
.fb-badge-default { background: var(--surface-flat-2); color: var(--text-muted); }
.fb-badge-custom { background: rgba(74,222,128,.14); color: #4ade80; }
.fb-badge-draft { background: rgba(248,144,16,.14); color: var(--accent, #F89010); }

.fb-ed-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 8px; }
.fb-ed-title { font-weight: 800; font-size: 17px; }
.fb-ed-sub { font-size: 12.5px; color: var(--text-muted); }
.fb-ed-actions { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

/* Version history panel (fbToggleHistory) */
.fb-history {
  margin: 4px 0 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-flat-2);
  padding: 4px 0;
}
.fb-history-row {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 14px;
  font-size: 13px; color: var(--text-muted);
}
.fb-history-row + .fb-history-row { border-top: 1px solid var(--border); }
.fb-history-v { font-weight: 700; color: var(--text); min-width: 34px; }
.fb-history-src { flex: 1; }
.fb-history-when { color: var(--text-dim); }
.fb-history-act { min-width: 70px; text-align: right; }

.fb-sec-title { font-weight: 700; font-size: 13px; letter-spacing: .03em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 10px; }
.fb-field-row { display: flex; align-items: center; gap: 10px; padding: 7px 8px; border-radius: 8px; }
.fb-field-row:hover { background: var(--surface-flat); }
.fb-field-row--section { margin-top: 8px; border-top: 1px solid var(--border); padding-top: 10px; }
.fb-field-row--section .fb-field-label { text-transform: uppercase; font-size: 12px; letter-spacing: .04em; color: var(--text-muted); }
.fb-move { display: flex; gap: 2px; flex: none; }
.fb-field-label { flex: 1; min-width: 0; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-req { color: var(--error, #ef4444); margin-left: 3px; }
.fb-chip { flex: none; font-size: 10.5px; font-weight: 700; color: var(--text-dim); background: var(--surface-flat-2); border-radius: 6px; padding: 2px 8px; }

/* ── WYSIWYG builder canvas (Onda 3b) ──────────────────────────────────────── */
.fb-ed-grid { display: grid; grid-template-columns: 200px minmax(0,1fr) minmax(0,1fr); gap: 18px; align-items: start; margin-top: 16px; }
.fb-inspector { font-size: 13px; }
.fb-insp-back { background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 12px; padding: 0 0 12px; }
.fb-insp-back:hover { color: var(--accent-ink); }
.fb-pdf-wrap { position: sticky; top: 12px; }
.fb-pdf { background: var(--surface-flat); border: 1px solid var(--border); border-radius: 12px; min-height: 520px; overflow: hidden; position: relative; }
.fb-pdf-frame { width: 100%; height: 640px; border: 0; display: block; background: #fff; }
.fb-pdf--loading::after { content: ''; position: absolute; top: 12px; right: 12px; width: 16px; height: 16px; border: 2px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: fb-spin .7s linear infinite; }
.fb-pdf-err { padding: 24px 20px; font-size: 12px; color: var(--text-dim); text-align: center; line-height: 1.6; }
@keyframes fb-spin { to { transform: rotate(360deg); } }
@media (max-width: 1100px) { .fb-ed-grid { grid-template-columns: 1fr; } .fb-pdf-wrap { position: static; } }
.fb-canvas-bar { font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--text-dim); margin-bottom: 12px; display: flex; align-items: center; gap: 10px; }
.fb-canvas-bar::before, .fb-canvas-bar::after { content: ''; height: 1px; flex: 1; background: var(--border); }
/* the canvas is a centred "form sheet" so it reads as the real form */
.fb-canvas { background: var(--surface-flat-2); border: 1px solid var(--border); border-radius: 16px; padding: 24px 24px 28px; max-width: 560px; margin: 0 auto; min-height: 260px; box-shadow: 0 18px 50px -28px rgba(0,0,0,.7); }
.fb-cv-head { display: flex; align-items: center; gap: 13px; padding-bottom: 15px; margin-bottom: 6px; border-bottom: 1px solid var(--border); }
.fb-cv-head-ic { width: 40px; height: 40px; border-radius: 11px; background: var(--accent-soft); display: flex; align-items: center; justify-content: center; font-size: 20px; flex: none; }
.fb-cv-head-t { font-size: 16px; font-weight: 700; color: var(--text); }
.fb-cv-head-s { font-size: 11.5px; color: var(--text-dim); margin-top: 1px; }
.fb-cv-field { position: relative; padding: 11px 12px 11px 30px; border: 1px solid transparent; border-radius: 10px; margin-top: 4px; cursor: pointer; transition: background .12s, border-color .12s; }
.fb-cv-field:hover { background: rgba(10,11,14,.025); } /* T2 light sweep — dark pinned at file end */
.fb-cv-field--sel { border-color: var(--accent); background: var(--accent-soft); }
.fb-cv-grip { position: absolute; left: 9px; top: 13px; color: transparent; cursor: grab; font-size: 13px; line-height: 1; transition: color .12s; }
.fb-cv-field:hover .fb-cv-grip, .fb-cv-field--sel .fb-cv-grip { color: var(--text-dim); }
.fb-cv-body { pointer-events: none; }
.fb-cv-body .field-group { margin: 0; }
.fb-cv-tools { position: absolute; top: -13px; right: 10px; display: flex; gap: 1px; background: var(--surface-flat-2); border: 1px solid var(--accent); border-radius: 8px; padding: 2px; box-shadow: 0 4px 12px -4px rgba(0,0,0,.5); }
.fb-cv-tool { border: none; background: transparent; cursor: pointer; padding: 3px 6px; border-radius: 6px; color: var(--text); font-size: 13px; line-height: 1; }
.fb-cv-tool:hover { background: var(--accent); color: #201800; }
.fb-cv-tool--del:hover { background: var(--error, #ef4444); color: #fff; }
.fb-cv-dragging { opacity: .45; }
.fb-cv-ph { display: flex; align-items: center; gap: 10px; border: 1.5px dashed var(--border); border-radius: 10px; padding: 13px 14px; }
.fb-cv-ph-lab { font-size: 13px; font-weight: 600; color: var(--text); }
.fb-cv-ph-note { margin-left: auto; font-size: 10px; text-transform: uppercase; letter-spacing: .1em; color: var(--text-dim); }
.fb-cv-drop { height: 3px; background: var(--accent); border-radius: 3px; margin: 4px 0 4px 26px; box-shadow: 0 0 10px var(--accent-soft); }

/* palette + props side rails */
.fb-props-h { font-size: 10.5px; text-transform: uppercase; letter-spacing: .14em; color: var(--text-dim); margin-bottom: 12px; font-weight: 700; }
.fb-pf { margin-bottom: 13px; }
.fb-pf label { display: block; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-dim); margin-bottom: 5px; }
.fb-pf-tog { display: flex; align-items: center; gap: 8px; font-size: 13px; margin-bottom: 13px; color: var(--text); cursor: pointer; }
.fb-props-empty, .fb-props-note { font-size: 12px; color: var(--text-dim); line-height: 1.55; }
.fb-pal-i { display: flex; align-items: center; gap: 9px; width: 100%; text-align: left; background: var(--surface-flat); border: 1px solid var(--border); border-radius: 9px; padding: 8px 11px; margin-top: 6px; cursor: grab; font-size: 13px; color: var(--text); transition: border-color .12s, background .12s; }
.fb-pal-i:hover { border-color: var(--accent); background: var(--surface-flat-2); }
.fb-pal-g { flex: none; width: 20px; text-align: center; color: var(--text-dim); font-size: 13px; }
.fb-pal-i:hover .fb-pal-g { color: var(--accent-ink); }
@media (max-width: 980px) { .fb-ed-grid { grid-template-columns: 1fr; } .fb-canvas { max-width: none; } }
.fb-field-actions { flex: none; display: flex; gap: 4px; align-items: center; }
.fb-icon-btn {
  background: none; border: 1px solid transparent; border-radius: 6px; cursor: pointer;
  color: var(--text-muted); font-size: 13px; padding: 3px 7px; line-height: 1.2;
  min-width: 28px; min-height: 26px;
}
.fb-icon-btn:hover { background: var(--surface-flat-2); color: var(--text); }
.fb-icon-btn:disabled { opacity: .3; cursor: default; }
.fb-lock { font-size: 13px; opacity: .55; padding: 0 5px; }

.fb-details { margin-top: 14px; }
.fb-details > summary { cursor: pointer; font-weight: 700; font-size: 14px; padding: 2px 0; }
.fb-hint { font-weight: 400; font-size: 12px; color: var(--text-dim); margin-left: 8px; }
.fb-list-row { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.fb-list-row .admin-input { flex: 1; }
.fb-check { flex: none; display: flex; align-items: center; }
.fb-check-inline { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; color: var(--text-muted); margin: 4px 10px 0 0; cursor: pointer; }
.fb-add-line { background: none; border: 1px dashed var(--border-strong); border-radius: 8px; color: var(--text-muted); font-size: 12.5px; padding: 7px 12px; cursor: pointer; margin-top: 10px; font-family: var(--font); }
.fb-add-line:hover { color: var(--text); border-color: var(--text-dim); }
.fb-tg-sec { border: 1px solid var(--border); border-radius: 10px; padding: 12px; margin-top: 12px; }
.fb-tg-sec-head { display: flex; gap: 8px; }
.fb-tg-sec-head .admin-input { font-weight: 700; }
.fb-flra-task { border: 1px solid var(--border); border-radius: 10px; padding: 12px; margin-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.fb-hazard-checks { display: flex; flex-wrap: wrap; }

/* ── Onboarding checklist (dashboard, field + admin) ──────────────────────── */
.onboard-card {
  background: var(--surface-flat);
  border: 1px solid var(--accent, #F89010);
  border-radius: var(--r-lg, 14px);
  padding: 16px 18px;
  margin-bottom: 16px;
}

/* Standing condition the admin should fix, not a transient error: same shell
   as the onboarding card, muted border so it never shouts over real data. */
.admin-warn-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: var(--surface-flat);
  border: 1px solid var(--border-strong, rgba(255,255,255,.16));
  border-left: 3px solid var(--accent, #F89010);
  border-radius: var(--r-lg, 14px);
  padding: 14px 16px;
  margin-bottom: 16px;
}
.admin-warn-card strong { font-size: 13.5px; font-weight: 700; color: var(--text); }
.admin-warn-card span   { font-size: 13px; line-height: 1.5; color: var(--text-muted); }
.onboard-head { display: flex; align-items: center; justify-content: space-between; gap: 8px 12px; flex-wrap: wrap; }
.onboard-title { font-size: 14px; font-weight: 700; color: var(--text); }
.onboard-tools { display: flex; align-items: center; gap: 6px 14px; flex-wrap: wrap; }
.onboard-videos { font-size: 13px; font-weight: 600; color: var(--accent-2); text-decoration: none; }
.onboard-videos:hover { text-decoration: underline; }
.onboard-dismiss {
  background: none; border: none; color: var(--text-dim); cursor: pointer;
  font-size: 13px; padding: 4px 6px; line-height: 1;
}
.onboard-dismiss:hover { color: var(--text); }
/* One row per step: number, what to do, the button that opens where it is done.
   Below ~520px the button drops under the text, full width, for a thumb. */
.onboard-list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; }
.onboard-item {
  display: flex; align-items: center; gap: 8px 12px; flex-wrap: wrap;
  padding: 10px 0; border-top: 1px solid var(--border-subtle);
}
.onboard-item .oi-box {
  width: 22px; height: 22px; flex: none; border-radius: 6px;
  border: 1.5px solid var(--border-strong);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800; color: var(--text-muted);
}
.onboard-item .oi-txt { flex: 1 1 0; min-width: 0; }
.onboard-item .oi-t { font-size: 13.5px; font-weight: 600; color: var(--text); }
.onboard-item .oi-s { font-size: 12px; color: var(--text-muted); margin-top: 2px; overflow-wrap: anywhere; }
.onboard-item .cw-btn { flex: none; text-decoration: none; }
.onboard-item.done .oi-box { background: var(--success, #22c55e); border-color: var(--success, #22c55e); color: #08130a; }
.onboard-item.done .oi-t { color: var(--text-dim); text-decoration: line-through; }
/* Half done: the invite is out, or the foreman is in without a project. */
.onboard-item.half .oi-box { border-color: var(--accent, #F89010); color: var(--accent-ink, var(--text)); }
.onboard-item.half .oi-s { color: var(--warning-ink, var(--text-muted)); }
@media (max-width: 520px) {
  .onboard-item .cw-btn { flex: 1 1 100%; justify-content: center; min-height: 44px; }
  .onboard-videos, .onboard-dismiss { min-height: 44px; display: inline-flex; align-items: center; }
}
#homeJoinedBanner:not(:empty) { margin-bottom: 12px; }

/* ══════════════════════════════════════════════════════════════════════════
   TODAY / OVERVIEW dashboard (js/admin/99-today.js) — the admin landing.
   Redesign v2 (OrdinexAdmin.dc.html): KPI row, compliance hero (O-ring gauge
   + coverage bars on blueprint ground), needs-attention, by-foreman board,
   weekly chart, recent submissions. Reuses .dash-skel for loading shimmer.
   ══════════════════════════════════════════════════════════════════════════ */
#todayDash { display: flex; flex-direction: column; gap: 16px; }

/* KPI row */
.td-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }
.td-kpi {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: 17px 18px;
}
.td-kpi-top { display: flex; align-items: center; justify-content: space-between; }
.td-kpi-label {
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-muted);
}
.td-kpi-ic svg { width: 17px; height: 17px; stroke-width: 1.85px; }
.td-kpi-ic--mu { color: var(--text-muted); }
.td-kpi-ic--ok { color: var(--success); }
.td-kpi-ic--ac { color: var(--accent-ink); }
.td-kpi-value {
  font-family: var(--display);
  font-size: 30px; font-weight: 800; letter-spacing: -0.03em;
  color: var(--text);
  margin-top: 10px;
}
.td-kpi-value--ok { color: var(--success); }
.td-kpi-value--ac { color: var(--accent-ink); }
.td-kpi-value--info { color: var(--info); }
.td-kpi-value--warn { color: var(--warning-ink); }
.td-kpi-foot { font-size: 12px; font-weight: 500; color: var(--text-dim); margin-top: 2px; }

/* Grids */
.td-grid-hero { display: grid; grid-template-columns: 1.15fr 1fr; gap: 16px; }
@media (max-width: 980px) {
  .td-grid-hero { grid-template-columns: 1fr; }
}

/* Shared card */
.td-card {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-2xl);
  padding: 20px;
}
.td-card--flush { padding: 0; overflow: hidden; }
.td-card-head {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 13px; font-weight: 700; color: var(--text);
  margin-bottom: 14px;
}
.td-card--flush .td-card-head { margin-bottom: 0; }
.td-card-head--pad { padding: 16px 20px; border-bottom: 1px solid var(--border); }
.td-viewall {
  background: none; border: none; cursor: pointer;
  font-family: var(--font); font-size: 12px; font-weight: 700; color: var(--accent-ink);
}
.td-viewall:hover { color: var(--accent-ink); }

/* Production per week — all sites. Reuses the field hero's .fh-pulse-*
   chart styles (css/styles.css) so both boards draw the identical
   instrument; only the card chrome and the head spacing are local. */
.td-pulse-card .fh-pulse-head { margin-bottom: 10px; }
.td-pulse-card .fh-pulse-kicker { color: var(--text); }
@media (max-width: 560px) {
  /* Stacked head: 3 legend chips beside the title squeeze the chart on a
     phone-width admin window. Chips go to a wrapping row underneath. */
  .td-pulse-card .fh-pulse-head { flex-direction: column; align-items: stretch; gap: 10px; }
  .td-pulse-card .fh-pulse-now { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 6px 16px; }
  /* Own line: inline after the chips it reads as another chip. */
  .td-pulse-card .fh-pulse-legend-cap { flex-basis: 100%; }
}

/* Compliance hero — blueprint ground + glow, gauge + bars */
.td-hero {
  position: relative;
  background-color: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-2xl);
  overflow: hidden;
  padding: 22px;
}
.td-hero-glow {
  position: absolute; top: -100px; right: -60px;
  width: 300px; height: 300px;
  background: radial-gradient(circle, rgba(248, 144, 16, 0.10), transparent 62%);
  pointer-events: none;
}
.td-hero-in { position: relative; display: flex; gap: 24px; align-items: center; flex-wrap: wrap; }
.td-hero-ring { display: flex; flex-direction: column; align-items: center; gap: 9px; flex-shrink: 0; }
.td-hero-ring-cap {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-muted);
}
.td-ring-pct   { font: 800 39px var(--display); letter-spacing: -0.03em; fill: var(--text); }
.td-ring-cap   { font: 600 10px var(--font); letter-spacing: 0.06em; fill: var(--text-muted); }
.td-ring-empty { font: 700 15px var(--font); fill: var(--text-muted); }
.td-hero-bars { flex: 1; min-width: 200px; display: flex; flex-direction: column; gap: 12px; }
.td-hero-bars-title { font-size: 13px; font-weight: 700; color: var(--text); }
.td-cov-line { display: flex; justify-content: space-between; font-size: 12px; font-weight: 600; margin-bottom: 5px; }
.td-cov-line span:first-child { color: var(--text-muted); }
.td-cov-val--ok { color: var(--success); }
.td-cov-val--ac { color: var(--accent-ink); }
.td-cov-val--mu { color: var(--text-dim); }
.td-cov-track { height: 7px; border-radius: var(--r-pill); background: var(--surface-flat-3); overflow: hidden; }
.td-cov-fill { height: 100%; border-radius: var(--r-pill); }
.td-cov-fill--ok { background: var(--success); }
.td-cov-fill--ac { background: var(--accent); }
.td-cov-fill--mu { background: var(--surface-flat-3); }

/* Needs attention */
.td-att-count {
  font-size: 11px; font-weight: 700; color: var(--error);
  background: rgba(239, 68, 68, 0.12);
  padding: 4px 10px; border-radius: var(--r-pill);
}
.td-att-list { display: flex; flex-direction: column; gap: 9px; }
.td-att-row, .td-att-clear {
  display: flex; align-items: center; gap: 12px;
  padding: 12px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.td-att-ic {
  width: 32px; height: 32px; flex-shrink: 0;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
}
.td-att-ic svg { width: 16px; height: 16px; stroke-width: 1.85px; }
.td-att-ic--err  { background: rgba(239, 68, 68, 0.14);  color: var(--error-ink); }
.td-att-ic--warn { background: rgba(245, 158, 11, 0.14); color: var(--warning-ink); }
.td-att-ic--ok   { background: rgba(34, 197, 94, 0.14);  color: var(--success); }
.td-att-txt   { flex: 1; min-width: 0; }
.td-att-title { font-size: 13px; font-weight: 600; color: var(--text); }
.td-att-meta  { font-size: 11.5px; font-weight: 500; color: var(--text-muted); margin-top: 1px; }
.td-att-btn {
  flex-shrink: 0;
  padding: 7px 13px;
  background: var(--surface-flat-2);
  border: 1px solid var(--border-strong);
  color: var(--text);
  border-radius: var(--r-md);
  font-family: var(--font); font-size: 12px; font-weight: 700;
  cursor: pointer;
  transition: border-color var(--t-fast), color var(--t-fast);
}
.td-att-btn--err:hover  { border-color: #f87171; color: var(--error-ink); }
.td-att-btn--warn:hover { border-color: #fbbf24; color: var(--warning-ink); }

/* By project — today */
.td-f-cols, .td-f-row {
  display: grid;
  grid-template-columns: 1.1fr 1.7fr 76px 76px;
  gap: 0 14px;
  align-items: center;
  padding: 12px 20px;
}
.td-f-cols {
  padding-top: 10px; padding-bottom: 10px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border);
}
.td-f-cols .td-f-cell { text-align: center; }
.td-f-row { border-bottom: 1px solid var(--border-subtle); }
.td-f-row:last-child { border-bottom: none; }
.td-f-who { display: flex; align-items: center; gap: 10px; min-width: 0; }
.td-f-av {
  width: 28px; height: 28px; flex-shrink: 0;
  border-radius: 50%;
  color: #0a0b0e;
  font-family: var(--display); font-size: 10px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}
.td-f-name {
  font-size: 13px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  display: flex; align-items: center; gap: 6px;
}
.td-f-cell { display: flex; justify-content: center; }

/* Middle column: what each site submitted today */
.td-f-subcell { min-width: 0; display: flex; align-items: center; }
.td-f-sub {
  display: inline-flex; align-items: center; gap: 8px; min-width: 0;
  font-size: 12.5px; color: var(--text-muted);
}
.td-f-sub svg { width: 15px; height: 15px; flex-shrink: 0; stroke-width: 1.85px; color: var(--text-dim); }
.td-f-sub-type { font-weight: 600; color: var(--text); white-space: nowrap; }
.td-f-sub-meta { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.td-f-sub-more {
  flex-shrink: 0;
  font-size: 10.5px; font-weight: 700;
  background: rgba(248, 144, 16, 0.13); color: var(--accent-ink);
  border-radius: var(--r-pill); padding: 1px 7px;
}
/* --text-faint is decorative-only (fails AA as text in both themes, always
   has — flagged in task-1-report.md) but "no submission today" is real
   label text a foreman reads. LIGHT-only fix: dark is pinned back to
   --text-faint at the file's end so it stays exactly v485 (T2 light
   sweep, 2026-08-05) — see the two sibling sites (.td-cell--na below,
   .cm-cell further down) fixed the same way. */
.td-f-nosub { color: var(--text-dim); font-size: 12.5px; }
.td-subtag {
  font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-muted); background: var(--surface-flat-3);
  border-radius: var(--r-sm); padding: 1px 5px;
}
.td-cell {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%;
}
.td-cell svg { width: 14px; height: 14px; stroke-width: 2.4; }
.td-cell--yes { background: rgba(34, 197, 94, 0.16); color: var(--success); }
.td-cell--no  { background: rgba(239, 68, 68, 0.15); color: var(--error-ink); }
.td-cell--na  { background: none; color: var(--text-dim); } /* LIGHT-only fix; dark pinned back to --text-faint at file's end */
.td-noassign { font-size: 13px; color: var(--text-muted); padding: 16px 20px; }

/* On phones the board keeps Project + status; today's submissions column
   hides (the Activity tab has the full list). */
@media (max-width: 720px) {
  .td-f-cols, .td-f-row { grid-template-columns: 1.6fr 76px 76px; }
  .td-f-subcell { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   SHARED redesign-v2 components (ox-*) — toolbar, table card, day groups,
   badges, icon buttons, drawer, empty states. Used across the admin tabs.
   ══════════════════════════════════════════════════════════════════════════ */

/* Toolbar: search + selects + count */
.ox-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.ox-toolbar-spacer { flex: 1; }
.ox-count { font-size: 12.5px; font-weight: 600; color: var(--text-muted); }
.ox-search { position: relative; }
.ox-search svg, .ox-search .anav-icon {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--text-dim); pointer-events: none;
}
.ox-search input {
  width: 250px;
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  color: var(--text);
  border-radius: 9px;
  padding: 9px 12px 9px 34px;
  font-family: var(--font); font-size: 13px; font-weight: 500;
  outline: none;
}
.ox-search input:focus { border-color: var(--focus); }
.ox-search input::placeholder { color: #5f636d; }
.ox-select {
  appearance: none;
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  color: var(--text);
  border-radius: 9px;
  padding: 9px 32px 9px 13px;
  font-family: var(--font); font-size: 13px; font-weight: 500;
  cursor: pointer; outline: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%237a7d87' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  color-scheme: dark;
  /* Option text (e.g. long project names) must never push the picker past
     its container — on 375px phones it ran off the right edge. */
  max-width: 100%;
}
.ox-select:focus { border-color: var(--focus); }
/* Text inputs/areas that borrow .ox-select for the border look must NOT
   inherit the picker chevron — every Settings field read as a dropdown. */
input.ox-select, textarea.ox-select {
  background-image: none;
  padding-right: 13px;
  cursor: text;
}

/* Table card + day group headers */
.ox-tablecard {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow: hidden;
}
.ox-dayhead {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 18px;
  background: var(--accent-soft);
  border-bottom: 1px solid var(--border);
  border-left: 2px solid var(--accent);
}
.ox-dayhead span:first-child {
  font-family: var(--display);
  font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--accent-ink);
}
.ox-dayhead span:last-child { font-size: 11px; font-weight: 600; color: var(--text-dim); }

/* Status badge — tones map to real states, never decoration */
.ox-badge {
  display: inline-flex; align-items: center; gap: 6px;
  justify-self: start;
  font-size: 11px; font-weight: 700;
  padding: 5px 10px; border-radius: var(--r-pill);
  white-space: nowrap;
}
.ox-badge svg { width: 12px; height: 12px; stroke-width: 2.4; }
.ox-badge--ok   { background: rgba(34, 197, 94, 0.12);  color: var(--success); }
.ox-badge--ac   { background: rgba(248, 144, 16, 0.13); color: var(--accent-ink); }
.ox-badge--warn { background: rgba(245, 158, 11, 0.13); color: var(--warning-ink); }
.ox-badge--err  { background: rgba(239, 68, 68, 0.13);  color: var(--error-ink); }
.ox-badge--mu   { background: var(--surface-flat-2);    color: var(--text-muted); }
.ox-badge--info { background: rgba(90, 169, 240, 0.14);  color: var(--info); }

/* Contracts list — shared Ref/Subject/(Project)/Date/Status table, used by
   Change Orders, RFI, Submittals and EWO (OrdinexContracts.dc.html). The
   5-col form includes Project; tabs that gate on a single project first
   (Change Orders, RFI) use --noproj to drop that redundant column. */
.ctr-card { background: var(--surface-flat); border: 1px solid var(--border); border-radius: 14px; overflow: hidden; }
.ctr-card-hdr { padding: 14px 18px; font-size: 13px; font-weight: 700; color: var(--text); border-bottom: 1px solid var(--border); }
.ctr-table-head, .ctr-row {
  display: grid; grid-template-columns: 100px 1.6fr 1.2fr 1fr 130px; gap: 12px; align-items: center;
}
.ctr-table--noproj .ctr-table-head, .ctr-table--noproj .ctr-row { grid-template-columns: 100px 2fr 1fr 130px; }
.ctr-table-head { padding: 10px 18px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-dim); border-bottom: 1px solid var(--border); }
/* Row hairline/hover below tuned for the dark row bg — dark-ink mirror for
   light, dark pinned at file end (T2 light sweep, 2026-08-05). */
.ctr-row { padding: 13px 18px; border-bottom: 1px solid rgba(10,11,14,.04); cursor: pointer; transition: background var(--t-fast); }
.ctr-row:last-child { border-bottom: none; }
.ctr-row:hover { background: rgba(10,11,14,.025); }
.ctr-ref { font-size: 12px; font-weight: 700; color: var(--accent-ink); white-space: nowrap; }
.ctr-subject { font-size: 13px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctr-project, .ctr-date { font-size: 12.5px; font-weight: 500; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctr-row .ox-badge { justify-self: start; }
.ctr-row-actions { display: flex; gap: 6px; justify-self: end; }

/* People table (Foremen / Workers, OrdinexAdminCrew.dc.html) — shares the
   row/head chrome above but its own 6-col grid (name|projects|certs|last
   active|today|actions); the reference has no actions column, but the real
   role/sub/assign controls can't just disappear, so they get one. */
.ppl-table-head, .ppl-row { display: grid; grid-template-columns: 1.7fr 1.1fr 90px 100px 90px 230px; gap: 12px; align-items: center; }
.ppl-table-head { padding: 10px 18px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-dim); border-bottom: 1px solid var(--border); }
.ppl-row { padding: 12px 18px; border-bottom: 1px solid rgba(10,11,14,.04); } /* T2 light sweep — dark pinned at file end */
.ppl-row:last-child { border-bottom: none; }
.ppl-name-wrap { display: flex; align-items: center; gap: 10px; min-width: 0; }
.ppl-avatar { width: 34px; height: 34px; border-radius: 50%; flex: 0 0 auto; display: flex; align-items: center; justify-content: center; font: 700 12px var(--display); color: #0a0b0e; }
.ppl-name-col { min-width: 0; }
.ppl-name { font-size: 13.5px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ppl-sub { font-size: 11px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ppl-cell { font-size: 12.5px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ppl-actions { display: flex; align-items: center; gap: 6px; justify-self: end; flex-wrap: wrap; justify-content: flex-end; }

/* Icon button (32px square, quiet) */
.ox-iconbtn {
  width: 32px; height: 32px; flex-shrink: 0;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.ox-iconbtn:hover { color: var(--text); border-color: var(--border-strong); }
.ox-iconbtn svg { width: 15px; height: 15px; stroke-width: 1.85px; }

/* Buttons */
/* A disabled .ox-btn had NO style of its own, so it rendered identically to a
   live one — a primary button sitting there in full accent orange, inviting a
   click that does nothing. 35-submissions.js had been papering over it with an
   inline opacity for its "No PDF on file" button; this puts the rule where it
   belongs, for every disabled button in the admin. */
.ox-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.ox-btn:disabled:hover { background: var(--surface-flat); border-color: var(--border-strong); }
.ox-btn--primary:disabled:hover { background: var(--accent); border-color: var(--accent); }

.ox-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 14px;
  background: var(--surface-flat);
  border: 1px solid var(--border-strong);
  color: var(--text);
  border-radius: var(--r-input);
  font-family: var(--font); font-size: 13px; font-weight: 700;
  cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.ox-btn:hover { background: var(--surface-flat-2); }
.ox-btn svg { width: 15px; height: 15px; stroke-width: 1.85px; }
.ox-btn--primary {
  flex: 1;
  background: var(--accent);
  border: none;
  color: var(--on-accent);
  font-family: var(--display); font-weight: 800;
}
.ox-btn--primary:hover { background: var(--accent-bright); }
.ox-btn--primary svg { stroke-width: 2.2; }
.ox-btn--danger {
  background: rgba(239, 68, 68, 0.10);
  border-color: rgba(239, 68, 68, 0.30);
  color: var(--error-ink);
}
.ox-btn--danger:hover { background: rgba(239, 68, 68, 0.16); }

/* Empty state (dashed card, per reference) */
.ox-empty {
  text-align: center;
  padding: 64px 20px;
  background: var(--bg-1);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-xl);
}
.ox-empty-title { font-family: var(--display); font-size: 16px; font-weight: 700; color: var(--text); }
.ox-empty-hint { font-size: 13px; color: var(--text-muted); margin-top: 6px; }
.ox-empty-btn {
  margin-top: 14px;
  background: var(--accent-soft);
  color: var(--accent-ink);
  border: 1px solid var(--accent-ring);
  font-family: var(--display); font-size: 13px; font-weight: 700;
  padding: 9px 16px; border-radius: 9px;
  cursor: pointer;
}
/* Authored isometric art for a high-traffic .ox-empty (same asset family as
   .admin-empty) — opt-in via a modifier so the many bare .ox-empty call
   sites elsewhere in the panel are untouched. Only the two modifiers that
   markup actually applies survive (2026-08-11 sweep): --inbox and --done
   went out with the empties nothing rendered. */
.ox-empty--docs::before,
.ox-empty--project::before {
  content: "";
  display: block;
  width: 148px; height: 92px;
  margin: 0 auto 14px;
  background: var(--empty-art) center / contain no-repeat;
  opacity: 0.92;
}
.ox-empty--docs    { --empty-art: url("/assets/illustrations/empty-no-docs.svg"); }
.ox-empty--project { --empty-art: url("/assets/illustrations/empty-no-project.svg"); }

/* Right drawer (440px, overlay + blur) */
.ox-drawer-overlay {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(6, 7, 10, 0.6);
  backdrop-filter: blur(3px);
  display: flex; justify-content: flex-end;
}
.ox-drawer {
  width: 440px; max-width: 92%;
  height: 100%;
  background: var(--bg-1);
  border-left: 1px solid var(--border-strong);
  box-shadow: -30px 0 80px -20px rgba(0, 0, 0, 0.7);
  display: flex; flex-direction: column;
  overflow: auto;
  animation: ox-drawer-in 0.2s var(--ease-out);
}
@keyframes ox-drawer-in { from { transform: translateX(24px); opacity: 0.4; } to { transform: none; opacity: 1; } }
.ox-drawer-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 14px;
  padding: 22px 22px 18px;
  border-bottom: 1px solid var(--border);
}
.ox-drawer-id { display: flex; gap: 13px; min-width: 0; }
.ox-drawer-ic {
  width: 44px; height: 44px; flex-shrink: 0;
  border-radius: 11px;
  background: var(--accent-soft);
  color: var(--accent-ink);
  display: flex; align-items: center; justify-content: center;
}
.ox-drawer-ic svg { width: 20px; height: 20px; stroke-width: 1.85px; }
.ox-drawer-title { font-family: var(--display); font-size: 18px; font-weight: 800; letter-spacing: -0.02em; color: var(--text); }
.ox-drawer-sub { font-size: 11px; font-weight: 500; color: var(--text-dim); margin-top: 2px; }
.ox-drawer-main { padding: 20px 22px; flex: 1; }
.ox-meta {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  margin-bottom: 16px;
}
.ox-meta-cell { background: var(--surface-flat); padding: 12px 14px; }
.ox-meta-k {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-dim); margin-bottom: 3px;
}
.ox-meta-v { font-size: 13px; font-weight: 700; color: var(--text); }
.ox-drawer-strow { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; }
.ox-drawer-note {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 15px;
  font-size: 13px; font-weight: 500; line-height: 1.6;
  color: var(--text-muted);
}
.ox-drawer-foot {
  padding: 16px 22px;
  border-top: 1px solid var(--border-strong);
  display: flex; gap: 10px;
}

/* ── Submissions tab (sx-*) ── */
.sx-cols, .sx-row {
  display: grid;
  grid-template-columns: 44px minmax(180px, 1.4fr) 1fr 1fr 100px 140px 92px;
  align-items: center;
  padding: 13px 18px;
}
/* Phone widths: the 7-column grid crushed into merged header words and
   overlapping avatar/status (gauntlet 2026-08-08) — stack each row as a
   two-line card instead and drop the column header entirely. */
@media (max-width: 560px) {
  .sx-cols { display: none; }
  .sx-row {
    grid-template-columns: 44px minmax(0, 1fr) auto;
    grid-template-areas:
      "ic form act"
      "ic who  status"
      "ic proj time";
    row-gap: 4px;
    padding: 12px 14px;
  }
  .sx-ic     { grid-area: ic; }
  .sx-form   { grid-area: form; }
  .sx-who    { grid-area: who; }
  .sx-proj   { grid-area: proj; }
  .sx-time   { grid-area: time; justify-self: end; }
  .sx-act    { grid-area: act; }
  .sx-row .ox-badge { grid-area: status; justify-self: start; }
}
.sx-cols {
  padding-top: 12px; padding-bottom: 12px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border);
}
/* T2 light sweep (2026-08-05) — dark-ink mirror, dark pinned at file end. */
.sx-row {
  border-bottom: 1px solid rgba(10, 11, 14, 0.04);
  cursor: pointer;
  transition: background var(--t-fast);
}
.sx-row:hover { background: rgba(10, 11, 14, 0.025); }
.sx-row:last-child { border-bottom: none; }
.sx-ic {
  width: 32px; height: 32px;
  border-radius: 9px;
  background: var(--surface-flat-2);
  color: var(--accent-ink);
  display: flex; align-items: center; justify-content: center;
}
.sx-ic svg { width: 16px; height: 16px; stroke-width: 1.85px; }
.sx-form { min-width: 0; padding-right: 10px; }
.sx-form-name {
  display: block;
  font-size: 14px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sx-form-sub { display: block; font-size: 11px; font-weight: 500; color: var(--text-dim); }
.sx-who {
  display: flex; align-items: center; gap: 9px; min-width: 0; padding-right: 10px;
  font-size: 13px; font-weight: 500; color: var(--text-muted);
}
.sx-who span:last-child { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sx-who .td-f-av { width: 26px; height: 26px; font-size: 10px; }
.sx-proj {
  font-size: 13px; font-weight: 500; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding-right: 10px;
}
.sx-time { font-size: 13px; font-weight: 500; color: var(--text-muted); }
.sx-act { display: flex; justify-content: flex-end; gap: 6px; }
.sx-moved {
  display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 999px;
  font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted); background: var(--surface-flat); border: 1px solid var(--border);
  cursor: help; vertical-align: middle;
}
.sx-moved-note {
  display: flex; gap: 10px; align-items: flex-start; margin-top: 12px; padding-top: 12px;
  border-top: 1px dashed var(--border); color: var(--text);
}
.sx-moved-note svg { width: 16px; height: 16px; flex: none; margin-top: 2px; color: var(--text-muted); }
.sx-move { margin-top: 16px; display: flex; flex-direction: column; gap: 8px; }
.sx-move .ox-select { width: 100%; }
.sx-move-hint { font-size: 12px; line-height: 1.55; color: var(--text-muted); }
/* Re-file hours (2026-10-19): the foreman's Activity bar (.ts-activity-* from
   styles.css, which loads first) inside the drawer, plus the "After re-file"
   table. At 375px the drawer is 92% of the phone and the bar has its own
   padding and border: seven boxes come out ~33px, not the 39px the field strip
   was cut for ('General' alone needs 38px), so the day grid wraps to 4 + 3
   there; the table scrolls sideways rather than squeezing. */
.sx-refile .ts-activity-bar { margin-bottom: 0; }
@media (max-width: 480px) {
  .sx-refile .ts-activity-days-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.sx-refile-preview { overflow-x: auto; }
.sx-refile-table { border-collapse: collapse; font-size: 12px; min-width: 100%; }
.sx-refile-table th, .sx-refile-table td {
  padding: 5px 8px; text-align: right; white-space: nowrap; border-bottom: 1px solid var(--border);
}
.sx-refile-table th:first-child, .sx-refile-table td:first-child { text-align: left; }
.sx-refile-table th { font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); }
.sx-refile-total { font-size: 12px; font-weight: 600; margin-top: 6px; }
.sx-refile-total--bad, .sx-refile-warn { color: var(--error-ink); }
.sx-general {
  display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 999px;
  font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted); background: var(--surface-flat); border: 1px solid var(--border);
  cursor: help; vertical-align: middle;
}
/* A production report whose numbers wait for a missing item (R3): it needs the office. */
.sx-general.sx-waiting { color: var(--error-ink); border-color: currentColor; }
.sx-moved-note.sx-waiting-note svg { color: var(--error-ink); }
.sx-moved-note .sx-undo { margin-left: 6px; padding: 2px 8px; min-height: 0; font-size: 12px; vertical-align: middle; }
.sx-mail-owed { display: inline-flex; align-items: center; margin-left: 6px; color: var(--warning-ink); vertical-align: middle; cursor: help; }
.sx-mail-owed svg { width: 14px; height: 14px; }
.sx-lock { display: inline-flex; align-items: center; padding: 8px; color: var(--text-dim); cursor: help; }
.sx-lock svg { width: 16px; height: 16px; }

@media (max-width: 900px) {
  .sx-cols, .sx-row { grid-template-columns: 44px minmax(140px, 1.4fr) 1fr 100px 92px; }
  .sx-proj, .sx-time { display: none; }
  .sx-cols div:nth-child(4), .sx-cols div:nth-child(5) { display: none; }
}

/* CTA button (toolbar primary — not the flex:1 drawer variant) */
.ox-btn--cta {
  background: var(--accent);
  border: none;
  color: var(--on-accent);
  font-family: var(--display); font-weight: 800;
  padding: 10px 15px;
}
.ox-btn--cta:hover { background: var(--accent-bright); }
.ox-btn--cta svg { stroke-width: 2.2; }

/* ── Actions tab (ca-*) — corrective action cards ── */
.ca-list { display: flex; flex-direction: column; gap: 10px; }
.ca-card {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: 13px;
  padding: 15px 18px;
  display: flex; align-items: center; gap: 15px; flex-wrap: wrap;
}
.ca-card--closed { opacity: 0.72; }
.ca-ic {
  width: 38px; height: 38px; flex-shrink: 0;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
}
.ca-ic svg { width: 17px; height: 17px; stroke-width: 1.85px; }
.ca-ic--ac  { background: rgba(248, 144, 16, 0.12); color: var(--accent-ink); }
.ca-ic--err { background: rgba(239, 68, 68, 0.13);  color: var(--error-ink); }
.ca-ic--ok  { background: rgba(34, 197, 94, 0.12);  color: var(--success); }
.ca-main { flex: 1; min-width: 220px; }
.ca-title {
  font-size: 14px; font-weight: 600; color: var(--text);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.ca-pr {
  font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 2px 7px; border-radius: var(--r-pill);
}
.ca-pr--err  { background: rgba(239, 68, 68, 0.13);  color: var(--error-ink); }
.ca-pr--warn { background: rgba(245, 158, 11, 0.13); color: var(--warning-ink); }
.ca-pr--mu   { background: var(--surface-flat-2);    color: var(--text-muted); }
.ca-meta { font-size: 12px; font-weight: 500; color: var(--text-muted); margin-top: 2px; }
.ca-owner {
  display: flex; align-items: center; gap: 8px; flex-shrink: 0;
  font-size: 12.5px; font-weight: 500; color: var(--text-muted);
}
.ca-av {
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--surface-flat-3);
  color: var(--text);
  font-family: var(--display); font-size: 10px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}
.ca-due { flex-shrink: 0; font-size: 12px; font-weight: 600; }
.ca-due--ac  { color: var(--text-muted); }
.ca-due--err { color: var(--error-ink); }
.ca-due--ok  { color: var(--success); }
.ca-complete {
  flex-shrink: 0;
  padding: 9px 15px;
  background: var(--accent);
  color: var(--on-accent);
  border: none; border-radius: 9px;
  font-family: var(--display); font-size: 12px; font-weight: 800;
  cursor: pointer;
  transition: background var(--t-fast);
}
.ca-complete:hover { background: var(--accent-bright); }

/* ── By Project (bp-*) — the GC folder view ── */
.bp-list { display: flex; flex-direction: column; gap: 14px; }
.bp-card {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: 15px;
  overflow: hidden;
}
.bp-head {
  width: 100%;
  display: flex; align-items: center; gap: 15px;
  padding: 16px 20px;
  background: transparent; border: none;
  cursor: pointer; text-align: left;
  font-family: var(--font);
  transition: background var(--t-fast);
}
.bp-head:hover { background: rgba(10, 11, 14, 0.02); } /* T2 light sweep — dark pinned at file end */
.bp-ic {
  width: 40px; height: 40px; flex-shrink: 0;
  border-radius: 11px;
  background: var(--surface-flat-2);
  color: var(--accent-ink);
  display: flex; align-items: center; justify-content: center;
}
.bp-ic svg { width: 18px; height: 18px; stroke-width: 1.85px; }
.bp-title { flex: 1; min-width: 0; }
.bp-name { display: block; font-size: 14.5px; font-weight: 700; color: var(--text); }
.bp-sub { display: block; font-size: 11.5px; font-weight: 500; color: var(--text-dim); margin-top: 1px; }
.bp-stat { text-align: right; flex-shrink: 0; }
.bp-stat-n { display: block; font-family: var(--display); font-size: 17px; font-weight: 800; color: var(--text); }
.bp-stat-l { display: block; font-size: 10px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
.bp-chev { color: var(--text-dim); display: flex; flex-shrink: 0; transition: transform 0.15s var(--ease-out); }
.bp-chev svg { width: 18px; height: 18px; }
.bp-chev--open { transform: rotate(180deg); }
.bp-body { border-top: 1px solid var(--border); padding: 16px 20px; }
.bp-folders {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 10px;
}
.bp-folder {
  display: flex; align-items: center; gap: 11px;
  padding: 12px 13px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  cursor: pointer; text-align: left;
  font-family: var(--font);
  transition: border-color var(--t-fast);
}
.bp-folder:hover { border-color: var(--accent-ring); }
.bp-folder > svg, .bp-folder > i { color: var(--accent-ink); flex-shrink: 0; }
.bp-folder svg { width: 17px; height: 17px; stroke-width: 1.85px; }
.bp-folder-txt { flex: 1; min-width: 0; }
.bp-folder-name {
  display: block;
  font-size: 12.5px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bp-folder-count { display: block; font-size: 10.5px; font-weight: 500; color: var(--text-dim); }
.bp-materials { margin-top: 16px; }
.bp-mat-label {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 10px;
}

/* ── Compliance tab (cr-*) ── */
.ox-date { padding: 8px 12px; }
.cr-score-grid { display: grid; grid-template-columns: 1fr 1.5fr; gap: 16px; }
@media (max-width: 980px) { .cr-score-grid { grid-template-columns: 1fr; } }
.cr-hero {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center;
}
.cr-hero-glow {
  position: absolute; top: -80px; left: 50%; transform: translateX(-50%);
  width: 280px; height: 280px;
  background: radial-gradient(circle, rgba(248, 144, 16, 0.12), transparent 62%);
  pointer-events: none;
}
.cr-hero-in { position: relative; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.cr-hero-cap { font-size: 13px; font-weight: 500; color: var(--text-muted); }
.cr-hero-cap b { color: var(--text); font-weight: 700; }
.cr-pill {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11.5px; font-weight: 700;
  padding: 6px 12px; border-radius: var(--r-pill);
}
.cr-pill svg { width: 13px; height: 13px; stroke-width: 2.2; }
.cr-pill--ok   { background: rgba(34, 197, 94, 0.12);  color: var(--success); }
.cr-pill--warn { background: rgba(245, 158, 11, 0.13); color: var(--warning-ink); }
.cr-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-content: start; }
@media (max-width: 640px) { .cr-tiles { grid-template-columns: 1fr; } }
.cr-grid2 { display: grid; grid-template-columns: 1.3fr 1fr; gap: 16px; }
@media (max-width: 980px) { .cr-grid2 { grid-template-columns: 1fr; } }
.cr-counts { padding: 6px 20px 14px; }
.cr-counts .td-noassign { padding: 10px 0; }

/* Evidence pack promo — light-sweep miss (2026-08-05): this was the one
   card left on a hardcoded obsidian gradient after the T2/LT sweeps, so
   light theme rendered --text (near-black) on a near-black surface —
   invisible. Base rule now themes like .td-card (white surface, ink
   text via --text/--text-muted, already correct); the exact original
   dark gradient is pinned verbatim below under [data-theme="dark"]. */
.cr-pack {
  position: relative;
  background: var(--surface-flat);
  border: 1px solid var(--accent-ring);
  border-radius: var(--r-2xl);
  padding: 22px;
  overflow: hidden;
}
.cr-pack::after {
  content: "";
  position: absolute; top: -60px; right: -40px;
  width: 200px; height: 200px;
  background: radial-gradient(circle, rgba(248, 144, 16, 0.16), transparent 62%);
  pointer-events: none;
}
.cr-pack-ic {
  width: 44px; height: 44px;
  border-radius: 12px;
  background: var(--accent);
  color: var(--on-accent);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 14px;
}
.cr-pack-ic svg { width: 20px; height: 20px; stroke-width: 2px; }
.cr-pack-title { font-family: var(--display); font-size: 18px; font-weight: 800; letter-spacing: -0.02em; color: var(--text); }
.cr-pack-p { margin: 8px 0 16px; font-size: 13px; font-weight: 500; line-height: 1.6; color: var(--text-muted); }
.cr-pack-btn {
  width: 100%;
  padding: 13px;
  background: var(--accent);
  color: var(--on-accent);
  border: none; border-radius: var(--r-lg);
  font-family: var(--display); font-size: 14px; font-weight: 800;
  cursor: pointer;
  transition: background var(--t-fast);
  position: relative;
}
.cr-pack-btn:hover:not(:disabled) { background: var(--accent-bright); }
.cr-pack-btn:disabled { opacity: 0.45; cursor: not-allowed; }

/* Evidence rows */
.cr-ev-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border-subtle);
}
.cr-ev-row:last-child { border-bottom: none; }
.cr-ev-main { flex: 1; min-width: 0; }
.cr-ev-name { font-size: 13.5px; font-weight: 600; color: var(--text); display: flex; align-items: center; gap: 7px; }
.cr-ev-lock { width: 13px; height: 13px; color: var(--text-dim); }
.cr-ev-name svg { width: 13px; height: 13px; }
.cr-ev-meta { font-size: 12px; font-weight: 500; color: var(--text-muted); margin-top: 1px; }
.cr-ev-nopdf { font-size: 12px; color: var(--text-dim); padding: 5px 10px; }

/* ── Deliveries tab (dx-*) ── */
.dx-pills { display: flex; gap: 8px; flex-wrap: wrap; }
.dx-pill {
  padding: 8px 14px;
  border-radius: var(--r-pill);
  border: 1px solid var(--border-strong);
  background: var(--surface-flat);
  color: var(--text-muted);
  font-family: var(--font); font-size: 12.5px; font-weight: 700;
  cursor: pointer;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.dx-pill:hover { color: var(--text); }
.dx-pill--on {
  background: var(--accent-soft);
  border-color: var(--accent-ring);
  color: var(--accent-ink);
}
.dx-cols, .dx-row {
  display: grid;
  grid-template-columns: 52px 1.5fr 1.1fr 1fr 130px 130px 34px;
  align-items: center;
  padding: 13px 18px;
}
.dx-cols {
  padding-top: 12px; padding-bottom: 12px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border);
}
/* T2 light sweep (2026-08-05) — dark-ink mirror, dark pinned at file end. */
.dx-row {
  border-bottom: 1px solid rgba(10, 11, 14, 0.04);
  cursor: pointer;
  transition: background var(--t-fast);
}
.dx-row:hover { background: rgba(10, 11, 14, 0.025); }
.dx-main { min-width: 0; padding-right: 10px; }
.dx-site {
  display: block;
  font-size: 13.5px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dx-po { display: block; font-size: 11px; font-weight: 500; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dx-window { font-size: 12.5px; font-weight: 500; color: var(--text); }
.dx-chev { color: var(--text-dim); display: flex; justify-content: center; transition: transform 0.15s var(--ease-out); }
.dx-chev svg { width: 16px; height: 16px; }
.dx-row--open .dx-chev { transform: rotate(180deg); }
.dx-detail {
  padding: 4px 18px 16px 70px;
  border-bottom: 1px solid rgba(10, 11, 14, 0.04); /* T2 light sweep — dark pinned at file end */
  cursor: default;
}
.dx-actions { display: flex; gap: 8px; align-items: center; margin-top: 12px; flex-wrap: wrap; }
.dx-cat-summary { cursor: pointer; font-weight: 700; font-size: 13.5px; color: var(--text); }
.dx-cat-hint { font-weight: 400; color: var(--text-dim); font-size: 12px; }
@media (max-width: 900px) {
  .dx-cols, .dx-row { grid-template-columns: 52px 1.5fr 130px 130px 34px; }
  .dx-cols div:nth-child(3), .dx-cols div:nth-child(4),
  .dx-row .sx-proj { display: none; }
  .dx-detail { padding-left: 18px; }
}

/* Packing slips waiting for the office — top of Deliveries. One card per
   slip: photo, who/when/note, then the two decisions. */
.dx-slip {
  display: grid; grid-template-columns: 64px minmax(0, 1fr) auto; align-items: center; gap: 14px;
  padding: 12px var(--row-pad-x); border-top: 1px solid var(--border-subtle);
}
.dx-slip-thumb {
  width: 64px; height: 64px; border-radius: 8px; object-fit: cover;
  border: 1px solid var(--border); background: var(--surface-flat-2);
}
.dx-slip-thumb--none { display: flex; align-items: center; justify-content: center; color: var(--text-dim); }
.dx-slip-thumb--none svg { width: 22px; height: 22px; }
.dx-slip-body { min-width: 0; }
.dx-slip-note { display: block; margin-top: 3px; font-size: 12px; color: var(--text-2); white-space: pre-line; overflow-wrap: anywhere; }
.dx-slip-acts { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.dx-slip-acts .ox-btn { min-height: 44px; white-space: nowrap; }
@media (max-width: 640px) {
  .dx-slip { grid-template-columns: 64px minmax(0, 1fr); }
  .dx-slip-acts { grid-column: 1 / -1; }
  .dx-slip-acts .ox-btn { flex: 1 1 0; }
}

/* Edit Delivery modal, two modes (openDeliveryEdit / openSlipEntry). Slip
   mode puts the photo beside the item list on a desk, above it on a phone. */
#deliveryEditModal .admin-modal[data-mode="edit"] .dx-slip-only,
#deliveryEditModal .admin-modal[data-mode="slip"] .dx-edit-only { display: none !important; }
#deliveryEditModal .admin-modal[data-mode="slip"] { max-width: 1040px; max-height: 92vh; }
#deliveryEditModal .admin-modal[data-mode="slip"] .dx-edit-grid {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 18px; align-items: start;
}
.dx-slip-meta { margin: 0 0 8px; font-size: 13px; color: var(--text); }
.dx-slip-photos { display: flex; flex-direction: column; gap: 10px; max-height: 64vh; overflow-y: auto; }
.dx-slip-photo img {
  display: block; width: 100%; height: auto; border-radius: 8px;
  border: 1px solid var(--border); background: var(--surface-flat-2);
}
@media (max-width: 760px) {
  #deliveryEditModal .admin-modal[data-mode="slip"] .dx-edit-grid { grid-template-columns: 1fr; }
  .dx-slip-photos { max-height: 46vh; }
}

/* The slip's item search box (_delivRenderItems): the results open under the
   box, grouped like the old select, every row a 48 px target (gloves). */
.dx-pick { position: relative; margin-top: 8px; }
.dx-pick input[type="search"] { width: 100%; min-height: 44px; font-size: 14px; }
.dx-pick-list {
  margin-top: 4px; max-height: 320px; overflow-y: auto; overscroll-behavior: contain;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface-flat);
}
.dx-pick-list[hidden] { display: none; }
.dx-pick-group {
  position: sticky; top: 0; padding: 6px 12px; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim);
  background: var(--surface-flat-2); border-bottom: 1px solid var(--border-subtle);
}
.dx-pick-opt {
  display: block; width: 100%; min-height: 48px; padding: 8px 12px; border: 0;
  border-bottom: 1px solid var(--border-subtle); background: none; color: var(--text);
  font: inherit; font-size: 14px; text-align: left; overflow-wrap: anywhere; cursor: pointer;
}
.dx-pick-opt:last-child { border-bottom: 0; }
.dx-pick-opt:hover, .dx-pick-opt.is-active { background: var(--surface-flat-2); }
.dx-pick-create { font-weight: 700; color: var(--accent-ink); }
.dx-old-free { margin-top: 14px; padding: 10px 12px; border: 1px dashed var(--border-strong); border-radius: var(--r-md); }
.dx-old-free-note { font-size: 11px; color: var(--text-dim); margin-bottom: 4px; }
.dx-old-free-text { font-size: 13px; color: var(--text-2); white-space: pre-line; overflow-wrap: anywhere; }
/* "+ Create" form under the search box: two columns on a desk, one stacked
   column on a phone with 48 px fields and buttons. */
.dx-create {
  margin-top: 8px; padding: 12px; border: 1px solid var(--border-strong);
  border-radius: var(--r-md); background: var(--surface-flat-2);
}
.dx-create-title { font-size: 13px; font-weight: 700; color: var(--text); margin-bottom: 8px; }
.dx-create-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 10px; }
.dx-create-f { display: flex; flex-direction: column; gap: 4px; min-width: 0; font-size: 11px; color: var(--text-dim); }
.dx-create-f .admin-input { width: 100%; min-height: 40px; box-sizing: border-box; font-size: 14px; }
.dx-create .admin-form-error:not(:empty) { margin-top: 8px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dx-create-acts { display: flex; gap: 8px; justify-content: flex-end; margin-top: 10px; }
.dx-create-acts button, .dx-create-twin { min-height: 40px; }
@media (max-width: 600px) {
  .dx-create-grid { grid-template-columns: 1fr; }
  .dx-create-f .admin-input, .dx-pick input[type="search"] { min-height: 48px; font-size: 16px; }
  .dx-create-acts button, .dx-create-twin { min-height: 48px; flex: 1 1 0; }
  .dx-create-acts .ox-btn--cta { flex-grow: 2; white-space: nowrap; }
}

/* ── Contract tab (jv-*) ── */
/* The modals and the takeoff panel of a line's detail (the cards and the
   detail itself are .jv-card / .jv-dt in redesign-tokens.css). */
/* Money columns — Archivo, tabular-nums, so Contract/Earned line up down the
   column the same way every ledger figure does on Job Costs. */
.jv-money {
  font-family: var(--display); font-size: 13.5px; font-weight: 800;
  letter-spacing: -0.01em; color: var(--text);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.jv-money--muted {
  font-family: var(--font); font-size: 12.5px; font-weight: 500;
  color: var(--text-dim); font-variant-numeric: normal;
}
.jv-money--muted em { font-style: normal; }
.jv-pct {
  font-size: 12.5px; font-weight: 700; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* The add-line modal's live note under the Estimated quantity box (see
   _jvUpdateOpenNote in 68-jobvalue.js) — shown whenever that box is blank,
   explaining that a blank quantity is now a deliberate, valid choice
   ("open line") rather than something left unfinished. Same accent-bordered
   shell as .admin-warn-card, at a smaller scale for one line of copy inside
   a modal body rather than a full standing-condition card. */
.jv-open-live-note {
  margin-top: 6px;
  padding: 7px 10px;
  font-size: 11.5px; font-weight: 500; line-height: 1.4;
  color: var(--text-muted);
  background: var(--surface-flat);
  border: 1px solid var(--border-strong, rgba(255,255,255,.16));
  border-left: 3px solid var(--accent, #F89010);
  border-radius: 8px;
}

/* Adds to line (jvSetContinues, 68-jobvalue.js), in a line's detail. */
.jv-continues-select {
  min-width: 0; max-width: 220px; height: 36px;
  padding: 0 8px;
  font-size: 13px; font-family: var(--font);
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: 6px; color: var(--text);
  cursor: pointer;
}
.jv-continues-select:focus { outline: none; border-color: var(--focus); }

/* Sell price + contract amount, side by side wherever the modal is wide
   enough (add-line modal and the price modals of a line's detail, all in
   68-jobvalue.js) — either box updates the other as the admin types, so
   showing them together is what tells you two-way entry is on offer. */
/* align-items: flex-end — a label that wraps to two lines on a phone ("SELL
   PRICE FOR THIS JOB ($/COUNT)") must not push its box below its neighbour's. */
.jv-price-pair { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.jv-price-field { flex: 1 1 150px; min-width: 0; }

/* A finished task: the badge, the day it finished (editable) and Reopen. */
.jv-finished { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
/* flex: none — .admin-input is flex: 1 / min-width: 0, which squeezed the box
   until the year was cut ("10/05/"). */
.jv-finished-date { flex: none; width: auto; height: 28px; padding: 2px 6px; font-size: 12px; }
/* A thumb in a glove: the date box as tall as the buttons beside it. */
@media (pointer: coarse), (max-width: 860px) { .jv-finished-date { height: 44px; } }

/* The takeoff panel of a line's detail (jvToggleLinePlan): its own grid —
   group name, budget. overflow-x here is the "wide content scrolls inside its
   own container" rule — the page itself never gains a horizontal scrollbar. */
.jv-plan-row {
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  padding: 6px 18px 14px 40px;
  overflow-x: auto;
}
.jv-plan-head, .jv-plan-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 130px;
  column-gap: 10px;
  align-items: center;
  min-width: 300px;
}
.jv-plan-head {
  padding: 6px 0;
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim);
}
.jv-plan-head > span:not(:first-child) { text-align: right; }
.jv-plan-line { padding: 4px 0; }
.jv-plan-name {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  font-size: 12.5px; font-weight: 500; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Small muted chip for the group's sigla (MAT/LAB/EQP…) — tabular-nums keeps
   a run of these lining up the same way every other money figure on this
   tab does, even though the content here is letters, not digits. */
.jv-plan-code {
  flex: none;
  font-size: 10px; font-weight: 700; letter-spacing: .04em;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim); background: var(--surface-flat-2);
  padding: 2px 6px; border-radius: 5px;
}
.jv-plan-in {
  width: 100%; min-width: 88px;
  padding: 6px 8px;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.jv-plan-line--total {
  margin-top: 4px; padding-top: 8px;
  border-top: 1px solid var(--border);
}
.jv-plan-line--total .jv-plan-name { font-weight: 700; color: var(--text); }
.jv-plan-line--total .jv-money {
  display: flex; align-items: center; justify-content: flex-end; gap: 6px;
  font-size: 12.5px;
}
/* The derived rows under the typed Total (overhead's budget, total with it,
   planned margin): read-only, so no box — the figure sits where the boxes'
   figures end. Their names say more than a group's does and may wrap; the
   row scrolls sideways before it would crush (min-width on .jv-plan-line). */
.jv-plan-line--derived .jv-money { display: block; text-align: right; font-size: 12.5px; padding-right: 8px; }
.jv-plan-line--derived .jv-plan-name { display: block; white-space: normal; overflow: visible; }
.jv-plan-line--derived.jv-plan-line--total { margin-top: 0; }
.jv-plan-sub { font-weight: 400; color: var(--text-dim); margin-left: 4px; }
/* A group named like the calculated overhead carries a note on its own cell;
   on a phone the note takes the next line instead of being cut. */
.jv-plan-name--wrap { flex-wrap: wrap; row-gap: 0; white-space: normal; overflow: visible; }
.jv-plan-name--wrap .jv-plan-sub { margin-left: 0; }
/* Profit's "%" box: in the name cell, against the amount box; on a narrow
   phone it takes the next line instead of being cut. */
.jv-plan-pct { margin-left: auto; display: inline-flex; align-items: center; gap: 4px; flex: none; font-weight: 500; color: var(--text-muted); }
.jv-plan-in--pct { width: 88px; }
/* A thumb in a glove: every plan box (cost groups, profit, escalation) the
   full 44px, like the finished date beside them. */
@media (pointer: coarse), (max-width: 860px) { .jv-plan-in { min-height: 44px; } }
.jv-plan-line--neg .jv-money { color: var(--error); }
/* A sentence row (a finished task's result): the whole width, no figure column. */
.jv-plan-line--note .jv-plan-name { grid-column: 1 / -1; }
.jv-plan-line--note .jv-money { display: none; }
.jv-plan-line--note.jv-plan-line--neg .jv-plan-name { color: var(--error); }
@media (max-width: 480px) {
  /* Same floor the brief calls for (inputs never drop below 88px) — the row
     scrolls horizontally inside itself (see overflow-x on .jv-plan-row above)
     rather than crushing the inputs any further. */
  .jv-plan-row { padding-left: 14px; padding-right: 14px; }
  .jv-plan-head, .jv-plan-line { min-width: 260px; }
}

/* ── Notifications tab (nx-*) ── */
.nx-group-label {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--display);
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--brand-orange-ink);
  margin-bottom: 10px;
}
.nx-group-label::before { content: ""; width: 14px; height: 2px; background: var(--brand-orange); border-radius: 2px; }
.nx-rule {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}
.nx-rule:last-of-type { border-bottom: none; }
.nx-rule--col { flex-direction: column; align-items: stretch; gap: 10px; }
.nx-rule-row { display: flex; align-items: center; gap: 14px; }
.nx-rule-ic {
  width: 36px; height: 36px; flex-shrink: 0;
  border-radius: 9px;
  background: var(--surface-flat-2);
  color: var(--accent-ink);
  display: flex; align-items: center; justify-content: center;
}
.nx-rule-ic svg { width: 16px; height: 16px; stroke-width: 1.85px; }
.nx-rule-txt { flex: 1; min-width: 0; }
.nx-rule-title { font-size: 13.5px; font-weight: 600; color: var(--text); }
.nx-rule-desc { font-size: 12px; font-weight: 500; color: var(--text-muted); margin-top: 2px; }
.nx-channel {
  flex-shrink: 0;
  padding: 7px 12px;
  border-radius: 8px;
  border: 1px solid var(--accent-ring);
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-size: 11.5px; font-weight: 700;
}
.nx-switch {
  flex-shrink: 0;
  width: 46px; height: 26px;
  border-radius: var(--r-pill);
  border: none;
  background: var(--surface-flat-3);
  position: relative;
  cursor: pointer;
  transition: background var(--t-fast);
}
.nx-switch .nx-knob {
  position: absolute; top: 3px; left: 3px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: #fff;
  transition: left 0.15s var(--ease-out);
}
.nx-switch--on { background: var(--accent); }
.nx-switch--on .nx-knob { left: 23px; }
.nx-reply { width: 240px; }
.nx-recips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding-left: 50px; }
.nx-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--surface-flat-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-pill);
  padding: 4px 6px 4px 12px;
  font-size: 12.5px; font-weight: 500; color: var(--text);
}
.nx-chip-x {
  border: none; background: none; cursor: pointer;
  color: var(--text-dim);
  display: inline-flex; align-items: center;
  padding: 2px;
}
.nx-chip-x:hover { color: var(--text); }
.nx-chip-x svg { width: 12px; height: 12px; }
.nx-fallback { font-size: 12px; color: var(--text-dim); font-style: italic; }
.nx-add { display: inline-flex; align-items: center; gap: 6px; }
.nx-add-input { width: 210px; padding: 7px 12px; }
@media (max-width: 640px) { .nx-recips { padding-left: 0; } }

/* ── Trade Packs tab (tp-*) — active pack wears the warm gradient ── */
/* Read-only plan banner. Was #c0272d with white text written into the tag —
   a red that exists nowhere else in the palette, at 3.4:1. Danger is real
   here, so it stays loud: the system's --error with the same dark ink the
   brand puts on any signal fill (5.9:1), not a second red. */
.plan-paywall-bar {
  position: sticky; top: 0; z-index: 999;
  background: var(--error);
  color: #0a0b0e;
  padding: 10px 16px;
  font-size: 14px; font-weight: 600; text-align: center;
}
.plan-paywall-bar a {
  color: inherit; font-weight: 800;
  text-decoration: underline; text-underline-offset: 2px;
}

/* Same body inset the picker uses, so the two pack modals read as one family. */
.tp-replace .admin-modal-body { padding: 16px 22px 22px; }

/* ── Re-import confirmation ─────────────────────────────────────────────────
   The list can run 20 forms long. It was raw <li> text with browser bullets
   and no bounds, so the modal grew past the fold and the Import button — the
   whole point of the screen — went under it. Now each group is a bounded,
   scrollable panel and the actions sit in a footer that never scrolls away. */
.tp-rep-lead {
  display: flex; align-items: flex-start; gap: 7px;
  font-size: 13px; font-weight: 500; color: var(--text-muted);
  margin: 0 0 8px; max-width: 62ch;
}
.tp-rep-lead + .tp-rep-group { margin-bottom: 18px; }
.tp-rep-lead--warn { color: var(--text); }
.tp-rep-lead--warn svg { width: 15px; height: 15px; flex: none; color: var(--warning); margin-top: 1px; }

.tp-rep-group { position: relative; }
.tp-rep-count {
  position: absolute; top: 10px; right: 12px;
  font-size: 11px; font-weight: 700; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.tp-rep-list {
  list-style: none; margin: 0; padding: 8px 10px;
  max-height: 208px; overflow-y: auto;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.tp-rep-list li {
  font-size: 13px; color: var(--text);
  padding: 5px 4px;
  border-bottom: 1px solid var(--border);
}
.tp-rep-list li:last-child { border-bottom: none; }

.tp-rep-ck { display: flex; align-items: center; gap: 9px; cursor: pointer; }
.tp-rep-ck input { width: 16px; height: 16px; flex: none; accent-color: var(--accent); cursor: pointer; }

.tp-rep-actions {
  display: flex; justify-content: flex-end; gap: 8px;
  margin-top: 18px; padding-top: 14px;
  border-top: 1px solid var(--border);
}

.tp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 14px; }
.tp-card {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-2xl);
  padding: 20px;
  display: flex; flex-direction: column;
}
.tp-card--active {
  background: linear-gradient(160deg, #1a1a12, #12130d);
  border-color: var(--accent-ring);
}
.tp-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tp-ic {
  width: 34px; height: 34px; flex-shrink: 0;
  border-radius: 9px;
  background: var(--surface-flat-2);
  color: var(--accent-ink);
  display: flex; align-items: center; justify-content: center;
}
.tp-card--active .tp-ic { background: var(--accent); color: var(--on-accent); }
.tp-ic svg { width: 16px; height: 16px; stroke-width: 1.85px; }
.tp-name { font-family: var(--display); font-size: 15px; font-weight: 800; letter-spacing: -0.01em; color: var(--text); }
.tp-desc { font-size: 13px; font-weight: 500; line-height: 1.55; color: var(--text-muted); margin: 10px 0 14px; flex: 1; }
.tp-foot { display: flex; justify-content: flex-end; }

/* Single-pack selector (2026-07-27): current-pack hero + picker modal */
.tp-hero { flex-direction: row; align-items: flex-start; gap: 16px; padding: 22px; max-width: 720px; }
.tp-hero .tp-ic { width: 42px; height: 42px; border-radius: 12px; }
.tp-hero .tp-ic svg { width: 20px; height: 20px; }
.tp-hero-main { flex: 1; min-width: 0; }
.tp-hero .tp-desc { margin: 8px 0 0; }
.tp-hero-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px; }
@media (max-width: 560px) { .tp-hero { flex-direction: column; } }

.tp-multi { max-width: 720px; border-color: rgba(245, 158, 11, 0.35); }
.tp-ic--warn { background: rgba(245, 158, 11, 0.12); color: var(--warning); }

.tp-picker { max-width: 960px; width: calc(100% - 32px); }
.tp-picker .admin-modal-body { padding: 4px 22px 22px; }
.tp-picker .tp-grid { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.tp-picker-sub { font-size: 13px; font-weight: 500; color: var(--text-muted); margin: 0 0 14px; max-width: 68ch; }
.tp-picker-x {
  background: none; border: none; cursor: pointer;
  color: var(--text-muted); font-size: 15px; line-height: 1;
  padding: 6px 8px; border-radius: 8px;
}
.tp-picker-x:hover { color: var(--text); background: var(--surface-2); }
.tp-card--pick { transition: border-color 0.15s ease, transform 0.15s ease; }
.tp-card--pick:hover { border-color: var(--accent-ring); transform: translateY(-1px); }

/* ── Billing (bx-*) ── */
.bx-note { font-size: 13px; font-weight: 500; color: var(--text-muted); margin: 10px 0 12px; max-width: 68ch; }
.bx-note--dim { font-size: 12px; color: var(--text-dim); margin: 10px 0 0; }
.bx-warnbox {
  background: rgba(245, 158, 11, 0.10);
  border: 1px solid rgba(245, 158, 11, 0.30);
  color: var(--warning-ink);
  padding: 10px 14px;
  border-radius: var(--r-md);
  margin-top: 12px;
  font-size: 13px; font-weight: 500;
}

/* Equipment reskin helpers */
.eq-btn-sm { padding: 8px 12px; font-size: 12px; }

/* ── Settings panel (st-*) ── */
.st-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 640px) { .st-grid { grid-template-columns: 1fr; } }
.st-field--wide { grid-column: 1 / -1; }
.st-input { width: 100%; }
.st-radios { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
@media (max-width: 720px) { .st-radios { grid-template-columns: 1fr; } }
.st-radio {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 13px 14px;
  background: var(--bg-1);
  border: 1.5px solid var(--border-strong);
  border-radius: var(--r-lg);
  cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.st-radio:has(input:checked) {
  border-color: var(--accent-ring);
  background: rgba(248, 144, 16, 0.08);
}
.st-radio input {
  width: 18px; height: 18px; margin-top: 1px;
  accent-color: var(--accent);
  flex-shrink: 0;
}
.st-radio-name { display: block; font-size: 13.5px; font-weight: 700; color: var(--text); }
.st-radio-desc { display: block; font-size: 12px; font-weight: 500; color: var(--text-muted); margin-top: 2px; line-height: 1.5; }
.nx-group-label--danger { color: var(--error-bright); }
.nx-group-label--danger::before { background: var(--error-bright); }
.st-danger { border-color: rgba(239, 68, 68, 0.25); padding: 0; overflow: hidden; }
.st-danger-row {
  display: flex; align-items: center; gap: 14px;
  padding: 15px 18px;
  border-bottom: 1px solid var(--border);
}
.st-danger-row:last-child { border-bottom: none; }

/* Critique fixes (Phase 3 assessment) */
.td-kpi-value--err { color: var(--error-ink); }
.td-kpi-ic--err { color: var(--error-ink); }
.admin-tab { min-height: 44px; } /* touch target — the old nav defended this */
.anav-group[data-section="overview"] { display: none !important; } /* single-tab row is redundant under the H1 */
.cert-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; vertical-align: middle; }

/* ── Forms registry (fb2-*) — redesign v2 registry cards ── */
.fb2-notice {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 16px;
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  margin-bottom: 16px;
}
.fb2-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; }
.fb2-card {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: 16px;
  display: flex; flex-direction: column; gap: 12px;
}
.fb2-head { display: flex; align-items: center; gap: 12px; }
.fb2-ic {
  width: 38px; height: 38px; flex-shrink: 0;
  border-radius: 10px;
  background: var(--surface-flat-2);
  color: var(--accent-ink);
  display: flex; align-items: center; justify-content: center;
}
.fb2-ic svg { width: 17px; height: 17px; stroke-width: 1.85px; }
.fb2-main { flex: 1; min-width: 0; }
.fb2-title { font-size: 14px; font-weight: 700; color: var(--text); }
.fb2-sub {
  font-size: 11.5px; font-weight: 500; color: var(--text-muted); margin-top: 1px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* One row held count + up to three badges + two buttons; on a 320px card it
   overflowed and clipped the Edit label. The meta chips now wrap as a group
   and the actions keep a slot that never shrinks. */
.fb2-foot {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 8px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.fb2-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  flex: 1 1 auto; min-width: 0;
}
.fb2-count { font-size: 11.5px; font-weight: 500; color: var(--text-dim); white-space: nowrap; }
.fb2-actions { margin-left: auto; flex: 0 0 auto; display: flex; gap: 6px; align-items: center; }

/* ── Documents: file cards with extension badges (redesign v2) ── */
.doc-file-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 10px; margin-bottom: 6px; }
.doc-file-card {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 13px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  transition: border-color var(--t-fast);
}
.doc-file-card:hover { border-color: var(--accent-ring); }
.doc-ext {
  width: 42px; height: 42px; flex-shrink: 0;
  border-radius: 9px;
  background: var(--surface-flat-2);
  border: 1px solid var(--border-strong);
  color: var(--accent-ink);
  font-family: var(--display); font-size: 10px; font-weight: 800; letter-spacing: 0.03em;
  display: flex; align-items: center; justify-content: center;
}
.doc-file-info { flex: 1; min-width: 0; }
.doc-file-title {
  display: block;
  font-size: 13px; font-weight: 600; color: var(--text);
  text-decoration: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.doc-file-title:hover { color: var(--accent-ink); }
.doc-file-meta { font-size: 11px; font-weight: 500; color: var(--text-dim); margin-top: 2px; }
.doc-file-notes {
  font-size: 11px; color: var(--text-muted); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.doc-file-actions { display: flex; gap: 5px; flex-shrink: 0; }
.doc-file-actions .ox-iconbtn { width: 28px; height: 28px; }
.doc-photo-edit svg, .doc-photo-del svg { width: 13px; height: 13px; }

/* ── Safety cert matrix (cm-*) ── */
.cm-scroll { overflow-x: auto; }
.cm-row { display: grid; align-items: center; padding: 10px 20px; border-bottom: 1px solid var(--border-subtle); min-width: fit-content; }
.cm-row:last-child { border-bottom: none; }
.cm-row--head {
  padding-top: 10px; padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.cm-colhead {
  font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--text-dim);
  text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding: 0 6px;
}
.cm-worker {
  font-size: 13px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  display: flex; align-items: center; gap: 7px;
}
.cm-trade {
  font-size: 10px; font-weight: 600; color: var(--text-dim);
  background: var(--surface-flat-2);
  border-radius: var(--r-sm);
  padding: 1px 6px;
}
.cm-c { display: flex; justify-content: center; }
/* Base (no --ok/--warn/--x modifier) is the "nothing to show" cell — same
   --text-faint-as-real-text case as .td-f-nosub/.td-cell--na above.
   LIGHT-only fix; dark pinned back to --text-faint at the file's end. */
.cm-cell {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%;
  font-size: 13px; color: var(--text-dim);
}
.cm-cell svg { width: 13px; height: 13px; stroke-width: 2.4; }
.cm-cell--ok   { background: rgba(34, 197, 94, 0.16);  color: var(--success); }
.cm-cell--warn { background: rgba(245, 158, 11, 0.16); color: var(--warning-ink); }
.cm-cell--x    { background: rgba(239, 68, 68, 0.15);  color: var(--error-ink); }
/* The cell became a BUTTON (click = add/renew right there) — reset the
   button chrome without losing the status circle, and give a hover/focus
   the circle never needed as a passive glyph. */
button.cm-cell { border: 0; padding: 0; font: inherit; cursor: pointer; }
button.cm-cell:hover, button.cm-cell:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}

/* ── Certs tab (2026-08-07): action bar, catalog, cell popover, bulk modal ──*/
.wk-certbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: 14px;
}
.wk-certbar-hint { font-size: 12.5px; color: var(--text-muted); }

.wk-cat-body { padding: 14px 16px; }
.wk-cat-empty { font-size: 13px; color: var(--text-muted); padding: 4px 0; }
.wk-cat-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 0; border-bottom: 1px solid var(--border);
}
.wk-cat-row:last-child { border-bottom: 0; }
.wk-cat-row--off { opacity: .6; }
.wk-cat-name { flex: 2 1 200px; font-weight: 600; }
.wk-cat-valid { display: inline-flex; align-items: center; gap: 6px; }
.wk-cat-months { width: 72px; text-align: right; }
.wk-cat-mo { font-size: 11.5px; color: var(--text-muted); white-space: nowrap; }
.wk-cat-used { flex: 1; min-width: 120px; font-size: 12px; color: var(--text-muted); }
.wk-cat-del { color: var(--error); }
.wk-cat-offhead {
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border);
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-muted);
}
.wk-cat-add { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

.wk-cell-pop {
  position: fixed; z-index: 60; width: 240px;
  background: var(--surface-flat-2, var(--surface-2));
  border: 1px solid var(--border-strong); border-radius: var(--r-lg);
  padding: 12px; box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; gap: 8px;
}
.wk-cell-pop-head { font-size: 12.5px; font-weight: 700; color: var(--text); }
.wk-cell-lbl { display: flex; flex-direction: column; gap: 3px; font-size: 11px;
  font-weight: 600; color: var(--text-muted); }
.wk-cell-pop-foot { display: flex; gap: 8px; justify-content: space-between; margin-top: 2px; }

.wk-bulk-tools { display: flex; gap: 8px; margin-bottom: 8px; }
.wk-bulk-tools .field-input { flex: 1; }
.wk-bulk-list {
  max-height: 300px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: var(--r-lg); padding: 4px 10px;
}
.wk-bulk-row {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 2px; border-bottom: 1px solid var(--border);
  font-size: 13px; cursor: pointer;
}
.wk-bulk-row:last-child { border-bottom: 0; }
.wk-bulk-name { flex: 1; font-weight: 600; }
.wk-bulk-trade { font-size: 11.5px; color: var(--text-muted); }

/* Salus card rows (Safety tab) */
.sl-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 0; border-bottom: 1px solid var(--border);
}
.sl-row:last-child { border-bottom: 0; }
.sl-name { flex: 2 1 220px; font-weight: 600; font-size: 13px; }
.sl-state {
  font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-dim); background: var(--surface-3);
  border-radius: 999px; padding: 2px 8px;
}
.sl-state--on { color: var(--success); background: rgba(34,197,94,.12); }
.sl-input { flex: 1 1 240px; }
@media (max-width: 640px) {
  .wk-cat-name { flex-basis: 100%; }
  .sl-input { flex-basis: 100%; }
}

/* ══ Billing (OrdinexAdminBilling.dc.html) ══════════════════════════════════
   Warm-gradient plan hero + renewal/payment side cards. The invoice-history
   and payment-method mocks in the model became one honest "ask Stripe" card
   — Ordinex never stores card details or a local invoice ledger. */
.bx-grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 16px;
}
@media (max-width: 860px) { .bx-grid { grid-template-columns: 1fr; } }

.bx-hero {
  position: relative;
  /* Fixed-dark card in BOTH themes (warm obsidian, Narwal v3) — so every
     text inside must use FIXED light colors, never theme vars (in light
     mode var(--text) is near-black and vanished on this card). */
  background: linear-gradient(160deg, #1a1510, #12100c);
  border: 1px solid var(--accent-ring);
  border-radius: 16px;
  padding: 24px;
  overflow: hidden;
}
.bx-hero-glow {
  position: absolute; top: -60px; right: -40px;
  width: 220px; height: 220px;
  background: radial-gradient(circle, rgba(248,144,16,.16), transparent 62%);
  pointer-events: none;
}
.bx-hero-body { position: relative; }
.bx-hero-top { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
.bx-hero-lead {
  font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: rgba(245, 246, 247, 0.6); margin-bottom: 2px;
}
.bx-hero-rate {
  font-family: var(--display);
  font-size: 34px; font-weight: 900; letter-spacing: -0.03em;
  color: #f5f6f7;
}
.bx-hero-rate-unit { font-size: 15px; font-weight: 600; color: rgba(245, 246, 247, 0.72); }
.bx-hero-meta { font-size: 13px; font-weight: 500; color: rgba(245, 246, 247, 0.72); margin-top: 6px; }
/* Notes inside the fixed-dark hero: same rule — fixed light ink. */
.bx-hero .bx-note { color: rgba(245, 246, 247, 0.78); }
.bx-hero .bx-note--dim { color: rgba(245, 246, 247, 0.55); }
.bx-hero-actions { margin-top: 14px; }

/* Live seat quote — what the chosen seat count costs, shown BEFORE the admin
   confirms. Stripe still owns the invoice; this is the published rate card. */
.bx-quote {
  margin-top: 14px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface-flat);
}
.bx-quote-line {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.bx-quote-calc { font-size: 13px; font-weight: 600; color: var(--text-muted); }
.bx-quote-total {
  font-family: var(--display);
  font-size: 26px; font-weight: 900; letter-spacing: -0.03em;
  color: var(--text);
}
.bx-quote-per { font-size: 13px; font-weight: 600; color: var(--text-muted); letter-spacing: 0; }
.bx-quote-alt { font-size: 12px; font-weight: 500; color: var(--text-muted); margin-top: 6px; }
.bx-quote-alt--dim { color: var(--text-dim); }
@media (max-width: 560px) {
  .bx-quote-line { flex-direction: column; gap: 2px; }
  .bx-quote-total { font-size: 22px; }
}

.bx-side { display: grid; grid-template-rows: 1fr 1fr; gap: 16px; }
.bx-card {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 18px;
}
.bx-card-lbl {
  font-size: 11.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted);
}
.bx-card-big {
  font-family: var(--display);
  font-size: 25px; font-weight: 800; letter-spacing: -0.02em;
  margin-top: 8px; color: var(--text);
}
.bx-card-sub { font-size: 12px; font-weight: 500; color: var(--text-dim); margin-top: 2px; }
.bx-card--stripe { display: flex; flex-direction: column; }
.bx-card--stripe .bx-note { margin: 8px 0 12px; }

/* ══ Projects — compact list: one row per site, accordion editor on Edit ═══
   Crew avatars are real (foreman_projects), not decoration. Active sites
   render first; inactive sit behind a divider at the bottom. */
.plist-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--border-subtle);
}
.plist-main {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 10px;
  background: none; border: none; padding: 0; cursor: pointer;
  font-family: var(--font); text-align: left;
}
.plist-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--surface-flat-3); }
.plist-dot--on { background: var(--success); }
.plist-code {
  flex: none; min-width: 52px; text-align: center;
  font-size: 11px; font-weight: 700; letter-spacing: .03em;
  color: var(--accent-ink); background: rgba(248,144,16,.08);
  padding: 3px 8px; border-radius: 6px;
}
.plist-name {
  font-size: 13.5px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.plist-gc {
  font-size: 12px; color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.plist-crewct { flex: none; width: 52px; text-align: right; font-size: 11.5px; color: var(--text-dim); }
.plist-row--off .plist-name { color: var(--text-muted); font-weight: 500; }
.plist-row--off .plist-code { color: var(--text-dim); background: var(--surface-flat-2); }
.plist-divider {
  padding: 10px 16px 6px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-dim);
  background: var(--bg-1);
  border-bottom: 1px solid var(--border-subtle);
}
.plist-editor {
  display: flex; flex-direction: column; gap: 10px;
  padding: 12px 16px 14px 38px;
  background: var(--bg-1);
  border-bottom: 1px solid var(--border-subtle);
}
.plist-editor[hidden] { display: none; }
.plist-ed-name { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.plist-ed-name .admin-input { max-width: 360px; }
.plist-ed-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
@media (max-width: 720px) {
  .plist-row .pcard-avatars { display: none; }
}

/* Crew avatar chips + the two inline inputs — shared by the list editor. */
.pcard-avatars { display: flex; }
.pcard-av {
  width: 24px; height: 24px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--display); font-size: 9px; font-weight: 700;
  background: var(--accent); color: var(--on-accent);
  border: 2px solid var(--surface-flat);
  margin-left: -7px;
}
.pcard-av:first-child { margin-left: 0; }
.pcard-av--empty { background: var(--surface-flat-3); color: var(--text-dim); }
.pcard-code-input {
  width: 74px; padding: 6px 8px;
  text-transform: uppercase; font-size: 11.5px; font-weight: 700; letter-spacing: 0.02em;
  border: 1px solid var(--border-strong); border-radius: 6px;
  background: var(--surface-flat-2); color: var(--text);
}
.pcard-salus-input {
  flex: 1; min-width: 140px; max-width: 280px; padding: 6px 8px;
  font-size: 11.5px; font-weight: 500;
  border: 1px solid var(--border-strong); border-radius: 6px;
  background: var(--surface-flat-2); color: var(--text);
}

/* ══ Buildings — a project that lives under a mother project (parent_id) ═══
   Row + editor are the SAME markup as any project; only the visual weight
   changes (indented, lighter) — a building never gets its own "Buildings"
   add-block (one level only, the DB guard rejects a grandchild). */
.proj-building-row { padding-left: 40px; background: var(--bg-1); }
.proj-building-row .plist-name { font-weight: 500; color: var(--text-dim); }
.proj-building-row + .plist-editor { padding-left: 62px; }

/* The "Buildings" add-block inside every non-building project's editor. */
.proj-buildings {
  padding-top: 10px; margin-top: 4px;
  border-top: 1px solid var(--border-subtle);
  display: flex; flex-direction: column; gap: 8px;
}
.proj-buildings-hd {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dim);
}
.proj-buildings-list { display: flex; flex-wrap: wrap; gap: 6px; }
.proj-buildings-chip {
  font-size: 11.5px; font-weight: 600; color: var(--text);
  background: var(--surface-flat-2); border: 1px solid var(--border-subtle);
  border-radius: 6px; padding: 3px 9px;
}
.proj-buildings-add { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.proj-buildings-add .admin-input { max-width: 260px; }

/* ══ Compliance — org-wide default view (OrdinexAdminCompliance.dc.html) ═══
   Was gated behind picking a project first; this renders unconditionally,
   above the existing per-project deep-dive toolbar (kept intact below). */
.cr-org-grid {
  display: grid;
  grid-template-columns: 1fr 1.5fr;
  gap: 16px;
}
@media (max-width: 780px) { .cr-org-grid, .cr-org-grid2 { grid-template-columns: 1fr; } }
.cr-org-ring {
  position: relative;
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 22px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
  overflow: hidden;
}
.cr-org-ring-lbl { position: relative; margin-top: 12px; font-size: 13px; font-weight: 700; color: var(--text); }
.cr-org-ring-badge {
  position: relative; margin-top: 6px;
  display: inline-flex; align-items: center; gap: 7px;
  background: rgba(34,197,94,.12); color: var(--success);
  font-size: 11.5px; font-weight: 700;
  padding: 6px 12px; border-radius: 999px;
}
.cr-org-ring-badge svg { width: 13px; height: 13px; stroke-width: 2px; }

.cr-org-grid2 { display: grid; grid-template-columns: 1.3fr 1fr; gap: 16px; }

/* Compliance-by-project table */
.crp-head {
  display: grid; grid-template-columns: 1.6fr 1.4fr 130px 110px;
  padding: 10px 20px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border);
}
.crp-row {
  display: grid; grid-template-columns: 1.6fr 1.4fr 130px 110px;
  align-items: center;
  padding: 13px 20px;
  border-bottom: 1px solid rgba(10,11,14,.04); /* T2 light sweep — dark pinned at file end */
}
.crp-name-txt { font-size: 13.5px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.crp-code { font-size: 11px; font-weight: 500; color: var(--text-dim); }
.crp-cov { display: flex; align-items: center; gap: 10px; }
.crp-cov-track { flex: 1; height: 7px; border-radius: 999px; background: var(--surface-flat-3); overflow: hidden; }
.crp-cov-fill { height: 100%; border-radius: 999px; }
.crp-cov-pct { font-size: 12px; font-weight: 700; min-width: 36px; text-align: right; }
.crp-cell { font-size: 13px; font-weight: 600; color: var(--text); text-align: center; }

/* Certifications expiring list */
.crc-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 20px;
  border-bottom: 1px solid rgba(10,11,14,.04); /* T2 light sweep — dark pinned at file end */
}
.crc-av {
  width: 30px; height: 30px; flex-shrink: 0; border-radius: 50%;
  background: var(--surface-flat-3); color: var(--text);
  font-family: var(--display); font-size: 10px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.crc-txt { flex: 1; min-width: 0; }
.crc-who { font-size: 13px; font-weight: 600; color: var(--text); }
.crc-cert { font-size: 11.5px; font-weight: 500; color: var(--text-muted); }
.crc-due { font-size: 11.5px; font-weight: 700; padding: 5px 11px; border-radius: 999px; white-space: nowrap; }
.cr-soon-pill {
  font-size: 11px; font-weight: 700; color: var(--warning);
  background: rgba(245,158,11,.12);
  padding: 4px 10px; border-radius: 999px;
}

/* ══════════════════════════════════════════════════════════════════════════
   JOB COSTS — the money instrument.

   Reads top-down as one question answered three ways: is this job inside its
   budget (the ring), where is the money going (the bars), what makes it up
   (the ledger). It borrows the Today board's grammar on purpose — same hero
   shell, same ring, same coverage track — so the two cockpits feel like one
   instrument rather than two apps.
   ══════════════════════════════════════════════════════════════════════════ */
.jc-hero {
  position: relative;
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-2xl);
  overflow: hidden;
  padding: 22px;
  margin-bottom: 16px;
}
.jc-hero-glow {
  position: absolute; top: -110px; right: -70px;
  width: 320px; height: 320px;
  background: radial-gradient(circle, rgba(248, 144, 16, 0.10), transparent 62%);
  pointer-events: none;
}
.jc-hero-in {
  position: relative; display: flex; gap: 26px;
  align-items: center; flex-wrap: wrap;
}
.jc-hero-gauge { display: flex; flex-direction: column; align-items: center; gap: 9px; flex-shrink: 0; }
.jc-hero-cap {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-muted); text-align: center;
}
/* Ring type lives inside SVG, so it takes fill rather than color. */
.jc-ring-val  { font: 800 34px var(--display); letter-spacing: -0.03em; fill: var(--text); }
/* --error already clears the 3:1 large-text floor (~3.76:1) even at 34px —
   left as-is. --success does not (~2.28:1, below even large-text AA) —
   swapped to --success-ink below; no dark pin needed, its dark value
   already resolves to plain --success (T2 light sweep, 2026-08-05). */
.jc-ring-val--over { fill: var(--error); }
/* The Contract tab's ring (68-jobvalue.js) reuses this exact geometry with
   one deliberate inversion: there, 100%+ is the job fully earned — success,
   never the --error tone above. */
.jc-ring-val--complete { fill: var(--success-ink); }
.jc-ring-cap  { font: 600 10px var(--font); letter-spacing: 0.06em; fill: var(--text-muted); }
.jc-ring-money { font: 800 19px var(--display); letter-spacing: -0.02em; fill: var(--text); }

.jc-hero-side { flex: 1; min-width: 260px; display: flex; flex-direction: column; gap: 16px; }
.jc-hero-side-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 1px;
}
.jc-hero-side-title { font-size: 13px; font-weight: 700; color: var(--text); }
.jc-hero-side-note { font-size: 11.5px; color: var(--text-dim); }

/* One bucket: name and money on a line, spend track under it. */
.jc-bucket {
  display: block; width: 100%; text-align: left;
  background: none; border: 0; padding: 2px 0; cursor: default;
  color: inherit; font: inherit;
}
.jc-bucket--act { cursor: pointer; }
.jc-bucket--act:hover .jc-bucket-name { color: var(--accent-ink); }
.jc-bucket-line {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 10px; margin-bottom: 5px;
}
/* The Budget modal's derived rows under the groups: overhead's budget and
   the total with it. Their names are sentences, not group names — they wrap
   rather than lose their last word to an ellipsis on a phone. */
.jc-bucket-line--derived .jc-bucket-name { white-space: normal; overflow: visible; }
.jc-bucket-line--total { padding-top: 7px; border-top: 1px solid var(--border); }
.jc-bucket-line--total .jc-bucket-name { color: var(--text); font-weight: 700; }
.jc-bucket-name {
  font-size: 12px; font-weight: 600; color: var(--text-muted);
  display: flex; align-items: center; gap: 6px;
  /* Job Costs' own bucket names are fixed short words (Material, Labour…)
     and never need this; the Contract tab's bars (68-jobvalue.js) reuse
     this exact class for free-text line descriptions, which can run long —
     truncate rather than push the amount off the card or wrap the row. */
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.jc-bucket-amt {
  font-family: var(--display); font-size: 14px; font-weight: 800;
  letter-spacing: -0.01em; color: var(--text);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.jc-bucket-track {
  height: 7px; border-radius: var(--r-pill);
  background: var(--surface-3); overflow: hidden;
}
.jc-bucket-fill { display: block; height: 100%; border-radius: var(--r-pill); background: var(--accent); }
.jc-bucket-fill--ok   { background: var(--success); }
.jc-bucket-fill--over { background: var(--error); }
.jc-bucket-foot { font-size: 11px; color: var(--text-dim); margin-top: 4px; }
.jc-bucket-foot--over { color: var(--error); }
.jc-bucket-foot--ok   { color: var(--success); }

/* Budget modal's read-only note (Task 8) — a task plan is doing the
   budgeting for this job, so the boxes below are replaced by a line per
   topic and a pointer back to where the numbers actually live. */
.jc-hint { font-size: 12.5px; color: var(--text-muted); line-height: 1.5; margin: 0 0 2px; }
/* Buildings note (Task 4, subprojects) — one muted line at the very top of
   the page, before the hero card, so it needs breathing room .jc-hint's own
   modal-context margin (2px) doesn't provide. */
.jc-buildings-note { margin: 0 0 14px; }

/* Totals rail: direct cost, overhead, and the number that includes it. */
.jc-rail {
  display: flex; flex-wrap: wrap; gap: 10px 26px; align-items: baseline;
  margin-top: 15px; padding-top: 14px; border-top: 1px solid var(--border);
}
.jc-rail-item { display: flex; align-items: baseline; gap: 8px; }
.jc-rail-lbl {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-muted);
}
.jc-rail-val {
  font-family: var(--display); font-size: 16px; font-weight: 800;
  letter-spacing: -0.02em; color: var(--text); font-variant-numeric: tabular-nums;
}
.jc-rail-val--total { font-size: 20px; color: var(--accent-ink); }
.jc-rail-note { font-size: 11px; color: var(--text-dim); }
.jc-rail-spacer { flex: 1; }

/* Margin row — the single most important number on Job Costs (it's the
   whole reason the Contract tab exists), so it gets a designed row of its
   own rather than borrowed KPI classes + inline styles. Tone lives on the
   NUMBER only — never a background or a border-left (DESIGN.md calls a
   colored border-left the AI tell). */
.jc-margin-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: 0; border-top: 1px solid var(--border);
  padding: 14px 0 0; margin-top: 14px;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.jc-margin-lbl {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-muted);
}
.jc-margin-val {
  font-family: var(--display); font-size: 19px; font-weight: 800;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.jc-margin-val--ok  { color: var(--success); }
.jc-margin-val--err { color: var(--error); }
.jc-margin-foot { font-size: 11.5px; color: var(--text-dim); }
.jc-margin-arrow { margin-left: auto; flex-shrink: 0; color: var(--text-dim); display: flex; }
.jc-margin-arrow svg { width: 16px; height: 16px; stroke-width: 1.85px; }
.jc-margin-row:hover .jc-margin-arrow { color: var(--accent-ink); }

/* Unpriced-lines warning, nested inside the Contract hero (68-jobvalue.js)
   instead of sitting in its own outer card. */
.jc-hero-warn { margin: 14px 0 0; }

/* ── Ledger ──────────────────────────────────────────────────────────────── */
.jc-section-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-muted); margin: 22px 0 10px;
}
.jc-group {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  margin-bottom: 12px; overflow: hidden;
}
.jc-group-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 11px 16px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border); background: var(--surface-2);
}
.jc-group-head span:last-child {
  font-family: var(--display); font-size: 15px; font-weight: 800;
  letter-spacing: -0.01em; color: var(--text);
  text-transform: none; font-variant-numeric: tabular-nums;
}
/* A statement line and the control that re-files it sit side by side. The
   wrapper owns the separator so the group still reads as one list, and the
   move control is a sibling of the row — never nested inside it, because most
   rows are buttons with a click of their own. */
.jc-row-wrap {
  display: flex; align-items: stretch;
  border-bottom: 1px solid var(--border);
}
.jc-row-wrap:last-child { border-bottom: 0; }
.jc-row {
  display: flex; align-items: center; gap: 14px;
  width: 100%; text-align: left;
  padding: 11px 16px; min-height: 44px;
  background: none; border: 0; border-bottom: 1px solid var(--border);
  color: inherit; font: inherit; cursor: pointer;
}
.jc-row:last-child { border-bottom: 0; }
.jc-row-wrap > .jc-row { flex: 1; min-width: 0; border-bottom: 0; }
.jc-row:not(.jc-row--static):hover { background: var(--surface-2); }
.jc-row--static { cursor: default; }

/* Always visible, never loud: hover-to-reveal would hide it on every phone,
   and this screen is read on site. Dim at rest, brand yellow once it matters. */
.jc-move-btn {
  flex: 0 0 auto; width: 42px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; padding: 0;
  color: var(--text-dim); cursor: pointer;
}
.jc-move-btn svg { width: 16px; height: 16px; stroke-width: 1.85px; }
/* Holds the column open on a row that cannot be moved, so every amount in the
   group stays on the same edge. */
.jc-move-spacer { flex: 0 0 auto; width: 42px; }
.jc-move-btn:hover, .jc-move-btn:focus-visible { color: var(--accent-ink); background: var(--surface-2); }
/* This line is not where the app filed it — the owner moved it. */
.jc-move-btn--moved { color: var(--accent-ink); }

/* ── The task column ────────────────────────────────────────────────────────
   On a job that has contract lines, the same control carries the answer the
   popover used to keep to itself: which task this line is filed under. A
   FIXED width, not a hugging one — the whole point is a column the eye can
   run down, and forty chips each as wide as its own task name is a ragged
   edge, not a column. The name ellipsizes; the full text is in the title. */
.jc-task-chip {
  flex: 0 0 auto; width: 176px; align-self: center;
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  margin: 8px 10px 8px 0; padding: 0 8px; min-height: 30px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-muted); font: inherit; font-size: 11.5px; font-weight: 700;
  letter-spacing: -0.01em; text-align: left; cursor: pointer;
}
.jc-task-chip-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jc-task-chip-arrow { width: 13px; height: 13px; flex: none; stroke-width: 2px; opacity: .65; }
.jc-task-chip-arrow svg { width: 100%; height: 100%; }
.jc-task-chip:hover, .jc-task-chip:focus-visible {
  border-color: var(--border-strong); color: var(--text); background: var(--surface-3);
}
/* Money on this line that nobody has filed yet. Same amber as .jc-badge--warn
   — one vocabulary for "this needs you", not a second one for this column. */
.jc-task-chip--warn {
  background: rgba(245,158,11,.10); border-color: rgba(245,158,11,.35); color: var(--warning);
}
.jc-task-chip--warn:hover, .jc-task-chip--warn:focus-visible {
  background: rgba(245,158,11,.16); border-color: rgba(245,158,11,.5); color: var(--warning);
}
/* The topic was moved by hand — the second thing this one control does, still
   said, now on the arrow instead of the whole button. */
.jc-task-chip--moved .jc-task-chip-arrow { color: var(--accent-ink); opacity: 1; }
.jc-move-spacer--chip { width: 186px; }

/* ── What still has no task ─────────────────────────────────────────────────
   The backlog, in one sentence, directly above the list it is about. */
.jc-unfiled {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 14px; margin-bottom: 12px;
  background: rgba(245,158,11,.08); border: 1px solid rgba(245,158,11,.32);
  border-radius: var(--r-xl);
  font-size: 12.5px; line-height: 1.5; color: var(--text);
}
.jc-unfiled > svg { width: 16px; height: 16px; flex: none; color: var(--warning); }
.jc-unfiled-text { flex: 1; min-width: 180px; font-weight: 600; }
.jc-unfiled-btn {
  min-height: 32px; padding: 0 12px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: 999px;
  color: var(--text); font: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
  white-space: nowrap;
}
.jc-unfiled-btn:hover, .jc-unfiled-btn:focus-visible { background: var(--surface-3); }
.jc-unfiled-btn--on { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.jc-unfiled-btn--primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.jc-unfiled-btn--primary:hover, .jc-unfiled-btn--primary:focus-visible { background: var(--accent-bright); border-color: var(--accent-bright); }
/* Nothing outstanding. Says so quietly — "am I done?" deserves an answer, not
   an empty space where the bar used to be. */
.jc-unfiled--done {
  background: rgba(34,197,94,.07); border-color: rgba(34,197,94,.26); color: var(--text-muted);
}
.jc-unfiled--done > svg { color: var(--success); }
/* Filtered view: the group head prints its own unfiled subtotal, so it has to
   say that is what the figure means. `span.` is load-bearing, not decoration:
   the head's own `.jc-group-head span:last-child` rule (the money) scores a
   pseudo-class in the same column as a class, so a plain
   `.jc-group-head .jc-group-head-note` LOSES to it and the note comes out in
   15px display weight 800. */
.jc-group-head span.jc-group-head-note {
  font-family: var(--font); font-size: 10px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--warning);
}

/* The statement's own bottom line. It has been in the markup since this tab
   shipped with no rule of its own — plain unstyled text under a column of
   cards. It carries the filtered view's outstanding total now, so it gets the
   weight the number deserves: the group head's bar, one step firmer. */
.jc-grand {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  margin-top: 12px; padding: 13px 16px;
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-xl);
  font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text-muted);
}
.jc-grand > span:last-child {
  font-family: var(--display); font-size: 19px; font-weight: 800;
  letter-spacing: -0.015em; text-transform: none; color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* ── Filing the backlog in one pass ─────────────────────────────────────────*/
/* align-self, because the modal body's .admin-row centres its flex children —
   a heading that reads centred over a left-aligned list is an accident. */
.jc-fileall-count {
  align-self: stretch; margin: 0;
  font-family: var(--display); font-size: 15px; font-weight: 800;
  letter-spacing: -0.01em; color: var(--text);
}
.jc-fileall-count:empty { display: none; }
.jc-fileall-all {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 6px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-lg);
}
.jc-fileall-all .admin-label { margin: 0; white-space: nowrap; }
.jc-fileall-all select { flex: 1; min-width: 180px; }
.jc-fileall-row {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 0; border-bottom: 1px solid var(--border);
}
.jc-fileall-row:last-child { border-bottom: 0; }
.jc-fileall-main { flex: 1; min-width: 0; }
.jc-fileall-name {
  font-size: 13px; font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.jc-fileall-sub { font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.jc-fileall-select { flex: 0 0 auto; width: 200px; max-width: 46%; }

/* ── Split editor ───────────────────────────────────────────────────────────
   from → to → task → share → worth → remove, one grid row. The date tracks
   exist only on a line that IS a period (.jc-csplit--dated); the share
   column only when rows actually overlap (.jc-csplit--shares) — in the
   ordinary handover the owner sees dates and nothing else. */
.jc-csplit-row {
  display: grid; grid-template-columns: 1fr auto 32px;
  gap: 8px; align-items: center; padding: 7px 0;
  border-bottom: 1px solid var(--border);
}
.jc-csplit--dated .jc-csplit-row { grid-template-columns: auto 14px auto 1fr auto 32px; }
.jc-csplit-row:last-child { border-bottom: 0; }
.jc-csplit-arrow { color: var(--text-dim); text-align: center; }
.jc-csplit-from, .jc-csplit-to { width: 138px; }
.jc-csplit-task { min-width: 0; }
.jc-csplit-sharewrap { display: none; align-items: center; gap: 3px; }
.jc-csplit--shares .jc-csplit-row { grid-template-columns: 1fr auto auto 32px; }
.jc-csplit--shares.jc-csplit--dated .jc-csplit-row {
  grid-template-columns: auto 14px auto 1fr auto auto 32px; }
.jc-csplit--shares .jc-csplit-sharewrap { display: inline-flex; }
.jc-csplit-share { width: 58px; text-align: right; }
.jc-csplit-pct { color: var(--text-muted); font-size: 12px; }
.jc-csplit-worth { text-align: right; min-width: 76px; font-variant-numeric: tabular-nums; }
.jc-csplit-del {
  width: 32px; min-height: 32px; display: flex; align-items: center; justify-content: center;
  background: none; border: 0; color: var(--text-dim); cursor: pointer; border-radius: 8px;
}
.jc-csplit-del:hover, .jc-csplit-del:focus-visible { color: var(--error); background: var(--surface-2); }
.jc-csplit-del svg { width: 14px; height: 14px; }
/* align-self: the modal body's .admin-row centres its flex children — the
   remainder line (and the rows list) must span the modal, not hug the middle. */
.jc-csplit-rest {
  align-self: stretch;
  display: flex; justify-content: space-between; gap: 12px; padding: 9px 2px 0;
  font-size: 12.5px; font-weight: 600; color: var(--text-muted);
}
#jcCostSplitRows { align-self: stretch; }
/* The popover's "this line is split" explainer, under the Task heading. */
.jc-move-note { padding: 2px 10px 8px; font-size: 11.5px; line-height: 1.45; color: var(--warning); }

/* A labour trade's timesheet split, one quiet sub-row per task under the row
   whose total they add up to. Indented, smaller money, no separate border
   weight — they explain the row above, they do not compete with it. */
.jc-sub-row { padding: 5px 16px 5px 34px; min-height: 0; }
.jc-sub-row .jc-row-sub { font-size: 12px; }
.jc-sub-amt { font-size: 12.5px; font-weight: 600; color: var(--text-muted); }

.jc-move-menu {
  position: fixed; z-index: 60; min-width: 208px; max-width: min(268px, calc(100vw - 16px));
  background: var(--surface-flat-2, var(--surface-2));
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg); padding: 6px;
  box-shadow: var(--shadow-lg);
  max-height: min(70vh, 420px); overflow-y: auto;
}
.jc-move-head {
  padding: 6px 10px 8px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-muted);
}
/* The Task section is a second heading in the same popover, after the topic
   list — a rule above it is the only thing that separates the two axes. */
.jc-move-sect { margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--border); }
.jc-move-opt {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 40px; padding: 9px 10px;
  border: 0; border-radius: 8px; background: transparent;
  color: var(--text); font-family: var(--font); font-size: 13px; font-weight: 600;
  text-align: left; cursor: pointer;
}
.jc-move-opt:hover, .jc-move-opt:focus-visible { background: var(--surface-flat-3, var(--surface-3)); }
.jc-move-opt-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.jc-move-opt--on { color: var(--accent-ink); }
/* Sized on the class itself, not on a descendant svg: Lucide replaces the <i>
   with an <svg> and carries the class across, so `.jc-move-tick svg` matches
   nothing and the tick renders at its intrinsic 24px. Same convention as
   .anav-icon above. */
.jc-move-tick { width: 15px; height: 15px; flex-shrink: 0; stroke-width: 2.2px; }
.jc-move-tick svg { width: 100%; height: 100%; }
.jc-move-manage {
  margin-top: 4px; padding-top: 11px;
  border-top: 1px solid var(--border); border-radius: 0 0 8px 8px;
  color: var(--text-muted); font-weight: 600;
}
.jc-move-manage svg { width: 15px; height: 15px; flex-shrink: 0; }
.jc-move-err:empty { display: none; }
.jc-move-err { padding: 6px 10px 2px; font-size: 11.5px; color: var(--error); }

/* Topics modal */
.jc-topics-empty { font-size: 13px; color: var(--text-dim); padding: 2px 0 4px; }
.jc-topic-row {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 0; border-bottom: 1px solid var(--border);
}
.jc-topic-row:last-child { border-bottom: 0; }
.jc-topic-name { flex: 1; min-width: 0; }
/* A group's sigla — short by design (2-5 chars), so the field is too. */
.jc-topic-code { flex: 0 0 60px; width: 60px; padding: 8px 4px; text-align: center; text-transform: uppercase; }
.jc-topic-del, .jc-topic-save, .jc-topic-reset {
  flex: 0 0 auto; width: 36px; height: 36px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; border-radius: var(--r-input);
  color: var(--text-dim); cursor: pointer;
}
.jc-topic-del svg, .jc-topic-save svg, .jc-topic-reset svg { width: 15px; height: 15px; stroke-width: 1.85px; }
.jc-topic-del:hover, .jc-topic-del:focus-visible { color: var(--error); background: var(--surface-2); }
.jc-topic-save:hover, .jc-topic-save:focus-visible,
.jc-topic-reset:hover, .jc-topic-reset:focus-visible { color: var(--text); background: var(--surface-2); }
.jc-topic-add { display: flex; align-items: center; gap: 8px; }
@media (max-width: 480px) {
  /* Six built-ins + a code field + up to two icon buttons is too much for one
     line at phone width — the name wraps to its own row above the rest. */
  .jc-topic-row { flex-wrap: wrap; }
  .jc-topic-name { flex-basis: 100%; }
}
.jc-row-main { flex: 1; min-width: 0; }
.jc-row-title { font-size: 13.5px; font-weight: 600; color: var(--text); }
.jc-row-sub {
  font-size: 12px; color: var(--text-dim); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.jc-row-amt {
  font-family: var(--display); font-size: 14.5px; font-weight: 800;
  letter-spacing: -0.01em; color: var(--text); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.jc-empty { padding: 16px; font-size: 13px; color: var(--text-dim); }
.jc-dim { color: var(--text-dim); font-weight: 500; }

/* Item split modal — one row per priced delivery line: what it is and what
   it cost on the left, which task claims it on the right. Same row rhythm as
   .jc-topic-row. */
.jc-split-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--border);
}
.jc-split-row:last-child { border-bottom: 0; }
.jc-split-name {
  flex: 1; min-width: 0; font-size: 13px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.jc-split-select { flex: 0 0 auto; width: auto; max-width: 45%; }
@media (max-width: 480px) {
  /* A label and a select rarely both fit on one line at phone width — the
     select drops to its own row rather than truncating the item name. */
  .jc-split-row { flex-wrap: wrap; }
  .jc-split-name { flex-basis: 100%; }
  .jc-split-select { flex: 1 1 auto; max-width: none; }
}

/* Sub rates modal — one rate box per production item of the job, the unit it
   is paid in beside the box. The list has NO scroller of its own: the modal
   body is the one scroller, as in every other modal, and Save is the end of
   that one scroll. (A list that scrolled inside the body left Save below the
   modal's edge on a 768px-tall laptop and a small phone, and the wheel over
   the list never reached it.) A label is a full-width block above its box at
   every width, so nothing to re-flow. */
.jc-subrates { display: flex; flex-direction: column; gap: 12px; }
.jc-subrate .admin-label { overflow-wrap: anywhere; }
.jc-subrate-in { display: flex; align-items: center; gap: 8px; }
.jc-subrate-in .admin-input { flex: 1; min-width: 0; }
.jc-subrate .admin-input { width: 100%; }
.jc-subrate-unit { flex: 0 0 auto; font-size: 12px; color: var(--text-dim); white-space: nowrap; }
.jc-subrate-note, .jc-subrate-empty {
  margin: 4px 0 0; font-size: 12px; line-height: 1.5; color: var(--text-dim);
}
.jc-subrate-empty { margin: 0; font-size: 13px; }
.jc-subrate-legacy {
  display: flex; flex-direction: column; gap: 10px;
  padding-top: 12px; border-top: 1px solid var(--border);
}
.jc-subrate-legacy-title { margin: 0; font-size: 12.5px; font-weight: 700; color: var(--text); }
.jc-subrate-legacy .jc-subrate-note { margin: 0; }
/* Dated changes (2026-10-18): the rule once above the list, what the statement
   has already priced per item, the item's change timeline with its ×, and ONE
   "Add change" row for the whole modal — item, new rate, the day it starts.
   The two inputs sit side by side and stack on a narrow phone. The × is a
   36px target: it is pressed in gloves. */
.jc-subrate-hint { margin: 0; font-size: 12px; line-height: 1.5; color: var(--text-dim); }
.jc-subrate-filed { margin: 4px 0 0; font-size: 12px; line-height: 1.5; color: var(--text); overflow-wrap: anywhere; }
.jc-subrate-changes { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; }
.jc-subrate-change {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-size: 12.5px; color: var(--text);
}
.jc-subrate-x {
  flex: 0 0 auto; width: 36px; height: 36px; padding: 0;
  border: 1px solid var(--border); border-radius: var(--r-pill); background: transparent;
  color: var(--text-dim); font-size: 18px; line-height: 1; cursor: pointer;
}
.jc-subrate-x:hover, .jc-subrate-x:focus-visible { color: var(--error); border-color: var(--error); }
.jc-subrate-add {
  display: flex; flex-direction: column; gap: 8px;
  padding-top: 12px; border-top: 1px solid var(--border);
}
.jc-subrate-add .admin-input { width: 100%; }
.jc-subrate-add .jc-subrate-hint { margin: 0; }
.jc-subrate-add-in { display: flex; gap: 8px; }
.jc-subrate-add-in > div { flex: 1 1 0; min-width: 0; }
@media (max-width: 360px) { .jc-subrate-add-in { flex-direction: column; } }

.jc-badge {
  display: inline-block; margin-left: 6px; padding: 1.5px 7px;
  border-radius: var(--r-pill); font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.03em; text-transform: uppercase; vertical-align: 1px;
}
.jc-badge--est  { background: var(--surface-3); border: 1px solid var(--border-strong); color: var(--text-muted); }
.jc-badge--conf { background: rgba(34,197,94,.10); border: 1px solid rgba(34,197,94,.30); color: var(--success); }
.jc-badge--warn { background: rgba(245,158,11,.10); border: 1px solid rgba(245,158,11,.35); color: var(--warning); }

/* Modal helpers */
.jc-rate-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 0; border-bottom: 1px solid var(--border);
}
.jc-rate-row:last-child { border-bottom: 0; }
.jc-rate-name { font-size: 13.5px; font-weight: 600; color: var(--text); }
.jc-rate-name .jc-dim { display: block; font-size: 11.5px; font-weight: 500; }
.jc-rate-input { display: flex; align-items: center; gap: 6px; color: var(--text-muted); font-size: 12px; font-weight: 600; }
.jc-rate-input input {
  width: 92px; padding: 8px 10px; text-align: right;
  font-size: 14px; font-weight: 700;
  border: 1px solid var(--border-strong); border-radius: var(--r-input);
  background: var(--surface-2); color: var(--text);
  font-variant-numeric: tabular-nums;
}
.jc-inv-line {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 4px 0; color: var(--text); font-variant-numeric: tabular-nums;
}
.jc-inv-line--warn  { color: var(--warning); }
.jc-inv-line--total {
  border-top: 1px solid var(--border); margin-top: 6px; padding-top: 8px; font-weight: 700;
}

/* A line that is on the statement for the record but carries no money — a
   delivery on a job that costs its material from the recipe. Dimmed and struck,
   with the figure that IS in force beside it: the same pairing the recipe editor
   uses for a price typed over the price book, so "replaced, not deleted" reads
   the same way in both places. Not a colour, not a border — the row is neither
   an error nor a warning, it simply is not the number in force. */
.jc-row--void .jc-row-title,
.jc-row--void .jc-row-sub { color: var(--text-dim); }
.jc-row-amt--void {
  color: var(--text-dim); font-weight: 600;
  text-decoration: line-through; text-decoration-thickness: 1px;
}

/* One sentence saying which material source this job counts, with the way to
   change it beside it. Quiet by construction: it explains a state, it does not
   warn about one. */
.jc-method-note {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 14px; margin-bottom: 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl);
  font-size: 12.5px; line-height: 1.5; color: var(--text-muted);
}
.jc-method-note > svg { width: 15px; height: 15px; flex: none; color: var(--accent-ink); }
.jc-method-note > span { flex: 1; min-width: 180px; }
.jc-method-link {
  display: inline-flex; align-items: center; gap: 5px;
  min-height: 32px; padding: 0 4px;
  background: none; border: 0; cursor: pointer;
  color: var(--accent-ink); font: inherit; font-weight: 700;
}
.jc-method-link svg { width: 14px; height: 14px; stroke-width: 2.2px; }
.jc-method-link:hover { color: var(--accent-ink); }

@media (max-width: 640px) {
  .jc-hero { padding: 17px; }
  .jc-hero-in { gap: 18px; }
  .jc-hero-gauge { margin-inline: auto; }
  .jc-rail { gap: 8px 18px; }
  .jc-row { flex-wrap: wrap; }
  .jc-row-amt { margin-left: auto; }
  /* The row wraps to two lines on a phone; the move control keeps its own
     44px target beside it rather than shrinking with the text. */
  .jc-row-wrap > .jc-row { padding-right: 8px; }
  .jc-move-btn { width: 44px; align-items: flex-start; padding-top: 13px; }
  /* A 176px column beside a 375px screen leaves the line itself about 190px —
     enough to turn "Aug 5, 2026 · PO 4471" into four wrapped lines. So on a
     phone the two STACK: the cost reads across the full width, and the task
     sits under it as its own full-height target. Only rows that actually
     carry a chip stack (--chip); an org with no contract lines keeps the
     arrow beside the row exactly as before. */
  .jc-row-wrap--chip { flex-direction: column; align-items: stretch; }
  .jc-row-wrap--chip > .jc-row { padding-right: 16px; }
  .jc-task-chip {
    width: auto; max-width: calc(100% - 32px); align-self: flex-start;
    margin: 0 16px 10px; min-height: 36px; font-size: 11.5px; gap: 10px;
  }
  /* The column it was holding open no longer exists on a phone. */
  .jc-move-spacer--chip { display: none; }
  .jc-unfiled-text { min-width: 100%; }
  .jc-unfiled-btn { flex: 1; }
  /* The dropdown drops under the line it belongs to rather than squeezing the
     name it is supposed to explain into three characters. */
  .jc-fileall-row { flex-direction: column; align-items: stretch; gap: 7px; }
  .jc-fileall-select { width: 100%; max-width: none; }
  /* Split editor on a phone: dates side by side, everything else stacked
     full-width — six grid tracks cannot share 375px. */
  .jc-csplit-row, .jc-csplit--dated .jc-csplit-row,
  .jc-csplit--shares .jc-csplit-row,
  .jc-csplit--shares.jc-csplit--dated .jc-csplit-row {
    grid-template-columns: 1fr 14px 1fr; padding: 10px 0;
  }
  .jc-csplit-from, .jc-csplit-to { width: 100%; }
  .jc-csplit-task { grid-column: 1 / -1; }
  .jc-csplit-sharewrap { justify-content: flex-start; }
  .jc-csplit-worth { text-align: left; }
  .jc-csplit-del { justify-self: end; }
  /* The struck figure and the one in force sit side by side rather than one
     pushing the other off the row. */
  .jc-row-amt--void { margin-left: auto; }
}

/* ── By-task comparison (P3 Task 5) — budget vs. actual per group, per
   contract line. Cards reuse .jc-group/.jc-group-head as-is (same shell, same
   header bar as every statement group below it); only the grid inside and
   the margin strip under it are new. Money cells reuse .jv-money's type
   (Archivo, tabular-nums, weight 800) rather than redeclaring it — this
   class only adds the right-alignment a grid cell needs that a table row
   didn't. */
.jc-bytask-hint { font-size: 12.5px; line-height: 1.5; color: var(--text-muted); margin: -6px 0 14px; }
.jc-bytask-block { margin-bottom: 12px; }
.jc-bytask-head-main {
  display: inline-flex; align-items: center; gap: 2px; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The grid scrolls inside its own box — the page itself never gains a
   horizontal scrollbar, same rule as the Contract tab's per-line plan row. */
.jc-bytask-scroll { overflow-x: auto; }
.jc-bytask-row {
  display: grid; grid-template-columns: minmax(140px, 2fr) 96px 96px 96px;
  column-gap: 10px; align-items: center; min-width: 460px;
  padding: 9px 16px; border-bottom: 1px solid var(--border);
}
.jc-bytask-row:last-child { border-bottom: 0; }
.jc-bytask-row--cols {
  padding: 8px 16px; border-bottom: 1px solid var(--border);
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim); background: var(--surface-2);
}
.jc-bytask-row--cols span:not(:first-child) { text-align: right; }
.jc-bytask-row--subtotal {
  font-weight: 700; color: var(--text);
  background: var(--surface-2); border-top: 1px solid var(--border); border-bottom: 0;
}
/* General has no plan to compare against by definition — one money column,
   not three. */
.jc-bytask-row--general { grid-template-columns: minmax(140px, 2fr) 96px; min-width: 260px; }
.jc-bytask-group { display: flex; align-items: center; gap: 7px; min-width: 0; }
.jc-bytask-code {
  flex: none; font-size: 10px; font-weight: 700; letter-spacing: .04em;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim); background: var(--surface-flat-2);
  padding: 2px 6px; border-radius: 5px;
}
.jc-bytask-label {
  font-size: 12.5px; font-weight: 500; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.jc-bytask-money { text-align: right; }
/* Expected revenue / Earned so far / Margin — the same question the
   summary's own margin row asks for the whole job, one task at a time. */
.jc-bytask-margin {
  display: flex; flex-wrap: wrap; gap: 14px 28px;
  padding: 12px 16px; border-top: 1px solid var(--border);
}
.jc-bytask-margin-cell { display: flex; flex-direction: column; gap: 3px; }
.jc-bytask-margin-lbl {
  font-size: 10px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--text-dim);
}
.jc-bytask-margin-val { font-size: 14.5px; }
@media (max-width: 640px) {
  .jc-bytask-hint { margin-top: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   P&L — portfolio + statement (Task 3). A pure READ over Job Costs' and
   Contract's own numbers (jcFetchFeeds/jcComputeProject), so it borrows their
   vocabulary rather than inventing a fourth: .jv-money for every dollar
   figure, .jc-margin-val--ok/--err for profit/margin tone, .jc-group/
   .jc-section-title for the cost-by-group list, .jc-bytask-* for the by-task
   grid. Only the portfolio table and the statement's own headline/warnings
   are genuinely new.
   ══════════════════════════════════════════════════════════════════════════ */

/* Portfolio table — 8 columns wide, so it scrolls inside its OWN box; the
   page itself never gains a horizontal scrollbar (same rule as the by-task
   grid and the Contract tab's plan row). */
.pnl-table-wrap {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow-x: auto;
  margin-bottom: var(--space-6);
}
.pnl-table { width: 100%; min-width: 720px; border-collapse: collapse; }
.pnl-table th, .pnl-table td {
  padding: 11px 14px; text-align: right;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.pnl-table th:first-child, .pnl-table td:first-child { text-align: left; }
.pnl-table thead th {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--text-dim); background: var(--surface-2);
}
.pnl-table tbody tr:last-child td { border-bottom: 0; }
.pnl-row { cursor: pointer; }
.pnl-row:hover td { background: var(--surface-2); }
.pnl-cell-name { font-size: 13.5px; font-weight: 600; color: var(--text); }
.pnl-row--totals td {
  font-weight: 700; background: var(--surface-2);
  border-top: 1px solid var(--border-strong); border-bottom: 0;
}
.pnl-row--totals td:first-child { text-transform: uppercase; font-size: 11px; letter-spacing: 0.06em; color: var(--text-muted); }

/* Roll-up expand (subprojects) — the ▸/▾ toggle on a mother's row (same
   lucide chevron convention as Cost Recipes/Rates & Defaults' own expand
   affordances) and the indented building/"— general" rows it reveals.
   Money is real on either row; only the visual weight says "this is inside
   that". */
.pnl-expand-btn {
  background: none; border: 0; padding: 2px; margin: 0 6px 0 -4px;
  color: var(--text-dim); cursor: pointer; display: inline-flex; vertical-align: -3px;
}
.pnl-expand-btn:hover { color: var(--text); }
.pnl-expand-btn svg { width: 14px; height: 14px; stroke-width: 2px; }
.pnl-row--child td { background: var(--bg-1); }
.pnl-row--child .pnl-cell-name { padding-left: 34px; font-weight: 500; color: var(--text-dim); }
.pnl-row--general .pnl-cell-name { font-style: italic; }

/* Sortable column headers (Earned/Profit/Margin %) — plain text buttons, the
   active one gets the arrow and the brighter tone; the rest read like every
   other header. */
.pnl-sort-btn {
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; text-transform: inherit; letter-spacing: inherit;
  cursor: pointer; display: inline-flex; align-items: center; gap: 4px;
}
.pnl-sort-btn:hover, .pnl-sort-btn--active { color: var(--text); }
.pnl-sort-arrow { font-size: 9px; }

/* Statement — back link, header, revenue line, cost-by-group, overhead,
   profit/margin headline, by-task table, warnings, the Job Costs link. */
.pnl-back {
  display: inline-flex; align-items: center; gap: 7px;
  background: none; border: 0; padding: 0; margin-bottom: 16px;
  color: var(--text-muted); font: inherit; font-weight: 600; font-size: 13px; cursor: pointer;
}
.pnl-back svg { width: 15px; height: 15px; stroke-width: 1.85px; }
.pnl-back:hover { color: var(--text); }
/* Same class, reused inside the (chrome-fixed) job workspace head — see
   admin.html's #jobWorkspaceHead comment. Scoped override so the shared
   class still themes normally everywhere else (the P&L statement body). */
#jobWorkspaceHead .pnl-back { color: var(--chrome-text-muted); }
#jobWorkspaceHead .pnl-back:hover { color: var(--chrome-text); }

.pnl-stmt-head { margin-bottom: 18px; }
.pnl-stmt-title {
  font-family: var(--display); font-size: 22px; font-weight: 800;
  letter-spacing: -0.02em; color: var(--text); margin: 0 0 3px;
}
.pnl-stmt-meta { font-size: 12.5px; color: var(--text-dim); }

.pnl-stmt-revenue {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-xl);
  padding: 16px 18px; margin-bottom: 14px;
}
.pnl-stmt-revenue-lbl {
  display: block; font-size: 10.5px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-muted); margin-bottom: 4px;
}
.pnl-stmt-revenue-val {
  font-family: var(--display); font-size: 24px; font-weight: 800;
  letter-spacing: -0.02em; color: var(--text); font-variant-numeric: tabular-nums;
}
.pnl-stmt-revenue-foot { display: block; font-size: 12px; color: var(--text-dim); margin-top: 4px; }

.pnl-group-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 16px; border-bottom: 1px solid var(--border);
}
.pnl-group-row:last-child { border-bottom: 0; }
.pnl-group-label { flex: 1; min-width: 0; font-size: 13px; color: var(--text); }

.pnl-overhead-row {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px;
  padding: 4px 2px 14px;
}
.pnl-overhead-row > span:first-child {
  font-size: 12.5px; font-weight: 600; color: var(--text-muted); margin-right: auto;
}
.pnl-overhead-foot { font-size: 11.5px; color: var(--text-dim); flex-basis: 100%; }

/* The headline — the whole reason this screen exists — reuses .jc-margin-lbl/
   .jc-margin-val's type and ok/err tone (DESIGN.md: tone lives on the NUMBER
   only) at a larger size, side by side rather than stacked. */
.pnl-headline {
  display: flex; flex-wrap: wrap; gap: 18px 34px;
  padding: 16px 18px; margin-bottom: 16px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-xl);
}
.pnl-headline-cell { display: flex; flex-direction: column; gap: 4px; }
.pnl-headline .jc-margin-val { font-size: 28px; }

.pnl-warnings { margin: 4px 0 16px; display: flex; flex-direction: column; gap: 8px; }
.pnl-warning-item {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 10px 12px; border-radius: var(--r-lg);
  background: rgba(245, 158, 11, .08); border: 1px solid rgba(245, 158, 11, .25);
  font-size: 12.5px; line-height: 1.5; color: var(--text-muted);
}
.pnl-warning-item svg { width: 15px; height: 15px; flex: none; margin-top: 1px; color: var(--warning); stroke-width: 1.85px; }

.pnl-stmt-foot {
  margin-top: 6px; display: flex; align-items: center;
  justify-content: space-between; gap: 12px; flex-wrap: wrap;
}
.pnl-task-name {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 13px; font-weight: 600; color: var(--text);
}

/* ── Period selector (Task 4) — segmented Job to date / This month / Last
   month / Custom, rendered at the top of BOTH the portfolio and the
   statement (_pnlPeriodSelectorHtml). Borrows .ox-btn for the Apply button
   rather than inventing a second button style. */
.pnl-period-bar { margin-bottom: 18px; }
.pnl-period-seg {
  display: inline-flex; flex-wrap: wrap; gap: 2px;
  background: var(--surface-flat); border: 1px solid var(--border-strong);
  border-radius: var(--r-input); padding: 3px;
}
.pnl-period-btn {
  background: none; border: 0; padding: 7px 13px;
  font: inherit; font-size: 12.5px; font-weight: 700; color: var(--text-muted);
  border-radius: calc(var(--r-input) - 3px); cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.pnl-period-btn:hover { color: var(--text); }
.pnl-period-btn--active { background: var(--accent); color: var(--on-accent); }
.pnl-period-custom {
  display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap;
  margin-top: 10px;
}
.pnl-period-custom-lbl {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--text-muted);
}
.pnl-period-custom-lbl input[type="date"] {
  padding: 8px 10px; border: 1px solid var(--border-strong); border-radius: var(--r-input);
  background: var(--surface-2); color: var(--text); font: inherit; font-size: 13px;
}
.pnl-period-showing { font-size: 12px; color: var(--text-dim); margin-top: 8px; }
/* How a period is priced (rates stay live) — its own line under the bar. */
.pnl-period-note { font-size: 12px; line-height: 1.45; color: var(--text-dim); margin-top: 6px; max-width: 92ch; }
.pnl-period-error {
  font-size: 12px; font-weight: 600; color: var(--warning); margin-top: 8px;
}

/* Paired value (This Period / Job to Date) — every money row in the period
   statement uses this once a period is active (_pnlPairHtml); .jv-money
   itself is untouched so a paired figure still lines up with a plain one. */
.pnl-p2-pair { display: flex; gap: 18px; flex-wrap: wrap; }
.pnl-group-row .pnl-p2-pair, .pnl-overhead-row .pnl-p2-pair { margin-left: auto; }
.pnl-p2-cell { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; min-width: 74px; }
.pnl-p2-lbl {
  font-size: 9px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-dim);
}
.pnl-p2-pair--lg .jv-money { font-size: 21px; }

/* By-task, period mode — the SAME .jc-bytask-* grid (unchanged, still used
   as-is by Job Costs' own by-task view and the job-to-date-only case above)
   rendered twice, side by side on desktop, stacking on a narrow viewport via
   plain flex-wrap — no media query needed, and each column keeps its own
   .jc-bytask-scroll for the 375px case. */
.pnl-bytask-period-wrap { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 4px; }
.pnl-bytask-period-col { flex: 1 1 320px; min-width: 300px; }
.pnl-bytask-period-cap {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 6px;
}

@media (max-width: 640px) {
  .pnl-stmt-title { font-size: 19px; }
  .pnl-headline { gap: 14px 24px; padding: 14px; }
  .pnl-headline .jc-margin-val { font-size: 23px; }
  .pnl-p2-pair { gap: 12px; }
  .pnl-p2-cell { min-width: 62px; }
}

/* Mother statement's roll-up header + Buildings table (subprojects) — the
   SAME .pnl-headline/.jc-bytask-* shells the plain statement already uses,
   fed different numbers/columns; only these bits are new. */
.pnl-rollup-label {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-muted); margin: 0 0 6px;
}
.pnl-buildings-row { grid-template-columns: minmax(140px, 2fr) 90px 90px 90px 68px; }
.pnl-buildings-block { margin-bottom: 4px; }
.pnl-ownbooks-note { font-size: 12px; color: var(--text-dim); margin: 4px 0 16px; font-style: italic; }

/* ══════════════════════════════════════════════════════════════════════════
   HOME — the admin landing (project-first nav, Task 1). Deliberately borrows
   rather than invents: the hero's production card reuses Today's own
   .td-card/.td-pulse-card/.fh-pulse-* chart shell (js/core/pulse-chart.js's
   engine is shared, only the container is new); each job card's money strip
   reuses .jv-money/.jc-margin-val--ok/--err exactly like the P&L portfolio's
   row, and the crew avatars reuse Projects' own .pcard-avatars/.pcard-av.
   Only the card chrome itself is genuinely new. (The coverage chips and the
   missing-crew list went out on 2026-08-14 with the banner they belonged to.) ══════════════════════════════════════════════════════ */

.home-pulse-card, .home-pulse-empty { margin-bottom: 20px; }
.home-pulse-empty { color: var(--text-muted); font-size: 13px; }

.home-cards { display: flex; flex-direction: column; gap: 10px; }
.home-card {
  background: var(--surface-flat); border: 1px solid var(--border);
  border-radius: var(--r-xl); padding: 16px 18px;
  cursor: pointer; transition: border-color var(--t-fast);
}
.home-card:hover { border-color: var(--border-strong); }
.home-card--child { margin-left: 22px; background: var(--bg-1); }
.home-card-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px;
  margin-bottom: 12px;
}
.home-card-name { font-family: var(--display); font-size: 15px; font-weight: 800; color: var(--text); }
.home-card-code {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--text-dim); background: var(--surface-flat-3);
  border-radius: var(--r-sm); padding: 1px 6px;
}
.home-card-sub { font-size: 12px; color: var(--text-muted); }
.home-card-spacer { flex: 1; min-width: 8px; }
.home-card-week { font-size: 12px; font-weight: 600; color: var(--text-muted); white-space: nowrap; }
.home-card-week strong { color: var(--text); font-family: var(--display); font-size: 13px; }

.home-money-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px 16px; }
.home-money-cell { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.home-money-lbl {
  font-size: 10px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--text-dim);
}
.home-money-cell .jv-money { font-size: 15px; }

@media (max-width: 720px) {
  .home-money-row { grid-template-columns: repeat(2, 1fr); }
  .home-card--child { margin-left: 10px; }
}
@media (max-width: 480px) {
  .home-card { padding: 14px; }
  .home-card-row { gap: 6px 10px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   PRODUCTION — the quantities the two money screens are built on.

   Deliberately borrows Job Costs' statement language for the list itself
   (.jc-section-title / .jc-group / .jc-row): a grouped list of dated records
   with one control on the right is the same shape, and the three Projects
   money tabs should read as one system rather than three dialects. Only the
   parts with no existing equivalent are new — the per-item totals card, and
   the quantity chip that carries a running total.

   No ring gauge here: the O-ring is the "how covered / how complete"
   instrument, and installed-to-date is not a fraction of anything this screen
   knows. Borrowing it would be decoration on an auditing tool.
   ══════════════════════════════════════════════════════════════════════════ */
.pr-summary {
  position: relative;
  /* background-color, never the shorthand — the shorthand would wipe
     .ox-blueprint's grid image (same trap noted in styles.css). */
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-2xl);
  padding: 20px 22px;
  margin-bottom: 16px;
}
.pr-summary-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px 16px; flex-wrap: wrap; margin-bottom: 16px;
}
.pr-summary-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-muted);
}
.pr-summary-meta { font-size: 12.5px; color: var(--text-dim); }
.pr-summary-foot {
  margin-top: 16px; padding-top: 13px; border-top: 1px solid var(--border);
  font-size: 12.5px; line-height: 1.5; color: var(--text-dim);
}
/* The note names the two tabs this figure feeds, so the names are the
   navigation (prGoTo). `font: inherit` is right here — unlike the Contract
   figure above, these sit inside a sentence and must match it exactly. */
.pr-golink {
  padding: 0; border: none; background: none;
  font: inherit; font-weight: 600; color: var(--text);
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}
.pr-golink:hover, .pr-golink:focus-visible { color: var(--accent-ink); }

/* KPI tile per production item (DESIGN.md: uppercase Inter label, big Archivo
   number, Inter footnote). auto-fit rather than a fixed column count — a job
   with one item should not leave three empty cells, and a pack with six
   should not squeeze. */
.pr-tiles {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.pr-tile {
  background: var(--surface-flat);
  border: 1px solid var(--border);
  border-radius: var(--r-lg, 14px);
  padding: 13px 15px;
  min-width: 0;
}
.pr-tile--none { grid-column: 1 / -1; }
.pr-tile-lbl {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-muted);
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
}
.pr-tile-badge { text-transform: none; letter-spacing: 0; }
.pr-tile-val {
  font-family: var(--display); font-size: 27px; font-weight: 800;
  letter-spacing: -0.02em; color: var(--text); margin-top: 7px;
  font-variant-numeric: tabular-nums; line-height: 1.05;
  overflow-wrap: anywhere;
}
.pr-tile-unit {
  font-family: var(--body); font-size: 12.5px; font-weight: 600;
  letter-spacing: 0; color: var(--text-dim); margin-left: 6px;
}
.pr-tile-foot { font-size: 12px; color: var(--text-dim); margin-top: 4px; }

.pr-warn { margin-bottom: 16px; }

/* The report row: date + who on top, the day's quantities under it. */
.pr-row { align-items: flex-start; }
.pr-who { font-weight: 500; color: var(--text-muted); margin-left: 9px; }
.pr-sub-badge { margin-left: 6px; vertical-align: 1px; }
.pr-group-count {
  font-family: var(--body) !important; font-size: 12px !important;
  font-weight: 600 !important; letter-spacing: 0 !important;
  color: var(--text-dim) !important;
}

/* The font-size is set HERE, not only on .pr-chip: the "no items on this
   report" fallback and the amber flags are direct children too, and without a
   base size they inherit the body's ~15px and render LOUDER than the
   quantities they sit beside — the absence of data shouting over the data. */
.pr-chips {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin-top: 6px; font-size: 12.5px;
}
/* What went in that day, and the project total it rolls into — side by side,
   because the comparison IS the audit. */
.pr-chip {
  display: inline-flex; align-items: baseline; gap: 7px;
  background: var(--surface-flat-2, var(--surface-2));
  border: 1px solid var(--border);
  border-radius: var(--r-pill, 999px);
  padding: 3px 11px;
  font-size: 12.5px;
  min-width: 0;
}
.pr-chip--warn { border-color: rgba(245, 158, 11, 0.35); }
.pr-chip-name { color: var(--text-muted); font-weight: 600; }
.pr-chip-qty {
  font-family: var(--display); font-weight: 800; color: var(--text);
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
}
.pr-chip-run { color: var(--text-dim); font-size: 11.5px; font-variant-numeric: tabular-nums; }
/* A fact about the row, not an alarm: amber text only, no fill, no side border
   (red is danger and decoration borders are the AI tell — DESIGN.md). */
.pr-flag {
  display: inline-flex; align-items: center;
  font-size: 11.5px; font-weight: 600; color: var(--warning);
  padding: 3px 2px;
}
.pr-pdf { flex: 0 0 auto; margin-top: 1px; }
/* No PDF: a dim marker, never a control that does nothing when tapped. */
.pr-pdf--none {
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-dim); opacity: 0.45;
}
.pr-pdf--none svg { width: 15px; height: 15px; stroke-width: 1.85px; }

@media (max-width: 640px) {
  .pr-summary { padding: 16px; }
  .pr-tiles { grid-template-columns: 1fr; }
  .pr-tile-val { font-size: 24px; }
  /* The title wraps on a phone; who moves under the date rather than
     squeezing both onto one line. */
  .pr-who { display: block; margin-left: 0; margin-top: 2px; }
  .pr-chip { width: 100%; justify-content: space-between; border-radius: var(--r-lg, 14px); }
  .pr-chip-run { margin-left: auto; }
}

/* ══════════════════════════════════════════════════════════════════════════
   RATES & DEFAULTS — the money sheet.

   Four settings that all have the same shape: a thing, its unit, its price.
   One field grammar for all of them, so the eye learns the row once. Every
   value is tabular and right-aligned; every label is the same micro-caps.
   ══════════════════════════════════════════════════════════════════════════ */
.rt-card-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 3px;
}
.rt-chip {
  font-size: 11px; font-weight: 700; color: var(--text-dim);
  background: var(--surface-2); border: 1px solid var(--border);
  padding: 3px 9px; border-radius: var(--r-pill); white-space: nowrap;
}
.rt-chip--ok { color: var(--success); border-color: rgba(34,197,94,.30); background: rgba(34,197,94,.08); }

.rt-colhead {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-muted);
  padding-bottom: 7px; border-bottom: 1px solid var(--border); margin-bottom: 9px;
}
.rt-name { font-size: 13px; font-weight: 600; color: var(--text); min-width: 0; }
.rt-name-sub { display: block; font-size: 11.5px; font-weight: 500; color: var(--text-dim); }

/* The single money field used by every card on this tab. */
.rt-money { position: relative; display: flex; align-items: center; }
.rt-money-pre, .rt-money-post {
  position: absolute; color: var(--text-muted);
  font-size: 12px; font-weight: 600; pointer-events: none;
}
.rt-money-pre  { left: 10px; }
.rt-money-post { right: 10px; }
.rt-money input, .rt-text {
  width: 100%; min-width: 0;
  padding: 9px 11px; font-size: 13.5px;
  border: 1px solid var(--border-strong); border-radius: var(--r-input);
  background: var(--surface-2); color: var(--text);
}
.rt-money input {
  padding-left: 22px; text-align: right; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.rt-money--pct input { padding-right: 26px; }
/* Suffix-only field (a percent, no currency): no room needed on the left. */
.rt-money--suffix input { padding-left: 11px; padding-right: 28px; }
.rt-money input:focus, .rt-text:focus {
  outline: 2px solid var(--focus); outline-offset: 1px; border-color: transparent;
}

/* The Edit-price modal's Amount side for an OPEN line (jvOpenRateModal,
   68-jobvalue.js) — an open line has no estimated_qty to peg a total
   against, so this modal shows PRICE ONLY: the rate stays a real, editable
   .rt-money input, but the amount side is this static readout instead of a
   second live input that would silently do nothing. Same box footprint as
   a real .rt-money input (border/radius/padding) so the pair still reads as
   one aligned row, just visibly inert rather than editable. */
.jv-rate-modal-open-amt {
  padding: 9px 11px;
  font-size: 12.5px; font-weight: 600; text-align: right;
  border: 1px solid var(--border-strong); border-radius: var(--r-input);
  background: var(--surface-flat); color: var(--text-dim);
}

/* Pay rates: trade, wage, loaded */
.rt-pay-grid {
  display: grid; grid-template-columns: minmax(110px,1fr) 118px 118px;
  gap: 9px 14px; align-items: center; max-width: 520px;
}
.rt-pay-grid .rt-colhead { margin-bottom: 0; }

/* Crew → Trades: one row per trade, with how many workers still carry it.
   Same 36px icon button as the production-items rows (.rt-mt-btn). */
/* Fixed usage column, not auto: sized to content it made every name box a
   different width down the list. */
.cr-role-row {
  display: grid; grid-template-columns: minmax(140px, 1fr) 74px 36px;
  gap: 10px; align-items: center; margin-bottom: 8px;
}
.cr-role-use {
  font-size: 11.5px; font-weight: 600; color: var(--text-dim);
  white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums;
}

/* Production items: name, unit, rate, then hide + delete sharing one cell */
.rt-mt-head, .rt-mt-row, .rt-mt-add {
  display: grid; grid-template-columns: minmax(140px,1fr) 104px 124px 82px;
  gap: 9px; align-items: center;
}
.rt-mt-acts { display: flex; gap: 6px; justify-content: flex-end; }
.rt-mt-head .rt-colhead { margin-bottom: 0; }
.rt-mt-row { padding: 3px 0; }
.rt-mt-row--off { opacity: .5; }
/* The price box and how many jobs it prices; the unit once crews reported it. */
.rt-mt-price { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.rt-mt-used { font-size: 11px; font-weight: 600; color: var(--text-dim); }
.rt-unit-lock { display: flex; flex-direction: column; gap: 1px; min-width: 0; padding: 0 2px; }
.rt-unit-lock-u { font-size: 13.5px; font-weight: 600; color: var(--text); }
.rt-unit-lock-n { font-size: 11px; font-weight: 600; color: var(--text-dim); }
/* The name once crews reported the item (R3): text with a lock, where the box was. */
.rt-name-lock { display: flex; align-items: center; gap: 7px; min-width: 0; padding: 0 2px; font-size: 13.5px; font-weight: 600; color: var(--text); }
.rt-name-lock svg { width: 13px; height: 13px; flex: none; color: var(--text-dim); }
.rt-name-lock span { min-width: 0; overflow-wrap: anywhere; }
.rt-mt-btn {
  display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0;
  background: none; border: 1px solid var(--border); border-radius: var(--r-md);
  color: var(--text-muted); cursor: pointer;
}
.rt-mt-btn:hover { color: var(--text); border-color: var(--border-strong); }
.rt-mt-btn svg { width: 15px; height: 15px; }
/* Destructive, so it only turns red under the pointer — a row of red bins would
   read as an alarm on a screen where nothing is wrong. */
.rt-mt-btn--del:hover { color: var(--error-ink); border-color: rgba(239, 68, 68, 0.45); }
.rt-mt-modal { max-width: 460px; }
.rt-mt-modal .admin-modal-body { padding: 16px 22px 22px; }
.rt-mt-modal-line {
  margin: 0 0 8px; max-width: 60ch;
  font-size: 13px; font-weight: 500; line-height: 1.5; color: var(--text-muted);
}
.rt-mt-add { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.rt-mt-add .ox-btn { grid-column: 3 / -1; }
.rt-mt-toggle, .rt-dp-pack-head {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 10px 2px; min-height: 44px;
  background: none; border: 0; cursor: pointer;
  color: var(--text-dim); font: inherit; text-align: left;
}
.rt-mt-toggle { font-size: 12.5px; font-weight: 600; }
.rt-mt-toggle:hover { color: var(--text); }
.rt-mt-toggle svg, .rt-dp-pack-head svg { width: 14px; height: 14px; flex: none; color: var(--text-muted); }

/* Delivery prices, folded per trade pack */
.rt-dp-needs {
  border: 1px solid rgba(245,158,11,.35);
  background: rgba(245,158,11,.07);
  border-radius: var(--r-xl);
  padding: 13px 15px; margin-bottom: 18px;
}
.rt-dp-needs-head {
  display: flex; align-items: center; gap: 7px;
  font-size: 13px; font-weight: 700; color: var(--warning);
}
.rt-dp-needs-head svg { width: 15px; height: 15px; }
.rt-dp-needs-sub { font-size: 12px; line-height: 1.5; color: var(--text-dim); margin: 4px 0 12px; }
/* A pre-filled price book says so above the list (features.price_book_note). */
.rt-dp-note {
  display: flex; align-items: flex-start; gap: 8px;
  margin-bottom: 12px; padding: 9px 12px;
  border: 1px solid var(--border-strong); border-radius: 8px; background: var(--surface-flat-2);
  font-size: 13px; line-height: 1.5; font-weight: 600; color: var(--text);
}
.rt-dp-note svg { width: 16px; height: 16px; flex: none; margin-top: 2px; color: var(--warning); }
.rt-dp-pack { border-top: 1px solid var(--border); }
.rt-dp-pack:first-of-type { border-top: 0; }
.rt-dp-pack-head:hover .rt-dp-pack-name { color: var(--accent-ink); }
.rt-dp-pack-name { font-size: 13.5px; font-weight: 600; color: var(--text); }
.rt-dp-pack-count { margin-left: auto; font-size: 11.5px; font-weight: 600; color: var(--text-dim); white-space: nowrap; }
.rt-dp-pack-count--some { color: var(--success); }
.rt-dp-pack-body { padding: 2px 0 10px 23px; }
.rt-dp-grid {
  display: grid; grid-template-columns: minmax(150px,1fr) 132px minmax(196px,238px);
  gap: 7px 14px; align-items: center; max-width: 1080px;
}
/* How the supplier packs it: "[48] [bags] per pallet", and underneath what one
   of those pieces costs. Beside the price on purpose — "$415.68 a pallet, and a
   pallet is 48 bags" is one thought, and the derived $8.66 a bag is the number
   the owner is actually after when he writes a recipe. */
.rt-pk { display: flex; align-items: center; flex-wrap: wrap; gap: 5px 6px; }
.rt-pk-n, .rt-pk-u {
  min-width: 0; padding: 9px 10px; font-size: 13.5px;
  border: 1px solid var(--border-strong); border-radius: var(--r-input);
  background: var(--surface-2); color: var(--text);
}
.rt-pk-n { width: 62px; text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }
.rt-pk-u { width: 78px; }
.rt-pk-n:focus, .rt-pk-u:focus {
  outline: 2px solid var(--focus); outline-offset: 1px; border-color: transparent;
}
.rt-pk-per { font-size: 11.5px; color: var(--text-dim); white-space: nowrap; }
.rt-pk-each {
  flex-basis: 100%; font-size: 11.5px; font-weight: 600;
  color: var(--text-muted); font-variant-numeric: tabular-nums;
}
/* The price box and the tax rule it follows ("+ 7% PST" / "PST included"),
   under it — one cell of the grid. Same pill in Cost Recipes. */
.rt-price { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.rt-pst { align-self: flex-start; letter-spacing: 0; }
.cx-pst { letter-spacing: 0; margin-left: 6px; }
.cx-line-src .cx-pst { margin-left: 0; display: inline-block; margin-top: 3px; }
.rt-dp-cat {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-muted); margin-bottom: 6px;
}
.rt-dp-hidden {
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border);
  font-size: 12px; line-height: 1.5; color: var(--text-dim);
}

/* Overhead: one number, so give it room instead of a row. */
.rt-oh { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; }
.rt-oh .rt-money { width: 116px; }
.rt-oh-note { font-size: 12.5px; color: var(--text-dim); }

@media (max-width: 640px) {
  .rt-pay-grid { grid-template-columns: 1fr 1fr; }
  .rt-pay-grid .rt-colhead:first-child { display: none; }
  .rt-mt-head { display: none; }
  .rt-mt-row, .rt-mt-add { grid-template-columns: 1fr 1fr; }
  .rt-mt-row > .rt-text:first-child, .rt-mt-row > .rt-name-lock, .rt-mt-add input:first-child { grid-column: 1 / -1; }
  /* Hide + delete get their own row on the phone, full-width and thumb-sized. */
  .rt-mt-acts { grid-column: 1 / -1; }
  .rt-mt-btn { width: 44px; height: 44px; }
  /* Delivery prices on a phone (2026-11-04, "não coube, há desperdício de
     área"): one item = two lines. The name runs across the top with its unit
     beside it; the price and the pack boxes share the line under it. The same
     "+ 7% PST" pill on all 122 rows said one thing 122 times: on a phone the
     card's "before any tax" line moves above the list and says it once. */
  .rt-dp-pack-body { padding-left: 0; }
  #tab-rates .rt-money input, #tab-rates .rt-text, #tab-rates #dpSearch { min-height: 44px; }
  .rt-dp-grid { grid-template-columns: 112px 1fr; gap: 6px 10px; }
  .rt-dp-grid > .rt-name { grid-column: 1 / -1; padding-top: 10px; border-top: 1px solid var(--border); }
  .rt-dp-grid > .rt-name:first-child { padding-top: 2px; border-top: 0; }
  .rt-dp-grid > .rt-name .rt-name-sub { display: inline; margin-left: 6px; }
  .rt-dp-grid > .rt-pk { padding-bottom: 6px; gap: 5px; }
  .rt-dp-grid .rt-pst { display: none; }
  .rt-pk-n, .rt-pk-u { min-height: 44px; }
  .rt-pk-n { width: 52px; }
  .rt-pk-u { width: 72px; }
  #tab-rates .admin-card:has(> #delivPricesBody) { display: flex; flex-direction: column; }
  #delivPricesBody { order: 2; }
  #delivPricesBody ~ * { order: 1; margin: 0 0 12px !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   COST RECIPES — what one unit of work consumes.
   The bridge between the two material lists: production items (what the crew
   builds) and delivery materials (what the crew orders). Shares the statement
   language of Job Costs (.jc-group, .jc-grand, .jc-section-title) and the
   money-box language of Rates & Defaults (.rt-money, .rt-mt-btn), because it
   is the same kind of screen doing the same kind of work.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Which method this job costs by ──────────────────────────────────────── */
.cx-method-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); padding: 15px 16px; margin-bottom: 18px;
}
.cx-method-head {
  display: flex; align-items: center; gap: 12px; margin-bottom: 12px;
}
.cx-method-lbl {
  flex: 1; min-width: 0;
  font-size: 11px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-muted);
}
.cx-golink {
  display: inline-flex; align-items: center; gap: 5px;
  min-height: 32px; padding: 0 4px;
  background: none; border: 0; cursor: pointer;
  color: var(--text-dim); font: inherit; font-size: 12.5px; font-weight: 700;
}
.cx-golink svg { width: 14px; height: 14px; stroke-width: 2.2px; }
.cx-golink:hover { color: var(--accent-ink); }

.cx-methods { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
/* Two choices side by side with what each one MEANS underneath — not a switch
   labelled "recipe" whose consequences the owner has to remember. */
.cx-method {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 13px 14px; text-align: left;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-lg); cursor: pointer;
  color: var(--text); font: inherit;
}
.cx-method:hover { border-color: var(--border-strong); }
.cx-method--on { border-color: var(--accent-ring, rgba(248,144,16,.30)); background: var(--soft); }
.cx-method-mark {
  flex: none; width: 16px; height: 16px; margin-top: 2px;
  border: 2px solid var(--text-dim); border-radius: 50%;
}
.cx-method--on .cx-method-mark {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 3px var(--accent), inset 0 0 0 4px var(--bg-1);
}
.cx-method-txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cx-method-title { font-size: 13.5px; font-weight: 700; }
.cx-method--on .cx-method-title { color: var(--accent-ink); }
.cx-method-body { font-size: 12px; line-height: 1.5; color: var(--text-muted); }
.cx-method-foot {
  font-family: var(--display); font-size: 12.5px; font-weight: 700;
  letter-spacing: -0.01em; color: var(--text); margin-top: 3px;
  font-variant-numeric: tabular-nums;
}
.cx-method-warn:empty { display: none; }
.cx-method-warn { margin-top: 10px; font-size: 12.5px; color: var(--error); }

/* ── List 1: one production item, opening onto its components ────────────── */
.cx-item { margin-bottom: 10px; }
.cx-item-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  width: 100%; min-height: 46px; padding: 11px 16px;
  background: var(--surface-2); border: 0; border-bottom: 1px solid var(--border);
  color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.cx-item-head:hover .cx-item-name { color: var(--accent-ink); }
.cx-item-chev { width: 15px; height: 15px; flex: none; color: var(--text-muted); }
.cx-item-name {
  font-family: var(--display); font-size: 14.5px; font-weight: 700;
  letter-spacing: -0.01em; color: var(--text); min-width: 0;
}
.cx-item-unitcost {
  margin-left: auto; font-size: 12.5px; font-weight: 600;
  color: var(--text-muted); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.cx-item-foot {
  padding: 8px 16px; font-size: 12px; color: var(--text-dim);
  border-bottom: 1px solid var(--border);
}
.cx-item:last-child .cx-item-foot { border-bottom: 0; }

/* ── List 2: the components of one item ──────────────────────────────────── */
.cx-lines { padding: 10px 16px 14px; }
.cx-line {
  display: grid;
  grid-template-columns: minmax(150px, 1fr) minmax(222px, 262px) 112px minmax(84px, 118px) 104px 38px;
  gap: 8px 12px; align-items: center; padding: 5px 0;
}
.cx-line--head {
  padding-bottom: 8px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-muted);
}
.cx-line-name { font-size: 13px; font-weight: 600; color: var(--text); min-width: 0; }
.cx-line-unit { display: block; font-size: 11.5px; font-weight: 500; color: var(--text-dim); }
.cx-line-price input { width: 100%; }

/* The consumption, written as a sentence instead of asked for as a fraction:
   "1 bag [covers ▾] [14] count". The two words in the select flip which side of
   the sentence the 1 sits on, which is the whole difference between a bag that
   lays 14 blocks and a block that takes 2 ties. */
.cx-line-use { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 6px; }
.cx-use-lead, .cx-use-tail {
  font-size: 12px; color: var(--text-dim); white-space: nowrap;
}
.cx-use-mode, .cx-use-val {
  min-width: 0; padding: 7px 8px; font-size: 12.5px;
  border: 1px solid var(--border-strong); border-radius: var(--r-input);
  background: var(--surface-2); color: var(--text);
}
.cx-use-mode { font-weight: 600; cursor: pointer; }
.cx-use-val {
  width: 66px; text-align: right; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.cx-use-mode:focus, .cx-use-val:focus {
  outline: 2px solid var(--focus); outline-offset: 1px; border-color: transparent;
}
.cx-line-each {
  font-family: var(--display); font-size: 13.5px; font-weight: 700;
  letter-spacing: -0.01em; color: var(--text); text-align: right;
  font-variant-numeric: tabular-nums;
}
/* The fraction of an ordered unit the sentence above works out to — the number
   this screen used to demand by hand. Kept in view, small and quiet, so the
   arithmetic can still be audited by anyone who wants to. */
.cx-line-conv {
  display: block; font-family: var(--font); font-size: 11px; font-weight: 500;
  color: var(--text-dim); letter-spacing: 0;
}
/* This component is consumed but has no price anywhere — the one thing on this
   screen that is actually costing the owner an understated job. Amber warns;
   red stays reserved for destructive and overdue (DESIGN.md). */
.cx-line--gap .cx-line-name { color: var(--warning); }
/* The measured sentence under the recipe's: what this job's deliveries say the
   line really consumed, and the one-click adoption. Quiet — it is a reading,
   not a warning. */
.cx-line-meas {
  display: flex; align-items: center; justify-content: flex-end; gap: 6px; flex-wrap: wrap;
  margin-top: 3px; font-family: var(--font); font-size: 11px; font-weight: 500;
  color: var(--text-muted); letter-spacing: 0; text-align: right;
}
.cx-meas-use { min-height: 24px; padding: 0 8px; font-size: 11px; }
/* Batch "use the logged amount" (2026-09-29): a tick beside each Use, and a
   bar on top of the item's components with Select all + one button. */
.cx-meas-pick { display: inline-flex; align-items: center; gap: 6px; min-height: 32px; font-size: 12px; font-weight: 600; color: var(--text-dim); cursor: pointer; }
.cx-meas-pick input { width: 18px; height: 18px; margin: 0; accent-color: var(--accent-ink); cursor: pointer; }
.cx-bulk { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px;
  padding: 10px 12px; margin-bottom: 8px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface); }
.cx-bulk .cx-meas-pick { color: var(--text); }
.cx-bulk-go { min-height: 40px; }
.cx-bulk-go:disabled { opacity: .45; cursor: not-allowed; }
.cx-item-meas { display: block; font-family: var(--font); font-size: 11px; font-weight: 500; color: var(--text-muted); letter-spacing: 0; }
.cx-line-src { font-size: 11.5px; min-width: 0; }
.cx-book { color: var(--text-dim); }
/* The price-book value, replaced by one the owner typed: shown dimmed and
   struck beside the lit value in the box. The same language the Job Costs
   deliveries use when a job costs by recipe. */
.cx-book--struck {
  text-decoration: line-through; text-decoration-thickness: 1px;
  font-variant-numeric: tabular-nums;
}
.cx-book--none { color: var(--warning); }
/* Review D12: the items nothing was installed of, folded; the one-line reason
   a delivered-vs-used row is off. D6: the last Use, with its Undo. */
.rx-idle { padding-top: 8px; padding-bottom: 8px; }
.rx-idle .rx-idle-btn { min-height: 44px; height: auto; width: 100%; white-space: normal; padding: 6px 12px; }
.jw-what-s.rx-dv-why { margin-top: 2px; white-space: normal; overflow: visible; }
.rx-dv-why--short { color: var(--warning-ink); font-weight: 600; }
.cx-undo { background: var(--success-soft); font-size: 12.5px; color: var(--text); }
.cx-undo .cx-undo-btn { min-height: 44px; min-width: 72px; }

/* Job Costs › "Recent changes on this project" (review D10, 73-job-changes.js). */
.jcx > summary { list-style: none; cursor: pointer; min-height: 44px; }
.jcx > summary::-webkit-details-marker { display: none; }
.jcx[open] > summary .cw-chevron svg { transform: rotate(90deg); }
.jcx > summary .cw-head-tt { align-items: center; }
.jcx-body { border-top: 1px solid var(--border); }
.jcx-empty { padding: 14px var(--row-pad-x, 16px); font-size: 12.5px; color: var(--text-dim); }
.jcx-row { padding: 10px var(--row-pad-x, 16px); border-bottom: 1px solid var(--border); font-size: 12.5px; min-width: 0; }
.jcx-row:last-child { border-bottom: 0; }
.jcx-when { font-size: 11.5px; color: var(--text-label); }
.jcx-what { margin-top: 2px; overflow-wrap: anywhere; }
.jcx-diff { margin-top: 2px; color: var(--text-2); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.cx-lines-empty { padding: 10px 0; font-size: 12.5px; color: var(--text-dim); }
.cx-add {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 40px; margin-top: 8px; padding: 0 12px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-lg); cursor: pointer;
  color: var(--text); font: inherit; font-size: 12.5px; font-weight: 600;
}
.cx-add:hover { border-color: var(--border-strong); color: var(--accent-ink); }
.cx-add svg { width: 14px; height: 14px; }
/* "Add a component" and "Import from another project" are the two ways this
   item's recipe gets written, so they sit side by side rather than one
   looking like the primary path and the other like an afterthought. */
.cx-add-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; }
.cx-add-row .cx-add { margin-top: 0; }
.cx-add-import svg { width: 14px; height: 14px; }

/* ── Import: copy a whole item's recipe from another project ─────────────── */
.cx-import-list { display: flex; flex-direction: column; gap: 6px; }
.cx-import-src {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; min-height: 42px; padding: 8px 12px; text-align: left;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); cursor: pointer; color: var(--text); font: inherit;
}
.cx-import-src:hover { border-color: var(--accent-ring, rgba(248,144,16,.30)); }
.cx-import-src:hover .cx-import-src-name { color: var(--accent-ink); }
.cx-import-src-name { font-size: 12.5px; font-weight: 600; min-width: 0; }
.cx-import-src-count {
  flex: none; font-size: 11.5px; color: var(--text-dim); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ── The component picker: pack → category, never a flat list of 86 ──────── */
.cx-picker {
  margin-top: 10px; padding: 12px 14px;
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
}

/* ── Export to other jobs ────────────────────────────────────────────────────
   The section title and its one action share a row. The title keeps its own
   .jc-section-title margins everywhere else on the screen, so those are
   neutralised HERE rather than weakened at the source. */
.cx-list-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin: 22px 0 10px;
}
.cx-list-title { margin: 0; }
.cx-export { margin-bottom: 14px; }
/* Two columns where there is room — what goes, and where it goes — stacking on
   a narrow screen. 560px, not a device name: it is the width at which two
   lists of job names stop being readable side by side. */
.cx-export-cols { display: grid; gap: 14px; margin-top: 10px; }
@media (min-width: 560px) { .cx-export-cols { grid-template-columns: 1fr 1fr; } }
.cx-export-list {
  display: flex; flex-direction: column; gap: 2px;
  max-height: 260px; overflow-y: auto;
}
.cx-export-row {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 8px; border-radius: 8px; cursor: pointer;
  font-size: 12.5px; color: var(--text);
}
.cx-export-row:hover { background: var(--surface-flat-2); }
.cx-export-row input { flex: none; width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; }
.cx-export-row input:disabled { cursor: default; }
.cx-export-name { flex: 1; min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cx-export-count { flex: none; font-size: 11px; font-weight: 500; color: var(--text-dim); }
/* "This one already has a recipe and the copy will overwrite it" — stated on
   the row, in the same amber the app uses for "read this before you commit".
   Tone on the TEXT, never a filled background (DESIGN.md). */
.cx-export-warn {
  flex: none; font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--accent-ink);
}
.cx-export-foot, .cx-export-done {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--border);
}
/* The action keeps its own size. Without this it is a flex ITEM in a
   space-between row and stretches into a full-width orange slab that reads as
   the most important thing on the screen, which it is not. */
.cx-export-foot > button { flex: none; }
.cx-export-summary { flex: 1; min-width: 0; font-size: 12px; color: var(--text-dim); }
.cx-export-done { font-size: 12.5px; font-weight: 600; color: var(--success-ink, var(--success)); }
.cx-export-fail {
  flex-basis: 100%; margin-top: 6px;
  font-size: 11.5px; font-weight: 500; color: var(--error);
}
.cx-picker-head {
  display: flex; align-items: center; gap: 10px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-muted);
}
.cx-picker-head > span { flex: 1; min-width: 0; }
.cx-picker-close {
  flex: none; width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; border-radius: 8px; cursor: pointer;
  color: var(--text-dim);
}
.cx-picker-close:hover { color: var(--text); background: var(--surface-3); }
.cx-picker-close svg { width: 15px; height: 15px; }
.cx-picker-sub { font-size: 12px; line-height: 1.5; color: var(--text-dim); margin: 5px 0 10px; }
.cx-picker-pack { border-top: 1px solid var(--border); }
.cx-picker-pack:first-of-type { border-top: 0; }
.cx-picker-cat { margin: 8px 0 12px; }
.cx-picker-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 7px;
}
.cx-pick {
  display: flex; flex-direction: column; gap: 2px;
  min-height: 44px; padding: 8px 11px; text-align: left;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); cursor: pointer; color: var(--text); font: inherit;
}
.cx-pick:hover { border-color: var(--accent-ring, rgba(248,144,16,.30)); }
.cx-pick:hover .cx-pick-name { color: var(--accent-ink); }
.cx-pick-name { font-size: 12.5px; font-weight: 600; }
.cx-pick-meta { font-size: 11px; color: var(--text-dim); }

/* ── The job's whole recipe cost ─────────────────────────────────────────── */
/* "Files under" — which group this component's money lands in on Job Costs.
   Lives under the name with the other line facts, same quiet weight; the
   select is the compact inline kind the how-much cell already uses. */
.cx-line-files {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; color: var(--text-dim);
}
.cx-line-topic {
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 7px;
  color: var(--text); font-family: var(--font); font-size: 11.5px; font-weight: 600;
  padding: 3px 6px; min-height: 26px; cursor: pointer;
}
/* Type-your-own component — one row: name, unit, price, add. */
.cx-custom { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.cx-custom-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.cx-custom-row #rxCustomName { flex: 2 1 200px; }
.cx-custom-row .cx-custom-unit { flex: 1 1 110px; max-width: 140px; }
.cx-custom-row .rt-money input { width: 90px; }

/* The switchover nudge borrows .jc-unfiled wholesale; it only needs its own
   breathing room above the method card. */
.cx-nudge { margin-bottom: 14px; }

.cx-grand { margin-top: 14px; }
.cx-total-note { margin-top: 8px; font-size: 12px; line-height: 1.5; color: var(--text-dim); }

@media (max-width: 900px) {
  .cx-methods { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  /* The name and the remove control (Material by task, 2026-11-02: the boxes
     and the money left the row). Each cell is placed explicitly.
     The selector has to OUTRANK the workspace's own stacking rule
     (.cw-card:not(.cw-keepgrid) .cw-row → one column, redesign-tokens.css,
     loaded after this file). Plain `.cx-line` lost to it: the row had ONE real
     column and a cell placed in column 2 made an implicit one as wide as its
     text. minmax(0, …): a long name wraps beside the 44px control. */
  .cw-card .cx-lines .cw-row.cx-line { grid-template-columns: minmax(0, 1fr) 44px; gap: 6px 10px; }
  .cx-line--head { display: none; }
  .cx-line-name  { grid-column: 1; }
  .cx-line-del   { grid-column: 2; }
  .cx-item-unitcost { margin-left: 0; width: 100%; }
  .cx-picker-close { width: 44px; height: 44px; }
  .cx-picker-grid { grid-template-columns: 1fr; }
  .cx-add-row { flex-direction: column; align-items: stretch; }
  .cx-add, .cx-add-import, .cx-import-src { min-height: 44px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   T2 light-sweep dark pins (2026-08-05) — a small set of persistent badges/
   hover states hand-coded --accent-bright (#FFA940) as TEXT before this
   sweep (not the plain --accent #F89010 that --accent-ink now mirrors in
   dark — see css/styles.css [data-theme="dark"] comment). Rewired to
   --accent-ink for a readable light value; pinned here so dark keeps
   rendering the exact original bright yellow, untouched.
   ═══════════════════════════════════════════════════════════════════════════ */
[data-theme="dark"] .td-viewall:hover,
[data-theme="dark"] .ox-dayhead span:first-child,
[data-theme="dark"] .ox-empty-btn,
[data-theme="dark"] .dx-pill--on,
[data-theme="dark"] .nx-channel,
[data-theme="dark"] .doc-file-title:hover,
[data-theme="dark"] .plist-code,
[data-theme="dark"] .jc-method-link:hover {
  color: var(--accent-bright);
}

/* Same reasoning, semantic side: these 3 call sites hardcoded a one-off red/
   amber (not the exact --error-bright/--warning-bright the -ink tokens now
   mirror in dark) — rewired to -ink above; pinned here to keep dark's exact
   original shade. */
[data-theme="dark"] .admin-btn-danger { color: #e05555; }
[data-theme="dark"] .doc-queue-remove:hover { color: #ef4444; }
[data-theme="dark"] .gantt-label-dep { color: #f59e0b; }

/* ═══════════════════════════════════════════════════════════════════════════
   T2 light-sweep dark pins, round 2 (2026-08-05) — white-alpha hairlines/
   hover washes and a few one-off literals that were tuned for the obsidian
   surface and read as dark-ink-alpha mirrors in light (same alpha, opposite
   polarity — the same convention css/styles.css uses for --border/
   --border-subtle). Pinned here so [data-theme="dark"] reproduces v485
   exactly; light values live at each rule's own definition above.
   ═══════════════════════════════════════════════════════════════════════════ */
[data-theme="dark"] .admin-table-row:hover,
[data-theme="dark"] .ctr-row:hover,
[data-theme="dark"] .sx-row:hover,
[data-theme="dark"] .dx-row:hover,
[data-theme="dark"] .fb-cv-field:hover {
  background: rgba(255, 255, 255, 0.025);
}
[data-theme="dark"] .bp-head:hover { background: rgba(255, 255, 255, 0.02); }
[data-theme="dark"] .sch-acc { background: rgba(255, 255, 255, 0.03); }
[data-theme="dark"] .ctr-row,
[data-theme="dark"] .sx-row,
[data-theme="dark"] .ppl-row,
[data-theme="dark"] .dx-row,
[data-theme="dark"] .dx-detail,
[data-theme="dark"] .crp-row,
[data-theme="dark"] .crc-row {
  border-bottom-color: rgba(255, 255, 255, 0.04);
}
[data-theme="dark"] .dash-skel {
  background: linear-gradient(90deg, rgba(255,255,255,0.04) 25%, rgba(255,255,255,0.09) 37%, rgba(255,255,255,0.04) 63%);
}
/* Gantt: tick divider, zebra stripe, label/track separators, weekly
   gridline (2 layers), Sunday-shading wash, dependency-arrow connector. */
[data-theme="dark"] .gantt-tick--wk { border-left-color: rgba(255,255,255,0.30); }
[data-theme="dark"] .gantt-row:nth-child(even) .gantt-track { background: rgba(255,255,255,0.015); }
[data-theme="dark"] .gantt-label { border-bottom-color: rgba(255,255,255,0.14); }
[data-theme="dark"] .gantt-track {
  border-bottom-color: rgba(255,255,255,0.14);
  background-image:
    repeating-linear-gradient(to right, rgba(150,160,190,0.11) 0, rgba(150,160,190,0.11) var(--d), transparent var(--d), transparent var(--wk)),
    repeating-linear-gradient(to right, transparent 0, transparent calc(var(--wk) - 1px), rgba(255,255,255,0.16) var(--wk));
}
[data-theme="dark"] .gantt-arrows path { stroke: rgba(210,215,230,0.55); }
[data-theme="dark"] .gantt-arrowhead { fill: rgba(210,215,230,0.8); }
/* Invite User modal (#inviteModal) — .adm-lbl/.adm-inp/.adm-sheet-footer
   were hardcoded dark-only before any theme existed; tokenized above. */
[data-theme="dark"] .adm-lbl { color: #7b82a0; }
[data-theme="dark"] .adm-inp {
  background: #12141e;
  border-color: rgba(255,255,255,.1);
  color: #eef0f8;
}
[data-theme="dark"] .adm-inp:focus {
  border-color: #3b5bc8;
  box-shadow: 0 0 0 3px rgba(59,91,200,.18);
}
[data-theme="dark"] .adm-inp::placeholder { color: #40475e; }
/* --bg-input was never a defined token (always fell through to its literal
   fallback in both themes) — the Schedule tab's filter select rendered
   hardcoded near-black regardless of theme. Pinned so dark keeps that exact
   historical shade even though it's not byte-identical to any real token. */
[data-theme="dark"] .dash-filter-select { background: #1a1a1a; color: #eee; }
/* Same --bg-input non-token bug, People tab's role <select>: pinned to its
   exact original hardcoded fallback (#222/#eee/#444), byte-identical. */
[data-theme="dark"] .role-select { background: #222; color: #eee; border-color: #444; }
/* Schedule/Gantt toolbar pills — restore the exact original pale text
   (chosen for legibility against near-black) and, for .sched-pill--mu,
   the exact original white-alpha ghost background. Same hover-specificity
   fix as the light rules above (review round 2): `[data-theme="dark"]
   .sched-pill--ok` alone (0,2,0) only beat `.admin-btn-sm:hover` (0,2,0) by
   SOURCE ORDER (this block happens to sit later in the file) — one
   reorder away from silently losing the tint on hover. Compounded with
   `.admin-btn-sm` (0,3,0 base / 0,4,0 :hover) removes that dependency
   entirely, in both themes. */
[data-theme="dark"] .admin-btn-sm.sched-pill--ok,
[data-theme="dark"] .admin-btn-sm.sched-pill--ok:hover   { color: #86efac; }
[data-theme="dark"] .admin-btn-sm.sched-pill--warn,
[data-theme="dark"] .admin-btn-sm.sched-pill--warn:hover { color: #fcd34d; }
[data-theme="dark"] .admin-btn-sm.sched-pill--info,
[data-theme="dark"] .admin-btn-sm.sched-pill--info:hover { color: #93c5fd; }
[data-theme="dark"] .admin-btn-sm.sched-pill--mu,
[data-theme="dark"] .admin-btn-sm.sched-pill--mu:hover   { background: rgba(255,255,255,0.08); color: #ddd; }
[data-theme="dark"] .sched-input { background: #222; }
[data-theme="dark"] .sched-stage-card { background: rgba(255, 255, 255, 0.03); }

/* --text-faint → --text-dim real-text fix (review round, 2026-08-05): the
   3 sites below (.td-f-nosub, .td-cell--na, base .cm-cell) were rewired to
   --text-dim so the LIGHT theme clears AA (--text-faint fails as text in
   both themes, always has). That swap also silently changed DARK — the
   dark baseline rule is v485 EXACTLY, so all 3 are pinned back to
   --text-faint here; light keeps --text-dim at each rule's own definition.
   .cm-cell needs :not() rather than a plain pin: it shares its base class
   with .cm-cell--ok/--warn/--x on the same element, and a bare
   `[data-theme="dark"] .cm-cell` pin would outrank those modifiers'
   own (correct, untouched) success/warning-ink/error-ink colors. */
[data-theme="dark"] .td-f-nosub,
[data-theme="dark"] .td-cell--na {
  color: var(--text-faint);
}
[data-theme="dark"] .cm-cell:not(.cm-cell--ok):not(.cm-cell--warn):not(.cm-cell--x) {
  color: var(--text-faint);
}

/* Compliance evidence-pack card — sweep miss fix (2026-08-05): the base
   rule above now themes to a white card in light; dark keeps the exact
   original obsidian gradient it always had, byte-identical. */
[data-theme="dark"] .cr-pack {
  background: linear-gradient(160deg, #1a1a12, #14150f);
}

/* ── Touch ergonomics (gauntlet 2026-08-08, finding B: sub-44px targets) ──
   Small controls keep their VISUAL size but gain an invisible ≥44px hit
   area on touch widths. The ::after inset math is negative only when the
   control is smaller than 44px on that axis, so big buttons are untouched.
   Percentages resolve per-axis against the button's own box. */
@media (max-width: 1023px) {
  .ox-iconbtn, .nx-chip-x, .eq-btn-sm, .wk-cat-del,
  .admin-back-btn, .admin-logout-btn, .admin-tab { position: relative; }
  .ox-iconbtn::after, .nx-chip-x::after, .eq-btn-sm::after, .wk-cat-del::after,
  .admin-back-btn::after, .admin-logout-btn::after, .admin-tab::after {
    content: '';
    position: absolute;
    top:    min(0px, calc((100% - 44px) / 2));
    bottom: min(0px, calc((100% - 44px) / 2));
    left:   min(0px, calc((100% - 44px) / 2));
    right:  min(0px, calc((100% - 44px) / 2));
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   CHECKLIST — the per-job pre-construction list (2026-09-23).
   One grid, one row per item. The row's colour IS its status: green done,
   red pending (Renan's spec); a row marked "not included" fades instead —
   it is not work, so it is neither. Wide content scrolls inside .ck-table,
   never the page.
   ══════════════════════════════════════════════════════════════════════════ */
.ck-head { display: flex; align-items: center; justify-content: space-between; gap: 18px; flex-wrap: wrap;
  padding: 14px 16px; margin-bottom: 12px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); }
.ck-head-n { font-family: var(--display); font-size: 18px; font-weight: 800; letter-spacing: -0.01em; }
.ck-head-s { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
.ck-bar { display: flex; flex: 0 0 220px; height: 8px; border-radius: 999px; background: var(--surface-flat-2); overflow: hidden; }
.ck-bar span { display: block; height: 100%; background: var(--success); transition: width .25s; }
.ck-bar .ck-bar-ready { background: #8CC4A8; }   /* the 'ready' share, lighter, after the done share */
.ck-table { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--surface); }
/* 900, not 1080: the card is 982px wide on a 1280 laptop with the sidebar
   open, and at 1080 the Status box was cut mid-word with "+" and Remove off
   the screen. Notes gives up width first. */
.ck-table > * { min-width: 900px; }
.ck-row { display: grid; grid-template-columns: 44px minmax(200px, 1fr) minmax(160px, 2.6fr) 150px 120px 40px;
  gap: 8px 12px; align-items: start; padding: 10px 12px; border-top: 1px solid var(--border); }
.ck-row--head { padding: 8px 12px; border-top: 0; background: var(--surface-flat-2); font-size: 10.5px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); align-items: center; }
/* Three states, two hues: red = pending, green = ready (light) / done (deep). */
.ck-row--pending { background: var(--error-soft-2); }
.ck-row--ready { background: var(--success-soft); }
.ck-row--done { background: var(--success-soft-2); }
.ck-row--out { opacity: .55; }
.ck-row--out .ck-in, .ck-row--out .ck-sel { background: transparent; }
.ck-section { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 9px 12px;
  border-top: 1px solid var(--border); background: var(--surface-flat-2); font-size: 12px; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; color: var(--text); }
.ck-n { font-family: var(--font-mono); font-size: 12px; color: var(--text-dim); padding-top: 9px; }
.ck-item { display: grid; gap: 3px; min-width: 0; }
.ck-hint { font-size: 11.5px; line-height: 1.35; color: var(--text-dim); }
.ck-in, .ck-sel { width: 100%; min-height: 34px; padding: 6px 9px; font: inherit; font-size: 13px;
  border: 1px solid var(--border-strong); border-radius: 9px; background: var(--surface); color: var(--text); }
.ck-item-t { font-size: 13.5px; font-weight: 700; line-height: 1.3; padding-top: 8px; }
.ck-in--spec { resize: vertical; min-height: 72px; line-height: 1.4; }
.ck-in:focus, .ck-sel:focus { outline: 2px solid var(--focus); outline-offset: 1px; border-color: transparent; }
.ck-row--done .ck-sel--status, .ck-row--ready .ck-sel--status { border-color: var(--success); color: var(--success-ink); font-weight: 700; }
.ck-row--pending .ck-sel--status { border-color: var(--error); color: var(--error-ink); font-weight: 700; }
.ck-add-section { margin-top: 12px; }
@media (max-width: 880px) { .ck-bar { flex-basis: 100%; } }

/* Lock + stamp (2026-09-23): the head carries the lock button and the last
   change; a locked table keeps its colours but reads as paper, not a form. */
.ck-head-r { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.ck-head--locked { border-color: var(--warning-border, var(--border)); background: var(--warning-soft, var(--surface)); }
.ck-lock-tag { display: inline-flex; align-items: center; gap: 4px; margin-left: 10px; vertical-align: middle; font-size: 11px; }
.ck-lock-tag svg { width: 12px; height: 12px; }
.ck-table--locked .ck-in, .ck-table--locked .ck-sel { background: transparent; border-color: transparent; color: var(--text); cursor: default; }
.ck-table--locked .ck-sel { appearance: none; -webkit-appearance: none; padding-left: 0; }

/* Phone (2026-09-23, Renan: "fit no celular"): the table becomes a stack of
   cards — one per item — instead of a 1080px grid scrolling sideways. Item
   name across the top, Notes full width, Supplier and Status side by side,
   the bin in the corner. Field labels come from data-l (the header row is
   gone at this width); the row colour still says done / pending. */
@media (max-width: 760px) {
  .ck-head { padding: 12px 14px; }
  .ck-head-r { width: 100%; }
  .ck-bar { flex: 1 1 auto; }
  .ck-table { border: 0; background: transparent; overflow: visible; }
  .ck-table > * { min-width: 0; }
  .ck-row--head { display: none; }
  .ck-section { border: 0; border-radius: 10px; margin-top: 14px; padding: 8px 12px; }
  .ck-row {
    grid-template-columns: 28px 1fr 1fr 36px;
    grid-template-areas: "n item item del" "notes notes notes notes" "sup sup st st";
    gap: 10px 8px; padding: 12px; margin-top: 8px;
    border: 1px solid var(--border); border-radius: 12px;
  }
  .ck-row > :nth-child(1) { grid-area: n; }
  .ck-row > :nth-child(2) { grid-area: item; }
  .ck-row > :nth-child(3) { grid-area: notes; }
  .ck-row > :nth-child(4) { grid-area: sup; }
  .ck-row > :nth-child(5) { grid-area: st; }
  .ck-row > :nth-child(6) { grid-area: del; justify-self: end; }
  .ck-n { padding-top: 2px; }
  .ck-item-t { padding-top: 0; font-size: 15px; }
  .ck-row > span[data-l]::before {
    content: attr(data-l); display: block; margin-bottom: 4px;
    font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted);
  }
  .ck-in, .ck-sel { min-height: 44px; font-size: 15px; }   /* glove-sized */
  .ck-in--spec { min-height: 84px; }
  .ck-row .cw-mini { height: 32px; width: 32px; padding: 0; display: inline-flex; align-items: center; justify-content: center; }
  .ck-add-section { width: 100%; justify-content: center; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   MOBILE-FIT 2026-09-23 — G1A
   Phone-fit fixes from docs/mobile-fit-audit-2026-09-23.md. Each work front
   appends ONLY inside its own block so parallel branches merge cleanly.
   ═══════════════════════════════════════════════════════════════════════════ */
/* -- G1A: start -- */

/* #4 / #35 — header with a CTA: bell + button drop under the title so the
   subtitle gets the full width instead of a ~105px column of four lines.
   Tabs without a CTA keep the one-row header. */
@media (max-width: 720px) {
  .admin-content-title:has(.admin-tab-cta:not([hidden])) { flex-wrap: wrap; row-gap: 8px; }
  .admin-content-title:has(.admin-tab-cta:not([hidden])) .admin-content-title-right {
    flex-basis: 100%; justify-content: flex-end;
  }
  .admin-content-title-right .admin-tab-cta { min-height: 36px; }
}

/* #29 — drawer eyebrows and meta lines were 9.5–10.5px; 11px is the floor. */
@media (max-width: 1023px) {
  .admin-side-brand .brand-sub, .admin-side-org-sub, .admin-side-user-role { font-size: 11px; }
}

@media (max-width: 640px) {
  /* #1 — pay rates: three cells per trade were flowing into a two-column
     grid, so every second trade landed offset by one box. The trade name now
     takes its own line with Wage | Loaded directly under it. */
  .rt-pay-grid .rt-name { grid-column: 1 / -1; padding-top: 6px; margin-bottom: -4px; }
  /* #9 — the desktop 'grid-column: 3 / -1' on + Add forced an implicit third
     track; unit and the button now share the second row. */
  .rt-mt-add .ox-btn { grid-column: 2 / 3; min-height: 44px; }
  /* #37 — hide + delete sit beside unit and price instead of a third row;
     still 44px targets, one row less per item. */
  .rt-mt-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; }
  .rt-mt-row .rt-mt-acts { grid-column: 3 / 4; }
  /* #38 — documents search takes its own full line under the project chips. */
  #tab-documents .ox-toolbar .ox-toolbar-spacer { display: none; }
  #tab-documents .ox-toolbar .ox-search { flex-basis: 100%; }
  #tab-documents .ox-toolbar .ox-search input { width: 100%; min-height: 44px; }
}

/* -- G1A: end -- */


/* ═══════════════════════════════════════════════════════════════════════════
   MOBILE-FIT 2026-09-23 — G1B
   Phone-fit fixes from docs/mobile-fit-audit-2026-09-23.md. Each work front
   appends ONLY inside its own block so parallel branches merge cleanly.
   ═══════════════════════════════════════════════════════════════════════════ */
/* -- G1B: start -- */
/* Record drawer (Submissions). Five meta cells in a two-column grid left the
   sixth slot as a bare block of grid background; an odd last cell takes the
   whole row instead. Not phone-specific — the drawer is 440px on the desk too. */
.ox-meta-cell:last-child:nth-child(odd) { grid-column: 1 / -1; }
@media (max-width: 860px) {
  /* The footer row shoved the lock and Delete past the drawer's right edge. */
  .ox-drawer-foot { flex-wrap: wrap; }
  .ox-drawer-foot .ox-btn { white-space: nowrap; }
  /* Tab-strip edge fades (R2). The strip scrolls to whatever position puts
     the active tab in view, so the tab at the far edge is cut mid-word
     ("orrective Actions") — a hard cut at the strip's edge, beside the
     chevron. Each fade is now 44px: solid over the header's 22px gutter, where
     the chevron sits, then fading across the first 22px of the strip itself,
     so the cut edge dissolves instead of reading as a typo. Same on both ends. */
  .anav-fade { width: 64px; }
  .anav-fade-l { background: linear-gradient(90deg,  var(--chrome-bg) 34%, transparent); }
  .anav-fade-r { background: linear-gradient(270deg, var(--chrome-bg) 34%, transparent); }
  /* scrollIntoView honours scroll-padding: the active tab lands clear of the
     fade instead of flush against the edge, under it. */
  .admin-nav-wrap { scroll-padding-inline: 44px; }
  .anav-fade-l::after { left: 6px; }
  .anav-fade-r::after { right: 6px; }
}
/* -- G1B: end -- */


/* ═══════════════════════════════════════════════════════════════════════════
   MOBILE-FIT 2026-09-23 — G2
   Phone-fit fixes from docs/mobile-fit-audit-2026-09-23.md. Each work front
   appends ONLY inside its own block so parallel branches merge cleanly.
   ═══════════════════════════════════════════════════════════════════════════ */
/* -- G2: start -- */

/* -- G2: end -- */

/* The shared toast (js/core/toast.js) must clear the admin modals (z 800). */
.toast { z-index: 9000; }

/* Deliveries → Manage catalog: on a phone the item's name takes its own line
   (the inline flex:1;min-width:0 squeezed it to nothing beside the unit and
   group boxes). */
@media (max-width: 640px) {
  #delivMaterialsManager .dm-row { flex-wrap: wrap; padding-bottom: 8px; border-bottom: 1px solid var(--border); }
  #delivMaterialsManager .dm-row > input:first-child { flex: 1 1 100% !important; }
}
