/* ==========================================================================
   Dufour Job Book - design system (redevelopment, 2026-07-27)
   Direction: LIGHT workspace, DARK chrome, ONE yellow accent used sparingly.
   Derived from the agreed Sales Pipeline concept. Every colour is a token;
   no component may invent its own.
   ========================================================================== */

:root{
  /* chrome + brand */
  --chrome:#111827;
  --chrome-2:#1B2432;
  --brand-yellow:#F2E519;
  --yellow-hover:#D9C900;
  --yellow-soft:#FDFAC7;

  /* surfaces */
  --app-bg:#F9FAFB;
  --surface:#FFFFFF;
  --surface-warm:#FAF6E1;
  --border:#E5E7EB;
  --border-strong:#D6DAE1;

  /* text */
  --text:#111827;
  --text-muted:#4B5563;
  --text-invert:#FFFFFF;

  /* semantic. TWO tokens per colour, and the difference is load-bearing:
     --won / --due are FILLS (a dot, a bar, a calendar block, a border), read as
     colour rather than as words. --won-text / --due-text are those colours
     taken down until they clear 4.5:1 as TEXT on their own tint AND on white,
     which the fill values do not: #16833D on #E7F5EC measures 4.29 and #B4832E
     on #FBF1DC measures 3.01. Use the -text one in any `color:` declaration. */
  --won:#16833D;
  --won-text:#157C3A;      /* 4.67 on --won-bg, 5.25 on white */
  --won-bg:#E7F5EC;
  --due:#B4832E;
  --due-text:#8C6624;      /* 4.62 on --due-bg, 5.18 on white */
  --due-bg:#FBF1DC;
  --overdue:#DC3545;
  --overdue-bg:#FDECEE;
  --info-bg:#EEF2F7;

  /* shape + depth */
  --r-card:10px;
  --r-pill:999px;
  --r-input:6px;
  --shadow:0 1px 2px rgba(17,24,39,.04), 0 4px 12px rgba(17,24,39,.06);
  --shadow-lift:0 2px 6px rgba(17,24,39,.08), 0 12px 28px rgba(17,24,39,.10);

  --sidebar-w:236px;
  --sidebar-w-collapsed:72px;
  --font:'Poppins',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
}

*{ box-sizing:border-box; }
html,body{ margin:0; padding:0; }
body{
  font-family:var(--font);
  background:var(--app-bg);
  color:var(--text);
  font-size:14px;
  line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
body.booting > .app,
body.booting > .mobile-topbar{ display:none; }
.hidden{ display:none !important; }
a{ color:inherit; }

/* utility label: small caps is where the industrial character lives */
.label,.tag,.section-note,.kpi-card .label{
  font-size:10.5px; font-weight:600; letter-spacing:.09em; text-transform:uppercase;
  color:var(--text-muted);
}

/* ======================= TEXT ON A DARK SURFACE =======================
   2026-08-19, the operator on his phone: "certain text on the job pop up is not
   visible at all and some has low contrast".

   It was not visible because it was #111827 on #111827, contrast 1.00. The
   cause is structural, and this is the third time it has bitten (11 August, the
   additional-works block at 1.06; 13 August, the same block moved the other
   way): a component written for the light workspace uses --text and
   --text-muted, and those two tokens mean near-black and dark grey whatever is
   painted behind them. Move that component into a dark block and it disappears,
   with no rule anywhere being wrong on its own.

   So the DARK BLOCK states what its own text is, once, and everything inside it
   is right by inheritance instead of by somebody remembering. A block that
   paints itself dark adds itself to this list. Measured, not guessed: white at
   .72 over #111827 is 9.57:1, at .55 is 6.06:1.

   The light islands INSIDE those blocks (a white input, a tinted pill, the
   yellow total bar) take the light set back, because they are light surfaces
   that happen to sit on a dark one. That list came from measuring every
   descendant's background: artifacts/qa/_islands.mjs. */
.job-header,
.pay-total,
.qb-summary{
  --text:#FFFFFF;
  --text-muted:rgba(255,255,255,.72);
  --border:rgba(255,255,255,.18);
  --border-strong:rgba(255,255,255,.30);
}
.job-header input, .job-header select, .job-header textarea,
.pay-total input, .pay-total select, .pay-total textarea,
.qb-summary input, .qb-summary select, .qb-summary textarea,
.job-header .pill, .job-header .pay-pill, .job-header .tag-chip,
.pay-total .pill, .pay-total .pay-pill, .pay-total .tag-chip,
.qb-summary .pill, .qb-summary .pay-pill, .qb-summary .tag-chip,
.qb-summary .qb-total{
  --text:#111827;
  --text-muted:#4B5563;
  --border:#E5E7EB;
  --border-strong:#D6DAE1;
}
/* A ghost button is transparent, so on a dark block the block's own text colour
   has to carry it, and the base rule's light-grey hover would put white text on
   #F3F4F6. Both stated here rather than left to inheritance. */
.job-header .btn-ghost,
.pay-total .btn-ghost,
.qb-summary .btn-ghost{ color:rgba(255,255,255,.86); border-color:rgba(255,255,255,.30); }
.job-header .btn-ghost:hover,
.pay-total .btn-ghost:hover,
.qb-summary .btn-ghost:hover{ background:rgba(255,255,255,.14); color:#FFFFFF; }
/* Its label is white at 15.9:1, but its edges are #111827 on #111827, so the
   button has no visible shape on the panel it sits on. */
.job-header .btn-dark,
.pay-total .btn-dark,
.qb-summary .btn-dark{ border-color:rgba(255,255,255,.30); }

/* ============================ SHELL ============================ */
.app{ display:flex; min-height:100vh; }

.sidebar{
  width:var(--sidebar-w); flex:0 0 var(--sidebar-w);
  background:var(--chrome); color:var(--text-invert);
  display:flex; flex-direction:column; position:sticky; top:0; height:100vh;
  transition:width .18s ease, flex-basis .18s ease;
}
.brand{ padding:24px 20px 20px; border-bottom:1px solid rgba(255,255,255,.08); position:relative; }
.brand-logo-big{ width:100%; max-width:148px; height:auto; display:block; transition:max-width .18s ease; }
.login-logo{ width:40px; height:40px; object-fit:contain; border-radius:6px; }

/* --------------------------- sidebar collapse ---------------------------- */
.sidebar-collapse-btn{
  position:absolute; top:15px; right:10px; width:24px; height:24px; border-radius:6px;
  display:flex; align-items:center; justify-content:center;
  border:1px solid rgba(255,255,255,.18); background:rgba(255,255,255,.06);
  color:rgba(255,255,255,.75); cursor:pointer; transition:background .12s ease,color .12s ease;
}
.sidebar-collapse-btn:hover{ background:rgba(255,255,255,.16); color:#fff; }
.sidebar-collapse-btn svg{ transition:transform .18s ease; }
.sidebar.collapsed{ width:var(--sidebar-w-collapsed); flex:0 0 var(--sidebar-w-collapsed); }
.sidebar.collapsed .brand{ padding:18px 8px 14px; }
.sidebar.collapsed .brand-logo-big{ max-width:34px; margin:0 auto; }
.sidebar.collapsed .sidebar-collapse-btn{ position:static; margin:8px auto 0; transform:none; }
.sidebar.collapsed .sidebar-collapse-btn svg{ transform:rotate(180deg); }
.sidebar.collapsed .navlist{ padding:12px 8px; }
.sidebar.collapsed .navlist button{ justify-content:center; padding:11px 0; gap:0; }
.sidebar.collapsed .navlist button .lbl{ display:none; }
.sidebar.collapsed .sidebar-foot{ padding:12px 6px 16px; }
.sidebar.collapsed .user-card{ justify-content:center; padding:8px 0; }
.sidebar.collapsed .user-meta,
.sidebar.collapsed .user-signout{ display:none; }
/* the content column reflows automatically since .sidebar is flex:0 0 <w> */

.navlist{ padding:12px 10px; display:flex; flex-direction:column; gap:2px; flex:1; overflow-y:auto; }
.navlist button{
  position:relative; display:flex; align-items:center; gap:11px;
  background:transparent; border:0; color:rgba(255,255,255,.72);
  font-family:var(--font); font-size:13.5px; font-weight:500;
  padding:10px 12px; border-radius:8px; cursor:pointer; text-align:left; width:100%;
  transition:background .12s ease,color .12s ease;
}
.navlist button:hover{ background:rgba(255,255,255,.07); color:#fff; }
.navlist button.active{ background:rgba(255,255,255,.10); color:#fff; font-weight:600; }
/* the vertical yellow selection bar from the concept */
.navlist button.active::before{
  content:''; position:absolute; left:0; top:9px; bottom:9px; width:3px;
  border-radius:0 3px 3px 0; background:var(--brand-yellow);
}
.navlist button .ico{
  display:flex; align-items:center; justify-content:center;
  width:16px; height:16px; flex:0 0 auto; opacity:.85;
}
.navlist button:hover .ico,
.navlist button.active .ico{ opacity:1; }

.sidebar-foot{
  padding:12px 12px 16px; border-top:1px solid rgba(255,255,255,.08);
}
.user-card{
  display:none; align-items:center; gap:9px; padding:8px 6px; border-radius:10px;
}
.user-avatar{
  width:32px; height:32px; border-radius:50%; flex:0 0 auto;
  background:var(--brand-yellow); color:var(--chrome);
  display:flex; align-items:center; justify-content:center;
  font-family:var(--font); font-weight:700; font-size:13px;
}
.user-meta{ flex:1; min-width:0; }
.user-name{ font-size:13px; font-weight:600; color:#fff; line-height:1.3; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.user-sub{ font-size:11px; color:rgba(255,255,255,.55); line-height:1.3; }  /* .45 measured 4.48:1 */
.user-signout{
  flex:0 0 auto; width:28px; height:28px; border-radius:7px; border:0; background:transparent;
  color:rgba(255,255,255,.5); display:flex; align-items:center; justify-content:center; cursor:pointer;
}
.user-signout:hover{ background:rgba(255,255,255,.12); color:#fff; }

.content{ flex:1; min-width:0; padding:26px 30px 60px; }

/* view header */
.view-head{
  display:flex; align-items:flex-start; justify-content:space-between; gap:16px;
  margin-bottom:20px; flex-wrap:wrap;
}
.view-head h2{ font-size:23px; font-weight:700; margin:0; letter-spacing:-.015em; }
.view-head .sub{ color:var(--text-muted); font-size:13px; margin-top:3px; }

/* ============================ CARDS ============================ */
.card{
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-card); padding:18px; box-shadow:var(--shadow);
  margin-bottom:16px;
}
.card h3{
  font-size:13px; font-weight:700; margin:0 0 14px; letter-spacing:-.01em;
  display:flex; align-items:center; justify-content:space-between; gap:10px;
}
.card-head-row{ display:flex; align-items:center; justify-content:space-between; gap:10px; margin-bottom:14px; }

.grid-2{ display:grid; grid-template-columns:1fr 1fr; gap:16px; align-items:start; }
.grid-3{ display:grid; grid-template-columns:repeat(3,1fr); gap:16px; align-items:start; }
.kpi-grid,.kpi-row{ display:grid; grid-template-columns:repeat(4,1fr); gap:14px; margin-bottom:18px; align-items:start; }

.kpi-card{
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-card);
  padding:15px 16px; box-shadow:var(--shadow);
}
.kpi-card .value{
  font-size:24px; font-weight:700; letter-spacing:-.02em; margin-top:5px; line-height:1.15;
}
.kpi-card .value.big{ font-size:30px; }
.kpi-card .delta{ font-size:11.5px; color:var(--text-muted); margin-top:4px; }
.kpi-card.is-hero{ border-color:var(--brand-yellow); box-shadow:0 0 0 3px var(--yellow-soft), var(--shadow); }
.kpi-card.is-alert{ border-color:var(--overdue); }
.kpi-card.is-alert .value{ color:var(--overdue); }

/* ============================ BUTTONS ============================ */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
  font-family:var(--font); font-size:13px; font-weight:600;
  padding:9px 15px; border-radius:var(--r-input); border:1px solid var(--border-strong);
  background:var(--surface); color:var(--text); cursor:pointer; white-space:nowrap;
  transition:background .12s ease,border-color .12s ease,transform .06s ease;
}
.btn:hover{ background:#F3F4F6; }
.btn:active{ transform:translateY(1px); }
.btn-sm{ font-size:12px; padding:6px 11px; }
.btn-dark{ background:var(--chrome); color:#fff; border-color:var(--chrome); }
.btn-dark:hover{ background:#000; }
/* the one bright accent: primary money/commit actions only */
.btn-amber{ background:var(--brand-yellow); color:#111827; border-color:var(--brand-yellow); font-weight:700; }
.btn-amber:hover{ background:var(--yellow-hover); border-color:var(--yellow-hover); }
.btn-ghost{ background:transparent; border-color:var(--border); color:var(--text-muted); }
.btn-ghost:hover{ background:#F3F4F6; color:var(--text); }
.btn-danger{ background:var(--surface); color:var(--overdue); border-color:#F3C2C7; }
.btn-danger:hover{ background:var(--overdue-bg); }
.btn-wa{ background:#25D366; color:#fff; border-color:#25D366; }
.btn-wa:hover{ background:#1FB457; border-color:#1FB457; }
.link-btn{
  background:none; border:0; color:var(--text); font-family:var(--font); font-size:12.5px;
  font-weight:600; cursor:pointer; padding:0; text-decoration:underline;
  text-underline-offset:3px; text-decoration-thickness:1.5px; text-decoration-color:var(--brand-yellow);
}
.row-actions{ display:flex; gap:6px; flex-wrap:wrap; align-items:center; justify-content:flex-start; }
td .row-actions{ flex-wrap:nowrap; }

/* ============================ FORMS ============================ */
.form-row{ margin-bottom:13px; }
.form-row label,.form-row > .label{ display:block; margin-bottom:5px; }
.form-2col{ display:grid; grid-template-columns:1fr 1fr; gap:13px; }
input,select,textarea{
  font-family:var(--font); font-size:13.5px; width:100%; padding:9px 11px;
  border:1px solid var(--border-strong); border-radius:var(--r-input);
  background:var(--surface); color:var(--text);
}
input:focus,select:focus,textarea:focus{
  outline:none; border-color:var(--chrome); box-shadow:0 0 0 3px rgba(17,24,39,.07);
}
textarea{ min-height:80px; resize:vertical; }
.toolbar{ display:flex; gap:9px; align-items:center; flex-wrap:wrap; margin-bottom:14px; }
.search-input{ max-width:290px; }
.hint{ font-size:11.5px; color:var(--text-muted); line-height:1.5; }
.section-note{ margin-bottom:9px; }

/* ============================ TABLES ============================ */
.table-wrap,.card-scroll{ overflow-x:auto; -webkit-overflow-scrolling:touch; }
/* a scrollable table should LOOK scrollable, not truncated */
.table-wrap{ background:linear-gradient(90deg,transparent 92%,rgba(17,24,39,.05) 100%); }
.table-wrap::-webkit-scrollbar{ height:7px; }
.table-wrap::-webkit-scrollbar-thumb{ background:var(--border-strong); border-radius:4px; }
table{ width:100%; border-collapse:collapse; font-size:13px; }
th{
  text-align:left; padding:9px 11px; border-bottom:1px solid var(--border);
  font-size:10.5px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
  color:var(--text-muted); white-space:nowrap; background:var(--surface);
}
td{ padding:10px 11px; border-bottom:1px solid #F1F3F5; vertical-align:middle; }
tbody tr:last-child td{ border-bottom:0; }
tbody tr:hover{ background:#FCFCFD; }
.num-cell{ text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; min-width:104px; }
/* header must follow its column's alignment, or the number sits under nothing */
th.num-cell{ text-align:right; }
/* money must never be truncated: let the wrapper scroll instead of clipping the figure */
td.num-cell{ overflow:visible; text-overflow:clip; }
.mono{ font-variant-numeric:tabular-nums; }
th.th-sort{ cursor:pointer; user-select:none; }
th.th-sort:hover{ color:var(--text); }
td.ed-cell{ cursor:pointer; }
td.ed-cell:hover{ background:var(--yellow-soft); box-shadow:inset 0 0 0 1.5px var(--brand-yellow); border-radius:4px; }
.ed-input{ padding:4px 6px; font-size:13px; border:1.5px solid var(--brand-yellow); border-radius:var(--r-input); }
.name{ font-weight:600; }
.meta{ font-size:11.5px; color:var(--text-muted); }
.empty-state{
  text-align:center; padding:34px 18px; color:var(--text-muted); font-size:13px;
  border:1px dashed var(--border-strong); border-radius:var(--r-card); background:#FCFCFD;
}

/* ============================ PILLS ============================ */
.pill{
  display:inline-flex; align-items:center; gap:5px; padding:3px 10px;
  border-radius:var(--r-pill); font-size:11px; font-weight:700;
  letter-spacing:.03em; background:var(--info-bg); color:var(--text-muted); white-space:nowrap;
}
/* Status pills are short labels and should never wrap, but the margin warning
   on a job is a whole sentence: on a phone it ran off the side of the card. */
.pill.pill-wrap{ white-space:normal; text-align:left; line-height:1.45; }
@media (max-width:820px){ .pill-overdue{ white-space:normal; line-height:1.45; } }
.pill-won,.pill-accepted,.pill-completed,.pill-paid{ background:var(--won-bg); color:var(--won-text); }
.pill-sent,.pill-quoted,.pill-ongoing,.pill-contacted,.pill-due{ background:var(--due-bg); color:var(--due-text); }
.pill-lost,.pill-rejected,.pill-overdue{ background:var(--overdue-bg); color:var(--overdue); }
.pill-new,.pill-draft,.pill-pipeline{ background:var(--info-bg); color:#4B5563; }
.pill-urgent{ background:var(--brand-yellow); color:#111827; }
.tag-chip{
  display:inline-block; padding:3px 9px; border-radius:var(--r-pill);
  background:var(--info-bg); font-size:11.5px; margin:0 5px 5px 0;
}

/* ============================ OVERVIEW COMPARTMENTS ============================ */
.zones{ display:grid; grid-template-columns:1fr 1fr; gap:16px; align-items:start; }
.zone{
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-card);
  box-shadow:var(--shadow); overflow:hidden;
}
.zone-head{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:13px 16px; border-bottom:1px solid var(--border); background:#FCFCFD;
}
.zone-head h3{ margin:0; font-size:12px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; }
.zone-body{ padding:16px; }
.zone-body > :last-child{ margin-bottom:0; }

/* Today list */
.today-item{
  display:flex; align-items:flex-start; gap:11px; padding:10px 0;
  border-bottom:1px solid #F1F3F5;
}
.today-item:last-child{ border-bottom:0; }
.today-dot{ width:9px; height:9px; border-radius:50%; margin-top:6px; flex:0 0 9px; }
.today-dot.red{ background:var(--overdue); }
.today-dot.amber{ background:var(--due); }
.today-dot.green{ background:var(--won); }
.today-text{ flex:1; font-size:13.5px; }
.today-text small{ display:block; color:var(--text-muted); font-size:11.5px; margin-top:1px; }

/* funnel */
.funnel-row{ display:flex; align-items:center; gap:11px; margin-bottom:10px; }
.funnel-label{ width:64px; font-size:11.5px; color:var(--text); font-weight:600; }
.funnel-track{ flex:1; height:22px; background:var(--info-bg); border-radius:var(--r-input); overflow:hidden; }
.funnel-fill{ height:100%; background:var(--chrome); border-radius:var(--r-input); }
.funnel-row:last-child .funnel-fill{ background:var(--brand-yellow); }
.funnel-val{ width:66px; text-align:right; font-weight:700; font-size:13px; font-variant-numeric:tabular-nums; }

/* goal bar */
.target-row{ display:flex; align-items:center; justify-content:space-between; margin-bottom:7px; }
.target-label{ font-size:12px; color:var(--text-muted); }
.target-bar{ height:11px; background:var(--info-bg); border-radius:var(--r-pill); overflow:hidden; }
.target-bar > span{ display:block; height:100%; background:var(--brand-yellow); border-radius:var(--r-pill); }

/* margin bar (estimated vs actual) */
.mbar{ height:8px; background:var(--info-bg); border-radius:var(--r-pill); overflow:hidden; margin-top:5px; }
.mbar > span{ display:block; height:100%; background:var(--won); border-radius:var(--r-pill); }
.mbar.warn > span{ background:var(--due); }
.mbar.over > span{ background:var(--overdue); }

/* ============================ PIPELINE (KANBAN) ============================ */
.kanban{ display:grid; grid-template-columns:repeat(4,minmax(220px,1fr)); gap:14px; align-items:start; }
.kcol{ background:#F3F4F6; border:1px solid var(--border); border-radius:var(--r-card); min-height:130px; }
.kcol-head{
  display:flex; align-items:center; justify-content:space-between;
  padding:11px 13px; border-bottom:1px solid var(--border);
}
.kcol-head strong{ font-size:12px; font-weight:700; letter-spacing:.05em; text-transform:uppercase; }
.kcount{ background:var(--surface); border:1px solid var(--border); border-radius:var(--r-pill); font-size:11px; font-weight:700; padding:1px 8px; }
/* Won holds every job ever landed (65 and counting), so an uncapped column
   stretched the page to seven screens and buried the three columns that
   actually need working. Each column scrolls inside itself instead. */
.kcol-body{
  padding:11px; display:flex; flex-direction:column; gap:9px;
  min-height:60px; max-height:64vh; overflow-y:auto; overscroll-behavior:contain;
}
@media (max-width:820px){ .kcol-body{ max-height:52vh; } }
.kcard{
  background:var(--surface); border:1px solid var(--border); border-radius:8px;
  padding:11px 12px; box-shadow:var(--shadow); cursor:grab;
}
.kcard:hover{ box-shadow:var(--shadow-lift); }
.kcard.dragging{ opacity:.45; }
.kcard .kname{ font-weight:600; font-size:13px; margin-bottom:3px; }
.kcard .kmeta{ font-size:11.5px; color:var(--text-muted); }
.kcard .kval{ font-weight:700; font-size:13.5px; margin-top:6px; font-variant-numeric:tabular-nums; }
.kcol.dragover{ outline:2px dashed var(--brand-yellow); outline-offset:-3px; }

/* bottom KPI strip from the concept */
.kpi-strip{
  display:flex; gap:26px; flex-wrap:wrap; align-items:center;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-card);
  padding:15px 20px; box-shadow:var(--shadow); margin:16px 0;
}
.kpi-strip .item{ flex:1; min-width:130px; }
.kpi-strip .item .value{ font-size:19px; font-weight:700; font-variant-numeric:tabular-nums; }

/* ============================ TIMELINE ============================ */
.timeline{ position:relative; padding-left:26px; }
.timeline::before{ content:''; position:absolute; left:8px; top:5px; bottom:5px; width:2px; background:var(--border); }
.tl-item{ position:relative; padding:0 0 17px; }
.tl-item::before{
  content:''; position:absolute; left:-22px; top:3px; width:13px; height:13px;
  border-radius:50%; background:var(--brand-yellow); border:2px solid var(--surface);
  box-shadow:0 0 0 1.5px var(--border);
}
.tl-item.future::before{ background:var(--border); }
.tl-title{ font-weight:600; font-size:13px; }
.tl-date{ font-size:11.5px; color:var(--text-muted); }

/* ============================ PHOTOS ============================ */
.photo-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(118px,1fr)); gap:10px; }
.photo-thumb{ position:relative; border-radius:8px; overflow:hidden; border:1px solid var(--border); background:#F3F4F6; aspect-ratio:1/1; }
.photo-thumb img{ width:100%; height:100%; object-fit:cover; display:block; }
.photo-thumb .pdel{
  position:absolute; top:5px; right:5px; background:rgba(17,24,39,.78); color:#fff;
  border:0; border-radius:50%; width:23px; height:23px; cursor:pointer; font-size:13px; line-height:1;
}
.photo-thumb .pdate{
  position:absolute; left:0; right:0; bottom:0; background:linear-gradient(transparent,rgba(0,0,0,.6));
  color:#fff; font-size:10.5px; padding:12px 6px 4px;
}
.upload-tile{
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px;
  aspect-ratio:1/1; border:2px dashed var(--border-strong); border-radius:8px;
  cursor:pointer; color:var(--text-muted); font-size:11.5px; text-align:center; background:#FCFCFD;
}
.upload-tile:hover{ border-color:var(--brand-yellow); background:var(--yellow-soft); color:var(--text); }

/* note cards */
.note-card{
  background:var(--surface-warm); border:1px solid #EFE7C6; border-radius:8px;
  padding:11px 13px; margin-bottom:9px; font-size:13px; position:relative;
}
.note-card .ndate{ font-size:11px; color:var(--text-muted); margin-top:5px; }
.note-card .ndel{ position:absolute; top:8px; right:9px; background:none; border:0; cursor:pointer; color:var(--text-muted); font-size:14px; }

/* ============================ MODAL ============================ */
.modal-backdrop{
  position:fixed; inset:0; background:rgba(17,24,39,.55); z-index:200;
  display:flex; align-items:flex-start; justify-content:center; padding:34px 16px; overflow-y:auto;
}
.modal{
  background:var(--surface); border-radius:12px; width:100%; max-width:640px;
  box-shadow:var(--shadow-lift); overflow:hidden;
}
.modal.modal-wide{ max-width:880px; }
.modal-head{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:16px 20px; border-bottom:1px solid var(--border); background:var(--chrome); color:#fff;
}
.modal-head h3{ margin:0; font-size:15px; font-weight:600; }
.modal-close{ background:none; border:0; color:rgba(255,255,255,.75); font-size:22px; cursor:pointer; line-height:1; }
.modal-close:hover{ color:#fff; }
.modal-body{ padding:20px; max-height:calc(100vh - 220px); overflow-y:auto; }
.modal-foot{ padding:14px 20px; border-top:1px solid var(--border); display:flex; justify-content:flex-end; gap:9px; background:#FCFCFD; }

/* ============================ QUOTE BUILDER ============================ */
.qb{ display:grid; grid-template-columns:1fr 300px; gap:18px; align-items:start; }
.qb-summary{
  background:var(--chrome); color:#fff; border-radius:var(--r-card); padding:17px; position:sticky; top:0;
}
.qb-summary .label{ color:rgba(255,255,255,.6); }
.qb-summary .row{ display:flex; justify-content:space-between; align-items:baseline; padding:8px 0; border-bottom:1px solid rgba(255,255,255,.11); }
.qb-summary .row:last-of-type{ border-bottom:0; }
.qb-summary .row .v{ font-weight:700; font-variant-numeric:tabular-nums; }
.qb-total{
  background:var(--brand-yellow); color:#111827; border-radius:8px; padding:12px 14px; margin-top:12px;
}
/* This sits INSIDE .qb-summary, so `.qb-summary .label` (white at .6, written
   for the dark card) applies to it and paints #FAF5A3 on #F2E519: contrast
   1.16, which is nothing at all. Equal specificity, so it has to come after. */
.qb-total .label{ color:rgba(17,24,39,.72); }   /* 6.26:1 on the yellow */
.qb-total .value{ font-size:25px; font-weight:700; letter-spacing:-.02em; font-variant-numeric:tabular-nums; }
.qb-line{ display:grid; grid-template-columns:118px 1fr 118px 34px; gap:8px; align-items:center; margin-bottom:8px; }
.margin-slider{ width:100%; accent-color:var(--brand-yellow); }

/* ============================ MOBILE ============================ */
/* Defaults must come BEFORE the media query: equal specificity means
   the LAST matching rule wins, so a trailing reset silently kills it. */
.tabbar{ display:none; }
.mobile-topbar{ display:none; }
.nav-scrim{ display:none; }
.mobile-only{ display:none !important; }

@media (max-width:1100px){
  .zones{ grid-template-columns:1fr; }
  .kpi-grid,.kpi-row{ grid-template-columns:repeat(2,1fr); }
  .qb{ grid-template-columns:1fr; }
  .qb-summary{ position:static; }
  .kanban{ grid-template-columns:repeat(2,minmax(200px,1fr)); }
}

@media (max-width:820px){
  .mobile-only{ display:block !important; }
  .desktop-only{ display:none !important; }

  .mobile-topbar{
    display:flex; align-items:center; gap:11px; position:sticky; top:0; z-index:90;
    background:var(--chrome); color:#fff; padding:11px 14px;
  }
  .mobile-topbar img{ height:26px; width:auto; object-fit:contain; }
  .hamburger{ background:none; border:0; color:#fff; font-size:21px; cursor:pointer; padding:2px 5px; }

  .app{ display:block; }
  .sidebar{
    position:fixed; left:0; top:0; bottom:0; z-index:120; height:100vh;
    transform:translateX(-100%); transition:transform .2s ease; width:260px;
  }
  /* the collapse toggle is a desktop concept; on a phone the sidebar is
     already an off-canvas drawer, so force full width regardless of a
     collapsed preference saved from a desktop session. */
  .sidebar.collapsed{ width:260px; }
  .sidebar-collapse-btn{ display:none; }
  body.nav-open .sidebar{ transform:translateX(0); }
  body.nav-open .nav-scrim{ display:block; position:fixed; inset:0; background:rgba(17,24,39,.5); z-index:110; }

  /* 90px cleared the tab bar but not the Quick Add button, which floats
     between 720px and 770px on an 844px screen: at full scroll the last row
     of a list sat under it. 128px puts the last card clear of both. */
  .content{ padding:16px 14px 128px; }
  .view-head h2{ font-size:20px; }
  .kpi-grid,.kpi-row,.grid-2,.grid-3,.form-2col{ grid-template-columns:1fr !important; }
  .kanban{ grid-template-columns:1fr; }
  .modal{ max-width:none; }
  .modal-body{ max-height:none; }
  .qb-line{ grid-template-columns:1fr 1fr; }
  .card{ padding:15px; }
  .btn{ padding:10px 14px; }
  .row-actions .btn{ flex:1 1 auto; min-width:84px; }
  table{ font-size:12.5px; }

  /* bottom tab bar: the phone's primary navigation */
  .tabbar{
    display:flex; position:fixed; left:0; right:0; bottom:0; z-index:100;
    background:var(--chrome); border-top:1px solid rgba(255,255,255,.1);
    padding:6px 4px calc(6px + env(safe-area-inset-bottom));
  }
  .tabbar button{
    flex:1; background:none; border:0; color:rgba(255,255,255,.6); cursor:pointer;
    font-family:var(--font); font-size:10.5px; font-weight:600; padding:7px 2px;
    display:flex; flex-direction:column; align-items:center; gap:3px;
  }
  .tabbar button .ico{ font-size:17px; line-height:1; }
  .tabbar button.active{ color:var(--brand-yellow); }
}

/* ============================ THIS MORNING (phone) ============================ */
.morning-card{
  display:flex; align-items:flex-start; gap:12px;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-card);
  padding:14px 15px; margin-bottom:10px; box-shadow:var(--shadow);
}
.morning-card .mstat{
  font-size:9.5px; font-weight:800; letter-spacing:.08em; padding:3px 8px;
  border-radius:var(--r-pill); white-space:nowrap;
}
.mstat.red{ background:var(--overdue-bg); color:var(--overdue); }
.mstat.amber{ background:var(--due-bg); color:var(--due-text); }
.mstat.green{ background:var(--won-bg); color:var(--won-text); }
.morning-card .mtext{ flex:1; font-size:14px; font-weight:500; }
.morning-card .mtext small{ display:block; font-weight:400; color:var(--text-muted); font-size:11.5px; margin-top:2px; }

/* big fat mobile action buttons on a job */
.job-actions{ display:grid; grid-template-columns:repeat(3,1fr); gap:9px; margin:14px 0; }
.job-actions .btn{ flex-direction:column; gap:5px; padding:15px 8px; font-size:11.5px; }
.job-actions .btn .ico{ font-size:19px; }

/* ============================ MISC ============================ */
.chart-wrap{ position:relative; height:230px; }
.upcoming-card{
  border:1px solid var(--border); border-radius:8px; padding:11px 13px; margin-bottom:9px; background:var(--surface);
}
.upcoming-card.clickable:hover{ border-color:var(--brand-yellow); background:#FFFEF5; cursor:pointer; }
.clickable{ cursor:pointer; }
.fu-name-link{ cursor:pointer; text-decoration:underline; text-decoration-style:dotted; text-underline-offset:2px; }
.fu-name-link:hover{ color:var(--due-text); }
.tip-item{ display:flex; gap:10px; align-items:flex-start; margin-bottom:11px; font-size:13px; }
.tip-icon{ flex:0 0 auto; }
.followup-item{
  display:flex; align-items:center; justify-content:space-between; gap:11px;
  padding:11px 0; border-bottom:1px solid #F1F3F5; flex-wrap:wrap;
}
.followup-item:last-child{ border-bottom:0; }
#toast{
  position:fixed; left:50%; bottom:26px; transform:translateX(-50%);
  background:var(--chrome); color:#fff; padding:11px 19px; border-radius:var(--r-pill);
  font-size:13px; z-index:400; box-shadow:var(--shadow-lift); opacity:0; pointer-events:none;
  transition:opacity .2s ease;
}
#toast.show{ opacity:1; }

/* The toasts the app ACTUALLY shows.
   showToast() has appended `div.toast` into #toastRoot since the redevelopment,
   and the only rule in this file was the older `#toast` element, which nothing
   creates. So every confirmation the app has raised, including the one added in
   August specifically so a saved cost could not be missed, was rendering as
   unstyled body text at the bottom of the page. Found while building the undo
   toast below, which cannot work without a styled, clickable surface. */
#toastRoot{
  position:fixed; left:50%; bottom:26px; transform:translateX(-50%);
  z-index:400; display:flex; flex-direction:column-reverse; align-items:center; gap:8px;
  pointer-events:none; max-width:min(560px, calc(100vw - 32px));
}
#toastRoot .toast{
  background:var(--chrome); color:#fff; padding:11px 19px; border-radius:var(--r-pill);
  font-size:13px; line-height:1.4; box-shadow:var(--shadow-lift); text-align:center;
  pointer-events:auto; animation:toast-in .18s ease-out;
}
@keyframes toast-in{ from{ opacity:0; transform:translateY(6px); } to{ opacity:1; transform:none; } }

/* Undo lives ON the toast: one tap is easy to do by accident, and the way back
   has to be under the thumb at the moment the mistake is noticed. */
#toastRoot .toast-undo{
  display:flex; align-items:center; gap:14px; text-align:left; padding:10px 10px 10px 19px;
}
#toastRoot .toast-undo .tu-msg{ flex:1 1 auto; }
#toastRoot .toast-undo .tu-undo{
  flex:0 0 auto; background:var(--brand-yellow); color:var(--chrome); border:0;
  border-radius:var(--r-pill); padding:6px 14px; font:inherit; font-weight:700; font-size:12.5px;
  cursor:pointer;
}
#toastRoot .toast-undo .tu-undo:hover{ background:var(--yellow-hover); }

/* ---- the job-value Save confirmation (2026-08-31) ----
   The form he filmed had no Save and said nothing after an edit, so a value
   that saved and a value that did not looked identical. This is the answer,
   in the form, with the way back attached. */
.pd-save-row{ display:flex; flex-direction:column; gap:10px; }
.pd-save-row .btn-amber{ min-height:44px; font-size:14px; }
.pd-saved{
  display:flex; align-items:center; gap:12px; padding:10px 12px 10px 16px;
  border-radius:8px; background:var(--chrome); color:#fff; font-size:13px;
}
.pd-saved strong{ color:var(--brand-yellow); }
.pd-saved > span{ flex:1 1 auto; }
.pd-saved .btn-undo{
  flex:0 0 auto; background:var(--brand-yellow); color:var(--chrome); border:0;
  border-radius:var(--r-pill); padding:6px 14px; font:inherit; font-weight:700;
  font-size:12.5px; cursor:pointer;
}
.pd-saved .btn-undo:hover{ background:var(--yellow-hover); }
.pd-saved-bad{ background:var(--overdue-bg); color:var(--overdue); }
@media (max-width:520px){
  #toastRoot{ bottom:84px; }   /* clear of the phone tab bar */
}
@media (prefers-reduced-motion:reduce){
  #toastRoot .toast{ animation:none; }
}

/* The "Coming up" entry point beside a view's primary action (item J). */
.head-actions{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.count-badge{
  display:inline-block; margin-left:7px; min-width:18px; padding:1px 6px; border-radius:var(--r-pill);
  background:var(--chrome); color:#fff; font-size:11px; font-weight:700; line-height:1.5;
  font-variant-numeric:tabular-nums;
}

/* ============================ LOGIN ============================ */
/* The gate is hidden by DEFAULT and shown only when .show is added.
   (Getting this the wrong way round leaves a fixed overlay covering the whole
   app after sign-in, which a full-page screenshot hides but a phone does not.) */
#loginGate{
  position:fixed; inset:0; z-index:500; background:var(--chrome);
  display:none; align-items:center; justify-content:center; padding:20px;
}
#loginGate.show{ display:flex; }
.login-card{
  background:var(--surface); border-radius:14px; padding:32px 30px; width:100%; max-width:370px;
  box-shadow:var(--shadow-lift); text-align:left;
}
.login-card .login-logo{ width:54px; height:54px; margin-bottom:14px; }
.login-card h2{ margin:0 0 3px; font-size:20px; font-weight:700; }
.login-sub{ color:var(--text-muted); font-size:13px; margin-bottom:20px; }
.login-card label{ display:block; font-size:11px; font-weight:600; letter-spacing:.07em; text-transform:uppercase; color:var(--text-muted); margin:12px 0 5px; }
.login-card .btn{ width:100%; margin-top:18px; padding:11px; }
.login-err{ display:none; background:var(--overdue-bg); color:var(--overdue); padding:9px 11px; border-radius:var(--r-input); font-size:12.5px; margin-bottom:12px; }
.login-err.show{ display:block; }

/* respect users who ask for less motion */
@media (prefers-reduced-motion:reduce){
  *{ transition:none !important; animation:none !important; }
}

/* ============================ QUICK ADD (capture) ============================ */
.qa-fab{
  position:fixed; right:22px; bottom:26px; z-index:150;
  width:56px; height:56px; border-radius:50%;
  background:var(--brand-yellow); color:#111827; border:0;
  font-size:30px; font-weight:400; line-height:1; cursor:pointer;
  box-shadow:var(--shadow-lift);
}
.qa-fab:hover{ background:var(--yellow-hover); }
/* The FAB is fixed at the bottom-right, so it lands ON TOP of whatever happens
   to be at that spot. That was harmless while the right-hand end of a row was
   an inert chevron. It stopped being harmless the moment a real action went
   there: measured on the live Money owed screen, the + was covering TWO "Paid
   in full" buttons, so tapping to settle those two jobs opened Quick Add
   instead. Flagged by a vision consult, then confirmed by measuring the
   rectangles rather than taken on trust.
   Padding the end of the list does NOT fix it (mid-scroll the + still lands on
   a row), so on the one screen where every row ends in an action, the + stands
   down. It is unchanged everywhere else. */
body[data-view="owed"] .qa-fab{ display:none; }
/* Clearance at the end of every list anyway, so the last row is never half
   under the button on the screens that keep it. */
.view{ padding-bottom:96px; }
/* The ask panel used to sit BEHIND this button (z-index 71 vs 150), so the
   FAB visibly overlapped the open chat drawer. Belt and braces: hide the FAB
   whenever the panel is open, on top of the panel now correctly outranking it. */
body.ask-open .qa-fab{ display:none; }

/* Voice capture. Recording is the one state that must be unmistakable at a
   glance on site, so it gets red plus a pulse rather than a subtle tint. */
.btn.is-recording{
  background:var(--overdue-bg); color:var(--overdue); border-color:var(--overdue);
  font-weight:700; animation:recPulse 1.4s ease-in-out infinite;
}
.btn.is-recording:hover{ background:var(--overdue-bg); }
.btn[disabled]{ opacity:.65; cursor:default; }
@keyframes recPulse{
  0%,100%{ box-shadow:0 0 0 0 rgba(220,53,69,.34); }
  50%    { box-shadow:0 0 0 6px rgba(220,53,69,0); }
}
@media (prefers-reduced-motion:reduce){ .btn.is-recording{ animation:none; } }
@media (max-width:820px){
  /* clear the bottom tab bar */
  .qa-fab{ bottom:calc(78px + env(safe-area-inset-bottom)); right:16px; width:54px; height:54px; }
}

/* stacked estimated-vs-actual rows for the phone */
.cost-row{ border:1px solid var(--border); border-radius:8px; padding:11px 12px; margin-bottom:9px; background:var(--surface); }
.cost-row-top{ display:flex; justify-content:space-between; align-items:baseline; gap:10px; margin-bottom:5px; font-size:13.5px; }
.cost-row-vals{ display:flex; justify-content:space-between; gap:10px; font-size:12px; color:var(--text-muted); margin-bottom:7px; }
/* the tab bar overlays content, so say so with a shadow rather than looking like a clip */
.tabbar{ box-shadow:0 -6px 18px rgba(17,24,39,.18); }

/* ==========================================================================
   OVERVIEW OVERHAUL + AGENT SURFACE (2026-07-27)
   Defaults are declared BEFORE their media queries throughout. Equal
   specificity means the last rule wins, and getting that backwards is how the
   phone tab bar went missing once already.
   ========================================================================== */

/* ------------------------------ segmented ------------------------------- */
.seg{
  display:inline-flex; gap:2px; padding:3px; background:#EFF1F4;
  border:1px solid var(--border); border-radius:var(--r-pill);
}
.seg button{
  border:0; background:transparent; cursor:pointer; font-family:var(--font);
  font-size:12.5px; font-weight:600; color:var(--text-muted);
  padding:6px 13px; border-radius:var(--r-pill); white-space:nowrap;
  transition:background .14s ease, color .14s ease;
}
.seg button:hover{ color:var(--text); }
.seg button.active{ background:var(--surface); color:var(--text); box-shadow:0 1px 2px rgba(17,24,39,.10); }
.seg.seg-sm button{ font-size:11.5px; padding:5px 11px; }
/* The board tabs are the primary control. A dark pill IS the active state;
   the earlier ::after underline stacked a second active-state treatment on
   top of the first pill and read as a stray line inside the button. */
.board-tabs button.active{ background:var(--chrome); color:var(--text-invert); }
.board-controls{
  display:flex; align-items:center; justify-content:space-between;
  gap:12px; flex-wrap:wrap; margin-bottom:18px;
}
.card-head{ display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-bottom:12px; }
.card-head h3{ margin:0; }

/* -------------------------------- hero ---------------------------------- */
.hero-row{ display:grid; grid-template-columns:minmax(260px,340px) 1fr; gap:16px; align-items:stretch; }
.hero-card{
  background:var(--chrome); color:var(--text-invert); border-radius:var(--r-card);
  padding:20px 22px; display:flex; flex-direction:column; justify-content:center;
  box-shadow:var(--shadow);
}
.hero-label{ font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; opacity:.7; }
.hero-figure{
  font-size:54px; line-height:1.02; font-weight:800; letter-spacing:-.02em;
  margin:6px 0 8px; color:var(--brand-yellow);
}
.hero-sub{ font-size:12.5px; line-height:1.5; opacity:.82; }
.hero-list{
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-card);
  box-shadow:var(--shadow); padding:6px 16px; overflow:hidden;
}

/* ------------------------- today: 5-row left column ----------------------
   Replaces the old oversized dark "needs you" card, which carried a huge
   54px figure for what was often a one-line message. The four stat tiles
   that used to sit in their own full-width row below now live as four more
   rows in the SAME column, so the whole "what needs attention" picture reads
   top to bottom in one glance instead of one hero card plus a separate grid. */
.today-col{ display:flex; flex-direction:column; gap:8px; }
.today-row{
  flex:1; display:flex; align-items:center; justify-content:space-between; gap:10px;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-card);
  padding:11px 15px; box-shadow:var(--shadow);
}
.today-row.clickable{ cursor:pointer; transition:border-color .14s ease, box-shadow .14s ease; }
.today-row.clickable:hover{ border-color:var(--border-strong); box-shadow:var(--shadow-lift); }
.today-row-hero{ background:var(--chrome); color:var(--text-invert); border-color:var(--chrome); }
.today-row .tr-label{ font-size:11px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; opacity:.68; }
.today-row-hero .tr-label{ opacity:.7; }
.today-row .tr-main{ display:flex; align-items:baseline; gap:9px; min-width:0; }
.today-row .tr-value{ font-size:19px; font-weight:800; letter-spacing:-.01em; flex:0 0 auto; }
.today-row-hero .tr-value{ color:var(--brand-yellow); }
.today-row .tr-sub{ font-size:11px; color:var(--text-muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.today-row-hero .tr-sub{ color:rgba(255,255,255,.72); }
.today-row.tone-good .tr-value{ color:var(--won-text); }
.today-row.tone-bad .tr-value{ color:var(--overdue); }
.today-row.tone-warn .tr-value{ color:var(--due-text); }
@media (max-width:600px){
  .today-row{ flex-wrap:wrap; }
  .today-row .tr-main{ width:100%; justify-content:space-between; }
  .today-row .tr-sub{ white-space:normal; text-align:right; }
}
.today-go{ margin-left:auto; color:var(--text-muted); font-size:17px; line-height:1; opacity:0; transition:opacity .14s ease; }
.today-item.clickable{ cursor:pointer; }
.today-item.clickable:hover{ background:#FBFCFD; }
.today-item.clickable:hover .today-go{ opacity:1; }

/* ----------------------------- stat tiles -------------------------------- */
.tile-grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:14px; margin-top:16px; }
.stat-tile{
  position:relative; overflow:hidden;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-card);
  padding:15px 16px 14px; box-shadow:var(--shadow);
  transition:border-color .14s ease, box-shadow .14s ease, transform .14s ease;
}
.stat-tile.clickable{ cursor:pointer; }
.stat-tile.clickable:hover{ border-color:var(--border-strong); box-shadow:var(--shadow-lift); transform:translateY(-1px); }
.tile-label{ font-size:10.5px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; color:var(--text-muted); }
.tile-value{ font-size:27px; font-weight:700; letter-spacing:-.015em; line-height:1.18; margin:5px 0 3px; }
.tile-foot{ display:flex; align-items:baseline; gap:7px; flex-wrap:wrap; min-height:17px; }
.tile-delta{ font-size:11.5px; font-weight:700; }
.tile-delta.up{ color:var(--won-text); }
.tile-delta.down{ color:var(--overdue); }
.tile-prev{ font-size:11.5px; color:var(--text-muted); }
.tile-spark{ margin:6px -16px -14px; height:40px; pointer-events:none; }
.stat-tile.tone-good .tile-value{ color:var(--won-text); }
.stat-tile.tone-bad  .tile-value{ color:var(--overdue); }
.stat-tile.tone-warn .tile-value{ color:var(--due-text); }

/* --------------------------- job lines / goal ---------------------------- */
.job-line{ padding:11px 0; border-bottom:1px solid var(--border); }
.job-line:last-child{ border-bottom:0; }
.job-line.clickable{ cursor:pointer; }
.job-line.clickable:hover .job-name{ text-decoration:underline; }
.job-line-top{ display:flex; justify-content:space-between; align-items:baseline; gap:10px; margin-bottom:7px; }
.job-name{ font-weight:600; font-size:13.5px; }
.job-val{ font-variant-numeric:tabular-nums; font-weight:600; font-size:13px; }
.job-line-foot{ display:flex; justify-content:space-between; gap:10px; font-size:11.5px; color:var(--text-muted); margin-top:6px; }
.job-line-foot .pos{ color:var(--won-text); font-weight:600; }
.job-line-foot .neg{ color:var(--overdue); font-weight:600; }
.spend-bar{ height:6px; border-radius:3px; background:#EFF1F4; overflow:hidden; }
.spend-bar > span{ display:block; height:100%; border-radius:3px; transition:width .3s ease; }
.goal-foot{ display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-top:6px; }
.goal-foot .label{ display:block; font-size:10.5px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--text-muted); }
.goal-foot strong{ font-size:15px; font-variant-numeric:tabular-nums; }

/* =============================== ASK BAR ================================= */
.ask-bar{
  display:flex; align-items:center; gap:8px;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-pill);
  padding:6px 6px 6px 14px; margin:0 0 18px; box-shadow:var(--shadow);
  transition:border-color .15s ease, box-shadow .15s ease;
}
.ask-bar:focus-within{ border-color:var(--chrome); box-shadow:var(--shadow-lift); }
.ask-spark{ display:flex; color:var(--chrome); flex:0 0 auto; }
.ask-input{
  flex:1 1 auto; min-width:0; border:0; outline:0; background:transparent;
  font-family:var(--font); font-size:13.5px; color:var(--text); padding:6px 2px;
}
.ask-input::placeholder{ color:#8B93A1; }
.ask-scope{
  flex:0 0 auto; font-size:10.5px; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  color:var(--text-muted); background:#EFF1F4; border-radius:var(--r-pill); padding:4px 10px;
}
.ask-mic, .ask-go{
  flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center;
  width:32px; height:32px; border-radius:50%; border:1px solid var(--border);
  background:var(--surface); color:var(--text-muted); cursor:pointer; font-size:15px; line-height:1;
  transition:background .14s ease, color .14s ease, border-color .14s ease;
  /* These are fixed-size circles in a flex row. If anything ever puts words
     inside one again, they get clipped here rather than laid across the
     pill and the send button. The real guard is in app3.js setBtn(). */
  padding:0; overflow:hidden; white-space:nowrap;
}
.ask-mic:hover, .ask-go:hover{ color:var(--text); border-color:var(--border-strong); }
.ask-go{ background:var(--chrome); color:var(--text-invert); border-color:var(--chrome); font-weight:700; }
.ask-go:hover{ background:#000; color:var(--brand-yellow); }

/* Recording has to be obvious at a glance without growing the button, so the
   icon circle turns red and pulses in place, the way the labelled Quick Add
   button does. Working = the mic swaps for a spinner (see setBtn). */
.ask-bar .is-recording{
  background:var(--overdue); color:#fff; border-color:var(--overdue);
  animation:recPulse 1.4s ease-in-out infinite;
}
.ask-mic.is-working{ opacity:.7; cursor:default; }
.voice-spin{ transform-origin:50% 50%; animation:voiceSpin .8s linear infinite; }
@keyframes voiceSpin{ to{ transform:rotate(360deg); } }
@media (prefers-reduced-motion:reduce){
  .ask-bar .is-recording, .ask-compose .ask-icon.is-recording{ animation:none; }
  .voice-spin{ animation:none; }
}

/* ======================= STAGING ENVIRONMENT BANNER ======================= */
/*
 * Staging is not the live book, and since 11 August it is not the address Jay
 * should be opening either. So the message has to be impossible to miss and
 * impossible to mistake for part of the app.
 *
 * It is a full-width bar in NORMAL DOCUMENT FLOW, not an overlay. It takes its
 * own height, and every element that pins itself to the top of the viewport is
 * offset by that height below, so the bar covers nothing: the 10 August session
 * bar covered the sidebar logo by 2,146px squared precisely because it was
 * anchored over the layout instead of inside it.
 *
 * z-index 130 sits above the app's own chrome (mobile topbar 90, tab bar 100,
 * off-canvas sidebar 120) and below the temporary overlays (drawers 155-160,
 * modals 200), so a drawer covers the bar while it is open, which is what an
 * overlay is for, and nothing is permanently hidden behind it.
 *
 * Production never sets `body.env-staging`, so none of this applies there even
 * though the identical stylesheet ships to both environments.
 */
/* A FALLBACK only, for the instant before the script measures the rendered bar
   and writes the real height into this property on <body>. Do not tune it to
   match a particular screen: the bar wraps to three lines on a phone, so any
   constant here is right on one width and wrong on the next. */
body.env-staging{ --envbar-h:46px; }

#envBar{
  position:sticky; top:0; z-index:130;
  display:flex; align-items:center; justify-content:center;
  flex-wrap:wrap; gap:5px 12px; text-align:center;
  /* A CONSTANT, never var(--envbar-h). The script writes the bar's measured
     height into that property, so using it here as the bar's own minimum locks
     the bar at the tallest height it has ever had: once the sentence wrapped to
     three lines the bar could never get short again, not on rotation and not
     when the phone rules take the sentence out of the layout. */
  box-sizing:border-box; min-height:42px; padding:11px 16px;
  background:#C4291F; color:#fff; border-bottom:2px solid #8B1D15;
  font-family:var(--font); font-size:13.5px; font-weight:600; line-height:1.35;
}
#envBar .envbar-tag{
  flex:0 0 auto; white-space:nowrap;
  font-size:11px; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
  /* DARKENS the red rather than lightening it: white on the lightened
     rgba(255,255,255,.2) chip measured 4.17:1, under AA at 10.5px. */
  background:rgba(0,0,0,.22); padding:3px 9px; border-radius:4px;
}
#envBar a{
  color:#fff; font-weight:700; white-space:nowrap;
  text-decoration:underline; text-underline-offset:2px; padding:1px 3px; border-radius:3px;
}
#envBar a:hover,#envBar a:focus-visible{ background:rgba(255,255,255,.18); }

/* Everything that pins to the top of the viewport now pins BELOW the bar. */
body.env-staging .sidebar{ top:var(--envbar-h); height:calc(100vh - var(--envbar-h)); }
body.env-staging #loginGate{ top:var(--envbar-h); }

@media (max-width:820px){
  /* 2026-08-19, the operator on his own iPhone: the sentence took three lines
     of a phone screen, which is a real slice of the only screen there is, to
     say something he already knows by the time he is testing. The phone keeps
     the MARK and drops the explanation: one thin red bar saying Test version,
     which is all the bar has to do (tell the two books apart in a screenshot
     or a bug report).

     The sentence is taken OUT OF THE LAYOUT rather than deleted, so a screen
     reader still hears what this page is: the bar is role="alert" and the
     explanation is the alert. display:none would have taken it off the
     accessibility tree with the pixels. */
  #envBar{ font-size:12.5px; padding:5px 12px; min-height:0; gap:0; }
  #envBar .envbar-msg{
    position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
  }
  #envBar .envbar-tag{ font-size:10.5px; padding:2px 8px; }
  body.env-staging .mobile-topbar{ top:var(--envbar-h); }
  body.env-staging .sidebar{ top:var(--envbar-h); height:calc(100vh - var(--envbar-h)); }
}

/* ============================== ASK PANEL ================================ */
.ask-scrim{
  position:fixed; inset:0; background:rgba(17,24,39,.34);
  opacity:0; pointer-events:none; transition:opacity .2s ease; z-index:155;
}
body.ask-open .ask-scrim{ opacity:1; pointer-events:auto; }
.ask-panel{
  position:fixed; top:0; right:0; bottom:0; width:min(440px,100vw);
  background:var(--surface); border-left:1px solid var(--border);
  box-shadow:-12px 0 40px rgba(17,24,39,.14);
  display:flex; flex-direction:column; z-index:156;
  transform:translateX(102%); transition:transform .24s cubic-bezier(.22,.7,.3,1);
}
body.ask-open .ask-panel{ transform:translateX(0); }
.ask-panel-head{
  display:flex; align-items:flex-start; justify-content:space-between; gap:12px;
  padding:15px 16px; background:var(--chrome); color:var(--text-invert); flex:0 0 auto;
}
.ask-panel-head strong{ font-size:14.5px; }
.ask-panel-sub{ font-size:11.5px; opacity:.72; margin-top:2px; }
.ask-panel-actions{ display:flex; gap:5px; }
.ask-icon{
  display:inline-flex; align-items:center; justify-content:center; width:28px; height:28px;
  border-radius:6px; border:1px solid rgba(255,255,255,.18); background:transparent;
  color:inherit; cursor:pointer; transition:background .14s ease;
}
.ask-icon:hover{ background:rgba(255,255,255,.12); }
.ask-thread{ flex:1 1 auto; overflow-y:auto; padding:16px; background:var(--app-bg); }
.ask-msg{ display:flex; gap:9px; margin-bottom:13px; align-items:flex-start; }
.ask-msg.user{ justify-content:flex-end; }
.ask-avatar{
  flex:0 0 24px; width:24px; height:24px; border-radius:50%; margin-top:2px;
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--chrome); color:var(--brand-yellow); font-size:12px;
}
.ask-bubble{
  max-width:82%; padding:10px 13px; border-radius:12px; font-size:13.5px; line-height:1.55;
  background:var(--surface); border:1px solid var(--border); box-shadow:var(--shadow);
}
.ask-msg.user .ask-bubble{ background:var(--chrome); color:var(--text-invert); border-color:var(--chrome); }
.ask-li{ display:block; padding-left:13px; position:relative; }
.ask-li::before{ content:'\00B7'; position:absolute; left:3px; font-weight:700; }
.ask-tools{
  margin-top:8px; padding-top:7px; border-top:1px solid var(--border);
  font-size:10.5px; color:var(--text-muted); letter-spacing:.02em;
}
.ask-err{ color:var(--overdue); }
.ask-dots{ display:inline-flex; gap:4px; padding:3px 0; }
.ask-dots i{ width:6px; height:6px; border-radius:50%; background:#B6BDC7; animation:askPulse 1.1s infinite ease-in-out; }
.ask-dots i:nth-child(2){ animation-delay:.15s; }
.ask-dots i:nth-child(3){ animation-delay:.3s; }
@keyframes askPulse{ 0%,80%,100%{ opacity:.3; transform:translateY(0); } 40%{ opacity:1; transform:translateY(-3px); } }
@media (prefers-reduced-motion:reduce){ .ask-dots i{ animation:none; } .ask-panel{ transition:none; } }

.ask-empty{ text-align:center; padding:26px 8px; }
.ask-empty-title{ font-weight:600; font-size:14.5px; margin-bottom:6px; }
.ask-empty-sub{ font-size:12.5px; color:var(--text-muted); line-height:1.55; max-width:330px; margin:0 auto 16px; }
.ask-suggest{ display:flex; flex-direction:column; gap:8px; align-items:stretch; }
.ask-chip{
  font-family:var(--font); font-size:12.5px; text-align:left; cursor:pointer;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-pill);
  padding:9px 14px; color:var(--text); transition:border-color .14s ease, background .14s ease;
}
.ask-chip:hover{ border-color:var(--chrome); background:#FFFEF5; }

.ask-compose{ flex:0 0 auto; display:flex; align-items:flex-end; gap:8px; padding:11px 12px; border-top:1px solid var(--border); background:var(--surface); }
.ask-compose textarea{
  flex:1 1 auto; resize:none; font-family:var(--font); font-size:13.5px; line-height:1.5;
  border:1px solid var(--border); border-radius:12px; padding:9px 11px; max-height:120px; outline:0;
}
.ask-compose textarea:focus{ border-color:var(--chrome); }
.ask-compose .ask-icon{
  border-color:var(--border); color:var(--text-muted); width:34px; height:34px;
  padding:0; overflow:hidden; white-space:nowrap;
}
.ask-compose .ask-icon:hover{ background:#EFF1F4; }
.ask-compose .ask-icon.is-recording{
  background:var(--overdue); color:#fff; border-color:var(--overdue);
  animation:recPulse 1.4s ease-in-out infinite;
}

.ask-history{ flex:0 0 auto; max-height:44%; overflow-y:auto; border-bottom:1px solid var(--border); background:var(--surface); }
.ask-hist-row{ display:flex; align-items:center; gap:8px; padding:10px 14px; border-bottom:1px solid var(--border); cursor:pointer; }
.ask-hist-row:hover{ background:#FBFCFD; }
.ask-hist-main{ flex:1 1 auto; min-width:0; }
.ask-hist-title{ font-size:13px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ask-hist-meta{ font-size:11px; color:var(--text-muted); text-transform:capitalize; }
.ask-hist-del{ border-color:var(--border); color:var(--text-muted); }
.ask-hist-del:hover{ background:var(--overdue-bg); color:var(--overdue); }

/* ------------------------- insight cards ("What can I do better?") ------- */
.insight-title{ display:flex; align-items:center; gap:7px; }
.insight-spark{ display:flex; color:var(--chrome); flex:0 0 auto; }
.insight-tag{
  font-size:9.5px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  color:var(--text-muted); background:#EFF1F4; border-radius:var(--r-pill); padding:3px 9px; white-space:nowrap;
}
.insight-list{ display:flex; flex-direction:column; gap:8px; }
.insight-row{
  border:1px solid var(--border); border-radius:10px; padding:11px 13px; background:var(--surface-warm);
  transition:border-color .14s ease, box-shadow .14s ease;
}
.insight-row.clickable{ cursor:pointer; }
.insight-row.clickable:hover{ border-color:var(--border-strong); box-shadow:var(--shadow); }
.insight-row:focus-visible{ outline:2px solid var(--chrome); outline-offset:1px; }
.insight-head{ font-size:13px; font-weight:600; line-height:1.4; }
.insight-detail{ font-size:12px; color:var(--text-muted); line-height:1.5; margin-top:4px; }
.insight-source{
  font-size:10px; color:var(--text-muted); text-transform:uppercase; letter-spacing:.04em;
  margin-top:7px; padding-top:6px; border-top:1px dashed rgba(17,24,39,.10);
}
.insight-loading{ font-size:12.5px; color:var(--text-muted); padding:4px 0; }

/* The draft a proposal produces. It is labelled "not saved" because it is not
   saved: nothing is written until Jay presses Save in the existing form. */
.draft-card{ border:1px solid var(--border-strong); border-radius:10px; padding:12px 13px; background:var(--surface-warm); }
.draft-head{ display:flex; align-items:center; justify-content:space-between; gap:10px; font-weight:700; font-size:13px; margin-bottom:9px; }
.draft-flag{
  font-size:9.5px; font-weight:800; letter-spacing:.07em; text-transform:uppercase;
  background:var(--chrome); color:var(--brand-yellow); border-radius:var(--r-pill); padding:3px 8px;
}
.draft-row{ display:flex; justify-content:space-between; gap:12px; font-size:12.5px; padding:4px 0; border-bottom:1px dashed rgba(17,24,39,.10); }
.draft-row:last-of-type{ border-bottom:0; }
.draft-row span{ color:var(--text-muted); }
.draft-actions{ display:flex; gap:8px; justify-content:flex-end; margin-top:11px; }

/* "Did you mean one of these?" (2026-08-31). Full-width tap targets, name
   first, because the whole point is that the name is one letter different from
   what he typed and he has to be able to see WHICH letter. */
.draft-near-wrap{ display:flex; flex-direction:column; gap:6px; margin-top:9px; }
.draft-near-head{ font-size:12px; font-weight:700; color:var(--text-muted); }
.btn.draft-near{
  display:flex; flex-direction:column; align-items:flex-start; gap:2px;
  width:100%; text-align:left; padding:9px 12px; min-height:44px; height:auto;
}
.btn.draft-near .dn-name{ font-weight:700; color:var(--text); font-size:13px; }
.btn.draft-near .dn-sub{ font-size:11.5px; color:var(--text-muted); }

/* ========================= SHARED ATTACHMENTS =========================== */
/* Files follow the work through enquiry -> quote -> job, so a tile has to say
   which stage it came in at when it was not added here. */
.file-tile{ display:block; }
.file-doc{
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:5px;
  text-decoration:none; color:var(--text); background:#FCFCFD; padding:10px 8px; text-align:center;
}
.file-doc:hover{ border-color:var(--border-strong); background:var(--info-bg); }
.file-ico{ color:var(--text-muted); line-height:0; }
.file-name{
  font-size:11px; font-weight:600; line-height:1.25; word-break:break-word;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
.file-meta{ font-size:10px; color:var(--text-muted); }
.stage-tag{
  position:absolute; left:5px; top:5px; background:rgba(17,24,39,.78); color:#fff;
  font-size:9.5px; font-weight:600; letter-spacing:.03em; text-transform:uppercase;
  padding:2px 6px; border-radius:var(--r-pill);
}
.upload-progress{ margin-top:10px; font-size:12px; color:var(--text-muted); }
.clip-badge{
  display:inline-flex; align-items:center; gap:2px; margin-left:6px; padding:1px 6px 1px 4px;
  background:var(--info-bg); color:var(--text-muted); border-radius:var(--r-pill);
  font-size:10.5px; font-weight:600; vertical-align:middle;
}
.clip-badge svg{ opacity:.75; }

/* ============================== GROWTH ================================== */
.growth-hero{
  background:var(--chrome); color:var(--text-invert); border-radius:var(--r-card);
  padding:20px 22px; margin-bottom:16px; box-shadow:var(--shadow);
}
.gh-top{ display:flex; align-items:center; justify-content:space-between; gap:18px; }
.gh-label{ font-size:11px; text-transform:uppercase; letter-spacing:.06em; color:#9CA3AF; font-weight:600; }
.gh-value{ font-size:38px; font-weight:700; line-height:1.15; display:flex; align-items:baseline; gap:10px; }
.gh-edit{
  background:transparent; border:1px solid rgba(255,255,255,.28); color:#E5E7EB;
  border-radius:var(--r-pill); font-size:11px; padding:3px 10px; cursor:pointer; font-family:var(--font);
}
.gh-edit:hover{ border-color:var(--brand-yellow); color:var(--brand-yellow); }
.gh-gauge{ width:170px; flex:0 0 170px; }
/* The bar is the year; the tick is today. Being left of the tick is being behind. */
.gh-bar{
  position:relative; height:9px; border-radius:var(--r-pill); background:rgba(255,255,255,.14);
  margin:16px 0 10px; overflow:visible;
}
.gh-bar > span{ display:block; height:100%; border-radius:var(--r-pill); background:var(--brand-yellow); }
.gh-pace{
  position:absolute; top:-4px; width:2px; height:17px; background:#fff; opacity:.85; border-radius:1px;
}
.gh-sub{ font-size:12.5px; color:#D1D5DB; }
.gh-flag{ font-weight:600; }
.gh-flag.behind{ color:#FCA5A5; }
.gh-flag.ahead{ color:#86EFAC; }
.growth-hero.no-goal{ text-align:center; }
.growth-hero.no-goal .gh-value{ justify-content:center; font-size:26px; margin-bottom:6px; }
.growth-hero.no-goal .gh-sub{ margin-bottom:14px; }

.growth-cols{ display:grid; grid-template-columns:1fr 1fr; gap:16px; align-items:start; }

.growth-need{ margin-bottom:14px; }
.gn-headline{ font-size:32px; font-weight:700; line-height:1.1; }
.gn-headline span{ display:block; font-size:12.5px; font-weight:500; color:var(--text-muted); margin-top:2px; }
.gn-note{ font-size:12.5px; color:var(--text-muted); margin-top:6px; }

.growth-funnel{ display:flex; flex-direction:column; gap:12px; }
.gf-row{ border-left:3px solid var(--border-strong); padding-left:12px; }
.gf-row.is-done{ border-left-color:var(--won); }
.gf-row.is-short{ border-left-color:var(--due); }
.gf-need{ display:flex; align-items:baseline; gap:7px; }
.gf-need strong{ font-size:21px; font-weight:700; }
.gf-need span{ font-size:12.5px; color:var(--text-muted); }
.gf-bar{ height:6px; border-radius:var(--r-pill); background:var(--border); margin:6px 0 5px; overflow:hidden; }
.gf-bar > span{ display:block; height:100%; background:#2C6BBE; border-radius:var(--r-pill); }
.gf-row.is-done .gf-bar > span{ background:var(--won); }
.gf-got{ font-size:12px; color:var(--text-muted); }
.gf-tick{ color:var(--won-text); font-style:normal; font-weight:600; margin-left:6px; }
.gf-gap{ color:var(--due-text); font-style:normal; font-weight:600; margin-left:6px; }
.growth-basis{
  margin-top:14px; padding-top:12px; border-top:1px solid var(--border);
  font-size:12.5px; color:var(--text-muted);
}
.growth-missing{ margin-top:4px; }

.growth-mix{ display:flex; height:12px; border-radius:var(--r-pill); overflow:hidden; background:var(--border); }
.gm-seg{ display:block; height:100%; }
.growth-mix-key{ display:flex; flex-wrap:wrap; gap:14px; margin-top:10px; font-size:12.5px; color:var(--text-muted); }
.growth-mix-key i{ display:inline-block; width:9px; height:9px; border-radius:3px; margin-right:6px; }

.growth-warn{ border-color:#F0D9A8; background:var(--due-bg); }
.growth-outlier{
  display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap;
  font-size:12.5px; padding:7px 0; border-bottom:1px dashed rgba(17,24,39,.12);
}
.growth-outlier:last-of-type{ border-bottom:0; }

.growth-levers{ display:flex; flex-direction:column; gap:2px; }
.gl-row{
  display:grid; grid-template-columns:1fr auto auto; gap:12px; align-items:baseline;
  padding:8px 0; border-bottom:1px dashed rgba(17,24,39,.10); font-size:12.5px;
}
.gl-row:last-child{ border-bottom:0; }
.gl-row.is-base{ color:var(--text-muted); }
.gl-value{ font-weight:600; white-space:nowrap; }
.gl-delta{ font-size:11.5px; color:var(--won-text); font-weight:600; white-space:nowrap; }
.gl-row.is-base .gl-delta{ color:var(--text-muted); font-weight:500; }

/* ------------------------------- responsive ------------------------------ */
@media (max-width:1100px){
  .tile-grid{ grid-template-columns:repeat(2,1fr); }
  .hero-row{ grid-template-columns:1fr; }
  .growth-cols{ grid-template-columns:1fr; }
}
@media (max-width:820px){
  .board-controls{ gap:9px; }
  /* The controls must never wrap into a two-line mess on a phone: they scroll. */
  .board-controls .seg{ max-width:100%; overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none; }
  .board-controls .seg::-webkit-scrollbar{ display:none; }
  .board-period{ order:2; }
  .hero-figure{ font-size:44px; }
  .tile-grid{ grid-template-columns:repeat(2,1fr); gap:10px; }
  .tile-value{ font-size:22px; }
  .ask-bar{ padding-left:12px; gap:6px; }
  /* The scope chip is the first thing to go: the input matters more than the label. */
  .ask-scope{ display:none; }
  .ask-panel{ width:100vw; border-left:0; }
  .ask-bubble{ max-width:88%; }
  .goal-foot{ gap:8px; }
  .goal-foot > div{ flex:1 1 30%; }
  /* Growth on a phone: the gauge and the big number cannot sit side by side
     without the number shrinking to nothing, so the gauge goes under it. */
  .growth-hero{ padding:16px 16px 18px; }
  .gh-top{ flex-direction:column; align-items:flex-start; gap:6px; }
  .gh-value{ font-size:30px; }
  .gh-gauge{ width:100%; flex:0 0 auto; margin-top:4px; }
  .gn-headline{ font-size:26px; }
  /* Three columns of levers do not fit; label over the two figures. */
  .gl-row{ grid-template-columns:1fr auto; }
  .gl-label{ grid-column:1 / -1; font-weight:600; color:var(--text); }
  .gl-row.is-base .gl-label{ color:var(--text-muted); }
}
@media (max-width:420px){
  .tile-grid{ grid-template-columns:1fr; }
}

/* ==========================================================================
   HEADLINE NUMBERS + THE SHEET (2026-07-28, Jay's 27 July feedback)

   "I just want that to be numbers, turnover, leads, ongoing jobs. And I click
    on that ... that will open up the slide."

   Two components: four pressable numbers at the top of Today, and one
   right-hand slide-over that every drill-through opens into. The sheet sits
   at z-index 160, above the ask panel (156), because a list opened from the
   chat has to land on top of it.
   ========================================================================== */
.big-nums{
  display:grid; grid-template-columns:repeat(4,1fr); gap:12px; margin-bottom:16px;
}
.big-num{
  display:flex; flex-direction:column; gap:5px; text-align:left;
  padding:16px 16px 15px; background:var(--surface);
  border:1px solid var(--border); border-radius:var(--r-card);
  box-shadow:var(--shadow-card); cursor:pointer; font:inherit; color:inherit;
  transition:border-color .14s ease, box-shadow .14s ease, transform .14s ease;
}
.big-num:hover{ border-color:var(--border-strong); box-shadow:var(--shadow-lift); transform:translateY(-1px); }
.big-num:focus-visible{ outline:2px solid var(--chrome); outline-offset:2px; }
.big-num .bn-label{
  font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
  color:var(--text-muted);
}
.big-num .bn-value{ font-size:30px; font-weight:800; letter-spacing:-.02em; line-height:1.05; }
.big-num .bn-sub{ font-size:11.5px; color:var(--text-muted); }
.big-num.tone-good .bn-value{ color:var(--won-text); }
.big-num.tone-bad  .bn-value{ color:var(--overdue); }

.needs-card .today-item:first-of-type{ border-top:1px solid var(--border); }
/* The chevron is hover-only elsewhere. On this list it must always show and
   sit centred: it is the affordance that says "there is a named list behind
   this row", and on a phone there is no hover, so a hover-only arrow means
   the one thing Jay asked for is invisible on the device he uses. */
.needs-card .today-go{
  color:var(--text-muted); font-size:17px; line-height:1;
  opacity:.55; align-self:center; margin-left:auto; flex:0 0 auto;
}
.needs-card .today-item.clickable:hover .today-go{ opacity:1; }
.needs-card .today-item{ align-items:center; }

@media (max-width:900px){ .big-nums{ grid-template-columns:repeat(2,1fr); gap:10px; } }
@media (max-width:430px){
  .big-num{ padding:13px 13px 12px; }
  .big-num .bn-value{ font-size:24px; }
}

/* ------------------------------- the sheet ------------------------------ */
.sheet-scrim{
  position:fixed; inset:0; background:rgba(17,24,39,.38);
  opacity:0; pointer-events:none; transition:opacity .2s ease; z-index:159;
}
body.sheet-open .sheet-scrim{ opacity:1; pointer-events:auto; }
.sheet{
  position:fixed; top:0; right:0; bottom:0; width:min(470px,100vw);
  background:var(--surface); border-left:1px solid var(--border);
  box-shadow:-12px 0 40px rgba(17,24,39,.16);
  display:flex; flex-direction:column; z-index:160;
  transform:translateX(102%); transition:transform .24s cubic-bezier(.22,.7,.3,1);
}
body.sheet-open .sheet{ transform:translateX(0); }
.sheet-head{
  display:flex; align-items:flex-start; justify-content:space-between; gap:12px;
  padding:16px; background:var(--chrome); color:var(--text-invert); flex:0 0 auto;
}
.sheet-head h3{ margin:0; font-size:15.5px; color:inherit; }
.sheet-sub{ font-size:11.5px; opacity:.74; margin-top:3px; line-height:1.5; }
.sheet-close{
  flex:0 0 28px; width:28px; height:28px; border-radius:6px;
  border:1px solid rgba(255,255,255,.18); background:transparent; color:inherit;
  cursor:pointer; font-size:13px; line-height:1;
}
.sheet-close:hover{ background:rgba(255,255,255,.12); }
.sheet-body{ flex:1 1 auto; overflow-y:auto; padding:14px 16px; background:var(--app-bg); }
.sheet-foot{
  flex:0 0 auto; padding:11px 16px; border-top:1px solid var(--border);
  background:var(--surface); display:flex; justify-content:flex-end;
}
.sheet-note{
  margin-top:12px; padding:10px 12px; border-radius:var(--r-input);
  background:var(--info-bg); font-size:11.5px; color:var(--text-muted); line-height:1.55;
}

/* ------------------------- named record list ---------------------------- */
.rec-list{ display:flex; flex-direction:column; gap:8px; }
.rec-row{
  display:flex; align-items:center; justify-content:space-between; gap:12px; width:100%;
  padding:12px 13px; background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-card); cursor:pointer; font:inherit; color:inherit; text-align:left;
  transition:border-color .14s ease, box-shadow .14s ease;
}
.rec-row:hover{ border-color:var(--border-strong); box-shadow:var(--shadow-lift); }
.rec-main{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.rec-name{ font-size:13.5px; font-weight:600; }
.rec-meta{ font-size:11.5px; color:var(--text-muted); line-height:1.45; }
.rec-right{ display:flex; align-items:center; gap:8px; flex:0 0 auto; }
.rec-value{ font-family:'JetBrains Mono',monospace; font-size:12.5px; font-weight:600; white-space:nowrap; }
.rec-value.tone-bad{ color:var(--overdue); }
.rec-value.tone-warn{ color:var(--due-text); }
.rec-go{ color:var(--text-muted); font-size:17px; line-height:1; }

/* --------------------- turnover, month by month ------------------------- */
.month-list{ display:flex; flex-direction:column; gap:9px; }
.month-row{
  padding:11px 13px; background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-card);
}
.month-top{ display:flex; align-items:baseline; justify-content:space-between; gap:10px; }
.month-name{ font-size:12.5px; font-weight:600; }
.month-rev{ font-family:'JetBrains Mono',monospace; font-size:13px; font-weight:700; }
.month-bar{ height:5px; border-radius:3px; background:var(--info-bg); margin:7px 0 6px; overflow:hidden; }
.month-bar span{ display:block; height:100%; background:var(--chrome); border-radius:3px; }
.month-foot{ display:flex; justify-content:space-between; gap:10px; font-size:11.5px; color:var(--text-muted); }
.month-foot .pos{ color:var(--won-text); }
.month-foot .neg{ color:var(--overdue); }
.month-total{
  margin-top:14px; padding:13px; border-radius:var(--r-card);
  background:var(--chrome); color:var(--text-invert);
  display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap;
}
.month-total .label{ display:block; font-size:10.5px; text-transform:uppercase; letter-spacing:.06em; opacity:.7; }
.month-total strong{ font-family:'JetBrains Mono',monospace; font-size:14px; }
.month-total .pos{ color:var(--brand-yellow); }
.month-total .neg{ color:#FF8A93; }

/* The quick-add button is fixed at bottom-right. At bottom:26px on a phone it
   sat ON the tab bar and covered the chevron of whichever action row happened
   to be under it, which both vision reviewers read as "that row is not
   pressable". Lift it clear of the bar. */
@media (max-width:820px){
  .qa-fab{ right:16px; bottom:calc(74px + env(safe-area-inset-bottom)); width:50px; height:50px; font-size:26px; }
}

@media (prefers-reduced-motion:reduce){
  .sheet{ transition:none; }
  .big-num{ transition:none; }
}

/* ==========================================================================
   THE JOB CALENDAR (2026-08-05)
   A month grid with jobs drawn as bars from start to finish. Read only.
   Bars are laid out per WEEK inside a 7-column grid, which is what lets a
   two-week job draw as one continuous run rather than ten separate chips.
   ========================================================================== */
.cal-head{ display:flex; align-items:center; justify-content:space-between; gap:14px; flex-wrap:wrap; margin-bottom:10px; }
.cal-nav{ display:flex; align-items:center; gap:8px; }
.cal-nav h3{ margin:0; min-width:190px; text-align:center; font-size:17px; }
.cal-legend{ display:flex; align-items:center; gap:14px; font-size:12px; color:var(--text-muted); }
.cal-key{ display:inline-flex; align-items:center; gap:6px; }
.cal-key i{ width:14px; height:9px; border-radius:3px; display:inline-block; }
.cal-key .k-live{ background:#2C6BBE; }
.cal-key .k-booked{ background:var(--due); }
.cal-key .k-done{ background:var(--won); }

.cal-sum{ font-size:13px; color:var(--text-muted); margin-bottom:10px; }
.cal-sum strong{ color:var(--text); }

.cal-grid{ background:var(--surface); border:1px solid var(--border); border-radius:var(--r-card); box-shadow:var(--shadow); overflow:hidden; }
.cal-dow{ display:grid; grid-template-columns:repeat(7,1fr); background:var(--info-bg); border-bottom:1px solid var(--border); }
.cal-dow span{ padding:7px 8px; font-size:11px; letter-spacing:.06em; text-transform:uppercase; color:var(--text-muted); font-weight:600; }

.cal-week{ position:relative; border-bottom:1px solid var(--border); }
.cal-week:last-child{ border-bottom:0; }
.cal-days{ display:grid; grid-template-columns:repeat(7,1fr); }
.cal-day{ min-height:26px; padding:5px 8px 0; border-right:1px solid var(--border); }
.cal-day:last-child{ border-right:0; }
.cal-day.out{ background:#FCFCFD; }
/* A date from the month either side is still a date he reads: #B6BCC6 on the
   calendar's own #FCFCFD measured 1.86:1. */
.cal-day.out .cal-dnum{ color:#6F7379; }   /* 4.67:1 */
.cal-day.today .cal-dnum{ background:var(--brand-yellow); color:#111827; border-radius:var(--r-pill); padding:1px 7px; font-weight:700; }
.cal-dnum{ font-size:12px; color:var(--text-muted); font-weight:600; }

.cal-lanes{ padding:2px 0 8px; display:flex; flex-direction:column; gap:3px; min-height:34px; }
.cal-lane{ display:grid; grid-template-columns:repeat(7,1fr); gap:0; }
.cal-bar{
  min-width:0; margin:0 3px; padding:3px 7px; border:0; border-radius:5px; cursor:pointer;
  font:inherit; font-size:11.5px; font-weight:600; line-height:1.35; text-align:left;
  color:#fff; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;
}
.cal-bar:hover{ filter:brightness(1.08); }
.cal-bar:focus-visible{ outline:2px solid var(--chrome); outline-offset:1px; }
.cal-bar-txt{ display:block; overflow:hidden; text-overflow:ellipsis; }
.cal-bar.t-live{ background:#2C6BBE; }
.cal-bar.t-booked{ background:var(--due); }
.cal-bar.t-done{ background:var(--won); }
/* A run continuing past the edge of the week squares off on that side, so a
   job that spans two weeks reads as one job rather than two. */
.cal-bar.open-l{ border-top-left-radius:0; border-bottom-left-radius:0; margin-left:0; }
.cal-bar.open-r{ border-top-right-radius:0; border-bottom-right-radius:0; margin-right:0; }
/* Start date but no finish date: a marker, never an open-ended bar. Eighteen
   live jobs are in this state and drawing them as long bars would make "we do
   not know" look identical to "six weeks on site". */
.cal-bar.one-day{ background:transparent; color:var(--text); border-left:3px solid #2C6BBE; border-radius:0 5px 5px 0; background:#EEF3FA; }
.cal-bar.one-day.t-booked{ border-left-color:var(--due); background:var(--due-bg); }
.cal-bar.one-day.t-done{ border-left-color:var(--won); background:var(--won-bg); }
.cal-more{ font-size:11px; color:var(--text-muted); padding:1px 10px; }

.cal-missing{ margin-top:12px; }
.cal-note{ margin-top:10px; font-size:12.5px; color:var(--text-muted); line-height:1.6; max-width:70ch; }

@media (max-width:760px){
  .cal-head{ gap:8px; }
  .cal-nav h3{ min-width:0; flex:1; font-size:15px; }
  .cal-legend{ width:100%; justify-content:flex-start; }
  .cal-dow span{ padding:6px 4px; font-size:10px; }
  .cal-day{ padding:4px 4px 0; }
  .cal-bar{ font-size:10px; padding:2px 4px; margin:0 1px; }
}

/* ---------------- Export panel (Settings) ----------------
   The two download buttons were laid out inline with a margin, so on a phone
   the second wrapped and sat flush against the bottom of the first: measured
   at 0px between them, which one vision provider read as an overlap and the
   other as "cramped". Both were describing the same real fault. A flex row
   with a gap fixes it at every width, and under 480px the buttons take the
   full width so a thumb has a proper target. */
.export-actions{ display:flex; flex-wrap:wrap; gap:10px; margin-top:2px; }
.export-actions .btn{ margin-left:0 !important; }
.export-dates{ display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.export-dates input[type="date"]{ max-width:170px; }
@media (max-width:480px){
  .export-actions .btn{ flex:1 1 100%; justify-content:center; }
  .export-dates input[type="date"]{ flex:1 1 100%; max-width:none; }
  .export-dates .btn{ flex:1 1 auto; }
}

/* ==========================================================================
   PROFIT MARGIN table on the Money screen (2026-08-13, r-fxccxi).
   Jay's voice note: the single 45% figure is across all work and therefore
   misleading. Three rows, his own spreadsheet's split, with finished work
   weighted as the one to read. Money cells are right-aligned and tabular so
   the percentages line up down the column, which IS the comparison.
   ========================================================================== */
.margin-table td.mono, .margin-table th:not(:first-child){ text-align:right; white-space:nowrap; }
.margin-table td.mono{ font-variant-numeric:tabular-nums; }
.margin-table .mr-label{ font-weight:600; min-width:190px; }
.margin-table .mr-note{
  display:block; font-weight:400; font-size:11.5px; color:var(--text-muted); margin-top:2px;
}
/* Finished work is the honest number, so it is the row that is emphasised. */
.margin-table tr.mr-strong td{ background:var(--yellow-soft); }
.margin-table tr.mr-strong .mr-pct{ font-weight:700; font-size:15px; }
.margin-table tr.mr-total td{ border-top:2px solid var(--border-strong); }
.margin-table tr.mr-total .mr-label{ color:var(--text-muted); }
.margin-table .mr-pct{ font-weight:600; }

.margin-net{ margin-top:14px; padding-top:13px; border-top:1px solid var(--border); }
.margin-net .mn-line{ display:flex; align-items:baseline; gap:12px; flex-wrap:wrap; }
.margin-net .mn-label{ font-size:13px; color:var(--text-muted); }
.margin-net .mn-line strong{ font-size:20px; font-variant-numeric:tabular-nums; }
.margin-net .mn-pct{ font-size:14px; font-weight:600; }
.margin-net .pos, .margin-net .mn-pct.pos{ color:var(--won-text); }
.margin-net .neg, .margin-net .mn-pct.neg{ color:var(--overdue); }
.margin-net .hint{ margin-top:7px; }
.mr-why{ margin-top:12px; }

@media (max-width:820px){
  /* STACKED on a phone, not scrolled. Five money columns at 390px put the
     Gross margin figure off the right-hand edge behind a sideways scroll,
     and that column is the entire point of the table. Each row becomes its
     own block, labelled from the data-label attributes on the cells, with
     the percentage as the headline. One set of markup, two layouts. */
  .margin-table, .margin-table thead, .margin-table tbody,
  .margin-table tr, .margin-table td{ display:block; width:auto; }
  .margin-table thead{ display:none; }
  .margin-table tr{
    border:1px solid var(--border); border-radius:10px;
    padding:11px 13px; margin-bottom:10px; background:var(--surface);
  }
  .margin-table tr:last-child{ margin-bottom:0; }
  .margin-table td{ border-bottom:0; padding:3px 0; }
  .margin-table td.mono, .margin-table th:not(:first-child){ text-align:left; }
  /* label on the left, figure on the right, on one line each */
  .margin-table td.mono{ display:flex; justify-content:space-between; align-items:baseline; gap:12px; }
  .margin-table td.mono::before{
    content:attr(data-label); font-size:11.5px; color:var(--text-muted); font-weight:600;
  }
  .margin-table .mr-label{
    min-width:0; font-size:15px; padding-bottom:7px; margin-bottom:5px;
    border-bottom:1px solid var(--border);
  }
  .margin-table .mr-note{ font-size:11.5px; }
  .margin-table .mr-pct{ font-size:17px; font-weight:700; }
  .margin-table tr.mr-strong td{ background:transparent; }
  .margin-table tr.mr-strong{ background:var(--yellow-soft); border-color:var(--brand-yellow); }
  .margin-table tr.mr-total td{ border-top:0; }
  .margin-net .mn-line{ gap:8px; }
}

/* ============ PHONE: NOTHING DRAGS SIDEWAYS (19 August 2026) ============
   Jay, 14 August: "the format on the phone isn't good, it's very difficult to
   understand, you have to scroll to the left, scroll to the right, but the most
   important thing is you can't actually add on expenses."

   Measured before writing any of this, across all eleven views at six phone
   widths (artifacts/qa/audit-sideways-2026-08-19.mjs). THREE separate faults,
   which all feel identical in the hand and have nothing else in common:

     (a) every form control is 13.5px or 14px, under Apple's 16px threshold, so
         iOS magnifies the whole page the moment one takes focus and never
         zooms back. Measured off Jay's own video frame: 1.16x. That is the
         video: the right-hand side off the screen, dragging left and right,
         and the cost cards pushed out of view so he never saw them.
     (b) the calendar's "35 jobs have no start date" is a BUTTON, and .btn is
         white-space:nowrap, so it made the document 38px wider than a 360px
         phone. This one moves the whole app, which is what the operator saw.
     (c) the five list tables are wider than a phone and sit in a box that
         scrolls sideways: Jobs hid 592px of every row at 360px, Quotes 470px,
         Enquiries 424px, the Financials costs 209px, Settings overheads 72px.
         The page does not move, so this is invisible from a desktop.
   ======================================================================== */

/* (a) 16px is not a style choice, it is the number iOS tests against. */
@media (max-width:820px){
  input, select, textarea, .ed-input, .ask-input, .ask-compose textarea{ font-size:16px; }
  /* the inline table editor grows its text without growing its box */
  .ed-input{ padding:4px 6px; }
}

/* (d) 2026-08-19, the operator on his own iPhone: "the date fields are slightly
       longer than the box surrounding them".

       A date field is not a text field that happens to hold a date. iOS draws a
       NATIVE control inside it and sizes that control itself, from the value and
       the font, which is why this appeared the day round 22 took every control
       from 13.5px to 16px: the control grew by 18% and the box around it did
       not. A squeezed text field just scrolls its own text and looks fine; the
       native date control paints past its border instead, by a few pixels, which
       is exactly what "slightly longer" describes.

       Measured (artifacts/qa/audit-dates-2026-08-19.mjs, WebKit, the engine an
       iPhone runs): at 320px the job's start and finish dates get a 212px box
       and demand 230px, and the Add-cost date gets 216px and demands 232px.
       Three separate things are needed and none of them is enough alone:
         appearance:none  the control stops sizing itself and obeys the box.
         min-width:0      it can no longer force the row it sits in wider.
         min-height       with the native control off, an EMPTY date field (an
                          unset finish date) has no content to give it height,
                          so the height is stated. 40px is below every one of
                          these fields' current rendered heights (41-45px), so
                          nothing on screen moves. */
@media (max-width:820px){
  input[type="date"], input[type="time"], input[type="datetime-local"], input[type="month"]{
    -webkit-appearance:none; appearance:none;
    min-width:0; max-width:100%; box-sizing:border-box; min-height:40px;
  }
  /* The shadow element iOS paints the value into. It carries its own width and
     centring, and it is the half that overflows. */
  input[type="date"]::-webkit-date-and-time-value{
    text-align:left; margin:0; min-width:0; width:100%;
  }
}

/* (b) A button holding a sentence has to be allowed to wrap. Wrapping only
       happens when there is not enough room, so "+ Add cost" is untouched. */
@media (max-width:820px){
  .btn{ white-space:normal; max-width:100%; }
  .cal-missing .btn{ text-align:left; line-height:1.35; }
}

/* (c) Wide tables become stacked cards. The cells are labelled at runtime by
       assets/responsive.js; every layout decision is here. Same pattern as
       .margin-table above, generalised so the next table gets it for free. */
@media (max-width:600px){
  table.stacks, table.stacks > thead, table.stacks > tbody,
  table.stacks > tbody > tr, table.stacks > tbody > tr > td{ display:block; width:auto; }
  table.stacks > thead{ display:none; }

  table.stacks > tbody > tr{
    display:flex; flex-direction:column;
    border:1px solid var(--border); border-radius:10px; background:var(--surface);
    padding:11px 13px; margin-bottom:10px;
  }
  table.stacks > tbody > tr:last-child{ margin-bottom:0; }
  table.stacks > tbody > tr:hover{ background:var(--surface); }

  /* label left, value right, one line per field */
  table.stacks > tbody > tr > td{
    border-bottom:0; padding:4px 0; text-align:left; vertical-align:baseline;
    display:flex; justify-content:space-between; align-items:baseline; gap:14px;
  }
  table.stacks > tbody > tr > td[data-label]::before{
    content:attr(data-label); flex:0 0 auto;
    font-size:10.5px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
    color:var(--text-muted); white-space:nowrap;
  }
  /* the row's own name heads the card, whichever column it came from */
  table.stacks > tbody > tr > td[data-lead]{
    order:-1; display:block; font-size:14.5px;
    padding:0 0 8px; margin-bottom:6px; border-bottom:1px solid var(--border);
  }
  table.stacks > tbody > tr > td[data-full]{ display:block; }
  /* a blank cell must not leave a labelled empty line */
  table.stacks > tbody > tr > td[data-empty]{ display:none; }

  /* money keeps its alignment but stops reserving desktop width */
  table.stacks .num-cell{ min-width:0; text-align:right; }
  table.stacks > tbody > tr > td .num-cell{ display:inline-block; }

  /* the buttons are the card's footer */
  table.stacks > tbody > tr > td.row-actions{
    display:flex; flex-wrap:wrap; gap:7px; justify-content:flex-start;
    padding-top:10px; margin-top:6px; border-top:1px solid var(--border);
  }
  table.stacks > tbody > tr > td.row-actions::before{ content:none; }
  table.stacks > tbody > tr > td.row-actions .btn{ flex:1 1 auto; min-width:96px; }

  /* the box around a stacked table has nothing left to scroll */
  .has-stacked{ overflow-x:visible !important; background:none !important; }
  .list-card.has-stacked{ padding:11px !important; }
}

/* The three list cards carried their layout in a style="" attribute, which no
   media query can override. Same values, now in a class that one can. */
.list-card{ padding:0; overflow-x:auto; }

/* ============ THE JOB SCREEN'S MONEY ACTIONS, ON A PHONE ============
   The panel is 5,839px tall on his phone and "+ Add cost" sits 3,537px down
   it: 4.2 screenfuls from the top, on the screen he opens standing on site
   for exactly that reason. The panel ORDER is not the thing to change (Jay
   asked on 13 August for additional works to move DOWN, and it did), so the
   two money actions get a bar pinned to the bottom of the phone screen that
   jumps to the right card and puts the caret in its first box.
   ==================================================================== */
.job-quick{ display:none; }
@media (max-width:820px){
  .job-quick{
    display:flex; gap:9px; position:fixed; left:0; right:0; bottom:0; z-index:210;
    padding:10px 12px calc(10px + env(safe-area-inset-bottom));
    background:var(--surface); border-top:1px solid var(--border);
    box-shadow:0 -6px 18px rgba(17,24,39,.18);
  }
  .job-quick .btn{ flex:1 1 0; justify-content:center; font-size:13.5px; padding:12px 10px; }
  /* the panel must be able to scroll past the bar it now sits under */
  .modal-backdrop.has-quick{ padding-bottom:96px; }
}

/* ==========================================================================
   ROUND 28 (9 September 2026)
   ========================================================================== */

/* The qualifier on a tile's title. Jay's decision, in his words: keep the big
   number, put "(banked only)" next to the word Profit smaller than it. It has
   to be readable, not decorative, so it is 0.78em and full-contrast muted
   rather than a faded 10px. */
.tile-qual{ font-size:9.5px; font-weight:600; text-transform:none; letter-spacing:.01em;
            color:var(--text-muted); white-space:nowrap; }

/* A cost row with no job on it. Not an empty cell: a kind of row. */
.biz-chip{
  display:inline-block; padding:1px 8px; border-radius:var(--r-pill);
  background:var(--info-bg); color:var(--text-muted);
  font-size:11px; font-weight:600; white-space:nowrap;
}

/* The overheads column of the monthly table opens the month it is showing. */
.ovh-cell{ cursor:pointer; }
.ovh-cell:hover{ background:var(--yellow-soft); }
.ovh-assumed{
  display:inline-block; margin-left:6px; padding:0 6px; border-radius:var(--r-pill);
  background:var(--info-bg); color:var(--text-muted);
  font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:.05em;
}
.ovh-cell.ovh-stated{ font-weight:700; }

/* The opening sentence of a sheet that is a FORM rather than a list. The list
   sheets carry their explanation in the subtitle; a form needs a line of its
   own above the fields. */
.sheet-lead{ font-size:13px; line-height:1.6; color:var(--text-muted); margin:0 0 14px; }
