:root {
  --navy: #1f3864;
  --navy-light: #2f5597;
  --bg: #f5f6f8;
  --card-bg: #ffffff;
  --border: #dfe3e8;
  --text: #1c1f24;
  --text-muted: #667085;
  --danger: #b3261e;
  --radius: 8px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
}

.app { max-width: 960px; margin: 0 auto; padding: 24px 20px 64px; }

.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 16px;
}
.app-header-brand { display: flex; flex-direction: column; gap: 4px; }
.app-header .company-logo { height: 40px; width: auto; max-width: 220px; object-fit: contain; }
.app-header .company-logo.admin-editable { cursor: pointer; }
.app-header .company-logo.admin-editable:hover { opacity: 0.85; }

/* ---------- Optek's own app logo -- fixed, code-drawn, not admin-editable
   (unlike the company logo just below it, which is). Shown above the
   company logo everywhere the company logo appears (login screen, signed-in
   header) -- see "Company logo" in README.md for why the two coexist. */
.app-logo { display: flex; align-items: center; gap: 3px; }
.app-logo-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 7px;
  background: linear-gradient(135deg, var(--navy), var(--navy-light));
  color: #fff;
  font-weight: 800;
  font-size: 16px;
  line-height: 1;
}
.app-logo-text { font-weight: 800; font-size: 20px; color: var(--navy); letter-spacing: -0.01em; }
.app-logo-sm { gap: 2px; }
.app-logo-sm .app-logo-badge { width: 17px; height: 17px; border-radius: 5px; font-size: 11px; }
.app-logo-sm .app-logo-text { font-size: 13px; }

.app-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 24px;
}
.app-nav .nav-link {
  display: inline-block;
  padding: 10px 14px;
  font-size: 14px;
  color: var(--text-muted);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.app-nav .nav-link:hover { color: var(--navy); }
.app-nav .nav-link.active {
  color: var(--navy);
  font-weight: 600;
  border-bottom-color: var(--navy);
}

/* ---------- in-page sub-navigation (Finance: General ledger accounts / Equipment) ---------- */
.subnav {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 20px;
}
.subnav-link {
  position: relative;
  display: inline-block;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none;
  background: #eef1f5;
  border-radius: 999px;
  white-space: nowrap;
}
.subnav-link:hover { color: var(--navy); }
.subnav-link.active { color: #fff; background: var(--navy); }

/* Small red alert-count circle in a subnav tab's upper-right corner (e.g.
   Project Management's "Cost Approvals" tab, showing the combined total of
   unapproved time entries + expense costs waiting on this PM) -- hidden
   entirely (via the shared .hidden class) rather than shown as "0" when
   there's nothing pending. */
.nav-alert-badge {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: #c0392b;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

.page { display: none; }
.page.is-active { display: block; }

/* Page-independent modal — currently just the vendor editor (see the
   comment above #vendor-editor-overlay in index.html). Deliberately sits
   outside every .page div so it can be opened from more than one page;
   .hidden (display:none !important) beats the display:flex below whenever
   it's added, so no separate .modal-overlay.hidden rule is needed. */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.45);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 40px 16px;
  overflow-y: auto;
  z-index: 1000;
}
.modal-card { width: 100%; max-width: 900px; margin: 0; }

/* Read-only key/value display -- currently just the Vendor register's
   vendor-information card (the master record fields, above the Edit
   button and the transaction report). Generic enough to reuse for a
   similar "here's the master record" card elsewhere later. */
.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px 24px; margin-top: 12px; }
.detail-item-wide { grid-column: 1 / -1; }
.detail-label { font-size: 12px; color: var(--text-muted); margin-bottom: 3px; }
.detail-value { font-size: 14px; color: var(--text); word-break: break-word; }
.who { display: flex; align-items: center; gap: 10px; }
.who label { font-size: 13px; color: var(--text-muted); }
.whoami { font-size: 14px; color: var(--text); }
.whoami .role-badge {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--navy);
  background: #eef1f5;
  border-radius: 999px;
  padding: 2px 8px;
  margin-left: 6px;
}

/* ---------- login screen ---------- */
.login-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  padding: 20px;
}
.login-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 32px;
  width: 100%;
  max-width: 360px;
}
.login-card .app-logo { margin: 0 0 14px; }
.login-card .app-logo-badge { width: 32px; height: 32px; font-size: 19px; border-radius: 8px; }
.login-card .app-logo-text { font-size: 24px; }
.login-card .company-logo { display: block; height: 56px; width: auto; max-width: 100%; object-fit: contain; margin: 0 0 16px; }
.login-card .muted { color: var(--text-muted); font-size: 13px; margin: 0 0 20px; }
.login-card .muted.small { margin: 16px 0 0; font-size: 12px; }
.login-card .field { margin-bottom: 14px; }
.login-card .actions { justify-content: space-between; }
.login-card button.btn-primary { width: 100%; }

/* ---------- modal ---------- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(20, 24, 30, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
}
/* Scoped to .modal-backdrop specifically -- this is the small centered
   password-change dialog's own card. The page-independent .modal-overlay
   pattern above (vendor editor, task popup) also uses the bare .modal-card
   class at 900px; without this scope, this rule's later position in the
   stylesheet would win at equal specificity and clamp every modal on the
   site to 340px regardless of which pattern it's using. */
.modal-backdrop .modal-card {
  background: var(--card-bg);
  border-radius: 12px;
  padding: 24px;
  width: 100%;
  max-width: 340px;
}
.modal-card h2 { margin: 0 0 14px; font-size: 16px; color: var(--navy); }

#pu-preview { display: block; width: 100%; max-height: 200px; object-fit: contain; border-radius: 8px; background: var(--bg); margin: 0 0 14px; }
#pv-image { display: block; max-width: 100%; max-height: 65vh; margin: 0 auto 12px; border-radius: 8px; }

.card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 20px 24px;
  margin-bottom: 20px;
}
.card h2 { font-size: 16px; margin: 0 0 14px; color: var(--navy); }

/* Splits one card into two visual sections (e.g. a workflow stepper on top,
   its tasks below) without the gap/border of a second stacked .card. */
.section-divider { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--border); }
.section-divider h2:first-child { margin-top: 0; }

/* ---------- stat tiles (Management > Dashboard: Profit & Loss summary) ---------- */
.stat-grid { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 4px; }
.stat-tile {
  flex: 1 1 180px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 18px;
}
.stat-label { font-size: 13px; color: var(--text-muted); margin-bottom: 6px; }
.stat-value { font-size: 26px; font-weight: 600; color: var(--navy); }
.stat-value.positive { color: #1a7f37; }
.stat-value.negative { color: var(--danger); }

.row { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 12px; }
.field { flex: 1; min-width: 160px; display: flex; flex-direction: column; gap: 4px; }
.field.small { flex: 0 0 120px; }
.field.search-field { max-width: 320px; margin-bottom: 12px; }
.field label { font-size: 12px; color: var(--text-muted); }
/* A read-only figure inside a .field, same box shape as its input siblings
   (e.g. the Bid Letter tab's LER, shown next to its editable Gross Margin/
   Bid Amount fields) so they all line up in a row. */
.field .static-value {
  margin: 0;
  padding: 9px 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}

/* A compact, wrapping row of "<label><input type=checkbox> Name</label>"
   pairs -- Cost Types assigned to a Standard Cost Code (in its table row
   and in the "Add a standard cost code" form), where .detail-grid's
   200px-minimum columns are too wide for what's usually just 2-3 short
   names. */
.cost-type-checkboxes { display: flex; flex-wrap: wrap; gap: 4px 14px; }
.cost-type-checkboxes label { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; white-space: nowrap; }
input:not([type="checkbox"]):not([type="radio"]), select, textarea {
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 14px;
  width: 100%;
  background: #fff;
  color: var(--text);
  font-family: inherit;
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--navy-light); outline-offset: 1px; }

/* ---------- Searchable comboboxes (Log time's Project field, Costs' Vendor field) ---------- */
.project-combobox, .vendor-combobox { position: relative; }
.combobox-results {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 20;
  margin-top: 2px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  max-height: 240px;
  overflow-y: auto;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.combobox-result { padding: 8px 10px; font-size: 14px; cursor: pointer; }
.combobox-result:hover, .combobox-result.active { background: #f3f4f6; }
.combobox-empty { padding: 8px 10px; font-size: 13px; color: var(--text-muted); }
/* Checkboxes used inline in a label (e.g. "Active", "Subcontractor" on the
   Vendors/Customers editors) -- excluded from the width:100%/border/padding
   rule above (that's for text-like inputs), sized normally instead. */
input[type="checkbox"], input[type="radio"] { width: auto; margin-right: 4px; }
/* Section headers inside a longer editor card (e.g. Vendors/Customers'
   Payment address / Additional addresses / Notes groupings) -- smaller and
   quieter than the card's own <h2> so the hierarchy stays obvious. */
.card h3 { font-size: 14px; margin: 20px 0 8px; color: var(--text-muted); }

.actions { display: flex; align-items: center; gap: 12px; margin-top: 8px; }
.btn-primary, .btn-secondary, .btn-danger {
  border: none;
  border-radius: var(--radius);
  padding: 9px 16px;
  font-size: 14px;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
}
.btn-primary { background: var(--navy); color: #fff; }
.btn-primary:hover { background: var(--navy-light); }
.btn-secondary { background: #eef1f5; color: var(--navy); border: 1px solid var(--border); }
.btn-secondary:hover { background: #e2e7ee; }
/* Reserved for a genuinely destructive, permanent action (e.g. completely
   deleting a journal entry) -- distinct from .btn-secondary so it doesn't
   look like an equally-safe alternative next to Void/Cancel. */
.btn-danger { background: #fdeceb; color: var(--danger); border: 1px solid #f3c8c4; }
.btn-danger:hover { background: #f9d9d6; }

.message { font-size: 13px; color: var(--text-muted); }
.message.error { color: var(--danger); }
.message.success { color: #1a7f37; }

.card-header-row { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; }
/* Small one-off spacing utilities — kept as classes rather than inline
   `style="..."` attributes so the app's Content-Security-Policy can forbid
   inline styles outright (see server.js) without losing this spacing. */
.mt-8 { margin-top: 8px; }
.mt-12 { margin-top: 12px; }
.filters { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; min-width: 0; max-width: 100%; }
.filters select, .filters input { width: auto; max-width: 100%; min-width: 0; }
.filters label { font-size: 13px; display: flex; align-items: center; gap: 4px; }
.filters-label { font-size: 13px; font-weight: 600; color: var(--text-muted); }
/* Toggle buttons (WIP report's Departments filter) reuse .subnav-link's pill
   look (see "in-page sub-navigation" above) so a selected department reads
   the same way an active subnav tab does, but as a real <button> since more
   than one can be selected at once rather than exactly one. */
button.subnav-link {
  border: none;
  cursor: pointer;
  font: inherit;
}

table { width: 100%; border-collapse: collapse; margin-top: 12px; font-size: 13.5px; }
th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); }
th { color: var(--text-muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; }
tbody tr:hover { background: #fafbfc; }
td.num { text-align: right; }
/* Every table on this app is wrapped in a `.table-scroll` div (see
   index.html) so a wide table (Cost approvals, GL accounts, and so on, most
   with 6+ columns) scrolls sideways in its own contained box on a narrow
   screen, instead of the table forcing the ENTIRE page to scroll
   horizontally along with the header and nav. `table` keeps width: 100%
   above so it still fills the card at desktop widths where everything
   fits; this only kicks in once the table's natural content width exceeds
   the container. -webkit-overflow-scrolling makes that scroll momentum-based
   on iOS instead of the stiff, step-by-step default. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* The Employees record's widest repeatable grids (Dedns/Liabs has ~44
   columns, Employee Leave ~32) -- built entirely from JS column defs (see
   employees.js), so cells need a sane fixed width instead of the usual
   input{width:100%}, or every column would stretch to fill whatever space
   is left and the table would become unreadable rather than just wide. */
.wide-grid-wrap table input,
.wide-grid-wrap table select { width: 90px; min-width: 70px; }
.wide-grid-wrap table input[type="checkbox"] { width: auto; min-width: 0; }
.wide-grid-wrap th, .wide-grid-wrap td { white-space: nowrap; padding: 4px 6px; }
.wide-grid-wrap td:last-child, .wide-grid-wrap th:last-child { white-space: normal; }
/* Project/GL/etc codes are short but were wrapping mid-code (e.g. "24-" /
   "007") once other columns started competing for space — codes read as a
   single token, so never let them break across lines. */
td.code-cell { white-space: nowrap; }
button.link-btn { background: none; border: none; color: var(--danger); cursor: pointer; font-size: 13px; padding: 0; }

/* ---------- "record" links (project/vendor/GL account code+name cells that
   navigate elsewhere in the app -- Projects, WIP report, Vendors, Open AP,
   GL accounts) ---------- */
/* A plain <a href="#/..."> here is a real link the browser tracks as
   visited, so left unstyled it comes out as the ordinary blue/underlined
   link that turns purple once clicked -- not the look we want for what's
   really an in-app navigation action. Styled instead as a small button: a
   pill, no underline, no color change once visited, a hover state matching
   the app's other pill controls (.subnav-link/.dept-toggle below). */
a.record-link,
a.record-link:visited {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 6px;
  background: #eef1f5;
  color: var(--navy);
  text-decoration: none;
  font-weight: 600;
  font-size: 13px;
  line-height: 1.3;
}
a.record-link:hover {
  background: var(--navy);
  color: #fff;
}

/* ---------- click-to-edit table cells (Manage projects: Name/Client) ---------- */
.editable-cell {
  cursor: pointer;
  border-bottom: 1px dashed transparent;
}
.editable-cell:hover {
  background: #f3f6fb;
  border-bottom-color: var(--navy-light);
}
.editable-cell-input {
  width: 100%;
  font: inherit;
  padding: 3px 5px;
  border: 1px solid var(--navy-light);
  border-radius: 4px;
  background: #fff;
}

/* ---------- Work In Progress report (Project Management > WIP) ---------- */
#wip-table tr.wip-department-row td {
  background: #eef1f6;
  font-weight: 700;
  color: var(--navy);
  border-bottom: 1px solid var(--border);
}
#wip-table tr.wip-subtotal-row td {
  font-weight: 600;
  border-top: 1px solid var(--border);
  border-bottom: 2px solid var(--border);
}
#wip-table tr.wip-grand-total-row td {
  font-weight: 700;
  background: #eef1f6;
  border-top: 2px solid var(--navy);
}
/* Flags a project with no cost budget estimated yet on Cost Budgets --
   without one, % Comp/Earned To Date/Billings Over-Under for that row are
   all meaningless zeros rather than a real 0% complete, so this is worth
   catching at a glance rather than reading as "just started." */
#wip-table td.wip-zero-estimate {
  color: var(--danger);
  background: #fbeae9;
  font-weight: 600;
}

/* ---------- Generic cost-type-grouped report rows -- the Project cost
   report and the Vendor register's Transactions report both group their
   rows by Cost Type with a subtotal per group and a grand total at the
   end (see costTypeGroupedTableHtml in public/expenses.js), same visual
   language as the WIP report's department groups above, just under
   report-scoped class names since more than one table uses these. ---------- */
tr.report-group-row td {
  background: #eef1f6;
  font-weight: 700;
  color: var(--navy);
  border-bottom: 1px solid var(--border);
}
tr.report-subtotal-row td {
  font-weight: 600;
  border-top: 1px solid var(--border);
  border-bottom: 2px solid var(--border);
}
tr.report-grand-total-row td {
  font-weight: 700;
  background: #eef1f6;
  border-top: 2px solid var(--navy);
}

/* A cost's dollar amount, styled and behaving like a link, that opens the
   shared "Edit cost" modal (#glr-review-overlay) for that specific row --
   used on the Project cost report and Vendor register Transactions report,
   in place of a separate "Edit" column, so re-coding a cost (cost type,
   project, cost code, GL account, or amount) is one click from the number
   itself. Navy rather than .link-btn's default danger-red, since this is a
   non-destructive inline action (same convention as .pd-edit-link above). */
button.amount-edit-link {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-weight: inherit;
  color: var(--navy);
  cursor: pointer;
  border-bottom: 1px dashed var(--navy-light);
}
button.amount-edit-link:hover {
  border-bottom-style: solid;
}

/* ---------- "Permanently delete" danger zone (the edit-cost modal,
   #glr-review) — visually set apart from the ordinary Save/Close actions
   above it, so a destructive, no-audit-trail action never reads as just
   another button in the same row. ---------- */
.danger-zone {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px dashed #f3c8c4;
}
.danger-zone-confirm {
  margin-top: 18px;
  padding: 12px 14px;
  border: 1px solid #f3c8c4;
  border-radius: 8px;
  background: #fdeceb;
}
.danger-zone-confirm .message {
  color: var(--danger);
  margin: 0 0 10px;
}
.danger-zone-confirm .actions { margin-top: 10px; }
/* Solid dark divider after "To Date Billings" -- the last of the "input"
   columns (Contract Amount through To Date Billings, one hand-entered),
   separating them from "Billings Over"/"Billings Under", the two computed
   flag columns that follow. Deliberately heavier/darker than the thin gray
   row borders elsewhere in the table, since it's marking a column boundary
   rather than a row boundary. */
#wip-table th.wip-billings-boundary,
#wip-table td.wip-billings-boundary {
  border-right: 2px solid #000;
}
/* Billings Under highlights red once it's a serious shortfall -- more than
   half the contract amount, or more than $10,000, whichever check catches
   it first (a small contract can trip the dollar threshold well under 50%,
   and a large one can pass $10k long before it's really concerning, so
   either condition alone is enough to flag it). */
#wip-table td.wip-under-flag {
  color: var(--danger);
  background: #fbeae9;
  font-weight: 600;
}
/* Billings Over highlights yellow once it's more than half the contract
   amount -- billed well ahead of what's actually been earned so far. */
#wip-table td.wip-over-flag {
  color: #7a5c00;
  background: #fff3cd;
  font-weight: 600;
}

.empty { color: var(--text-muted); font-size: 14px; margin-top: 12px; }
.muted-note { color: var(--text-muted); font-size: 13px; margin: 0 0 12px; }
.muted-note strong { color: var(--text); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.hidden { display: none !important; }

details { margin-top: 10px; }
summary { cursor: pointer; font-size: 14px; color: var(--navy); margin-bottom: 10px; }
details form { margin-top: 12px; }

/* ---------- onboarding ---------- */
.role-badge.hr-badge { background: #fdecc8; color: #7a5200; margin-left: 4px; }
.role-badge.pm-badge { background: #dceefb; color: #0b5a86; margin-left: 4px; }
.role-badge.foreman-badge { background: #dcf3e3; color: #12693b; margin-left: 4px; }

/* ---------- status badges (Costs: pending approval / approved) ---------- */
.status-badge {
  display: inline-block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  border-radius: 999px;
  padding: 2px 8px;
}
.status-badge.status-pending { background: #fdecc8; color: #7a5200; }
.status-badge.status-approved { background: #dcf3e3; color: #12693b; }
/* ---------- bid status (Project Management > Bidding) ---------- */
.status-badge.status-draft { background: #eef1f5; color: var(--navy); }
.status-badge.status-submitted { background: #dceefb; color: #0b5a86; }
.status-badge.status-won { background: #dcf3e3; color: #12693b; }
.status-badge.status-lost { background: #fbdede; color: #8a1f1f; }
/* ---------- vendor-not-on-file flag (Cost approvals) ---------- */
.status-badge.status-flagged { background: #fbe4d5; color: #8a4a12; margin-left: 6px; }
/* ---------- voided journal entry (Finance > Journal entries) ---------- */
.status-badge.status-voided { background: #eef1f5; color: var(--text-muted); margin-left: 6px; }

/* ---------- attachment icon (Costs / Cost approvals / GL register rows) ---------- */
.attachment-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 6px;
  color: var(--navy);
  text-decoration: none;
}
.attachment-icon:hover { background: #eef1f6; }
.attachment-icon svg { width: 16px; height: 16px; }

.checklist { list-style: none; margin: 0; padding: 0; }
.checklist-item { display: flex; align-items: center; gap: 8px; padding: 6px 0; font-size: 14px; color: var(--text-muted); border-bottom: 1px solid var(--border); }
.checklist-item:last-child { border-bottom: none; }
.checklist-item.done { color: var(--text); }
.checklist-icon { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: 50%; border: 1px solid var(--border); font-size: 12px; }
.checklist-item.done .checklist-icon { background: #1a7f37; color: #fff; border-color: #1a7f37; }

.onboarding-form { max-width: 640px; }
.reveal-row { margin-top: 2px; }
.reveal-row .link-btn { color: var(--navy); font-size: 12px; }

/* Project homepage's inline "Edit"/"Add address" affordances (see pd-address
   in projects.js) — reuse .link-btn's button reset but in the neutral navy
   used for non-destructive inline actions elsewhere, not .link-btn's default
   danger-red (meant for Delete buttons). */
.pd-edit-link { color: var(--navy); font-size: 12px; margin-left: 6px; }
.pd-pm-select { display: inline-block; width: auto; margin-left: 6px; }
.onboarding-form input:disabled,
.onboarding-form select:disabled,
.onboarding-form textarea:disabled {
  background: #f3f4f6;
  color: var(--text);
  opacity: 1;
  cursor: default;
}

/* ---------- Onboarding — locked section + "request a change" ---------- */
.request-change-block { max-width: 640px; margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--border); }
.request-change-block .locked-note { margin-bottom: 8px; }
.request-change-form { margin-top: 8px; }
.request-change-pending { margin: 0; font-style: italic; }

.disclaimer {
  background: #fff7e6;
  border: 1px solid #f0d385;
  border-radius: var(--radius);
  padding: 10px 14px;
  font-size: 13px;
  color: #6b4d00;
  margin: 0 0 14px;
}
.disclaimer a { color: #6b4d00; }

.dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  padding: 24px;
  text-align: center;
  margin: 12px 0;
  transition: border-color 0.15s, background 0.15s;
}
.dropzone.dragover { border-color: var(--navy-light); background: #eef3fb; }
.dropzone p { margin: 0 0 12px; color: var(--text-muted); font-size: 14px; }
.dropzone-actions { display: flex; justify-content: center; gap: 10px; }

#hr-detail-body h3 { font-size: 14px; color: var(--navy); margin: 18px 0 8px; }
#hr-detail-body h3:first-child { margin-top: 0; }
#hr-detail-body .row { margin-bottom: 6px; }
#hr-detail-body .field label { margin-bottom: 0; }

/* ---------- my schedule calendar (Home) ----------
   A continuously-scrollable list of Sun-Sat weeks (see createWeekCalendar()
   in public/app.js), not a paged month grid: .schedule-calendar is a
   fixed-height, natively-scrollable viewport so an ordinary mouse-wheel/
   trackpad scroll over it moves seamlessly from week to week and across
   month boundaries -- no custom wheel handling, the browser's own scrolling
   does it. .calendar-weekday-row and .calendar-scroll-body are both direct
   children of that scrolling element (required for position:sticky to
   pin the weekday header against ITS scrolling, not the page's). */
.schedule-calendar {
  margin-top: 10px;
  height: 420px;
  overflow-y: auto;
  overflow-x: hidden;
  position: relative;
  border: 1px solid var(--border);
  border-radius: 6px;
}
.calendar-weekday-row {
  position: sticky;
  top: 0;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 5px;
  background: #fff;
  border-bottom: 1px solid var(--border);
}
.calendar-scroll-body { padding: 5px; }
.calendar-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; margin-bottom: 5px; }
.calendar-head {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  text-align: center;
  padding: 4px 0 6px;
}
.calendar-cell {
  min-height: 76px;
  max-height: 150px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 5px;
  background: #fff;
}
/* The week containing today, highlighted so "defaults to the current week
   in the middle" (see boot()'s call into createWeekCalendar()) is
   obviously the current week once it's centered, not just coincidentally
   in the middle of the viewport. */
.calendar-cell.today { border-color: var(--navy); box-shadow: inset 0 0 0 1px var(--navy); }
.calendar-cell.today .cal-daynum { color: var(--navy); font-weight: 700; }
.cal-daynum { font-size: 11px; color: var(--text-muted); margin-bottom: 4px; }
.cal-entry {
  background: #eef3fb;
  color: var(--navy);
  border-radius: 4px;
  padding: 2px 5px;
  margin-bottom: 3px;
  font-size: 11px;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- PM schedule calendar (Schedule tab) ---------- */
.schedule-toggle-row { margin-bottom: 8px; }
/* Today button, sitting in its own row directly above the calendar --
   .card-header-row's default space-between would just left-align a lone
   child, so this overrides to push it to the far right instead. */
.schedule-today-row { justify-content: flex-end; }
.schedule-toggle-hint { font-size: 12px; color: var(--text-muted); }
.schedule-toggle-actions { display: inline-flex; gap: 10px; }
.schedule-employee-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  align-items: center;
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.employee-toggle-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: var(--text);
  cursor: pointer;
  user-select: none;
}
.employee-toggle-chip input[type="checkbox"] { margin: 0; }
.employee-toggle-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  display: inline-block;
  flex: none;
}
.schedule-calendar-pm { height: 520px; }
.schedule-calendar-pm .calendar-cell {
  min-height: 92px;
  max-height: 170px;
  overflow-y: auto;
}
.cal-entry-pm {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
  border-left: 3px solid transparent;
  padding-left: 4px;
}
.cal-entry-pm .cal-entry-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Click-to-open affordance for the task popup (public/projects.js) — an
   entry or an open day cell, whenever the viewer isn't a read-only "user"-
   role account (see canManageSchedule() in public/planning.js). */
.cal-entry-pm.clickable { cursor: pointer; }
.cal-entry-pm.clickable:hover { background: #e3ebf8; }
.calendar-cell.clickable { cursor: pointer; }
.calendar-cell.clickable:hover { background: #f7f9fc; }

/* ---------- project stage badges (Projects list) ---------- */
.stage-badge {
  display: inline-block;
  padding: 3px 11px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  /* Fallback for a custom/renamed workflow step that has no dedicated
     color rule below — still readable, just neutral. */
  background: #eef1f5;
  color: #51586b;
}
.stage-planning { background: #eef1f5; color: #51586b; }
.stage-permitting { background: #fdecc8; color: #7a5200; }
.stage-procurement { background: #dceefb; color: #0b5a86; }
.stage-construction { background: #dbe7ff; color: #1f3864; }
.stage-punch-list { background: #f0e3fb; color: #5b2a86; }
.stage-closeout { background: #d9f2ea; color: #0d6b4f; }
.stage-complete { background: #d9f5db; color: #1a7f37; }

/* ---------- project detail — workflow stepper ---------- */
.workflow-stepper { display: flex; margin: 28px 0 8px; }
.workflow-step { flex: 1; text-align: center; position: relative; }
.workflow-step.clickable { cursor: pointer; }
.workflow-step .dot {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 8px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-muted);
  position: relative;
  z-index: 1;
}
.workflow-step .label { font-size: 12px; color: var(--text-muted); padding: 0 4px; }
.workflow-step::before {
  content: "";
  position: absolute;
  top: 14px;
  left: -50%;
  width: 100%;
  height: 2px;
  background: var(--border);
  z-index: 0;
}
.workflow-step:first-child::before { display: none; }
.workflow-step.reached::before { background: #1a7f37; }
.workflow-step.done .dot { background: #1a7f37; border-color: #1a7f37; color: #fff; }
.workflow-step.current .dot { background: var(--navy); border-color: var(--navy); color: #fff; }
.workflow-step.current .label { color: var(--navy); font-weight: 600; }
.workflow-step.clickable:hover .dot { border-color: var(--navy-light); }

/* ---------- Project Admin — per-project workflow step checklist ---------- */
.checklist-inline { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 4px; }
.checklist-inline .checklist-item { display: flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 400; }

/* ---------- Project detail — tasks under each workflow step ---------- */
.workflow-step-tasks-block { margin-bottom: 24px; }
.workflow-step-tasks-block:last-child { margin-bottom: 0; }
.workflow-step-tasks-block h3 { margin: 0 0 8px; font-size: 15px; }

.task-card { border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; margin-bottom: 10px; }
.task-card-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.task-done-label { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.task-done-label strong.done { color: var(--text-muted); text-decoration: line-through; }
.task-card-actions { display: flex; gap: 10px; flex-shrink: 0; }
.task-card-meta { margin-top: 6px; }

.task-checklist-block { margin-top: 10px; }
.task-checklist { list-style: none; margin: 0 0 6px; padding: 0; }
.task-checklist-item { display: flex; align-items: center; gap: 8px; padding: 4px 0; }
.task-checklist-item span.done { color: var(--text-muted); text-decoration: line-through; }
.task-checklist-text { flex: 1; border: 1px solid transparent; background: transparent; font-size: 14px; padding: 2px 4px; border-radius: 4px; }
.task-checklist-text:hover, .task-checklist-text:focus { border-color: var(--border); background: #fff; }
.task-checklist-add-form { display: flex; gap: 8px; margin-top: 4px; }
.task-checklist-new-text { flex: 1; }

/* ---------- Project detail — photo album ---------- */
.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.photo-grid-item {
  cursor: pointer;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  background: #fff;
  text-align: left;
  padding: 0;
  font: inherit;
}
.photo-grid-item:hover { border-color: var(--navy-light); }
.photo-grid-item img { display: block; width: 100%; height: 110px; object-fit: cover; background: var(--bg); }
.photo-grid-item .photo-caption { padding: 6px 8px; }
.photo-grid-item .photo-name {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.photo-grid-item .photo-meta { display: block; font-size: 11px; color: var(--text-muted); margin-top: 2px; }

/* ---------- Costs (Home) ---------- */
.receipt-review {
  margin-top: 16px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: #fafbfc;
}
.receipt-review-body { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }
.receipt-thumb {
  width: 140px;
  height: 140px;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: #fff;
  flex: none;
}
.receipt-review-fields { flex: 1 1 320px; min-width: 260px; }
.receipt-review-fields .message { display: block; margin-bottom: 10px; }
/* Read-only stand-in for a field value, used where a review panel shows
   the submitted data without letting it be edited (e.g. a Project
   Manager's Expense Approvals review, which can only approve or leave a
   cost alone -- correcting it is Finance's job). */
.static-field {
  margin: 0;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: #fafbfc;
  min-height: 1.2em;
}
.receipt-drafts-list {
  list-style: none;
  margin: 8px 0 16px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.receipt-drafts-list li { font-size: 13.5px; }
#receipts-table td.num { text-align: right; }

/* Change history -- Contracts (Schedule of Values) and Cost Budgets, each
   save's required change note listed newest first alongside who made it
   and when. Same plain, unstyled-list-turned-flex-column approach as
   .receipt-drafts-list above rather than a new table. */
.change-history-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.change-history-list li {
  font-size: 13.5px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.change-history-list li:last-child { border-bottom: none; padding-bottom: 0; }
.change-history-list .change-log-meta {
  display: block;
  color: var(--text-muted);
  font-size: 12px;
  margin-bottom: 2px;
}

/* Journal entries — Finance page: the editor's running debit/credit totals
   and balanced/out-of-balance indicator (see public/journal.js
   recalculateJeTotals()). */
#je-lines-table td.num,
#je-lines-table input[type="number"] { text-align: right; }
.je-totals {
  display: flex;
  gap: 20px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 10px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: #fafbfc;
  font-size: 13.5px;
}
.je-balance-indicator { font-weight: 600; padding: 2px 10px; border-radius: 999px; }
.je-balance-indicator.balanced { color: #1a7f37; background: #e6f4ea; }
.je-balance-indicator.unbalanced { color: var(--danger); background: #fdeceb; }

/* ===================================================================
   Mobile (narrow screens) — everything above this point already degrades
   reasonably on its own (forms/cards stack via flex-wrap, tables scroll in
   their own .table-scroll box, nav wraps instead of hiding tabs off-screen)
   without needing a breakpoint. This is the one thing that genuinely needs
   one: iOS Safari auto-zooms the whole page in when a focused text
   input/select is under 16px, which reads as broken/janky on a phone even
   though nothing is actually wrong. Scoped to narrow screens rather than
   raised globally so the desktop layout stays at the density it was
   already tuned for.
   =================================================================== */
@media (max-width: 640px) {
  input, select, textarea, .editable-cell-input {
    font-size: 16px;
  }
}

/* ---------- Bidding: bid letter preview (Project Management > Bidding) ---------- */
#bid-letter-preview-wrap { margin-top: 16px; }
#bid-letter-preview {
  width: 100%;
  height: 800px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
}

/* ---------- Bidding: Cost Estimate tab draft grid ---------- */
/* Same "fixed-width input" convention as .line-qty/.line-unit-cost/
   .line-hours (set inline in public/bidding.js) -- the Cost Code column
   just needs a bit more room for "CODE — Name". */
.line-cost-code { width: 160px; }
/* A row a Save attempt flagged as missing its Cost Code -- cleared on the
   next full re-render (public/bidding.js's renderBidEstimateRows()). */
#bid-lines-table tr.row-error { background: #fbdede; }

/* ---------- Project Financials: change-order ledger ---------- */
/* Reuses the generic table/.table-scroll styling everywhere else in this
   app uses -- just a touch of breathing room above the "Add" row. */
#co-new-form { margin-bottom: 12px; }

/* ---------- Project documents (plans & specifications) ---------- */
/* See public/documents.js -- a popup opened straight from Project detail's
   "Documents" button, not a page. #pdoc-connect-banner is a plain callout,
   not a .card -- it lives inside the popup's own modal-card. */
#pdoc-connect-banner {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 16px;
  margin: 8px 0 16px;
}
#pdoc-connect-banner p { margin: 0 0 10px; }

/* The live SharePoint folder browser -- folders and files, one per row.
   Deliberately its own class (not .checklist) since these rows aren't a
   done/not-done checklist. */
.pdoc-browse-list { list-style: none; margin: 10px 0 0; padding: 0; max-height: 420px; overflow-y: auto; }
.pdoc-browse-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 4px;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
}
.pdoc-browse-item:last-child { border-bottom: none; }
.pdoc-browse-item .pdoc-browse-name { display: flex; align-items: center; gap: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pdoc-browse-item.is-folder .pdoc-browse-name { cursor: pointer; color: var(--navy); }
.pdoc-browse-item.is-folder .pdoc-browse-name:hover { text-decoration: underline; }
.pdoc-crumb { cursor: pointer; color: var(--navy); }
.pdoc-crumb:hover { text-decoration: underline; }

#pdoc-preview-frame { display: block; width: 100%; height: 72vh; border: 0; border-radius: 8px; background: var(--bg); }
.modal-card-large { max-width: 1100px; }
