/* Steel City Electric - portal styles
   Palette: the logo's black and gold on warm paper; gold is the one thing you should press. Square corners, thin
   rules, a black side menu (owner, 2026-11-12: the Steel City brand look, and "make it look less ai": no soft rounded
   boxes, no pastel tiles). Every colour a component uses is a name from this block, so the dark palette below
   (:root[data-theme="dark"], set by public/js/theme.js) redraws the whole portal. Documents that are paper stay
   paper in both modes: the printable ticket, proposals and change orders, PDF pages, signatures. */
:root {
  --paper: #F3F3F0;          /* the page */
  --surface: #FFFFFF;        /* boxes on it */
  --field: #FFFFFF;          /* inputs */
  --ink: #101820;            /* text: the logo's black */
  --steel: #555D65;          /* quieter text */
  --rule: #DADAD5;
  --rule-strong: #A8ABA6;
  --hover: #F7F7F4;          /* a row under the pointer */
  --hivis: #FFB612;          /* the logo's gold */
  --hivis-press: #E5A100;
  --on-hivis: #101820;       /* text on gold, in both modes */
  --signal: #C60C30;         /* the logo's red: text, edges */
  --signal-fill: #C60C30;    /* red behind white text */
  --go: #23764A;
  --go-fill: #23764A;
  --wait: #9A6200;
  --info: #1B4F8F;           /* links and focus: the logo's navy, lifted to read as a link */
  --strong: #101820;         /* black chips: counts, the toast, step numbers */
  --on-strong: #FFFFFF;
  --tint-hivis: #FFF3CC;     /* selected, current */
  --tint-hivis-soft: #FFFAE8;
  --tint-signal: #FBECEE;    /* needs action, problem, overdue */
  --tint-signal-strong: #F5D9DE;
  --tint-go: #E6F3EB;
  --tint-info: #E9F0F8;
  --tint-pw: #E8E0F7;        /* prevailing wage tag */
  --pw-ink: #3F2A73;
  --bar: #DDE5EC;            /* schedule bars */
  --bar-edge: #93A5B3;
  --bar-fill: #A9C3D9;
  --bar-done: #B4D8C1;
  /* The side menu is black in both modes */
  --side-bg: #101820;
  --side-ink: #FFFFFF;
  --side-muted: #AEB6BD;
  --side-rule: #2A333C;
  --side-hover: #1A232C;
  --side-current: #222C36;
  --shadow: rgba(16, 24, 32, .18);
  --display: "Barlow Semi Condensed", "Arial Narrow", system-ui, sans-serif;
  --body: "Barlow", system-ui, -apple-system, "Segoe UI", sans-serif;
  --r-sm: 2px;
  --r-md: 3px;
  --r-pill: 2px;             /* what used to be pill-shaped: link buttons, tags, chips */
  /* Older names some rules use (costing bars, key numbers, proposals); without them those rules drew nothing */
  --navy: var(--ink);
  --gold: var(--wait);
  --r: var(--r-md);
  color-scheme: light;
}
/* Dark mode (Account > Appearance, or the switch at the foot of the menu). Screen only: paper prints light. */
@media screen {
  :root[data-theme="dark"] {
    --paper: #0D1114;
    --surface: #161B20;
    --field: #1D242B;
    --ink: #E9ECEE;
    --steel: #9CA6AF;
    --rule: #29313A;
    --rule-strong: #47525D;
    --hover: #1B2228;
    --hivis: #FFB612;
    --hivis-press: #FFC94D;
    --signal: #FF8E99;
    --signal-fill: #B3122F;
    --go: #74D09B;
    --go-fill: #1F7A4A;
    --wait: #F2B552;
    --info: #92BEF3;
    --strong: #E9ECEE;
    --on-strong: #101820;
    --tint-hivis: #3A3013;
    --tint-hivis-soft: #25220F;
    --tint-signal: #35181D;
    --tint-signal-strong: #4A2028;
    --tint-go: #15301F;
    --tint-info: #17283B;
    --tint-pw: #2B2347;
    --pw-ink: #CFC0F8;
    --bar: #22303D;
    --bar-edge: #4F6477;
    --bar-fill: #35526C;
    --bar-done: #2B5A40;
    --side-bg: #080B0E;
    --side-rule: #1C242C;
    --side-hover: #121920;
    --side-current: #18212A;
    --shadow: rgba(0, 0, 0, .55);
    color-scheme: dark;
  }
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }
/* scrollbar-gutter: the scroll bar's space is always kept, so a page does not shift sideways (and its header buttons
   with it) between a long list and a short one - Purchasing's tabs did (owner, 2026-11-12: "the buttons move") */
html { -webkit-text-size-adjust: 100%; scrollbar-gutter: stable; }
body { margin: 0; background: var(--paper); color: var(--ink); font: 400 15px/1.45 var(--body); }
a { color: var(--info); }
/* No underlined blue text (owner, 2026-11-11: "all underlined blue verbiage should have interactive buttons"): every
   plain text link in a page, a dialog or the photo viewer is drawn as a small button. Links that already have their
   own look (.btn, .row, .tile, cards, the menu) carry a class and are left alone; `a.small` are the header actions
   such as "See all" and "Request time off". */
#view a:not([class]), #view a.small:not(.btn), #view a.hcard-link, #view a.ci-link, #modal-body a:not([class]), #modal-body a.small:not(.btn), #modal-body a.ci-link, .lb-info a:not([class]), #public a:not([class]) {
  display: inline-flex; align-items: center; max-width: 100%; vertical-align: baseline;
  /* A record link reads as a soft chip in the link colour, not a grey outlined box (owner, 2026-11-12: "there has to be a way to make these boxes look better") */
  padding: 1px 8px; margin: 1px 0; border: 1px solid transparent; border-radius: var(--r-sm);
  background: var(--tint-info); color: var(--info); font-weight: 600; line-height: 1.45; text-decoration: none; overflow-wrap: anywhere;
}
#view a:not([class]):hover, #view a.small:not(.btn):hover, #view a.hcard-link:hover, #view a.ci-link:hover, #modal-body a.ci-link:hover, #modal-body a:not([class]):hover, #modal-body a.small:not(.btn):hover, .lb-info a:not([class]):hover, #public a:not([class]):hover {
  background: color-mix(in srgb, var(--info) 20%, var(--surface)); border-color: color-mix(in srgb, var(--info) 55%, transparent);
}
/* .btn links are buttons already: a small one (a.btn.small) keeps the button look, like a small <button> beside it */
#view a.small:not(.btn), #modal-body a.small:not(.btn) { padding: 3px 11px; }
/* On a phone the small header buttons ("See all", "Request time off") are big enough to tap */
@media (max-width: 600px) { #view a.small:not(.btn), #modal-body a.small:not(.btn) { min-height: 34px; padding: 5px 12px; } }
/* On a phone or tablet every link button is tall enough to tap, with room between wrapped rows */
@media (max-width: 820px) {
  #view a:not([class]), #view a.hcard-link, #view a.ci-link, #modal-body a:not([class]), #modal-body a.ci-link, .lb-info a:not([class]), #public a:not([class]) {
    min-height: 32px; margin: 3px 0; padding-top: 3px; padding-bottom: 3px;
  }
  #view .related a { min-height: 34px; display: inline-flex; align-items: center; }
  #view a.hcard-add { min-width: 36px; min-height: 36px; display: inline-grid; place-items: center; }
}
@media print { #view a:not([class]), #view a.small, #public a:not([class]) { border: 0; padding: 0; background: none; color: inherit; font-weight: inherit; } }
:focus-visible { outline: 3px solid var(--info); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }

/* ── Shell ─────────────────────────────────────────── */
#shell { display: grid; grid-template-columns: 228px 1fr; min-height: 100vh; }
#sidebar { position: sticky; top: 0; height: 100vh; overflow-y: auto; border-right: 1px solid var(--side-rule); background: var(--side-bg); color: var(--side-ink); display: flex; flex-direction: column; padding: 18px 0 14px; scrollbar-color: var(--side-rule) var(--side-bg); }
.brand { display: block; padding: 0 16px 18px; }
.brand img { width: 100%; max-width: 200px; height: auto; display: block; }
.bolt { width: 28px; height: 36px; background: var(--hivis); clip-path: polygon(58% 0, 8% 56%, 44% 56%, 30% 100%, 92% 40%, 54% 40%); flex: none; }
#nav { display: flex; flex-direction: column; flex: 1; }
#nav a { display: flex; justify-content: space-between; align-items: center; padding: 7px 18px 7px 15px; border-left: 3px solid transparent; color: var(--side-muted); text-decoration: none; font-weight: 500; }
#nav a:hover { color: var(--side-ink); background: var(--side-hover); }
#nav a[aria-current="page"] { color: var(--side-ink); border-left-color: var(--hivis); background: var(--side-current); font-weight: 600; }
#nav .group { margin: 18px 18px 5px; font-size: 11px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--side-muted); opacity: .7; }
/* A plain count beside a menu item is quiet on the black menu; a red one (waiting on you) keeps its red */
#nav a .count:not(.action) { background: var(--side-current); color: var(--side-ink); box-shadow: inset 0 0 0 1px var(--side-rule); }
.count { min-width: 22px; padding: 0 6px; border-radius: var(--r-sm); background: var(--strong); color: var(--on-strong); font-size: 12px; font-weight: 600; text-align: center; line-height: 20px; }
#whoami { padding: 12px 18px 0; border-top: 1px solid var(--side-rule); font-size: 13px; color: var(--side-muted); }
#whoami strong { display: block; color: var(--side-ink); font-size: 14px; }
/* Light / dark, at the foot of the menu (public/js/app.js themeSwitch) */
.theme-switch { margin-top: 10px; width: 100%; justify-content: center; min-height: 32px; padding: 4px 10px; font-size: 13px; font-weight: 600; background: transparent; color: var(--side-muted); border-color: var(--side-rule); }
.theme-switch:hover { color: var(--side-ink); border-color: var(--side-muted); }
/* On the black menu the focus ring is gold (navy would not show) */
#sidebar :focus-visible { outline-color: var(--hivis); }
#view { padding: 22px clamp(16px, 3vw, 36px) 96px; max-width: 1280px; width: 100%; min-width: 0; outline: none; }
#tabbar { display: none; }

@media (max-width: 820px) {
  #shell { grid-template-columns: 1fr; }
  #sidebar { display: none; }
  #view { padding: 18px 14px 96px; }
  #tabbar { display: grid; grid-template-columns: repeat(5, 1fr); position: fixed; inset: auto 0 0 0; background: var(--surface); border-top: 1px solid var(--rule); padding-bottom: env(safe-area-inset-bottom); z-index: 20; }
  #tabbar a { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 9px 2px 8px; font-size: 12px; color: var(--steel); text-decoration: none; border-top: 3px solid transparent; }
  #tabbar a[aria-current="page"] { color: var(--ink); border-top-color: var(--hivis); font-weight: 600; }
  #tabbar svg { width: 22px; height: 22px; }
}
#whoami a { color: inherit; text-decoration: none; }
#whoami a:hover strong { text-decoration: underline; text-decoration-color: var(--hivis); }

/* Global search (public/js/search.js): the box at the top of the menu and its results panel, which opens beside the
   menu (the menu scrolls, so the panel is fixed to the window rather than hung under the box) */
#gsearch { position: relative; margin: 0 14px 6px; }
#gsearch input { padding: 6px 34px 6px 10px; min-height: 36px; background: var(--side-hover); border-color: var(--side-rule); color: var(--side-ink); }
#gsearch input::placeholder { color: var(--side-muted); }
#gsearch input:focus { background: var(--side-current); border-color: var(--hivis); outline-color: var(--hivis); }
#gsearch kbd { background: var(--side-bg); border-color: var(--side-rule); color: var(--side-muted); }
#gsearch kbd { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); pointer-events: none; }
#gsearch input:focus + kbd, #gsearch input:not(:placeholder-shown) + kbd { display: none; }
kbd { display: inline-block; min-width: 20px; padding: 0 5px; border: 1px solid var(--rule-strong); border-bottom-width: 2px; border-radius: 4px; background: var(--surface);
  color: var(--steel); font: 600 12px/18px var(--body); text-align: center; }
#gsearch-pop { position: fixed; z-index: 40; top: 12px; left: 236px; width: min(560px, calc(100vw - 252px)); max-height: calc(100vh - 24px); overflow-y: auto;
  background: var(--surface); border: 1px solid var(--rule-strong); border-radius: var(--r-md); box-shadow: 0 12px 32px var(--shadow); padding: 6px 0; }
.gs-head { padding: 10px 14px 4px; font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--steel); }
.gs-head .muted { font-weight: 500; letter-spacing: 0; text-transform: none; }
.gs-item { display: flex; align-items: center; gap: 12px; padding: 8px 14px; color: var(--ink); text-decoration: none; border-left: 3px solid transparent; }
.gs-item:hover, .gs-item.active { background: var(--tint-hivis); border-left-color: var(--hivis); }
.gs-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.gs-title { font-weight: 600; overflow-wrap: anywhere; }
.gs-meta { color: var(--steel); font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gs-side { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; font-size: 14px; white-space: nowrap; }
.gs-all { margin-top: 6px; border-top: 1px solid var(--rule); font-weight: 600; color: var(--info); }
.gs-note { margin: 0; padding: 12px 14px; color: var(--steel); }
.gs-note strong { color: var(--ink); }
/* The full results page (#/search), also the phone's Search tab */
.search-page { display: flex; gap: 8px; margin-bottom: 16px; }
.search-page input { flex: 1; min-width: 0; }
.search-more { padding-bottom: 12px; }
@media (max-width: 820px) { #gsearch-pop { display: none; } }

/* Trail above a detail page's title (crumbs() in core.js), a person's contact line, the next step in an empty list,
   and the More page's row for the page that is open */
.page-head .crumbs { margin: 0 0 4px; font-size: 14px; overflow-wrap: anywhere; }
.page-head .person-reach { font-size: 15px; overflow-wrap: anywhere; }
.empty-next { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
a.row[aria-current="page"] { background: var(--tint-hivis); }
.row.nav-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; color: var(--ink); text-decoration: none; }
.row.nav-row .side { color: var(--steel); font-size: 20px; line-height: 1; }

/* Back button (public/js/app.js decorate): one per page that is not a menu page, first thing in the page head */
.back-row { flex: 0 0 100%; }
.back-row.lone { margin-bottom: 12px; }
button.back { min-height: 36px; padding: 6px 14px 6px 10px; border-radius: var(--r-pill); color: var(--steel); }
button.back:hover { color: var(--ink); }
button.back span { font-size: 20px; line-height: 1; margin-top: -2px; }
@media (max-width: 820px) { button.back { min-height: 44px; padding: 8px 18px 8px 12px; font-size: 16px; } }
@media print { .back-row { display: none; } }

/* Microsoft calendar (public/js/views-calendar.js): the "See this schedule in Outlook or Teams" dialog. One box per
   calendar: its name, what it holds, then its buttons (they wrap on a phone) and the link in a read-only box. */
.cal-feed { border: 1px solid var(--rule); border-radius: var(--r-md); background: var(--paper); padding: 12px 14px; margin: 0 0 12px; }
.cal-feed .cal-name { font: 600 18px/1.25 var(--display); overflow-wrap: anywhere; }
.cal-feed p { margin: 8px 0 0; }
.cal-feed .notice { margin: 10px 0 0; }
.cal-feed select { margin-top: 8px; }
#modal-body .actions.cal-actions, .actions.cal-actions { justify-content: flex-start; margin-top: 10px; }
.cal-actions .small { min-height: 34px; padding: 5px 12px; font-size: 14px; }
input.cal-url { margin-top: 10px; font: 13px ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--steel); background: var(--surface); text-overflow: ellipsis; }
details.cal-how { margin: 0 0 12px; border: 1px solid var(--rule); border-radius: var(--r-md); }
details.cal-how > summary { cursor: pointer; padding: 11px 14px; font-weight: 600; min-height: 44px; }
details.cal-how ol { margin: 0; padding: 0 14px 12px 34px; }
details.cal-how li { margin: 6px 0; }
.cal-sync { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.cal-sync .btn.small { min-height: 32px; padding: 4px 12px; font-size: 14px; }

/* Action required (owner, 2026-11-11): red marks what is waiting on the person looking at it, and only that. The same
   record seen by someone who cannot act keeps its usual status. core.js: actionTag('review'), needsAction(cond), actionCount(n).
     .status.action-required   the red chip that reads "Action required"
     .needs-action             on a .row, .section, .kpi, tile or .notice: red left edge, very light red ground
     .notice.action            the red "Action required" banner for the top of a page or box
     .count.action             a red number: on a tab or filter button ("To approve 3") and beside a menu item */
.status.action-required { background: var(--signal-fill); color: #fff; font-weight: 700; padding: 2px 8px; border-radius: var(--r-pill); white-space: normal; }
.status.action-required::before { display: none; }
.needs-action { box-shadow: inset 4px 0 0 var(--signal); background-color: var(--tint-signal); }
.row.needs-action:hover, .row.linked.needs-action:hover { background-color: var(--tint-signal-strong); }
.section.needs-action, .kpi.needs-action, .notice.needs-action { box-shadow: none; border-left: 4px solid var(--signal); }
.notice.action { border-left-color: var(--signal); background: var(--tint-signal); }
.notice.action::before { content: "Action required"; display: inline-block; margin-right: 8px; padding: 1px 8px; border-radius: var(--r-pill); background: var(--signal-fill); color: #fff; font-size: 13px; font-weight: 700; }
.count.action { background: var(--signal-fill); color: #fff; display: inline-block; }
.btn .count, button .count { margin-left: 2px; }
#nav a .count { flex: none; }
#tabbar a { position: relative; }
#tabbar .count { position: absolute; top: 4px; left: calc(50% + 6px); min-width: 18px; padding: 0 5px; font-size: 12px; line-height: 18px; }

/* Time page (public/js/views-time.js): the period filter (Earlier, the choice, Later, the period in words) and the
   day headings inside a pay week */
.period-bar { align-items: center; }
.period-bar select { min-width: 0; flex: 0 1 auto; }
.period-bar .range input { min-width: 0; width: auto; }
.period-step { min-width: 42px; justify-content: center; font-size: 22px; line-height: 1; padding: 6px 10px; }
.period-words { font-weight: 600; flex: 1 1 220px; }
/* To-Do: the pay week line under the clock cards (Saturday to Friday, paid the following Friday) */
.pay-week { margin: -6px 0 18px; }
.day-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
/* A day's buttons on a timesheet the office can change (Edit hours, Add time), then the day's hours */
.day-side { display: inline-flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 8px; }
.day-side button { min-height: 30px; padding: 3px 10px; font-size: 13px; }
@media (max-width: 820px) { .day-side button { min-height: 38px; padding: 6px 12px; font-size: 14px; } }
.section > header + .day-head { border-top: 0; }
/* Time: a day's hours by pay class - Total, Regular, Overtime, Double time, Emergency, Holiday worked, Time off.
   The same seven boxes every day, so the breakdown reads down the page like a timesheet. */
.day-stats { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; padding: 2px 18px 10px; }
.day-stats > div { border: 1px solid var(--rule); border-radius: var(--r-sm); padding: 5px 8px; background: var(--surface); min-width: 0; }
.day-stats .k { display: block; font-size: 11px; font-weight: 700; line-height: 1.25; color: var(--steel); text-transform: uppercase; letter-spacing: .03em; overflow-wrap: anywhere; }
.day-stats .v { display: block; font-weight: 700; color: var(--navy); }
.day-stats .zero .v { font-weight: 400; color: var(--steel); }
.day-stats .on { border-color: var(--hivis-press); box-shadow: inset 0 3px 0 var(--hivis); }
@media (max-width: 700px) { .day-stats { grid-template-columns: repeat(4, minmax(0, 1fr)); padding: 2px 12px 10px; } }
/* Time: the period's eight tiles (Total, Regular, Overtime, Double time / Emergency, Holiday worked, Time off, Paid
   total) sit in two even rows of four, two columns on a narrow screen */
.kpis.time-kpis { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 900px) { .kpis.time-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Weekly totals: the View timesheet button stays on one line */
table.timesheets .btn.small { min-height: 30px; padding: 4px 10px; font-size: 13px; white-space: nowrap; }
/* Each pay class column says its multiplier under its name: 1.5x, 2x, 2.5x, 3x */
table.timesheets th .x { display: block; font-size: 13px; letter-spacing: 0; text-transform: none; color: var(--ink); }
/* ...and a name is never broken in the middle to make room for the hour columns (the table scrolls sideways instead) */
table.timesheets th:first-child, table.timesheets td:first-child { min-width: 160px; }
table.timesheets th, table.timesheets td { padding-left: 6px; padding-right: 6px; }
table.timesheets td:first-child a { overflow-wrap: normal; }

/* ── Type ─────────────────────────────────────────── */
h1, h2, h3 { font-family: var(--display); font-weight: 600; letter-spacing: .005em; margin: 0; }
h1 { font-size: clamp(24px, 3vw, 30px); line-height: 1.1; }
h2 { font-size: 18px; line-height: 1.2; }
h3 { font-size: 16px; }
.page-head { display: flex; flex-wrap: wrap; gap: 10px 20px; align-items: center; justify-content: space-between; margin-bottom: 16px; padding-bottom: 12px; border-bottom: 2px solid var(--ink); }
.page-head p { margin: 4px 0 0; color: var(--steel); }
.muted { color: var(--steel); }
.small { font-size: 14px; }
.num { font-variant-numeric: tabular-nums; }

/* ── Sections & rows ──────────────────────────────── */
.section { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-md); margin-bottom: 16px; }
.section > header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 16px; border-bottom: 1px solid var(--rule); background: var(--hover); }
.section > .body { padding: 14px 16px; }
.rows { list-style: none; margin: 0; padding: 0; }
.row { display: grid; grid-template-columns: 1fr auto; gap: 2px 16px; padding: 9px 16px; border-top: 1px solid var(--rule); align-items: center; }
.rows > .row:first-child { border-top: 0; }
a.row { color: inherit; text-decoration: none; }
a.row:hover { background: var(--hover); }
.row .title { font-weight: 600; }
.row .meta { color: var(--steel); font-size: 14px; }
.row .side { text-align: right; font-size: 14px; }
.empty { padding: 18px 16px; color: var(--steel); }
.empty strong { color: var(--ink); display: block; margin-bottom: 2px; }
.split { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 20px; align-items: start; }
@media (max-width: 980px) { .split { grid-template-columns: minmax(0, 1fr); } }   /* minmax: a wide table scrolls in its box instead of widening the page on a phone */
/* The label column never takes more than about two fifths of the box, so a long label ("Signed for Steel City Electric") wraps
   instead of squeezing the value into a sliver in a narrow side box (owner, 2026-11-12: "the sidebar doesn't look right") */
dl.facts { display: grid; grid-template-columns: fit-content(40%) minmax(0, 1fr); gap: 8px 18px; margin: 0; }
dl.facts dd a { overflow-wrap: break-word; }
/* In a narrow box (a side column) each label sits above its value instead of beside it */
.body:has(> dl.facts) { container-type: inline-size; }
@container (max-width: 360px) { dl.facts { grid-template-columns: minmax(0, 1fr); gap: 0; } dl.facts dt { font-size: 13px; } dl.facts dd { margin-bottom: 10px; } }
dl.facts dt { color: var(--steel); }
dl.facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
/* Client information block (client-info.js): the billing rows start under a rule; on a phone each label sits above its value */
dl.facts .ci-billing { border-top: 1px solid var(--rule); padding-top: 8px; }
.ci-same { white-space: nowrap; }
@media (max-width: 420px) {
  .client-info dl.facts { grid-template-columns: minmax(0, 1fr); gap: 2px 0; }
  .client-info dl.facts dd { margin-bottom: 8px; }
  .client-info dl.facts dd.ci-billing { border-top: 0; padding-top: 0; }
}
/* A client's addresses (client page): what is at each one, then its buttons */
.addr-row { align-items: start; }
.addr-row .addr-work { margin-top: 2px; }
.addr-row .addr-actions { margin-top: 10px; }
.addr-row.addr-off .title > a { color: var(--steel); }
.nc-billing { border-top: 1px solid var(--rule); padding-top: 12px; }

/* Today: the one bold moment - the job you're on right now */
.now { border: 2px solid var(--ink); border-radius: var(--r-md); background: var(--surface); padding: 18px 20px; margin-bottom: 20px; display: grid; grid-template-columns: 1fr auto; gap: 14px 20px; align-items: center; }
.now .when { font: 600 15px var(--display); color: var(--steel); }
.now .what { font: 700 clamp(24px, 3.6vw, 32px)/1.1 var(--display); margin: 2px 0 4px; }
.now.clocked { border-color: var(--go); box-shadow: inset 6px 0 0 var(--go); }
@media (max-width: 600px) { .now { grid-template-columns: 1fr; } }
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 12px; margin-bottom: 20px; }
.tile { display: block; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-md); padding: 14px 16px; text-decoration: none; color: var(--ink); }
.tile b { display: block; font: 700 30px/1 var(--display); }
.tile span { color: var(--steel); font-size: 14px; }
.tile.attn { border-color: var(--hivis-press); box-shadow: inset 0 -3px 0 var(--hivis); }

/* Status: dot + word, colour is never the only signal */
.status { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; white-space: nowrap; }
.status::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--steel); }
.status.go::before { background: var(--go); } .status.wait::before { background: var(--wait); }
.status.stop::before { background: var(--signal); } .status.info::before { background: var(--info); }
.prio-emergency { color: var(--signal); font-weight: 600; }

/* ── Controls ─────────────────────────────────────── */
button, .btn { font: 600 14px var(--body); border-radius: var(--r-sm); border: 1px solid var(--rule-strong); background: var(--surface); color: var(--ink); padding: 7px 13px; cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; gap: 6px; min-height: 36px; }
button:hover, .btn:hover { border-color: var(--ink); }
button.primary, .btn.primary { background: var(--hivis); border-color: var(--hivis-press); color: var(--on-hivis); }
button.primary:hover, .btn.primary:hover { background: var(--hivis-press); border-color: var(--hivis-press); }
/* A finger needs more than a pointer does */
@media (max-width: 820px) { button, .btn { min-height: 42px; padding: 9px 14px; font-size: 15px; } }
button.danger { color: var(--signal); }
button.big { min-height: 52px; padding: 12px 22px; font-size: 17px; }
/* On my way: the arrival time as four big choices (views-tickets.js onMyWayDialog) */
.eta-pick { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 12px 0 0; padding: 0; border: 0; min-width: 0; }
.eta-pick label { position: relative; margin: 0; }
.eta-pick input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.eta-pick span { display: flex; align-items: center; justify-content: center; min-height: 52px; border: 1px solid var(--rule-strong); border-radius: var(--r-sm); background: var(--surface); color: var(--ink); font-size: 17px; font-weight: 600; cursor: pointer; white-space: nowrap; }
.eta-pick input:checked + span { background: var(--hivis); border-color: var(--hivis-press); color: var(--on-hivis); }
.eta-pick input:focus-visible + span { outline: 2px solid var(--info); outline-offset: 2px; }
button:disabled { opacity: .55; cursor: not-allowed; }
.actions { display: flex; flex-wrap: wrap; gap: 8px; }
label { display: block; font-weight: 600; font-size: 14px; margin: 0 0 4px; }
.hint { font-weight: 400; color: var(--steel); }
input, select, textarea { width: 100%; font: 400 16px var(--body); color: var(--ink); background: var(--field); border: 1px solid var(--rule-strong); border-radius: var(--r-sm); padding: 7px 10px; min-height: 38px; }
@media (max-width: 820px) { input, select, textarea { min-height: 42px; padding: 9px 11px; } }
textarea { min-height: 92px; resize: vertical; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--info); outline-offset: 0; border-color: var(--info); }
.field { margin-bottom: 14px; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 14px; }
@media (max-width: 560px) { .grid2, .grid3 { grid-template-columns: 1fr; } }
.filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.filters select, .filters input { width: auto; min-width: 150px; }
/* A tick box or a date inside a filter row keeps its own size (it was stretched to 150 px) */
.filters input[type=checkbox], .filters input[type=radio] { min-width: 0; }
.filters .check input[type=date] { min-width: 0; width: auto; }
/* Schedule: ‹ Today › as one control */
.sched-nav { display: inline-flex; }
.sched-nav button { border-radius: 0; margin-left: -1px; }
.sched-nav button:first-child { border-radius: var(--r-sm) 0 0 var(--r-sm); margin-left: 0; }
.sched-nav button:last-child { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
.sched-nav button[aria-label] { min-width: 40px; font-size: 18px; line-height: 1; }
/* Search + filters bar drawn by listTools (core.js): the search box stretches, the count sits at the right end */
.list-tools { align-items: center; }
.list-tools input[type="search"] { flex: 1 1 220px; }
.list-tools .range { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; font-weight: 500; font-size: 14px; }
.list-tools .range input, .list-tools .check input { min-width: 0; }
.list-tools .list-count { margin-left: auto; white-space: nowrap; }
.list-tools .list-count:empty { display: none; }
.check { display: flex; align-items: center; gap: 8px; font-weight: 500; }
.check input[type=checkbox], .check input[type=radio] { width: 18px; height: 18px; min-height: 0; }
/* A run of buttons inside text (a dialog's intro, a row's side): spaced so they never touch, also when they wrap */
.btn-run { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.row .side .btn-run { justify-content: flex-end; }
/* A list of people to tick (dispatching several field staff at once: views-tickets.js staffPicker) */
.check-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 4px 14px; max-height: 230px; overflow-y: auto; padding: 8px 10px; border: 1px solid var(--rule-strong); border-radius: var(--r-sm); background: var(--surface); }
.check-list .check { font-weight: 400; min-height: 34px; cursor: pointer; }
.check-list .check input { flex: none; }

table.lines { width: 100%; border-collapse: collapse; }
table.lines th, table.lines td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--rule); vertical-align: top; }
table.lines th { font-size: 11.5px; color: var(--steel); font-weight: 700; letter-spacing: .05em; text-transform: uppercase; background: var(--hover); border-bottom-color: var(--rule-strong); vertical-align: bottom; }
/* A plain row lights up under the pointer; a row with its own look (a total, an overdue line) keeps it */
table.lines tbody tr:not([class]):hover > td { background: var(--hover); }
table.lines td.r, table.lines th.r { text-align: right; }

/* Messages */
.thread { display: flex; flex-direction: column; gap: 10px; max-height: 420px; overflow-y: auto; padding: 4px 2px; }
.msg { max-width: 86%; padding: 8px 12px; border-radius: var(--r-md); background: var(--paper); border: 1px solid var(--rule); }
.msg.mine { align-self: flex-end; background: var(--tint-hivis); border-color: var(--hivis-press); }
.msg .who { font-size: 13px; color: var(--steel); }
.composer { display: flex; gap: 8px; margin-top: 12px; }
.composer textarea { min-height: 44px; height: 44px; }

/* Dialog, toast, notices */
dialog { border: 1px solid var(--rule-strong); border-top: 3px solid var(--hivis); border-radius: var(--r-md); padding: 0; width: min(560px, calc(100vw - 24px)); max-height: calc(100vh - 32px); background: var(--surface); color: var(--ink); box-shadow: 0 24px 60px var(--shadow); }
dialog::backdrop { background: rgba(29, 35, 41, .45); }
#modal-body { padding: 20px 22px; }
#modal-body h2 { margin-bottom: 14px; }
#modal-body .actions { justify-content: flex-end; margin-top: 8px; }
/* A form's Save / Cancel row stays in view at the bottom of a long dialog (Permissions, Manage, Invite) */
#modal-body > form > .actions:last-child { position: sticky; bottom: 0; z-index: 2; margin: 12px -22px -20px; padding: 12px 22px 16px; background: var(--surface); border-top: 1px solid var(--rule); }
#toast { position: fixed; left: 50%; bottom: 84px; transform: translateX(-50%) translateY(20px); background: var(--strong); color: var(--on-strong); padding: 10px 16px; border-radius: var(--r-sm); opacity: 0; pointer-events: none; transition: opacity .18s, transform .18s; z-index: 50; max-width: calc(100vw - 32px); }
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
#toast.err { background: var(--signal-fill); color: #fff; }
.notice { border: 1px solid var(--rule); border-left: 4px solid var(--hivis); background: var(--surface); padding: 9px 14px; border-radius: var(--r-sm); margin-bottom: 16px; }
.notice.err { border-left-color: var(--signal); background: var(--tint-signal); }
.copybox { display: flex; gap: 8px; } .copybox input { font-size: 14px; }

/* Public pages (sign in, invitation) */
#public { min-height: 100vh; display: grid; place-items: center; padding: 24px 16px; }
.auth { width: min(420px, 100%); }
.auth .brand { padding: 0 0 20px; }
.auth .brand img { max-width: 300px; margin: 0 auto; }
.auth .remember { margin: 6px 0 14px; font-weight: 500; }
.auth .section > .body { padding: 22px; }
.auth .or { display: flex; align-items: center; gap: 10px; color: var(--steel); font-size: 14px; margin: 18px 0; }
.auth .or::before, .auth .or::after { content: ""; flex: 1; border-top: 1px solid var(--rule); }
.ms { width: 100%; justify-content: center; }
/* Sign-in help (owner, 2026-11-11: "forgot password button at login, and a help button"). Forgot password and Help
   sit side by side under the sign-in form, as buttons; the reset pages reuse the sign-in card (views-auth.js) */
.auth-more { display: flex; gap: 8px; margin: 12px 0 14px; }
.auth-more > * { flex: 1 1 0; justify-content: center; min-height: 44px; padding-left: 8px; padding-right: 8px; }
.auth a.btn.u-full { box-sizing: border-box; }
.auth a.btn.big { min-height: 52px; padding: 12px 22px; font-size: 17px; box-sizing: border-box; }   /* a link that is the page's main button (Sign in with Microsoft 365) is as big as one */
.auth-ms-out { margin: 12px 0 0; }
.auth-ms-out .btn { width: 100%; justify-content: center; font-weight: 500; font-size: 14px; min-height: 36px; color: var(--steel); }
.help-list { margin: 0 0 6px; padding-left: 20px; }
.help-list li { margin: 0 0 10px; }
/* Help: the button at the top of the menu (a row on the phone's More page), and the Help page (views-help.js): one
   box per group, each answer a <details> with its steps and the button that goes where it is done */
#helpbtn { margin: 2px 14px 8px; justify-content: center; min-height: 32px; padding: 4px 12px; font-size: 13px; background: transparent; color: var(--side-muted); border-color: var(--side-rule); }
#helpbtn:hover, #helpbtn[aria-current="page"] { color: var(--side-ink); border-color: var(--side-muted); }
#helpbtn[aria-current="page"] { border-color: var(--hivis); background: var(--side-current); }
/* Report something: under Help, in the logo's red so it stands out (owner, 2026-11-13) */
#reportbtn { margin: 0 14px 8px; justify-content: center; min-height: 32px; padding: 4px 12px; font-size: 13px; font-weight: 700; background: #C60C30; color: #fff; border-color: #C60C30; }
#reportbtn:hover { background: #A50A28; border-color: #A50A28; }
.help-search { max-width: 560px; }
.help-item { border-top: 1px solid var(--rule); }
.help-item:first-child { border-top: 0; }
.help-item > summary { cursor: pointer; padding: 13px 18px; font-weight: 600; min-height: 48px; display: flex; align-items: center; gap: 10px; list-style: none; }
.help-item > summary::-webkit-details-marker { display: none; }
.help-item > summary::before { content: "+"; flex: none; width: 22px; height: 22px; border-radius: 50%; border: 1px solid var(--rule-strong); display: inline-flex; align-items: center; justify-content: center; font-weight: 600; color: var(--steel); line-height: 1; }
.help-item[open] > summary::before { content: "\2212"; }
.help-item > summary:hover { background: var(--paper); }
.help-item ol { margin: 0; padding: 2px 18px 4px 50px; }
.help-item li { margin: 0 0 8px; }
.help-item .actions { margin: 6px 18px 16px 50px; }
/* People page: who asked to reset their password and could not be emailed (views-signin.js) */
.reset-rows { margin-top: 10px; display: grid; gap: 8px; }
.reset-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
.signin-status { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 14px; }
.signin-status .btn { min-height: 32px; padding: 4px 12px; font-size: 14px; }
.qr { display: block; margin: 8px auto 12px; border: 1px solid var(--rule); border-radius: var(--r-sm); }
code { font-size: 14px; background: var(--paper); padding: 1px 5px; border-radius: 3px; word-break: break-all; }

/* Utilities (CSP forbids inline style attributes) */
.u-full { width: 100%; justify-content: center; }
.u-mt0 { margin-top: 0; } .u-mt6 { margin-top: 6px; } .u-mt8 { margin-top: 8px; } .u-mt16 { margin-top: 16px; }
.u-mb0 { margin-bottom: 0; } .u-mb4 { margin-bottom: 4px; } .u-mb6 { margin-bottom: 6px; } .u-m0 { margin: 0; } .u-my12 { margin: 12px 0; }
.u-end { justify-content: flex-end; } .u-pre { white-space: pre-wrap; } .u-signal { color: var(--signal); } .u-bt { border-top: 1px solid var(--rule); }
.w-44 { width: 44px; } .w-90 { width: 90px; } .w-120 { width: 120px; } .w-130 { width: 130px; }

/* Phones: stack row details under the title instead of squeezing it */
@media (max-width: 560px) {
  .row { grid-template-columns: 1fr; }
  .row .side { text-align: left; display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: center; }
  .row .side .actions { justify-content: flex-start; width: 100%; }
  .section > header { flex-wrap: wrap; }
  .section > header a { white-space: nowrap; }
}

/* ── Ticket editor ─────────────────────────────────── */
.tl-head, .tline { display: grid; gap: 8px; align-items: center; }
.tl-labor { grid-template-columns: minmax(130px, 1.6fr) 70px 80px minmax(140px, 1.5fr) 90px 100px 40px; }
.tl-goods { grid-template-columns: minmax(160px, 3fr) 80px 80px 100px 100px 40px; }
.tl-head { font-size: 13px; color: var(--steel); font-weight: 600; padding: 0 0 6px; border-bottom: 1px solid var(--rule); margin-bottom: 8px; }
.tl-head .r, .tline .r { text-align: right; }
.tline { padding: 6px 0; border-bottom: 1px dashed var(--rule); }
.tline input, .tline select { min-height: 40px; padding: 7px 8px; }
.tline button { min-height: 40px; padding: 0 10px; justify-content: center; }
.tl-note { grid-column: 1 / -1; margin-top: -4px; }
.d-block { display: block; }
.grid4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0 14px; }
table.summary { max-width: 420px; margin-left: auto; }
.tk-wrap { overflow-x: auto; }
table.tk { margin-bottom: 18px; }
table.tk-summary { max-width: 420px; margin-left: auto; }
table.tk-summary thead th { background: #262626; color: #fff; text-align: center; }
table.tk-summary tr.total td { background: #31869B; color: #fff; font-weight: 700; }
@media (max-width: 760px) {
  .tl-head { display: none; }
  .tl-labor { grid-template-columns: 1fr 1fr; }
  .tl-labor > select:first-child { grid-column: 1 / -1; }
  .tl-goods { grid-template-columns: 1fr 1fr; }
  .tl-goods > input:first-child { grid-column: 1 / -1; }
  .tline .r { text-align: left; }
  .grid4 { grid-template-columns: 1fr 1fr; }
}

/* ── Printable ticket: mirrors the workbook's ticket sheets ── */
body.printing { background: var(--rule); }
body.printing #public { display: block; place-items: initial; padding: 20px 12px; }
.print-bar { display: flex; gap: 8px; justify-content: center; margin-bottom: 14px; }
.ticket-sheet { background: #fff; width: min(8.5in, 100%); margin: 0 auto; padding: 0.35in; font: 400 11px/1.35 Arial, "Helvetica Neue", sans-serif; color: #000; box-shadow: 0 2px 12px rgba(0,0,0,.15); }
.ts-band { background: #000; display: flex; justify-content: center; align-items: center; padding: 10px 0 6px; }
.ts-band img { width: 230px; height: auto; }
.ts-title { background: #262626; color: #fff; text-align: center; font-weight: 700; font-size: 14px; padding: 9px; }
.ts-entity { text-align: center; font-size: 10px; color: #333; padding: 6px 0 8px; }
.ticket-sheet table { width: 100%; border-collapse: collapse; margin-bottom: 10px; }
.ticket-sheet th, .ticket-sheet td { border: 1px solid #bfbfbf; padding: 3px 5px; font-size: 10.5px; vertical-align: top; }
.ticket-sheet .ts-info th { text-align: left; width: 18%; font-weight: 700; background: #fff; }
.ticket-sheet .ts-info td { background: #DDEBF7; }
.ticket-sheet table.tk thead th { background: #000; color: #fff; font-weight: 700; text-align: center; }
.ticket-sheet table.tk tfoot td { font-weight: 700; }
.ticket-sheet table.tk-summary { width: 45%; margin-left: auto; }
.ticket-sheet .r { text-align: right; }
.ticket-sheet .small.muted { color: #555; font-size: 9px; }
.ts-terms { font-size: 9.5px; color: #333; margin: 6px 0 0; padding-left: 16px; }

@media print {
  @page { size: letter; margin: 0.3in; }
  body, body.printing { background: #fff; }
  .print-bar, #shell, #toast, dialog { display: none !important; }
  body.printing #public { padding: 0; }
  .ticket-sheet { box-shadow: none; width: 100%; padding: 0; }
  .ticket-sheet * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ── PDF viewer ────────────────────────────────────── */
.pdf-toolbar { position: sticky; top: 0; z-index: 5; display: flex; align-items: center; gap: 8px; padding: 8px 0; background: var(--paper); }
.pdf-toolbar button { min-height: 36px; padding: 6px 12px; }
.pdf-toolbar .num { margin-left: auto; color: var(--steel); font-size: 14px; }
.pdf-stage { background: var(--rule); border: 1px solid var(--rule); border-radius: var(--r-md); padding: 12px 0; overflow-x: auto; }
.pdf-page { margin: 0 auto 12px; width: max-content; max-width: 100%; }
.pdf-page canvas { display: block; background: #fff; box-shadow: 0 1px 4px rgba(0,0,0,.25); max-width: 100%; height: auto; }
.ack-box { margin-top: 18px; border: 2px solid var(--ink); border-radius: var(--r-md); background: var(--surface); padding: 16px 18px; }
.ack-box p { margin: 0 0 12px; }
.jump-bubble { position: fixed; right: 20px; bottom: 24px; z-index: 30; padding: 12px 18px; border-radius: var(--r-pill); border: 0; background: var(--hivis); color: var(--on-hivis); font-weight: 700; font-size: 15px; box-shadow: 0 4px 14px rgba(0,0,0,.25); cursor: pointer; }
.jump-bubble[hidden] { display: none; }
/* Material request line items: qty + item per row */
.line-items .li-rows { display: grid; gap: 6px; margin-bottom: 8px; }
.line-items .li-row { display: grid; grid-template-columns: 76px 1fr auto; gap: 6px; align-items: center; }
.line-items.with-unit .li-row { grid-template-columns: 70px 76px 1fr auto; }
textarea[hidden] { display: none; }
.row.clickable { cursor: pointer; }

/* Rate book: three kinds of rate, kept visibly apart so estimators bid from burdened cost only */
.tag-use { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 3px 9px; border-radius: var(--r-pill); background: var(--rule); color: var(--ink); }
.rate-burdened { border-left: 5px solid #2E7D4F; } .rate-burdened .tag-use { background: var(--tint-go); color: var(--go); }
.rate-sell { border-left: 5px solid #B5651D; } .rate-sell .tag-use { background: var(--tint-hivis); color: var(--wait); }
.rate-service { border-left: 5px solid #2F5F9E; } .rate-service .tag-use { background: var(--tint-info); color: var(--info); }
.rate-why { margin: 0 0 10px; color: var(--steel); }

/* Prevailing wage: the "Prevailing wage" / "PW" badge and the "Rates incomplete" warning */
.tag-pw { display: inline-block; font-size: 12px; font-weight: 700; letter-spacing: .03em; padding: 2px 8px; border-radius: var(--r-pill); background: var(--tint-pw); color: var(--pw-ink); white-space: nowrap; vertical-align: middle; }
.tag-pw.warn { background: var(--tint-signal); color: var(--signal); }
.rate-pw { border-left: 5px solid #5B3FA0; } .rate-pw .tag-use { background: var(--tint-pw); color: var(--pw-ink); }

/* Monthly reports */
.report-table input:not([type=checkbox]), .report-table select { min-width: 110px; padding: 6px 8px; font-size: 14px; }
.report-table td { vertical-align: middle; }
.num-in { width: 110px; text-align: right; }
/* WIP Schedule (views-reports.js wipBody): the headline figures, then one table in six groups with the job column
   kept in place while the figures scroll; a phone gets one card per job. */
.wip-kpis { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.wip-kpis .kpi .v { font-size: 22px; }
.wip-wrap { border-top: 1px solid var(--rule); }
table.wip-table { border-collapse: separate; border-spacing: 0; font-size: 14px; }
table.wip-table th, table.wip-table td { padding: 9px 10px; white-space: nowrap; }
table.wip-table thead th { background: var(--paper); }
table.wip-table tr.wip-groups th { text-align: center; text-transform: uppercase; letter-spacing: .05em; font-size: 12px; font-weight: 700; color: var(--ink); border-bottom: 0; padding-bottom: 2px; }
table.wip-table tr.wip-groups th.wip-job { text-align: left; vertical-align: bottom; padding-bottom: 9px; border-bottom: 1px solid var(--rule); }
table.wip-table .g { border-left: 1px solid var(--rule); }
table.wip-table .wip-job { position: sticky; left: 0; z-index: 1; background: var(--surface); text-align: left; white-space: normal; min-width: 210px; max-width: 280px; box-shadow: 1px 0 0 var(--rule); font-weight: 400; color: var(--ink); font-size: 14px; }
table.wip-table thead .wip-job { background: var(--paper); font-weight: 700; font-size: 13px; color: var(--steel); }
table.wip-table tr.wip-row > * { border-bottom: 0; }
table.wip-table tr.wip-row:not(:has(+ tr.wip-note-row)) > * { border-bottom: 1px solid var(--rule); }
table.wip-table tr.wip-note-row > td { padding-top: 0; white-space: normal; }
table.wip-table tr.total > td { background: var(--paper); border-bottom: 0; }
.wip-name { font-weight: 700; overflow-wrap: anywhere; }
.wip-links { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.wip-links .btn.small { min-height: 30px; padding: 4px 10px; font-size: 13px; }
.wip-note { display: flex; align-items: center; gap: 10px; }
.wip-note input { flex: 1; min-width: 0; max-width: 640px; }
.wip-pct { display: inline-flex; align-items: center; gap: 8px; justify-content: flex-end; }
.wip-pct progress { width: 64px; height: 8px; appearance: none; -webkit-appearance: none; border: 0; border-radius: 999px; overflow: hidden; background: var(--rule); }
.wip-pct progress::-webkit-progress-bar { background: var(--rule); }
.wip-pct progress::-webkit-progress-value { background: var(--go); }
.wip-pct progress::-moz-progress-bar { background: var(--go); }
.wip-neg { color: var(--signal); }
.wip-over { color: var(--wait); font-weight: 600; }
.wip-under { color: var(--signal); font-weight: 600; }
.wip-how { padding-top: 12px; padding-bottom: 14px; }
.wip-how summary { cursor: pointer; font-weight: 600; color: var(--steel); font-size: 14px; }
.wip-cards { display: grid; gap: 12px; }
.wip-card { border: 1px solid var(--rule); border-radius: var(--r-md); padding: 12px 14px; background: var(--surface); }
.wip-card.total { background: var(--paper); }
.wip-card > header { margin-bottom: 8px; }
.wip-group { border-top: 1px solid var(--rule); padding: 8px 0 2px; }
.wip-group h4 { margin: 0 0 4px; font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--steel); }
.wip-group dl { display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; margin: 0; align-items: center; }
.wip-group dt { color: var(--steel); font-size: 14px; }
.wip-group dd { margin: 0; text-align: right; }
.wip-card .wip-note { border-top: 1px solid var(--rule); padding-top: 10px; margin-top: 6px; flex-direction: column; align-items: stretch; gap: 4px; }
.wip-card .num-in { width: 130px; }
.grid-safety { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px 18px; }
.grid-safety .field span { display: block; font-size: 13.5px; color: var(--steel); margin-bottom: 4px; }
.row-link { text-decoration: none; display: inline-flex; gap: 6px; align-items: center; }

/* Home screen: summary cards, year to date, employee status */
.home-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; margin-bottom: 20px; }
.hcard { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-md); padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; }
.hcard-head { display: flex; align-items: center; justify-content: space-between; }
.hcard-head h2 { font-size: 16px; margin: 0; }
.hcard-add { font: 700 22px/1 var(--display); text-decoration: none; color: var(--navy, var(--ink)); padding: 0 4px; }
.hcard-stat { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 12px; background: var(--hover); border: 1px solid var(--rule); border-radius: var(--r-sm); padding: 10px 12px; text-decoration: none; color: var(--ink); }
.hcard-stat:hover { border-color: var(--ink); }
.hcard-stat b { font: 600 30px/1 var(--display); }
.hcard-stat span { font-weight: 600; font-size: 15px; } .hcard-stat small { display: block; font-weight: 400; color: var(--steel); font-size: 12.5px; margin-top: 2px; }
.hcard-stat i { font-style: normal; font-size: 20px; color: var(--steel); }
.hcard-done { padding: 6px 2px; } .hcard-done strong { display: block; } .hcard-done span { color: var(--steel); font-size: 13px; }
.hcard-link { font-size: 13.5px; font-weight: 600; }
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.kpi-cell { padding: 18px 12px; text-align: center; text-decoration: none; color: var(--ink); border-right: 1px solid var(--rule); }
.kpi-cell:last-child { border-right: 0; }
.kpi-cell span { display: block; font-size: 12px; letter-spacing: .04em; text-transform: uppercase; color: var(--steel); margin-bottom: 8px; }
.kpi-cell b { font: 600 24px/1.1 var(--display); text-decoration: underline; text-decoration-color: var(--rule-strong, var(--rule)); text-underline-offset: 4px; }
.kpi-cell small { display: block; font: 400 12px var(--body, inherit); color: var(--steel); text-decoration: none; margin-top: 4px; }
.seg { display: inline-flex; border: 1px solid var(--rule-strong); border-radius: var(--r-sm); overflow: hidden; }
.seg button { border: 0; border-radius: 0; background: var(--surface); padding: 6px 14px; font-weight: 600; color: var(--steel); }
.seg button + button { border-left: 1px solid var(--rule-strong); }
.seg button.on { background: var(--strong); color: var(--on-strong); }
@media (max-width: 820px) { .kpi-cell { border-right: 0; border-bottom: 1px solid var(--rule); } }
@media (max-width: 820px) { .jump-bubble { bottom: calc(76px + env(safe-area-inset-bottom)); right: 14px; } }
input[type="file"] { padding: 8px; }
@media (max-width: 820px) { .pdf-toolbar { top: 0; } }
.tl-field { grid-template-columns: minmax(160px, 3fr) 80px 80px 110px 40px; }
@media (max-width: 760px) { .tl-field { grid-template-columns: 1fr 1fr; } .tl-field > input:first-child { grid-column: 1 / -1; } }

/* ── Training courses ─────────────────────────────── */
.course-card { display: grid; grid-template-columns: 1fr auto; gap: 12px 20px; align-items: center; padding: 6px 0; }
.course-card + .course-card { border-top: 1px solid var(--rule); margin-top: 10px; padding-top: 14px; }
.course-card .title { font-weight: 600; font-size: 17px; }
.course-card .meta { color: var(--steel); font-size: 14px; }
.progress { height: 8px; background: var(--rule); border-radius: 4px; margin: 8px 0 4px; overflow: hidden; max-width: 420px; }
.progress span { display: block; height: 100%; width: var(--w, 0%); background: var(--go); border-radius: 4px; }
.course-card.overdue .progress span { background: var(--signal); }
.u-signal { color: var(--signal); }
.course-modules { list-style: none; padding: 0; margin: 0; counter-reset: none; }
.prose p { margin: 0 0 12px; max-width: 72ch; }
.prose ul { margin: 0 0 12px; padding-left: 22px; max-width: 72ch; }
.prose li { margin-bottom: 6px; }
ol.quiz { list-style: none; padding: 0; margin: 0; counter-reset: q; }
ol.quiz > li { counter-increment: q; padding: 14px 0; border-top: 1px solid var(--rule); }
ol.quiz > li:first-child { border-top: 0; padding-top: 0; }
ol.quiz .prompt { font-weight: 600; margin: 0 0 8px; }
ol.quiz .prompt::before { content: counter(q) ". "; color: var(--steel); }
.opt { display: flex; gap: 10px; align-items: flex-start; padding: 8px 10px; border: 1px solid var(--rule); border-radius: var(--r-sm); margin-bottom: 6px; cursor: pointer; font-weight: 400; }
.opt input { margin-top: 3px; width: 18px; height: 18px; min-height: 0; flex: none; }
.opt:hover { border-color: var(--rule-strong); }
.opt.is-correct { border-color: var(--go); background: var(--tint-go); }
.opt.is-chosen:not(.is-correct) { border-color: var(--signal); background: var(--tint-signal); }
.feedback { margin-top: 8px; padding: 10px 12px; border-radius: var(--r-sm); background: var(--paper); font-size: 14px; }
li.right .feedback { border-left: 4px solid var(--go); } li.wrong .feedback { border-left: 4px solid var(--signal); }
@media (max-width: 560px) { .course-card { grid-template-columns: 1fr; } }

/* ── Agreements (e-sign) ──────────────────────────── */
.esign-split { grid-template-columns: minmax(0, 1fr) 300px; align-items: start; }
.esign-split aside { position: sticky; top: 72px; display: grid; gap: 16px; }
.sign-doc-wrap { min-width: 0; }
.swatch { display: inline-block; width: 14px; height: 14px; vertical-align: -2px; margin-right: 6px; border-radius: 2px; }
.swatch.company { outline: 2px solid rgba(26,115,232,.6); background: rgba(255,244,150,.5); }
.swatch.client { outline: 2px solid rgba(26,115,232,.6); background: rgba(255,244,150,.5); border: 1px dashed #888; }
.swatch.locked { outline: 1px dashed rgba(0,0,0,.4); }
.rows.compact .row { padding: 8px 12px; }
.rows.compact button.row { width: 100%; text-align: left; background: none; border: 0; border-radius: 0; font: inherit; }
.stack { display: grid; gap: 10px; }
.stack label { display: grid; gap: 4px; font-size: 13px; font-weight: 600; }
.stack label input, .stack label select { font-weight: 400; }
.stack label.check { display: flex; align-items: center; gap: 8px; }
input.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; width: 100%; }
@media (max-width: 960px) { .esign-split { grid-template-columns: 1fr; } .esign-split aside { position: static; } }

/* ── Job costing & rentals ───────────────────────── */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; margin-bottom: 14px; }
.kpi { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r); padding: 10px 14px; }
/* A key number that says something (good, waiting, stop) carries a bar across its top; the rest are plain */
.kpi.go { box-shadow: inset 0 3px 0 var(--go); } .kpi.wait { box-shadow: inset 0 3px 0 var(--hivis); } .kpi.stop { box-shadow: inset 0 3px 0 var(--signal); }
.kpi .k { font-size: 11.5px; font-weight: 700; color: var(--steel); text-transform: uppercase; letter-spacing: .05em; }
.kpi .v { font: 600 26px/1.1 var(--display); color: var(--ink); margin: 3px 0 2px; font-variant-numeric: tabular-nums; }
.kpi .s { font-size: 13px; color: var(--steel); }
.costbar { height: 6px; background: var(--rule); border-radius: 3px; overflow: hidden; margin-top: 6px; max-width: 520px; }
.costbar.big { height: 10px; max-width: none; margin: 0 0 16px; }
.costbar span { display: block; height: 100%; width: 0; background: var(--navy); border-radius: 3px; }
.costbar span.over { background: var(--signal); }
table.lines tr.total td { border-top: 2px solid var(--rule-strong); font-weight: 700; }
.row.overdue { background: var(--tint-signal); }

/* ── Progress billing ────────────────────────────── */
.tablewrap { overflow-x: auto; }
table.g703 th { font-size: 11px; line-height: 1.2; vertical-align: bottom; white-space: nowrap; }
table.g703 td input { width: 110px; min-height: 32px; padding: 4px 6px; text-align: right; }
table.g703 tr.over td { background: var(--tint-signal); }
table.g702 td { padding: 7px 6px; }
table.g702 tr.total td { font-size: 16px; }
table.g702 td.neg { color: var(--signal); }
table.sov input { min-height: 34px; padding: 4px 8px; }
table.sov .w-item { width: 80px; } table.sov .w-amt { width: 160px; } table.sov .w-x { width: 44px; }
.billing-split { grid-template-columns: minmax(0, 1fr) 360px; align-items: start; }
@media (max-width: 1100px) { .billing-split { grid-template-columns: minmax(0, 1fr); } }   /* minmax: the wide G703 table scrolls in its box instead of widening the page */
.grow { flex: 1; }

/* ── Labor calculator ────────────────────────────── */
.lc-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1.4fr; gap: 12px; align-items: end; }
.lc-grid .field label.check { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; }
.lc-out { display: grid; grid-template-columns: max-content 1fr; gap: 6px 18px; margin: 14px 0 0; max-width: 420px; }
.lc-out dd { text-align: right; font-variant-numeric: tabular-nums; }
@media (max-width: 760px) { .lc-grid { grid-template-columns: 1fr 1fr; } }

/* ── New customer inside a customer picker ───────── */
fieldset.new-customer { border: 1px solid var(--rule); border-left: 4px solid var(--navy); border-radius: var(--r); padding: 10px 14px 4px; margin: 0 0 14px; }
/* Home screen period picker in the section header */
.period-select { font: inherit; font-weight: 700; border: 1px solid var(--rule); border-radius: var(--r); padding: 4px 28px 4px 8px; min-height: 0; width: auto; background-color: var(--surface); color: var(--navy); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
#statCells.loading { opacity: .5; }
fieldset.new-customer legend { font-weight: 700; font-size: 13px; padding: 0 6px; color: var(--navy); }

/* ── Client proposal (public link page and office preview) ── */
.proposal { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-md); padding: 24px; margin: 0 0 18px; }
.pr-head { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; border-bottom: 2px solid var(--navy); padding-bottom: 12px; margin-bottom: 14px; }
.pr-head h1 { margin: 0; font-size: 22px; color: var(--navy); }
.pr-num { margin: 4px 0 0; color: var(--steel); }
.pr-co { text-align: right; font-size: 13px; }
.pr-pre { white-space: pre-line; }
.pr-facts { display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px; margin: 0 0 16px; }
.pr-facts dt { font-weight: 700; color: var(--steel); }
.pr-facts dd { margin: 0; }
.pr-scope h2, .pr-decide h2 { font-size: 16px; margin: 0 0 6px; color: var(--navy); }
.pr-lines, .pr-totals { width: 100%; border-collapse: collapse; margin: 12px 0 0; }
.pr-lines td, .pr-totals td { padding: 6px 4px; border-bottom: 1px solid var(--rule); vertical-align: top; }
.pr-group th { text-align: left; padding: 12px 4px 4px; font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--steel); }
.pr-detail { color: var(--steel); white-space: nowrap; }
.pr-amt { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.pr-totals { max-width: 360px; margin-left: auto; }
.pr-total td { font-weight: 800; font-size: 17px; border-top: 2px solid var(--navy); border-bottom: 0; }
.pr-terms { margin: 16px 0 0; font-size: 13px; color: var(--steel); }
.pr-decide { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-md); padding: 20px 24px; }
.pr-decide .form-msg { color: var(--signal); min-height: 1em; }
.pr-decided { margin-bottom: 16px; }
@media (max-width: 600px) { .proposal, .pr-decide { padding: 16px; } .pr-co { text-align: left; } .pr-detail { white-space: normal; } }
.pr-print { max-width: 820px; margin: 24px auto; padding: 0 16px; }
/* Change Order / T&M Ticket document: Steel City Electric's change order format (always on white paper) */
.co-doc { background: #fff; color: #111; padding: 36px 56px 40px; font-family: Calibri, Carlito, "Segoe UI", Arial, sans-serif; }
.co-doc .co-logo { text-align: center; margin: 0 0 28px; }
.co-doc .co-logo img { width: 260px; max-width: 70%; height: auto; }
.co-facts p, .co-title, .co-intro, .co-totals { font-family: "Times New Roman", Times, serif; }
.co-facts p { margin: 0 0 14px; font-size: 18px; }
.co-facts sup, .co-totals sup { font-size: .6em; }
.co-title { text-align: center; text-decoration: underline; font-size: 21px; font-weight: 700; margin: 40px 0 2px; color: #111; }
.co-intro { text-align: center; font-size: 18px; margin: 0 0 4px; }
.co-ref { text-align: center; font-size: 12px; color: #666; margin: 0 0 20px; }
.co-items { list-style: none; counter-reset: co; padding: 0; margin: 0; }
.co-items li { counter-increment: co; margin: 0 0 18px; }
.co-items h3 { font-size: 16px; margin: 0 0 2px; font-weight: 700; color: #111; }
.co-items h3::before { content: counter(co) ". "; }
.co-items p { margin: 0; font-size: 15px; line-height: 1.4; }
.co-estimate h3 { font-size: 16px; margin: 18px 0 2px; }
.co-doc .pr-lines td, .co-doc .pr-group th { color: #111; border-color: #ddd; }
.co-totals { text-align: center; font-size: 18px; margin: 34px 0 0; }
.co-totals p { margin: 4px 0; }
.co-doc .pr-terms { text-align: center; color: #555; font-size: 12px; margin-top: 18px; }
@media (max-width: 600px) { .co-doc { padding: 20px 16px; } .co-facts p, .co-intro, .co-totals { font-size: 15px; } }
.u-w100 { width: 100%; } .u-mb16 { margin-bottom: 16px; }
/* Proposal progress on the ticket */
ol.steps { display: flex; flex-wrap: wrap; gap: 6px 18px; list-style: none; padding: 0; margin: 0 0 12px; counter-reset: step; }
ol.steps li { counter-increment: step; color: var(--steel); font-size: 13px; }
ol.steps li::before { content: counter(step); display: inline-grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; border: 1px solid var(--rule-strong, var(--rule)); margin-right: 6px; font-size: 11px; font-weight: 700; }
ol.steps li.done { color: var(--ink); font-weight: 600; }
ol.steps li.done::before { content: '✓'; background: var(--go-fill); border-color: var(--go-fill); color: #fff; }
@media print { .pr-print .no-print { display: none !important; } .proposal { border: 0; padding: 0; } }
/* Receipts: the photo of the receipt, as large as the screen allows */
.receipt-photo { display: block; max-width: 100%; max-height: 85vh; height: auto; margin: 0 auto; background: #fff; border: 1px solid var(--rule); border-radius: var(--r-sm); }
/* Training videos: the player fills the width (phones included) and never runs off the screen */
.video-frame { background: #000; border-radius: var(--r-md); overflow: hidden; margin-bottom: 10px; }
.video-frame video { display: block; width: 100%; max-height: 75vh; background: #000; }
.video-nav { justify-content: space-between; margin-top: 18px; }
/* Hub pages (project, job, ticket, client): key numbers, then every related kind of record in the same boxes */
.hub-kpis { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.hub-kpis .kpi .v { font-size: 22px; overflow-wrap: anywhere; }
.hub-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); gap: 0 20px; align-items: start; }
.hub-section > header h2 { margin: 0; }
/* Account page (views-admin.js renderAccount): two headed parts; the boxes are packed in columns so a short box does
   not leave a gap beside a tall one; one column on a phone */
.page-sub { font-size: 13px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--steel); margin: 26px 0 10px; }
.account-grid { columns: 2 380px; column-gap: 20px; }
.account-grid > * { break-inside: avoid; display: block; width: 100%; }
.account-grid > .section, .account-grid > div > .section { margin-bottom: 20px; }
.account-grid .section { break-inside: avoid; }
/* A person's page: the boxes with nothing in them, named on one line above the others */
.person-none { column-span: all; margin: 0 0 14px; }
/* Time → Time off: the views under the Time tabs (Mine, Requests, Balances, Who is out, Holidays), one smaller row that
   scrolls sideways on a phone instead of wrapping */
.filters.subtabs { margin-top: -4px; }
.filters.subtabs a.btn { min-height: 32px; padding: 4px 12px; font-size: 14px; }
@media (max-width: 600px) { .filters.subtabs { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; } .filters.subtabs a.btn { flex: none; } }
/* On a phone the key numbers are left out: each one is in its box below, and they pushed the boxes off the first screen */
@media (max-width: 600px) { .person-kpis { display: none; } }
.account-lead { margin: 0 0 12px; }
.perm-yes { margin: 0 0 12px; padding-left: 20px; display: grid; gap: 6px; }
.perm-yes li::marker { color: var(--go); }
details.perm-no { margin: 0 0 12px; font-size: 14px; }
details.perm-no summary { cursor: pointer; color: var(--steel); font-weight: 600; }
details.perm-no ul { margin: 8px 0 0; padding-left: 20px; color: var(--steel); display: grid; gap: 4px; }
.hub-head { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; justify-content: flex-end; }
.hub-sub { margin: 0; padding: 10px 18px 0; }
.hub-sub-head { padding: 12px 18px 4px; border-top: 1px solid var(--rule); font-weight: 600; }
/* Ticket pricing: the crew behind the composite labor rate, a count per classification (owner, 2026-11-11) */
.crew-mix { border: 1px solid var(--rule); border-radius: var(--r-md); background: var(--paper); padding: 10px 12px; margin: 0 0 12px; }
.crew-mix-counts { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: flex-end; margin-top: 8px; }
.crew-mix-counts label { display: grid; gap: 2px; font-size: 13px; font-weight: 600; color: var(--steel); }
.crew-mix-counts input { width: 84px; }
/* Training videos: a section's heading opens and closes its list (owner, 2026-11-11) */
details.video-section > summary { cursor: pointer; padding: 12px 18px; min-height: 44px; }
details.video-section > summary:hover { background: var(--paper); }
details.video-section[open] > summary { padding-bottom: 6px; }
.hub-msg { white-space: pre-wrap; overflow-wrap: anywhere; }
.hub-error { padding: 0 2px; }
/* The project page (one page for the project and its site job): office links under the key numbers, the More list */
.hub-links { margin: -6px 0 18px; color: var(--steel); }
.menu-list { display: grid; gap: 8px; margin: 12px 0 4px; }
.menu-list button { width: 100%; text-align: left; }
.msg { white-space: pre-wrap; overflow-wrap: anywhere; }
@media (max-width: 560px) { .hub-kpis .kpi { padding: 10px 12px; } .hub-kpis .kpi .v { font-size: 19px; } .hub-head { justify-content: flex-start; }
  .proj-actions { width: 100%; } .proj-actions > * { flex: 1 1 auto; } }
/* Job photos: thumbnail grids (hubs, change orders, the Photos page), the upload dialog and the lightbox */
.photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 6px; }
.photo-grid.small { grid-template-columns: repeat(auto-fill, minmax(64px, 84px)); }
.photo-tile { position: relative; display: block; width: 100%; aspect-ratio: 1; padding: 0; min-height: 0; border: 1px solid var(--rule); border-radius: var(--r-sm); overflow: hidden; background: var(--paper); cursor: zoom-in; }
.photo-tile img { display: block; width: 100%; height: 100%; object-fit: cover; }
.photo-tile .photo-tag { position: absolute; left: 4px; bottom: 4px; max-width: calc(100% - 8px); padding: 1px 6px; border-radius: 3px; background: rgba(29, 35, 41, .72); color: #fff; font-size: 12px; font-weight: 600; line-height: 1.5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.photo-grid.small .photo-tag { display: none; }
.photo-ph { display: grid; place-items: center; width: 100%; height: 100%; color: var(--steel); font-size: 12px; font-weight: 700; background: repeating-linear-gradient(45deg, var(--paper), var(--paper) 6px, var(--rule) 6px, var(--rule) 12px); }
.photo-more { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; padding: 0 18px 16px; }
.photo-more:empty { display: none; }
/* Photos page: one album per project and per ticket (views-photos.js renderAlbums), and the groups inside a project's album */
.albums { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 14px; }
a.album { display: flex; flex-direction: column; gap: 2px; padding: 8px; border: 1px solid var(--rule); border-radius: var(--r-md); background: var(--surface); color: var(--ink); text-decoration: none; min-width: 0; }
a.album:hover, a.album:focus-visible { border-color: var(--info); box-shadow: 0 1px 4px rgba(0, 0, 0, .12); }
a.album[hidden] { display: none; }
.album-covers { display: grid; grid-template-columns: 1fr 1fr; grid-auto-rows: 1fr; gap: 2px; aspect-ratio: 4 / 3; border-radius: var(--r-sm); overflow: hidden; background: var(--paper); margin-bottom: 6px; }
.album-covers.n1 { grid-template-columns: 1fr; }
.album-covers.n3 > :first-child { grid-row: span 2; }
.album-covers img, .album-covers .photo-ph { display: block; width: 100%; height: 100%; min-height: 0; object-fit: cover; }
.album-title { font-weight: 700; overflow-wrap: anywhere; }
.album-sub, .album-meta { color: var(--steel); font-size: 13px; overflow-wrap: anywhere; }
.photo-view-row { margin-bottom: 12px; }
.photo-group { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 20px 0 8px; font-size: 15px; }
.photo-group:first-child { margin-top: 0; }
@media (max-width: 480px) { .albums { grid-template-columns: 1fr 1fr; gap: 10px; } .seg.photo-view button { padding: 6px 10px; } }
#photoTools .list-count { display: none; }   /* the page counts below the grid ("60 of 240 shown") */
.photo-pick { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
.photo-pick .btn { cursor: pointer; }
.photo-pick-tag { width: auto; min-width: 140px; }
.photo-queue { display: grid; gap: 8px; margin: 4px 0 12px; }
.pq-row { display: grid; grid-template-columns: 64px minmax(0, 1fr) auto; gap: 10px; align-items: start; padding: 8px; border: 1px solid var(--rule); border-radius: var(--r-sm); }
.pq-row.done { border-color: var(--go); }
.pq-row.err { border-color: var(--signal); }
.pq-row.err .pq-msg { color: var(--signal); }
.pq-thumb { width: 64px; height: 64px; border-radius: var(--r-sm); overflow: hidden; background: var(--paper); }
.pq-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pq-name { font-weight: 600; font-size: 14px; overflow-wrap: anywhere; }
.pq-each { gap: 6px; margin: 6px 0; }
.pq-each select, .pq-each input { min-height: 38px; font-size: 15px; }
.pq-row progress { width: 100%; height: 8px; margin-top: 6px; accent-color: var(--go); }
.pq-x { min-height: 36px; padding: 4px 10px; }
.photo-mini { display: flex; flex-wrap: wrap; gap: 6px; }
.photo-mini .mini { position: relative; width: 64px; height: 64px; border: 1px solid var(--rule); border-radius: var(--r-sm); overflow: hidden; }
.photo-mini .mini.err { border-color: var(--signal); }
.photo-mini img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-mini button { position: absolute; top: 2px; right: 2px; min-height: 0; padding: 0 5px; font-size: 12px; line-height: 18px; border-radius: 3px; }
dialog.lightbox { width: 100vw; height: 100vh; height: 100dvh; max-width: 100vw; max-height: 100dvh; margin: 0; padding: 0; box-sizing: border-box; overflow: hidden; border-radius: 0; background: #111; color: #fff; }
dialog.lightbox::backdrop { background: rgba(0, 0, 0, .85); }
.lb { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; height: 100%; }
.lb-top { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; font-size: 14px; color: #ccc; }
.lb-x { background: transparent; color: #fff; border-color: #555; }
.lb-stage { position: relative; display: grid; place-items: center; min-height: 0; padding: 0 8px; overflow: hidden; }
/* A tall (portrait) photo must never push the caption and buttons off the screen: the photo gets the room between the
   top bar and the info panel (owner, 2026-11-10: "the message sits behind the photo") */
.lb-img { max-width: 100%; max-height: calc(100vh - 230px); max-height: calc(100dvh - 230px); object-fit: contain; display: block; }
.lb-ph { padding: 24px; max-width: 420px; text-align: center; color: #ddd; border: 1px dashed #555; border-radius: var(--r-md); }
.lb-nav { position: absolute; top: 50%; transform: translateY(-50%); width: 44px; height: 64px; justify-content: center; font-size: 30px; background: rgba(0, 0, 0, .45); color: #fff; border-color: transparent; }
.lb-nav.prev { left: 8px; } .lb-nav.next { right: 8px; }
.lb-info { padding: 12px 16px 16px; background: #1B1F23; overflow-wrap: anywhere; max-height: 180px; overflow-y: auto; }
.lb-info .meta { color: #bbb; font-size: 14px; margin: 4px 0 10px; }
.lb-info a:not(.btn) { color: #9CC8F0; }
.lb-info .status::before { background: var(--hivis); }
.lb-cap { font-size: 16px; }
.lb-info label { color: #ddd; }
.lb-err { color: #FFB4A9; margin-top: 8px; }
.lb-confirm p { margin: 0 0 10px; }
@media (max-width: 560px) { .lb-nav { width: 36px; height: 52px; font-size: 24px; } .lb-info { padding: 10px 12px 14px; } }

/* "Related" row under a page head (public/js/related.js): links from a record to its neighbours - tickets, agreements,
   forms, resources, training, PTO, monthly reports, HR, prevailing wage and certified payroll pages */
.related { display: flex; flex-wrap: wrap; gap: 6px 8px; align-items: center; margin: -8px 0 18px; }
.related-label { font-size: 13px; font-weight: 600; color: var(--steel); text-transform: uppercase; letter-spacing: .04em; margin-right: 2px; }
#view .related a, .related a { font-size: 14px; font-weight: 600; text-decoration: none; padding: 5px 11px; border: 1px solid var(--rule-strong); border-radius: var(--r-pill); background: var(--surface); color: var(--ink); overflow-wrap: anywhere; }
.related a:hover { background: var(--hover); }
.related-step { justify-content: space-between; }
/* Ticket page (views-tickets.js): the visit's buttons under the field's notices; the row goes away when it has none */
.visit-actions { margin: 0 0 22px; }
.visit-actions:not(:has(button, .btn)) { display: none; }
.visit-actions #tcrAction:empty { display: none; }
.visit-boxes { margin-bottom: 0; }
/* A tab or view chip whose count waits on the viewer ("Pending pricing (2)", "Waiting for review (3)"): red, like Action required */
.filters .btn.action-required:not(.primary) { border-color: var(--signal); color: var(--signal); }
.course-card.needs-action { border-radius: var(--r-sm); padding-left: 10px; }

/* Linked rows (public/js/hub.js mainLink / linkedRow): a list row that opens one record and also names others. A link
   cannot sit inside a link, so the row is a box whose title link is stretched over the whole row (still clickable
   anywhere); the other links and buttons inside sit above it. Used on Schedule, Projects, Purchasing, Receipts,
   Rentals, Change orders, Job costing, billing and the hub boxes. */
.row.linked { position: relative; }
.row.linked:hover { background: var(--hover); }
.row.linked .row-main { color: inherit; text-decoration: none; }
.row.linked .row-main::after { content: ""; position: absolute; inset: 0; }
.row.linked .row-main:focus-visible { outline: none; }
.row.linked .row-main:focus-visible::after { outline: 3px solid var(--info); outline-offset: -3px; }
.row.linked a:not(.row-main), .row.linked button, .row.linked .actions { position: relative; z-index: 1; }
/* Where a filtered list came from ("Material requests on FL-2026-003 · Project · Job costing · Show all") */
.list-context { margin: -6px 0 14px; color: var(--steel); font-size: 14px; }
/* A project's dated visits are worked on the project page (no job pages): the open visit's row and its detail, the
   visit a message in the project's conversation is about, and the "about" picker over the message box */
.row.visit.open { background: var(--tint-hivis); }
.visit-detail { padding: 14px 18px 16px; border-top: 1px dashed var(--rule-strong); background: var(--tint-hivis-soft); display: grid; gap: 12px; }
.visit-detail .rows { border: 1px solid var(--rule); border-radius: var(--r-sm); background: var(--surface); }
.visit-detail .empty { padding: 10px 0; }
.visit-crew .hub-sub-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.visit-links { margin: 0; }
.msg-tag { display: inline-block; margin-right: 4px; padding: 0 6px; border-radius: var(--r-sm); background: var(--strong); color: var(--on-strong); font-size: 12px; font-weight: 600; text-decoration: none; }
.composer.has-to { flex-wrap: wrap; }
.composer.has-to .composer-to { flex: 1 0 100%; width: 100%; }

/* Material deliveries (public/js/views-deliveries.js): the receiving page's numbered steps (what arrived, BOL photo,
   count every line, site photos, sign), the lines being counted, and the delivery page's count and signature.
   Phone first: one column, nothing wider than the screen. */
.step > header h2 { display: flex; align-items: center; gap: 10px; margin: 0; }
.step-n { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 28px; height: 28px; border-radius: var(--r-sm); background: var(--strong); color: var(--on-strong); font-size: 15px; font-weight: 700; }
.dv-saved { font-weight: 600; }
.dv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); gap: 0 14px; }
.dv-reqs { border: 1px solid var(--rule); border-radius: var(--r-sm); padding: 8px 12px 10px; min-width: 0; }
.dv-reqs legend { font-weight: 600; font-size: 14px; padding: 0 4px; }
.dv-req { align-items: flex-start; margin: 0; padding: 8px 0; border-top: 1px solid var(--rule); font-weight: 400; }
.dv-req:first-of-type { border-top: 0; }
.dv-req input { flex: none; width: 22px; height: 22px; margin-top: 2px; }
.dv-req span { min-width: 0; overflow-wrap: anywhere; }
.dv-req-what { display: block; }
.dv-ahead ol { margin: 6px 0 0; padding-left: 22px; color: var(--steel); }
.dv-lines { display: grid; gap: 10px; margin-bottom: 12px; }
.dv-line { display: grid; gap: 8px; min-width: 0; padding: 10px; border: 1px solid var(--rule-strong); border-radius: var(--r-sm); background: var(--surface); }
.dv-line.problem { border-left: 4px solid var(--signal); }
.dv-line-top { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px; }
.dv-line-qty { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px 8px; align-items: end; }
.dv-line-qty label { margin: 0; font-size: 13px; }
.dv-line-qty button { grid-column: 1 / -1; justify-content: center; min-height: 44px; }
.dv-line-cond { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); gap: 8px; align-items: center; }
.dv-line input.need { border-color: var(--signal); background: var(--tint-signal); }
@media (min-width: 700px) { .dv-line-qty { grid-template-columns: 110px 1fr 1fr auto; } .dv-line-qty button { grid-column: auto; min-height: 42px; } }
.dv-verify { align-items: flex-start; margin: 14px 0; padding: 12px; border: 2px solid var(--ink); border-radius: var(--r-sm); font-size: 16px; }
.dv-verify input { flex: none; width: 26px; height: 26px; margin-top: 1px; }
.dv-left { margin: 6px 0 0; padding-left: 20px; }
.dv-sum { margin: 0 0 4px; overflow-wrap: anywhere; }
.dv-discard { margin: 0 0 24px; }
.dv-item.problem { border-left: 4px solid var(--signal); background: var(--tint-signal); }
.dv-item .dv-note { color: var(--ink); }
.dv-signed { margin: 0 0 8px; }
.dv-signname { font-family: 'Caveat', cursive; font-size: 30px; font-weight: 600; line-height: 1.1; }
.dv-facts { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px 14px; margin: 0; }
.dv-facts dt { color: var(--steel); font-size: 14px; }
.dv-facts dd { margin: 0; overflow-wrap: anywhere; }

/* Permissions per person (views-permissions.js): the switches in the Invite and Manage dialogs, the box on a profile
   and "What you can do" on Account. A switch is a real checkbox (role="switch"): Tab reaches it, Space flips it. */
.hub-slot { display: contents; }
.perms-slot { margin: 4px 0 14px; }
details.perms { border: 1px solid var(--rule); border-radius: var(--r-md); background: var(--paper); }
details.perms > summary { cursor: pointer; padding: 12px 14px; font-weight: 600; display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; min-height: 44px; }
details.perms > summary .perms-title { font-family: var(--display); font-size: 18px; }
details.perms[open] > summary { border-bottom: 1px solid var(--rule); }
.perms-note { margin: 12px 14px 0; }
.perm-group { border: 0; margin: 0; padding: 10px 14px 2px; min-width: 0; }
.perm-group legend { float: left; width: 100%; padding: 0; margin: 0 0 6px; font: 600 13px var(--body); letter-spacing: .04em; text-transform: uppercase; color: var(--steel); }
.perm-group legend + * { clear: both; }
.perm-row { padding: 8px 0 10px; border-top: 1px solid var(--rule); min-width: 0; }
.perm-row.changed { box-shadow: inset 3px 0 0 var(--hivis); padding-left: 10px; }
label.switch { position: relative; display: flex; align-items: center; gap: 12px; cursor: pointer; min-height: 32px; font-weight: 600; }
label.switch input { position: absolute; left: 0; top: 50%; transform: translateY(-50%); opacity: 0; width: 44px; height: 26px; margin: 0; cursor: pointer; }
label.switch .track { flex: 0 0 44px; height: 26px; border-radius: 999px; background: var(--rule-strong); position: relative; transition: background .15s; }
label.switch .track::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0, 0, 0, .3); transition: transform .15s; }
label.switch input:checked + .track { background: var(--go); }
label.switch input:checked + .track::after { transform: translateX(18px); }
label.switch input:focus-visible + .track { outline: 3px solid var(--info); outline-offset: 2px; }
label.switch input:disabled + .track { opacity: .5; }
label.switch input:disabled ~ .perm-label { color: var(--steel); }
label.switch .perm-label { min-width: 0; overflow-wrap: anywhere; }
.perm-help { margin: 2px 0 0 56px; }
.perm-flag, .perm-lock { display: block; margin-top: 2px; color: var(--ink); font-weight: 600; }
.perm-lock { color: var(--steel); font-weight: 400; font-style: italic; }
.perm-warn { margin: 8px 0 0 56px; padding: 8px 12px; font-size: 14px; }
.perm-limit { margin: 8px 0 0 56px; max-width: 280px; }
.perm-limit input { width: 100%; }
.perms-foot { margin: 0; padding: 4px 14px 12px; }
.perm-group-head { background: var(--paper); padding-top: 6px; padding-bottom: 6px; }
.perm-line .side { text-align: right; }
@media (max-width: 480px) {
  .perm-help, .perm-warn, .perm-limit { margin-left: 0; }
  .perm-limit { max-width: none; }
}
@media (prefers-reduced-motion: reduce) { label.switch .track, label.switch .track::after { transition: none; } }

/* ── Schedule: the Month range as a calendar (public/js/views-ops.js renderSchedule: monthGrid) ─────────────
   One table, a week a row, Monday to Sunday. A day's cell: its number (a link that opens that day; today's is gold),
   then its work, a line each: the status dot (.status and its colours; the word stays for screen readers), the title
   in bold and the work after it. Work waiting on the viewer to assign carries .needs-action, finished work is quiet,
   cancelled work is struck through. Days of the neighbouring months (.out) are muted and carry no work.
   Up to 1080px wide (a phone, a tablet, a small window beside the menu: a day is then too narrow to hold a title)
   the lines give way to a count (.count, and the red .count.action for work to assign), and the picked day's work is
   listed under the grid (.mcal-pick; the page reads its display to know that a tap picks a day). Every colour is a
   palette name, so dark mode needs nothing of its own. */
table.mcal { width: 100%; table-layout: fixed; border-collapse: collapse; }
table.mcal th { padding: 6px 8px; text-align: left; font-size: 11.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--steel); background: var(--hover); border-bottom: 1px solid var(--rule-strong); }
table.mcal td { height: 127px; padding: 4px; vertical-align: top; border-top: 1px solid var(--rule); border-left: 1px solid var(--rule); }   /* the number and four lines */
table.mcal tr > :first-child { border-left: 0; }
table.mcal td.out { background: var(--paper); }
table.mcal td.today { background: var(--tint-hivis-soft); }
.mcal-num { display: inline-flex; align-items: center; justify-content: center; vertical-align: top; min-width: 26px; height: 22px; padding: 0 4px; border: 1px solid transparent; border-radius: var(--r-sm);
  color: var(--ink); font-size: 14px; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; text-decoration: none; }
.mcal-num:hover { border-color: var(--ink); }
table.mcal td.out .mcal-num { color: var(--steel); font-weight: 400; }
table.mcal td.today .mcal-num { background: var(--hivis); border-color: var(--hivis-press); color: var(--on-hivis); font-weight: 700; }
.mcal-ev { display: flex; align-items: center; gap: 6px; margin-top: 2px; padding: 1px 6px 1px 8px; border-radius: var(--r-sm); color: var(--ink); font-size: 13px; line-height: 20px; text-decoration: none; }
.mcal-ev:hover { background-color: var(--hover); }
.mcal-ev.needs-action:hover { background-color: var(--tint-signal-strong); }
.mcal-st { display: flex; flex: none; width: 8px; overflow: hidden; }
.mcal-st .status, .mcal-st .status::before { flex: none; }
.mcal-t { display: flex; flex: 1 1 auto; gap: 5px; min-width: 0; }
.mcal-t > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mcal-t b { flex: 0 1 auto; font-weight: 600; }
.mcal-t span { flex: 0 1000 auto; }   /* a ticket's kind ("Service Call") is read whole: its work takes what is left of the line */
.mcal-t.proj b { flex-shrink: 1000; }   /* a project's name gives way to the phase, which keeps up to its share */
.mcal-t.proj span { flex-shrink: 1; max-width: 55%; }
.mcal-ev.done .mcal-t { color: var(--steel); }
.mcal-ev.off .mcal-t { color: var(--steel); text-decoration: line-through; }
.mcal-more { display: block; margin-top: 2px; padding: 1px 6px 1px 8px; border-radius: var(--r-sm); color: var(--info); font-size: 13px; font-weight: 600; line-height: 20px; text-decoration: none; }
.mcal-more:hover { background: var(--tint-info); }
.mcal-more.act { color: var(--signal); }
.mcal-more.act:hover { background: var(--tint-signal); }
.mcal-n, .mcal-pick { display: none; }
@media (max-width: 1080px) {
  table.mcal th { padding: 6px 0; text-align: center; letter-spacing: 0; }
  table.mcal td { height: 58px; padding: 4px 1px; text-align: center; cursor: pointer; }
  table.mcal td.picked { outline: 2px solid var(--ink); outline-offset: -2px; }
  .mcal-ev, .mcal-more { display: none; }
  .mcal-n { display: flex; flex-wrap: wrap; justify-content: center; gap: 2px; margin-top: 3px; }
  .mcal-n .count { min-width: 18px; padding: 0 4px; margin: 0; }
  .mcal-pick { display: block; }
}

/* ── Schedule project (public/js/views-project-schedule.js) ──────────────────
   The project page's Schedule box: the progress line, Timeline (a Gantt-style chart in plain HTML: bars on a week
   grid), List and Lookahead; the Schedule project and Update progress dialogs; the printed lookahead.
   Sizes that depend on the data (bar positions, filled parts, the chart's scale) are CSS custom properties that the
   page sets from JavaScript (--pct, --s, --len, --days, --day, --name, --today): the security policy allows no
   style attributes. */
.ps-meter { display: inline-block; vertical-align: middle; width: 120px; max-width: 100%; height: 8px; border-radius: 4px; background: var(--rule); overflow: hidden; }
.ps-meter > span { display: block; height: 100%; width: calc(var(--pct, 0) * 1%); background: var(--go); border-radius: 4px; }
.ps-meter.big { width: 180px; height: 10px; }
.ps-summary { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; padding: 12px 18px; border-bottom: 1px solid var(--rule); }
.ps-rowprog, .ps-progress { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin-top: 6px; }
.ps-progress { margin: 0; }
.ps .hub-head .seg button { min-height: 34px; padding: 4px 14px; }
.ps-open-phase { border-top: 2px solid var(--rule-strong); }
.ps-links { align-items: center; }
#modal-body .ps-links { justify-content: flex-start; }

/* Timeline. Only the chart scrolls sideways, never the page; the phase names and the month names stay in view. */
.ps-gantt { overflow-x: auto; overscroll-behavior-x: contain; --name: 196px; --day: 12px; --days: 7; }
.ps-gantt:focus-visible { outline: 3px solid var(--info); outline-offset: -3px; }
.ps-g-inner { position: relative; width: calc(var(--name) + var(--days) * var(--day)); padding-bottom: 20px; }
.ps-g-row { display: flex; border-top: 1px solid var(--rule); min-height: 46px; }
.ps-g-row:first-child { border-top: 0; }
.ps-g-name { flex: 0 0 var(--name); width: var(--name); position: sticky; left: 0; z-index: 3; background: var(--surface); border-right: 1px solid var(--rule-strong);
  padding: 6px 10px 6px 18px; min-width: 0; display: flex; flex-direction: column; justify-content: center; font-weight: 600; }
.ps-g-row.needs-action { box-shadow: none; background: none; }
.ps-g-row.needs-action .ps-g-name { box-shadow: inset 4px 0 0 var(--signal); background: var(--tint-signal); }
.ps-g-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps-g-name .small { font-weight: 400; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps-g-name .status.action-required { font-size: 12px; padding: 1px 7px; white-space: nowrap; }
.ps-gantt.slim .ps-ar { display: none; }
.ps-gantt.slim .ps-g-name .status.action-required { text-transform: capitalize; }
.ps-g-track { position: relative; flex: 0 0 calc(var(--days) * var(--day)); display: flex; }
.ps-g-months, .ps-g-weeks { min-height: 0; background: var(--paper); }
.ps-g-months .ps-g-name, .ps-g-weeks .ps-g-name { background: var(--paper); font-size: 14px; color: var(--steel); padding-top: 4px; padding-bottom: 4px; }
.ps-g-month { flex: 0 0 calc(var(--len) * var(--day)); overflow: clip; border-left: 1px solid var(--rule-strong); font: 600 14px var(--display); white-space: nowrap; }
.ps-g-month:first-child, .ps-g-week:first-child { border-left: 0; }
.ps-g-month span { position: sticky; left: calc(var(--name) + 1px); display: inline-block; padding: 5px 8px; }
.ps-g-week { flex: 0 0 calc(7 * var(--day)); overflow: clip; border-left: 1px solid var(--rule); font-size: 12px; color: var(--steel); padding: 3px 4px; white-space: nowrap; }
.ps-g-week .wk-long { display: none; }
.ps-gantt.wide .ps-g-week .wk-long { display: inline; }
.ps-gantt.wide .ps-g-week .wk-short { display: none; }
.ps-g-grid { background-image: linear-gradient(to right, var(--rule) 1px, transparent 1px); background-size: calc(7 * var(--day)) 100%; }
.ps-gantt.no-weekends .ps-g-grid { background-image: linear-gradient(to right, var(--rule) 1px, transparent 1px),
  linear-gradient(to right, transparent calc(5 * var(--day)), var(--hover) calc(5 * var(--day))); }
.ps-bar { position: absolute; top: 9px; height: 28px; left: calc(var(--s) * var(--day) + 1px); width: calc(var(--len) * var(--day) - 2px); min-width: 8px; z-index: 1;
  border-radius: var(--r-sm); background: var(--bar); border: 1px solid var(--bar-edge); overflow: hidden; color: var(--ink); text-decoration: none; }
.ps-bar:hover { border-color: var(--ink); }
.ps-bar:focus-visible { outline: 3px solid var(--info); outline-offset: 1px; }
.ps-fill { position: absolute; left: 0; top: 0; bottom: 0; width: calc(var(--pct, 0) * 1%); background: var(--bar-fill); box-shadow: inset -2px 0 0 var(--info); }
.ps-fill[data-pct="0"] { box-shadow: none; }
.ps-bar.st-complete { border-color: var(--go); }
.ps-bar.st-complete .ps-fill { background: var(--bar-done); box-shadow: none; }
.ps-bar.act { border-color: var(--signal); box-shadow: inset 4px 0 0 var(--signal); }
.ps-bar.tiny .ps-bar-label { display: none; }
.ps-bar-label { position: relative; display: block; padding: 0 7px; font: 600 13px/26px var(--body); white-space: nowrap; font-variant-numeric: tabular-nums; }
.ps-today { position: absolute; top: 0; bottom: 0; left: calc(var(--name) + (var(--today) + .5) * var(--day)); width: 0; border-left: 2px solid var(--ink); z-index: 2; pointer-events: none; }
.ps-today span { position: absolute; bottom: 2px; left: 3px; background: var(--strong); color: var(--on-strong); font-size: 12px; font-weight: 600; line-height: 16px; padding: 0 5px; border-radius: 3px; white-space: nowrap; }
.ps-legend { margin: 0; padding: 8px 18px 10px; border-top: 1px solid var(--rule); }

/* Lookahead: the next weeks, day by day */
.ps-la-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 10px 18px; border-bottom: 1px solid var(--rule); }
.ps-la-tools .seg button { min-height: 34px; padding: 4px 13px; }
.ps-la-tools > button { margin-left: auto; }
.ps-la-week { padding: 8px 18px; background: var(--paper); border-top: 1px solid var(--rule); font: 600 15px var(--display); color: var(--steel); }
.ps-la-week:first-child { border-top: 0; }
.ps-la-day { display: grid; grid-template-columns: 132px minmax(0, 1fr); gap: 4px 14px; padding: 9px 18px; border-top: 1px solid var(--rule); align-items: start; }
.ps-la-day.is-today { background: var(--tint-hivis-soft); }
.ps-la-date { font-weight: 600; padding-top: 6px; }
.ps-la-items { display: grid; gap: 6px; min-width: 0; }
.ps-la-items > .muted { padding-top: 6px; }
.ps-la-item { display: grid; gap: 1px; padding: 6px 10px; border: 1px solid var(--rule-strong); border-left: 4px solid var(--info); border-radius: var(--r-sm); background: var(--surface);
  color: var(--ink); text-decoration: none; min-width: 0; overflow-wrap: anywhere; }
.ps-la-item:hover { border-color: var(--ink); border-left-color: var(--info); }
.ps-la-item.st-not_started { border-left-color: var(--steel); }
.ps-la-item.st-complete { border-left-color: var(--go); }
.ps-la-item.act { border-left-color: var(--signal); background: var(--tint-signal); }
.ps-la-title { font-weight: 600; }
/* Room for it: one line per phase (name, hours and day, who) */
@media (min-width: 1100px) { .ps:not(.narrow) .ps-la-item { grid-template-columns: minmax(150px, 1fr) minmax(0, 1.3fr) minmax(0, 1.7fr); gap: 2px 14px; align-items: baseline; } }
@media (max-width: 560px) {
  .ps-la-day { grid-template-columns: minmax(0, 1fr); }
  .ps-la-date { padding-top: 0; }
  .ps-la-tools > button { margin-left: 0; }
  .ps-summary, .ps-la-tools, .ps-la-day, .ps-la-week { padding-left: 14px; padding-right: 14px; }
}

/* Schedule project and Update progress dialogs */
dialog.wide { width: min(760px, calc(100vw - 24px)); }
.ps-dialog .ps-d-sub { margin: -8px 0 14px; }
.ps-d-h { margin: 18px 0 10px; padding-top: 14px; border-top: 1px solid var(--rule); }
.ps-dialog .ps-summary { padding: 0 0 10px; border-bottom: 0; }
.ps-d-facts { margin-bottom: 8px; }
.ps-d-rows { border: 1px solid var(--rule); border-radius: var(--r-sm); }
.ps-d-rows .row { padding: 10px 12px; }
.ps-d-row.editing { background: var(--tint-hivis); }
#modal-body .ps-d-row .actions { margin-top: 6px; align-items: center; }
.ps-picks { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.ps-picks button { min-height: 34px; padding: 4px 10px; border-radius: var(--r-pill); font-weight: 500; }
.ps-picks button.used { color: var(--steel); border-style: dashed; }
.ps-d-warn { margin: 0 0 14px; }
.ps-d-quick { margin: 16px 0 4px; border: 1px solid var(--rule); border-radius: var(--r-sm); background: var(--paper); }
.ps-d-quick > summary { cursor: pointer; padding: 11px 14px; font-weight: 600; min-height: 44px; }
.ps-d-quick > p, .ps-d-quick > .ps-d-checks, .ps-d-quick > .actions { margin: 0 14px 12px; }
.ps-d-checks { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 8px 14px; }
.ps-pct-now { text-align: center; font: 700 44px/1 var(--display); margin: 6px 0 10px; font-variant-numeric: tabular-nums; }
.ps-pct input[type="range"] { padding: 0; min-height: 44px; border: 0; background: transparent; accent-color: var(--go); }
.ps-pct-quick { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 6px; }
.ps-pct-quick button { flex: 1 1 auto; justify-content: center; min-height: 44px; }

/* Overlaps that are allowed (the same person on two phases of one project, or on a ticket's visit inside a phase):
   a small neutral marker for the people who schedule, with who and when in its title. Never the Action-required red. */
.ps-overlap { display: inline-block; vertical-align: baseline; padding: 0 7px; border: 1px dashed var(--wait); border-radius: var(--r-pill); color: var(--wait); background: var(--surface);
  font: 600 12px/18px var(--body); white-space: nowrap; cursor: help; position: relative; z-index: 1; }
.ps-bar.ov::after { content: ""; position: absolute; top: 0; bottom: 0; right: 0; width: 7px;
  background: repeating-linear-gradient(135deg, var(--wait) 0 2px, transparent 2px 5px); border-left: 1px solid var(--wait); }
.ps-d-overlaps { margin: 14px 0 0; }
.ps-d-overlaps ul { margin: 6px 0 0; padding-left: 20px; }

/* The printed lookahead: its own sheet, shown only on paper (the app itself is hidden when printing, see @media print above) */
#printSheet { display: none; }
@media print {
  body.print-sheet > *:not(#printSheet) { display: none !important; }
  body.print-sheet #printSheet { display: block; color: #000; font: 400 11pt/1.35 Arial, "Helvetica Neue", sans-serif; }
  .ps-print h1 { font: 700 16pt Arial, sans-serif; margin: 0 0 2pt; }
  .ps-print .pl-sub { margin: 0 0 2pt; color: #333; font-size: 10pt; }
  .ps-print table { width: 100%; border-collapse: collapse; margin-top: 8pt; }
  .ps-print th, .ps-print td { border: 1px solid #999; padding: 3pt 5pt; text-align: left; vertical-align: top; font-size: 10pt; }
  .ps-print thead th { background: #222; color: #fff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .ps-print tbody th { width: 17%; font-weight: 700; white-space: nowrap; }
  .ps-print tr.wk th { background: #e6e6e6; font-size: 10pt; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .ps-print .r { text-align: right; white-space: nowrap; }
  .ps-print .pl-dim { color: #555; }
  .ps-print .pl-h { white-space: nowrap; }
  .ps-print tr { break-inside: avoid; }
}
ul.holiday-list { columns: 2 170px; column-gap: 20px; }
/* Phone page headers: the main button plus More… (app.js compactHead); the other buttons are listed under More… */
.page-head .head-more { display: none; }
@media (max-width: 600px) {
  .page-head .head-extra { display: none !important; }
  .page-head .head-more { display: inline-flex; align-items: center; justify-content: center; }
  /* Purchasing keeps its three header buttons on a phone, the same on every tab: they fill their rows (two, then one) */
  .purchasing-head .actions { width: 100%; }
  .purchasing-head .actions > button { flex: 1 1 auto; }
}
.box-action { color: var(--signal); font-size: 13px; font-weight: 700; white-space: nowrap; }
/* Hub boxes: "See all" sits under the rows, so the header keeps its title on one line beside the add buttons */
.hub-foot { padding: 8px 18px 12px; border-top: 1px solid var(--rule); }
.hub-section > header { flex-wrap: wrap; }
@media (min-width: 561px) { .hub-section > header h2 { flex: none; } }
/* Phone timeline: phase names take two lines instead of being cut off */
.ps-gantt.slim .ps-g-name { padding: 6px 6px 6px 10px; }
.ps-gantt.slim .ps-g-title { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.2; font-size: 14px; overflow-wrap: anywhere; }
/* Monthly reports: each cell is a link that says "Open report", tall enough to tap */
a.report-cell { flex-wrap: wrap; min-height: 36px; padding: 4px 0; }
a.report-cell .report-open { color: var(--info); font-weight: 600; }
.hub-nothing { grid-column: 1 / -1; margin: 0 0 20px; }

/* ── Appearance (public/js/theme.js; owner, 2026-11-12) ─────────────────────────────
   Explanations: a paragraph that only explains a page carries class "note" and is shown only when the person turns
   "Show the explanations on pages" on (Account > Appearance). Off is the usual. */
html[data-notes="off"] .note { display: none !important; }
/* The sign-in pages carry both logos: black lettering on light, white lettering on dark */
.brand .logo-dark { display: none; }
:root[data-theme="dark"] .brand .logo-light { display: none; }
:root[data-theme="dark"] .brand .logo-dark { display: block; }
/* The switch as a row of the phone's More page: a button that looks like the rows around it */
button.theme-row { width: 100%; border: 0; border-top: 1px solid var(--rule); border-radius: 0; background: none; text-align: left; font: inherit; min-height: 0; cursor: pointer; }
button.theme-row:hover { background: var(--hover); }
/* Account > Appearance: Light, Dark, Match this device */
fieldset.choice { border: 0; padding: 0; margin: 0 0 12px; min-width: 0; display: flex; flex-wrap: wrap; gap: 6px 18px; }
fieldset.choice legend { padding: 0; margin: 0 0 6px; font-weight: 600; font-size: 14px; }
fieldset.choice label { display: inline-flex; align-items: center; gap: 7px; margin: 0; font-weight: 500; font-size: 15px; min-height: 34px; cursor: pointer; }
fieldset.choice input { width: 18px; height: 18px; min-height: 0; flex: none; }
/* Dark mode: photos and scans keep their own light ground; nothing else needs a special case because every
   component colour is a palette name */
:root[data-theme="dark"] .receipt-photo, :root[data-theme="dark"] .qr { background: #fff; }

/* ── Employee hub (public/js/views-person.js; owner, 2026-11-12: "a hub for every employee") ─────────────
   One page per employee: a row of buttons that jump to its parts (it stays at the top while the page scrolls), the
   parts under their headings, and the HR file's folders at the end. */
.hub-jump { position: sticky; top: 0; z-index: 6; display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; padding: 8px 0; background: var(--paper); border-bottom: 1px solid var(--rule); }
.hub-jump button { min-height: 34px; padding: 4px 12px; font-size: 14px; }
.hub-group, #hubHr [data-cat] { scroll-margin-top: 62px; }
.hub-file-head { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; justify-content: space-between; margin: 0 0 12px; }
.hub-file-head p { margin: 0; overflow-wrap: anywhere; min-width: 0; }
/* A phone: the jump row is one line that scrolls sideways inside itself (the page never does), and a fact's
   name sits above its value */
@media (max-width: 600px) {
  .hub-jump { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .hub-jump button { flex: none; min-height: 38px; }
  dl.hub-facts { grid-template-columns: minmax(0, 1fr); gap: 2px 0; }
  dl.hub-facts dd { margin-bottom: 8px; }
  .hub-file-head .btn { width: 100%; justify-content: center; }
}

/* ── Project files (public/js/views-project-files.js; owner, 2026-11-12) ────────────
   The Files box on the project page: folders and files as dense rows (kind, name and caption, Edit), the folder
   line, the find box, and the Add files / Edit dialogs. Every row is at least 44 px tall to tap on a phone. */
.pf-rows { margin: 0; }
.pf-row { position: relative; display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; gap: 2px 12px; align-items: center; min-height: 44px; padding: 8px 16px; border-top: 1px solid var(--rule); }
.pf-rows > .pf-row:first-child { border-top: 0; }
.pf-row:hover { background: var(--hover); }
.pf-row.pf-hit { background: var(--tint-hivis-soft); box-shadow: inset 3px 0 0 var(--hivis); }
.pf-ext { display: flex; align-items: center; justify-content: center; width: 40px; height: 32px; border: 1px solid var(--rule-strong); border-radius: var(--r-sm); font: 600 11px var(--body); letter-spacing: .02em; color: var(--steel); background: var(--surface); overflow: hidden; }
.pf-ext.dir { background: var(--hivis); border-color: var(--hivis-press); color: var(--on-hivis); font-size: 14px; }
.pf-main { min-width: 0; }
.pf-open { display: inline; padding: 0; min-height: 0; border: 0; background: none; font: 600 15px var(--body); color: inherit; text-align: left; text-decoration: none; cursor: pointer; overflow-wrap: anywhere; }
.pf-open::after { content: ""; position: absolute; inset: 0; }
.pf-open:focus-visible { outline: none; }
.pf-open:focus-visible::after { outline: 3px solid var(--info); outline-offset: -3px; }
.pf-row .meta { display: flex; flex-wrap: wrap; gap: 2px 10px; align-items: center; font-size: 13px; color: var(--steel); }
.pf-row .pf-dl, .pf-row .pf-btn { position: relative; z-index: 1; }
.pf-row .pf-dl { color: var(--info); }
.pf-tag { display: inline-block; padding: 0 6px; border: 1px solid var(--rule-strong); border-radius: var(--r-sm); font-size: 12px; font-weight: 600; line-height: 18px; color: var(--ink); background: var(--surface); white-space: nowrap; }
.pf-tag.office { border-color: var(--signal); color: var(--signal); background: var(--tint-signal); }
.pf-crumb { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; padding: 8px 16px; border-bottom: 1px solid var(--rule); }
.pf-crumb strong { overflow-wrap: anywhere; }
.pf-find { padding: 8px 16px; border-bottom: 1px solid var(--rule); }
.pf-find input { width: 100%; }
.pf-form .pf-where { margin: -8px 0 12px; }
.pf-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
button.pf-chip { min-height: 32px; padding: 3px 9px; font-size: 13px; font-weight: 500; }
.pf-queue { margin: 10px 0 14px; border: 1px solid var(--rule); border-radius: var(--r-sm); }
.pf-queue:empty { display: none; }
.pf-q { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0 10px; align-items: center; padding: 6px 10px; border-top: 1px solid var(--rule); }
.pf-q:first-child { border-top: 0; }
.pf-q-name { font-weight: 600; overflow-wrap: anywhere; }
.pf-q-msg { grid-column: 1; }
.pf-q.err .pf-q-msg { color: var(--signal); }
.pf-q.done .pf-q-msg { color: var(--go); }
button.pf-x { grid-column: 2; grid-row: 1 / span 2; min-height: 36px; padding: 4px 10px; border: 0; background: none; color: var(--steel); }
#modal-body .pf-form .actions .pf-remove { margin-right: auto; }
@media (max-width: 820px) {
  .pf-row { padding: 8px 12px; gap: 2px 10px; }
  .pf-row .pf-btn { min-height: 44px; min-width: 52px; justify-content: center; }
  .pf-row .pf-dl { display: inline-flex; align-items: center; min-height: 30px; }
  button.pf-chip { min-height: 40px; padding: 6px 11px; font-size: 14px; }
  button.pf-x { min-height: 44px; min-width: 44px; }
  .pf-crumb, .pf-find { padding: 8px 12px; }
}

/* ── Review fixes (site review, 2026-11-12; owner: "Create more buttons where possible to make the website less
   tacky. Make everything easily understandable and easy to navigate and accessible for humans") ─────────────
   One block, so what the review changed can be read and undone in one place. Colours only through the variables at
   the top of this file, so dark mode follows. Four parts: buttons, jump rows, tap targets on a phone, small text. */

/* 1. Buttons. The To-Do cards' "+ New" and "View ..." are real buttons now (.btn small in views-ops.js): they sit
   at the edge of the card and do not stretch across it. */
.hcard-head .hcard-new { flex: none; }
.hcard .hcard-all { align-self: flex-start; }
/* The Clear button of a list's search and filters keeps to one line beside the count */
.list-tools button.small { white-space: nowrap; }

/* 2. Jump rows. The row of buttons that jumps between the parts of a long page (views-person.js jumpRow) is on the
   project and client pages too; each part stops below the row, which stays at the top of the screen. */
#psBox, #messages, #corBox, #siteBox, #hubTickets, #hubRequests, #hubDeliveries, #hubReceipts, #hubFiles, #hubPhotos, #hubTime, #hub,
#cliTop, #cliProjects, #cliTickets, #cliInvoices, #cliActivity, #cliAgreements, section[id^="jump-"] { scroll-margin-top: 62px; }
/* (section[id^="jump-"]: the boxes of a monthly report and of the rate book, numbered by autoJump) */
/* "On this page" in front of the Resources and training jump row, so the row does not read as tabs */
.jump-row .related-label { align-self: center; }

/* 3. Tap targets on a phone: at least 40px tall where the review measured less (375px wide). */
@media (max-width: 600px) {
  /* Related links, "See all" and the other small link buttons, phone / email / address links, name links in text */
  #view .related a, #view a.small:not(.btn), #modal-body a.small:not(.btn) { min-height: 40px; }
  #view a:not([class]), #view a.ci-link, #modal-body a:not([class]), #modal-body a.ci-link, #public a:not([class]) { min-height: 40px; }
  /* The jump row's buttons (person, Account, project, client) */
  .hub-jump button { min-height: 40px; }
  /* To-Do: the Period picker */
  .period-select { min-height: 40px; }
  /* Schedule: a day's number in the Month calendar, and Timeline / List / Lookahead */
  .mcal-num { min-width: 40px; height: 40px; }
  .seg button { min-height: 40px; }
  /* Weekly totals: View timesheet */
  table.timesheets .btn.small { min-height: 40px; }
  /* Checkboxes and radios: the label is the target, so the whole line is 40px tall */
  label.check { min-height: 40px; }
  /* Progress billing: the schedule of values and the application's "this period" and "stored" cells */
  table.g703 td input, table.sov input { min-height: 40px; }
  /* Account: "Not part of your role" under Permissions */
  details.perm-no > summary { padding: 9px 0; }
}

/* 4. Small text: nothing on a page is under 12px (table headings, the key numbers' captions, the day boxes on Time).
   The printed ticket sheet keeps its own sizes: it is laid out for paper. */
.day-stats .k, table.lines th, .kpi .k, table.g703 th, table.mcal th { font-size: 12px; }

/* Focus stays visible on everything the review turned into a button or a link (the global :focus-visible ring) */
.hub-jump button:focus-visible, .hcard .btn:focus-visible { outline: 3px solid var(--info); outline-offset: 2px; }

/* ── Bids (public/js/views-bids.js; owner, 2026-11-12) ────────────
   The bid board, the bid page (figures, the eight steps, RFQ and RFI logs, review, follow-up) and the Bid data table;
   the request-for-quote dialogs (public/js/rfq.js, also opened from Purchasing); the Vendors pages
   (public/js/views-vendors.js). Nothing here scrolls the page sideways at 375 px: the Bid data table scrolls inside
   its own box. */
.bid-tpl .btn-run, #bidBc .btn-run { justify-content: flex-end; }
details.bid-older { margin-top: 4px; font-size: 14px; }
details.bid-older summary { cursor: pointer; color: var(--steel); min-height: 28px; }
details.bid-older ul { margin: 4px 0 0; padding-left: 18px; }
.bid-links { margin-top: 14px; }
table.bid-data { min-width: 980px; }
table.bid-data td { font-size: 14px; }
table.bid-data td.bid-feedback { min-width: 200px; white-space: normal; overflow-wrap: anywhere; }
table.bid-data tr.needs-action > td { background: var(--tint-signal); }
table.bid-data tr.needs-action > td:first-child { box-shadow: inset 4px 0 0 var(--signal); }
.bid-step { padding: 9px 16px; border-top: 1px solid var(--rule); }
.bid-steps > .bid-step:first-child { border-top: 0; }
.bid-step .check { min-height: 30px; cursor: pointer; }
.bid-step div.check { cursor: default; }
.bid-step .meta { margin-left: 26px; color: var(--steel); font-size: 14px; }
.bid-step.done { background: var(--tint-go); }
.bid-step .bid-who { color: var(--go); font-weight: 600; }
.bid-tick { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 18px; height: 18px; border: 1px solid var(--rule-strong); border-radius: var(--r-sm); background: var(--surface); color: var(--go); font-weight: 700; font-size: 13px; }
.bid-cats { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 8px 0 2px 26px; }
.bid-cat { display: inline-flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.bid-entry { border-top: 1px solid var(--rule); }
.bid-log > .bid-entry:first-child { border-top: 0; }
.bid-entry-head { display: flex; flex-wrap: wrap; gap: 6px 12px; align-items: center; justify-content: space-between; padding: 9px 16px 4px; }
.bid-entry-head > div:first-child { min-width: 0; overflow-wrap: anywhere; }
.bid-entry .bid-scope { padding: 0 16px 6px; color: var(--steel); font-size: 14px; white-space: pre-line; overflow-wrap: anywhere; }
.bid-entry .rows.compact .row { padding-left: 28px; }
.bid-q, .bid-a { margin-top: 4px; font-size: 14px; white-space: pre-line; overflow-wrap: anywhere; }
.bid-a { padding: 4px 8px; border-left: 3px solid var(--go); background: var(--tint-go); }
#bidRfis .row, #bidReview .row, .rfq-send .row, #vendorContacts .row, .bid-tpl { grid-template-columns: minmax(0, 1fr) auto; }
#bidRfis .row .side .btn-run { margin-top: 6px; }
.rfq-items { display: grid; gap: 8px; margin-bottom: 8px; }
.rfq-item { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.rfq-item.short { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.rfq-item input:first-child { grid-column: 1 / -1; }
.rfq-item input, .rfq-vendor-add input { min-width: 0; width: 100%; }
.rfq-vendor-add { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin-top: 8px; }
.rfq-vendor-add button { grid-column: 1 / -1; justify-self: start; }
.rfq-to:empty { display: none; }
.rfq-to .check span { min-width: 0; overflow-wrap: anywhere; }
details.rfq-more { margin-top: 6px; }
details.rfq-more > summary { cursor: pointer; min-height: 32px; color: var(--steel); font-weight: 600; }
.rfq-send { margin: 0 0 12px; border: 1px solid var(--rule); border-radius: var(--r-sm); }
.rfq-send .row .meta { overflow-wrap: anywhere; }
.rfq-entry { margin-top: 12px; border: 1px solid var(--rule); border-radius: var(--r-sm); }
.rfq-entry > .meta { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; justify-content: space-between; padding: 6px 12px; background: var(--hover); border-bottom: 1px solid var(--rule); font-size: 14px; color: var(--steel); }
.rfq-entry .row { grid-template-columns: minmax(0, 1fr); }
.rfq-entry .row .side { text-align: left; }
.rfq-entry .row .side .btn-run { justify-content: flex-start; }
.rfq-copy { display: flex; gap: 8px; align-items: flex-start; }
.rfq-copy input, .rfq-copy textarea { flex: 1; min-width: 0; font-size: 14px; }
.rfq-copy textarea { min-height: 120px; font-family: var(--body); }
.vendor-reach { overflow-wrap: anywhere; }
.vendor-form [data-cats] input[name=catOther] { margin-top: 6px; }
@media (max-width: 600px) {
  dl.bid-facts { grid-template-columns: minmax(0, 1fr); gap: 2px 0; }
  dl.bid-facts dd { margin-bottom: 8px; }
  #bidRfis .row, #bidReview .row, .bid-tpl, #bidBc .row { grid-template-columns: minmax(0, 1fr); }
  #bidRfis .row .side, #bidReview .row .side, .bid-tpl .side, #bidBc .row .side { text-align: left; }
  .bid-tpl .btn-run, #bidBc .btn-run, #bidRfis .row .side .btn-run { justify-content: flex-start; }
  .bid-step .meta, .bid-cats { margin-left: 0; }
  .bid-cats button, .bid-entry button, #bidRfis button, .bid-tpl .btn, .bid-tpl button { min-height: 40px; }
  .bid-entry .rows.compact .row { padding-left: 12px; grid-template-columns: minmax(0, 1fr); }
  .bid-entry .rows.compact .row .side { text-align: left; }
  .bid-links .btn, .bid-links button { width: 100%; justify-content: center; }
  .rfq-copy { flex-direction: column; }
  .rfq-copy input, .rfq-copy textarea { width: 100%; }
  .rfq-send .row, #vendorContacts .row { grid-template-columns: minmax(0, 1fr); }
  .rfq-send .row .side, #vendorContacts .row .side { text-align: left; }
  #vendorContacts .btn-run { justify-content: flex-start; }
  .rfq-send .btn, .rfq-entry button, #vendorContacts button { min-height: 40px; }
  dl.vendor-facts { grid-template-columns: minmax(0, 1fr); gap: 2px 0; }
  dl.vendor-facts dd { margin-bottom: 8px; }
  #vendorList .row { grid-template-columns: minmax(0, 1fr); }
  #vendorList .row .side { text-align: left; }
}

/* Client documents: Download PDF and Print on the client pages (/proposal, /sign), at the top of the document and again
   by the decision / sign buttons. Printing /proposal prints the document only (with the decision once there is one). */
.doc-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 12px; }
.doc-actions .btn, .doc-actions button { min-height: 38px; }
.pr-decide .doc-actions { margin: 12px 0 0; }
@media print {
  .doc-actions { display: none !important; }
  body.client-doc { background: #fff; }
  body.client-doc .sign-head, body.client-doc .sign-foot, body.client-doc .pr-decide, body.client-doc .pr-decided .pr-next { display: none !important; }
  body.client-doc .sign-main { padding: 0; margin: 0; max-width: none; }
  body.client-doc .proposal { border: 0; padding: 0; box-shadow: none; }
}

/* ── Schedule: Year calendar, and today in the Week list (public/js/views-ops.js renderSchedule: yearGrid) ──────
   Twelve small months, Monday to Sunday, four across, two up to 1080px wide, one up to 600px. A day is a link to that
   day: its number, and under it how many jobs are worked that day. A day with work is shaded with the schedule-bar
   colour; one with work waiting on the viewer to assign is shaded light red with a red count (Action required).
   Today's number is gold, as in Month. The month's name is a button that opens Month. In the Week (and Day) list,
   today's box carries the same gold "Today" mark. Palette names only, so dark mode needs nothing of its own. */
.sched-today-tag { display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: var(--r-sm); background: var(--hivis); color: var(--on-hivis);
  font: 700 12px/18px var(--body); vertical-align: 2px; }
.section.sched-today > header { background: var(--tint-hivis-soft); }
#schedList.sched-land { padding-bottom: var(--land, 0px); }   /* room under a short week so today's box can sit at the top (set from JavaScript) */
.ycal { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: -1px 0 0 -1px; }
.ycal-month { min-width: 0; padding: 8px 10px 10px; border-top: 1px solid var(--rule); border-left: 1px solid var(--rule); }
.ycal-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 2px; }
.ycal .ycal-m { min-height: 30px; padding: 2px 6px; margin-left: -6px; border: 0; border-radius: var(--r-sm); background: none; color: var(--ink); font: 600 16px var(--display); }
.ycal .ycal-m:hover { background: var(--hover); color: var(--info); }
.ycal-t { width: 100%; table-layout: fixed; border-collapse: collapse; }
.ycal-t th { padding: 2px 0 3px; text-align: center; font-size: 11px; font-weight: 700; color: var(--steel); }
.ycal-t td { height: 38px; padding: 1px; }   /* blank days keep the height, so the months line up */
.ycal-d { display: flex; flex-direction: column; align-items: center; gap: 1px; height: 36px; padding-top: 2px; border-radius: var(--r-sm); color: var(--ink); text-decoration: none; font-size: 13px; line-height: 1; }
.ycal-d:hover { outline: 1px solid var(--ink); outline-offset: -1px; }
.ycal-d.has { background: var(--bar); }
.ycal-d.act { background: var(--tint-signal); }
.ycal-num { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 18px; padding: 0 2px; border-radius: var(--r-sm); font-variant-numeric: tabular-nums; }
.ycal-d.has .ycal-num { font-weight: 700; }
.ycal-d.today .ycal-num { background: var(--hivis); color: var(--on-hivis); font-weight: 700; }
.ycal-n { font-size: 11px; font-weight: 700; color: var(--steel); font-variant-numeric: tabular-nums; }
.ycal-n.act { color: var(--signal); }
@media (max-width: 1080px) { .ycal { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .ycal { grid-template-columns: minmax(0, 1fr); } .ycal .ycal-m { min-height: 40px; } .ycal-t td { height: 42px; } .ycal-d { height: 40px; font-size: 14px; } }

/* ── Monthly reports (#/reports, #/reports/:id: views-reports.js) ─────────────────
   Summary as one tight grid of figures, empty sections on one "Nothing this month" line, long tables behind
   "Show all", denser tables and safety boxes. Colours only from the variables at the top. */
.rep-hint { margin: -6px 0 12px; }
.rep-sec { margin-bottom: 12px; }
.rep-sec > header { padding: 7px 14px; }
.rep-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); border-bottom: 1px solid var(--rule); }
.rep-cell { padding: 8px 12px; border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); margin-bottom: -1px; min-width: 0; }
.rep-cell .k { font-size: 11px; font-weight: 700; color: var(--steel); text-transform: uppercase; letter-spacing: .05em; }
.rep-cell .v { font: 600 20px/1.15 var(--display); color: var(--ink); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.rep-cell .s { font-size: 12.5px; color: var(--steel); overflow-wrap: anywhere; }
.rep-cell.stop { box-shadow: inset 3px 0 0 var(--signal); }
.rep-cell.wait { box-shadow: inset 3px 0 0 var(--hivis); }
.rep-bad { color: var(--signal); font-weight: 600; }
.rep-notes { display: grid; gap: 4px; padding: 10px 14px; }
.rep-notes label { font-size: 13px; font-weight: 600; color: var(--steel); }
.rep-notes textarea { width: 100%; min-height: 0; }
.rep-none { margin: 0 0 12px; padding: 7px 14px; border: 1px solid var(--rule); background: var(--surface); border-radius: var(--r-md); font-size: 14px; }
.rep-portal { margin: 0 0 10px; }
.rep-unrated { margin: 0; border-width: 1px 0 0; border-radius: 0; }
.rep-showall { padding: 6px 14px 8px; border-top: 1px solid var(--rule); }
.rep-more { display: none !important; }
.report-table th, .report-table td { padding: 5px 8px; }
@media (min-width: 821px) { .report-table input:not([type=checkbox]), .report-table select, .rep-safety input { min-height: 30px; padding: 4px 8px; } }
.report-table th { white-space: nowrap; }
.rep-safety { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 8px 14px; }
.rep-safety .field { margin: 0; }
.rep-safety .field span em { font-style: normal; font-size: 12px; }
.rep-safety .num-in { width: 100%; max-width: 140px; }
.rep-kpis { gap: 8px; margin-bottom: 12px; }
.rep-kpis .kpi { padding: 8px 12px; }
.rep-kpis .kpi .v { font-size: 20px; }
@media (max-width: 760px) {
  .rep-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rep-cell .v { font-size: 18px; }
  .rep-safety { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rep-safety .num-in { max-width: none; }
  .rep-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rep-kpis .kpi { padding: 7px 10px; min-width: 0; }
  .rep-kpis .kpi .v { font-size: 17px; overflow-wrap: anywhere; }
  .rep-kpis .kpi .s { font-size: 12px; }
  .wip-card { padding: 10px 12px; }
  .wip-card .wip-group { display: grid; grid-template-columns: 82px minmax(0, 1fr); gap: 0 8px; padding: 5px 0 3px; }
  .wip-card .wip-group h4 { margin: 3px 0 0; }
  .wip-card .wip-group dl { gap: 2px 10px; }
}
@media print { .rep-showall, .rep-hint { display: none; } .rep-more { display: revert !important; } }

/* ── Report something ─────────────────────────────────────────────────────────
   The crews' short report (public/js/views-field-reports.js): the button on the home page, project and ticket pages
   and More; the dialog's big square choices; Field reports and one report. Colours from the palette only. */
.fr-report-btn { border-color: var(--signal); color: var(--signal); font-weight: 600; }
.fr-report-btn:hover { background: var(--tint-signal); }
.page-head > .fr-report-btn { align-self: flex-start; }
.fr-more-row { width: 100%; text-align: left; }
.fr-more-row .title { color: var(--signal); font-weight: 700; }
.fr-form { max-width: 560px; }
.fr-group { border: 0; margin: 0 0 12px; padding: 0; min-width: 0; }
.fr-group legend { font-weight: 700; font-size: 15px; margin-bottom: 6px; padding: 0; }
.fr-kinds { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.fr-yesno { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.fr-choice { min-height: 52px; padding: 8px 10px; font-size: 16px; font-weight: 600; border: 1px solid var(--rule-strong); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink); white-space: normal; overflow-wrap: anywhere; line-height: 1.2; }
.fr-choice:hover { background: var(--hover); }
.fr-choice[aria-pressed="true"] { background: var(--hivis); border-color: var(--hivis-press); color: var(--on-hivis); }
.fr-choice.fr-yes[aria-pressed="true"] { background: var(--signal-fill); border-color: var(--signal-fill); color: var(--on-strong); }
.fr-private { margin: -4px 0 10px; }
.fr-form textarea { min-height: 96px; }
.fr-sent h3 { margin: 12px 0 4px; font-size: 15px; }
.fr-told { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.fr-told li { padding: 7px 0; border-bottom: 1px solid var(--rule); overflow-wrap: anywhere; }
.fr-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.fr-urgent { margin-left: 4px; }
.fr-hurt-notice { font-size: 16px; }
.fr-yes-text { color: var(--signal); }
.fr-desc { overflow-wrap: anywhere; }
@media (max-width: 600px) {
  .fr-kinds { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .page-head > .fr-report-btn { width: 100%; }
  .fr-sent .actions > * { flex: 1 1 auto; }
}

/* ── Compact pages ────────────────────────────────────────────────────────────
   Owner, 2026-11-12: "compact the pages so there is less scrolling". Tighter spacing on the shared boxes (every page),
   key figures two to a row on a phone, two columns where a page is one long column of short boxes, long lists behind
   "Show all N" (core.js limitRows; the rows are drawn, only hidden). Text stays 12px or more, phone tap targets 40px or
   more, square corners from the radius tokens, colours only from the variables at the top. */
.page-head { margin-bottom: 12px; padding-bottom: 10px; }
.section { margin-bottom: 12px; }
.section > header { padding: 7px 14px; }
.section > .body { padding: 11px 14px; }
.row { padding: 7px 14px; }
.empty { padding: 10px 14px; }
.notice { margin-bottom: 12px; padding: 8px 12px; }
.filters { margin-bottom: 10px; }
.split { gap: 16px; }
.split.esign-split { gap: 20px; }   /* a document beside its form keeps its width: a wider page only draws the PDF taller */
.kpis { gap: 8px; margin-bottom: 12px; }
.kpi { padding: 8px 12px; }
.tiles { gap: 10px; margin-bottom: 12px; }
.tile { padding: 10px 14px; }
.home-cards { gap: 10px; margin-bottom: 12px; }
.hcard { gap: 8px; padding: 10px 12px; }
.hcard-stat { padding: 8px 10px; }
.kpi-cell { padding: 12px 10px; }
.kpi-cell span { margin-bottom: 4px; }
.hub-grid { gap: 0 16px; }
.hub-sub { padding: 7px 14px 0; }
.hub-sub-head { padding: 8px 14px 3px; }
.hub-foot { padding: 6px 14px 8px; }
.hub-nothing { margin: 0 0 12px; }
.hub-jump { margin-bottom: 10px; padding: 6px 0; }
.hub-none > .empty { padding: 8px 14px; }
.account-grid > .section, .account-grid > div > .section { margin-bottom: 12px; }
.hr-none { padding-top: 8px; padding-bottom: 8px; }
/* Long lists: the rows past the first few, until "Show all" is pressed */
.rows:not(.rows-all) > .row-more { display: none !important; }
.show-all { padding: 6px 14px 8px; border-top: 1px solid var(--rule); }
/* Help: the answers' titles are tighter; on a wide screen the groups run in two columns */
.help-item > summary { padding: 8px 14px; min-height: 40px; }
.help-item ol { padding: 0 14px 2px 46px; }
.help-item li { margin: 0 0 6px; }
.help-item .actions { margin: 4px 14px 12px 46px; }
/* Two short boxes side by side on a wide screen (a ticket's details and its client); one box alone takes the width */
.box-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); gap: 0 16px; align-items: start; }
@media (min-width: 1100px) {
  #helpGroups { columns: 2; column-gap: 16px; }
  #helpGroups > .help-group { break-inside: avoid; display: block; }
  #hubHr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; align-items: start; }
  #hubHr > :not(.section) { grid-column: 1 / -1; }
}
@media (max-width: 820px) {
  #view { padding-top: 12px; }
}
@media (max-width: 600px) {
  .section > header { padding: 6px 12px; }
  .section > .body { padding: 10px 12px; }
  .row { padding: 7px 12px; }
  .empty { padding: 9px 12px; }
  .hub-sub, .hub-sub-head, .hub-foot, .show-all { padding-left: 12px; padding-right: 12px; }
  /* Key figures two to a row (an odd last one takes the whole row) */
  .kpis, .kpis.hub-kpis, .kpis.time-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kpis > .kpi:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .kpi { min-width: 0; padding: 7px 10px; }
  .kpi .v { font-size: 20px; overflow-wrap: anywhere; }
  .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kpi-row > .kpi-cell:nth-child(odd) { border-right: 1px solid var(--rule); }
  .kpi-row > .kpi-cell:last-child:nth-child(odd) { grid-column: 1 / -1; border-right: 0; }
  .kpi-cell { padding: 9px 8px; min-width: 0; }
  .kpi-cell b { font-size: 20px; overflow-wrap: anywhere; }
}
/* Search boxes in a row of filters (owner, 2026-11-13: the Schedule's "needs to be bigger, cant read whats inside it"):
   wide enough for the whole placeholder, and they take the room left in the row */
.filters input[type=search] { flex: 1 1 340px; min-width: min(100%, 300px); max-width: 560px; }

/* Profile photos (owner, 2026-11-13: a headshot "used in messaging and communication"): round, the person's initials
   when there is none. public/js/profile-photo.js */
.avatar { display: inline-flex; align-items: center; justify-content: center; flex: none; border-radius: 50%; object-fit: cover; background: var(--strong); color: var(--on-strong); font-weight: 700; line-height: 1; overflow: hidden; }
.avatar-sm { width: 32px; height: 32px; font-size: 12px; }
.avatar-md { width: 36px; height: 36px; font-size: 13px; }
.avatar-lg { width: 64px; height: 64px; font-size: 22px; }
img.avatar { background: var(--paper); border: 1px solid var(--rule); }
.person-title { display: flex; align-items: center; gap: 14px; min-width: 0; }
.person-title h1 { margin: 0; }
/* Messages: the sender's photo beside the bubble */
.msg { display: flex; gap: 10px; align-items: flex-start; white-space: normal; }
.msg .msg-main { min-width: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.msg.mine { flex-direction: row-reverse; }
/* People rows: the photo, then the rest of the row */
.row > .avatar:first-child + div { min-width: 0; }
.row:has(> .avatar:first-child) { grid-template-columns: auto 1fr auto; }
/* The menu: your photo beside your name */
#whoami .whoami-name { display: flex; align-items: center; gap: 10px; }
#whoami .whoami-name strong { display: inline; }
@media (max-width: 700px) {
  .row:has(> .avatar:first-child) { grid-template-columns: auto 1fr; }
  .row:has(> .avatar:first-child) > .side { grid-column: 1 / -1; }
  .avatar-lg { width: 52px; height: 52px; font-size: 18px; }
}

/* Kept on the phone without signal (public/js/outbox.js): a bar at the bottom while anything waits to send */
#outbox-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 60; padding: 8px 16px calc(8px + env(safe-area-inset-bottom)); background: var(--hivis); color: #111; font-size: 14px; box-shadow: 0 -2px 6px rgba(0,0,0,.2); }
#outbox-bar .muted { color: #333; }
@media (max-width: 820px) { #outbox-bar { bottom: calc(60px + env(safe-area-inset-bottom)); padding-bottom: 8px; } }

/* Install the app (public/js/install-app.js): a row on the phone's More page */
.install-row { width: 100%; text-align: left; }
.install-row .title { font-weight: 700; }

/* The photo is its own button (owner, 2026-11-13): click to add or change it; on a computer, hovering shows "Change
   photo"; on a phone a small badge says it can be tapped */
.avatar-edit { position: relative; display: inline-flex; padding: 0; border: 0; background: none; border-radius: 50%; cursor: pointer; flex: none; min-height: 0; }
.avatar-edit:focus-visible { outline: 3px solid var(--hivis); outline-offset: 2px; }
.avatar-edit-label { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; text-align: center; border-radius: 50%;
  background: rgba(0, 0, 0, .62); color: #fff; font-size: 11px; font-weight: 700; line-height: 1.1; padding: 6px; opacity: 0; transition: opacity .15s; }
@media (hover: hover) { .avatar-edit:hover .avatar-edit-label, .avatar-edit:focus-visible .avatar-edit-label { opacity: 1; } }
@media (hover: none) {
  .avatar-edit-label { inset: auto -2px -2px auto; width: 22px; height: 22px; padding: 0; opacity: 1; font-size: 0; background: var(--hivis); border: 2px solid var(--surface); }
  .avatar-edit-label::before { content: '+'; font-size: 15px; color: #111; }
}

/* RFQ lines: the Vendor RFQ template's section on its own line above the description (2026-11-13) */
.rfq-item select[name=i_section] { grid-column: 1 / -1; min-width: 0; width: 100%; }
.rfq-item select[name=i_section] + input { grid-column: 1 / -1; }
