/* Admin-specific styles. Layered on top of shared.css. */

/* ──────────────────────────────────────────────────────────────
   Demo Mode — toggle button (in header) + persistent banner
   The toggle is a small pill-style switch sized to sit next to
   the Sign Out button without dominating the header. The banner
   is a thin amber strip that appears below the header whenever
   body.is-demo-mode is set; it's the user's "you're still in
   demo mode" reminder.
─────────────────────────────────────────────────────────────── */
.demo-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgba(232,224,208,.08);
  border: 1px solid rgba(232,224,208,.22);
  border-radius: 999px;
  padding: 5px 12px 5px 8px;
  color: rgba(232,224,208,.75);
  font: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.demo-toggle:hover {
  background: rgba(232,224,208,.14);
  border-color: rgba(232,224,208,.35);
  color: var(--beige);
}
.demo-toggle-knob {
  width: 22px;
  height: 12px;
  background: rgba(232,224,208,.25);
  border-radius: 999px;
  position: relative;
  transition: background .18s;
  flex-shrink: 0;
}
.demo-toggle-knob::after {
  content: "";
  position: absolute;
  top: 1px;
  left: 1px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #fff;
  transition: transform .18s;
}
/* On-state — knob slides right, fill goes amber so the toggle's
   active state is visible at a glance from across the room
   (the whole point of demo mode). */
.demo-toggle.is-on {
  background: rgba(220,150,30,.18);
  border-color: rgba(220,150,30,.55);
  color: #f4c97b;
}
.demo-toggle.is-on .demo-toggle-knob { background: #d89630; }
.demo-toggle.is-on .demo-toggle-knob::after { transform: translateX(10px); }

/* Phone tweaks — keep the toggle visible but a touch tighter so
   it doesn't crowd Sign Out. */
@media (max-width: 720px) {
  .demo-toggle { padding: 4px 10px 4px 6px; gap: 6px; font-size: 9px; }
  .demo-toggle-knob { width: 18px; height: 10px; }
  .demo-toggle-knob::after { width: 8px; height: 8px; }
  .demo-toggle.is-on .demo-toggle-knob::after { transform: translateX(8px); }
}


/* ── Centered "lock" card (login + first-run setup) ───────── */
.lock-screen {
  flex: 1; display: flex; align-items: center; justify-content: center;
  padding: 48px 36px;
}
/* On phones the outer padding crowds the card against the edge of the
   viewport, and the card's 380px max-width is already narrow enough
   that we don't need extra margin. Tighten padding so more vertical
   space goes to the card itself. */
@media (max-width: 720px) {
  .lock-screen { padding: 24px 16px; }
}
@media (max-width: 460px) {
  .lock-screen { padding: 18px 10px; align-items: flex-start; padding-top: 32px; }
  .lock-card { max-width: 100%; }
  .lock-body { padding: 18px 16px 16px; }
}
.lock-card {
  width: 100%; max-width: 380px;
  background: #fff; border-radius: 6px;
  box-shadow: 0 8px 32px rgba(0,0,0,.18), 0 2px 8px rgba(0,0,0,.08);
  overflow: hidden;
}
.lock-head {
  background: var(--navy); color: var(--white);
  padding: 16px 20px;
}
.lock-head-title {
  font-size: 12px; font-weight: 700; letter-spacing: 2px; text-transform: uppercase;
}
.lock-head-sub {
  font-size: 10px; font-weight: 500; letter-spacing: 1.5px;
  color: rgba(232,224,208,.55); text-transform: uppercase; margin-top: 4px;
}
.lock-body {
  padding: 22px 20px 20px;
}
.lock-body .field-group { margin-bottom: 14px; }
.lock-body .text-input  { font-size: 13px; padding: 10px 12px; }
.lock-actions {
  display: flex; justify-content: flex-end; gap: 8px; margin-top: 6px;
}
.lock-msg {
  font-size: 10.5px; line-height: 1.55;
  color: rgba(26,46,61,.55); margin-bottom: 14px;
}
.lock-msg.error { color: #a93226; }

/* Google sign-in button — official-style: white background, dark
   text, brand-color G mark on the left. Sized to match the lock
   card's primary action. */
.btn-google {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: #fff;
  border: 1px solid rgba(26,46,61,.18);
  border-radius: 4px;
  padding: 10px 16px 10px 14px;
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .2px;
  color: #3c4043;
  cursor: pointer;
  transition: background .12s, border-color .12s, box-shadow .12s, transform .1s;
  width: 100%;
  justify-content: center;
}
.btn-google:hover {
  background: #f8f9fa;
  border-color: rgba(26,46,61,.3);
  box-shadow: 0 1px 3px rgba(0,0,0,.08);
}
.btn-google:active { transform: scale(.99); }
.btn-google svg { flex: 0 0 auto; }

/* ── Dashboard ────────────────────────────────────────────── */
.dash-toolbar {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 18px; gap: 12px;
}
.dash-actions {
  display: flex; align-items: center; gap: 10px;
}
.dash-sort-label {
  font-size: 9.5px; font-weight: 700; letter-spacing: 1.5px;
  text-transform: uppercase; color: rgba(26,46,61,.5);
}
.dash-sort-select {
  width: auto; padding: 5px 9px; font-size: 11px;
}
.dash-title {
  font-size: 11px; font-weight: 700; letter-spacing: 3px;
  text-transform: uppercase; color: rgba(26,46,61,.55);
}

/* Projects-tab summary strip — four short cards in a single row
   that spans the full width of the projects list. Each card has
   the dollar amount + small uppercase label on ONE line so the
   strip stays compact ("$2,945.00 OUTSTANDING"). Cards share the
   row equally via flex:1; hidden cards collapse and the remaining
   ones grow to fill. Whole row hides when all four are zero. */
.prj-stats-row {
  display: grid;
  /* 4 wide on desktop; auto-fits down to 2 / 1 on narrow viewports
     so the labels never collapse letter-by-letter the way they did
     in the previous fixed-flex layout. */
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 8px;
  margin: -4px 0 16px;
}
.prj-stat-card {
  min-width: 0;
  background: #fff;
  border: 1px solid rgba(26,46,61,.09);
  border-radius: 5px;
  padding: 6px 12px;
  box-shadow: 0 1px 2px rgba(26,46,61,.04);
  display: flex;
  flex-direction: row;
  align-items: baseline;
  gap: 7px;
  /* Don't ever wrap the dollar amount or the label across lines —
     the card just truncates instead of producing the vertical
     letter-stack the old layout was prone to on phones. */
  white-space: nowrap;
  overflow: hidden;
}
.prj-stat-card-value, .prj-stat-card-label {
  overflow: hidden;
  text-overflow: ellipsis;
}
.prj-stat-card-value {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: -.1px;
  line-height: 1.2;
}
.prj-stat-card-label {
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: rgba(26,46,61,.5);
}
.prj-stat-card.is-incoming    .prj-stat-card-value { color: #1d6f49; }
.prj-stat-card.is-tracked     .prj-stat-card-value { color: #1f5d99; }
.prj-stat-card.is-outstanding .prj-stat-card-value { color: #b03a2a; }
.prj-stat-card.is-paid        .prj-stat-card-value { color: rgba(26,46,61,.75); }
.job-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
}
.job-card {
  background: #fff; border-radius: 5px; overflow: hidden;
  box-shadow: 0 1px 4px rgba(0,0,0,.07), 0 4px 16px rgba(0,0,0,.04);
  display: flex; flex-direction: column;
}
.job-card-head {
  background: var(--navy); color: var(--beige); padding: 11px 14px;
  position: relative;
  cursor: pointer;       /* hint: double-click opens color picker */
  user-select: none;
}

/* Hidden color input behind the header. Activated by JS on dblclick of
   the header (input.click() opens the native picker). */
.card-color-input {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0;
  pointer-events: none;
  border: 0; padding: 0;
}
.job-card-client {
  font-size: 9px; font-weight: 700; letter-spacing: 2px;
  color: rgba(232,224,208,.55); text-transform: uppercase;
}
.job-card-project {
  font-size: 13px; font-weight: 600; margin-top: 2px;
  color: #fff; line-height: 1.3;
}
.job-card-range {
  font-size: 10px; letter-spacing: .3px;
  margin-top: 6px;
  color: rgba(232,224,208,.7);
}
/* Copy-link icon button in the colored card header. Sits above the
   card-color-input via z-index so the click reaches it. */
.job-card-link {
  position: absolute;
  top: 8px; right: 8px;
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.12);
  border: none;
  border-radius: 3px;
  font-size: 12px; line-height: 1;
  color: inherit;
  opacity: .65;
  cursor: pointer;
  z-index: 2;
  transition: background .12s, opacity .12s;
}
.job-card-link:hover {
  background: rgba(255,255,255,.24);
  opacity: 1;
}
.job-card-body {
  padding: 11px 14px; flex: 1;
  display: flex; flex-direction: column; gap: 5px;
  font-size: 11px; color: rgba(26,46,61,.7);
}
.job-card-created {
  font-size: 10px; color: rgba(26,46,61,.5); letter-spacing: .3px;
}
.job-card-url {
  font-family: "SF Mono","Fira Code",monospace; font-size: 10px;
  color: rgba(26,46,61,.55); word-break: break-all; line-height: 1.4;
}
.job-card-foot {
  padding: 10px 14px; border-top: 1px solid rgba(26,46,61,.07);
  display: flex; gap: 6px; align-items: center;
  justify-content: space-between;
}
.job-card-foot-actions {
  display: flex; gap: 6px; align-items: center;
}
.job-card-foot .btn-ghost { padding: 4px 10px; font-size: 9px; }

/* Small red-outline Delete button in bottom-left of each job card */
.btn-card-del {
  background: none;
  border: 1px solid rgba(169,50,38,.4);
  border-radius: 3px;
  padding: 4px 10px;
  font-family: var(--font);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .5px;
  text-transform: uppercase;
  color: #a93226;
  cursor: pointer;
  transition: all .12s;
}
.btn-card-del:hover {
  background: rgba(169,50,38,.07);
  border-color: rgba(169,50,38,.65);
}
.btn-card-del:active { transform: scale(.95); }

.empty-state {
  background: #fff; padding: 36px 24px; border-radius: 5px;
  text-align: center; color: rgba(26,46,61,.55);
  box-shadow: 0 1px 4px rgba(0,0,0,.05);
}
.empty-state .field-label { margin-bottom: 12px; }

/* ── Job setup form ───────────────────────────────────────── */
.setup-shell {
  background: #fff; border-radius: 6px; overflow: hidden;
  box-shadow: 0 1px 4px rgba(0,0,0,.07), 0 4px 16px rgba(0,0,0,.05);
}
.setup-head {
  background: var(--navy); color: var(--beige);
  padding: 14px 22px;
  display: flex; align-items: center; justify-content: space-between;
}
.setup-head-title {
  font-size: 11px; font-weight: 700; letter-spacing: 2.5px; text-transform: uppercase;
}
.setup-body { padding: 22px 22px 8px; }

/* Sections: let whitespace divide. The top-border line was doing
   double duty with the section-title's trailing rule and felt
   striped on tall forms. Whitespace alone reads as "new section"
   when the section-title is strong enough — see the title style
   bumped below. */
.section-block {
  padding-top: 32px;
  margin-top: 32px;
}
.section-block:first-child { padding-top: 0; margin-top: 0; }
#view-project-form .section-block { padding-top: 36px; margin-top: 36px; }
/* Sections that lead a tab panel shouldn't carry the top spacer —
   the tab strip already provides separation, and a doubled gap reads
   as a layout bug. */
.prj-tab-panel .section-block:first-child { padding-top: 0; margin-top: 0; }

/* Project edit tab nav. Sits above the panels inside .setup-body.
   Restrained: text-only buttons, navy underline marks the active tab,
   no boxy chrome — matches the rest of the form chrome. */
.prj-tabs {
  display: flex;
  gap: 28px;
  border-bottom: 1px solid rgba(26,46,61,.12);
  margin-bottom: 8px;
  padding: 0 2px;
}
.prj-tab {
  background: none;
  border: 0;
  padding: 12px 0;
  margin: 0;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(26,46,61,.5);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color .15s ease, border-color .15s ease;
}
.prj-tab:hover { color: rgba(26,46,61,.85); }
.prj-tab.is-active {
  color: var(--navy);
  border-bottom-color: var(--navy);
}
.prj-tab:focus-visible { outline: 2px solid var(--navy); outline-offset: 4px; }

.prj-tab-panel { display: none; }
.prj-tab-panel.is-active { display: block; }

/* Section titles do the visual work of the (now-removed) border.
   Bumped to 14px solid navy (was 13px muted) so the heading
   carries the divider weight on its own. No trailing rule
   anymore — cleaner read, less stripe noise. */
.section-title {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--navy);
  margin-bottom: 18px;
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.section-hint {
  font-size: 11px; color: rgba(26,46,61,.55);
  line-height: 1.55; margin-bottom: 14px;
  max-width: 760px;
}

.row-list { display: flex; flex-direction: column; gap: 8px; }
.row-list .editable-row {
  display: grid; align-items: center; gap: 10px;
  padding: 8px 10px; background: #f7f5ef; border-radius: 4px;
}
/* Activity / milestone row: swatch | label | (banner toggle) | delete */
.editable-row.row-type   { grid-template-columns: 32px 1fr auto auto; }
.editable-row.row-mile   { grid-template-columns: 32px 1fr auto; }
/* Delivery date: swatch | label | date | delete */
.editable-row.row-deliv  { grid-template-columns: 32px 1fr 150px auto; }

.row-list input.text-input {
  font-size: 12px; padding: 6px 9px;
  border-color: transparent; background: transparent;
}
.row-list input.text-input:hover { background: #fff; border-color: rgba(26,46,61,.18); }
.row-list input.text-input:focus { background: #fff; border-color: var(--navy); }

.btn-row-del {
  background: none; border: none; color: rgba(169,50,38,.45);
  font-size: 17px; line-height: 1; cursor: pointer; padding: 0 4px;
  transition: color .12s;
}
.btn-row-del:hover { color: #a93226; }
.btn-add-row {
  /* Inline + left-aligned in both flex and grid parents. Without
     justify-self the button stretches to fill grid columns, which
     was the source of the "full-width add button" complaint. */
  align-self: flex-start;
  justify-self: start;
  margin-top: 6px;
  background: transparent; color: var(--navy);
  border: 1px solid rgba(26,46,61,.18);
  padding: 6px 12px; border-radius: 3px; font-family: var(--font);
  font-size: 10px; font-weight: 600; letter-spacing: .6px;
  text-transform: none; cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
.btn-add-row:hover {
  background: rgba(26,46,61,.05);
  border-color: rgba(26,46,61,.4);
}

.banner-toggle {
  display: flex; align-items: center; gap: 6px;
  font-size: 9.5px; font-weight: 600; color: rgba(26,46,61,.6);
  letter-spacing: .8px; text-transform: uppercase; cursor: pointer;
  user-select: none;
}
.banner-toggle input[type="checkbox"] { cursor: pointer; }

/* Estimate-form preview of the structured deliverables grid. Read-
   only mirror of what the PDF + public viewer render. Edit affordance
   lives on the Edit Deliverables button above the grid; clicking it
   opens the shared deliverables-editor modal. */
.est-deliverables-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 8px;
}
.est-deliverables-preview { margin-top: 6px; }
.est-dv-grid {
  display: grid;
  gap: 1px;
  background: rgba(26,46,61,.10);
  border: 1px solid rgba(26,46,61,.10);
  border-radius: 4px;
  overflow: hidden;
}
.est-dv-col { background: #fff; display: flex; flex-direction: column; }
.est-dv-col-hd {
  color: #fff;
  padding: 8px 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  text-align: center;
}
.est-dv-col-body { padding: 8px 10px; flex: 1; }
.est-dv-group + .est-dv-group {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed rgba(26,46,61,.12);
}
.est-dv-group-name {
  font-size: 12px;
  font-weight: 600;
  color: var(--navy);
}
.est-dv-group-ratios {
  font-size: 10.5px;
  color: rgba(26,46,61,.6);
  margin-top: 2px;
  letter-spacing: 0.4px;
}
.est-dv-group-note {
  font-size: 11px;
  color: rgba(26,46,61,.65);
  margin-top: 4px;
  font-style: italic;
}

/* Deliverable column blocks */
.dv-col-block {
  background: #f7f5ef; border-radius: 5px;
  padding: 12px 14px; margin-bottom: 10px;
  border-left: 4px solid var(--navy);
}
.dv-col-head-row {
  display: grid; grid-template-columns: 32px 1fr 1fr auto;
  gap: 10px; align-items: center; margin-bottom: 10px;
}
.dv-col-head-row .field-label { margin-bottom: 0; font-size: 8.5px; }
.dv-col-head-row select.select-input { font-size: 11px; padding: 6px 8px; }
.dv-col-head-row input.text-input { font-size: 12px; padding: 6px 9px; }

.dv-groups-list {
  display: flex; flex-direction: column; gap: 6px;
  padding-left: 8px; border-left: 2px solid rgba(26,46,61,.1);
  margin-bottom: 8px;
}
.dv-group-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) auto minmax(0, 1fr) auto;
  gap: 10px; align-items: center; padding: 6px 8px;
  background: #fff; border-radius: 3px;
}
.dv-group-row input.text-input {
  font-size: 11px; padding: 5px 8px;
  border-color: rgba(26,46,61,.12); background: #fff;
}

/* Aspect-ratio checkbox cluster — replaces the prior single text
   field for ratios. Each checked box increments the deliverable
   tally shown next to the column name and in the section header. */
.dv-ratio-group {
  display: flex; gap: 10px; align-items: center;
  padding: 4px 8px;
  background: #f7f5ef;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 3px;
}
.dv-ratio-check {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 500;
  color: var(--navy);
  cursor: pointer;
  user-select: none;
}
.dv-ratio-check input[type="checkbox"] {
  width: 13px; height: 13px;
  accent-color: var(--navy);
  cursor: pointer;
  margin: 0;
}
.dv-ratio-check input[type="checkbox"]:not(:checked) + span {
  opacity: .55;
}

.setup-foot {
  padding: 16px 22px; border-top: 1px solid rgba(26,46,61,.08);
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
}
.setup-foot-right { display: flex; gap: 8px; }

/* ── From Estimate flow ──────────────────────────────────── */
.fe-radio-row {
  display: flex; gap: 18px; flex-wrap: wrap;
  font-size: 12px; color: var(--navy);
}
.fe-radio-row label {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
}

.fe-file-input {
  font-size: 12px; padding: 8px 0; color: var(--navy);
}

/* Drag-and-drop upload zone */
.fe-drop-zone {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px;
  padding: 22px 20px;
  max-width: 420px;
  background: #f7f5ef;
  border: 2px dashed rgba(26,46,61,.22);
  border-radius: 6px;
  cursor: pointer;
  transition: background .15s, border-color .15s, transform .1s;
  user-select: none;
  outline: none;
  position: relative;
}
.fe-drop-zone:hover,
.fe-drop-zone:focus-visible {
  background: #f0ece1;
  border-color: rgba(26,46,61,.4);
}
.fe-drop-zone.is-dragover {
  background: #e8f1e9;
  border-color: var(--navy);
  border-style: solid;
}
.fe-drop-zone.has-file {
  border-style: solid;
  border-color: #1e8449;
  background: #f0f8f1;
  cursor: default;
}
.fe-drop-zone .fe-drop-empty  { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.fe-drop-zone .fe-drop-filled { display: none;  flex-direction: column; align-items: center; gap: 4px; }
.fe-drop-zone.has-file .fe-drop-empty  { display: none; }
.fe-drop-zone.has-file .fe-drop-filled { display: flex; }

.fe-drop-text {
  font-size: 13px; font-weight: 600; color: var(--navy);
  letter-spacing: .2px;
}
.fe-drop-sub {
  font-size: 11px; color: rgba(26,46,61,.55);
}
.fe-drop-check {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: #1e8449; color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 700;
  margin-bottom: 4px;
}
.fe-drop-filename {
  font-size: 13px; font-weight: 600; color: var(--navy);
  word-break: break-all; text-align: center;
  max-width: 360px;
}
.fe-drop-filesize {
  font-size: 11px; color: rgba(26,46,61,.55);
}
.fe-drop-clear {
  margin-top: 6px;
  background: none;
  border: 1px solid rgba(169,50,38,.4);
  border-radius: 3px;
  padding: 3px 10px;
  font-family: var(--font);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .5px;
  text-transform: uppercase;
  color: #a93226;
  cursor: pointer;
}
.fe-drop-clear:hover {
  background: rgba(169,50,38,.07);
  border-color: rgba(169,50,38,.65);
}

/* Per-platform delivery date rows */
.fe-deliv-row {
  display: grid; grid-template-columns: 1fr 180px;
  align-items: center; gap: 10px;
  padding: 8px 10px; background: #f7f5ef; border-radius: 4px;
}
.fe-plat-label {
  font-size: 12px; font-weight: 600; color: var(--navy);
}

/* Product blocks */
.fe-prod-block {
  background: #f7f5ef; border-radius: 5px;
  padding: 12px 14px; margin-bottom: 12px;
  border-left: 4px solid var(--navy);
}
.fe-prod-head {
  display: grid; grid-template-columns: 1fr auto auto auto;
  align-items: center; gap: 12px; margin-bottom: 10px;
}
.fe-prod-name { font-weight: 600; font-size: 13px; }

.fe-platforms {
  display: flex; flex-direction: column; gap: 8px;
  padding-left: 8px; border-left: 2px solid rgba(26,46,61,.1);
  margin-bottom: 8px;
}
.fe-plat-block {
  background: #fff; border-radius: 4px; padding: 10px 12px;
}
.fe-plat-head {
  display: grid; grid-template-columns: 1fr auto auto;
  align-items: center; gap: 10px; margin-bottom: 8px;
}
.fe-plat-name { font-size: 12px; font-weight: 600; }

.fe-variants {
  display: flex; flex-direction: column; gap: 5px;
  padding-left: 8px; border-left: 2px solid rgba(26,46,61,.07);
  margin-bottom: 6px;
}
.fe-var-row {
  display: grid; grid-template-columns: 80px 100px 1fr 70px auto;
  gap: 6px; align-items: center;
  padding: 5px 8px; background: #f7f5ef; border-radius: 3px;
}
.fe-var-row input.text-input {
  font-size: 11px; padding: 4px 7px;
}
.fe-add-var, .fe-add-plat {
  font-size: 9px; padding: 4px 8px;
}

/* Events list */
.fe-events-head {
  display: grid; grid-template-columns: 140px 56px 160px 1fr 28px;
  gap: 8px;
  padding: 0 10px 6px;
  font-size: 9px; font-weight: 700; letter-spacing: 1.5px;
  text-transform: uppercase; color: rgba(26,46,61,.5);
}
.fe-events-list {
  display: flex; flex-direction: column; gap: 4px;
  margin-bottom: 8px;
}
.fe-event-row {
  display: grid; grid-template-columns: 140px 56px 160px 1fr 28px;
  gap: 8px; align-items: center;
  padding: 5px 10px; background: #f7f5ef; border-radius: 3px;
}
.fe-event-row .text-input,
.fe-event-row .select-input {
  font-size: 11px; padding: 5px 8px;
}

/* Conflict groups (same-day same-type) */
.fe-conflicts {
  background: #fdf6ec; border-radius: 5px; padding: 12px 16px;
  border: 1px solid rgba(211,84,0,.18);
}
.fe-conflict-block {
  background: #fff; border-radius: 4px; padding: 10px 12px;
  margin-bottom: 8px;
  border-left: 3px solid #d35400;
}
.fe-conflict-head {
  display: flex; gap: 12px; align-items: center;
  font-size: 11px; color: var(--navy); margin-bottom: 6px;
}
.fe-conflict-date { font-weight: 700; }
.fe-conflict-type {
  font-size: 9.5px; font-weight: 700; letter-spacing: 1.2px;
  text-transform: uppercase; color: rgba(26,46,61,.6);
}
.fe-conflict-count { font-size: 10px; color: rgba(26,46,61,.55); }
.fe-conflict-events {
  list-style: disc; padding-left: 18px; margin: 0 0 8px;
  font-size: 11px; color: rgba(26,46,61,.85); line-height: 1.55;
}
.fe-conflict-actions { display: flex; gap: 6px; }
.fe-conflict-actions button { padding: 5px 10px; font-size: 9.5px; }
.fe-conflicts-bulk {
  display: flex; gap: 8px; margin-top: 12px;
  padding-top: 10px; border-top: 1px solid rgba(211,84,0,.15);
}
.fe-conflicts-bulk button { padding: 5px 12px; font-size: 9.5px; }

/* Day-load + unmapped warning panels (use the same style family) */
.fe-dayload, .fe-unmapped {
  background: #fdf2f2; border-radius: 5px; padding: 12px 16px;
  border: 1px solid rgba(169,50,38,.15);
}
.fe-dayload .section-title,
.fe-unmapped .section-title { color: #a93226; }

/* Warnings panel */
.fe-warnings {
  background: #fdf2f2; border-radius: 5px; padding: 12px 16px;
  border: 1px solid rgba(169,50,38,.15);
}
.fe-warnings-list {
  margin: 0; padding-left: 18px;
  font-size: 11px; color: rgba(26,46,61,.85); line-height: 1.55;
}
.fe-warnings-list li { margin-bottom: 4px; }

/* ════════════════════════════════════════════════════════════
   ESTIMATE BUILDER  -  document-preview aesthetic.

   Brand color (estimate UI + PDF): --ap-est-navy #0a3254
   The rest of the admin chrome stays --navy (#1a2e3d).

   All type uses the system sans stack (var(--font)), same as the
   rest of the app. Visual hierarchy comes from size, weight,
   color, and letter-spacing on uppercase labels.

   The editor is intentionally sparse so it reads as a draft of
   the printed estimate: white "paper" inside the dark setup-shell
   chrome, hairline rules instead of filled bands, all-caps small
   labels with letter-spacing, generous whitespace.
   Inputs are borderless by default; hover/focus reveals the affordance.
   ════════════════════════════════════════════════════════════ */

/* ─── List view ─────────────────────────────────────────────── */
.est-list-toolbar {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 18px; gap: 12px; flex-wrap: wrap;
}
.est-list-actions { display: flex; align-items: center; gap: 10px; }
.est-list-search { width: 220px; padding: 6px 10px; font-size: 11px; }

.est-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 14px;
}
.est-card {
  background: #fff; border-radius: 5px; overflow: hidden;
  box-shadow: 0 1px 4px rgba(0,0,0,.07), 0 4px 16px rgba(0,0,0,.04);
  display: flex; flex-direction: column;
  border-top: 3px solid #0a3254;
}
.est-card-head {
  padding: 12px 14px 8px;
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 10px;
}
.est-card-num {
  font-family: "SF Mono","Fira Code",monospace;
  font-size: 11px; font-weight: 700; color: #0a3254; letter-spacing: .8px;
}
.est-card-body {
  padding: 4px 14px 10px; flex: 1;
  display: flex; flex-direction: column; gap: 4px;
}
.est-card-client {
  font-size: 9px; font-weight: 700; letter-spacing: 1.8px;
  text-transform: uppercase; color: rgba(26,46,61,.55);
}
.est-card-project { font-size: 13px; font-weight: 600; color: var(--navy); line-height: 1.3; }
.est-card-meta { margin-top: 6px; font-size: 10px; color: rgba(26,46,61,.55); letter-spacing: .3px; }
.est-card-total { font-size: 14px; font-weight: 700; color: #0a3254; margin-top: 4px; letter-spacing: .2px; }
.est-card-foot {
  padding: 9px 14px; border-top: 1px solid rgba(26,46,61,.07);
  display: flex; gap: 6px; align-items: center; justify-content: space-between;
}
.est-card-foot-actions { display: flex; gap: 6px; }
.est-card-foot .btn-ghost { padding: 4px 10px; font-size: 9px; }

.est-empty {
  background: #fff; padding: 36px 24px; border-radius: 5px;
  text-align: center; color: rgba(26,46,61,.55);
  box-shadow: 0 1px 4px rgba(0,0,0,.05);
}

/* ─── Builder shell + chrome bar ─────────────────────────────── */
.est-form-actions-right { display: flex; gap: 8px; align-items: center; }

.est-status-select {
  width: auto;
  padding: 5px 26px 5px 10px;        /* room on the right for the chevron */
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.3px;
  background-color: rgba(255,255,255,.10);
  color: var(--beige);
  border: 1px solid rgba(232,224,208,.35);
  border-radius: 4px;
  /* Explicit chevron — .select-input strips appearance:none so the
     native dropdown arrow is gone; without this glyph the select
     reads as a flat editable field. Inline SVG keeps it crisp at any
     DPI without an extra HTTP request. */
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%23e8e0d0' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 8px center;
  cursor: pointer;
}
.est-status-select:hover { background-color: rgba(255,255,255,.16); }
.est-status-select option { color: var(--navy); background: #fff; }

/* Icon-only button on the navy chrome bar. Visual weight matches
   .btn-ghost-light (beige on faint translucent fill, hover deepens)
   but pads down to a square so the SVG icon is the whole content.
   Used by the Copy share link button in the estimate form header. */
.btn-icon-light {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px; height: 30px;
  padding: 0;
  background: rgba(255,255,255,.06);
  color: var(--beige);
  border: 1px solid rgba(232,224,208,.25);
  border-radius: 4px;
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.btn-icon-light:hover {
  background: rgba(255,255,255,.16);
  border-color: rgba(232,224,208,.55);
}
.btn-icon-light:active { transform: translateY(1px); }
.btn-icon-light[hidden] { display: none; }

/* The estimate body is treated as a "paper" preview. Override the
   generic setup-body padding so the document fills more of the shell.
   Same treatment for the invoice form so both documents read like
   8.5x11 paper sitting on a beige frame. */
#view-estimate-form .setup-body,
#view-invoice-form  .setup-body,
#view-project-form  .setup-body {
  background: #fff;
  padding: 44px 56px 36px;
  max-width: 920px;
  margin: 0 auto;
}
#view-estimate-form .setup-shell,
#view-invoice-form  .setup-shell,
#view-project-form  .setup-shell {
  background: #f5f1e6;  /* light beige frame around the paper */
  padding-bottom: 0;
}

/* PDF view panels — inline PDF display replacing the old "Preview" tab */
#view-invoice-pdf  .setup-body,
#view-estimate-pdf .setup-body { padding: 0; overflow: hidden; }
#view-invoice-pdf  .setup-body iframe,
#view-estimate-pdf .setup-body iframe {
  display: block;
  width: 100%;
  height: calc(100vh - 100px);
  border: none;
}

/* Strip the section-block dividers so the document flows as one piece */
#view-estimate-form .section-block,
#view-invoice-form  .section-block {
  border-top: none; padding-top: 0; margin-top: 28px;
}
#view-estimate-form .section-block:first-child,
#view-invoice-form  .section-block:first-child { margin-top: 0; }

/* Invoice-specific Balance Due bar — much shorter than the estimate's
   grand-total bar, with a smaller dollar amount. The label stays at
   roughly the same visual weight; the number is the thing that gets
   downsized so the bar reads as a polite footer rather than a
   trumpet blast. */
#view-invoice-form .est-totals-row.is-final {
  padding: 6px 22px;
  margin-top: 12px;
}
#view-invoice-form .est-totals-row.is-final .label {
  font-size: 10px;
}
#view-invoice-form .est-totals-row.is-final .value {
  font-size: 11px;
}

/* Tiny doc labels (replace .section-title for inline use) */
.est-doc-label {
  display: block;
  font-family: var(--font);
  font-size: 9.5px; font-weight: 700; letter-spacing: 2.5px;
  text-transform: uppercase; color: #0a3254;
  margin-bottom: 8px;
  padding-bottom: 5px;
  border-bottom: 1px solid rgba(10,50,84,.18);
}
/* Inline meta beside a section label, e.g. "(56 total deliverables)"
   — same uppercase tracking but lighter weight so it reads as
   secondary info next to the heading. The number itself is an
   editable inline input so the user can override the auto-count. */
.est-doc-label-meta {
  font-weight: 500;
  color: rgba(10,50,84,.55);
  margin-left: 10px;
  letter-spacing: 1.6px;
}
.est-doc-label-meta-input {
  background: transparent;
  border: none;
  border-bottom: 1px dashed rgba(10,50,84,.32);
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  width: 38px;
  text-align: center;
  padding: 0 2px;
  margin: 0 1px;
  outline: none;
  transition: border-bottom-color .12s, background .12s;
}
.est-doc-label-meta-input:hover {
  border-bottom-color: rgba(10,50,84,.55);
}
.est-doc-label-meta-input:focus {
  border-bottom-color: var(--navy);
  color: var(--navy);
  background: rgba(255,255,255,.55);
}

/* ─── PDF-preview header (mirrors the PDF header layout) ───── */
.est-doc-header {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: flex-start; gap: 24px;
  padding-bottom: 20px;
  border-bottom: 2px solid #0a3254;
  margin-bottom: 24px;
}
.est-doc-company {
  font-size: 11px; line-height: 1.6; color: var(--navy);
}
.est-doc-company div { letter-spacing: .1px; }
.est-doc-logo {
  width: 168px; height: auto; display: block;
}

/* Share settings — public-viewer URL slug. Sits ABOVE the doc body
   so it doesn't get mixed up with the formal estimate content. Looks
   like a regular labeled input (visible border, left-aligned text)
   so the editing affordance is unambiguous, unlike the borderless
   doc-stamp inputs below. URL prefix is rendered as fixed text so
   the user always sees the share host they're configuring. */
.est-share-settings {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 22px;
  padding: 10px 14px;
  background: rgba(26,46,61,.04);
  border: 1px solid rgba(26,46,61,.10);
  border-radius: 4px;
}
.est-share-settings-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  white-space: nowrap;
}
.est-share-settings-input {
  display: flex;
  align-items: stretch;
  flex: 1 1 auto;
  min-width: 0;
  background: #fff;
  border: 1px solid rgba(26,46,61,.22);
  border-radius: 3px;
  overflow: hidden;
  transition: border-color .12s;
}
.est-share-settings-input:focus-within {
  border-color: var(--navy);
}
.est-share-prefix {
  display: flex;
  align-items: center;
  padding: 5px 8px 5px 10px;
  font-family: var(--font);
  font-size: 11px;
  color: rgba(26,46,61,.55);
  background: rgba(26,46,61,.03);
  border-right: 1px solid rgba(26,46,61,.10);
  white-space: nowrap;
  user-select: none;
}
.est-share-settings input {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font);
  font-size: 12px;
  color: var(--navy);
  padding: 5px 8px;
  border: none;
  background: transparent;
  outline: none;
  text-align: left;
}
.est-share-settings input::placeholder {
  color: rgba(26,46,61,.40);
}

/* Copy button on the right of the Share URL row — same chrome as the
   surrounding outline-input but with a navy fill so it reads as the
   row's primary action. Hidden until the estimate has a real id. */
.est-share-copy-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  font-family: var(--font);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  background: var(--navy);
  color: var(--beige);
  border: 1px solid var(--navy);
  border-radius: 3px;
  cursor: pointer;
  transition: background .12s, transform .04s;
  white-space: nowrap;
  flex: 0 0 auto;
}
.est-share-copy-btn:hover  { background: var(--navy-mid); border-color: var(--navy-mid); }
.est-share-copy-btn:active { transform: translateY(1px); }
.est-share-copy-btn[hidden] { display: none; }
.est-share-copy-btn svg { flex: 0 0 auto; }

/* Client + meta block (under the logo header) - tight document layout.
   Each client field reads as a line of text; the box only appears on
   hover/focus, matching the section title and stamp inputs. */
.est-doc-meta-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 36px; align-items: flex-start;
  margin-bottom: 22px;
}
/* Client block - single column stack. Each line reads as a row of an
   address; box appears on hover/focus, matching the stamp inputs. */
.est-doc-client {
  display: flex; flex-direction: column;
  gap: 3px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--navy);
  max-width: 320px;
}
/* "Prepared for" label sits above the client block. Same small-caps
   navy treatment the stamp labels use on the right so the two sides
   read as a matched pair. */
.est-doc-prepared-for {
  display: inline-block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--navy);
  margin-bottom: 4px;
}
/* City / State / Zip on one tight line - same visual rhythm as a
   real address line, but each field stays independently editable. */
.est-doc-client-citystate {
  display: grid;
  grid-template-columns: 1fr 32px 64px;
  gap: 3px;
}
.est-doc-client-citystate input { text-align: left; }

/* Estimate stamp - tighter spacing, label and input share a single line. */
.est-doc-stamp {
  min-width: 250px;
  display: grid; grid-template-columns: auto 1fr;
  gap: 1px 12px;
  align-items: baseline;
}
.est-doc-stamp .stamp-label {
  font-family: var(--font);
  font-size: 9.5px; font-weight: 600; letter-spacing: 2px;
  text-transform: uppercase; color: #0a3254;
  text-align: right;
  padding-top: 4px;
  white-space: nowrap;
}
.est-doc-stamp input {
  font-family: var(--font); font-size: 12px; color: var(--navy);
  text-align: right;
  padding: 2px 6px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 3px;
  width: 100%;
  line-height: 1.3;
}
.est-doc-stamp input:hover  { border-color: rgba(26,46,61,.15); background: #f9f7f2; }
.est-doc-stamp input:focus  { outline: none; border-color: var(--navy); background: #fff; }

/* Inline doc inputs - faint box always visible so each line clearly
   reads as an editable field. Box gets stronger on hover/focus. */
.est-doc-input,
#view-estimate-form .text-input.est-doc-input {
  border: 1px solid rgba(26,46,61,.12);
  background: #fbfaf6;
  font-size: 12px;
  color: var(--navy);
  padding: 3px 6px;
  border-radius: 3px;
  font-family: var(--font);
  line-height: 1.4;
}
.est-doc-input:hover  { background: #f5f1e6; border-color: rgba(26,46,61,.25); }
.est-doc-input:focus  { outline: none; background: #fff; border-color: var(--navy); }
.est-doc-input::placeholder { color: rgba(26,46,61,.30); font-style: italic; }

/* Project name - large, full-width inline */
.est-doc-projectname {
  font-family: var(--font);
  font-size: 20px; font-weight: 700; color: #0a3254;
  letter-spacing: .2px;
  margin: 6px 0 14px;
  padding: 4px 8px;
}
.est-doc-projectname::placeholder { font-style: italic; font-weight: 400; }

/* Scope summary textarea sits right under the project name -
   reads as document body text. */
.est-doc-scope-input {
  margin-top: 0;
  font-size: 12px; line-height: 1.55;
  min-height: 44px;
}
.est-scope-block { margin-top: 8px; }

/* Scope summary textarea reads as document text */
.est-doc-scope {
  width: 100%;
  border: 1px solid transparent;
  background: transparent;
  padding: 8px 10px;
  font-family: var(--font);
  font-size: 12px;
  line-height: 1.6;
  color: var(--navy);
  border-radius: 3px;
  resize: vertical;
  min-height: 50px;
}
.est-doc-scope:hover { background: #f9f7f2; border-color: rgba(26,46,61,.15); }
.est-doc-scope:focus { outline: none; background: #fff; border-color: var(--navy); }
.est-doc-scope::placeholder { color: rgba(26,46,61,.30); font-style: italic; }

/* ─── Information Provided ─────────────────────────────────── */
.est-info-list { display: flex; flex-direction: column; gap: 2px; margin-bottom: 6px; }
.est-info-row {
  display: grid; grid-template-columns: 14px 1fr auto;
  gap: 8px; align-items: center;
  padding: 4px 0;
}
.est-info-row::before {
  content: "-"; color: rgba(26,46,61,.55); font-size: 12px;
  text-align: center;
}
.est-info-row input.text-input { font-size: 12px; }
.est-info-row .btn-row-del { padding: 0 6px; }

/* ─── Sections (line item groups) - hairline aesthetic ─────── */
.est-section {
  margin-bottom: 22px;
  background: transparent;
  border-radius: 0;
  box-shadow: none;
}
.est-section { transition: margin .15s ease, opacity .12s ease, height .15s ease; }
.est-section.is-dragging {
  opacity: 0;
  height: 0;
  margin: 0;
  overflow: hidden;
  pointer-events: none;
}
/* Section drop target opens a slot the size of the source section. */
.est-section.drop-before {
  margin-top: var(--est-drag-h, 60px);
  position: relative;
}
.est-section.drop-before::before {
  content: "";
  position: absolute;
  left: 0; right: 0;
  top: calc(-1 * var(--est-drag-h, 60px));
  height: calc(var(--est-drag-h, 60px) - 6px);
  margin: 3px 0;
  background: rgba(240, 236, 225, .70);
  border: 1px dashed rgba(10, 50, 84, .35);
  border-radius: 3px;
  pointer-events: none;
}
.est-section.drop-after {
  margin-bottom: var(--est-drag-h, 60px);
  position: relative;
}
.est-section.drop-after::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  bottom: calc(-1 * var(--est-drag-h, 60px));
  height: calc(var(--est-drag-h, 60px) - 6px);
  margin: 3px 0;
  background: rgba(240, 236, 225, .70);
  border: 1px dashed rgba(10, 50, 84, .35);
  border-radius: 3px;
  pointer-events: none;
}

.est-section-head {
  display: grid;
  grid-template-columns: 24px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 4px 10px 4px 4px;
  background: #f0ece1;
  border-bottom: none;
  margin-bottom: 0;
  border-radius: 2px;
}
.est-section.is-headerless .est-section-head {
  background: transparent;
}
.est-drag-handle {
  display: flex;
  align-items: center; justify-content: center;
  cursor: grab; color: rgba(10,50,84,.55);
  font-size: 11px;
  user-select: none; line-height: 1;
  align-self: center;
  height: 24px;
  border-radius: 3px;
  touch-action: none;
}
.est-drag-handle:hover  { background: #ddd5be; color: #0a3254; }
.est-drag-handle:active { cursor: grabbing; background: #ccc4ad; }

.est-section-label-input {
  background: transparent; border: 1px solid transparent;
  color: #0a3254;
  font-family: var(--font);
  font-size: 11px; font-weight: 700;
  letter-spacing: 2px; text-transform: uppercase;
  padding: 3px 6px; border-radius: 3px;
  width: 100%;
}
.est-section-label-input::placeholder { color: rgba(10,50,84,.35); }
.est-section-label-input:hover  { background: #f9f7f2; border-color: rgba(26,46,61,.15); }
.est-section-label-input:focus  { outline: none; background: #fff; border-color: var(--navy); }

.est-section-del {
  background: none; border: none; color: rgba(26,46,61,.30);
  font-size: 14px; line-height: 1; padding: 2px 4px; cursor: pointer;
  transition: color .12s;
}
.est-section-del:hover { color: #0a3254; }

/* Section subtotal row: lives under the items, aligned to the items grid
   so the value sits beneath the LINE TOTAL column. Mirrors the PDF. */
.est-section-subtotal-row {
  display: grid;
  grid-template-columns: 24px minmax(0,1.0fr) minmax(0,2.4fr) 76px 60px 80px 38px;
  gap: 6px;
  padding: 7px 0 4px;
  border-top: 1px solid rgba(26,46,61,.10);
  margin-top: 2px;
}
.est-section-subtotal-row .label {
  grid-column: 5;
  text-align: right;
  font-family: var(--font);
  font-size: 9px; font-weight: 700;
  letter-spacing: 1.5px; text-transform: uppercase;
  color: rgba(26,46,61,.55);
  align-self: center;
  white-space: nowrap;
}
.est-section-subtotal-row .value {
  grid-column: 6;
  text-align: right;
  font-size: 12px; font-weight: 700; color: #0a3254;
  letter-spacing: .2px;
  white-space: nowrap;
}

/* ─── Line items ───────────────────────────────────────────── */
/* Column grid: handle | service | description | rate-stepper | qty-stepper | total | del
   Stepper columns include the +/- buttons so they get explicit width. */
.est-items {
  display: flex; flex-direction: column; gap: 0;
}
.est-item-row {
  display: grid;
  grid-template-columns: 24px minmax(0,1.0fr) minmax(0,2.4fr) 76px 60px 80px 38px;
  gap: 6px;
  align-items: start;
  padding: 5px 0 5px 0;
  border-bottom: 1px solid rgba(26,46,61,.07);
}
.est-item-row:last-child { border-bottom: none; }
.est-item-row { transition: margin .15s ease, padding .15s ease, height .15s ease, opacity .12s ease; }

/* Source row while dragging: collapses to zero height. Other rows shift
   up to fill the gap, then a fresh slot opens at the drop target. */
.est-item-row.is-dragging {
  height: 0;
  min-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  margin: 0;
  opacity: 0;
  border: 0;
  overflow: hidden;
  pointer-events: none;
}

/* Drop target: opens a real slot the size of the source so the cursor
   sees other rows pushing out of the way (Trello-style). The slot is a
   pseudo-element rendered in the gap. --est-drag-h is set in JS to the
   source row's height when the drag starts. */
.est-item-row.drop-before {
  margin-top: var(--est-drag-h, 32px);
  position: relative;
}
.est-item-row.drop-before::before {
  content: "";
  position: absolute;
  left: 0; right: 0;
  top: calc(-1 * var(--est-drag-h, 32px));
  height: calc(var(--est-drag-h, 32px) - 4px);
  margin: 2px 0;
  background: rgba(240, 236, 225, .70);
  border: 1px dashed rgba(10, 50, 84, .35);
  border-radius: 3px;
  pointer-events: none;
}
.est-item-row.drop-after {
  margin-bottom: var(--est-drag-h, 32px);
  position: relative;
}
.est-item-row.drop-after::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  bottom: calc(-1 * var(--est-drag-h, 32px));
  height: calc(var(--est-drag-h, 32px) - 4px);
  margin: 2px 0;
  background: rgba(240, 236, 225, .70);
  border: 1px dashed rgba(10, 50, 84, .35);
  border-radius: 3px;
  pointer-events: none;
}
.est-item-drag {
  display: flex;
  align-items: center; justify-content: center;
  cursor: grab; color: rgba(26,46,61,.40);
  font-size: 11px; line-height: 1;
  height: 26px; min-height: 26px;
  text-align: center;
  user-select: none;
  align-self: start;
  border-radius: 3px;
  /* No native draggable attribute - we use pointer events instead. */
  touch-action: none;
}
.est-item-drag:hover  { background: #ece6d5; color: #0a3254; }
.est-item-drag:active { cursor: grabbing; background: #ddd5be; }

/* Inline item inputs match the doc-input aesthetic */
.est-item-row .text-input {
  font-size: 11px; padding: 3px 7px;
  border: 1px solid transparent; background: transparent;
  color: var(--navy);
  line-height: 1.4;
}
.est-item-row .text-input:hover { background: #f9f7f2; border-color: rgba(26,46,61,.15); }
.est-item-row .text-input:focus { outline: none; background: #fff; border-color: var(--navy); }
.est-item-row .text-input.is-service { font-weight: 700; color: #0a3254; }
.est-item-row .text-input.is-numeric { text-align: right; }

/* Service type + description: textareas that auto-grow vertically
   so long values wrap into multiple lines instead of getting cut off.
   field-sizing handles modern browsers; JS fallback covers the rest. */
.est-item-row textarea.is-desc,
.est-item-row textarea.is-service {
  width: 100%;
  resize: none;
  overflow: hidden;
  min-height: 22px;
  field-sizing: content;
  font-family: var(--font);
  line-height: 1.4;
  word-break: break-word;
}
.est-item-row textarea.is-service {
  font-weight: 700;
  color: #0a3254;
}
.est-item-linetotal {
  font-size: 11px; font-weight: 700; color: var(--navy);
  text-align: right; padding: 8px 4px;
  align-self: center;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}
/* Tabular figures everywhere a column of money or quantities lines up,
   so digits sit on the same vertical track. */
.est-item-row .text-input.is-numeric,
.est-stepper input,
.est-totals-row .value,
.est-section-subtotal-row .value,
.est-discount-input,
.est-tax-input {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}
.est-item-actions {
  display: flex; gap: 2px; align-items: center;
  align-self: center; justify-content: flex-end;
}
.est-item-dup, .est-item-del {
  background: none; border: none;
  color: rgba(26,46,61,.30);
  font-size: 13px; line-height: 1; cursor: pointer;
  padding: 6px 4px;
  border-radius: 3px;
  transition: color .12s, background .12s;
}
.est-item-dup:hover { color: #0a3254; background: #f0ece1; }
.est-item-del:hover { color: #a93226; background: rgba(169,50,38,.08); }

.est-items-foot {
  padding: 8px 0 0 22px;
  display: flex; justify-content: flex-start;
}

/* Column header (within each section) - very subtle */
.est-items-head {
  display: grid;
  grid-template-columns: 24px minmax(0,1.0fr) minmax(0,2.4fr) 76px 60px 80px 38px;
  gap: 6px;
  padding: 4px 0;
  font-family: var(--font);
  font-size: 8.5px; font-weight: 700; letter-spacing: 2px;
  text-transform: uppercase; color: rgba(26,46,61,.5);
}
.est-items-head .col-rate,
.est-items-head .col-qty,
.est-items-head .col-total { text-align: right; }

/* ─── Numeric stepper: large +/- buttons flanking a hidden-arrow input ── */
.est-stepper {
  display: grid;
  grid-template-columns: 16px 1fr 16px;
  align-items: stretch;
  border: 1px solid rgba(26,46,61,.10);
  border-radius: 3px;
  background: #fbfaf6;
  height: 22px;
  transition: background .12s, border-color .12s;
}
.est-stepper:hover            { background: #f9f7f2; border-color: rgba(26,46,61,.15); }
.est-stepper:focus-within     { background: #fff; border-color: var(--navy); }
.est-stepper input {
  border: none !important;
  background: transparent !important;
  text-align: center;
  font-family: var(--font);
  font-size: 11px;
  font-weight: 400;
  color: var(--navy);
  padding: 0 2px !important;
  width: 100%;
  /* Hide native browser stepper arrows so our custom buttons aren't redundant */
  -moz-appearance: textfield;
  appearance: textfield;
}
.est-stepper input::-webkit-outer-spin-button,
.est-stepper input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.est-stepper input:focus { outline: none; }
.est-stepper-btn {
  background: transparent;
  border: none;
  color: rgba(10,50,84,.55);
  font-family: var(--font);
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  transition: background .12s, color .12s;
  user-select: none;
}
.est-stepper-btn:first-child { border-right: 1px solid rgba(26,46,61,.08); }
.est-stepper-btn:last-child  { border-left:  1px solid rgba(26,46,61,.08); }
.est-stepper-btn:hover  { background: #ece6d6; color: #0a3254; }
.est-stepper-btn:active { background: #e0d8c4; }

/* ─── Headerless section (empty label - hides the visual heading) ─── */
.est-section.is-headerless .est-section-head {
  border-bottom: none;
  padding-bottom: 0;
  opacity: .35;
  transition: opacity .15s;
}
.est-section.is-headerless .est-section-head:hover,
.est-section.is-headerless .est-section-head:focus-within {
  opacity: 1;
}
.est-section.is-headerless .est-section-subtotal {
  /* Hide the per-section subtotal when the heading is hidden -
     the user is asking for compact, run-on items. */
  visibility: hidden;
}

/* ─── Add section / add CO buttons ─────────────────────────── */
.est-add-section-row {
  display: flex; gap: 10px; margin-top: 16px;
  flex-wrap: wrap;
}
.est-add-section-row .btn-add-row {
  background: transparent; color: #0a3254;
  border: 1px dashed rgba(10,50,84,.35);
}
.est-add-section-row .btn-add-row:hover {
  background: #f9f7f2; border-color: rgba(10,50,84,.6);
}

/* ─── Change order block - same hairline aesthetic, just emphasized ─── */
.est-co-block {
  margin: 30px 0 4px;
  padding: 18px 0 4px;
  border-top: 2px solid #0a3254;
  border-bottom: 1px solid rgba(26,46,61,.10);
  background: transparent;
  border-radius: 0;
}
.est-co-band {
  display: grid;
  grid-template-columns: auto 1fr auto auto auto;
  gap: 12px; align-items: baseline;
  padding: 0 0 12px 0;
}
.est-co-band-label {
  font-size: 9.5px; font-weight: 700; letter-spacing: 2.5px;
  text-transform: uppercase; color: #0a3254;
}
.est-co-band-num {
  background: transparent; color: #0a3254;
  border: 1px solid transparent;
  font-family: "SF Mono","Fira Code",monospace; font-size: 11px;
  font-weight: 700; letter-spacing: .5px;
  padding: 4px 10px; border-radius: 3px;
  width: 200px; min-width: 200px;
}
.est-co-band-num:hover { background: #f9f7f2; border-color: rgba(26,46,61,.15); }
.est-co-band-num:focus { outline: none; background: #fff; border-color: var(--navy); }

.est-co-band-date {
  background: transparent; color: var(--navy);
  border: 1px solid transparent;
  font-size: 11px; padding: 4px 8px; border-radius: 3px;
  font-family: var(--font);
}
.est-co-band-date:hover { background: #f9f7f2; border-color: rgba(26,46,61,.15); }
.est-co-band-date:focus { outline: none; background: #fff; border-color: var(--navy); }

.est-co-subtotal {
  font-size: 12px; font-weight: 700; color: #0a3254; letter-spacing: .3px;
  white-space: nowrap;
}
.est-co-del {
  background: none; border: none; color: rgba(26,46,61,.30);
  font-size: 14px; line-height: 1; padding: 2px 4px; cursor: pointer;
}
.est-co-del:hover { color: #0a3254; }

.est-co-reason {
  padding: 4px 0 14px;
}
.est-co-reason textarea {
  width: 100%; min-height: 44px; resize: vertical;
  padding: 8px 10px;
  border: 1px solid transparent;
  font-family: var(--font); font-size: 12px;
  font-style: italic;
  color: var(--navy);
  background: transparent; line-height: 1.55;
  border-radius: 3px;
}
.est-co-reason textarea:hover { background: #f9f7f2; border-color: rgba(26,46,61,.15); }
.est-co-reason textarea:focus { outline: none; background: #fff; border-color: var(--navy); }
.est-co-reason textarea::placeholder { color: rgba(26,46,61,.35); }

.est-co-sections { padding: 0; }
.est-co-sections .est-section { margin-bottom: 18px; }

/* ─── Totals block ─────────────────────────────────────────── */
.est-totals {
  margin-top: 22px;
  padding: 18px 0 0;
  border-top: 1px solid rgba(26,46,61,.10);
  display: flex; flex-direction: column; align-items: stretch;
}
.est-totals > .est-totals-row:not(.is-final) {
  align-self: flex-end;
}
/* Three explicit columns: label | optional input controls | value.
   The middle column collapses to 0 when not needed. */
.est-totals-row {
  display: grid;
  grid-template-columns: 1fr auto 130px;
  align-items: baseline; gap: 18px;
  padding: 8px 0;
  font-size: 11px; color: var(--navy);
  width: 500px; max-width: 100%;
}
.est-totals-row .label {
  color: rgba(26,46,61,.65);
  text-align: right;
}
.est-totals-row .value {
  font-weight: 700;
  text-align: right;
}
/* Final ESTIMATE TOTAL: navy fill bar that spans the full content width.
   The visual anchor at the end of the document, mirroring the PDF.
   Use flex so the empty middle span (used by the input rows) collapses. */
.est-totals-row.is-final {
  margin-top: 10px; padding: 14px 22px;
  border-top: none;
  background: #0a3254;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  width: 100%;
  border-radius: 3px;
  gap: 12px;
}
.est-totals-row.is-final > :nth-child(2):empty { display: none; }
.est-totals-row.is-final .label {
  font-family: var(--font);
  font-weight: 700; letter-spacing: 2px; text-transform: uppercase;
  font-size: 10.5px; color: #e8e0d0;
  text-align: left;
}
.est-totals-row.is-final .value {
  color: #ffffff;
  font-family: var(--font);
  font-size: 20px; font-weight: 700;
  letter-spacing: .2px;
  text-align: right;
  min-width: auto;
}

.est-totals-controls {
  display: flex; align-items: center; gap: 8px; justify-content: flex-end;
}

/* Discount + tax inputs - same look as inline doc inputs but explicit width */
.est-discount-input,
.est-tax-input {
  width: 88px; padding: 5px 8px;
  font-size: 12px; text-align: right;
  border: 1px solid transparent; background: transparent;
  color: var(--navy); border-radius: 3px;
  font-family: var(--font);
  /* Hide native browser stepper arrows (default control is too small to use) */
  -moz-appearance: textfield;
  appearance: textfield;
}
.est-discount-input::-webkit-outer-spin-button,
.est-discount-input::-webkit-inner-spin-button,
.est-tax-input::-webkit-outer-spin-button,
.est-tax-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.est-discount-input:hover, .est-tax-input:hover { background: #f9f7f2; border-color: rgba(26,46,61,.15); }
.est-discount-input:focus, .est-tax-input:focus { outline: none; background: #fff; border-color: var(--navy); }

.est-discount-toggle {
  display: inline-flex; gap: 0;
  border: 1px solid rgba(26,46,61,.18);
  border-radius: 3px; overflow: hidden;
  height: 28px;
}
.est-discount-toggle button {
  background: #fff; color: rgba(26,46,61,.6); border: none;
  font-family: var(--font); font-size: 11px; font-weight: 700;
  padding: 4px 10px; cursor: pointer;
  transition: background .12s, color .12s;
  min-width: 28px;
}
.est-discount-toggle button.is-active { background: #0a3254; color: #fff; }
.est-discount-toggle button:hover:not(.is-active) { background: #f0eee8; }

/* ─── Notes & terms - inline doc textareas ─────────────────── */
.est-textarea {
  width: 100%; min-height: 60px; resize: vertical;
  padding: 8px 10px;
  border: 1px solid transparent;
  font-family: var(--font); font-size: 12px; color: var(--navy);
  background: transparent; line-height: 1.6;
  border-radius: 3px;
}
.est-textarea:hover { background: #f9f7f2; border-color: rgba(26,46,61,.15); }
.est-textarea:focus { outline: none; background: #fff; border-color: var(--navy); }
.est-textarea.is-long { min-height: 110px; }
.est-textarea::placeholder { color: rgba(26,46,61,.30); font-style: italic; }

/* Notes block doc label inset to match other doc labels */
.est-notes-block .est-doc-label,
.est-terms-block .est-doc-label { margin-top: 8px; }

.est-terms-block { margin-top: 12px; }
.est-terms-block .est-doc-label { margin-top: 18px; }
.est-terms-block .est-doc-label:first-child { margin-top: 0; }

/* Dirty Save button — keep navy (no rust) */
.btn-modal.is-dirty {
  background: var(--navy);
  color: var(--beige);
  box-shadow: 0 0 0 2px rgba(232,224,208,.5);
}
.btn-modal.is-dirty::after {
  content: " *";
}

/* Fast custom tooltip that shows ~200ms after hover via the
   data-tooltip attribute (replacing the slow native title= behavior) */
[data-tooltip] {
  position: relative;
}
[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 4px);
  left: 50%;
  transform: translateX(-50%) translateY(2px);
  background: var(--navy);
  color: var(--beige);
  font-family: var(--font);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .3px;
  padding: 4px 8px;
  border-radius: 3px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s ease .15s, transform .12s ease .15s;
  z-index: 100;
  box-shadow: 0 2px 6px rgba(0,0,0,.18);
}
[data-tooltip]:hover::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Drag ghost: a clone of the row/section that follows the cursor.
   The clone is a snapshot - inputs are disabled, no transitions, just
   visual. It sits on top of the page and never receives pointer events. */
.est-drag-ghost {
  background: #ffffff !important;
  border: 1px solid rgba(10,50,84,.18) !important;
  border-radius: 4px !important;
  box-shadow:
    0 8px 24px rgba(10,50,84,.18),
    0 2px 6px rgba(10,50,84,.12);
  opacity: .70 !important;
  padding: 6px 10px !important;
  margin: 0 !important;
  pointer-events: none !important;
  user-select: none !important;
  transition: none !important;
  /* Override the is-dragging collapse if the cloned node ever
     accidentally carries that class. */
  height: auto !important;
  min-height: auto !important;
  overflow: visible !important;
}
.est-drag-ghost.est-section {
  padding: 0 !important;
  overflow: hidden;
}
.est-drag-ghost.drop-before,
.est-drag-ghost.drop-after {
  box-shadow:
    0 8px 24px rgba(10,50,84,.18),
    0 2px 6px rgba(10,50,84,.12) !important;
}

/* Suppress the data-tooltip popovers while a drag is in progress -
   otherwise hovering over neighboring handles flashes "Drag to reorder"
   tooltips all over the place during the drag itself. */
body.is-dragging-active [data-tooltip]:hover::after,
body.is-dragging-active [data-tooltip]::after {
  display: none !important;
  opacity: 0 !important;
}

/* Multi-line variant of data-tooltip used on stat cards to explain
   how each figure is calculated. Positioned BELOW the host element
   (the top-row stat cards have no headroom above) and wraps to a
   max width so multi-sentence explanations stay readable. */
[data-tooltip-wide] { position: relative; }
[data-tooltip-wide]::after {
  content: attr(data-tooltip-wide);
  position: absolute;
  top: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%) translateY(-2px);
  background: var(--navy);
  color: var(--beige);
  font-family: var(--font);
  font-size: 11px;
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: .1px;
  padding: 9px 12px;
  border-radius: 4px;
  width: max-content;
  max-width: 280px;
  white-space: normal;
  text-align: left;
  opacity: 0;
  pointer-events: none;
  transition: opacity .14s ease .2s, transform .14s ease .2s;
  z-index: 200;
  box-shadow: 0 4px 12px rgba(0,0,0,.22);
}
[data-tooltip-wide]:hover::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
body.is-dragging-active [data-tooltip-wide]:hover::after,
body.is-dragging-active [data-tooltip-wide]::after {
  display: none !important;
  opacity: 0 !important;
}

/* ────────────────────────────────────────────────────────────
   PHASE 2: Invoices + Clients
   ──────────────────────────────────────────────────────────── */

/* Close (X) button in the client form's setup-head. Mirrors the
   .modal-close treatment used in pop-up dialogs but sized for the
   slightly bigger setup-head height. */
.cli-close-btn {
  font-size: 20px;
  padding: 4px 8px;
  margin-left: auto;
  color: rgba(232,224,208,.7);
}
.cli-close-btn:hover { color: var(--beige); }

/* Status pills used in invoice list + client detail */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 9px; font-weight: 700; letter-spacing: 1.5px;
  text-transform: uppercase;
  padding: 3px 9px 3px 7px;
  border-radius: 10px;
  line-height: 1;
}
/* Status pill iconography — non-color signal so Active vs Delivered
   read distinctly even with color stripped. ● = live/in-progress,
   ✓ = completed, ◌ = inert/archived, ⋯ = draft, → = in transit. */
.status-pill::before {
  content: "";
  display: inline-block;
  width: 9px; text-align: center;
  font-size: 11px; font-weight: 700; line-height: 1;
}
.status-active::before      { content: "\25CF"; }   /* ● filled circle */
.status-delivered::before   { content: "\2713"; }   /* ✓ check */
.status-archived::before    { content: "\25CC"; }   /* ◌ dotted circle */
.status-approved::before    { content: "\2713"; }   /* ✓ legacy */
.status-awarded::before     { content: "\2713"; }   /* ✓ check — bid won */
.status-not_awarded::before { content: "\25CC"; }   /* ◌ dotted circle — bid done */
.status-draft::before       { content: "\22EF"; }   /* ⋯ ellipsis */
.status-sent::before        { content: "\2192"; }   /* → arrow */
.status-paid::before        { content: "\2713"; }   /* ✓ */
.status-draft { background: rgba(26,46,61,.10); color: rgba(26,46,61,.7); }
.status-sent  { background: rgba(201,122,0,.14);  color: #c97a00; }
.status-paid  { background: rgba(40,140,80,.14);  color: #287850; }

/* Global max-width for the main admin app views. Keeps content
   readable on wide monitors (lists don't stretch arbitrarily, form
   shells don't float in space) without affecting the lock screens.
   The estimate + invoice form's inner .setup-body still caps at
   920px for the paper-document feel — it sits centered inside the
   1200px shell. */
#view-dashboard,
#view-estimates,
#view-invoices,
#view-clients,
#view-projects,
#view-overview,
#view-reports,
#view-from-estimate,
#view-job-form,
#view-estimate-form,
#view-invoice-form,
#view-client-form,
#view-project-form {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 28px;
}
/* The list-toolbar already handles its own horizontal padding
   internally, so zero out the section padding when it's wrapping. */
#view-invoices .est-list-toolbar,
#view-clients  .est-list-toolbar,
#view-projects .est-list-toolbar,
#view-overview .est-list-toolbar,
#view-estimates .est-list-toolbar {
  padding-left: 0;
  padding-right: 0;
}

/* Invoice list container — block layout (vertical stack of rows),
   NOT the card-grid layout the .est-grid class provides. Each row is
   a full-width grid that distributes its own columns. */
.inv-grid {
  display: block;
}

/* Invoice list table */
.inv-row {
  display: grid;
  /* Checkbox | Invoice # | Project (wide) | Client | Date | Status | Amount | Actions
     Actions column is sized for 3 buttons (Send Invoice + Mark Paid + Delete). */
  grid-template-columns: 28px 110px minmax(0, 2.2fr) minmax(0, 1fr) 90px 80px 110px 240px;
  gap: 14px;
  align-items: center;
  padding: 11px 14px;
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 4px;
  margin-bottom: 6px;
  font-size: 11.5px;
  color: var(--navy);
}
/* Grid cells default to min-width: auto, which is the content's
   intrinsic minimum width. When content is wider than the column
   allocation, the cell bullies neighbors out of place. Forcing
   min-width: 0 makes the column width authoritative — content
   either truncates or wraps but never displaces other cells. */
.inv-row > * { min-width: 0; }
.inv-row-head {
  background: transparent;
  border: none;
  font-size: 9px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  padding: 4px 14px;
  margin-bottom: 0;
}
.inv-row.is-clickable {
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.inv-row.is-clickable:hover {
  background: #faf8f2;
  border-color: rgba(26,46,61,.18);
}
.inv-row .inv-num { text-align: right; font-variant-numeric: tabular-nums; }
/* Invoice number reads as a link so the click affordance is obvious */
.inv-cell-num {
  font-weight: 600;
  color: #2e6da4;
  text-decoration: underline;
  text-decoration-color: rgba(46,109,164,.4);
  text-underline-offset: 2px;
}
.inv-row.is-clickable:hover .inv-cell-num { text-decoration-color: #2e6da4; }
.inv-cell-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.inv-actions { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: nowrap; }
.inv-actions .btn-ghost {
  padding: 4px 9px;
  font-size: 9.5px;
  letter-spacing: 0.6px;
  white-space: nowrap;
}

.inv-grand-total {
  display: flex; justify-content: flex-end; align-items: baseline;
  gap: 16px; padding: 14px 14px 0;
  font-size: 11px; color: rgba(26,46,61,.6);
}
.inv-grand-amount {
  font-size: 14px; font-weight: 700; color: var(--navy);
  font-variant-numeric: tabular-nums;
}

/* Invoice form line items grid */
.inv-form-row {
  display: grid;
  grid-template-columns: 110px 1fr 100px 80px 110px 36px;
  gap: 8px;
  align-items: center;
  padding: 6px 0;
  border-bottom: 1px dashed rgba(26,46,61,.08);
}
.inv-form-head {
  font-size: 9px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase; color: rgba(26,46,61,.55);
  border-bottom: 1px solid rgba(26,46,61,.18);
  padding-bottom: 6px;
}
.inv-form-row .inv-num { text-align: right; }
.inv-num-input { text-align: right; }
.inv-line-total { font-variant-numeric: tabular-nums; }
.btn-row-del {
  background: none; border: none; cursor: pointer;
  font-size: 16px; color: rgba(26,46,61,.4);
  padding: 0 4px; line-height: 1;
}
.btn-row-del:hover { color: #c0392b; }

/* Client list table */
.cli-grid { padding: 0; }
.cli-row {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.2fr) minmax(0, 1.4fr) 100px 100px 110px;
  gap: 12px;
  align-items: center;
  padding: 11px 14px;
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 4px;
  margin-bottom: 6px;
  font-size: 11.5px;
  color: var(--navy);
  cursor: pointer;
}
.cli-row > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cli-row-head > * { white-space: nowrap; }
.cli-row[data-action="open"]:hover { background: #faf8f2; }
.cli-row-head {
  background: transparent; border: none; cursor: default;
  font-size: 9px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  padding: 4px 14px;
  margin-bottom: 0;
}
.cli-row-head:hover { background: transparent; }
.cli-num { text-align: right; font-variant-numeric: tabular-nums; }
.cli-cell-name { font-weight: 600; }

/* Client detail screen */
.cli-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}
.cli-stat {
  flex: 1;
  min-width: 130px;
  display: flex; flex-direction: column;
  background: #faf8f2;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 4px;
  padding: 10px 12px;
}
.cli-stat-label {
  font-size: 9px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  margin-bottom: 4px;
}
.cli-stat-value {
  font-size: 16px; font-weight: 700; color: var(--navy);
  font-variant-numeric: tabular-nums;
}
.cli-summary-empty {
  font-size: 11px; color: rgba(26,46,61,.55);
  font-style: italic; padding: 8px 0;
}

.cli-detail-tabs {
  display: flex; gap: 0;
  border-bottom: 1px solid rgba(26,46,61,.18);
  margin-bottom: 12px;
}
.cli-detail-tab {
  background: none; border: none; cursor: pointer;
  font-family: var(--font);
  font-size: 10.5px; font-weight: 600; letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  padding: 8px 14px;
  border-bottom: 2px solid transparent;
  transition: color .12s, border-color .12s;
}
.cli-detail-tab:hover    { color: var(--navy); }
.cli-detail-tab.is-active{ color: var(--navy); border-bottom-color: var(--navy); }

.cli-detail-list { font-size: 11.5px; color: var(--navy); }
.cli-detail-row {
  display: grid;
  grid-template-columns: 130px minmax(0, 1fr) 100px 80px 100px;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px dashed rgba(26,46,61,.08);
}
.cli-detail-row > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cli-detail-row.is-clickable {
  cursor: pointer;
  border-radius: 3px;
  padding-left: 6px;
  padding-right: 6px;
  margin-left: -6px;
  margin-right: -6px;
  transition: background .12s;
}
.cli-detail-row.is-clickable:hover { background: #faf8f2; }
.cli-detail-num {
  color: #2e6da4;
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: rgba(46,109,164,.4);
  text-underline-offset: 2px;
}
.cli-detail-row.is-clickable:hover .cli-detail-num {
  text-decoration-color: #2e6da4;
}
.cli-detail-row[grid-template-columns] { display: grid; }   /* keep override */
.cli-detail-row.cli-detail-row-head {
  font-size: 9px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase; color: rgba(26,46,61,.55);
  border-bottom: 1px solid rgba(26,46,61,.18);
}

/* Client typeahead floating panel (shared by estimate + invoice forms) */
.client-typeahead-panel {
  position: absolute;
  background: #fff;
  border: 1px solid rgba(26,46,61,.18);
  border-radius: 4px;
  box-shadow: 0 8px 22px rgba(10,50,84,.18);
  font-family: var(--font);
  font-size: 11.5px;
  color: var(--navy);
  z-index: 9999;
  max-height: 240px;
  overflow-y: auto;
}
.client-typeahead-row {
  padding: 8px 12px;
  cursor: pointer;
  border-bottom: 1px solid rgba(26,46,61,.06);
}
.client-typeahead-row:last-child { border-bottom: none; }
.client-typeahead-row:hover,
.client-typeahead-row.is-active { background: #faf8f2; }
.client-typeahead-name    { font-weight: 600; }
.client-typeahead-company { font-size: 10px; color: rgba(26,46,61,.55); margin-top: 1px; }

/* Empty state for the sections list */
.est-empty-sections {
  padding: 24px;
  text-align: center;
  background: #f9f7f2;
  border: 1px dashed rgba(26,46,61,.18);
  border-radius: 4px;
  font-size: 11px;
  color: rgba(26,46,61,.55);
  margin-bottom: 12px;
}

/* ── Deck-import review banner ───────────────────────────────────
   Yellow callout pinned to the top of the estimate-form view when
   the deck analyzer flagged things worth a human glance — edit-only
   groups, complex VFX, V2 cuts, language versioning. Cleared on
   save and when opening an already-saved estimate. */
.est-review-banner {
  background: #fef7e0;
  border: 1px solid #e9c46a;
  border-left: 4px solid #d99e2b;
  border-radius: 4px;
  padding: 12px 16px 14px;
  margin-bottom: 18px;
  color: #5a4413;
  font-family: var(--font);
}
.est-review-banner[hidden] { display: none; }
.est-review-banner-title {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: #8a6a1c;
  margin-bottom: 6px;
}
.est-review-banner-list {
  margin: 0; padding: 0 0 0 18px; list-style: disc;
  font-size: 11.5px; line-height: 1.55;
}
.est-review-banner-list li { margin-bottom: 4px; }
.est-review-banner-list li:last-child { margin-bottom: 0; }

/* ── From Estimate wizard: "or" divider between PDF drop and
   the saved-estimates dropdown. */
.fe-or-divider {
  display: flex; align-items: center;
  margin: 14px 0 10px;
  color: rgba(26,46,61,.45);
  font-size: 10px; font-weight: 700; letter-spacing: 2px;
  text-transform: uppercase;
}
.fe-or-divider::before,
.fe-or-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: rgba(26,46,61,.14);
}
.fe-or-divider span {
  padding: 0 12px;
}

/* ── Deck Analyzer: paste-screenshot zone ───────────────────────
   Click-to-focus zone inside the paste modal. Users press Cmd+V
   to paste a screenshot; the empty/filled states mirror the
   existing FreshBooks PDF drop zone styling so the two flows feel
   like siblings. */
.deck-paste-zone {
  border: 2px dashed rgba(26,46,61,.28);
  border-radius: 6px;
  background: #fbfaf6;
  min-height: 180px;
  display: flex; align-items: center; justify-content: center;
  cursor: text;
  transition: border-color .12s, background .12s;
  outline: none;
}
.deck-paste-zone:focus,
.deck-paste-zone:hover {
  border-color: var(--navy);
  background: #f6f3eb;
}
.deck-paste-zone.is-dragover { border-color: var(--navy); background: #eee9d9; }

.deck-paste-empty,
.deck-paste-filled { width: 100%; padding: 18px; text-align: center; }
.deck-paste-zone.is-filled .deck-paste-empty  { display: none; }
.deck-paste-zone:not(.is-filled) .deck-paste-filled { display: none; }

.deck-paste-icon {
  display: inline-block;
  background: var(--navy); color: var(--beige);
  font-size: 11px; font-weight: 700; letter-spacing: 2px;
  padding: 6px 12px; border-radius: 4px;
  margin-bottom: 12px;
}
.deck-paste-text {
  font-size: 12px; color: var(--navy);
  margin-bottom: 4px;
}
.deck-paste-sub {
  font-size: 10.5px; color: rgba(26,46,61,.55);
}

.deck-paste-filled img {
  max-width: 100%;
  max-height: 220px;
  border-radius: 4px;
  border: 1px solid rgba(26,46,61,.18);
  display: block; margin: 0 auto 10px;
  background: #fff;
}
.deck-paste-meta {
  display: flex; align-items: center; justify-content: center;
  gap: 12px;
  font-size: 11px; color: rgba(26,46,61,.65);
}

/* ── Deck Analyzer: progress overlay ────────────────────────────
   Full-screen scrim while Claude is working through the deck. The
   inner card is centered and uses the same beige/navy palette as
   the rest of the admin tools. */
.deck-progress {
  position: fixed; inset: 0;
  background: rgba(26,46,61,.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 9999;
  backdrop-filter: blur(2px);
}
.deck-progress[hidden] { display: none; }

.deck-progress-card {
  background: var(--beige);
  color: var(--navy);
  width: 360px;
  max-width: calc(100vw - 32px);
  padding: 28px 28px 22px;
  border-radius: 6px;
  box-shadow: 0 16px 40px rgba(10,50,84,.32);
  text-align: center;
  font-family: var(--font);
}
.deck-progress-spinner {
  width: 36px; height: 36px;
  border: 3px solid rgba(26,46,61,.15);
  border-top-color: var(--navy);
  border-radius: 50%;
  margin: 0 auto 16px;
  animation: deck-spin 0.85s linear infinite;
}
@keyframes deck-spin {
  to { transform: rotate(360deg); }
}
.deck-progress-title {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 6px;
}
.deck-progress-status {
  font-size: 12px;
  color: var(--navy);
  margin-bottom: 12px;
  min-height: 16px;
}
.deck-progress-hint {
  font-size: 10.5px;
  color: rgba(26,46,61,.6);
  line-height: 1.55;
  margin: 0;
}

/* ────────────────────────────────────────────────────────────
   PHASE 3: DASHBOARD ("overview" tab) + PROJECTS tab
   ──────────────────────────────────────────────────────────── */

/* ── Status pills — extra colors for project + estimate states ── */
.status-active      { background: rgba(31,93,153,.13);  color: #1f5d99; }
.status-delivered   { background: rgba(29,111,73,.13);  color: #1d6f49; }
.status-archived    { background: rgba(26,46,61,.10);   color: rgba(26,46,61,.55); }
/* Estimate vocabulary: awarded = bid won (green), not_awarded =
   bid lost (muted dark — not a failure state, just done). */
.status-awarded     { background: rgba(40,140,80,.14);  color: #287850; }
.status-not_awarded { background: rgba(26,46,61,.10);   color: rgba(26,46,61,.55); }
/* Legacy class kept for any stale markup; same color as awarded. */
.status-approved    { background: rgba(40,140,80,.14);  color: #287850; }

/* ── Dashboard (overview) ─────────────────────────────────── */
.ov-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 20px;
}
.ov-grid.ov-grid-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }

/* Today's schedule — sits between briefing and stat cards.
   Aggregates events spanning today across all active projects'
   linked calendars. Each event row uses the activity's color as
   a left-edge stripe; clicking the row opens the underlying
   project. Hidden when no events match today. */
.ov-today-cal {
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 8px;
  padding: 16px 20px 18px;
  margin-bottom: 20px;
  box-shadow: 0 1px 2px rgba(26,46,61,.05);
}
.ov-today-cal-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 12px;
}
.ov-today-cal-eyebrow {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--navy);
  opacity: 0.6;
}
.ov-today-cal-date {
  font-size: 11px;
  color: rgba(26,46,61,.55);
  font-style: italic;
}
.ov-today-cal-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
/* Event row — pill-style bar with the activity color as a 4px
   left-edge stripe so the type signal is unmistakable. Faint
   wash of the activity color across the bar adds depth. */
.ov-today-cal-event {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px 10px 18px;
  background: color-mix(in srgb, var(--ev-color, var(--navy)) 8%, #fff);
  border: 1px solid color-mix(in srgb, var(--ev-color, var(--navy)) 22%, transparent);
  border-radius: 6px;
  color: var(--navy);
  font-family: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, transform .12s ease;
}
.ov-today-cal-event::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 4px;
  background: var(--ev-color, var(--navy));
  border-top-left-radius: 6px;
  border-bottom-left-radius: 6px;
}
.ov-today-cal-event:hover {
  background: color-mix(in srgb, var(--ev-color, var(--navy)) 14%, #fff);
  border-color: color-mix(in srgb, var(--ev-color, var(--navy)) 38%, transparent);
  transform: translateY(-1px);
}
.ov-today-cal-event.is-milestone {
  background: color-mix(in srgb, var(--ev-color, var(--navy)) 14%, #fff);
  border-color: color-mix(in srgb, var(--ev-color, var(--navy)) 34%, transparent);
}
.ov-today-cal-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  font-size: 11px;
  color: var(--ev-color, var(--navy));
  flex-shrink: 0;
}
.ov-today-cal-label {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.ov-today-cal-sep {
  opacity: 0.4;
  flex-shrink: 0;
}
.ov-today-cal-project {
  opacity: 0.7;
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1 1 auto;
}

/* Mobile: tighter padding, allow event row to wrap label + project
   across two lines if needed so neither truncates aggressively. */
@media (max-width: 720px) {
  .ov-today-cal { padding: 14px 16px 16px; }
  .ov-today-cal-event {
    flex-wrap: wrap;
    padding: 10px 12px 10px 16px;
  }
  .ov-today-cal-sep { display: none; }
  .ov-today-cal-project { flex-basis: 100%; }
}

/* Morning briefing card — pulls from /morning_briefings/{today}.
   Sits above the stat cards as a quiet "here's your day" preface.
   Uses a slightly different surface (beige tint) than the stat
   cards so it reads as a different KIND of content — narrative
   summary rather than a number to scan. */
.ov-briefing {
  position: relative;
  background: linear-gradient(135deg, #fbf8f1 0%, #f5f1e6 100%);
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 8px;
  padding: 18px 22px 18px 26px;
  margin-bottom: 20px;
  box-shadow: 0 1px 2px rgba(26,46,61,.05);
  overflow: hidden;
}
.ov-briefing::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 3px;
  background: var(--navy);
  opacity: .85;
}
.ov-briefing-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 10px;
}
.ov-briefing-head-left {
  display: flex;
  align-items: baseline;
  gap: 14px;
  min-width: 0;
}
.ov-briefing-eyebrow {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--navy);
  opacity: 0.6;
}
.ov-briefing-date {
  font-size: 11px;
  color: rgba(26,46,61,.55);
  font-style: italic;
}
/* Collapse toggle — small chevron button, rotates when collapsed
   so the affordance is obvious. Sits top-right of the briefing
   card head. */
.ov-briefing-toggle {
  background: none;
  border: 1px solid var(--border);
  border-radius: 50%;
  width: 26px;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--navy);
  transition: background-color .15s ease, border-color .15s ease, transform .2s ease;
  flex-shrink: 0;
}
.ov-briefing-toggle:hover {
  background: rgba(26,46,61,.06);
  border-color: rgba(26,46,61,.22);
}
.ov-briefing-toggle svg { display: block; }
.ov-briefing.is-collapsed .ov-briefing-toggle svg {
  transform: rotate(-90deg);
  transition: transform .2s ease;
}

/* Chips — small navigation strip for the last N days. Today is
   highlighted; days without a briefing are disabled. */
.ov-briefing-chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.ov-briefing-chip {
  background: rgba(255,255,255,0.55);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 10px;
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .3px;
  color: var(--navy);
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.ov-briefing-chip:hover {
  background: #fff;
  border-color: rgba(26,46,61,.22);
}
.ov-briefing-chip.is-selected {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--beige);
}
.ov-briefing-chip.is-empty,
.ov-briefing-chip[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
  background: transparent;
}

/* Picker = chip-button with a caret + an absolutely-positioned
   dropdown of past days. Replaces the old row-of-7-chips strip. */
.ov-briefing-picker {
  position: relative;
  display: inline-flex;
}
.ov-briefing-select {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.ov-briefing-caret {
  font-size: 9px;
  line-height: 1;
  opacity: 0.7;
}
.ov-briefing-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  background: #fff;
  border: 1px solid rgba(26,46,61,.12);
  border-radius: 6px;
  box-shadow: 0 6px 18px rgba(26,46,61,.10);
  padding: 4px;
  min-width: 150px;
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.ov-briefing-menu-item {
  background: transparent;
  border: 0;
  text-align: left;
  padding: 6px 10px;
  border-radius: 4px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .2px;
  color: var(--navy);
  cursor: pointer;
  white-space: nowrap;
}
.ov-briefing-menu-item:hover {
  background: rgba(26,46,61,.06);
}
.ov-briefing-menu-item.is-selected {
  background: var(--navy);
  color: var(--beige);
}

/* Collapsed state: hide chips + body, keep just the head row so
   the card becomes a slim bar. Smooth height collapse via the
   :not selector on body / chips for max-height transition. */
.ov-briefing.is-collapsed .ov-briefing-body,
.ov-briefing.is-collapsed .ov-briefing-chips {
  display: none;
}
.ov-briefing.is-collapsed { padding-bottom: 14px; padding-top: 14px; }
.ov-briefing.is-collapsed .ov-briefing-head { margin-bottom: 0; }
.ov-briefing-body {
  font-size: 13px;
  line-height: 1.55;
  color: var(--navy);
}
.ov-briefing-para {
  margin-bottom: 10px;
}
.ov-briefing-para:last-child { margin-bottom: 0; }
.ov-briefing-line {
  word-wrap: break-word;
}
/* The first line of a multi-line paragraph reads as a tighter
   lead (slightly heavier, smaller letter-spacing) so section
   headers like "WEATHER" or "CALENDAR" anchor the chunk below. */
.ov-briefing-line.is-lead {
  font-weight: 600;
  margin-bottom: 2px;
  letter-spacing: -0.005em;
}

@media (max-width: 720px) {
  .ov-briefing { padding: 14px 16px 14px 20px; }
  .ov-briefing-head { flex-wrap: wrap; gap: 6px; }
}

/* Stat card — three layers of treatment to lift it off the page:
   1) White surface w/ subtle border + box-shadow (depth).
   2) Top inner-glow strip (1px lighter line at the top edge) so
      the card feels lit from above instead of flat.
   3) Left-edge accent stripe colored by data-accent. Same pattern
      as the project sheet's left-edge accent — keeps the visual
      vocabulary consistent across the suite. */
.ov-stat-card {
  position: relative;
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 8px;
  padding: 18px 18px 16px 18px;
  box-shadow: 0 1px 2px rgba(26,46,61,.05);
  /* overflow:hidden removed so the formula tooltip (rendered as
     ::after) can extend below the card. The inner-glow gradient now
     clips itself via its own border-radius below. */
}
/* Inner glow at the top edge — sits inside the border via ::before
   so the card reads as having material/light source. border-radius
   matches the card's top corners so the glow stays inside the
   rounded outline without needing overflow:hidden on the parent. */
.ov-stat-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 36px;
  border-radius: 8px 8px 0 0;
  background: linear-gradient(180deg, rgba(255,255,255,.65) 0%, rgba(255,255,255,0) 100%);
  pointer-events: none;
}
/* Left-edge accent stripe removed — kept data-accent attributes in
   the markup in case we want to reintroduce a softer visual cue
   (e.g., tinted value text) later, but the stripe itself is gone. */

.ov-stat-card.is-clickable { cursor: pointer; }
/* hover lift is supplied by the shared motion block — keep border
   transition local so it animates alongside the lift. */
.ov-stat-card.is-clickable:hover { border-color: rgba(26,46,61,.18); }

.ov-stat-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: rgba(26,46,61,.6);
  margin-bottom: 10px;
}
.ov-stat-value {
  font-size: 26px;
  font-weight: 700;
  color: var(--navy);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
  line-height: 1.05;
  position: relative;     /* keeps text above ::before glow */
}
.ov-stat-sub {
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
  margin-top: 8px;
  position: relative;
}

/* Tiny sparkline that lives inside the Today's Earnings card.
   Empty by default; populated by dashboard.js into an existing
   <svg> element. The 100×24 viewBox is normalized so the path
   coordinates can run 0–100 horizontally. */
.ov-stat-spark {
  display: block;
  width: 100%;
  height: 22px;
  margin-top: 10px;
  overflow: visible;
  position: relative;
}
.ov-stat-spark path {
  fill: none;
  stroke: var(--navy);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.75;
}
.ov-stat-spark .ov-stat-spark-fill {
  fill: rgba(26,46,61,.06);
  stroke: none;
}
.ov-stat-spark .ov-stat-spark-dot {
  fill: var(--navy);
}

.ov-twocol {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 16px;
  margin-bottom: 28px;
}
.ov-panel {
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 6px;
  padding: 16px 18px 18px;
}
.ov-panel-head {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  border-bottom: 1px solid rgba(26,46,61,.08);
  padding-bottom: 8px;
  margin-bottom: 10px;
}
.ov-empty {
  padding: 12px 4px;
}

/* ── To-do panel ─────────────────────────────────────────────
   Lives at the top of the dashboard, between action callouts and
   the morning briefing. Manual list — Joel adds and ticks off
   tasks. Each row: checkbox + text + ×. Click the text to edit
   inline. Completed rows fade and collapse behind a toggle. */
.ov-todos {
  margin-bottom: 12px;
}
.ov-todos-empty {
  padding: 8px 2px 12px;
}
.ov-todos-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.ov-todo-row {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr) 24px;
  align-items: center;
  gap: 8px;
  padding: 6px 4px;
  border-radius: 4px;
  transition: background .12s;
}
.ov-todo-row:hover { background: var(--hover-tint); }
.ov-todo-check {
  background: transparent;
  border: 0;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ov-todo-check-box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1.5px solid rgba(26,46,61,.3);
  color: var(--navy);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  background: #fff;
  transition: border-color .12s, background .12s;
}
.ov-todo-check:hover .ov-todo-check-box { border-color: var(--navy); }
.ov-todo-row.is-done .ov-todo-check-box {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--beige);
}
.ov-todo-text {
  font-size: 13px;
  color: var(--navy);
  cursor: text;
  line-height: 1.45;
  outline: none;
  overflow-wrap: anywhere;
}
.ov-todo-row.is-done .ov-todo-text {
  color: rgba(26,46,61,.45);
  text-decoration: line-through;
}
.ov-todo-edit-input {
  width: 100%;
  font: inherit;
  color: inherit;
  padding: 2px 4px;
  border: 1px solid rgba(26,46,61,.2);
  border-radius: 3px;
  background: #fff;
}
.ov-todo-del {
  background: transparent;
  border: 0;
  color: rgba(26,46,61,.4);
  font-size: 14px;
  cursor: pointer;
  border-radius: 50%;
  padding: 2px 6px;
  opacity: 0;
  transition: opacity .12s, color .12s, background .12s;
}
.ov-todo-row:hover .ov-todo-del { opacity: 1; }
.ov-todo-del:hover { color: #b03b3b; background: rgba(176,59,59,.08); }

.ov-todos-add {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed rgba(26,46,61,.08);
}
.ov-todos-add .text-input {
  font-size: 12.5px;
}

.ov-todos-toggle {
  background: none;
  border: 0;
  color: rgba(26,46,61,.55);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .4px;
  cursor: pointer;
  padding: 6px 4px;
  margin-top: 4px;
}
.ov-todos-toggle:hover { color: var(--navy); }
.ov-todos-completed {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Frame.io "Client Feedback" panel — one row per linked project,
   click-through opens the Frame.io project in a new tab. */
#ov-frameio-panel { margin-bottom: 28px; }
.ov-frameio-list {
  display: flex;
  flex-direction: column;
}
.ov-frameio-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 4px;
  text-decoration: none;
  color: var(--navy);
  border-bottom: 1px solid rgba(26,46,61,.06);
  transition: background-color .12s ease;
}
.ov-frameio-row:last-child { border-bottom: 0; }
.ov-frameio-row:hover { background: rgba(26,46,61,.03); }
.ov-frameio-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--navy);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ov-frameio-count {
  font-size: 12px;
  font-weight: 700;
  color: #a93226;
  letter-spacing: .2px;
  white-space: nowrap;
}
.ov-frameio-err {
  font-size: 11px;
  color: rgba(26,46,61,.5);
}

/* Revenue table */
.ov-rev-row {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(60px, 1fr) 100px;
  gap: 12px;
  align-items: center;
  padding: 7px 4px;
  font-size: 11.5px;
  color: var(--navy);
}
.ov-rev-row[data-client] { cursor: pointer; }
.ov-rev-row[data-client]:hover { background: rgba(26,46,61,.04); border-radius: 4px; }
.ov-rev-head {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  padding: 4px 4px 6px;
  border-bottom: 1px dashed rgba(26,46,61,.1);
}
.ov-rev-client {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 600;
}
.ov-rev-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.ov-rev-bar {
  height: 6px;
  background: rgba(26,46,61,.06);
  border-radius: 3px;
  overflow: hidden;
}
.ov-rev-bar-fill {
  height: 100%;
  background: var(--navy);
  border-radius: 3px;
}

/* Recent activity */
.ov-activity-row {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr) 90px 90px;
  gap: 12px;
  align-items: center;
  padding: 9px 4px;
  border-bottom: 1px dashed rgba(26,46,61,.08);
  font-size: 11.5px;
  color: var(--navy);
  cursor: pointer;
  transition: background .12s;
}
.ov-activity-row:last-child { border-bottom: none; }
.ov-activity-row:hover { background: #faf8f2; }
.ov-activity-kind {
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
}
.ov-activity-main { min-width: 0; }
.ov-activity-title {
  font-weight: 600;
  color: #2e6da4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ov-activity-sub {
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  margin-top: 2px;
}
.ov-activity-pill { text-align: center; }
.ov-activity-date {
  text-align: right;
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
  font-variant-numeric: tabular-nums;
}

/* ── Projects list ────────────────────────────────────────── */
.prj-grid { display: block; }

/* Active projects render as cards (5-10 typical) instead of rows.
   Card grid sits above the row table; cards lead with the two
   numbers that matter for in-flight work — Tracked and Outstanding —
   and have a left-edge accent stripe matching the project's color
   (same vocabulary as the project sheet). */
.prj-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}
.prj-card {
  position: relative;
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 8px;
  padding: 16px 18px 14px 18px;
  box-shadow: 0 1px 2px rgba(26,46,61,.05);
  cursor: pointer;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* Baseline height so sparse Active cards aren't dwarfed by data-
     heavy Delivered cards in the same row. With align-items:stretch
     on the grid, cards in a row equalize to the tallest — the min
     just prevents collapse on a sub-default row. */
  min-height: 168px;
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
/* Overdue accent — when ANY unpaid linked invoice's due_date is in
   the past, paint a thin red rule on the card's left edge so the
   project pops at a glance. */
.prj-card.is-overdue {
  border-left: 3px solid #b03a2a;
  padding-left: 15px;
}
/* Subtle lift on hover — clarifies the card is interactive without
   adding visual weight to the resting state. */
.prj-card:hover {
  border-color: rgba(26,46,61,.18);
  box-shadow: 0 4px 14px rgba(26,46,61,.08);
  transform: translateY(-1px);
}
/* Per-card "Edit" affordance — only shown on Active cards, parked
   in the bottom-right corner where the card has spare whitespace. */
.prj-card-edit {
  position: absolute;
  right: 12px;
  bottom: 10px;
  background: transparent;
  border: 1px solid rgba(26,46,61,.18);
  color: rgba(26,46,61,.65);
  font-family: var(--font);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 12px;
  cursor: pointer;
  opacity: 0;
  transition: opacity .14s, color .14s, border-color .14s, background .14s;
  z-index: 2;
}
.prj-card:hover .prj-card-edit { opacity: 1; }
.prj-card-edit:hover {
  background: var(--navy);
  color: var(--beige);
  border-color: var(--navy);
}
/* Inner-glow at the top edge — adds material/depth. */
.prj-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 32px;
  background: linear-gradient(180deg, rgba(255,255,255,.6) 0%, rgba(255,255,255,0) 100%);
  pointer-events: none;
}
.prj-card > * { position: relative; }    /* sit above the ::before glow */
/* Override — the Edit affordance is intentionally absolute-positioned
   in the bottom-right corner. The blanket rule above would force it
   back into the document flow. */
.prj-card > .prj-card-edit { position: absolute; }

.prj-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 20px;
}
.prj-card-head .status-pill {
  font-size: 8px;
  letter-spacing: 1.1px;
  padding: 2px 7px;
}
/* Project ID — sans now (was mono). Mono caused a baseline mismatch
   with the sans client name across the · separator. Keep the small,
   muted treatment so it reads as label, not chip. */
.prj-card-pid {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .3px;
  color: rgba(26,46,61,.55);
}
/* Small colored dot at the start of the meta line, keyed off the
   card's --prj-color. Lightweight identifier that lets the eye map
   "this color = this project" without painting a heavy edge stripe. */
.prj-card-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--prj-color, #888);
  flex-shrink: 0;
  align-self: center;
  margin-right: 2px;
}
.prj-card-name {
  /* Inline size set per-card via --name-size (17/15/13 thresholds)
     so long names shrink to one line instead of wrapping. */
  font-size: var(--name-size, 17px);
  font-weight: 600;
  letter-spacing: -0.2px;
  line-height: 1.25;
  color: var(--navy);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prj-card-meta {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.prj-card-meta-sep {
  color: rgba(26,46,61,.3);
  font-size: 11px;
}
.prj-card-client {
  font-size: 12px;
  color: rgba(26,46,61,.6);
}
.prj-card-money {
  display: grid;
  /* auto-fit lets the row collapse to a single column when a card
     only has Tracked (no invoices yet → Outstanding cell omitted).
     With two cells, splits 50/50 once each can reach 120px. */
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 14px;
  padding: 6px 0 4px;
  /* hairline above removed — whitespace alone separates this from
     the meta line + name; the rule was just visual noise. */
}
.prj-card-money-label {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  margin-bottom: 4px;
}
.prj-card-money-value {
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--navy);
  letter-spacing: -0.01em;
}
.prj-card-money-value.is-emphasized {
  color: #a02c1e;          /* dark red = "attention" — money owed */
  font-size: 19px;         /* the chase-money number is the headline
                              of any Delivered card — go a touch
                              larger than the project name */
}
/* Wraps the Outstanding amount + optional DUE chip on one baseline. */
.prj-card-money-line {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}
.prj-card-due {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.2px;
  color: rgba(26,46,61,.5);
  white-space: nowrap;
}
.prj-card-due.is-overdue {
  color: #b03a2a;
}
.prj-card-money-value.is-empty {
  color: rgba(26,46,61,.4);
  font-style: italic;
  font-weight: 500;
  font-size: 13px;
  letter-spacing: normal;
}
.prj-card-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding-top: 4px;
  /* Pin pills to the bottom of the card. Cards in the same row
     equalize to the tallest one (grid stretches by default), so
     pushing the pills down with margin-top:auto means every card's
     pill row lines up with its neighbors regardless of inner
     content height. */
  margin-top: auto;
}
.prj-card-pills .prj-link-pill { font-size: 9px; padding: 3px 7px; }

@media (max-width: 720px) {
  .prj-card-grid { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .prj-card { padding: 14px 16px 12px 20px; }
  .prj-card-name { font-size: 15px; }
}

.prj-row {
  display: grid;
  /* Project (wide) | Client | Status | Linked | Tracked | Billed | Outstanding */
  grid-template-columns: minmax(0, 2.4fr) minmax(0, 1fr) 80px 170px 100px 100px 110px;
  gap: 14px;
  align-items: center;
  padding: 11px 14px;
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 4px;
  margin-bottom: 6px;
  font-size: 11.5px;
  color: var(--navy);
}
/* Two-line project cell: name on top, project ID beneath as a muted
   typographic sibling (no chip box). */
.prj-cell-name-block { min-width: 0; }
.prj-cell-id-sub {
  margin-top: 2px;
  font-size: 10px;
  letter-spacing: .4px;
  font-weight: 500;
  color: rgba(26,46,61,.5);
  font-variant-numeric: tabular-nums;
}
.prj-row.is-clickable:hover .prj-cell-id-sub { color: rgba(26,46,61,.7); }
.prj-row > * { min-width: 0; }
.prj-row-head {
  background: transparent;
  border: none;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  padding: 4px 14px;
  margin-bottom: 0;
}
.prj-row.is-clickable {
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.prj-row.is-clickable:hover {
  background: #faf8f2;
  border-color: rgba(26,46,61,.18);
}
.prj-cell-name {
  font-weight: 600;
  color: #2e6da4;
  text-decoration: underline;
  text-decoration-color: rgba(46,109,164,.4);
  text-underline-offset: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.prj-row.is-clickable:hover .prj-cell-name { text-decoration-color: #2e6da4; }
.prj-cell-truncate {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.prj-cell-icons {
  display: flex;
  gap: 4px;
}
.prj-link-pill {
  display: inline-block;
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  padding: 3px 6px;
  border-radius: 3px;
  background: rgba(26,46,61,.06);
  color: rgba(26,46,61,.35);
  line-height: 1;
}
.prj-link-pill.is-on {
  background: rgba(46,109,164,.14);
  color: #2e6da4;
}
.prj-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* "Not invoiced" placeholder inside a numeric column. Muted +
   italic so it reads as "intentionally blank" rather than "the
   number happens to be zero." */
.prj-num-empty {
  color: rgba(26,46,61,.4);
  font-style: italic;
  font-weight: 500;
}
/* Outstanding dollar value when there's a balance owed — dark
   red (replacing the muted gold) for stronger "needs attention"
   signal. */
.prj-num-outstanding {
  color: #a02c1e;
}

/* ── Project form ─────────────────────────────────────────── */
.prj-link-grid {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.prj-link-row {
  display: grid;
  /* Fixed-width action column so the button column lines up cleanly
     across rows regardless of which row carries Open/Unlink, +Create,
     Open ↗, or nothing. 160px fits "[OPEN] [UNLINK]" without wrapping. */
  grid-template-columns: 100px minmax(0, 1fr) 160px;
  gap: 12px;
  align-items: center;
  padding: 12px 14px;
  background: rgba(26,46,61,.025);
  border: 1px solid rgba(26,46,61,.06);
  border-radius: 4px;
}
.prj-link-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  flex-wrap: nowrap;
}
.prj-link-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  display: flex;
  align-items: center;
  gap: 5px;
}
/* Subtle "linked" indicator — a small green check appears next to
   the slot's label when something is linked there. Reads as a
   passive at-a-glance status, not a button. Toggled by JS. */
.prj-link-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: #4baf5a;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0;
}
.prj-link-check[hidden] { display: none; }
.prj-link-body { min-width: 0; }
.prj-link-pick { width: 100%; }

/* Calendar row gets a stacked body so both Internal + External
   sub-inputs fit in the same Linked Documents slot. The row's
   alignment switches from center to start so the label sits at
   the top edge of the two stacked rows. */
.prj-link-row-calendar { align-items: start; }
.prj-link-row-calendar .prj-link-label { padding-top: 6px; }
/* Music License row is also stacked (1..N rows + an "+ Add another"
   button below them). Match Calendar's top alignment so the label
   sits flush with the first input. */
.prj-link-row-music { align-items: start; }
.prj-link-row-music .prj-link-label { padding-top: 6px; }
/* The music row's body holds 1..N rows of [input | notes? | Open].
   Use display: contents on the body wrapper so its children (the
   per-license rows + the +Add button) participate directly in the
   parent grid. That lets each music row span body+actions columns
   so the Open ↗ button right-aligns to the SAME x-coord as every
   other row's action button (100px slot at the right edge). */
.prj-link-row-music > .prj-link-body { display: contents; }
.prj-link-row-music > .prj-link-actions { display: none; }
.prj-music-row {
  grid-column: 2 / 4;          /* span body + 12px gap + actions */
  display: grid;
  gap: 8px;
  align-items: center;
}
/* Three layouts:
     edit    — single URL input that becomes a link on commit
     display — committed-URL hyperlink (no notes box on URL-only)
     upload  — filename hyperlink + notes input
   The trailing 22px slot is the × delete button across all three. */
.prj-music-row-edit    { grid-template-columns: minmax(0, 1fr) 22px; }
.prj-music-row-display { grid-template-columns: minmax(0, 1fr) 22px; }
.prj-music-row-upload  { grid-template-columns: minmax(0, 1fr) 220px 22px; }
.prj-music-add {
  grid-column: 2 / 4;
  justify-self: flex-start;
  margin-top: 2px;
  font-size: 9.5px;
  padding: 4px 8px;
}

/* Bills / Receipts row — same pattern as music license. Three
   variants: edit (label + URL inputs), display (hyperlink only),
   upload (hyperlink with date). × is always the last 22px slot. */
.prj-link-row-ci { align-items: start; }
.prj-link-row-ci .prj-link-label { padding-top: 6px; }
.prj-link-row-ci > .prj-link-body { display: contents; }
.prj-link-row-ci > .prj-link-actions { display: none; }
.prj-ci-row {
  grid-column: 2 / 4;
  display: grid;
  gap: 8px;
  align-items: center;
}
.prj-ci-row-edit    { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr) 22px; }
.prj-ci-row-display { grid-template-columns: minmax(0, 1fr) 22px; }
.prj-ci-row-upload  { grid-template-columns: minmax(0, 1fr) 22px; }
/* Per-row delete × — small, low-contrast until hover. Matches the
   delete glyphs used elsewhere on the form (contractor list, etc). */
.prj-ci-del {
  border: none;
  background: transparent;
  color: rgba(26,46,61,.55);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 2px;
  border-radius: 4px;
}
.prj-ci-del:hover { color: rgba(26,46,61,1); background: rgba(26,46,61,.06); }
/* Uploaded row content — filename + date in one inline group. */
.prj-ci-uploaded {
  display: flex;
  gap: 6px;
  align-items: baseline;
  min-width: 0;
  padding: 4px 0;
}
.prj-ci-uploaded-name {
  font-size: 12px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.prj-ci-uploaded-date {
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
  white-space: nowrap;
}
/* Hyperlink that replaces the standalone "Open ↗" button. Reads
   as a blue link so it's unambiguously clickable, underline on
   hover. Truncates with ellipsis when the filename is long.
   flex: 1 so it expands to fill the available space inside its
   .prj-ci-uploaded flex container — that's what lets the whole
   filename show before the ellipsis kicks in. */
.prj-ci-link {
  color: #1f6feb;
  font-size: 12px;
  font-weight: 500;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1 1 auto;
}
.prj-ci-link:hover { text-decoration: underline; color: #155bb5; }

/* Drop zone — sits below the URL rows in Bills/Receipts/Licenses.
   Idle reads as a faint dashed pill; hover state lights up while
   files are being dragged over; uploading swaps to a solid bar with
   the progress text. */
.prj-drop {
  grid-column: 2 / 4;
  margin-top: 6px;
  padding: 10px 12px;
  border: 1px dashed rgba(26,46,61,.25);
  border-radius: 8px;
  background: rgba(26,46,61,.025);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  user-select: none;
  transition: background-color .12s ease, border-color .12s ease;
}
.prj-drop[data-state="hover"] {
  background: rgba(72,131,180,.10);
  border-color: rgba(72,131,180,.55);
  border-style: solid;
}
.prj-drop[data-state="uploading"] {
  background: rgba(72,131,180,.10);
  border-color: rgba(72,131,180,.55);
  border-style: solid;
  cursor: progress;
}
.prj-drop[data-state="ok"] {
  background: rgba(67,160,71,.10);
  border-color: rgba(67,160,71,.55);
  border-style: solid;
}
.prj-drop[data-state="error"] {
  background: rgba(229,57,53,.08);
  border-color: rgba(229,57,53,.55);
  border-style: solid;
}
.prj-drop-msg {
  font-size: 10.5px;
  color: rgba(26,46,61,.65);
  letter-spacing: .2px;
}
.prj-drop strong { color: rgba(26,46,61,.85); font-weight: 600; }
.prj-link-body-stacked {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.prj-link-sub-row {
  display: grid;
  /* Just label + body — no reserved action column. Actions live in
     the row's outer .prj-link-actions cell (single column on the
     right edge), so the Internal/External fields extend to match the
     width of the other rows' fields in this section. */
  grid-template-columns: 70px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  min-height: 32px;
}
.prj-link-mode-label {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: rgba(26,46,61,.5);
}
.prj-link-mode-open {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: rgba(26,46,61,.6);
  text-decoration: none;
  padding: 4px 8px;
  border: 1px solid rgba(26,46,61,.18);
  border-radius: 3px;
  white-space: nowrap;
}
.prj-link-mode-open:hover {
  background: rgba(26,46,61,.05);
  color: var(--navy);
}
.prj-link-mode-open[hidden] { display: none; }
.prj-link-hint {
  margin: 0;
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
  line-height: 1.5;
}
.prj-link-hint em {
  font-style: italic;
  color: rgba(26,46,61,.7);
}
.prj-link-card {
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 4px;
  padding: 8px 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-width: 0;
}
.prj-link-card-title {
  font-size: 11.5px;
  color: var(--navy);
  font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 1; min-width: 0;
}
.prj-link-card-meta {
  font-size: 10px;
  color: rgba(26,46,61,.55);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.prj-link-actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* Buttons size to their natural content width + min-width floor.
     Previously align-items: stretch was making every button fill
     the full 160px action column — that's why the buttons looked
     enormous in the form. Right-align so the buttons hug the right
     edge of the column in a tidy vertical strip. */
  align-items: flex-end;
  justify-content: flex-start;
}
/* Calendar row has stacked sub-rows in the body (Internal + External)
   and a separate files-region sibling for the multi-file list +
   drop zone. The action buttons (+Create, Open ↗) only relate to
   Internal/External, so cluster them at the top of the column. */
.prj-link-row-calendar > .prj-link-actions {
  justify-content: flex-start;
}

/* Calendar files-region — sibling of body / actions inside the row.
   display: contents flattens this wrapper out so its children (the
   file rows, +Add button, drop zone) become direct grid children
   of the row, just like Bills / Receipts / Music. They pick up the
   same `grid-column: 2 / 4` from .prj-ci-row's existing rule and
   span body+actions, putting Open / × at the row's right edge —
   same X-position as the other three drag-and-drop sections. */
.prj-link-files-region {
  display: contents;
}
/* Subtle divider above the first file row inside Calendar so the
   files area reads as a distinct group below Internal / External. */
.prj-link-row-calendar > .prj-link-files-region > :first-child {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed rgba(26,46,61,.12);
}
.prj-link-btn {
  /* Compact action button: 29px tall, equal-width across labels.
     min-width sits at the longest label's natural width ("+ Create"
     ≈ 64px) so shorter labels (Open ↗, Open) grow up to match
     instead of rendering at varying widths. Combined with the
     actions column's align-items: flex-end, this stack reads as
     a tight right-aligned column of identical pills. */
  padding: 0 8px !important;
  min-height: 29px;
  font-size: 9px !important;
  letter-spacing: 0.3px;
  white-space: nowrap;
  min-width: 100px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  box-sizing: border-box;
}

/* Small inline × that lives INSIDE a linked card (or next to a URL
   input) to clear the link. Replaces the old prj-link-btn-styled
   Unlink button — Joel didn't want unlinking to read as a primary
   action with equal visual weight. */
.prj-link-card-x,
.prj-link-input-x {
  background: transparent;
  border: 0;
  color: rgba(26,46,61,.5);
  font-size: 16px;
  line-height: 1;
  padding: 2px 6px;
  border-radius: 50%;
  cursor: pointer;
  flex-shrink: 0;
  transition: color .12s, background .12s;
}
.prj-link-card-x:hover,
.prj-link-input-x:hover {
  color: #b03b3b;
  background: rgba(176,59,59,.08);
}
/* Form-scope rule overrides the global one that paints all
   prj-link-btn navy — these aren't .prj-link-btn so they need their
   own form-scope override to stay transparent inside #view-project-form. */
#view-project-form .setup-body .prj-link-card-x,
#view-project-form .setup-body .prj-link-input-x {
  background: transparent !important;
  color: rgba(26,46,61,.5) !important;
  border: 0 !important;
}
#view-project-form .setup-body .prj-link-card-x:hover,
#view-project-form .setup-body .prj-link-input-x:hover {
  background: rgba(176,59,59,.08) !important;
  color: #b03b3b !important;
}
.prj-link-empty {
  padding: 6px 0;
}
.prj-invoice-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 8px;
}
.prj-invoice-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 4px;
  padding: 8px 12px;
  gap: 10px;
}
.prj-invoice-meta { min-width: 0; flex: 1; }
.prj-invoice-num {
  font-size: 11.5px;
  color: var(--navy);
  font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.prj-invoice-sub {
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
  margin-top: 2px;
  display: flex;
  gap: 8px;
  align-items: center;
}
.prj-invoice-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

/* Actuals */
.prj-actuals {
  border: 1px solid rgba(26,46,61,.06);
  border-radius: 4px;
  background: #fff;
  margin-bottom: 18px;
  overflow: hidden;
}
.prj-actuals-empty {
  padding: 14px 14px;
}
.prj-actuals-head,
.prj-actuals-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) 110px 110px 110px;
  gap: 12px;
  padding: 9px 14px;
  align-items: center;
  font-size: 11.5px;
  color: var(--navy);
}
.prj-actuals-head {
  background: rgba(26,46,61,.04);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
}
.prj-actuals-row + .prj-actuals-row {
  border-top: 1px dashed rgba(26,46,61,.08);
}
.prj-actuals-delta.is-over  { color: #c0392b; font-weight: 600; }
.prj-actuals-delta.is-under { color: #287850; }

/* Compact ID badge for grids/lists. Used in the Projects tab list
   and the Clients tab project history. */
.prj-id-badge {
  display: inline-block;
  padding: 2px 6px;
  background: rgba(26,46,61,.06);
  border: 1px solid rgba(26,46,61,.12);
  border-radius: 3px;
  font-family: var(--font);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .6px;
  color: rgba(26,46,61,.7);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Stacks the ID above the project name inside the .prj-cell-name
   cell — keeps the existing 7-column grid intact. */
.prj-cell-id {
  margin-bottom: 3px;
  line-height: 1;
}


/* ── Migration modal — wider than the default confirmModal so the
   preview table fits comfortably. Uses the same backdrop / card
   shell as ap-modal-root from shared.css; only overrides the
   width and adds table styling. */
.prj-migrate-modal-root .prj-migrate-card {
  max-width: 920px;
  max-height: calc(100vh - 60px);
  display: flex;
  flex-direction: column;
}
.prj-migrate-modal-root .ap-modal-body { padding-bottom: 4px; }
.prj-migrate-table {
  flex: 1;
  overflow: auto;
  margin-top: 16px;
  border: 1px solid rgba(26,46,61,.10);
  border-radius: 4px;
}
.prj-migrate-year { padding: 8px 12px 12px; }
.prj-migrate-year + .prj-migrate-year {
  border-top: 1px solid rgba(26,46,61,.10);
}
.prj-migrate-year-head {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.65);
  margin-bottom: 6px;
}
.prj-migrate-row {
  display: grid;
  grid-template-columns: 100px 80px minmax(0, 2fr) minmax(0, 1.4fr) 100px 100px;
  gap: 12px;
  align-items: center;
  padding: 6px 4px;
  font-size: 11.5px;
  color: var(--navy);
}
.prj-migrate-row + .prj-migrate-row {
  border-top: 1px dashed rgba(26,46,61,.08);
}
.prj-migrate-row-head {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  border-bottom: 1px solid rgba(26,46,61,.18);
  padding-bottom: 6px;
  margin-bottom: 2px;
}
.prj-migrate-row > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prj-migrate-id {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: .4px;
  color: rgba(26,46,61,.85);
}
.prj-migrate-name { color: var(--navy); }
.prj-migrate-client { color: rgba(26,46,61,.65); }
.prj-migrate-date { color: rgba(26,46,61,.65); font-variant-numeric: tabular-nums; }
.prj-migrate-tag {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .8px;
  text-transform: uppercase;
}
.prj-migrate-tag-new {
  background: rgba(46,109,164,.12);
  color: #2e6da4;
}
.prj-migrate-tag-update {
  background: rgba(26,46,61,.08);
  color: rgba(26,46,61,.7);
}

/* All buttons inside the project form's light areas (setup-body
   and setup-foot) wear the navy uniform — navy fill, beige text,
   no outline variation between Save / Cancel / +Add. The setup-head
   bar is excluded since it's already navy-backed and needs light
   buttons to be legible. Small row-delete X buttons are excluded
   too — they're icon-only and stay subtle. */
#view-project-form .setup-body .btn-primary,
#view-project-form .setup-body .btn-ghost,
#view-project-form .setup-body .btn-ghost-light,
#view-project-form .setup-body .btn-save-light,
#view-project-form .setup-body .btn-add-row,
#view-project-form .setup-body .prj-link-btn,
#view-project-form .setup-body .prj-ext-open,
#view-project-form .setup-body .prj-link-mode-open,
#view-project-form .setup-foot .btn-modal {
  background: var(--navy);
  color: var(--beige);
  border: 1px solid var(--navy);
}
#view-project-form .setup-body .btn-primary:hover,
#view-project-form .setup-body .btn-ghost:hover,
#view-project-form .setup-body .btn-ghost-light:hover,
#view-project-form .setup-body .btn-save-light:hover,
#view-project-form .setup-body .btn-add-row:hover,
#view-project-form .setup-body .prj-link-btn:hover,
#view-project-form .setup-body .prj-ext-open:hover,
#view-project-form .setup-body .prj-link-mode-open:hover,
#view-project-form .setup-foot .btn-modal:hover {
  background: var(--navy-mid);
  border-color: var(--navy-mid);
  color: var(--beige);
}

/* "+ Add URL row" inside the Linked Documents drag-and-drop fields
   (Bills, Receipts, Music License, Calendar files) is tertiary —
   the drop zone is the primary action and these add-buttons are
   the escape hatch for paste-a-URL. Override the navy uniform with
   a quieter ghost style so they don't compete with real actions. */
#view-project-form .setup-body .prj-link-row .btn-add-row {
  background: transparent;
  border: 1px solid rgba(26,46,61,.22);
  color: rgba(26,46,61,.7);
  font-size: 9px;
  letter-spacing: .6px;
  padding: 5px 10px;
}
#view-project-form .setup-body .prj-link-row .btn-add-row:hover {
  background: rgba(26,46,61,.04);
  border-color: rgba(26,46,61,.45);
  color: rgba(26,46,61,.9);
}
/* "Open ↗" links inside the form are anchors, not buttons — strip
   their underline since they now look like buttons. */
#view-project-form .setup-body a.prj-ext-open,
#view-project-form .setup-body a.prj-link-mode-open {
  text-decoration: none;
  display: inline-flex;
  align-items: center;
}

/* Contractors — even rhythm across all three sub-blocks
   (Contractor Hours / Timesheet Links / Contractor Invoices) so
   the Actuals section reads as a single grouped column instead of
   three competing layouts. */
.prj-contractors-block {
  margin-top: 22px;
}
.prj-contractors-block:first-of-type { margin-top: 16px; }
.prj-subhead {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  margin-bottom: 10px;
}
/* Consistent gap between any list inside a contractors-block and
   the +Add button below it. Without this, each list's last row
   sits flush against the +Add button (which has its own variable
   margin-top), and the blocks read unevenly. */
.prj-contractors-block .btn-add-row { margin-top: 10px; }
.prj-contractor-head,
.prj-contractor-row {
  display: grid;
  grid-template-columns: 110px minmax(0, 1fr) 70px 80px 80px 80px 85px 28px;
  gap: 8px;
  align-items: center;
  padding: 6px 0;
}
.prj-contractor-cost {
  font-variant-numeric: tabular-nums;
  color: rgba(26,46,61,.65);
}
.prj-contractor-head {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  border-bottom: 1px solid rgba(26,46,61,.18);
  padding-bottom: 6px;
}
.prj-contractor-row + .prj-contractor-row {
  border-top: 1px dashed rgba(26,46,61,.08);
}
.prj-contractor-total {
  font-variant-numeric: tabular-nums;
}
.prj-num-in {
  text-align: right;
}

/* Timesheet Links — token-generated contractor self-service. Same
   visual rhythm as .prj-contractor-row but with action buttons in
   place of the rate/hours inputs (data is read-only here). */
.prj-timesheet-block { margin-top: 18px; }
.prj-ts-subhead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.prj-ts-live {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .3px;
  text-transform: none;
  color: rgba(26,46,61,.45);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.prj-ts-live::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #5cb86a;
  box-shadow: 0 0 0 0 rgba(92,184,106,.5);
  animation: prj-ts-pulse 2s ease-in-out infinite;
}
.prj-ts-live:empty { display: none; }
@keyframes prj-ts-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(92,184,106,.5); }
  50%      { box-shadow: 0 0 0 4px rgba(92,184,106,0); }
}
.prj-ts-head,
.prj-ts-row {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) 80px 80px 60px 80px 90px auto auto auto;
  gap: 6px;
  align-items: center;
  padding: 6px 0;
}
.prj-ts-head {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  border-bottom: 1px solid rgba(26,46,61,.18);
  padding-bottom: 6px;
}
.prj-ts-row + .prj-ts-row { border-top: 1px dashed rgba(26,46,61,.08); }
.prj-ts-row .prj-num { font-variant-numeric: tabular-nums; }

.prj-ts-add-form {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) 130px 130px auto auto;
  gap: 8px;
  align-items: center;
  margin: 8px 0;
  padding: 10px;
  background: rgba(26,46,61,.04);
  border-radius: 4px;
}
.prj-ts-entries {
  grid-column: 1 / -1;
  margin-top: 6px;
  padding: 8px 10px;
  background: rgba(26,46,61,.04);
  border-radius: 4px;
  font-size: 12px;
}
.prj-ts-entries-head,
.prj-ts-entry-row {
  display: grid;
  grid-template-columns: 90px minmax(0, 1fr) 60px 80px;
  gap: 8px;
  align-items: center;
  padding: 4px 0;
}
.prj-ts-entries-head {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
}
.prj-ts-entry-row + .prj-ts-entry-row { border-top: 1px dashed rgba(26,46,61,.08); }
.prj-ts-entry-row .prj-num { font-variant-numeric: tabular-nums; text-align: right; }

.btn-ts-action {
  background: transparent;
  border: 1px solid rgba(26,46,61,.25);
  border-radius: 3px;
  padding: 4px 10px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  cursor: pointer;
  color: rgba(26,46,61,.85);
}
.btn-ts-action:hover { background: rgba(26,46,61,.06); }

/* Collaborators (logged-in restricted-view users) — same visual
   rhythm as the timesheet contractor row but simpler: name +
   per-project rate + remove. */
.prj-collab-row,
.prj-collab-head {
  display: grid;
  /* Identity | Cost rate | Bill rate | Hours | Cost $ | Revenue $ | × */
  grid-template-columns: minmax(0, 1.2fr) 80px 80px 60px 80px 80px 32px;
  gap: 8px;
  align-items: center;
  padding: 6px 0;
}
.prj-collab-head {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  border-bottom: 1px solid rgba(26,46,61,.18);
  padding-bottom: 6px;
}
.prj-collab-row + .prj-collab-row { border-top: 1px dashed rgba(26,46,61,.08); }
.prj-collab-row .prj-num { font-variant-numeric: tabular-nums; }
.prj-collab-add-form {
  display: grid;
  /* Picker spans the whole first row; second row: Name | Email |
     Cost | Bill | Add | Cancel. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr) 90px 90px auto auto;
  gap: 8px;
  align-items: center;
  margin: 8px 0;
  padding: 10px;
  background: rgba(26,46,61,.04);
  border-radius: 4px;
}
.prj-collab-pick {
  font-size: 12px;
  padding: 6px 10px;
  background: #fff;
  border: 1px solid rgba(26,46,61,.18);
  border-radius: 4px;
  color: var(--navy);
  flex: 1;
  min-width: 0;
}
.prj-collab-pick[hidden] { display: none; }
.prj-collab-pick-row {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 8px;
}
.prj-collab-manage-link {
  appearance: none;
  background: transparent;
  border: none;
  padding: 6px 4px;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .4px;
  color: rgba(26,46,61,.6);
  cursor: pointer;
  white-space: nowrap;
}
.prj-collab-manage-link:hover { color: var(--navy); text-decoration: underline; }

/* Manage Collaborators modal — list rows with a remove button on
   each. Same chrome language as other inline-CRUD lists in the
   project form. */
.manage-collab-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 12px;
  max-height: 360px;
  overflow-y: auto;
}
.manage-collab-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  background: rgba(26,46,61,.03);
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 4px;
}
.manage-collab-id { min-width: 0; flex: 1; }
.manage-collab-name {
  font-size: 13px; font-weight: 600; color: var(--navy);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.manage-collab-email {
  font-size: 11px; color: rgba(26,46,61,.55);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.manage-collab-del {
  appearance: none;
  font: inherit;
  font-size: 10px; font-weight: 600; letter-spacing: .6px;
  text-transform: uppercase;
  padding: 5px 10px;
  background: transparent;
  border: 1px solid rgba(192,57,43,.4);
  border-radius: 3px;
  color: #c0392b;
  cursor: pointer;
  white-space: nowrap;
}
.manage-collab-del:hover {
  background: rgba(192,57,43,.08);
  border-color: rgba(192,57,43,.6);
}
.manage-collab-empty {
  padding: 18px 12px;
  text-align: center;
  border: 1px dashed rgba(26,46,61,.14);
  border-radius: 4px;
  margin-top: 12px;
}
.prj-handoff-block {
  margin-top: 18px;
}
.prj-handoff-block textarea {
  width: 100%;
  min-height: 100px;
  font-family: var(--font);
  font-size: 13px;
  line-height: 1.5;
  resize: vertical;
}

/* ── Close Checklist ────────────────────────────────────────
   Three-stage flow. Each stage is a card with a header (number,
   title, status), then the items. Locked stages dim out. */
.prj-stage {
  background: rgba(26,46,61,.03);
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 4px;
  padding: 14px 16px;
  margin-top: 12px;
}
.prj-stage:first-child { margin-top: 0; }
.prj-stage.is-locked   { opacity: .5; pointer-events: none; }
.prj-stage.is-complete {
  background: rgba(40,140,80,.06);
  border-color: rgba(40,140,80,.18);
}
.prj-stage-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.prj-stage-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--navy);
  color: var(--beige);
  font-size: 11px;
  font-weight: 700;
  flex: 0 0 auto;
}
.prj-stage.is-complete .prj-stage-num { background: #287850; }
.prj-stage-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--navy);
  letter-spacing: .2px;
}
.prj-stage-status {
  margin-left: auto;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
}
.prj-stage-status.is-complete { color: #287850; }

.prj-check-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 22px;
  gap: 10px;
  align-items: center;
  padding: 8px 0;
  border-top: 1px dashed rgba(26,46,61,.1);
}
.prj-check-item:first-of-type { border-top: none; }
.prj-check-item.is-na .prj-check-label { color: rgba(26,46,61,.45); text-decoration: line-through; }
.prj-check-label {
  font-size: 13px;
  color: var(--navy);
}

/* Real checkbox styled to match the AP palette. The checkbox is
   the primary state — checked or unchecked. N/A is a separate
   chip on the right that's mutually exclusive with checked. */
.prj-checkbox {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  margin: 0;
  border: 1.5px solid rgba(26,46,61,.35);
  border-radius: 3px;
  background: #fff;
  cursor: pointer;
  display: inline-grid;
  place-content: center;
  transition: background .12s, border-color .12s;
}
.prj-checkbox:hover    { border-color: rgba(26,46,61,.55); }
.prj-checkbox:checked  {
  background: #287850;
  border-color: #287850;
}
.prj-checkbox:checked::before {
  content: "";
  width: 10px; height: 10px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.5 8.5l3 3 6-7' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 12px;
}

/* N/A toggle + clear (×) chip */
.prj-check-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.prj-na-btn {
  background: #fff;
  border: 1px solid rgba(26,46,61,.2);
  border-radius: 3px;
  padding: 3px 8px;
  font-family: var(--font);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: rgba(26,46,61,.6);
  cursor: pointer;
  transition: all .12s;
}
.prj-na-btn:hover { background: rgba(26,46,61,.06); border-color: rgba(26,46,61,.4); }
.prj-na-btn.is-on {
  background: rgba(26,46,61,.55);
  border-color: rgba(26,46,61,.55);
  color: #fff;
}

.prj-check-extra {
  grid-column: 1 / -1;
  margin-top: 6px;
  display: grid;
  gap: 6px;
}
.prj-check-extra .text-input,
.prj-check-extra textarea {
  font-size: 12.5px;
  padding: 7px 9px;
}
.prj-check-extra-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) 100px minmax(0, 1.2fr);
  gap: 8px;
}
.prj-check-extra-row select { font-size: 12.5px; padding: 7px 9px; }

/* Frame.io delivery links — committed entries render as
   read-only pills (label or URL + × to remove). The inline add row
   below is always visible (mirrors the RAID picker pattern). */
.prj-frameio-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 6px;
}
.prj-frameio-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px 4px 10px;
  background: #fff;
  border: 1px solid rgba(26,46,61,.12);
  border-radius: 14px;
  font-size: 11.5px;
}
.prj-frameio-pill-link {
  color: var(--navy);
  text-decoration: none;
  font-weight: 500;
  max-width: 260px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
a.prj-frameio-pill-link:hover { text-decoration: underline; }
.prj-frameio-pill button {
  background: transparent;
  border: 0;
  color: rgba(26,46,61,.55);
  font-size: 13px;
  cursor: pointer;
  padding: 0 4px;
  border-radius: 50%;
  line-height: 1;
}
.prj-frameio-pill button:hover { color: #b03b3b; background: rgba(176,59,59,.08); }

.prj-frameio-add-row {
  display: grid;
  grid-template-columns: minmax(0,1fr) minmax(0,1.4fr) auto;
  gap: 8px;
  align-items: center;
}
.prj-frameio-add-row .text-input { font-size: 12.5px; padding: 7px 9px; }

/* RAID picker — pills list of selected drives + a single-pick
   dropdown that adds one and resets. Cleaner than a multi-select
   that requires Cmd-clicking. */
.prj-raid-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
/* Hide the wrapper when empty so the add-row sits flush below the
   checkbox label — matches the Frame.io section's empty state. */
.prj-raid-pills:empty {
  display: none;
}
.prj-raid-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: rgba(26,46,61,.08);
  border: 1px solid rgba(26,46,61,.15);
  border-radius: 4px;
  padding: 4px 4px 4px 10px;
  font-size: 11.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--navy);
}
.prj-raid-pill button {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  color: rgba(26,46,61,.5);
  padding: 0 4px;
  border-radius: 2px;
}
.prj-raid-pill button:hover { color: #b03b3b; background: rgba(176,59,59,.08); }
.prj-raid-add-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
  margin-top: 4px;
}

.prj-stage3-prompt {
  margin-top: 12px;
  padding: 12px 14px;
  background: rgba(46,109,164,.08);
  border: 1px solid rgba(46,109,164,.18);
  border-radius: 4px;
  font-size: 12.5px;
  color: var(--navy);
}
.prj-stage3-prompt strong { color: #2e6da4; }

/* Tab strip override: make sure projects + dashboard buttons size
   the same as the existing tabs (already inherits .tab-strip-btn). */

/* Responsive: stack the dashboard cards on narrower viewports */
@media (max-width: 900px) {
  .ov-grid, .ov-grid.ov-grid-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ov-twocol     { grid-template-columns: minmax(0, 1fr); }
  .prj-row {
    grid-template-columns: minmax(0, 1fr) 90px 130px;
  }
  /* Hide Client (2), Linked (4), Tracked (5), Billed (6); keep
     Project, Status, Outstanding visible on small viewports. */
  .prj-row > :nth-child(2),
  .prj-row > :nth-child(4),
  .prj-row > :nth-child(5),
  .prj-row > :nth-child(6) { display: none; }
  .prj-row-head > :nth-child(2),
  .prj-row-head > :nth-child(4),
  .prj-row-head > :nth-child(5),
  .prj-row-head > :nth-child(6) { display: none; }
}

/* ── Phase 4: clickable pills + actuals refinements ────────── */
.prj-link-pill.is-clickable {
  cursor: pointer;
  transition: background .12s, color .12s, transform .08s;
}
.prj-link-pill.is-clickable:hover {
  background: #2e6da4;
  color: #fff;
}
.prj-link-pill.is-clickable:active {
  transform: scale(.95);
}
/* Discoverability — small ↗ glyph after the pill label tells the
   user this pill OPENS something (estimate / calendar / invoice /
   time-tracker modal). Without it, linked pills read as static
   indicators. Hidden on unlinked / non-clickable pills. */
.prj-link-pill.is-clickable::after {
  content: " ↗";
  font-size: 8px;
  font-weight: 700;
  margin-left: 2px;
  opacity: .7;
  letter-spacing: 0;
}

/* Sub-line under the Actual cell ("12.5 h") */
.prj-actuals-sub {
  font-size: 9.5px;
  color: rgba(26,46,61,.55);
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}

/* Bottom totals row of the actuals table */
.prj-actuals-row.prj-actuals-total {
  background: rgba(26,46,61,.04);
  font-weight: 600;
  border-top: 1px solid rgba(26,46,61,.18);
}

/* ── Phase 4 v2: Actuals summary (single 3-stat block) ────── */
.prj-actuals-summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  padding: 14px 16px;
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 6px;
}
.prj-actuals-stat {
  display: flex;
  flex-direction: column;
}
.prj-actuals-stat-label {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  margin-bottom: 6px;
}
.prj-actuals-stat-value {
  font-size: 22px;
  font-weight: 700;
  color: var(--navy);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  line-height: 1.1;
}
.prj-actuals-stat-value.is-over     { color: #c0392b; }
.prj-actuals-stat-value.is-under    { color: #287850; }
.prj-actuals-stat-value.is-positive { color: #287850; }
.prj-actuals-stat-value.is-negative { color: #c0392b; }

/* Contractor margin row sits directly under the Estimated/Actual/Delta
   summary as a second stat card. Slight top margin separates them
   visually without needing a divider. */
.prj-actuals-margin { margin-top: 8px; }
.prj-actuals-stat-sub {
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
  margin-top: 4px;
}

/* ── Archived section divider in projects list ────────────── */
.prj-section-divider {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.5);
  padding: 18px 14px 6px;
  border-top: 1px solid rgba(26,46,61,.08);
  margin-top: 12px;
}
/* The first section header in the list doesn't need a top rule —
   nothing's above it to separate from. Without this, "Active" would
   draw a stray horizontal line across the top of the projects view. */
.prj-section-divider:first-child {
  border-top: none;
  margin-top: 0;
  padding-top: 4px;
}

/* ── Phase 4 v3: per-project color accents ─────────────────── */

/* Inset 4px stripe on the left edge of each project row, colored
   from the project's --prj-color CSS var (set inline by JS, sourced
   from the tracker's published color_hex or a name-hash fallback).
   Adds no extra DOM and respects the row's existing border + radius. */
.prj-row {
  box-shadow: inset 4px 0 0 var(--prj-color, transparent);
  padding-left: 18px;   /* 14 + 4 to clear the stripe */
}
.prj-row.prj-row-head {
  box-shadow: none;     /* header has no project to color */
}

/* Swatch in the project form header (small dot next to the title). */
.prj-form-swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #ccc;
  border: 1px solid rgba(255,255,255,.18);
  flex-shrink: 0;
}

/* ── Phase A: view transitions ──────────────────────────────
   Subtle slide-in + fade when switching tabs or opening a form.
   Keyed off the [hidden] attribute that admin.js toggles, so no
   JS animation orchestration needed. The animation runs only on
   the section that just BECAME visible — closed sections don't
   animate (they're display:none anyway). */
@keyframes view-fade-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
main .lock-screen,
main > section:not([hidden]) {
  animation: view-fade-in 160ms ease-out;
}
/* Don't animate views that contain document-style forms (estimate/
   invoice forms have lots of inputs and the slide can feel heavy on
   long content). The list/dashboard views still get the polish. */
#view-estimate-form:not([hidden]),
#view-invoice-form:not([hidden]),
#view-job-form:not([hidden]) {
  animation: none;
}
@media (prefers-reduced-motion: reduce) {
  main > section:not([hidden]) { animation: none; }
}

/* ── Phase C: bulk-select on list views ───────────────────── */
.inv-checkbox-cell {
  display: flex; align-items: center; justify-content: center;
}
.inv-checkbox-cell input[type="checkbox"] {
  margin: 0;
  cursor: pointer;
  accent-color: var(--navy);
}
.inv-row.is-selected {
  background: #f4ede0;
  border-color: rgba(26,46,61,.22);
}

/* Sticky action bar that appears above the list when 1+ rows are
   selected. Same horizontal alignment as the list to feel anchored. */
.bulk-action-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 14px;
  margin-bottom: 8px;
  background: var(--navy);
  color: var(--beige);
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(26,46,61,.18);
  animation: view-fade-in 140ms ease-out;
}
.bulk-action-bar-count {
  font-size: 11.5px;
  letter-spacing: .3px;
  color: var(--beige);
}
.bulk-action-bar-count strong {
  font-weight: 700;
  margin-right: 4px;
}
.bulk-action-bar-meta {
  margin-left: 10px;
  color: rgba(232,224,208,.55);
  font-variant-numeric: tabular-nums;
}
.bulk-action-bar-actions {
  display: flex; gap: 6px;
}
.bulk-action-bar-actions .btn-ghost {
  border-color: rgba(232,224,208,.35);
  color: var(--beige);
  background: transparent;
}
.bulk-action-bar-actions .btn-ghost:hover {
  background: rgba(232,224,208,.1);
  border-color: var(--beige);
}

/* ── Phase D: global search modal ──────────────────────────── */
.search-modal {
  border: none;
  border-radius: 10px;
  padding: 0;
  width: 560px;
  max-width: 92vw;
  max-height: 70vh;
  background: #fff;
  box-shadow: 0 20px 56px rgba(0,0,0,.32), 0 4px 12px rgba(0,0,0,.12);
  overflow: hidden;
  margin: 8vh auto auto;
}
/* Only render the modal contents when the dialog is open. Without
   this, `display: flex` would override the browser's default
   `dialog:not([open]) { display: none }` rule and the modal would
   stay visible at all times. */
.search-modal[open] {
  display: flex; flex-direction: column;
}
.search-modal::backdrop {
  background: rgba(26,46,61,.45);
  backdrop-filter: blur(2px);
}
.search-input-wrap {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid rgba(26,46,61,.08);
  flex-shrink: 0;
}
.search-icon {
  width: 18px; height: 18px;
  color: rgba(26,46,61,.45);
  flex-shrink: 0;
}
#search-input {
  flex: 1;
  border: none;
  outline: none;
  font-family: var(--font);
  font-size: 14px;
  color: var(--navy);
  background: transparent;
}
#search-input::placeholder { color: rgba(26,46,61,.4); }
.search-kbd {
  font-family: var(--font);
  font-size: 9px; font-weight: 600;
  letter-spacing: .8px; text-transform: uppercase;
  padding: 3px 6px; border-radius: 3px;
  background: rgba(26,46,61,.07);
  color: rgba(26,46,61,.55);
}
.search-results {
  overflow-y: auto;
  flex: 1;
  min-height: 80px;
}
.search-empty {
  padding: 26px 18px;
  text-align: center;
  font-size: 11.5px;
  color: rgba(26,46,61,.5);
}
.search-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 16px;
  border: none;
  background: transparent;
  cursor: pointer;
  font-family: var(--font);
  text-align: left;
  border-bottom: 1px solid rgba(26,46,61,.04);
}
.search-row:last-child { border-bottom: none; }
.search-row:hover,
.search-row.is-active {
  background: var(--hover-tint);
}
.search-row-icon {
  width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  color: rgba(26,46,61,.55);
  background: rgba(26,46,61,.05);
  border-radius: 4px;
  flex-shrink: 0;
}
.search-row.is-active .search-row-icon { color: var(--navy); }
.search-row-main {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 2px;
}
.search-row-label {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--navy);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.search-row-sub {
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.search-row-kind {
  font-size: 8.5px; font-weight: 700;
  letter-spacing: 1.4px; text-transform: uppercase;
  color: rgba(26,46,61,.4);
  flex-shrink: 0;
}
.search-foot {
  display: flex; gap: 18px; justify-content: flex-end;
  padding: 9px 14px;
  border-top: 1px solid rgba(26,46,61,.08);
  background: #faf8f2;
  font-size: 9.5px;
  color: rgba(26,46,61,.5);
  flex-shrink: 0;
}
.search-foot kbd {
  font-family: var(--font);
  font-size: 9px; font-weight: 600;
  padding: 1px 5px; border-radius: 2px;
  background: rgba(26,46,61,.08);
  color: rgba(26,46,61,.65);
  margin: 0 2px;
}

/* ── Phase D2: dashboard / Today action callouts ─────────── */
.ov-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 10px;
  margin-bottom: 16px;
}
.ov-action-card {
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-left: 3px solid var(--navy);
  border-radius: 6px;
  padding: 12px 14px;
  text-align: left;
  font-family: var(--font);
  cursor: pointer;
  transition: background .12s, border-color .12s, transform .08s;
}
.ov-action-card:hover {
  background: var(--hover-tint);
  border-color: rgba(26,46,61,.18);
}
.ov-action-card:active { transform: scale(.99); }
.ov-action-card.ov-action-warn { border-left-color: #c0392b; }
.ov-action-card.ov-action-info { border-left-color: #2e6da4; }
.ov-action-head {
  font-size: 12px;
  font-weight: 600;
  color: var(--navy);
  line-height: 1.35;
}
.ov-action-sub {
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
  margin-top: 4px;
}

/* ── Phase D3: Reports tab ────────────────────────────────── */
.rep-twocol {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 16px;
  margin-bottom: 14px;
}

/* Monthly bars */
.rep-bars {
  display: flex; flex-direction: column; gap: 6px;
}
.rep-bar-row {
  display: grid;
  grid-template-columns: 56px minmax(60px, 1fr) 90px;
  align-items: center;
  gap: 12px;
  padding: 4px 0;
  font-size: 11px;
  color: var(--navy);
}
.rep-bar-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: rgba(26,46,61,.6);
}
.rep-bar-track {
  height: 8px;
  background: rgba(26,46,61,.06);
  border-radius: 4px;
  overflow: hidden;
}
.rep-bar-fill {
  height: 100%;
  background: var(--navy);
  border-radius: 4px;
}
.rep-bar-value {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Profitability table */
.rep-projects-table { display: block; }
.rep-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) 100px 100px 110px 90px;
  gap: 12px;
  align-items: center;
  padding: 9px 14px;
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 4px;
  margin-bottom: 4px;
  font-size: 11.5px;
  color: var(--navy);
}
.rep-row > * { min-width: 0; }
.rep-row-head {
  background: transparent;
  border: none;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  padding: 4px 14px;
  margin-bottom: 0;
}
.rep-cell-name {
  font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rep-cell-truncate {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rep-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.rep-num.is-over  { color: #c0392b; font-weight: 600; }
.rep-num.is-under { color: #287850; }

/* ── Batch invoice import modal ───────────────────────────── */
.batch-modal {
  border: none;
  border-radius: 8px;
  padding: 0;
  width: 640px;
  max-width: 92vw;
  max-height: 80vh;
  background: #fff;
  box-shadow: 0 18px 56px rgba(0,0,0,.32), 0 4px 12px rgba(0,0,0,.12);
  overflow: hidden;
  margin: 6vh auto auto;
}
.batch-modal[open] {
  display: flex; flex-direction: column;
}
.batch-modal::backdrop { background: rgba(26,46,61,.5); }
.batch-modal .modal-body {
  padding: 16px 18px 18px;
  overflow-y: auto;
}
.batch-blurb {
  font-size: 11.5px;
  color: rgba(26,46,61,.7);
  line-height: 1.5;
  margin-bottom: 14px;
}

.batch-dropzone {
  border: 2px dashed rgba(26,46,61,.18);
  border-radius: 8px;
  padding: 28px 16px;
  text-align: center;
  cursor: pointer;
  background: #faf8f2;
  transition: background .12s, border-color .12s;
  margin-bottom: 14px;
}
.batch-dropzone:hover,
.batch-dropzone:focus-visible {
  background: #f3eedf;
  border-color: rgba(26,46,61,.35);
}
.batch-dropzone.is-dragover {
  background: rgba(46,109,164,.08);
  border-color: #2e6da4;
  border-style: solid;
}
.batch-drop-text {
  font-size: 13px;
  font-weight: 600;
  color: var(--navy);
}
.batch-drop-sub {
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
  margin-top: 4px;
}

.batch-list {
  display: flex; flex-direction: column;
  gap: 4px;
  max-height: 320px;
  overflow-y: auto;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 6px;
  padding: 4px;
  background: #fbfaf6;
}
.batch-empty {
  text-align: center;
  font-size: 11px;
  color: rgba(26,46,61,.5);
  padding: 18px 12px;
}
.batch-row {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  padding: 7px 9px;
  background: #fff;
  border-radius: 4px;
}
.batch-row-main { min-width: 0; }
.batch-row-label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--navy);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.batch-row-sub {
  font-size: 10px;
  color: rgba(26,46,61,.55);
  margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.batch-row-saved  { background: rgba(70,160,90,.08); }
.batch-row-failed { background: rgba(192,57,43,.06); }
.batch-row-failed .batch-row-sub { color: #c0392b; }

.batch-glyph {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%;
  font-size: 10px; font-weight: 700; line-height: 1;
}
.batch-glyph-queued  { background: rgba(26,46,61,.06); color: rgba(26,46,61,.5); }
.batch-glyph-working { background: rgba(46,109,164,.14); color: #2e6da4;
  animation: batch-spin 1.2s linear infinite; }
.batch-glyph-saved   { background: rgba(70,160,90,.18); color: #287850; }
.batch-glyph-failed  { background: rgba(192,57,43,.18); color: #c0392b; }
@keyframes batch-spin { to { transform: rotate(360deg); } }

.batch-summary {
  margin-top: 12px;
  padding: 9px 11px;
  border-radius: 4px;
  background: var(--navy);
  color: var(--beige);
  font-size: 11px;
  letter-spacing: .3px;
}
.batch-summary strong { color: #fff; font-weight: 700; }

/* Year break in the invoice list when sorted chronologically.
   Quiet uppercase label that visually anchors a year's worth of
   invoices below it, like a section header in a transcript. */
.inv-year-divider {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.5);
  padding: 18px 14px 6px;
  border-top: 1px solid rgba(26,46,61,.08);
  margin-top: 12px;
}
.inv-year-divider:first-child {
  border-top: none;
  padding-top: 4px;
  margin-top: 0;
}

/* Year-total footer — closes out each year's section in the invoice
   list. Right-aligned dollar amount in navy so the total pops as
   the answer to "how much did this year produce", with the small
   uppercase year label as quiet context to the left. */
.inv-year-total {
  display: flex;
  justify-content: flex-end;
  align-items: baseline;
  gap: 14px;
  padding: 6px 14px 14px;
  margin-bottom: 6px;
  border-bottom: 1px dashed rgba(26,46,61,.10);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
}
.inv-year-total-amount {
  font-size: 14px;
  font-weight: 700;
  color: var(--navy);
  letter-spacing: -0.01em;
  text-transform: none;
  font-variant-numeric: tabular-nums;
}

/* ── Card icon buttons (calendar + estimate cards) ────────── */
.btn-card-icon {
  width: 28px; height: 28px;
  border: 1px solid rgba(26,46,61,.18);
  border-radius: 4px;
  background: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  color: rgba(26,46,61,.6);
  padding: 0;
  transition: background .12s, border-color .12s, color .12s, transform .1s;
}
.btn-card-icon:hover {
  background: var(--hover-tint);
  border-color: rgba(26,46,61,.35);
  color: var(--navy);
}
.btn-card-icon:active { transform: scale(.92); }
/* Trash variant — neutral at rest, red on hover so destructive
   intent is signaled only when the user lands on it. */
.btn-card-icon.is-danger:hover {
  background: rgba(192,57,43,.08);
  border-color: rgba(192,57,43,.4);
  color: #c0392b;
}

/* Clickable estimate-card body. Subtle hover lift mirrors the
   list-row hover pattern elsewhere in the suite. */
.est-card.is-clickable { cursor: pointer; }
.est-card.is-clickable:hover {
  box-shadow: 0 2px 8px rgba(0,0,0,.10), 0 6px 20px rgba(0,0,0,.06);
  transform: translateY(-1px);
}
.est-card { transition: box-shadow .14s, transform .14s; }

/* Calendar-card body becomes the open-target — body cursor signals
   that clicks open the calendar. The header is intentionally NOT a
   click target because it owns the dblclick color picker. */
.job-card-body[data-action="open"] {
  cursor: pointer;
  transition: background .12s;
}
.job-card-body[data-action="open"]:hover {
  background: var(--hover-tint);
}

/* Estimate card foot left cluster (duplicate + trash) */
.est-card-foot-left {
  display: flex; gap: 6px;
}

/* ── External Resources (project form) ────────────────────── */
.prj-ext-row {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: 10px 14px;
  align-items: center;
  padding: 10px 0;
}
.prj-ext-row + .prj-ext-row {
  border-top: 1px solid rgba(26,46,61,.06);
  margin-top: 4px;
}
.prj-ext-row-block {
  grid-template-columns: 1fr;
  align-items: start;
}
.prj-ext-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.6);
}
.prj-ext-body {
  display: flex;
  align-items: center;
  gap: 8px;
}
.prj-ext-body .text-input { flex: 1; min-width: 0; }
.prj-ext-open { white-space: nowrap; padding: 6px 12px; }
.prj-ext-hint {
  grid-column: 2;
  margin: 0;
  font-size: 11px;
  color: rgba(26,46,61,.55);
}

/* "Open ↗" glyph used inline inside External Costs rows. (The
   former Bills/Receipts/Music inline Open buttons are gone — they
   live as hyperlinks now.) */
.prj-ci-open {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 3px;
  text-decoration: none;
  color: var(--navy);
  font-size: 13px;
  background: rgba(26,46,61,.04);
  transition: background .12s, color .12s;
}
.prj-ci-open:hover { background: rgba(26,46,61,.1); }
.prj-ci-open.is-disabled { color: rgba(26,46,61,.25); cursor: not-allowed; }

/* Inline "label + sublabel" checkbox row used in Archive & Storage
   for the "RAID only" toggle. Sits below the HDD label / Storage
   inputs with deliberate vertical breathing room, so it reads as a
   modifier on the row above rather than the next field down. */
.prj-checkline {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-top: 14px;
  padding: 12px 14px;
  background: rgba(26,46,61,.025);
  border: 1px solid rgba(26,46,61,.06);
  border-radius: 4px;
  cursor: pointer;
  user-select: none;
}
.prj-checkline:hover { background: rgba(26,46,61,.045); }
.prj-checkline input[type="checkbox"] { margin-top: 2px; }
.prj-checkline-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.prj-checkline-body strong {
  font-size: 12px;
  font-weight: 600;
  color: var(--navy);
}
.prj-checkline-body .muted { font-size: 11px; color: rgba(26,46,61,.6); }
/* When raid_only is on, dim the HDD-label row above. */
.prj-archive-hdd-row.is-disabled { opacity: .45; }
.prj-archive-notes-group { margin-top: 14px; }

/* Two-line identity cell on the project's Collaborators row: name
   on top, email muted beneath. Falls back to single-line email when
   no name was provided at add time. */
.prj-collab-id { min-width: 0; }
.prj-collab-name {
  font-size: 12.5px; font-weight: 600; color: var(--navy);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.prj-collab-email {
  font-size: 10.5px; color: rgba(26,46,61,.55);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── PHASE 8: My Schedule (personal availability calendar) ─── */
.sch-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.sch-nav {
  display: flex;
  align-items: center;
  gap: 8px;
}
.sch-nav-btn {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-size: 16px;
  line-height: 1;
}
.sch-month-label {
  font-size: 17px;
  font-weight: 600;
  color: var(--navy);
  min-width: 180px;
  text-align: center;
  letter-spacing: .2px;
}
.sch-today-btn {
  font-size: 11px;
  letter-spacing: .8px;
  text-transform: uppercase;
  padding: 6px 12px;
}
.sch-legend {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  font-size: 11px;
  color: rgba(26,46,61,.65);
}
.sch-legend-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.sch-legend-swatch {
  display: inline-block;
  width: 12px; height: 12px;
  border-radius: 3px;
}
.sch-legend-swatch-ring {
  background: transparent;
  border: 2px solid #2e6da4;
  border-radius: 50%;
  width: 10px; height: 10px;
}

/* Grid */
.sch-grid {
  background: #fff;
  border: 1px solid rgba(26,46,61,.1);
  border-radius: 5px;
  overflow: hidden;
}
.sch-week {
  display: block;
}
/* Slim weekend columns — mirror the project calendar's
   `.33fr 1fr 1fr 1fr 1fr 1fr .33fr` treatment. Sun + Sat
   compress so weekday cells get the lion's share of width. */
.sch-week-head {
  display: grid;
  grid-template-columns: .33fr 1fr 1fr 1fr 1fr 1fr .33fr;
  background: rgba(26,46,61,.04);
  border-bottom: 1px solid rgba(26,46,61,.1);
}
.sch-week-head .sch-weekday:first-child,
.sch-week-head .sch-weekday:last-child {
  background: rgba(26,46,61,.06);
  color: rgba(26,46,61,.4);
}
.sch-weekday {
  padding: 8px 10px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
}
.sch-week {
  position: relative;
  border-bottom: 1px solid rgba(26,46,61,.07);
}
.sch-week:last-child { border-bottom: none; }
.sch-week-days {
  display: grid;
  grid-template-columns: .33fr 1fr 1fr 1fr 1fr 1fr .33fr;
  min-height: 110px;
}
.sch-day.is-weekend {
  background: #faf8f4;
}
.sch-day.is-weekend.is-out { background: #eef1f6; }
.sch-day.is-weekend:hover { background: #f2f0ea; }
.sch-day.is-weekend .sch-day-num { color: rgba(26,46,61,.42); }
.sch-day {
  padding: 6px 8px 4px;
  border-right: 1px solid rgba(26,46,61,.07);
  cursor: pointer;
  position: relative;
  /* Reserve vertical room at top for the block-strips overlay so
     blocks don't crowd the day number on busy days. */
  padding-top: 28px;
  transition: background .12s;
}
.sch-day:last-child { border-right: none; }
.sch-day:hover { background: rgba(26,46,61,.025); }
.sch-day.is-out .sch-day-num { color: rgba(26,46,61,.25); }
.sch-day-num {
  position: absolute;
  top: 4px; left: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--navy);
}
.sch-day.is-today .sch-day-num {
  /* Distinct from Confirmed Job navy so today's date doesn't read
     as a one-day block of confirmed work. Compact circle so the
     bottom edge doesn't tuck under block strips overlaid above. */
  background: #b85c3a;
  color: #fff;
  width: 18px; height: 18px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 10.5px;
  top: 3px; left: 6px;
}
.sch-day-dots {
  position: absolute;
  bottom: 4px; left: 8px;
  display: flex;
  gap: 3px;
  align-items: center;
}
.sch-day-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  display: inline-block;
}
.sch-day-dot-more {
  font-size: 9px;
  font-weight: 600;
  color: rgba(26,46,61,.55);
  letter-spacing: .4px;
}

/* Block strips overlay each week row's day cells. CSS grid handles
   the horizontal spanning; absolute positioning keeps them above
   the day cells without blocking clicks on cells outside the strip. */
.sch-week-blocks {
  position: absolute;
  top: 22px; left: 0; right: 0;
  display: grid;
  grid-template-columns: .33fr 1fr 1fr 1fr 1fr 1fr .33fr;
  grid-auto-rows: 20px;
  row-gap: 2px;
  padding: 0 2px;
  pointer-events: none;
}
.sch-block {
  pointer-events: auto;
  background: var(--navy);
  color: #fff;
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 10.5px;
  font-weight: 500;
  overflow: hidden;
  white-space: nowrap;
  cursor: pointer;
  display: flex;
  align-items: center;
  box-shadow: 0 1px 0 rgba(0,0,0,.06);
  transition: filter .12s;
}
.sch-block:hover { filter: brightness(1.08); }
.sch-block-label {
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Derived blocks (auto-pulled from project calendars) read as
   subtler "context" markers — slight transparency + a diagonal
   stripe pattern overlay so they're clearly distinct from manually-
   placed availability blocks. Clicking jumps to the project. */
.sch-block.is-derived {
  opacity: .82;
  background-image: repeating-linear-gradient(
    -45deg,
    rgba(255,255,255,.08) 0 6px,
    rgba(255,255,255,0)   6px 12px
  );
}
.sch-block.is-derived:hover { opacity: 1; }

/* Modal — slightly wider so the four fields fit two-up. */
.ap-modal-card-wide { max-width: 460px; width: 92vw; }
.sch-modal-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 8px;
}
.sch-modal-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.sch-modal-field .field-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.6);
}
.sch-modal-field .text-input {
  padding: 8px 10px;
  font-size: 13px;
}
/* Label spans the full width so a long block name fits. */
.sch-modal-field:first-child { grid-column: 1 / -1; }
.sch-modal-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.sch-modal-actions-right { display: flex; gap: 8px; }
.sch-modal-delete {
  color: #c0392b;
  border-color: rgba(192,57,43,.4);
}
.sch-modal-delete:hover {
  background: rgba(192,57,43,.08);
  border-color: rgba(192,57,43,.6);
}

/* Mobile: stack toolbar bits + legend. */
@media (max-width: 900px) {
  .sch-week-days { min-height: 90px; }
  .sch-block { font-size: 10px; }
  .sch-legend { gap: 10px; font-size: 10.5px; }
}

/* ── PHASE 4b: Archive tab ─────────────────────────────────── */
.arch-toolbar { margin-bottom: 6px; }
.arch-actions { flex-wrap: wrap; }
.arch-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--navy);
  cursor: pointer;
  user-select: none;
  padding: 4px 8px;
  border: 1px solid rgba(26,46,61,.12);
  border-radius: 4px;
  background: #fff;
}
.arch-toggle:hover { border-color: rgba(26,46,61,.3); }
.arch-toggle input { margin: 0; }
.arch-btn { font-size: 11px; }

.arch-grid { display: block; }
.arch-row {
  display: grid;
  /* ID  | Name (wide) | Client | Year | Deliv | Archived | RAID | HDD */
  grid-template-columns:
    110px minmax(0, 3fr) minmax(0, 1.4fr) 60px 60px 110px
    minmax(0, 1.1fr) minmax(0, 1.1fr);
  gap: 10px;
  align-items: center;
  padding: 9px 14px;
  background: #fff;
  border: 1px solid rgba(26,46,61,.08);
  border-radius: 4px;
  margin-bottom: 4px;
  font-size: 11.5px;
  color: var(--navy);
}
.arch-row > * { min-width: 0; }
.arch-row.is-deleted {
  opacity: .55;
  background: repeating-linear-gradient(
    -45deg,
    #fff 0, #fff 8px,
    rgba(26,46,61,.04) 8px, rgba(26,46,61,.04) 14px
  );
}
.arch-row-head {
  background: transparent;
  border: none;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  padding: 4px 12px;
  margin-bottom: 0;
}
.arch-row-head .arch-sort {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.arch-row-head .arch-sort:hover { color: var(--navy); }
.arch-row-head .arch-sort.is-active { color: var(--navy); }

.arch-cell-id   { cursor: pointer; }
.arch-cell-name {
  cursor: pointer;
  font-weight: 600;
  color: #2e6da4;
  text-decoration: underline;
  text-decoration-color: rgba(46,109,164,.4);
  text-underline-offset: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.arch-cell-name:hover { text-decoration-color: #2e6da4; }
.arch-cell-truncate {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.arch-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.arch-input {
  width: 100%;
  padding: 4px 6px;
  font-size: 11px;
  font-family: inherit;
  color: var(--navy);
  background: rgba(26,46,61,.025);
  border: 1px solid transparent;
  border-radius: 3px;
  transition: background .12s, border-color .12s;
}
.arch-input:hover {
  background: #fff;
  border-color: rgba(26,46,61,.18);
}
.arch-input:focus {
  outline: none;
  background: #fff;
  border-color: #2e6da4;
  box-shadow: 0 0 0 2px rgba(46,109,164,.18);
}
.arch-locked {
  display: inline-block;
  padding: 3px 6px;
  font-size: 10.5px;
  background: rgba(26,46,61,.04);
  border-radius: 3px;
  color: rgba(26,46,61,.75);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 100%;
}
.arch-locked.arch-locked-muted {
  background: transparent;
  border: 1px dashed rgba(26,46,61,.2);
  color: rgba(26,46,61,.55);
  font-style: italic;
}
.arch-raid-select {
  padding-right: 22px;
  background-position: right 6px center;
  background-size: 8px;
}

.arch-actions-cell {
  display: flex;
  justify-content: flex-end;
  gap: 4px;
}
.arch-row-btn {
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(26,46,61,.15);
  border-radius: 3px;
  background: #fff;
  color: var(--navy);
  cursor: pointer;
  font-size: 12px;
  line-height: 1;
  transition: background .12s, border-color .12s, color .12s;
}
.arch-row-btn:hover {
  background: rgba(26,46,61,.06);
  border-color: rgba(26,46,61,.4);
}
.arch-row-btn-danger:hover {
  background: rgba(192,57,43,.08);
  border-color: rgba(192,57,43,.6);
  color: #c0392b;
}
.arch-empty { padding: 22px 18px; }

@media (max-width: 1180px) {
  .arch-row {
    grid-template-columns:
      100px minmax(0, 2.4fr) minmax(0, 1.2fr) 50px 50px 100px
      minmax(0, 1fr) minmax(0, 1fr);
    gap: 8px;
    font-size: 10.5px;
    padding: 7px 10px;
  }
}

/* ──────────────────────────────────────────────────────────────
   Project Sheet — read-only summary view
   The "open the folder" landing page that replaces direct-to-edit
   on project click. Spec: AP brand (navy + beige), generous white
   space, big typography for things you scan (status, money, stage
   progress), nothing editable. Edit button on the header band
   flips to the existing form (#view-project-form).
────────────────────────────────────────────────────────────── */

/* The view container is just a page-padding band; the actual
   "sheet" sits inside it as a contained, paper-feel card. The
   head row (Back / Edit) lives OUTSIDE the card so it reads as a
   browser-chrome-ish toolbar rather than a heading on the doc. */
#view-project-sheet { padding: 18px 28px 60px; }

.prj-sheet-wrap {
  max-width: 920px;
  margin: 0 auto;
}

.prj-sheet {
  background: #fff;
  border: 1px solid var(--border);
  /* The left edge gets a 4px stripe coloured with the project's
     accent (set inline). It replaces the in-flow color swatch the
     previous layout had and keeps the title row clean. */
  border-left: 4px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 1px 3px rgba(26,46,61,0.06), 0 6px 20px rgba(26,46,61,0.05);
  padding: 48px 56px 56px;
  color: var(--navy);
}

/* ── Header band: back link + actions (lives outside the card) ── */
.prj-sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}
.prj-sheet-head-left,
.prj-sheet-head-right {
  display: flex;
  align-items: center;
  gap: 10px;
}
.prj-sheet-back {
  background: none;
  border: none;
  color: var(--navy);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .2px;
  padding: 6px 10px 6px 4px;
  cursor: pointer;
  border-radius: 6px;
  opacity: 0.7;
  transition: opacity .15s ease, background-color .15s ease;
}
.prj-sheet-back:hover { opacity: 1; background: rgba(26,46,61,0.06); }
.prj-sheet-back span { margin-right: 6px; }

/* ── Identity band: ID + name + status pill ─────────────────── */
.prj-sheet-identity {
  padding: 0 0 28px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 28px;
}
/* Title row: name on the left, status pill on the right. The
   project ID badge moved out to its own line below so the title
   sits at the same left edge as the client info underneath. */
.prj-sheet-id-band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 6px;
}
.prj-sheet-pid-line {
  margin-bottom: 8px;
}
.prj-sheet-pid {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  letter-spacing: .5px;
  color: var(--navy);
  opacity: 0.65;
  padding: 4px 8px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: rgba(255,255,255,0.5);
  display: inline-block;
}
.prj-sheet-name {
  font-size: 26px;
  font-weight: 600;
  letter-spacing: -.4px;
  line-height: 1.15;
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
}
.prj-sheet-status {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  padding: 5px 10px;
  border-radius: 999px;
  flex: 0 0 auto;
  align-self: center;
}
.prj-sheet-status-active     { color: #1f5d99; background: rgba(31,93,153,0.12); }
.prj-sheet-status-delivered  { color: #1d6f49; background: rgba(29,111,73,0.12); }
.prj-sheet-status-archived   { color: #555;    background: rgba(0,0,0,0.07); }

/* Payment/invoicing state chip — rendered next to the project status
   pill. Computed from linked invoices in computePaymentState(); each
   variant signals the next billing action. */
.prj-sheet-pay-uninvoiced  { color: #6e6e6e; background: rgba(0,0,0,0.05); }
.prj-sheet-pay-draft       { color: #a06b00; background: rgba(160,107,0,0.13); }
.prj-sheet-pay-outstanding { color: #b03a2a; background: rgba(176,58,42,0.12); }
.prj-sheet-pay-paid        { color: #1d6f49; background: rgba(29,111,73,0.12); }

.prj-sheet-client {
  font-size: 15px;
  color: var(--navy);
  opacity: 0.78;
  margin-left: 0;
}
.prj-sheet-meta {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  margin-top: 14px;
}
.prj-sheet-meta-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.prj-sheet-meta-row .tiny { letter-spacing: .6px; text-transform: uppercase; font-weight: 600; }
.prj-sheet-meta-row > span:not(.tiny) { font-size: 13px; }

/* ── Financials band: 4 big stats ────────────────────────────── */
.prj-sheet-financials {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 28px;
  padding: 4px 0 28px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 28px;
}
.prj-sheet-stat-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--navy);
  opacity: 0.6;
  margin-bottom: 8px;
}
.prj-sheet-stat-value {
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -.3px;
  line-height: 1.1;
  margin-bottom: 4px;
}
.prj-sheet-stat-value.is-over   { color: #a02c1e; }   /* over-budget = dark red */
.prj-sheet-stat-value.is-under  { color: #1d6f49; }   /* under-budget = green */
.prj-sheet-stat-value.is-neutral { color: var(--navy); opacity: 0.5; }
/* Empty / "not yet" state for stat values — when there's nothing
   to display (no invoices yet, no estimate linked, etc.) we
   render an italic muted phrase instead of "$0.00". Smaller font
   so it doesn't compete with the real numeric values on adjacent
   cards. */
.prj-sheet-stat-value.is-empty {
  font-size: 16px;
  font-weight: 500;
  font-style: italic;
  color: rgba(26,46,61,.45);
  letter-spacing: normal;
}
.prj-sheet-stat-sub {
  font-size: 11px;
  color: var(--navy);
  opacity: 0.55;
}

/* ── Generic section block ───────────────────────────────────── */
.prj-sheet-section {
  padding: 4px 0 28px;
  margin-bottom: 28px;
  border-bottom: 1px solid var(--border);
}
.prj-sheet-section:last-child { border-bottom: none; margin-bottom: 0; }
.prj-sheet-section-title {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--navy);
  margin-bottom: 14px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
}
/* A section that wants both a left-aligned title AND a right-aligned
   control (e.g. the Hard Costs "Include my labor" toggle). The title
   itself stays styled by .prj-sheet-section-title; this wrapper just
   adds the row layout. */
.prj-sheet-section-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 14px;
}
.prj-sheet-section-title-row .prj-sheet-section-title {
  margin-bottom: 0;
}
.prj-sheet-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: rgba(26,46,61,.6);
  cursor: pointer;
  user-select: none;
}
.prj-sheet-toggle input { cursor: pointer; }
.prj-sheet-toggle:hover { color: var(--navy); }

/* "Open ↗" link in a section header — subtle navigation affordance
   that sits at the right edge of the section title row. */
.prj-sheet-section-link {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: rgba(26,46,61,.55);
  text-decoration: none;
  transition: color .12s;
}
.prj-sheet-section-link:hover { color: var(--navy); text-decoration: underline; }

/* Inline read-only calendar embed inside the project sheet (Active
   projects with a linked AP-suite calendar). Iframe height matches
   the AE collaborator view's read-only calendar embed; width fills
   the section. */
.prj-sheet-calendar-embed {
  border: 1px solid rgba(26,46,61,.1);
  border-radius: 5px;
  overflow: hidden;
  background: #f8f5ec;
}
.prj-sheet-calendar-embed iframe {
  display: block;
  width: 100%;
  height: 720px;
  border: none;
  background: #f8f5ec;
}
.prj-sheet-empty {
  font-size: 13px;
  color: var(--navy);
  opacity: 0.5;
  font-style: italic;
  padding: 6px 0;
}

/* ── Links row: 4 tiles ──────────────────────────────────────── */
.prj-sheet-links {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}
.prj-sheet-link {
  display: block;
  background: rgba(255,255,255,0.55);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  text-align: left;
  text-decoration: none;
  color: var(--navy);
  font: inherit;
  cursor: default;
  transition: background-color .15s ease, border-color .15s ease, transform .12s ease;
  min-height: 72px;
}
button.prj-sheet-link { width: 100%; }
.prj-sheet-link.is-linked { cursor: pointer; }
.prj-sheet-link.is-linked:hover,
a.prj-sheet-link.is-linked:hover {
  background: rgba(255,255,255,0.85);
  border-color: rgba(26,46,61,0.22);
  transform: translateY(-1px);
}
.prj-sheet-link.is-empty {
  background: transparent;
  opacity: 0.55;
}
.prj-sheet-link-head {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 6px;
}
.prj-sheet-link-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  font-size: 9px;
  color: #fff;
  background: #1d6f49;
  border-radius: 50%;
  font-weight: 700;
}
.prj-sheet-link-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  opacity: 0.7;
}
.prj-sheet-link-body {
  font-size: 13px;
  line-height: 1.35;
  /* Belt-and-suspenders for long single-token strings (URLs, IDs).
     overflow-wrap covers normal long words; word-break helps with
     URLs that have no whitespace at all. */
  overflow-wrap: break-word;
  word-break: break-word;
  min-width: 0;
}
.prj-sheet-link-strong { font-weight: 600; }
.prj-sheet-link-body .muted { opacity: 0.55; }

/* ── Stage strip ─────────────────────────────────────────────── */
.prj-sheet-stages {
  display: grid;
  grid-template-columns: 1fr 40px 1fr 40px 1fr;
  align-items: center;
  gap: 0;
  padding: 6px 4px;
}
.prj-sheet-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-align: center;
}
.prj-sheet-stage-dot {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 12px;
  border: 1.5px solid var(--border);
  background: #fff;
  color: var(--navy);
  opacity: 0.5;
  margin-bottom: 4px;
}
.prj-sheet-stage.is-complete .prj-sheet-stage-dot {
  background: #1d6f49;
  border-color: #1d6f49;
  color: #fff;
  opacity: 1;
}
.prj-sheet-stage.is-current .prj-sheet-stage-dot {
  background: #fff;
  border-color: var(--navy);
  color: var(--navy);
  opacity: 1;
  box-shadow: 0 0 0 4px rgba(26,46,61,0.08);
}
.prj-sheet-stage-label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: -.1px;
}
.prj-sheet-stage.is-locked .prj-sheet-stage-label { opacity: 0.45; }
.prj-sheet-stage-state {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  opacity: 0.55;
}
.prj-sheet-stage.is-complete .prj-sheet-stage-state { color: #1d6f49; opacity: 1; }
.prj-sheet-stage.is-current  .prj-sheet-stage-state { color: var(--navy); opacity: 0.9; }
/* "Pending" = next-in-line stage with no activity yet. Reads as
   "Not started" so we don't claim work that hasn't happened. */
.prj-sheet-stage.is-pending .prj-sheet-stage-dot {
  background: #fff;
  border-color: var(--border);
  color: var(--navy);
  opacity: 0.55;
}
.prj-sheet-stage.is-pending .prj-sheet-stage-label { opacity: 0.65; }

/* ── Delivery link list ──────────────────────────────────────── */
.prj-sheet-deliv-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.prj-sheet-deliv-row {
  display: grid;
  grid-template-columns: minmax(120px, 1fr) minmax(0, 2.4fr) auto auto;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(255,255,255,0.55);
  font-size: 13px;
  color: var(--navy);
}
.prj-sheet-deliv-label {
  font-weight: 600;
}
/* Hyperlink-styled URL so it reads as clickable, not plain text.
   Uses a desaturated AP-friendly blue rather than the standard
   web royal blue so the link sits inside the brand. */
.prj-sheet-deliv-url {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
  color: #2e6da4;
  text-decoration: underline;
  text-decoration-color: rgba(46,109,164,.35);
  text-underline-offset: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  transition: color .15s ease, text-decoration-color .15s ease;
}
.prj-sheet-deliv-url:hover {
  color: #1f4a73;
  text-decoration-color: #1f4a73;
}
.prj-sheet-deliv-btn {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 6px;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .4px;
  color: var(--navy);
  padding: 6px 12px;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color .15s ease, border-color .15s ease;
}
.prj-sheet-deliv-btn:hover {
  background: var(--navy);
  color: var(--beige);
  border-color: var(--navy);
}

@media (max-width: 700px) {
  .prj-sheet-deliv-row {
    grid-template-columns: 1fr;
    gap: 6px;
  }
  .prj-sheet-deliv-url { white-space: normal; }
}

.prj-sheet-stage-link {
  height: 2px;
  background: var(--border);
  margin-top: -22px;       /* aligns the bar to the dot row vertically */
  transition: background-color .2s ease;
}
.prj-sheet-stage-link.is-complete { background: #1d6f49; }

/* ── Collaborators ───────────────────────────────────────────── */
.prj-sheet-collabs {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.prj-sheet-collab {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 10px 14px;
  background: rgba(255,255,255,0.55);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.prj-sheet-collab-name { font-size: 14px; font-weight: 600; }
.prj-sheet-collab-email { margin-top: 1px; }
.prj-sheet-collab-meta {
  text-align: right;
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex-shrink: 0;
}
.prj-sheet-collab-rate { font-size: 13px; font-weight: 500; }
.prj-sheet-collab-rate .tiny { font-weight: 600; letter-spacing: .6px; text-transform: uppercase; opacity: 0.55; margin-right: 2px; }
.prj-sheet-collab.is-clickable {
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.prj-sheet-collab.is-clickable:hover {
  background: var(--hover-tint);
  border-color: var(--hover-border);
}
/* Clickable rows inside the Actuals table — only collaborator rows
   open the hours modal today, but the class is generic in case other
   rows become clickable later. */
.prj-sheet-actuals-clickable {
  cursor: pointer;
}
.prj-sheet-actuals-clickable:hover {
  background: var(--hover-tint);
}

/* External-cost inline list inside the project edit form. */
.prj-ec-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 6px;
}
/* Row template: [service_type | label | cost | bill | url | open ↗ | × ].
   Bill is the marked-up amount (35% default) editable per row.
   Service type is manual per row so the line item lands on the
   invoice with Joel's chosen category. */
.prj-ec-row {
  display: grid;
  grid-template-columns: 110px minmax(0,1fr) 90px 90px minmax(0,1.1fr) 24px 24px;
  gap: 8px;
  align-items: center;
}
.prj-ec-head {
  display: grid;
  grid-template-columns: 110px minmax(0,1fr) 90px 90px minmax(0,1.1fr) 24px 24px;
  gap: 8px;
  align-items: center;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: rgba(26,46,61,.45);
  padding: 0 2px 4px;
}
.prj-ec-head .prj-num { text-align: right; }
.prj-ec-add-form {
  display: grid;
  grid-template-columns: 110px minmax(0,1fr) 90px 90px minmax(0,1.1fr) auto auto;
  gap: 8px;
  align-items: center;
  margin: 6px 0;
}
.prj-ec-row-open {
  margin-left: 6px;
  text-decoration: none;
  color: var(--navy);
  opacity: 0.55;
}
.prj-ec-row-open:hover { opacity: 1; }
.prj-ec-total {
  display: flex;
  justify-content: flex-end;
  align-items: baseline;
  gap: 8px;
  padding-top: 4px;
}
.prj-ec-total-value {
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* ── Actuals table ───────────────────────────────────────────── */
.prj-sheet-actuals {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.prj-sheet-actuals thead th {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--navy);
  opacity: 0.55;
  text-align: left;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
}
.prj-sheet-actuals th.num,
.prj-sheet-actuals td.num { text-align: right; font-variant-numeric: tabular-nums; }
.prj-sheet-actuals td {
  padding: 9px 10px;
  border-bottom: 1px solid rgba(26,46,61,0.06);
}
.prj-sheet-actuals .muted { opacity: 0.5; }
.prj-sheet-actuals tr.prj-sheet-subtotal td {
  font-weight: 600;
  border-top: 1px solid var(--border);
  background: rgba(255,255,255,0.4);
}
.prj-sheet-actuals tr.prj-sheet-total td {
  font-weight: 700;
  font-size: 14px;
  border-top: 2px solid var(--navy);
  border-bottom: none;
  padding-top: 12px;
}

/* ── Handoff notes ───────────────────────────────────────────── */
.prj-sheet-handoff {
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  background: rgba(255,255,255,0.55);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 16px;
  color: var(--navy);
  opacity: 0.9;
}

/* ── Archive block ───────────────────────────────────────────── */
.prj-sheet-archive {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.prj-sheet-arch-row {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: 14px;
  align-items: baseline;
  font-size: 13px;
}
.prj-sheet-arch-row .tiny {
  letter-spacing: .6px;
  text-transform: uppercase;
  font-weight: 600;
  opacity: 0.55;
}

/* Tighter layout on narrow viewports */
@media (max-width: 880px) {
  .prj-sheet-financials { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px; }
  .prj-sheet-links       { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .prj-sheet-stages      { grid-template-columns: 1fr; gap: 14px; }
  .prj-sheet-stage-link  { display: none; }
}

/* ──────────────────────────────────────────────────────────────
   Time Tracker entries modal
   Opened from the Time Tracker tile on the project sheet. Shows
   every entry the Swift app published for this project, grouped
   by date.
────────────────────────────────────────────────────────────── */
.prj-tracker-card {
  max-width: 760px;
  width: 92vw;
  max-height: 86vh;
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}
.prj-tracker-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding: 22px 28px 18px;
  border-bottom: 1px solid var(--border);
  background: rgba(255,255,255,0.6);
}
.prj-tracker-eyebrow {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--navy);
  opacity: 0.6;
}
.prj-tracker-title {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -.2px;
  color: var(--navy);
  margin-top: 4px;
}
.prj-tracker-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 18px 28px 28px;
}
.prj-tracker-loading {
  font-size: 13px;
  color: var(--navy);
  opacity: 0.55;
  font-style: italic;
  padding: 20px 0;
  text-align: center;
}
/* Project Entries modal — one section per labor source (Joel, each
   collaborator, each timesheet contractor). Section head holds the
   person's name + role + their per-section totals. */
.prj-entries-section + .prj-entries-section {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid rgba(26,46,61,.08);
}
.prj-entries-section-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 10px;
}
.prj-entries-section-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--navy);
}

.prj-tracker-totals {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 18px;
  padding: 12px 16px;
  margin-bottom: 22px;
  background: rgba(255,255,255,0.6);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.prj-tracker-totals-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--navy);
  opacity: 0.6;
  margin-bottom: 4px;
}
.prj-tracker-totals-value {
  font-size: 18px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Sectioned modal — one block per source (Tracker / Collaborators
   / Timesheet). Each section has its own head row with a total
   strip on the right. Empty sections don't render. */
.prj-tracker-section {
  margin-bottom: 26px;
}
.prj-tracker-section:last-child { margin-bottom: 0; }
.prj-tracker-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid rgba(26,46,61,.16);
}
.prj-tracker-section-title {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--navy);
}
.prj-tracker-section-totals {
  font-size: 11px;
  font-weight: 600;
  color: var(--navy);
  display: flex;
  gap: 6px;
  font-variant-numeric: tabular-nums;
}

.prj-tracker-day { margin-bottom: 22px; }
.prj-tracker-day:last-child { margin-bottom: 0; }
.prj-tracker-day-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.prj-tracker-day-date {
  font-size: 13px;
  font-weight: 600;
  color: var(--navy);
}
.prj-tracker-day-totals {
  font-size: 11px;
  color: var(--navy);
  opacity: 0.7;
  display: flex;
  gap: 6px;
  font-variant-numeric: tabular-nums;
}
.prj-tracker-day-entries {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.prj-tracker-entry {
  display: grid;
  grid-template-columns: 80px minmax(0, 1fr) 70px 90px;
  gap: 14px;
  align-items: start;
  padding: 9px 12px;
  border-radius: 6px;
  background: rgba(255,255,255,0.45);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.prj-tracker-entry-time {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11.5px;
  color: var(--navy);
  opacity: 0.75;
  padding-top: 2px;
}
.prj-tracker-entry-task {
  font-weight: 600;
  color: var(--navy);
}
.prj-tracker-entry-desc {
  font-size: 12px;
  color: var(--navy);
  opacity: 0.7;
  margin-top: 2px;
  line-height: 1.4;
  white-space: pre-wrap;
}
.prj-tracker-entry-hours { text-align: right; opacity: 0.78; }
.prj-tracker-entry-dollars { text-align: right; font-weight: 600; }

@media (max-width: 600px) {
  .prj-tracker-totals { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .prj-tracker-entry  { grid-template-columns: 60px minmax(0, 1fr) auto; }
  .prj-tracker-entry-hours { display: none; }
}

/* ══════════════════════════════════════════════════════════════
   Mobile Phase 2 — Admin views responsive pass

   Each view that's grid-heavy or table-heavy on desktop gets a
   media-gated layout swap here. The shared.css drawer + hamburger
   already handle navigation; this block handles content density.
   All rules sit at the bottom so desktop selectors win cascade
   precedence — only at narrow widths do these kick in.
   ══════════════════════════════════════════════════════════════ */

@media (max-width: 720px) {

  /* ─── Dashboard ──────────────────────────────────────────── */
  .dash-toolbar { flex-direction: column; align-items: stretch; gap: 10px; }
  .dash-actions { flex-wrap: wrap; gap: 8px; }
  .dash-actions .btn-primary,
  .dash-actions .btn-ghost { flex: 1 1 auto; min-width: 120px; }

  /* List-view toolbars (invoices, estimates, clients, projects) all
     use .est-list-toolbar + .est-list-actions. Stack vertically and
     let the actions wrap. Labels get nowrap globally so they no
     longer break to vertical letters. */
  .est-list-toolbar { flex-direction: column; align-items: stretch; gap: 10px; }
  .est-list-actions {
    flex-wrap: wrap;
    gap: 8px 10px;
    align-items: center;
  }
  .est-list-search { width: 100%; }
  .est-list-actions .dash-sort-select,
  .est-list-actions .select-input { min-width: 110px; flex: 0 1 auto; }
  .est-list-actions .btn-primary,
  .est-list-actions .btn-ghost { flex: 1 1 auto; min-width: 120px; }

  .ov-grid,
  .ov-grid.ov-grid-5 { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .ov-twocol         { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  /* Activity rows lose the pill + date columns at phone widths so
     the title stays readable; the kind chip still gives context. */
  .ov-activity-row {
    grid-template-columns: 56px minmax(0, 1fr);
    gap: 10px;
  }
  .ov-activity-row > .ov-activity-pill,
  .ov-activity-row > .ov-activity-date { display: none; }
  .ov-rev-row {
    grid-template-columns: minmax(0, 1.2fr) minmax(40px, 1fr) 80px;
    gap: 8px;
    font-size: 11px;
  }

  /* ─── Calendar / Estimate cards ───────────────────────────── */
  /* job-grid + est-grid already use auto-fill with min 280-300px,
     so they naturally collapse to one column on phones. Just
     tighten the gap a hair. */
  .job-grid, .est-grid { gap: 10px; }

  /* ─── Projects list ──────────────────────────────────────── */
  /* On phones the row becomes a stacked card — name + ID, status
     pill below, outstanding + tracked on a meta line. All the
     hidden-on-tablet columns stay hidden. */
  .prj-row,
  .prj-row-head {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 8px 10px;
    padding: 10px 12px;
  }
  .prj-row > :nth-child(2),
  .prj-row > :nth-child(4),
  .prj-row > :nth-child(5),
  .prj-row > :nth-child(6),
  .prj-row-head > :nth-child(2),
  .prj-row-head > :nth-child(4),
  .prj-row-head > :nth-child(5),
  .prj-row-head > :nth-child(6) { display: none; }
  /* Hide the header row entirely on phones — the cards are
     self-labeled and the empty heading is just chrome. */
  .prj-row-head { display: none; }

  /* ─── Invoices list ──────────────────────────────────────── */
  /* Show: checkbox, invoice #, project name, amount. Hide the
     rest (client, date, status, actions) — clicking the row
     opens the PDF view where those details live. */
  .inv-row,
  .inv-row-head {
    grid-template-columns: 24px 90px minmax(0, 1fr) 90px;
    gap: 10px;
    padding: 10px 12px;
  }
  .inv-row > :nth-child(4),  /* client */
  .inv-row > :nth-child(5),  /* date */
  .inv-row > :nth-child(6),  /* status */
  .inv-row > :nth-child(8),  /* actions */
  .inv-row-head > :nth-child(4),
  .inv-row-head > :nth-child(5),
  .inv-row-head > :nth-child(6),
  .inv-row-head > :nth-child(8) { display: none; }
  .inv-row-head { display: none; }

  /* ─── Setup / form toolbar (project, estimate, invoice, calendar) ─ */
  .setup-head {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    padding: 12px 14px;
  }
  .setup-head > div { flex-wrap: wrap; }
  .setup-body { padding: 16px 14px 6px; }
  .setup-foot { padding: 14px; flex-direction: column; gap: 10px; align-items: stretch; }
  .setup-foot-right { justify-content: flex-end; }
  .est-form-actions-right { flex-wrap: wrap; gap: 6px; }

  /* Form field rows stack instead of side-by-side. The 2-col and
     3-col grids in shared.css become single-column on phone. */
  .field-row,
  .field-row-3 {
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
  }

  /* Section block padding tighter so forms aren't mostly white space */
  .section-block { padding-top: 18px; margin-top: 18px; }
  #view-project-form .section-block { padding-top: 18px; margin-top: 18px; }

  /* ─── Project sheet card padding ─────────────────────────── */
  /* Already has an 880px breakpoint that stacks financials/links
     to 2-col; at this narrower width, drop padding so the card
     uses the available width. */
  #view-project-sheet { padding: 12px 6px 36px; }
  .prj-sheet { padding: 24px 16px 28px; }
  .prj-sheet-name { font-size: 22px; }
  .prj-sheet-financials { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
  .prj-sheet-links       { grid-template-columns: minmax(0, 1fr); }
  .prj-sheet-arch-row    { grid-template-columns: 120px 1fr; gap: 8px; }
  .prj-sheet-collab { flex-direction: column; align-items: stretch; gap: 6px; }
  .prj-sheet-collab-meta { text-align: left; flex-direction: row; gap: 12px; flex-wrap: wrap; }

  /* ─── PDF views (estimate + invoice) ─────────────────────── */
  /* The PDF view is shell + iframe. Make the iframe fill width,
     and let its toolbar wrap. */
  #view-estimate-pdf .setup-head,
  #view-invoice-pdf  .setup-head {
    flex-direction: column;
    gap: 8px;
  }
  #est-pdf-frame, #inv-pdf-frame { width: 100%; min-height: 70vh; }

  /* ─── Archive table ──────────────────────────────────────── */
  /* Already has a 1180px treatment; at phone widths drop more
     columns (delivered date, year, sizes) so just Project + RAID
     + Vault HDD remain. */
  .arch-row,
  .arch-row-head {
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
    gap: 8px;
    padding: 8px 10px;
    font-size: 11px;
  }
  .arch-row > :not(:nth-child(2)):not(:nth-child(3)),
  .arch-row-head > :not(:nth-child(2)):not(:nth-child(3)) { display: none; }

  /* ─── Schedule (My Schedule) ─────────────────────────────── */
  /* The month grid is dense; can't really fit on phones without a
     rethink. For Phase 2 we just tighten cell typography so a
     swipe-y reading still works in landscape; full mobile schedule
     redesign would be a separate ticket. */
  .schedule-cell { font-size: 10px; }
  .schedule-cell-num { font-size: 11px; }

  /* ─── Refinement pass: catch remaining overflow patterns ─── */

  /* Clients list: collapse the 6-column row to Company + Total.
     The other columns (contact, project count, last invoice, etc.)
     are read-only metadata better surfaced in the client detail. */
  .cli-row,
  .cli-row-head {
    grid-template-columns: minmax(0, 1fr) 90px;
    gap: 8px;
    padding: 10px 12px;
    font-size: 12px;
  }
  .cli-row > :nth-child(n+3),
  .cli-row-head > :nth-child(n+3) { display: none; }
  .cli-row-head { display: none; }   /* cards self-label */

  /* Client detail tab rows (recent estimates/invoices/projects).
     Keep date + name + amount; drop status pill and num column. */
  .cli-detail-row {
    grid-template-columns: 88px minmax(0, 1fr) 80px;
    gap: 10px;
    font-size: 12px;
  }
  .cli-detail-row > :nth-child(n+4) { display: none; }

  /* Invoice + estimate form line-item rows: collapse to a single
     column so each input gets its own line. Looks tall but won't
     overflow; edit-on-desktop is the priority flow anyway. The
     header row hides since the stacked inputs are self-labeling
     via their placeholders. */
  .inv-form-row,
  .editable-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
    padding: 10px 0;
    border-bottom: 1px dashed rgba(26,46,61,.12);
  }
  .inv-form-head { display: none; }

  /* Project edit form: link-pill row that lists linked invoices,
     contractor invoices, etc. Each pill can be long — let them
     wrap onto multiple lines rather than overflow. */
  .prj-link-pill { white-space: normal; word-break: break-word; }

  /* Toast / snack-bar can be wider than the viewport on phones
     because it was sized for desktop. Constrain. */
  #toast {
    max-width: calc(100vw - 24px) !important;
    left: 12px !important;
    right: 12px !important;
  }

  /* Reports tab — two-column panel grid stacks to single column.
     This was the bug where Monthly Revenue + Top Clients stayed
     side-by-side on phones, squashing both. */
  .rep-twocol {
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
  }

  /* Top Clients header row: "Client" + (bar) + "Paid" — the bare
     <div> in the head wasn't in the shared.css nowrap allowlist so
     letter-spaced "Client" still wrapped at narrow widths. Force
     nowrap on every cell of the head row. */
  .ov-rev-head > * { white-space: nowrap; }
  /* Same row's data cells: numbers must never break ("$58,525.00"
     was wrapping at the comma on the narrowest phones). */
  .ov-rev-num,
  .ov-rev-row .ov-rev-client { white-space: nowrap; }
  .ov-rev-row .ov-rev-client {
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Reports tab — profitability table */
  /* Reduce the 6-column row to: Name + Actual + Delta. Estimated,
     Client, and Margin% are still computable from the project
     sheet; this card on the reports page just needs to be readable. */
  .rep-row,
  .rep-row-head {
    grid-template-columns: minmax(0, 1.6fr) 90px 80px;
    gap: 8px;
    padding: 9px 10px;
    font-size: 11px;
  }
  .rep-row > :nth-child(2),    /* client */
  .rep-row > :nth-child(3),    /* estimated */
  .rep-row > :nth-child(6),    /* margin% */
  .rep-row-head > :nth-child(2),
  .rep-row-head > :nth-child(3),
  .rep-row-head > :nth-child(6) { display: none; }
  .rep-row-head { display: none; }    /* cards self-label */
  /* Numeric cells in the profitability rows can't wrap or they
     split mid-number ("$22,925.00" → "$22,925." / "00"). */
  .rep-num, .rep-row > .rep-num { white-space: nowrap; }

  /* Monthly revenue bars: nowrap on the value so "$35,400.00" never
     wraps and gets clipped by the card edge. */
  .rep-bar-row {
    grid-template-columns: 50px minmax(40px, 1fr) 78px;
    gap: 8px;
    font-size: 10.5px;
  }
  .rep-bar-value { white-space: nowrap; }

  /* ─── Project sheet actuals table: numeric cells must not wrap ───
     The sheet's <table.prj-sheet-actuals> inherits overflow-wrap:
     anywhere from .main-content. That makes "$3,750.00" or "34.5 h"
     break in narrow cells. Lock all numeric cells (rate, hours,
     total, subtotals) to single-line. */
  .prj-sheet-actuals td.num,
  .prj-sheet-actuals th.num,
  .prj-sheet-actuals tr.prj-sheet-total td,
  .prj-sheet-actuals tr.prj-sheet-subtotal td {
    white-space: nowrap;
  }
  /* Rate column is the one that crowds the table on mobile. The
     rate is the same for all of Joel's tracker entries (his hourly),
     so it's redundant per-row. Hide it on narrow widths — Hours +
     Total still tell the full story. */
  .prj-sheet-actuals th:nth-child(3),
  .prj-sheet-actuals td:nth-child(3) { display: none; }
}

/* Phone-only tweaks (below tablet portrait). Mostly typographic so
   small screens don't word-wrap critical labels into 3 lines. */
@media (max-width: 460px) {
  /* Stats compress further */
  .ov-stat-value { font-size: 20px; }
  .ov-stat-label { font-size: 8.5px; letter-spacing: 1.3px; }
  /* Project sheet identity */
  .prj-sheet { padding: 22px 16px 28px; }
  .prj-sheet-name { font-size: 19px; }
  .prj-sheet-status { font-size: 9px; padding: 4px 8px; }
  .prj-sheet-financials { gap: 14px; }
  .prj-sheet-stat-value { font-size: 18px; }

  /* Projects toolbar stats — stack value above label on phones so
     the dollar amount has full card width and doesn't truncate next
     to the label. Two-column 2×2 grid stays from the desktop rule. */
  .prj-stat-card {
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    padding: 8px 12px 9px;
  }
  .prj-stat-card-value { font-size: 14px; }
  .prj-stat-card-label { font-size: 9px; letter-spacing: 1.3px; }

  /* The External Costs and Frame.io inline add-rows are 3-column
     grids on desktop; on phones each input is too narrow to type
     into. Flatten to a single column so each field is full-width
     with the button last. */
  .prj-ec-add-form,
  .prj-frameio-add-row {
    grid-template-columns: 1fr;
    gap: 6px;
  }
  /* Same for the rendered external-cost rows. The delete + open
     glyphs become a small action row below the inputs.
     Column order (desktop): service_type, label, amount (cost), bill,
     url, open, del — preserve that vertical order on narrow widths. */
  .prj-ec-row {
    grid-template-columns: 1fr 90px;
    grid-template-areas:
      "service service"
      "label   label"
      "amount  amount"
      "bill    bill"
      "url     url"
      "open    del";
    gap: 6px 8px;
  }
  .prj-ec-row > :nth-child(1) { grid-area: service; }
  .prj-ec-row > :nth-child(2) { grid-area: label; }
  .prj-ec-row > :nth-child(3) { grid-area: amount; }
  .prj-ec-row > :nth-child(4) { grid-area: bill; }
  .prj-ec-row > :nth-child(5) { grid-area: url; }
  .prj-ec-row > :nth-child(6) { grid-area: open; justify-self: start; }
  .prj-ec-row > :nth-child(7) { grid-area: del;  justify-self: end; }

  /* Section title row on the project sheet — let the toggle wrap
     under the title at narrow widths so the label has room. */
  .prj-sheet-section-title-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }

  /* Restore Backup modal — let the action buttons inside backup-row
     wrap below the timestamp on phones. */
  .backup-row {
    grid-template-columns: 1fr auto;
    gap: 6px 8px;
  }
  .backup-row-rel { grid-column: 1 / 2; }
  .backup-row .btn-restore { grid-row: 1 / 3; grid-column: 2 / 3; align-self: center; }
}

/* ─── Send Invoice modal (Stripe ACH + Gmail) ───────────────────── */
.inv-send-card { max-width: 420px; width: 92vw; padding: 20px 20px 16px; }
/* Shared .ap-modal-body sets white-space:pre-wrap, which turns every
   newline + indent in the modal's HTML template into literal vertical
   whitespace. Reset to normal flow inside the Send Invoice card. */
.inv-send-card .ap-modal-body {
  white-space: normal;
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.inv-send-card .ap-modal-actions { margin-top: 14px; }
.inv-send-summary {
  padding: 10px 12px;
  border: 1px solid rgba(10, 50, 84, .12);
  border-radius: 6px;
  background: rgba(10, 50, 84, .03);
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--navy);
}
.inv-send-summary > div { margin: 0; }
.inv-send-summary > div + div { margin-top: 4px; }
.inv-send-card .field-label {
  font-size: 10px;
  letter-spacing: 1.5px;
  color: rgba(26, 46, 61, .55);
  margin: 0 0 6px 0;
  text-transform: uppercase;
  font-weight: 600;
}
.inv-send-card .text-input {
  width: 100%;
  font-size: 13px;
  padding: 7px 10px;
}
.inv-send-template-choices {
  display: flex;
  gap: 10px;
}
.inv-send-template-choice {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 8px 8px 10px;
  border: 1px solid rgba(10, 50, 84, .15);
  border-radius: 8px;
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease;
}
.inv-send-template-choice:hover { border-color: rgba(10, 50, 84, .35); }
.inv-send-template-choice:has(input:checked) {
  border-color: #0a3254;
  background: rgba(10, 50, 84, .04);
}
.inv-send-template-choice input { margin: 0; accent-color: #0a3254; }
/* Thumbnail container — fixed aspect, clips an internal iframe that
   renders the real email template scaled down. The radial-gradient
   placeholder behind shows immediately so the thumb never reads as
   blank while the iframe is loading. */
.inv-send-template-thumb {
  width: 100%;
  /* Taller than square so the iframe can show header + headline +
     amount-due card + Pay Now button. The email natural width is
     600px; at scale(0.25) the visible vertical range is
     thumb-height-px * 4. With aspect-ratio 4/5 + ~150px wide thumbs,
     that's 187px × 4 = 750px of email content. */
  aspect-ratio: 4 / 5;
  border-radius: 4px;
  border: 1px solid rgba(0, 0, 0, .08);
  position: relative;
  overflow: hidden;
}
.inv-send-template-thumb.is-dark {
  background:
    radial-gradient(ellipse at 30% 0%, #1a3a5c 0%, #0c1420 55%, #050e18 100%);
}
.inv-send-template-thumb.is-light {
  background:
    radial-gradient(ellipse at 30% 0%, #f7f3eb 0%, #ffffff 55%, #ffffff 100%);
}
/* The iframe is fixed at the email's natural width (600px) and a tall
   crop, scaled with CSS transform so the recipient-facing template
   renders correctly inside a tiny thumbnail. pointer-events: none so
   clicks pass through to the surrounding radio label. */
.inv-send-template-thumb iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 600px;
  height: 800px;
  border: 0;
  transform: scale(0.25);
  transform-origin: top left;
  pointer-events: none;
}
.inv-send-template-label {
  font-size: 9.5px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(26, 46, 61, .65);
}
.inv-send-error {
  padding: 8px 10px;
  border-radius: 6px;
  background: rgba(190, 50, 50, .08);
  color: #8a2424;
  font-size: 12px;
  line-height: 1.4;
  word-break: break-all;
}

/* Tiny "Sent May 12, 2026" under the status pill in invoice rows.
   Sits on the same column as the pill, single line, small + muted. */
.inv-sent-stamp {
  margin-top: 3px;
  font-size: 10.5px;
  line-height: 1.2;
  white-space: nowrap;
}

/* ── RESTORE FROM BACKUP MODAL ─────────────────────────────
   Sized for a long scrollable list of snapshots grouped by day.
   Uses <details> elements for the day grouping so the open/close
   state is browser-native, keyboard-friendly, and free. */
.backup-restore-modal {
  width: 520px;
  max-width: calc(100vw - 32px);
}
.backup-modal-intro {
  padding: 14px 18px 6px;
  font-size: 11.5px;
  line-height: 1.55;
  color: rgba(26,46,61,.7);
  background: #fbf9f3;
  border-bottom: 1px solid rgba(26,46,61,.08);
}
.backup-restore-modal .modal-body {
  padding: 6px 12px 16px;
  max-height: calc(92vh - 200px);
}
.backup-state {
  padding: 28px 14px;
  text-align: center;
  font-size: 12px;
  color: rgba(26,46,61,.6);
}
.backup-state.backup-error { color: #8a2424; }

.backup-day {
  border-top: 1px solid rgba(26,46,61,.06);
}
.backup-day:first-of-type { border-top: none; }
.backup-day > summary {
  list-style: none;
  cursor: pointer;
  padding: 11px 8px 11px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-radius: 4px;
  user-select: none;
}
.backup-day > summary::-webkit-details-marker { display: none; }
.backup-day > summary::before {
  content: "▸";
  font-size: 10px;
  color: rgba(26,46,61,.4);
  margin-right: 8px;
  transition: transform .14s;
  display: inline-block;
}
.backup-day[open] > summary::before { transform: rotate(90deg); }
.backup-day > summary:hover { background: var(--hover-tint); }
.backup-day-label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--navy);
  letter-spacing: .2px;
  flex: 1;
}
.backup-day-count {
  font-size: 10px;
  color: rgba(26,46,61,.5);
  letter-spacing: .3px;
}
.backup-list {
  list-style: none;
  margin: 0 0 6px;
  padding: 0 0 0 8px;
}
.backup-row {
  display: grid;
  grid-template-columns: 64px 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 7px 10px 7px 22px;
  border-radius: 4px;
  transition: background .12s;
}
.backup-row:hover { background: var(--hover-tint); }
.backup-row-time {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--navy);
  font-weight: 500;
}
.backup-row-rel {
  font-size: 10.5px;
  color: rgba(26,46,61,.55);
}
.btn-restore {
  background: transparent;
  border: 1px solid rgba(26,46,61,.18);
  color: var(--navy);
  padding: 4px 12px;
  border-radius: 14px;
  font-family: var(--font);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .14s, border-color .14s, color .14s;
}
.btn-restore:hover {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--beige);
}
