/* ============================================================
   Elliott Safety Operations
   Visual system: Elliott brand blue + flag green, light theme,
   soft multi-layer shadows and a restrained brand glow.
   Single theme by choice: a client operations tool, painted
   explicitly rather than inheriting the browser's mood.
   ============================================================ */

:root{
  /* --- brand: blues taken from the Elliott letterhead --- */
  --brand-900:#102C52;
  --brand-800:#1B3F73;
  --brand-700:#224F8F;   /* logo wordmark blue */
  --brand-600:#02538A;   /* deep document blue */
  --brand-500:#3169AF;
  --brand-300:#9DB8E0;
  --brand-200:#C3D3EC;
  --brand-100:#D9E2F3;   /* light blue tint */
  --brand-50:#EDF3FC;

  /* --- brand: the green of the flag mark --- */
  --leaf-700:#4C7A1C;
  --leaf-600:#6EA330;
  --leaf-500:#8FC74A;
  --leaf-200:#D3EAAF;
  --leaf-100:#E9F5D5;
  --leaf-50:#F4FAEA;

  /* --- neutrals --- */
  --ground:#F3F6FB;
  --ground-2:#E9EEF8;
  --surface:#FFFFFF;
  --ink:#262626;
  --ink-2:#4A5462;
  --muted:#646F86;       /* was #7A8698 at 3.69:1 on white, now 5.05:1 */
  --ink-3:#5F6B82;       /* was used 4x and never defined, fell back to #7C8DA6 at 3.38:1 */
  --rule:#E3E9F3;
  --rule-soft:#EFF2F8;
  --line:var(--rule);    /* was used with no fallback at all */
  --bg:var(--surface);   /* was used with no fallback at all */
  --sunk:#F4F6F9;        /* was used with a fallback only */

  /* --- semantic --- */
  --accent:var(--brand-700);
  --accent-soft:var(--brand-50);
  --ok:#4C7A1C;
  --ok-soft:#EEF7E1;
  --warn:#96590F;
  --warn-soft:#FBF1DF;
  --bad:#A4342B;
  --bad-soft:#FAE7E4;

  /* --- elevation + glow --- */
  --shadow-xs:0 1px 2px rgba(16,44,82,.06);
  --shadow:0 1px 2px rgba(16,44,82,.05), 0 10px 24px -14px rgba(16,44,82,.22);
  --shadow-md:0 1px 3px rgba(16,44,82,.06), 0 18px 38px -20px rgba(16,44,82,.30);
  --shadow-lg:0 2px 6px rgba(16,44,82,.07), 0 34px 70px -30px rgba(16,44,82,.38);
  --glow-blue:0 0 0 3px rgba(34,79,143,.16);
  --glow-green:0 0 0 3px rgba(143,199,74,.32);

  --r-sm:8px;
  --r:10px;
  --r-lg:14px;
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
/* E-017 (Valera, 30 Sep: older users). The one knob for text size. Every
   font-size below is in rem, written as the old px over 16, so this line
   scales all of it together and nothing else: 106.25% is 17px on a browser
   left at its 16px default, about one step up (the body's 14.5px becomes
   15.4px), and it still follows anyone who has set a larger default. Layout
   widths and heights stay in px. Inline sizes in templates are not covered. */
html{font-size:106.25%}
body{
  background:var(--ground);
  background-image:
    radial-gradient(1100px 520px at 78% -12%, rgba(34,79,143,.07), transparent 60%),
    radial-gradient(760px 420px at -8% 6%, rgba(143,199,74,.09), transparent 62%);
  background-attachment:fixed;
  color:var(--ink);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,"Helvetica Neue",Arial,sans-serif;
  font-size:.90625rem;line-height:1.55;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  font-feature-settings:"kern" 1,"liga" 1;
}
a{color:var(--brand-700);text-decoration:none}
a:hover{text-decoration:underline}
:focus-visible{outline:2px solid var(--brand-500);outline-offset:2px;border-radius:4px}
h1,h2,h3{letter-spacing:-.015em}
b,strong{font-weight:640}

/* ============================================================
   Shell: deep-blue sidebar + light scrolling content
   ============================================================ */
.shell{display:flex;min-height:100vh}

.sidebar{
  width:232px;flex:0 0 232px;
  background:linear-gradient(168deg,#1B3F73 0%,#224F8F 52%,#1E4682 100%);
  color:#EAF1FB;
  display:flex;flex-direction:column;
  position:sticky;top:0;height:100vh;
  padding:20px 14px 16px;
  border-right:1px solid rgba(16,44,82,.35);
  box-shadow:1px 0 0 rgba(255,255,255,.05) inset, 14px 0 40px -30px rgba(16,44,82,.9);
  z-index:5;
}

/* brand block */
.brand{
  display:flex;align-items:center;gap:11px;
  color:#fff;font-weight:650;font-size:.9375rem;line-height:1.18;
  padding:4px 8px 18px;margin:0 0 14px;
  border-bottom:1px solid rgba(255,255,255,.14);
}
.brand:hover{text-decoration:none}
.brand-text{display:flex;flex-direction:column}
.brand-sub{
  color:var(--brand-200);font-weight:500;font-size:.71875rem;
  letter-spacing:.09em;text-transform:uppercase;margin-top:2px;
}
.brand-mark{
  width:26px;height:26px;flex:none;border-radius:8px;position:relative;
  background:linear-gradient(150deg,var(--leaf-500),var(--leaf-700));
  box-shadow:0 0 0 1px rgba(255,255,255,.22), 0 6px 16px -6px rgba(143,199,74,.85);
}
.brand-mark::after{
  content:"";position:absolute;left:8px;top:6px;
  width:0;height:0;border-style:solid;
  border-width:7px 0 7px 9px;
  border-color:transparent transparent transparent #fff;
  opacity:.95;
}
.brand-mark.big{width:38px;height:38px;border-radius:11px}
.brand-mark.big::after{left:12px;top:9px;border-width:10px 0 10px 13px}

/* nav */
.sidenav{display:flex;flex-direction:column;gap:2px;overflow-y:auto;margin:0 -2px;padding:0 2px}
.nav-h{
  font-size:.625rem;letter-spacing:.14em;text-transform:uppercase;font-weight:700;
  color:rgba(195,211,236,.62);padding:14px 12px 5px;
}
.sidenav > .nav-h:first-child{padding-top:2px}
.sidenav a{
  display:flex;align-items:center;gap:10px;position:relative;
  color:#D2E0F3;padding:8px 11px;border-radius:9px;
  font-weight:520;font-size:.84375rem;white-space:nowrap;
  transition:background .14s ease,color .14s ease,box-shadow .14s ease;
}
.sidenav a:hover{background:rgba(255,255,255,.10);color:#fff;text-decoration:none}
.sidenav a.active{
  background:linear-gradient(90deg,rgba(255,255,255,.20),rgba(255,255,255,.09));
  color:#fff;font-weight:640;
  box-shadow:0 1px 0 rgba(255,255,255,.14) inset, 0 8px 20px -14px rgba(0,0,0,.9);
}
.sidenav a.active::before{
  content:"";position:absolute;left:-2px;top:7px;bottom:7px;width:3px;border-radius:0 3px 3px 0;
  background:var(--leaf-500);box-shadow:0 0 12px 1px rgba(143,199,74,.75);
}
.sidenav .ni{width:18px;text-align:center;font-size:.78125rem;opacity:.62;flex:none}
.sidenav a:hover .ni{opacity:.85}
.sidenav a.active .ni{opacity:1;color:var(--leaf-500)}
.nav-rule{border-top:1px solid rgba(255,255,255,.13);margin:10px 12px}
/* Waiting count on a nav link (30 Sep, To approve). Leaf green on navy so it
   reads as "something here for you", not as an error. */
.nav-count{
  margin-left:auto;min-width:20px;height:20px;padding:0 6px;border-radius:10px;
  display:inline-grid;place-items:center;font-size:.71875rem;font-weight:750;line-height:1;
  background:var(--leaf-500);color:#102C52;
}
html.nav-folded .nav-count{position:absolute;top:2px;right:2px;min-width:16px;height:16px;font-size:.625rem;padding:0 4px}

.userbox{
  margin-top:auto;color:var(--brand-200);font-size:.78125rem;
  display:flex;gap:10px;align-items:center;
  padding:13px 11px 2px;border-top:1px solid rgba(255,255,255,.13);
}
.userbox .uname{color:#fff;font-weight:600;overflow:hidden;text-overflow:ellipsis}
.userbox a{color:var(--brand-200);white-space:nowrap}
.userbox a:first-of-type{margin-left:auto}
.userbox a:hover{color:#fff;text-decoration:none}

/* The sidebar fold (2026-09-12, plan: sidebar fold and cell fixes). Width for
   the schedule grid: option A of the 12 September explore, a chevron in the
   sidebar that folds it to a 52 px rail of icons, remembered per browser. The
   rail keeps 92 percent of what Deputy's top bar would give and keeps the
   shell every other page uses. The class sits on <html>, set by the inline
   script in base.html before first paint. Above 820 px only. */
.nav-fold{
  position:absolute;top:14px;right:10px;width:26px;height:26px;border-radius:7px;
  border:0;background:rgba(255,255,255,.08);color:#D2E0F3;font-size:1.0625rem;line-height:1;
  cursor:pointer;padding:0;
}
.nav-fold:hover{background:rgba(255,255,255,.16);color:#fff}
@media(min-width:821px){
  html.nav-folded .sidebar{width:52px;flex:0 0 52px;padding:20px 6px 16px}
  html.nav-folded .brand{justify-content:center;padding:4px 0 14px;gap:0}
  html.nav-folded .brand-text,html.nav-folded .nav-h,html.nav-folded .nl,html.nav-folded .userbox .uname{display:none}
  html.nav-folded .nav-fold{top:auto;bottom:52px;right:auto;left:50%;transform:translateX(-50%)}
  html.nav-folded .sidenav a{justify-content:center;padding:9px 0;gap:0}
  html.nav-folded .sidenav .ni{width:auto;font-size:.90625rem}
  html.nav-folded .sidenav a.active::before{left:0}
  html.nav-folded .nav-rule{margin:10px 6px}
  html.nav-folded .userbox{justify-content:center;padding:13px 0 2px;font-size:.6875rem}
  html.nav-folded .userbox a{margin-left:0}
}
@media(max-width:820px){.nav-fold{display:none}}

/* ============================================================
   Page
   ============================================================ */
/* flex column so the footer is pushed to the bottom rather than floating in
   the middle of a short page. The bottom padding reserves space for the fixed
   "Something not right?" pill, which used to sit on top of page content. */
.page{flex:1;min-width:0;max-width:1720px;padding:34px 38px 46px;
  display:flex;flex-direction:column}
.page-head{margin:0 0 22px}
/* The schedule is the widest page in the app; the month grid gets the side
   padding back (38 px a side elsewhere), which is two more pixels a column. */
.page.wide{padding-left:20px;padding-right:20px;max-width:none}
.page-head h1{font-size:1.5625rem;margin:0 0 5px;font-weight:680;color:var(--brand-900)}
.page-sub{color:var(--ink-2);margin:0;max-width:78ch;font-size:.875rem}
.crumb{font-size:.78125rem;color:var(--muted);margin:0 0 10px;letter-spacing:.02em}
.meta-line{color:var(--ink-2);font-size:.84375rem;margin:5px 0}
.muted{color:var(--muted)}
.foot{
  margin-top:auto;padding-top:16px;padding-bottom:64px;color:var(--muted);font-size:.75rem;
  border-top:1px solid var(--rule);letter-spacing:.02em;
}
.section-h{
  font-size:.75rem;text-transform:uppercase;letter-spacing:.12em;color:var(--brand-700);
  margin:30px 0 12px;font-weight:700;display:flex;align-items:center;gap:10px;
}
.section-h::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--rule),transparent)}

/* small screens: sidebar becomes a slim top bar */
@media(max-width:820px){
  .shell{flex-direction:column}
  .sidebar{
    width:auto;flex:none;height:auto;position:sticky;top:0;
    flex-direction:row;align-items:center;gap:10px;
    padding:10px 14px;border-right:0;
    border-bottom:1px solid rgba(16,44,82,.35);
    background:linear-gradient(96deg,#1B3F73,#224F8F);
    box-shadow:0 10px 26px -22px rgba(16,44,82,.9);
  }
  .brand{border-bottom:0;margin:0;padding:0 10px 0 0;flex:none;gap:9px}
  .brand br{display:none}
  .brand-sub{display:none}
  .brand-mark{width:22px;height:22px;border-radius:7px}
  .brand-mark::after{left:7px;top:5px;border-width:6px 0 6px 8px}
  .nav-h{display:none}
  .sidenav{flex-direction:row;overflow-x:auto;gap:3px;flex:1;margin:0;padding:2px 0}
  .sidenav a{padding:6px 11px;font-size:.8125rem}
  .sidenav a.active::before{left:6px;right:6px;top:auto;bottom:1px;width:auto;height:2px;border-radius:2px}
  .sidenav .ni{display:none}
  .nav-rule{border-top:0;border-left:1px solid rgba(255,255,255,.2);margin:4px 4px}
  .userbox{margin-top:0;border-top:0;padding:0;flex:none}
  .userbox .uname{display:none}
  .page{padding:22px 16px 34px}
  .page-head h1{font-size:1.375rem}
}

/* ============================================================
   Tables
   ============================================================ */
.tablewrap{
  overflow-x:auto;background:var(--surface);
  border:1px solid var(--rule);border-radius:var(--r);box-shadow:var(--shadow);
  /* a clipped right edge, so a table that still scrolls says so */
  background-image:linear-gradient(to right,rgba(16,44,82,0),rgba(16,44,82,.10));
  background-size:14px 100%;background-position:right center;background-repeat:no-repeat;
  background-attachment:local,scroll;
}
/* min-width earns a board its columns, but a flat 640px also applies inside a
   card, where it pushed the invoice Amount column (and so the total) out of
   sight. min() keeps the floor on wide containers and drops it on narrow ones. */
table{border-collapse:separate;border-spacing:0;width:100%;min-width:min(640px,100%)}
th,td{text-align:left;padding:11px 13px;vertical-align:middle}
/* A control never overflows the cell it is in. Two pages were doing it on
   2026-09-23, both for the same reason: a fixed-layout table that was never
   told how wide its columns are, so the browser divided the width evenly and
   any control with its own width spilled into the column beside it. On Rates
   the two rate boxes sat on top of each other and on the Save button; on the
   price list the audit type select ran over Kind of work and the service name
   over Rate. `min-width:0` is the half that is easy to miss: a table cell, like
   a grid item, will not shrink its content below its intrinsic width without
   being told to. Column PROPORTIONS are a colgroup's job, per table; this is
   only the floor under them. */
.tablewrap table input,.tablewrap table select,.tablewrap table textarea{
  max-width:100%;min-width:0;box-sizing:border-box;
}
th{
  font-size:.6875rem;text-transform:uppercase;letter-spacing:.11em;
  color:var(--muted);font-weight:700;white-space:nowrap;
  background:linear-gradient(180deg,#FBFCFE,#F5F8FD);
  border-bottom:1px solid var(--rule);
  position:sticky;top:0;z-index:1;
}
thead tr:first-child th:first-child{border-top-left-radius:var(--r)}
thead tr:first-child th:last-child{border-top-right-radius:var(--r)}
td{border-bottom:1px solid var(--rule-soft);font-size:.8625rem;color:var(--ink)}
tbody tr:last-child td{border-bottom:none}
tbody tr{transition:background .12s ease}
.tablewrap tbody tr:hover td{background:var(--brand-50)}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}
.rowlink{cursor:pointer}
.rowlink:hover td{background:var(--brand-50)}
table.inner{min-width:min(560px,100%)}
table.inner th,table.inner td{padding:8px 13px;font-size:.8125rem}
table.inner th{font-size:.625rem}

/* ============================================================
   Pills
   ============================================================ */
.pill{
  display:inline-block;padding:3px 10px;border-radius:999px;
  font-size:.71875rem;font-weight:640;line-height:1.5;letter-spacing:.01em;
  white-space:nowrap;vertical-align:middle;
  box-shadow:0 1px 1px rgba(16,44,82,.04);
}
.pill.small{font-size:.65625rem;padding:2px 8px;letter-spacing:.02em}
.pill.ok{background:var(--ok-soft);color:var(--ok);box-shadow:inset 0 0 0 1px rgba(76,122,28,.16)}
.pill.warn{background:var(--warn-soft);color:var(--warn);box-shadow:inset 0 0 0 1px rgba(150,89,15,.18)}
.pill.neutral{background:#F4F7FC;color:var(--ink-2);box-shadow:inset 0 0 0 1px var(--rule)}

/* status pills: semantic, harmonised to the Elliott blue/green identity */
.st{background:#F4F7FC;color:var(--ink-2);box-shadow:inset 0 0 0 1px var(--rule)}
.st-job-todo,.st-proposal-sent_email,.st-invoice-sent,.st-project-quoting,.st-task-in_progress{
  background:var(--brand-50);color:var(--brand-700);box-shadow:inset 0 0 0 1px rgba(34,79,143,.16)}
.st-job-booked,.st-proposal-sent_docusign,.st-task-for_review,.st-task-awaiting_approval{
  background:var(--brand-100);color:#1A4478;box-shadow:inset 0 0 0 1px rgba(34,79,143,.24)}
.st-job-in_progress,.st-invoice-draft{
  background:var(--warn-soft);color:var(--warn);box-shadow:inset 0 0 0 1px rgba(150,89,15,.18)}
.st-job-complete,.st-proposal-signed,.st-invoice-paid,.st-project-won,.st-project-active{
  background:var(--ok-soft);color:var(--ok);box-shadow:inset 0 0 0 1px rgba(76,122,28,.22)}
.st-job-closed_out,.st-proposal-lost,.st-invoice-not_invoiced,.st-invoice-void,.st-project-lost{
  background:var(--bad-soft);color:var(--bad);box-shadow:inset 0 0 0 1px rgba(164,52,43,.18)}
/* Booked, and nobody is doing it. Same blue as booked, because that is what it
   is, plus the outline that says it is waiting on somebody here rather than on
   the client. */
.st-job-booked.needs{
  box-shadow:inset 0 0 0 1px rgba(150,89,15,.45);
  background:var(--warn-soft);color:var(--warn);font-weight:640;
}
/* The audit day has passed and the report has not gone. Booked blue with the
   same waiting-on-us outline as `needs`, because that is exactly what it is. */
.st-job-booked.awaiting{
  box-shadow:inset 0 0 0 1px rgba(150,89,15,.45);
  background:var(--warn-soft);color:var(--warn);font-weight:640;
}
.st-proposal-draft,.st-project-complete{
  background:#F4F7FC;color:var(--ink-2);box-shadow:inset 0 0 0 1px var(--rule)}
.st-chase-needed,.st-chase-chased{
  background:var(--warn-soft);color:var(--warn);box-shadow:inset 0 0 0 1px rgba(150,89,15,.18)}
.st-source-hammertech{
  background:#EAEEFA;color:#3C4C93;box-shadow:inset 0 0 0 1px rgba(60,76,147,.16)}
.st-source-procore_email,.st-source-buildpass,.st-source-breadcrumb,.st-source-manual{
  background:#F4F7FC;color:var(--ink-2);box-shadow:inset 0 0 0 1px var(--rule)}
/* The report went out of this system, which is the designed completion signal.
   Green because it is the one that carries a receipt behind it. */
.st-source-report_issued{
  background:var(--ok-soft);color:var(--ok);box-shadow:inset 0 0 0 1px rgba(76,122,28,.22)}

/* ============================================================
   Cards
   ============================================================ */
.card{
  background:var(--surface);border:1px solid var(--rule);border-radius:12px;
  box-shadow:var(--shadow);padding:20px 22px;margin:0 0 18px;
}
.card-head{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:4px}
.card-head h2{font-size:1.0625rem;margin:0;font-weight:660;color:var(--brand-900)}
/* A card's actions, top right: buttons in one row, wrapping under the heading
   on a narrow screen, with an optional one-line note beneath them. */
.head-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px}
.head-actions form.inline{margin:0}
.head-actions .head-note{flex-basis:100%;margin:0;text-align:right;font-size:.75rem;line-height:1.4;color:var(--muted)}
.card .tablewrap{margin-top:14px;box-shadow:none}

/* stat tiles */
.statrow{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:14px;margin:0 0 20px}
.stat{
  background:linear-gradient(170deg,#FFFFFF,#FAFCFF);
  border:1px solid var(--rule);border-radius:12px;padding:14px 16px;
  box-shadow:var(--shadow);position:relative;overflow:hidden;
}
.stat::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:3px;
  background:linear-gradient(180deg,var(--brand-700),var(--brand-500));
}
.stat.stat-green::before{background:linear-gradient(180deg,var(--leaf-500),var(--leaf-700))}
.stat b{
  display:block;font-size:.65625rem;text-transform:uppercase;letter-spacing:.11em;
  color:var(--muted);font-weight:700;margin-bottom:3px;
}
.stat span{font-size:1.375rem;font-weight:660;color:var(--brand-900);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.stat small{display:block;color:var(--muted);font-size:.75rem;margin-top:2px}
/* The Ops Board counts (E-013): each tile opens the page it counts. */
a.stat{display:block;color:inherit;text-decoration:none}
a.stat:hover{border-color:var(--brand-300);text-decoration:none}
.statrow.counts{margin-bottom:14px}
@media(max-width:700px){
  .statrow.counts{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
  .statrow.counts .stat{padding:10px 10px}
  .statrow.counts .stat b{letter-spacing:.04em}
}

/* ============================================================
   Proposal board
   ============================================================ */
.board{display:grid;grid-template-columns:repeat(5,1fr);gap:14px}
@media(max-width:960px){.board{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){.board{grid-template-columns:1fr}}
.col{
  background:var(--surface);border:1px solid var(--rule);border-radius:12px;
  padding:13px;min-height:120px;box-shadow:var(--shadow-xs);
}
.col-signed{
  border-color:rgba(110,163,48,.42);
  background:linear-gradient(180deg,var(--leaf-50),var(--surface) 62%);
  box-shadow:0 0 0 1px rgba(143,199,74,.14), var(--shadow);
}
.col-lost{opacity:.72}
.col-head{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:2px}
.col-head h3{font-size:.71875rem;text-transform:uppercase;letter-spacing:.1em;color:var(--ink-2);margin:0;font-weight:700}
.col-count{color:var(--muted);font-size:.75rem;font-variant-numeric:tabular-nums}
.col-total{color:var(--brand-700);font-size:.8125rem;font-weight:660;margin:0 0 10px;font-variant-numeric:tabular-nums}
.col-empty{color:var(--rule);text-align:center;margin:22px 0}
.prop{
  border:1px solid var(--rule);border-radius:9px;padding:10px 12px;margin:8px 0;
  background:var(--surface);box-shadow:var(--shadow-xs);transition:box-shadow .15s ease,transform .15s ease;
}
.prop:hover{box-shadow:var(--shadow);transform:translateY(-1px)}
.prop-no{font-size:.6875rem;color:var(--muted);font-variant-numeric:tabular-nums;letter-spacing:.05em;text-transform:uppercase}
.prop-title{font-size:.84375rem;font-weight:600;margin:2px 0 2px}
.prop-meta{font-size:.78125rem;color:var(--muted)}

/* ============================================================
   Login
   ============================================================ */
.login-body{
  background:#12305A;
  background-image:
    radial-gradient(900px 520px at 20% 8%, rgba(143,199,74,.30), transparent 58%),
    radial-gradient(1000px 620px at 84% 92%, rgba(2,83,138,.75), transparent 62%),
    linear-gradient(160deg,#173A6A 0%,#12305A 55%,#0D2444 100%);
  min-height:100vh;display:grid;place-items:center;margin:0;padding:24px;
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,"Helvetica Neue",Arial,sans-serif;
  color:var(--ink);
}
.login-card{
  background:var(--surface);border:1px solid rgba(255,255,255,.6);border-radius:18px;
  box-shadow:0 0 0 1px rgba(16,44,82,.10), 0 40px 90px -30px rgba(4,18,40,.75), 0 0 60px -18px rgba(143,199,74,.30);
  padding:38px 36px 34px;width:min(92vw,398px);
}
.login-brand{margin-bottom:18px}
.login-card h1{font-size:1.3125rem;margin:0 0 3px;font-weight:680;color:var(--brand-900)}
.login-sub{color:var(--muted);margin:0 0 22px;font-size:.84375rem}
.login-card label{display:block;font-size:.71875rem;font-weight:700;color:var(--ink-2);margin:0 0 15px;
  text-transform:uppercase;letter-spacing:.08em}
.login-card input{
  display:block;width:100%;margin-top:6px;padding:11px 13px;
  border:1px solid var(--rule);border-radius:var(--r-sm);
  font-size:.90625rem;font-weight:400;letter-spacing:normal;text-transform:none;
  background:#F7F9FD;color:var(--ink);font-family:inherit;
  transition:border-color .14s ease,box-shadow .14s ease,background .14s ease;
}
.login-card input:focus{border-color:var(--brand-500);outline:none;background:var(--surface);box-shadow:var(--glow-blue)}
.login-card button{
  width:100%;padding:12px;border:0;border-radius:var(--r-sm);
  background:linear-gradient(180deg,var(--brand-700),var(--brand-800));
  color:#fff;font-size:.90625rem;font-weight:650;cursor:pointer;margin-top:8px;
  font-family:inherit;letter-spacing:.01em;
  box-shadow:0 1px 0 rgba(255,255,255,.20) inset, 0 10px 22px -12px rgba(34,79,143,.9);
  transition:box-shadow .16s ease,transform .12s ease,filter .16s ease;
}
.login-card button:hover{filter:brightness(1.08);box-shadow:0 1px 0 rgba(255,255,255,.22) inset, 0 14px 28px -12px rgba(34,79,143,1), var(--glow-green)}
.login-card button:active{transform:translateY(1px)}
.login-foot{margin:20px 0 0;text-align:center;color:var(--muted);font-size:.71875rem;letter-spacing:.04em}
.form-error{
  background:var(--bad-soft);color:var(--bad);padding:10px 13px;border-radius:var(--r-sm);
  font-size:.8125rem;font-weight:550;box-shadow:inset 0 0 0 1px rgba(164,52,43,.20);margin:0 0 16px;
}

/* ============================================================
   Grouped lists
   ============================================================ */
.group{
  background:var(--surface);border:1px solid var(--rule);border-radius:12px;
  box-shadow:var(--shadow);margin:0 0 16px;overflow:hidden;
}
.group-head{
  display:flex;align-items:center;gap:10px;padding:11px 15px;
  border-bottom:1px solid var(--rule);
  background:linear-gradient(180deg,#FBFCFE,#F4F7FC);
}
.group-count{
  color:var(--ink-2);font-size:.71875rem;font-weight:640;font-variant-numeric:tabular-nums;
  background:#fff;border:1px solid var(--rule);border-radius:999px;padding:1px 8px;
}
.group-total{margin-left:auto;color:var(--brand-700);font-size:.8125rem;font-weight:660;font-variant-numeric:tabular-nums}
.group .tablewrap{border:0;border-radius:0;box-shadow:none}
.group .tablewrap th{background:#FCFDFE;border-bottom:1px solid var(--rule-soft)}
.group-empty{color:var(--muted);padding:14px 15px;font-size:.8125rem;margin:0}

/* ============================================================
   Page tabs
   ============================================================ */
.tabs{
  display:inline-flex;gap:3px;margin:0 0 18px;padding:3px;
  background:var(--ground-2);border:1px solid var(--rule);border-radius:11px;
}
.tabs a{
  padding:6px 15px;border-radius:8px;font-weight:580;color:var(--ink-2);font-size:.8125rem;
  transition:background .14s ease,color .14s ease,box-shadow .14s ease;
}
.tabs a:hover{text-decoration:none;color:var(--brand-700);background:rgba(255,255,255,.6)}
.tabs a.active{
  background:var(--surface);color:var(--brand-700);font-weight:650;
  box-shadow:0 1px 2px rgba(16,44,82,.10), 0 0 0 1px rgba(34,79,143,.10);
}

/* ============================================================
   Buttons + form controls
   ============================================================ */
.btn{
  display:inline-block;padding:6px 13px;border-radius:8px;
  border:1px solid var(--rule);background:linear-gradient(180deg,#FFFFFF,#F7F9FD);
  color:var(--brand-700);font-size:.78125rem;font-weight:640;cursor:pointer;line-height:1.45;
  font-family:inherit;white-space:nowrap;
  box-shadow:var(--shadow-xs);
  transition:box-shadow .16s ease,border-color .16s ease,background .16s ease,transform .1s ease;
}
.btn:hover{
  text-decoration:none;border-color:var(--brand-300);
  background:linear-gradient(180deg,#FFFFFF,var(--brand-50));
  box-shadow:var(--shadow-xs), var(--glow-blue);
}
.btn:active{transform:translateY(1px)}
.btn.small{padding:3px 10px;font-size:.71875rem}
.btn-primary{
  border-color:transparent;color:#fff;
  background:linear-gradient(180deg,var(--brand-600),var(--brand-800));
  box-shadow:0 1px 0 rgba(255,255,255,.18) inset, 0 6px 16px -10px rgba(34,79,143,.95);
}
.btn-primary:hover{
  color:#fff;border-color:transparent;
  background:linear-gradient(180deg,#0A5F9B,var(--brand-700));
  box-shadow:0 1px 0 rgba(255,255,255,.20) inset, 0 10px 22px -10px rgba(34,79,143,1), var(--glow-green);
}
form.inline{display:inline;margin:0}
.checkline{display:inline-flex;align-items:center;gap:6px;font-size:.8125rem;color:var(--ink-2);cursor:pointer}
.checkline input{accent-color:var(--brand-700);width:15px;height:15px;cursor:pointer}
select,input[type="search"],input[type="text"]{font-family:inherit}
select{
  padding:7px 11px;border:1px solid var(--rule);border-radius:8px;font-size:.8125rem;
  background:linear-gradient(180deg,#FFFFFF,#F7F9FD);color:var(--ink);
  box-shadow:var(--shadow-xs);cursor:pointer;font-weight:520;
  transition:border-color .14s ease,box-shadow .14s ease;
}
select:hover{border-color:var(--brand-300)}
select:focus{outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}

/* ============================================================
   Banner (missed-invoice alarm): a first-class alert
   ============================================================ */
.banner{
  position:relative;display:flex;align-items:flex-start;gap:11px;
  background:linear-gradient(180deg,#FFF9EE,var(--warn-soft));
  border:1px solid rgba(150,89,15,.24);
  border-left:4px solid #C98A22;
  color:var(--warn);border-radius:11px;padding:13px 18px;margin:0 0 20px;
  font-size:.8625rem;font-weight:530;line-height:1.5;
  box-shadow:0 1px 2px rgba(150,89,15,.08), 0 14px 30px -22px rgba(150,89,15,.7);
}
.banner a{color:#7E4A0B;text-decoration:underline;font-weight:640;text-underline-offset:2px}
.banner a:hover{color:#5E370A}
.banner.ok{
  background:linear-gradient(180deg,#F7FCEF,var(--ok-soft));
  border-color:rgba(76,122,28,.24);border-left-color:var(--leaf-600);
  color:var(--ok);
  box-shadow:0 1px 2px rgba(76,122,28,.08), 0 14px 30px -22px rgba(76,122,28,.6);
}
.banner.ok a{color:#3B6215}
.banner-icon{
  flex:none;width:24px;height:24px;border-radius:7px;display:grid;place-items:center;
  font-size:.8125rem;line-height:1;margin-top:1px;
  background:rgba(201,138,34,.16);color:#8A5410;
  box-shadow:inset 0 0 0 1px rgba(150,89,15,.20);
}
.banner.ok .banner-icon{background:rgba(110,163,48,.16);color:var(--ok);box-shadow:inset 0 0 0 1px rgba(76,122,28,.22)}
.banner-body{min-width:0}
.banner-title{display:block;font-weight:700;font-size:.875rem;letter-spacing:-.005em;margin-bottom:1px}
/* Needs a look (21 Sep): the To Quote band of replies intake could not place.
   The warn banner, with one card per row and three forms side by side. */
.banner.needs-look .banner-body{flex:1 1 auto}
.needs-look-row{
  margin-top:12px;padding:10px 12px;border-radius:9px;
  background:rgba(255,255,255,.7);border:1px solid rgba(150,89,15,.16);
  color:var(--ink);font-weight:450;
}
.needs-look-meta{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;font-size:.8125rem}
.needs-look-subject{font-weight:650;margin-top:4px}
.needs-look-text{margin-top:4px;font-size:.8125rem;white-space:pre-line;color:var(--ink-2)}
.needs-look-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:10px}
.needs-look-actions form{display:flex;align-items:center;gap:6px;margin:0}
.needs-look-attach select{max-width:320px;font-size:.78125rem}

/* To approve (30 Sep, Valera): its own page, one compact card per email so
   ten of them fit a screen. Who and what on top, "They want" held to two lines,
   the decision along the bottom; the email and the full read open under "Read
   the email". A "not sure" card carries the warn edge so it reads as a
   question, not a claim. */
.approve{margin:0 0 22px}
.approve-count{
  display:inline-grid;place-items:center;min-width:22px;height:22px;padding:0 6px;border-radius:11px;
  background:var(--brand-700);color:#fff;font-size:.75rem;font-weight:700;flex:none;
}
.approve-card{
  background:var(--surface);border:1px solid var(--rule);border-left:4px solid var(--brand-500);
  border-radius:11px;padding:10px 14px;margin:0 0 8px;box-shadow:var(--shadow-xs);
}
.approve-card.unsure{border-left-color:#C98A22}
.approve-meta{display:flex;flex-wrap:wrap;align-items:center;gap:2px 8px;font-size:.8125rem}
.approve-subject{font-weight:680;font-size:.90625rem;margin-top:2px}
.approve-want{
  font-size:.8125rem;margin-top:2px;color:var(--ink-2);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.approve-more{margin-top:6px;font-size:.78125rem}
.approve-more summary{cursor:pointer;color:var(--brand-700);font-weight:600;width:max-content}
.approve-grid{display:grid;grid-template-columns:minmax(0,3fr) minmax(0,2fr);gap:14px;margin-top:8px}
.approve-label{font-size:.6875rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);margin-bottom:4px}
.approve-body{
  font-size:.8125rem;line-height:1.5;white-space:pre-line;color:var(--ink);
  background:var(--sunk);border:1px solid var(--rule-soft);border-radius:8px;padding:8px 10px;
  max-height:420px;overflow:auto;overflow-wrap:anywhere;
}
.approve-thread{margin-top:8px;font-size:.78125rem}
.approve-thread summary{cursor:pointer;color:var(--muted);font-weight:600;width:max-content}
.approve-earlier{margin-top:6px;color:var(--ink-2);background:#FAFBFD;max-height:360px}
.approve-read dl{margin:0;display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 10px;font-size:.8125rem}
.approve-read dt{color:var(--muted);font-weight:600}
.approve-read dd{margin:0;overflow-wrap:anywhere}
.approve-actions{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;margin-top:8px;
  padding-top:8px;border-top:1px solid var(--rule-soft)}
.approve-actions form{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0}
.approve-company{display:flex;align-items:center;gap:6px;font-size:.78125rem;font-weight:600;color:var(--ink-2)}
.approve-company input{width:240px;max-width:100%;font-size:.8125rem}
.approve-tick,.approve-cross{font-size:.8125rem;padding:6px 13px}
.approve-cross{color:#9A2B1E}
.approve-lands{font-size:.78125rem;flex:1 1 200px}
/* The one line on To Quote that says emails are waiting. */
.approve-strip{
  display:flex;align-items:center;gap:10px;margin:0 0 14px;padding:10px 14px;border-radius:11px;
  background:var(--brand-50);border:1px solid var(--brand-200);color:var(--ink);font-size:.84375rem;
}
.approve-strip:hover{text-decoration:none;border-color:var(--brand-300);background:#E4EDFB}
.approve-strip-go{margin-left:auto;font-weight:680;color:var(--brand-700);white-space:nowrap}
@media (max-width:820px){
  .approve-grid{grid-template-columns:1fr}
  .approve-company input{width:100%}
  .approve-yes{flex:1 1 100%}
  .approve-company{flex:1 1 auto}
}

/* assumption note (8hr audit day label) */
.assumption{color:var(--muted);font-size:.78125rem;font-style:italic}

/* empty states */
.emptystate{
  background:linear-gradient(180deg,#FFFFFF,#FAFCFF);
  border:1px dashed var(--rule);border-radius:12px;
  color:var(--muted);font-size:.84375rem;
  padding:26px 22px;margin:0 0 18px;text-align:center;
}

/* ============================================================
   Client 360 master-detail
   ============================================================ */
.masterdetail{display:grid;grid-template-columns:296px 1fr;gap:20px;align-items:start}
@media(max-width:900px){.masterdetail{grid-template-columns:1fr}}
.clientlist{
  background:var(--surface);border:1px solid var(--rule);border-radius:12px;
  box-shadow:var(--shadow);overflow:hidden;position:sticky;top:22px;
}
@media(max-width:900px){.clientlist{position:static}}
.clientlist .search{padding:11px;border-bottom:1px solid var(--rule);background:linear-gradient(180deg,#FBFCFE,#F6F9FD)}
.clientlist .search input{
  width:100%;padding:8px 11px;border:1px solid var(--rule);border-radius:8px;
  font-size:.84375rem;background:var(--surface);color:var(--ink);font-family:inherit;
  transition:border-color .14s ease,box-shadow .14s ease;
}
.clientlist .search input:focus{outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}
.side-h{
  font-size:.625rem;text-transform:uppercase;letter-spacing:.13em;color:var(--muted);
  font-weight:700;padding:13px 15px 5px;
}
.side-h.side-ops{color:var(--brand-700)}
.side-h.side-systems{color:var(--warn)}
.side-h.side-both{color:var(--leaf-700)}
.clientlist a.crow{
  display:block;padding:8px 15px;color:var(--ink);font-size:.84375rem;
  border-left:3px solid transparent;transition:background .12s ease,border-color .12s ease;
}
/* The sidebar search sets the `hidden` attribute on a row. The UA stylesheet's
   [hidden]{display:none} is an author-beaten rule, so `display:block` above won
   and NOTHING was ever hidden: typing "Charter Hall" filtered zero of 147 rows
   (Nathan, 23 Sep, Client 360). An author rule is needed to honour it. Same for
   a side heading left with no clients under it. */
.clientlist a.crow[hidden],.clientlist .side-h[hidden]{display:none}
.clientlist a.crow:hover{background:var(--brand-50);text-decoration:none}
.clientlist a.crow.active{
  background:linear-gradient(90deg,var(--brand-50),rgba(237,243,252,0));
  border-left-color:var(--leaf-500);color:var(--brand-800);font-weight:650;
  box-shadow:inset 6px 0 14px -12px rgba(143,199,74,.9);
}
.detail-kv{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:12px 24px;margin:16px 0}
.detail-kv .kv b{
  display:block;font-size:.65625rem;text-transform:uppercase;letter-spacing:.1em;
  color:var(--muted);font-weight:700;
}
.detail-kv .kv span{font-size:.875rem;color:var(--ink)}
/* A grid track is 210px and a <select> sizes itself to its widest option. The
   longest audit type on production is "ISO Internal Management System Audit
   (Safety)", 44 characters, so the Audit type select ran over the cell beside
   it and Kate clicked job type meaning to click side (23 Sep: "can those
   buttons be configured differently because that's a bit odd"). min-width:0 is
   the half that matters: a grid item's default min-width:auto refuses to
   shrink below its content. Fixes every .detail-kv block, not just pricing. */
.detail-kv .kv{min-width:0}
.detail-kv .kv select,.detail-kv .kv input,.detail-kv .kv textarea{
  max-width:100%;box-sizing:border-box;
}

/* ============================================================
   Schedule grid
   ============================================================ */
.schedwrap{
  overflow-x:auto;background:var(--surface);
  border:1px solid var(--rule);border-radius:12px;box-shadow:var(--shadow);
}
.sched{border-collapse:separate;border-spacing:0;width:100%;min-width:960px}
.sched th,.sched td{
  border-right:1px solid var(--rule-soft);border-bottom:1px solid var(--rule-soft);
  padding:6px 7px;font-size:.78125rem;vertical-align:top;min-width:78px;
}
.sched th:last-child,.sched td:last-child{border-right:0}
.sched tbody tr:last-child td{border-bottom:0}
.sched thead th{
  background:linear-gradient(180deg,#FBFCFE,#F2F6FC);
  border-bottom:1px solid var(--rule);
  font-size:.625rem;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);
  font-weight:700;text-align:center;padding:9px 7px;white-space:nowrap;
  position:sticky;top:0;z-index:2;
}
.sched thead th .dow{display:block;color:var(--ink-2);font-size:.65625rem;letter-spacing:.12em}
.sched thead th .dnum{display:block;margin-top:2px;color:var(--muted);font-size:.6875rem;letter-spacing:.02em;font-weight:600}
.sched thead th:first-child{
  position:sticky;left:0;top:0;z-index:3;min-width:150px;
  background:linear-gradient(90deg,#FBFCFE,#F4F7FC);
  border-right:1px solid var(--rule);
}
.sched th.wknd,.sched td.wknd{background:#F4F6FB}
.sched th.wknd .dow,.sched th.wknd .dnum{color:var(--muted)}

/* today: the one column that glows */
.sched th.today{
  background:linear-gradient(180deg,var(--brand-100),var(--brand-50));
  box-shadow:inset 0 -2px 0 var(--leaf-500);
}
.sched th.today .dow{color:var(--brand-800)}
.sched th.today .dnum{color:var(--brand-700)}
.sched td.today{
  background:linear-gradient(180deg,rgba(217,226,243,.42),rgba(237,243,252,.30));
  box-shadow:inset 1px 0 0 rgba(34,79,143,.16), inset -1px 0 0 rgba(34,79,143,.16);
}
.sched td.rowhead{
  font-weight:640;font-size:.8125rem;white-space:nowrap;color:var(--brand-900);
  background:linear-gradient(90deg,#FBFCFE,#F6F9FD);
  border-right:1px solid var(--rule);
  position:sticky;left:0;z-index:1;min-width:150px;padding:9px 14px;
}
.sched td.rowhead .muted{font-weight:500}

/* entry chips */
.sched .ent,.legend .ent{
  display:block;background:linear-gradient(180deg,#FFFFFF,#F6F9FE);
  color:var(--brand-800);border:1px solid var(--rule);
  border-left:3px solid var(--brand-600);
  border-radius:7px;padding:5px 8px;margin:3px 0;font-size:.71875rem;line-height:1.35;
  font-weight:580;
  box-shadow:0 1px 2px rgba(16,44,82,.07), 0 5px 12px -9px rgba(16,44,82,.5);
  transition:box-shadow .15s ease,transform .12s ease,border-color .15s ease;
}
.sched .ent:hover{
  box-shadow:0 1px 2px rgba(16,44,82,.09), 0 9px 20px -10px rgba(16,44,82,.65), var(--glow-blue);
  transform:translateY(-1px);border-left-color:var(--brand-700);
}
.sched .ent.leave,.legend .ent.leave{
  background:linear-gradient(180deg,#FFFCF5,var(--warn-soft));
  color:var(--warn);border-color:rgba(150,89,15,.22);border-left-color:#D79A2B;
  font-style:italic;font-weight:560;
}
.sched .ent.leave:hover{box-shadow:0 1px 2px rgba(150,89,15,.10), 0 9px 20px -10px rgba(150,89,15,.5), 0 0 0 3px rgba(215,154,43,.20)}
.sched .ent.generated,.legend .ent.generated{
  background:linear-gradient(180deg,#FBFCFF,#F1F5FD);
  color:#4A5B93;border:1px dashed rgba(74,91,147,.42);
  border-left:3px dashed rgba(74,91,147,.7);
  font-weight:540;
}
/* A hold: dates are out with a client on this person, nothing is agreed. Not
   draggable, because there is no entry yet to move. */
.sched .ent.hold,.legend .ent.hold{
  background:repeating-linear-gradient(135deg,#FFFCF5,#FFFCF5 6px,#FDF6E7 6px,#FDF6E7 12px);
  color:#96590F;border:1px dashed rgba(150,89,15,.42);
  border-left:3px dashed #D79A2B;font-weight:560;cursor:default;
}
.sched .ent.generated:hover{box-shadow:0 1px 2px rgba(74,91,147,.10), 0 9px 20px -10px rgba(74,91,147,.55), 0 0 0 3px rgba(74,91,147,.14)}
.sched .ent small{display:block;color:inherit;opacity:.68;font-size:.65625rem;font-weight:500;margin-top:1px}
.sched .ent[draggable="true"]{cursor:grab}
.sched .ent.dragging{opacity:.42;cursor:grabbing;transform:none;box-shadow:none}
.sched td.dropover{
  background:linear-gradient(180deg,var(--leaf-50),var(--leaf-100));
  outline:2px dashed var(--leaf-600);outline-offset:-3px;
  box-shadow:inset 0 0 22px -6px rgba(143,199,74,.55);
}

.weeknav{
  display:flex;align-items:center;gap:10px;margin:0 0 16px;flex-wrap:wrap;
  background:var(--surface);border:1px solid var(--rule);border-radius:11px;
  padding:8px 12px;box-shadow:var(--shadow-xs);
}
.weeknav b{
  font-size:.875rem;color:var(--brand-900);font-weight:660;
  padding:0 6px;letter-spacing:-.01em;
}
.weeknav .hidden-note{font-size:.75rem}
.weeknav .hidden-note small{font-size:.6875rem}
.legend{
  display:flex;gap:14px;margin:14px 0 0;color:var(--muted);font-size:.78125rem;
  align-items:center;flex-wrap:wrap;
}
.legend .ent{padding:3px 10px;border-radius:7px;font-size:.71875rem;display:inline-block;margin:0}
.legend .legend-note{flex:1;min-width:260px;line-height:1.5}

/* One colour per client (C6, 11 Sept; bold since 2026-09-28). Kate on the
   28 Sep walkthrough: "I'd like bold colours. I don't want those mushy, fluffy
   colours. I need an array of colours." Eighteen tones, each a solid fill with
   white text. The client's slot is picked on Client 360 (clients.colour_slot);
   with no pick, the client id modulo eighteen chooses one, so a client keeps
   one colour either way (schedule.tone_for). Slots, not free hex, so two
   clients cannot land one shade apart and a light pick cannot make the white
   text unreadable.
   Contrast against white, checked 2026-09-28 (WCAG ratio; the second figure is
   the .l2/.l3 lines at opacity .9). Every one clears 4.5:1 at the 10 px month
   size; any tone added later has to as well:
     0 #1F5FBF 6.1/5.3   1 #B8321F 6.0/5.1   2 #1A7340 5.9/5.1   3 #6D2FB5 7.7/6.6
     4 #A34A07 5.9/5.1   5 #0C7070 5.8/5.0   6 #B02570 6.3/5.4   7 #55700F 5.7/5.0
     8 #3346B8 7.8/6.6   9 #8F4A22 6.6/5.7  10 #186F94 5.6/4.9  11 #7E2E2E 9.1/7.7
    12 #256B2B 6.5/5.6  13 #86198F 8.2/6.9  14 #A11A1A 7.8/6.6  15 #0F6B64 6.4/5.5
    16 #7A5C00 6.3/5.4  17 #475569 7.6/6.5 */
:root{
  --client-0:#1F5FBF; --client-1:#B8321F; --client-2:#1A7340; --client-3:#6D2FB5;
  --client-4:#A34A07; --client-5:#0C7070; --client-6:#B02570; --client-7:#55700F;
  --client-8:#3346B8; --client-9:#8F4A22; --client-10:#186F94; --client-11:#7E2E2E;
  --client-12:#256B2B; --client-13:#86198F; --client-14:#A11A1A; --client-15:#0F6B64;
  --client-16:#7A5C00; --client-17:#475569;
  /* The same eighteen at 14% on white. Only a forecast uses these now: it
     stays a tint so it still reads as not yet real. Precomputed rather than
     color-mix() because Monique's browser is unknown. */
  --client-0-soft:#E0E9F6; --client-1-soft:#F5E2E0; --client-2-soft:#DFEBE4; --client-3-soft:#EBE2F5;
  --client-4-soft:#F2E6DC; --client-5-soft:#DDEAEA; --client-6-soft:#F4E0EB; --client-7-soft:#E7EBDD;
  --client-8-soft:#E2E5F5; --client-9-soft:#EFE6E0; --client-10-soft:#DFEBF0; --client-11-soft:#EDE2E2;
  --client-12-soft:#E0EAE1; --client-13-soft:#EEDFEF; --client-14-soft:#F2DFDF; --client-15-soft:#DDEAE9;
  --client-16-soft:#ECE8DB; --client-17-soft:#E5E7EA;
  /* No client: the seed's forecast rows with no job, and any internal day. */
  --client-none:#6B7280; --client-none-soft:#F1F2F5;
}
.sched .ent{border-left-width:4px}
.sched .ent small.builder{opacity:.9;font-weight:560}
/* An audit entry is a solid block in the client's colour with white text.
   --tone and --tone-soft are set inline by the grid template per entry. A
   forecast keeps the soft tint, a dashed border and dark text, so it still
   reads as a forecast rather than a booking. */
.sched .ent.audit,.legend .ent.audit{
  background:var(--tone,var(--brand-600));border-color:var(--tone,var(--brand-600));
  color:#fff;
}
.sched .ent.audit .l2,.sched .ent.audit .l3,.sched .ent.audit small{opacity:.9}
.sched .ent.audit .inv-dot{box-shadow:0 0 0 1.5px #fff}
.sched .ent.audit.generated,.legend .ent.audit.generated{
  background:var(--tone-soft,#F6F9FE);opacity:.72;border-style:dashed;color:#3E4F80;
}
.sched .ent.audit.generated .inv-dot{box-shadow:none}
.sched .ent.audit:hover{border-left-color:var(--tone,var(--brand-700));filter:brightness(1.08)}
/* A roster day off Deputy with no project attached yet (2026-09-28): the same
   fill, and a quiet dashed right edge. A marker, not a warning: the day is
   real work, the office just has not said which project it is. */
.sched .ent.audit.roster,.legend .ent.audit.roster{border-right:2px dashed rgba(255,255,255,.7)}
.legend .ent.audit.roster{outline:1px solid var(--tone,var(--brand-600));outline-offset:-1px}

/* The colour picker on Client 360's billing rules. Radios under the swatches,
   so it is keyboard reachable and posts one value. Auto shows the fallback. */
.swatches{display:flex;flex-wrap:wrap;gap:6px;margin:4px 0 2px}
.swatches label{display:inline-flex;position:relative;cursor:pointer;margin:0}
.swatches input{position:absolute;opacity:0;width:1px;height:1px}
.swatches span{
  width:20px;height:20px;border-radius:5px;background:var(--tone);display:inline-block;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.12);
}
.swatches .auto span{
  width:auto;padding:0 6px;color:#fff;font-size:.65625rem;font-weight:640;line-height:20px;
}
.swatches input:checked + span{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--ink,#111)}
.swatches input:focus-visible + span{outline:2px solid var(--brand-600);outline-offset:3px}
.rules-grid .colour-pick{grid-column:1 / -1;display:flex;flex-direction:column;gap:4px;font-size:.71875rem;font-weight:700;color:var(--ink-2)}
.rules-grid .colour-pick small{font-weight:500}
.rules-grid .swatches label{display:inline-flex;flex-direction:row;gap:0}

/* Blocked days: leave, RDO, public holiday, shutdown. Muted, not draggable,
   removed with the small cross. Leave keeps its old amber; the other three
   are grey so a month of public holidays does not read as a month of leave. */
.sched .ent.blocked,.legend .ent.blocked{
  background:linear-gradient(180deg,#FAFAFB,#F1F2F5);
  color:#4B5563;border-color:rgba(75,85,99,.22);border-left-color:#9AA3AF;
  font-style:italic;font-weight:560;cursor:default;position:relative;padding-right:20px;
}
.sched .ent.blocked:hover{transform:none;box-shadow:0 1px 2px rgba(16,44,82,.07)}
.sched .ent.blocked.leave,.legend .ent.blocked.leave{
  background:linear-gradient(180deg,#FFFCF5,var(--warn-soft));
  color:var(--warn);border-color:rgba(150,89,15,.22);border-left-color:#D79A2B;
}
.sched .ent.blocked.shutdown,.legend .ent.blocked.shutdown{
  background:repeating-linear-gradient(135deg,#F7F7F9,#F7F7F9 6px,#ECEDF1 6px,#ECEDF1 12px);
}
.sched .ent.blocked.public_holiday,.legend .ent.blocked.public_holiday{border-left-color:#6B7280}
/* Other work (A2): a real day's work on someone's line, so upright and blue
   rather than grey and italic, but still not draggable and still blocking. */
.sched .ent.blocked.work,.legend .ent.blocked.work{
  background:linear-gradient(180deg,#F7FAFF,#EAF1FB);
  color:#1F3B66;border-color:rgba(34,79,143,.22);border-left-color:#224F8F;font-style:normal;
}
.legend .ent.blocked{padding-right:10px}
.ent-x{
  position:absolute;top:2px;right:3px;border:0;background:transparent;color:inherit;
  opacity:.5;font-size:.8125rem;line-height:1;padding:2px 4px;cursor:pointer;border-radius:4px;
}
.ent-x:hover{opacity:1;background:rgba(0,0,0,.06)}

/* Month view: 22 weekday columns in one screen (31 with weekends shown).
   Narrow cells, two-letter weekday, day number. An audit entry is three
   short lines that wrap, never one long line with an ellipsis: the client's
   short name, the builder's short name (or the audit type), then the start
   time with an invite-state dot. Height is free; width is not. */
.sched.month{min-width:0;table-layout:fixed}
/* The month grid's chips stay in px, outside the E-017 text size knob: 31
   columns share a fixed width and one step up clipped the start time. */
.sched.month th,.sched.month td{min-width:0;padding:3px 1px;font-size:.6875rem}
.sched.month thead th:first-child,.sched.month td.rowhead{width:100px;min-width:100px;padding:7px 8px;font-size:.75rem;white-space:normal;line-height:1.2}
.sched.month thead th .dow{font-size:.5625rem;letter-spacing:.06em}
.sched.month thead th .dnum{font-size:.65625rem;margin-top:1px}
/* 10 px with tight tracking. A line never breaks inside a word (12 Sept: the
   block-level word-break was splitting "Northbridge" into "Northbri / dge");
   a word wider than the column is cut with an ellipsis, and the client's
   full name is on hover and in the drawer. The stored short name on Client
   360 is the real fix for a client whose name is regularly too long, and the
   sidebar fold gives the column about 8 px back. Cell and block side padding
   is 1 px and 2 px (trimmed the same day, 4 px a column); below that the
   blocks touch the cell rule and a row reads as one smear. */
.sched.month .ent{padding:3px 2px;font-size:10px;letter-spacing:-.015em;line-height:1.25;border-radius:4px;margin:2px 0;
  border-left-width:3px;white-space:normal;overflow:hidden}
.sched.month .ent.audit{min-height:42px}
.sched.month .ent .l1{display:block;font-weight:640;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sched.month .ent .l2{display:block;opacity:.85;font-weight:520;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sched.month .ent .l3{display:flex;align-items:center;gap:4px;opacity:.75;font-size:9.5px;margin-top:1px;min-height:10px}
.inv-dot{width:6px;height:6px;border-radius:50%;background:#9AA3AF;flex:none}
.inv-dot.sent,.inv-dot.updated{background:var(--leaf-600)}
.inv-dot.cancelled{background:#B42318}
.inv-dot.generated{background:transparent;border:1px dashed #6B7A9E}
/* The key for the invite dot, in the legend (12 Sept). Reuses the dot classes
   so the colours cannot drift from the cells. */
.legend .dotkey{display:inline-flex;align-items:center;gap:5px;font-size:.71875rem;color:var(--ink-2);margin-left:4px}
.legend .dotkey .inv-dot{width:7px;height:7px}
.sched.month .ent.blocked{padding-right:14px;font-size:10px}
.sched.month .ent-x{top:0;right:0;font-size:.75rem}
.sched.month td[data-staff-id]:not(:has(.ent)){cursor:cell}

/* The side drawer for one entry (2026-09-11). Fixed to the right edge, the
   grid stays visible and scrollable behind it, so the next entry is one click
   away. Not a modal and no backdrop, on purpose. */
.drawer{
  position:fixed;top:0;right:0;bottom:0;width:380px;max-width:92vw;z-index:20;
  background:var(--surface);border-left:1px solid var(--rule);
  box-shadow:-12px 0 32px -18px rgba(16,44,82,.5);padding:18px 20px;overflow-y:auto;
}
.drawer-head{display:flex;align-items:flex-start;gap:10px;margin-bottom:12px}
.drawer-head h2{font-size:1.0625rem;margin:0;color:var(--brand-900);line-height:1.25;overflow-wrap:anywhere}
.drawer-x{border:0;background:transparent;font-size:1.25rem;line-height:1;cursor:pointer;color:var(--muted);padding:2px 7px;border-radius:6px;flex:none}
.drawer-x:hover{background:rgba(0,0,0,.05);color:var(--ink)}
.drawer-kv{display:grid;grid-template-columns:auto 1fr;gap:7px 14px;font-size:.8125rem;margin:10px 0;align-items:start}
.drawer-kv b{color:var(--ink-2);font-weight:600;white-space:nowrap}
.drawer-kv span{overflow-wrap:anywhere}
.drawer-notes{margin:12px 0 0;padding:10px 12px;background:#FFF6E5;border-left:3px solid #E8B341;border-radius:3px;font-size:.8125rem;white-space:pre-line}
@media (max-width:700px){.drawer{width:100%;max-width:100%}}

/* The add-leave form under the week nav */
.leave-form{margin:0 0 16px}
.leave-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px 14px;align-items:end}
.leave-grid label{display:flex;flex-direction:column;gap:4px;font-size:.78125rem;font-weight:600;color:var(--ink-2)}
.leave-grid label input,.leave-grid label select{font:inherit;font-weight:400;padding:7px 9px;border:1px solid var(--rule);border-radius:8px;background:#fff;color:var(--ink)}
.leave-grid .leave-note{grid-column:1 / -1}
@media (max-width:820px){.leave-grid{grid-template-columns:1fr 1fr}}

/* Known-contact chips on the Prepare dates page: click to add the address */
.chip{
  display:inline-block;font:inherit;font-size:.71875rem;padding:2px 9px;margin:2px 3px 2px 0;
  border:1px solid var(--rule);border-radius:999px;background:var(--surface);color:var(--brand-800);
  cursor:pointer;
}
.chip:hover{border-color:var(--brand-300);background:var(--brand-50)}

/* ============================================================
   Filters row
   ============================================================ */
.filters{display:flex;gap:10px;margin:0 0 18px;flex-wrap:wrap;align-items:center}

/* ============================================================
   Error page
   ============================================================ */
.errorbox{
  background:var(--surface);border:1px solid var(--rule);border-radius:16px;
  box-shadow:var(--shadow-md);padding:44px 40px;max-width:540px;margin:48px auto;text-align:center;
}
.errorbox h1{font-size:1.3125rem;margin:0 0 8px;color:var(--brand-900)}
.errorbox .page-sub{margin:0 auto 14px;max-width:42ch}

/* ============================================================
   Variation sub-rows
   ============================================================ */
tr.subrow td{
  border-bottom:1px solid var(--rule-soft);
  background:linear-gradient(90deg,var(--brand-50),#FBFCFE);
  font-size:.78125rem;color:var(--ink-2);padding:6px 15px 6px 32px;
}
tbody tr.subrow:hover td{background:linear-gradient(90deg,var(--brand-100),#F6F9FD)}

/* ============================================================
   To Quote record: enquiry beside the service catalogue
   ============================================================ */
.quotegrid{display:grid;grid-template-columns:minmax(320px,1fr) minmax(0,1.15fr);gap:20px;align-items:start}
@media(max-width:1000px){.quotegrid{grid-template-columns:1fr}}

/* the extracted ask: the one thing on the page Kate reads before deciding */
.askbox{
  background:linear-gradient(180deg,var(--brand-50),#FBFCFE);
  border:1px solid var(--brand-100);border-left:3px solid var(--brand-600);
  border-radius:10px;padding:13px 15px;margin:14px 0 10px;
}
.askbox b{
  display:block;font-size:.65625rem;text-transform:uppercase;letter-spacing:.1em;
  color:var(--brand-700);font-weight:700;margin-bottom:5px;
}
.askbox p{margin:0;font-size:.90625rem;color:var(--ink);line-height:1.5}

/* service catalogue rows */
.svc-cat{
  font-size:.625rem;text-transform:uppercase;letter-spacing:.13em;color:var(--muted);
  font-weight:700;padding:14px 2px 6px;
}
.svc-cat:first-of-type{padding-top:4px}
.svc{
  display:grid;grid-template-columns:auto 1fr auto 62px;align-items:center;gap:11px;
  padding:8px 11px;border:1px solid var(--rule-soft);border-radius:9px;margin-bottom:5px;
  cursor:pointer;background:var(--surface);
  transition:border-color .13s ease,background .13s ease,box-shadow .13s ease;
}
.svc:hover{border-color:var(--brand-300);background:var(--brand-50)}
.svc.on{border-color:var(--brand-500);background:var(--brand-50);box-shadow:var(--glow-blue)}
.svc input[type=checkbox]{accent-color:var(--brand-700);width:16px;height:16px;cursor:pointer}
.svc-name{font-size:.84375rem;color:var(--ink);min-width:0}
.svc-name small{display:block;font-size:.71875rem;margin-top:1px}
.svc-rate{
  font-size:.84375rem;font-weight:640;color:var(--brand-800);
  font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap;
}
.svc-rate small{display:block;font-size:.65625rem;font-weight:500;color:var(--muted);letter-spacing:.02em}
.svc-qty{
  width:100%;padding:5px 7px;border:1px solid var(--rule);border-radius:7px;
  font-size:.8125rem;font-family:inherit;color:var(--ink);background:var(--surface);
  text-align:center;font-variant-numeric:tabular-nums;
}
.svc-qty:focus{outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}
.svc-qty:disabled{background:var(--rule-soft);color:var(--muted);cursor:not-allowed}

/* A custom line's own type pickers. Appended as a fifth grid child so it
   wraps onto a second line and spans the full width of the row. */
.svc-types{
  grid-column:1/-1;display:flex;gap:8px;flex-wrap:wrap;
  padding-top:7px;margin-top:5px;border-top:1px dashed var(--rule-soft);
}
.svc-types select{
  padding:4px 7px;border:1px solid var(--rule);border-radius:7px;
  font-size:.75rem;font-family:inherit;color:var(--ink);background:var(--surface);
  max-width:100%;
}
.svc-types select:focus{outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}

.svc-total{
  display:flex;justify-content:space-between;align-items:baseline;
  border-top:1px solid var(--rule);margin-top:16px;padding-top:14px;
  font-size:.8125rem;color:var(--ink-2);
}
.svc-total b{font-size:1.3125rem;color:var(--brand-900);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.svc-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:14px}
/* E-018: the optional proposal number above the Generate buttons, and the
   Change number fold-away on the proposal page. One narrow field, not a row. */
.quote-number{display:block;margin:14px 0 4px;font-size:.78125rem;color:var(--ink-2)}
.quote-number input,.renumber input[type=text]{
  display:block;width:100%;max-width:240px;margin-top:3px;padding:7px 9px;
  border:1px solid var(--rule);border-radius:7px;font:inherit;color:var(--ink);
  background:var(--surface);text-transform:uppercase;
}
.quote-number input:focus,.renumber input[type=text]:focus{outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}
.renumber form{padding:0 14px 12px}
/* The service name and the two rate figures: fill the column the colgroup gave
   them rather than carrying a width of their own, which is what overflowed. */
.svc-name{width:100%}
.ratebox{width:100%;text-align:right}
/* The rate card under a price row's service name. Quieter than the service
   itself because it is the qualifier, not the thing, but a real input: Kate
   adds client rates from this page and has to be able to label them. */
.svc-note{display:block;width:100%;margin-top:4px;
  font-size:.71875rem;color:var(--muted);
  /* No box. The dashed border was doing the job of saying "editable but
     optional", and on a page where fourteen of eighteen rows have no note
     it just drew fourteen empty boxes (Nathan, 26 Sep: "the checkered box
     underneath is confusing"). A note now reads as what it is, a line of
     quiet text under the service, marked by a rule down its left edge. */
  border:0;border-left:2px solid var(--rule);border-radius:0;
  background:transparent;padding:0 0 0 7px}
/* An empty note is not a field at all: it collapses to nothing and comes
   back on row hover or keyboard focus, so the four rows that carry a note
   read as text and the other fourteen show a clean service name. Height
   rather than display:none, so the input keeps its place in the tab order. */
.svc-note:placeholder-shown{height:0;margin-top:0;padding-top:0;padding-bottom:0;
  border-left-color:transparent;opacity:0}
tr:hover .svc-note:placeholder-shown,
.svc-note:placeholder-shown:focus{height:auto;margin-top:4px;opacity:1}
.svc-note:hover{border-left-color:var(--brand-300)}
.svc-note:focus{color:var(--ink);border-left-color:var(--brand-500);outline:none}
.svc-note::placeholder{font-style:italic;opacity:.7}
/* The note on a client rate row. NOT .svc-note: that one carries
   min-width:260px for the price list, where it sits under a service name
   with the row to itself. In a table cell a 260px floor forces the column
   wide and pushes the rate and the buttons off the end. */
.rate-note{width:100%}
.rate-note input{width:100%;min-width:0;font-size:.71875rem;color:var(--muted);
  border-style:dashed}
.rate-note input:focus{color:var(--ink);border-style:solid}
.rate-note input::placeholder{font-style:italic;opacity:.7}

/* the enquiry snippet on the list page */
.enq-ask{
  display:inline-block;max-width:34ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  vertical-align:bottom;color:var(--ink-2);font-size:.78125rem;
  background:var(--brand-50);border:1px solid var(--brand-100);border-radius:6px;padding:2px 8px;
}

/* ============================================================
   Editable rules (2026-09-02): inline editors on Client 360,
   the Rules and Rates pages, and the schedule correction prompt
   ============================================================ */
/* Required fields (2026-09-11, Nathan's review of Release 1). The mark goes on
   the inline element that holds the label text (a span inside a flex label, the
   <b> of a .kv, an <h2> on the public form) and the asterisk is drawn, never
   typed. The input carries `required` where a phone should stop the obvious
   miss; the server check is still the one that matters. */
.req::after{content:" *";color:#B42318;font-weight:700}
.req-key{font-size:.78125rem;color:var(--muted);margin:0 0 12px}

.rules-block{border-top:1px solid var(--rule-soft);margin-top:14px;padding-top:12px}
.rules-block.compact{margin-top:8px;padding-top:8px}
.rules-head{display:flex;align-items:center;gap:10px;margin:0 0 8px;font-size:.84375rem;color:var(--brand-900)}
.rules-sub{font-size:.75rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-2);margin:0 0 6px}
.rules-sub small{font-weight:500;letter-spacing:0;text-transform:none}
.rules-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:10px 18px}
.rules-grid label,.rules-inline label{display:flex;flex-direction:column;gap:4px;font-size:.71875rem;font-weight:700;color:var(--ink-2)}
.rules-grid label.wide{grid-column:1 / -1}
.rules-grid input[type="text"],.rules-grid textarea,.rules-inline input,.addrow input[type="text"],
.rules-block input[type="date"],.rules-block input[type="number"],.card input[type="text"],.card input[type="number"]{
  font:inherit;font-size:.8125rem;padding:6px 10px;border:1px solid var(--rule);border-radius:8px;
  background:var(--surface);color:var(--ink);box-shadow:var(--shadow-xs);
}
.rules-grid input:focus,.rules-grid textarea:focus,.rules-inline input:focus,.addrow input:focus,.card input:focus{
  outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}
.rules-checks{display:flex;flex-wrap:wrap;gap:8px 22px;margin:10px 0 6px}
.rules-checks small{margin-left:2px}
/* The roster: fourteen names with a role and sometimes a workload pill, so a
   grid of even columns rather than a ragged wrap. */
.roster-checks{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:8px 22px}
.rules-actions{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:8px}
.rules-inline{display:flex;flex-wrap:wrap;align-items:flex-end;gap:8px 14px}
.rules-inline label{min-width:120px}
.rules-cols{display:grid;grid-template-columns:1fr 1fr;gap:14px 26px}
@media(max-width:820px){.rules-cols{grid-template-columns:1fr}}
.rule-list{list-style:none;margin:0;padding:0}
.rule-list li{display:flex;align-items:center;gap:10px;padding:6px 0;border-bottom:1px dashed var(--rule-soft);font-size:.84375rem}
.rule-list li:last-child{border-bottom:0}
.rule-who{font-weight:640;color:var(--brand-900);min-width:120px}
.rule-who.bad{color:var(--bad)}
.rule-why{flex:1;font-size:.78125rem}
.rule-empty{color:var(--muted);font-size:.8125rem;margin:4px 0}
.rule-empty.design{color:var(--ink-2)}
.addrow{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:10px}
.rule-add select{min-width:120px}
.rules-entities{margin-top:14px;font-size:.84375rem}
.entity-list{list-style:none;margin:6px 0;padding:0}
.entity-list li{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:4px 0;border-bottom:1px dashed var(--rule-soft)}
.entity-list li:last-child{border-bottom:0}
.banner.correction{
  background:linear-gradient(180deg,#F5F9FF,var(--brand-50));
  border-color:rgba(34,79,143,.22);border-left-color:var(--brand-700);color:var(--brand-900);
  box-shadow:0 1px 2px rgba(16,44,82,.06), 0 14px 30px -22px rgba(16,44,82,.55);
}
.banner.correction .banner-icon{background:rgba(34,79,143,.12);color:var(--brand-700);box-shadow:inset 0 0 0 1px rgba(34,79,143,.2)}
.banner.correction .rule-add{margin-top:8px}
.card.inactive{opacity:.72}

/* Client 360: projects as an index you click into, not a stack of cards */
.section-count{font-weight:500;font-size:.8125rem;margin-left:6px}
.project-index{padding:14px 16px}
.project-index .project-rows{margin:0}
.project-rows tr.rowlink td{cursor:pointer}
.project-rows tr.open td{background:var(--brand-50);font-weight:600}
.project-rows tr.open td a{color:var(--brand-900)}
.project-open{border-left:4px solid var(--brand-700)}

/* ============================================================
   Feedback control (2026-09-04, moved 2026-09-06 per Valera):
   a floating pill in the bottom-left of the page canvas, on every
   page, every role. Opens a native dialog that pops up above the
   pill rather than centring on the screen, so it reads as "about
   this page". The page it was opened on is captured, never typed.
   ============================================================ */
/* Bottom-right, not bottom-left. It still sits on the page canvas rather than
   in the sidebar, which was the point of the 2026-09-06 decision, but the left
   corner is where every table's first column and every row link live, so it was
   covering content on half the pages. Nothing is right-aligned down there. */
.fb-trigger{
  position:fixed;right:24px;bottom:18px;z-index:60;
  display:inline-flex;align-items:center;gap:8px;
  padding:9px 14px 9px 12px;border:1px solid var(--brand-100);border-radius:999px;
  background:var(--surface);color:var(--brand-900);
  font:inherit;font-size:.8125rem;font-weight:600;cursor:pointer;white-space:nowrap;
  box-shadow:var(--shadow-lg);
  transition:transform .14s ease,box-shadow .14s ease,background .14s ease;
}
.fb-trigger:hover{background:var(--brand-50);transform:translateY(-1px)}
.fb-trigger:focus-visible{outline:2px solid var(--brand-500);outline-offset:2px}
.fb-trigger .ni{width:16px;text-align:center;font-size:.8125rem;color:var(--leaf-500);flex:none}
.fb-dialog{
  position:fixed;right:24px;bottom:70px;margin:0;inset-inline-start:auto;inset-block-start:auto;
  border:1px solid var(--rule);border-radius:16px;padding:0;width:min(92vw,480px);
  background:var(--surface);color:var(--ink);box-shadow:var(--shadow-lg);
}
.fb-dialog::backdrop{background:rgba(16,44,82,.18)}
@media(prefers-reduced-motion:no-preference){
  .fb-dialog[open]{animation:fb-pop .16s ease-out}
  @keyframes fb-pop{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
}
.fb-head{padding:22px 24px 0}
.fb-head h2{font-size:1.125rem;margin:0 0 4px;font-weight:660;color:var(--brand-900)}
.fb-sub{color:var(--ink-2);font-size:.8125rem;margin:0}
#feedback-body{padding:16px 24px 22px}
#feedback-body .banner{margin-bottom:14px}
.fb-page{
  display:flex;gap:10px;align-items:baseline;font-size:.8125rem;margin:0 0 12px;padding:8px 11px;
  background:var(--brand-50);border:1px solid var(--brand-100);border-radius:8px;
}
.fb-page b{font-size:.65625rem;text-transform:uppercase;letter-spacing:.1em;color:var(--brand-700);font-weight:700}
.fb-page small{margin-left:8px;font-size:.71875rem}
#feedback-body label{display:flex;flex-direction:column;gap:4px;font-size:.71875rem;font-weight:700;color:var(--ink-2);margin:0 0 12px}
#feedback-body textarea{
  font:inherit;font-size:.84375rem;padding:8px 10px;border:1px solid var(--rule);border-radius:8px;
  background:var(--surface);color:var(--ink);box-shadow:var(--shadow-xs);resize:vertical;
}
#feedback-body textarea:focus{outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}
.fb-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:4px}
.fb-text{white-space:pre-wrap;min-width:200px;max-width:44ch;font-size:.8125rem}
@media(max-width:820px){
  .fb-trigger{right:12px;left:auto;bottom:12px;padding:9px 11px}
  .fb-trigger .fb-label{display:none}
  .fb-dialog{left:12px;right:12px;bottom:60px;width:auto}
}

/* ============================================================
   Filter bar (app/filters.py + _filterbar.html), 2026-09-07
   Added when the real client list landed: 247 clients and 187
   proposals cannot be worked from a flat scroll.
   ============================================================ */
/* Laid out across the width rather than stacked: three tab rows and a search
   box in a column pushed the actual table below the fold on a laptop. Each
   group stays an unbreakable unit, so they wrap as whole groups instead of
   splitting a label from its tabs. */
.filterbar{
  display:flex;flex-flow:row wrap;align-items:center;column-gap:26px;row-gap:10px;
  margin:0 0 18px;padding:12px 15px;
  background:linear-gradient(180deg,#FBFCFE,#F6F9FD);
  border:1px solid var(--rule);border-radius:12px;
}
.filterrow{display:flex;align-items:center;gap:9px;flex:0 0 auto}
.filterlabel{
  font-size:.6875rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-3,#7C8DA6);min-width:52px;
}
.filterbar .tabs{margin:0}
.filterbar .tabs a{padding:5px 12px;font-size:.78125rem}
.tabn{
  display:inline-block;margin-left:5px;padding:0 6px;border-radius:7px;
  background:rgba(34,79,143,.09);color:var(--brand-700);
  font-size:.6875rem;font-weight:700;line-height:17px;vertical-align:1px;
}
.tabs a.active .tabn{background:rgba(34,79,143,.16)}
/* Search takes the leftover width and sits at the end of the bar. */
.filtersearch{flex:1 1 260px;margin-left:auto;justify-content:flex-end}
.filtersearch input[type="search"]{
  flex:1 1 240px;min-width:180px;max-width:380px;
  padding:7px 11px;border:1px solid var(--rule);border-radius:9px;
  background:var(--surface);font-size:.8125rem;color:var(--ink);
}
.filtersearch input[type="search"]:focus{
  outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue);
}
/* Tier 3. It kept the border, gradient and shadow before, so it read as a
   second tier-2 button rather than as a quiet one. */
.btn-quiet{
  color:var(--ink-2);font-weight:600;border-color:transparent;
  background:none;box-shadow:none;text-decoration:underline;
  text-underline-offset:2px;text-decoration-color:var(--rule);
}
.btn-quiet:hover{
  background:none;box-shadow:none;border-color:transparent;
  color:var(--brand-700);text-decoration-color:currentColor;
}
/* Destructive. Outlined and never filled: a solid red button on a page of blue
   pulls the eye straight to the one control nobody should press. */
.btn-danger{
  color:var(--bad);border-color:rgba(164,52,43,.28);
  background:linear-gradient(180deg,#FFFFFF,#FDF6F5);
}
.btn-danger:hover{
  color:var(--bad);border-color:var(--bad);background:var(--bad-soft);
  box-shadow:var(--shadow-xs),0 0 0 3px rgba(164,52,43,.16);
}
/* .btn-remove was used in the markup and had no rule at all. */
.btn-remove{color:var(--bad);border-color:rgba(164,52,43,.28);background:none;box-shadow:none}
.btn-remove:hover{background:var(--bad-soft);border-color:var(--bad)}
.filtercount{margin-left:auto;font-size:.78125rem;color:var(--ink-2);white-space:nowrap}
.filtercount b{color:var(--brand-700)}
.emptyfilter{
  padding:26px 18px;text-align:center;color:var(--ink-2);font-size:.875rem;
  background:var(--ground-2);border:1px dashed var(--rule);border-radius:12px;
}
.emptyfilter b{color:var(--ink)}
@media (max-width:820px){
  .filterlabel{min-width:0}
  .filtercount{margin-left:0;width:100%}
}
.clstatus{padding:10px 11px 0;background:linear-gradient(180deg,#FBFCFE,#F6F9FD)}
.clstatus .tabs{margin:0;width:100%;display:flex;flex-wrap:wrap;gap:2px}
.clstatus .tabs a{padding:4px 9px;font-size:.71875rem;flex:1 1 auto;text-align:center}
.clstatus .tabn{margin-left:3px;padding:0 4px;font-size:.625rem;line-height:15px}

/* Outcome of Generate Proposal: whether the Word document reached the person
   who pressed the button. Separate from the proposal row, which is saved
   either way. */
.doc-note{margin:-4px 0 18px;padding:10px 14px;border-radius:4px;font-size:.875rem;line-height:1.5}
.doc-ok{background:#EAF4EC;border:1px solid #6FA57E;color:#22452C}
.doc-warn{background:#FFF4E5;border:1px solid #E8B341;color:#5C4210}
.doc-bad{background:#FBEAE5;border:1px solid #C0563A;color:#5C2313}

/* A line the client did not take. Still on the record, visibly not counted. */
.li-declined td{opacity:.55}
.li-declined td:first-child{text-decoration:line-through;text-decoration-thickness:1px}

/* ---- Proposals list: collapsible stages, clickable rows, status + document ---- */

/* <details> keeps the .group card look; the summary is the old group-head. */
details.group > summary{list-style:none;cursor:pointer;user-select:none}
details.group > summary::-webkit-details-marker{display:none}
.group-caret{
  width:0;height:0;flex:none;margin-right:2px;
  border-left:5px solid var(--ink-3,#7C8DA6);
  border-top:4px solid transparent;border-bottom:4px solid transparent;
  transition:transform .15s ease;
}
details[open] > summary .group-caret{transform:rotate(90deg) translateX(-1px)}
details.group > summary:hover{background:linear-gradient(180deg,#F7FAFE,#EDF3FB)}

/* The row is a link. Anything interactive inside it opts out (see app.js). */
tr.rowlink{cursor:pointer}
tr.rowlink:hover{background:var(--brand-50,#F4F8FD)}

/* Document: a heading and an icon under it, not a button competing with the
   status control. */
.col-doc{width:92px;text-align:center}
td.col-doc{text-align:center}
.doclink{
  display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;border-radius:8px;color:var(--brand-700);
  border:1px solid transparent;
}
.doclink:hover{background:var(--brand-50,#F1F6FC);border-color:var(--rule);text-decoration:none}

/* Held well clear of the document icon so the two never read as one control. */
.col-status{width:170px;padding-left:22px}
.statusselect{
  width:100%;padding:6px 9px;border:1px solid var(--rule);border-radius:8px;
  background:var(--surface);font-size:.78125rem;color:var(--ink);cursor:pointer;
}
.statusselect:focus{outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}

/* ---- Notes ---- */
.noteform{display:flex;gap:9px;align-items:flex-start}
.noteform textarea{
  flex:1;padding:8px 11px;border:1px solid var(--rule);border-radius:9px;
  background:var(--surface);font:inherit;font-size:.8125rem;color:var(--ink);resize:vertical;
}
.noteform textarea:focus{outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}
.notelist{list-style:none;margin:14px 0 0;padding:0;display:flex;flex-direction:column;gap:11px}
.notelist li{border-left:2px solid var(--rule);padding:1px 0 1px 12px}
.notemeta{font-size:.71875rem;color:var(--ink-3,#7C8DA6);font-weight:600}
.notebody{font-size:.84375rem;white-space:pre-wrap;margin-top:2px}

/* Ops board: project and work are separate columns, and the auditor is a
   control rather than a printed name. */
/* Enough for a full name, which is the whole point of the column: "Justin
   Dessent" truncated to "Justin Des..." tells you less than nothing on a board
   where two auditors could share a first name. */
.col-assign{width:200px;min-width:200px}
/* The long ones are addresses. Let them wrap onto a second line rather than
   pushing every other column off the screen. */
/* Every status group is its own <table>, so auto layout sized each one to its
   own content and the same column landed at a different x in every group.
   Fixed layout makes the existing .col-* width classes authoritative. */
.group table{table-layout:fixed}
.col-project{max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.col-project a{overflow-wrap:normal;overflow:hidden;text-overflow:ellipsis;display:block}
td.col-hc,td.col-type{white-space:normal;max-width:170px}
.assignselect{
  width:100%;padding:5px 8px;border:1px solid var(--rule);border-radius:7px;
  background:var(--surface);font-size:.78125rem;color:var(--ink);cursor:pointer;
}
.assignselect:focus{outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}

/* ---- Availability strip on Propose dates ----
   Six weeks of weekdays. Read-only information, not a booking surface: the
   three option fields remain the only thing that gets saved. */
.availstrip{display:flex;flex-direction:column;gap:5px;margin-top:8px}
.availweek{display:grid;grid-template-columns:58px repeat(5,1fr);gap:5px;align-items:stretch}
.availwk{
  display:flex;align-items:center;font-size:.6875rem;font-weight:700;letter-spacing:.03em;
  color:var(--ink-3,#7C8DA6);white-space:nowrap;
}
.availday{
  display:flex;flex-direction:column;align-items:center;gap:1px;
  padding:6px 4px;border:1px solid var(--rule);border-radius:8px;
  background:var(--surface);cursor:pointer;font:inherit;line-height:1.15;
  transition:background .12s ease,border-color .12s ease;
}
.availday:hover:not(:disabled){border-color:var(--brand-500);background:var(--brand-50,#F4F8FD)}
.availdow{font-size:.59375rem;text-transform:uppercase;letter-spacing:.08em;color:var(--muted)}
.availnum{font-size:.875rem;font-weight:660;color:var(--ink)}
.availfree{font-size:.65625rem;color:var(--ink-2);font-variant-numeric:tabular-nums}
/* Everyone free: worth spotting at a glance. Nobody free: worth avoiding. */
.availday.all{background:#F2F9F4;border-color:#BFDFC8}
.availday.none{background:#FBF3F1;border-color:#E4C3B9}
.availday.none .availfree{color:#A8321B}
/* Held mode: the strip is one person's diary, so a day says what is on it
   rather than counting a pool. Forecast is not a booking, so it reads as a
   maybe rather than a wall. */
.availday.forecast{
  background:repeating-linear-gradient(135deg,#FFFFFF,#FFFFFF 5px,#F1F5FD 5px,#F1F5FD 10px);
  border-color:rgba(74,91,147,.36);
}
.availday.forecast .availfree{color:#4A5B93}
.availday.held{
  background:#FFFCF5;border-color:#D79A2B;border-style:dashed;
}
.availday.held .availfree{color:#96590F}
.availday.past{opacity:.35;cursor:not-allowed;background:var(--sunk,#F4F6F9)}
.availday.picked{
  border-color:var(--brand-700);background:var(--brand-50,#EAF1FB);
  box-shadow:inset 0 0 0 1px var(--brand-700);
}
.availday.picked .availnum{color:var(--brand-900)}
/* All three used: the rest stop inviting a click they cannot honour. */
.availstrip.full .availday:not(.picked){opacity:.5}
.availstrip.full .availday:not(.picked):hover{border-color:var(--rule);background:var(--surface);cursor:default}


/* ============================================================
   Create by hand (plan 2026-09-09, step 7)
   Collapsed by default: the automation is the normal path and these are the
   backup, so they sit out of the way until somebody needs one.
   ============================================================ */
.newthing{margin:0 0 14px;background:var(--surface);border:1px dashed var(--rule);border-radius:10px}

/* The head is tinted so "New task", "New enquiry" and the rest read as the
   place you go to add one, rather than as another collapsed section. Found on
   2026-09-23: Kate went looking for where to add a task and the head looked
   like every other grey strip on the page. */
.newthing > .group-head{
  padding:8px 12px;font-size:.8125rem;
  background:var(--brand-50);border-radius:9px 9px 0 0;
}
.newthing:not([open]) > .group-head{border-radius:9px}
.newthing > .group-head b{color:var(--brand-700)}

/* These four were scoped to `.newthing` alone until 2026-09-23, so the form
   only laid out when it sat inside a New-something panel. The SAME macro is
   used for the inline edit of a row, which is not in one, so on /tasks the
   edit form lost the grid, the block labels and the full-width inputs, and
   rendered as one run of inline text with the help copy wrapping through the
   middle of it. `.task-form` is on the form element either way. */
/* `.stackform` joined them on 2026-09-23: /account/password was built with the
   forced first-login change the day before and never styled, so its three bare
   labels were `display:inline` and the captions and boxes ran together on one
   line. Kate, setting her own password on the call: "that looks a bit
   disformatted". It is the first screen the whole team sees. */
.newthing label,.task-form label,.stackform label{display:block;margin:0 0 8px;font-size:.78125rem;color:var(--ink-2)}
/* `display:block` above beats the browser's [hidden]; E-010 hides a field by side. */
.newthing label[hidden]{display:none}
.newthing label input,.newthing label select,.newthing label textarea,
.task-form label input,.task-form label select,.task-form label textarea,
.stackform label input,.stackform label select,.stackform label textarea{
  display:block;width:100%;margin-top:3px;
}
/* A checkbox is not a field that wants a line of its own at full width. */
.newthing label input[type=checkbox],.task-form label input[type=checkbox],
.stackform label input[type=checkbox]{
  display:inline-block;width:auto;margin-top:0;flex:none;
}
.newthing .rulegrid,.task-form .rulegrid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:8px 14px;
}
.newthing .rulegrid label.wide,.task-form .rulegrid label.wide{grid-column:1/-1}
/* The one label that is a checkbox and its sentence, not a label and a field. */
.rulegrid label.checkline{display:flex;flex-direction:row;align-items:center;gap:8px}
.newthing .assumption{margin-top:8px}

/* "More" on the task form (23 Sep). A disclosure, not a second card: the four
   fields above it are the whole of an ordinary task and this is where the
   other six went. Quiet enough that it does not read as another section, and
   the summary marker is the only thing that says it opens. */
.morefields{margin:0 0 8px}
.morefields > summary{
  cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:6px;
  font-size:.75rem;font-weight:650;color:var(--ink-2);padding:4px 0;user-select:none;
}
.morefields > summary::-webkit-details-marker{display:none}
.morefields > summary::before{content:"\203A";font-size:.9375rem;line-height:1;transition:transform .12s}
.morefields[open] > summary::before{transform:rotate(90deg)}
.morefields > summary:hover{color:var(--brand-700)}
.morefields > .rulegrid{
  margin-top:6px;padding-top:10px;border-top:1px dashed var(--rule);
}

/* "Add another line" on a draft proposal. Two alternatives, not one form with
   twice the fields it needs, so each gets its own block and the "or" between
   them does the explaining that a paragraph used to have to do. */
.addline{padding:0}
.addline-opt{padding:11px 13px 13px}
.addline-opt-head{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;margin:0 0 9px}
.addline-opt-head b{font-size:.8125rem;color:var(--brand-900)}
.addline-opt-head .muted{font-size:.75rem}
.addline-opt .btn{margin-top:9px}
.addline-opt .assumption{margin:9px 0 0}
.addline-or{
  display:flex;align-items:center;gap:11px;margin:0 13px;
  font-size:.65625rem;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);
}
.addline-or::before,.addline-or::after{content:"";flex:1;height:1px;background:var(--rule-soft)}


/* ============================================================
   The report drop zone
   ============================================================
   A real file input with a label over it: it works from the keyboard, it
   works without a pointer, and the drag handling is an addition rather than
   the only way in. The input is moved off-screen rather than display:none,
   because a hidden input is not focusable and the keyboard path would go with
   it. */
.dropform{margin-top:10px}
.dropzone{
  display:flex;flex-direction:column;gap:3px;align-items:center;justify-content:center;
  padding:22px 16px;text-align:center;cursor:pointer;
  border:1.5px dashed var(--brand-300);border-radius:var(--r);
  background:var(--brand-50);transition:background .12s ease,border-color .12s ease;
}
.dropzone:hover,.dropzone:focus-within{background:var(--brand-100);border-color:var(--brand-500)}
.dropzone.over{background:var(--brand-100);border-color:var(--brand-700);box-shadow:var(--glow-blue)}
.dropzone .drop-main{font-weight:640;color:var(--brand-700);font-size:.84375rem}
.dropzone .drop-sub{color:var(--muted);font-size:.75rem}
.dropinput{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.drop-status{margin:8px 0 0;font-size:.78125rem;color:var(--ink-2);min-height:1em}
.drop-status.bad{color:var(--bad);font-weight:640}

/* Where the issued report was filed. Always says something, including
   "not configured", because a report that never reached the client's folder
   has to be visible rather than absent. */
.filing-line{margin:6px 0 0;font-size:.78125rem}
.pill.filing-filed{background:var(--ok-soft);color:var(--ok);box-shadow:inset 0 0 0 1px rgba(76,122,28,.22)}
.pill.filing-failed{background:var(--bad-soft);color:var(--bad);box-shadow:inset 0 0 0 1px rgba(164,52,43,.24)}
.pill.filing-pending,.pill.filing-not_configured{
  background:#F4F7FC;color:var(--ink-2);box-shadow:inset 0 0 0 1px var(--rule)}

/* The draft page: the recipients, and the note she can change before it goes. */
.recipients{margin:0 0 10px;padding:10px 12px;border-radius:var(--r-sm);
  background:var(--ground);box-shadow:inset 0 0 0 1px var(--rule)}
.recipients b{display:block;font-size:.71875rem;letter-spacing:.04em;text-transform:uppercase;
  color:var(--muted);margin-bottom:3px}
.recipients .who{font-size:.84375rem;color:var(--ink)}
.recipients.substituted{background:var(--warn-soft);box-shadow:inset 0 0 0 1px rgba(150,89,15,.28)}


/* The state list at the top of a job: one line per fact, generous enough to
   scan without reading. This is the thing somebody came to the page to find
   out, so it does not look like a form. */
.statelist li{
  display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;
  padding:7px 0;border-bottom:1px solid var(--rule-soft);
}
.statelist li:last-child{border-bottom:0}
.statelist .muted{font-size:.78125rem}

/* "Where this job stands", 21 Sep: one labelled row per question. The label
   column is the same small caps as .detail-kv; the value carries the pill and
   its sentence; an action, when there is one, sits at the right on the row it
   belongs to. */
.standing{margin-top:6px}
.standing-row{
  display:grid;grid-template-columns:96px 1fr auto;gap:6px 16px;align-items:baseline;
  padding:9px 0;border-bottom:1px solid var(--rule-soft);
}
.standing-row:last-child{border-bottom:0}
.standing-row>b{
  font-size:.65625rem;text-transform:uppercase;letter-spacing:.1em;
  color:var(--muted);font-weight:700;padding-top:3px;
}
.standing-val{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;min-width:0}
.standing-val .muted{font-size:.78125rem}
.standing-list{flex-direction:column;align-items:flex-start;gap:6px}
.standing-list>div{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.standing-act{justify-self:end}
@media (max-width:600px){
  .standing-row{grid-template-columns:1fr;gap:4px}
  .standing-act{justify-self:start}
}

/* An edit that is available but not offered. Used where a value is already
   recorded: the fact reads as a fact, and the box to change it is one click
   away rather than sitting there looking unsaved. */
.quiet-edit > summary{
  cursor:pointer;color:var(--accent);font-size:.78125rem;font-weight:600;
  list-style:none;display:inline-block;padding:2px 0;
}
.quiet-edit > summary::-webkit-details-marker{display:none}
.quiet-edit > summary::before{content:"✎ ";opacity:.7}
.quiet-edit > summary:hover{text-decoration:underline}

/* ---------------------------------------------------------- the invoice page
   The lines are editable in place, so each row is its own form. `display:
   contents` lets that form sit inside a <tr> without breaking the table
   layout, which is the one thing that makes an editable table honest: the
   figures line up with the ones above and below them. */
.contents{display:contents}

/* The logo, top right of the canvas. In flow rather than absolute so it can
   never land on a page title, and pulled up by its own height plus the page
   padding so it does not push every page down a row. Hidden under 900px, where
   the canvas is too narrow to give it a line of its own. */
.topbrand{display:flex;justify-content:flex-end;margin:0 0 -6px;pointer-events:none}
.topbrand img{height:30px;width:auto;opacity:.92}
@media(max-width:900px){.topbrand{display:none}}
.cell{width:100%;padding:5px 7px;border:1px solid var(--line);border-radius:5px;
  font:inherit;font-size:.8125rem;background:var(--bg);color:inherit}
.cell.num{text-align:right}
.cell:focus{outline:2px solid var(--accent);outline-offset:-1px}
.rowacts{white-space:nowrap;text-align:right}
.inline-form{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:8px}
.inline-form .cell{width:auto;flex:1 1 240px}
.inline-form .cell.num{flex:0 0 auto}
.factlist{display:grid;grid-template-columns:auto 1fr;gap:6px 14px;margin:0;font-size:.8125rem}
.factlist dt{color:var(--muted);white-space:nowrap}
.factlist dd{margin:0}


/* ------------------------------------------------------------------
   Keyboard focus. Ten rules across this sheet set `outline:none` and
   replace it with a 16%-alpha glow, which is easy to miss. Those rules
   are more specific than a bare :focus-visible, so this override is
   deliberate: it applies to keyboard focus only and leaves the softer
   mouse-focus treatment alone.
   ------------------------------------------------------------------ */
:focus-visible{
  outline:2px solid var(--brand-700) !important;
  outline-offset:1px;
}

/* ------------------------------------------------------------------
   The invoice page
   ------------------------------------------------------------------ */

/* Fixed column widths for the editable lines table. The figures are the point
   of this page, so Amount is guaranteed its space and Description takes what
   is left. */
table.lines{table-layout:fixed}
table.lines .c-qty{width:56px}
table.lines .c-rate{width:104px}
table.lines .c-amt{width:104px}
/* Wide enough for the widest button that lands in it ("Remove"), which used to
   overflow its cell and sit behind the scrollbar. */
table.lines .c-act{width:96px}
table.lines th,table.lines td{padding:9px 8px}
table.lines .cell{min-width:0;padding:5px 6px}
table.lines tfoot td{border-bottom:none;padding-top:10px}
table.lines tfoot tr:first-child td{border-top:1px solid var(--rule)}

/* The add forms, behind one disclosure rather than permanently on screen. */
.addrow-wrap{margin-top:12px}
.addrow-wrap>summary{
  cursor:pointer;display:inline-flex;align-items:center;gap:6px;
  font-size:.78125rem;font-weight:600;color:var(--brand-700);
  list-style:none;padding:4px 0;
}
.addrow-wrap>summary::-webkit-details-marker{display:none}
.addrow-wrap>summary::before{content:"+";font-weight:700;line-height:1}
.addrow-wrap[open]>summary::before{content:"–"}
.addrow-wrap>summary:hover{text-decoration:underline;text-underline-offset:2px}

/* The decision block, in the right-hand column under the facts. This is where
   Approve goes when it is built. */
.decision{
  margin-top:16px;padding-top:14px;border-top:1px solid var(--rule);
}
.decision h3{
  margin:0 0 6px;font-size:.8125rem;font-weight:700;color:var(--brand-900);
}
.decision p{margin:0 0 6px;font-size:.8125rem;color:var(--ink-2)}
.decision p:last-child{margin-bottom:0}
/* Itemised or summary on a draft invoice (E-011): one choice per line. */
.detail-level .checkline{display:flex;align-items:flex-start;margin:3px 0}
.detail-level .checkline input{margin-top:3px;flex:none}

/* ------------------------------------------------------------------
   The boards: Ops Board and Systems Tasks
   ------------------------------------------------------------------ */

/* (The fixed-layout declaration for these tables was repeated here until
   2026-09-23. One copy now, kept beside the comment that explains it.) */
.c-due{width:80px}  /* 74px until E-017; "05 Aug" wrapped one step up */
.c-assign{width:158px}
.c-money{width:92px}
.c-act{width:220px}

/* The job cell carries the name, then what used to be three more columns. */
.col-job{min-width:0}
.col-job .job-name{font-weight:600;display:inline-block;max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}
.col-job .job-meta{
  display:block;font-size:.75rem;color:var(--ink-2);margin-top:2px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.col-job .job-meta a{color:var(--ink-2)}
.col-job .job-meta a:hover{color:var(--brand-700)}
.col-assign{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* A row the board wants something doing to. The bar carries the signal, so the
   text beside the action can stay plain instead of becoming a fifth pill. */
tbody tr.rowflag td:first-child{box-shadow:inset 3px 0 0 var(--warn)}
.flagtext{color:var(--warn);font-weight:600;font-size:.75rem;display:block;margin-bottom:4px}
.col-act{white-space:normal}
.col-act .btn{margin-top:2px}

/* Group heading: a plain title and a plain count. */
.group-title{
  margin:0;font-size:.875rem;font-weight:700;color:var(--brand-900);
  display:inline-block;
}
.c-client{width:210px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.c-enq{width:300px}
.c-enq .enq-ask{display:block;max-height:2.8em;overflow:hidden}

/* The escalation preview sits in a narrow card, and long service names pushed
   the "After" column out of sight, which is the one column the preview exists
   to show. */
table.inner{table-layout:fixed}
/* Any table that declares a colgroup means it, so honour it. Auto layout
   ignores the widths and sizes to content, which is how the boards ended up
   wider than the page they sit on. */
table:has(> colgroup){table-layout:fixed}
table.inner th:first-child,table.inner td:first-child{
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* 82px was scoped to every `table.inner` until 2026-09-23, which meant it also
   applied to Rates, whose .num cells hold editable 110px boxes: they overflowed
   an 82px fixed column and landed on each other. The rule was only ever about
   the escalation preview, which is what its neighbour's comment says, so it now
   names it. Every other .num column is sized by its table's colgroup. */
.preview-table th.num,.preview-table td.num{width:82px}

/* The job page leads with the answer, so the answer gets the wider column. */
.quotegrid.answer-first{grid-template-columns:minmax(0,1.35fr) minmax(300px,1fr)}
@media(max-width:1000px){.quotegrid.answer-first{grid-template-columns:1fr}}

/* Anything that leaves the building. Tier 2, never tier 1, and never the same
   as a control that only writes a field. */
.btn-send{border-color:var(--brand-300);color:var(--brand-700);background:linear-gradient(180deg,#FFFFFF,var(--brand-50))}
.btn-send:hover{border-color:var(--brand-500);background:var(--brand-50)}
.send-glyph{font-weight:700;margin-right:2px}
.sendline{margin:8px 0 0}

/* The quiet disclosure used for hand-correction benches. */
.quiet-edit>summary{
  cursor:pointer;font-size:.78125rem;font-weight:600;color:var(--ink-2);
  list-style:none;padding:4px 0;
}
.quiet-edit>summary::-webkit-details-marker{display:none}
.quiet-edit>summary::before{content:"▸ ";color:var(--muted)}
.quiet-edit[open]>summary::before{content:"▾ "}
.quiet-edit>summary:hover{color:var(--brand-700)}

/* Invoicing Review */
.c-xero{width:130px}
.c-why{width:220px}
.c-po{width:130px}
/* Covers was sharing the boards' 74px date column, so "September 2026, 3 visits"
   wrapped a word a line and made every row tall (Nathan, 28 Sep). */
.c-covers{width:200px}
.section-n{
  font-size:.6875rem;font-weight:700;color:var(--ink-2);background:var(--ground-2);
  border-radius:var(--r-pill,999px);padding:2px 8px;letter-spacing:0;
}
.c-why b{font-weight:600;font-size:.8125rem;color:var(--ink)}
.c-why .job-meta{margin-top:1px}
.c-valid{white-space:nowrap}
.statusselect{max-width:120px}
.c-propno{width:132px}
.c-date{width:112px;white-space:nowrap}
.c-validcol{width:168px;white-space:nowrap}
.c-doccol{width:92px}
.c-statuscol{width:140px}
/* The quiet tier still has to read as pressable, so the underline is a mid grey
   rather than the near-white rule colour. */
.btn-quiet{text-decoration-color:var(--muted)}
/* A card head that is also a disclosure summary. */
.cardsummary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:10px}
.cardsummary::-webkit-details-marker{display:none}
.cardsummary::after{content:"▸";color:var(--muted);font-size:.75rem;margin-left:auto}
details[open]>.cardsummary::after{content:"▾"}


/* The invoice page: the lines table is the page, so it gets the room. The stock
   .quotegrid split gives the right-hand column more, which left the editable
   lines in 469px and put the Remove buttons behind a horizontal scrollbar. */
.quotegrid.lines-left{grid-template-columns:minmax(0,1.9fr) minmax(280px,1fr)}
@media(max-width:1100px){.quotegrid.lines-left{grid-template-columns:1fr}}

/* ---- Visits on the job page (2026-09-12 recurring-visits plan, C7) ----
   The booked run as a small table in the card's style, and the proposal
   table under it with an editable date and person per row. */
.visits{width:100%;border-collapse:collapse;font-size:.8125rem;margin-top:4px}
.visits th,.visits td{padding:6px 8px;text-align:left;border-bottom:1px solid var(--rule);vertical-align:middle}
.visits th{font-size:.71875rem;color:var(--ink-2);font-weight:600}
.visits tr.past{opacity:.6}
.visits .warn{color:#B42318}
.visits input[type=date],.visits select{font-size:.78125rem}
.visit-form .detail-kv select{max-width:100%}
.visit-form .detail-kv select+select{margin-top:6px}
/* The sites on one Hazard ID visit (C8, Release 2b): four inputs and a cross
   per row, one grid line each, wrapping to stacked inputs on a phone. */
.visit-sites{display:grid;gap:6px;margin-top:6px}
.visit-sites-head,.visit-site-row{display:grid;grid-template-columns:1.3fr 2fr 1.2fr 1.4fr 32px;gap:6px;align-items:center}
.visit-sites-head span{font-size:.71875rem;color:var(--ink-2);font-weight:600}
.visit-site-row input{width:100%;min-width:0;font-size:.8125rem}
.visit-site-row .btn-remove{padding:2px 0;line-height:1.3}
@media (max-width:720px){
  .visit-sites-head{display:none}
  .visit-site-row{grid-template-columns:1fr 32px}
  .visit-site-row input{grid-column:1}
  .visit-site-row .btn-remove{grid-column:2;grid-row:1}
}

/* ============================================================
   My schedule as cards, and the phone cut
   (2026-09-16, plan explore-2026-09-16-elliott-mobile-auditor-view)
   The auditor's landing page is read on a phone in a car park. One
   column, today large, everything tappable at a thumb's size. The same
   rules give the office a usable app on a phone without a second
   layout: 44 px targets, the drawer as a bottom sheet, the feedback
   pill shrunk to a dot so it stops covering the cards.
   ============================================================ */
.page.mine{max-width:900px}
/* Phone and desk from one page (27 Sep, redesigned the same day). Every
   section is placed by a named grid area. Below 1180px the two column
   wrappers step aside (display:contents) and the areas stack in one column,
   today first; from 1180px the week runs the full width and the wrappers
   become a main column and a side column. The page head steps aside too, so
   its title and the receipt button share the top row. */
.ms-layout{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:14px;align-items:start;
  grid-template-areas:"title act" "sub sub" "today today" "week week" "issue issue" "later later" "past past"}
.ms-main,.ms-side,.ms-head{display:contents}
.ms-head h1{grid-area:title;margin:0;align-self:center}
.ms-head .page-sub{grid-area:sub;margin:4px 0 0}
.ms-receipt{grid-area:act;justify-self:end;align-self:center}
.ms-today{grid-area:today}.ms-week{grid-area:week}.ms-issue{grid-area:issue}
.ms-later{grid-area:later}.ms-past{grid-area:past}
.ms-sec{min-width:0}
.mine .ms-receipt .btn{min-height:44px;display:inline-flex;align-items:center;padding:8px 18px;font-size:.875rem}
.mine .section-h .sh-note{font-weight:500;letter-spacing:0;text-transform:none;color:var(--muted);font-size:.78125rem}
.ms-week{margin-top:20px}

/* Reports to issue: one quiet list, oldest first. The buttons are outlined,
   not filled: eight filled buttons in a column outshout the one primary
   action on the page and stop the eye reading the names. */
.ti-count{display:inline-block;min-width:22px;padding:1px 7px;border-radius:999px;background:var(--leaf-100);
  color:var(--leaf-700);font-size:.71875rem;letter-spacing:0;text-align:center;box-shadow:inset 0 0 0 1px var(--leaf-200)}
.ti-box{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-lg);box-shadow:var(--shadow-xs);
  padding:2px 14px 4px;position:relative}
.ti-list{list-style:none;margin:0;padding:0}
.ti{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:11px 0;border-top:1px solid var(--rule-soft)}
.ti:first-child{border-top:0}
.ti-what{display:flex;flex-direction:column;min-width:0;line-height:1.35}
.ti-date{font-size:.75rem;color:var(--ink-2)}
.ti-age{color:var(--muted);margin-left:4px}
.ti-age.is-old{color:var(--warn);font-weight:600}
.ti-client{font-size:.875rem;font-weight:650;color:var(--ink);overflow-wrap:anywhere}
.ti-site{font-size:.78125rem;color:var(--muted);overflow-wrap:anywhere}
.ti-go{flex:0 0 auto}
.ti-all{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none}
.ti-list.is-long .ti:nth-child(n+4){display:none}
.ti-all:checked + .ti-list .ti{display:flex}
.ti-more{display:flex;align-items:center;justify-content:center;min-height:44px;border-top:1px solid var(--rule-soft);
  color:var(--brand-700);font-weight:640;font-size:.84375rem;cursor:pointer}
.ti-more-open,.ti-all:checked ~ .ti-more .ti-more-closed{display:none}
.ti-all:checked ~ .ti-more .ti-more-open{display:inline}
.ti-all:focus-visible ~ .ti-more{outline:2px solid var(--brand-500);outline-offset:-2px;border-radius:var(--r-sm)}

/* From tablet width the Elliott logo sits top right, so the button drops to
   line up with the subtitle rather than sit on top of it. */
@media (min-width:701px){
  .ms-layout{grid-template-areas:"title act" "sub act" "today today" "week week" "issue issue" "later later" "past past"}
  .ms-head h1{align-self:end}
  .ms-receipt{align-self:end}
}
@media (min-width:1180px){
  .page.mine{max-width:1480px}
  .ms-layout{grid-template-columns:minmax(0,1fr) 360px;column-gap:28px;
    grid-template-areas:"title act" "sub act" "week week" "main side"}
  .ms-layout[data-side="off"]{grid-template-areas:"title act" "sub act" "week week" "main main"}
  .ms-main{display:block;grid-area:main;min-width:0}
  .ms-side{display:block;grid-area:side;min-width:0}
  .ms-week{margin-top:22px}
  .ms-main > .ms-sec:first-child .section-h,.ms-side > .ms-sec:first-child .section-h{margin-top:26px}
  /* The whole list shows at a desk; there is room, and a hidden row is one
     more thing to remember to go looking for. */
  .ti-list.is-long .ti:nth-child(n+4){display:flex}
  .ti-more{display:none}
}
.mine .top-actions{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 18px}
.mine .top-actions .btn{min-height:44px;display:inline-flex;align-items:center;padding:8px 18px;font-size:.875rem}
.jc-list{display:flex;flex-direction:column;gap:10px;margin:0 0 6px}
.jc{
  background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-lg);
  box-shadow:var(--shadow);padding:14px 16px;cursor:pointer;display:grid;gap:3px;
  transition:border-color .14s ease,box-shadow .14s ease;
}
.jc:hover,.jc:focus-visible{border-color:var(--brand-300);box-shadow:var(--shadow),var(--glow-blue)}
.jc.big{padding:18px 18px 16px;border-color:var(--brand-200);box-shadow:var(--shadow-md),0 0 0 1px rgba(34,79,143,.08)}
.jc-when{
  display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  font-size:.71875rem;color:var(--muted);text-transform:uppercase;letter-spacing:.09em;font-weight:700;
}
.jc-time{color:var(--brand-700);font-size:.9375rem;letter-spacing:0;text-transform:none;font-variant-numeric:tabular-nums}
.jc.big .jc-day{color:var(--leaf-700)}
.jc.big .jc-time{font-size:1.5rem;font-weight:720;line-height:1}
.jc-client{font-size:1.0625rem;margin:3px 0 0;color:var(--brand-900);line-height:1.25;font-weight:680;overflow-wrap:anywhere}
.jc.big .jc-client{font-size:1.4375rem}
.jc-site{color:var(--ink-2);font-size:.875rem;overflow-wrap:anywhere}
.jc-type{font-size:.78125rem;color:var(--muted)}
.jc-addr{font-size:.875rem;color:var(--ink);margin-top:5px;overflow-wrap:anywhere}
.jc-sites{margin:7px 0 0;padding:0;list-style:none;display:grid;gap:7px}
.jc-sites li{padding-left:24px;position:relative;font-size:.875rem;line-height:1.4;overflow-wrap:anywhere}
.jc-sites li::before{
  content:attr(data-n);position:absolute;left:0;top:2px;width:17px;height:17px;border-radius:50%;
  background:var(--brand-100);color:var(--brand-800);font-size:.65625rem;font-weight:700;text-align:center;line-height:17px;
}
.jc-sites small{display:block;color:var(--muted);font-size:.78125rem}
.jc-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.jc-actions .btn{min-height:44px;display:inline-flex;align-items:center;justify-content:center;padding:8px 16px;font-size:.875rem;flex:1 1 auto}
.jc.blocked{background:var(--ground-2);box-shadow:none;cursor:default;grid-template-columns:auto 1fr;align-items:center;gap:10px;padding:11px 14px;font-size:.875rem}
.jc.blocked:hover{border-color:var(--rule)}
.jc-empty{color:var(--muted);font-size:.875rem;padding:4px 2px;margin:0}
.jc-more{margin:12px 0 0}
.jc-more .btn{min-height:44px;display:inline-flex;align-items:center;padding:8px 18px;font-size:.875rem}
.mine details.past{margin-top:6px}
.mine details.past summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:10px;min-height:44px}
.mine details.past summary::-webkit-details-marker{display:none}
.mine details.past summary::after{content:"Show";font-size:.78125rem;font-weight:650;color:var(--brand-700);white-space:nowrap}
.mine details.past[open] summary::after{content:"Hide"}
.mine details.past .jc-list{margin-top:12px}

/* thumbs, not cursors */
@media(max-width:820px){
  .btn{min-height:40px;display:inline-flex;align-items:center;padding:8px 14px;font-size:.84375rem}
  .btn.small{min-height:36px;padding:6px 12px;font-size:.78125rem}
  .sidenav a{padding:10px 12px;font-size:.875rem;min-height:40px;display:flex;align-items:center}
  .userbox a{padding:10px 8px}
  .page.mine{padding:16px 14px 34px}
  .mine .page-head{margin-bottom:14px}
  .mine .page-sub{font-size:.84375rem}
  .mine .section-h{margin:22px 0 10px}
  .jc{padding:13px 14px}
  .jc.big{padding:16px 16px 14px}
  .fb-trigger{width:46px;height:46px;border-radius:50%;padding:0;justify-content:center;gap:0}
  .fb-trigger .fb-label{display:none}
  .fb-trigger .ni{font-size:1.125rem}
}

/* the drawer as a bottom sheet */
@media(max-width:700px){
  body.drawer-open{overflow:hidden}
  body.drawer-open::before{content:"";position:fixed;inset:0;background:rgba(16,44,82,.38);z-index:19}
  .drawer{
    top:auto;bottom:0;left:0;right:0;width:100%;max-width:100%;max-height:88vh;
    border-left:0;border-top:1px solid var(--rule);border-radius:18px 18px 0 0;
    padding:10px 18px calc(20px + env(safe-area-inset-bottom));
    box-shadow:0 -14px 40px -20px rgba(16,44,82,.6);
  }
  .drawer::before{content:"";display:block;width:40px;height:4px;border-radius:2px;background:var(--rule);margin:0 auto 12px}
  .drawer-head h2{font-size:1.1875rem}
  .drawer-kv{font-size:.875rem;gap:9px 14px}
  .drawer-kv .btn.small{min-height:40px;padding:8px 14px;font-size:.84375rem}
  .drawer-x{font-size:1.625rem;padding:6px 10px;min-width:44px;min-height:44px}
}

/* the office pages on a phone: the filter groups scroll inside their own row
   rather than pushing the page wide, and the month grid scrolls inside
   .schedwrap instead of squashing thirty columns into a phone width */
@media(max-width:820px){
  .filterbar{column-gap:14px}
  .filterrow{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:2px}
  .filterrow .tabs,.filterrow .filterlabel{flex:none}
  .filtersearch{flex:1 1 100%;margin-left:0;justify-content:flex-start}
  .filtersearch input[type="search"]{min-width:0;max-width:none}
  .sched.month{min-width:900px}
}


/* ============================================================
   The receipt form (2026-09-16): one set of rules for the public token
   page (receipt_public.html) and the signed-in page (receipt_mine.html),
   both wrapping the shared partial in .rcpt. Moved here from the public
   page's own <style> block when the second page arrived.
   ============================================================ */
  .rcpt h1{font-size:1.4375rem;margin:0 0 6px;letter-spacing:-.02em;}
  .rcpt .lede{color:var(--ink-2);margin:0 0 20px;line-height:1.55;}
  .rcpt .card{background:var(--surface);border:1px solid var(--rule);border-radius:13px;
    padding:20px;margin-bottom:15px;}
  .rcpt h2{font-size:.875rem;margin:0 0 4px;letter-spacing:-.01em;}
  .rcpt .hint{font-size:.8125rem;color:var(--muted);margin:0 0 13px;line-height:1.5;}
  .opt{display:flex;align-items:center;gap:12px;border:1.5px solid var(--rule);
    border-radius:10px;padding:13px 15px;margin-bottom:9px;cursor:pointer;
    transition:border-color .12s,background .12s;}
  .opt:hover{border-color:var(--brand-300);}
  .opt input{width:19px;height:19px;flex:none;accent-color:var(--brand-700);}
  .opt.on{border-color:var(--brand-700);background:var(--brand-50);}
  .opt b{font-size:.9375rem;display:block;}
  .opt small{color:var(--muted);font-size:.78125rem;}
  .rcpt textarea,.rcpt input[type=text],.rcpt input[type=number]{width:100%;font:inherit;
    padding:10px 12px;border:1px solid var(--rule);border-radius:9px;background:#fff;color:var(--ink);}
  .rcpt input[type=number]{font-size:1.0625rem;}
  .rcpt textarea:focus,.rcpt input:focus{outline:2px solid var(--brand-300);outline-offset:1px;}
  .field{margin-bottom:14px;}
  .field label{display:block;font-weight:600;font-size:.84375rem;margin-bottom:3px;}
  .field .sub{font-size:.78125rem;color:var(--muted);margin:0 0 7px;line-height:1.45;}
  .rcpt .go{width:100%;padding:14px;font-size:.9375rem;font-weight:600;border:0;border-radius:10px;
    background:var(--brand-700);color:#fff;cursor:pointer;}
  .rcpt .go:hover{background:var(--brand-800);}
  .rcpt .go[disabled]{opacity:.55;cursor:default;}
  .rcpt .err{background:#FDECEC;border:1px solid #F5C2C2;color:#8A2020;padding:12px 14px;
    border-radius:10px;margin-bottom:15px;font-size:.84375rem;}
  .rcpt .foot{text-align:center;color:var(--muted);font-size:.75rem;margin-top:22px;line-height:1.6;}
  .done-tick{width:46px;height:46px;border-radius:50%;background:var(--leaf-100);
    color:var(--leaf-700);display:flex;align-items:center;justify-content:center;
    font-size:1.5rem;margin:0 auto 14px;}
  /* The camera. Big, because it is the first thing a thumb goes for. */
  .shot{display:block;width:100%;border:1.5px dashed var(--rule);border-radius:11px;
    padding:22px 16px;text-align:center;cursor:pointer;background:#fff;
    font:inherit;color:var(--ink);}
  .shot:hover{border-color:var(--brand-300);}
  .shot b{display:block;font-size:.9375rem;margin-bottom:2px;}
  .shot small{color:var(--muted);font-size:.78125rem;}
  .shot.has{border-style:solid;border-color:var(--leaf-700);background:var(--leaf-100);}
  .shot input{display:none;}
  .say{font-size:.8125rem;margin:9px 0 0;color:var(--muted);min-height:18px;}
  .say.bad{color:#8A2020;}
  .amt{display:flex;align-items:center;gap:8px;}
  .amt .sign{font-size:1.1875rem;color:var(--muted);}
  .seen{border-top:1px solid var(--rule);margin-top:14px;padding-top:12px;}
  .seen li{font-size:.8125rem;color:var(--ink-2);margin-bottom:4px;list-style:none;}
  .seen ul{margin:0;padding:0;}
  .who{font-size:.78125rem;color:var(--muted);}
.rcpt .card{margin-bottom:15px}

/* ---------------------------------------------------------------- week strip
   /my-schedule, 27 Sep (redesigned the same day): the auditor's week at a
   glance. A calendar on a laptop: weekday and date number at the head of
   each column, today's number in a blue disc, days gone greyed, a blocked
   day hatched with its pill, and an empty day left empty rather than saying
   "Free" five times. Under 700px each day is a row, date on the left,
   because five 70px columns on a phone cut every client name to nothing. */
.wk{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-lg);box-shadow:var(--shadow-xs);
  padding:14px 16px 6px;margin:0 0 4px}
.wk-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.wk-title{font-size:1rem;margin:0;color:var(--brand-900);font-weight:680;flex:1 1 auto;min-width:0;
  display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 10px}
.wk-range{font-size:.8125rem;font-weight:500;color:var(--ink-2);letter-spacing:0}
.wk-count{font-size:.71875rem;font-weight:640;color:var(--brand-700);background:var(--brand-50);
  padding:1px 8px;border-radius:999px;box-shadow:inset 0 0 0 1px var(--brand-100);letter-spacing:0}
.wk-navs{display:flex;align-items:center;gap:6px;margin-left:auto}
.wk-count.is-none{color:var(--muted);background:var(--ground);box-shadow:inset 0 0 0 1px var(--rule)}
.wk-nav{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;
  font-size:1.25rem;line-height:1}
.wk-nav.is-off{opacity:.35;pointer-events:none;box-shadow:none}
.wk-back{display:inline-flex;align-items:center;height:36px;padding:0 12px}
.wk-grid{display:grid;grid-template-columns:repeat(var(--wk-n,5),minmax(0,1fr));border-top:1px solid var(--rule)}
.wk-day{display:flex;flex-direction:column;gap:8px;padding:10px 8px 12px;min-width:0;min-height:124px;
  border-left:1px solid var(--rule-soft)}
.wk-day:first-child{border-left:0}
.wk-date{display:flex;align-items:baseline;gap:6px;line-height:1.1;padding:0 2px}
.wk-dow{font-size:.6875rem;text-transform:uppercase;letter-spacing:.09em;font-weight:700;color:var(--muted)}
.wk-dnum{font-size:1.25rem;font-weight:650;color:var(--ink);font-variant-numeric:tabular-nums}
.wk-mon{font-size:.71875rem;color:var(--muted)}
.wk-day.is-today{background:var(--brand-50)}
.wk-day.is-today .wk-dow{color:var(--brand-700)}
.wk-day.is-today .wk-dnum{display:inline-flex;align-items:center;justify-content:center;min-width:30px;height:30px;
  padding:0 6px;border-radius:999px;background:var(--brand-700);color:var(--surface);font-size:1.0625rem}
.wk-day.is-past .wk-dnum,.wk-day.is-past .wk-dow{color:var(--muted);font-weight:500}
.wk-day.is-past .wk-audit{opacity:.62}
.wk-day.is-blocked{background:repeating-linear-gradient(135deg,var(--ground) 0 7px,var(--surface) 7px 14px)}
.wk-items{display:flex;flex-direction:column;gap:6px;min-width:0}
.wk-audit{all:unset;box-sizing:border-box;cursor:pointer;display:flex;flex-direction:column;gap:2px;
  padding:8px 9px;border-radius:var(--r-sm);background:var(--brand-50);border-left:4px solid var(--tone,var(--brand-600));
  font-size:.78125rem;line-height:1.3;min-width:0;transition:background .14s ease,box-shadow .14s ease}
.wk-day.is-today .wk-audit{background:var(--surface)}
.wk-audit:hover{background:var(--brand-100)}
.wk-audit:focus-visible{box-shadow:var(--glow-blue);background:var(--brand-100)}
/* The client's colour on My schedule (2026-09-28): the same slot as the
   grid, as a left edge, because a phone list reads better on white. */
.jc.toned{border-left:5px solid var(--tone)}
.vr.toned{box-shadow:inset 4px 0 0 var(--tone)}
.wk-time{font-weight:700;color:var(--brand-700);font-size:.75rem;font-variant-numeric:tabular-nums}
.wk-client{font-weight:650;color:var(--brand-900);font-size:.8125rem;overflow-wrap:anywhere;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.wk-site{color:var(--ink-2);font-size:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wk-type{color:var(--muted);font-size:.71875rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wk-block{display:flex;flex-direction:column;align-items:flex-start;gap:4px;min-width:0}
.wk-note{font-size:.75rem;color:var(--ink-2);overflow-wrap:anywhere}
.wk-free{display:none}

/* ---------------------------------------------------------------- visit rows
   Coming up and Past on /my-schedule, and the whole of /my-schedule/past:
   one white list with hairlines between rows instead of a stack of shadowed
   cards, so ten visits read as a log in date order. The date block matches
   the calendar's, so the two read as one system. */
.vr-list{background:var(--surface);border:1px solid var(--rule);border-radius:var(--r-lg);box-shadow:var(--shadow-xs);
  overflow:hidden;margin:0 0 6px}
.vr{display:flex;align-items:center;gap:8px 10px;border-top:1px solid var(--rule-soft);padding-right:12px;
  transition:background .12s ease}
.vr:first-child,.vr-month + .vr{border-top:0}
.vr:not(.blocked):hover{background:var(--ground)}
.vr-main{all:unset;box-sizing:border-box;flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:14px;
  padding:10px 4px 10px 12px;cursor:pointer}
.vr.blocked .vr-main{cursor:default}
.vr-main:focus-visible{box-shadow:inset 0 0 0 2px var(--brand-500);border-radius:var(--r-sm)}
.vr-date{flex:0 0 42px;display:flex;flex-direction:column;align-items:center;line-height:1.1;text-align:center}
.vr-dow{font-size:.65625rem;text-transform:uppercase;letter-spacing:.09em;font-weight:700;color:var(--muted)}
.vr-dnum{font-size:1.1875rem;font-weight:650;color:var(--ink);font-variant-numeric:tabular-nums}
.vr-mon{font-size:.65625rem;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}
.vr-text{display:flex;flex-direction:column;min-width:0;gap:1px;line-height:1.35}
.vr-client{font-weight:650;color:var(--brand-900);font-size:.90625rem;overflow-wrap:anywhere}
.vr-site{font-size:.8125rem;color:var(--ink-2);overflow-wrap:anywhere}
.vr-meta{font-size:.75rem;color:var(--muted)}
.vr-meta b{color:var(--brand-700);font-weight:650}
.vr-note{font-size:.8125rem;color:var(--ink-2);margin-left:4px}
.vr.is-past .vr-client{color:var(--ink)}
.vr.is-past .vr-dnum{color:var(--ink-2)}
.vr.blocked{background:var(--ground)}
.vr-actions{display:flex;gap:6px;flex:0 0 auto}
.vr-actions .btn{box-shadow:none;background:var(--surface)}
.vr-month{padding:14px 14px 6px;font-size:.71875rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;
  color:var(--brand-700);background:var(--ground);border-top:1px solid var(--rule)}
.vr-month:first-child{border-top:0}
.ms-pastall{max-width:900px}

@media (max-width:700px){
  .wk{padding:12px 12px 4px}
  .wk-grid{grid-template-columns:1fr}
  .wk-day{flex-direction:row;align-items:center;gap:12px;min-height:48px;padding:7px 4px;
    border-left:0;border-top:1px solid var(--rule-soft)}
  .wk-day:first-child{border-top:0}
  .wk-date{flex:0 0 42px;flex-direction:column;align-items:center;gap:1px;padding:0}
  .wk-mon{display:none}
  .wk-day.is-today{border-radius:var(--r-sm)}
  .wk-day.is-today .wk-dnum{min-width:28px;height:28px;font-size:.9375rem}
  .wk-items{flex:1 1 auto}
  .wk-audit{font-size:.8125rem;padding:9px 10px}
  .wk-client{font-size:.875rem}
  .wk-free{display:block;font-size:.8125rem;color:var(--muted)}
  .wk-block{flex-direction:row;align-items:center;flex-wrap:wrap;gap:4px 8px}
  .wk-nav,.wk-back{height:44px}
  .wk-nav{width:44px}
  /* A row's actions drop under its text, lined up with the name, as quiet
     buttons: a thumb-sized target without the weight of a filled block. */
  .vr{flex-wrap:wrap;padding-right:0}
  .vr-actions{flex:1 1 100%;padding:0 12px 10px 68px;margin-top:-4px}
  .vr-actions .btn{min-height:40px;flex:1 1 0;justify-content:center;font-size:.8125rem;
    background:var(--brand-50);border-color:transparent}
  .vr-main{padding:11px 12px}
}

/* ------------------------------------------------ phone top bar (27 Sep)
   On a phone the bar held the name, the menu, Password and Log out in one row,
   so the menu was squeezed into a scroll strip ("My sched") with a visible
   scrollbar, and the floating feedback pill sat over the right-hand buttons.
   Feedback moves into the bar; under 560px the name gives way to the mark. */
.fb-top{display:none}
@media(max-width:820px){
  .fb-trigger{display:none}
  .fb-top{display:inline-flex;align-items:center;justify-content:center;flex:none;
    width:32px;height:32px;margin-right:4px;padding:0;border-radius:8px;cursor:pointer;
    border:1px solid rgba(255,255,255,.28);background:rgba(255,255,255,.08);
    color:var(--leaf-500);font:inherit;font-size:.9375rem;line-height:1}
  .fb-top:hover,.fb-top:focus-visible{background:rgba(255,255,255,.18);outline:none}
  .userbox{display:flex;align-items:center;gap:10px}
  .sidenav{scrollbar-width:none}
  .sidenav::-webkit-scrollbar{display:none}
}
@media(max-width:560px){
  .brand-text{display:none}
  .brand{padding-right:2px}
  .sidebar{gap:8px;padding:10px 12px}
  .userbox{gap:9px;font-size:.78125rem}
}
/* The week arrows jump to #wk; on a phone the sticky bar would cover the
   calendar's own heading and arrows after the jump. */
@media(max-width:820px){ #wk{scroll-margin-top:72px} }

/* ------------------------------------------------ the help assistant (28 Sep)
   Two doors, side by side: "Need a hand?" for questions, "Something not
   right?" for things that went wrong. One fixed group so neither covers the
   other; the feedback pill keeps its own look inside it. On a phone both
   doors live in the top bar as a pair of bordered squares, the ? left of the
   flag. The drawer is the schedule's drawer (and its bottom sheet), holding
   a conversation instead of a record. */
.doors{position:fixed;right:24px;bottom:18px;z-index:60;display:flex;gap:8px;align-items:center}
.doors .fb-trigger{position:static}
.help-trigger{
  display:inline-flex;align-items:center;gap:8px;
  padding:9px 14px 9px 12px;border:1px solid var(--brand-100);border-radius:999px;
  background:var(--surface);color:var(--brand-900);
  font:inherit;font-size:.8125rem;font-weight:600;cursor:pointer;white-space:nowrap;
  box-shadow:var(--shadow-lg);
  transition:transform .14s ease,box-shadow .14s ease,background .14s ease;
}
.help-trigger:hover{background:var(--brand-50);transform:translateY(-1px)}
.help-trigger:focus-visible{outline:2px solid var(--brand-500);outline-offset:2px}
.help-trigger .ni{width:16px;text-align:center;font-size:.8125rem;font-weight:800;color:var(--brand-500);flex:none}
.help-top{display:none}
@media(max-width:820px){
  .help-trigger{display:none}
  .help-top{display:inline-flex;align-items:center;justify-content:center;flex:none;
    width:32px;height:32px;margin-right:0;padding:0;border-radius:8px;cursor:pointer;
    border:1px solid rgba(255,255,255,.28);background:rgba(255,255,255,.08);
    color:#fff;font:inherit;font-size:.9375rem;font-weight:800;line-height:1}
  .help-top:hover,.help-top:focus-visible{background:rgba(255,255,255,.18);outline:none}
}
.asst-drawer{display:flex;flex-direction:column;gap:10px}
.asst-drawer[hidden]{display:none}
.asst-drawer .drawer-head{margin-bottom:0}
.asst-intro,.asst-off{font-size:.84375rem;color:var(--ink-2);margin:0}
.asst-turn{display:flex;flex-direction:column;max-width:88%}
.asst-turn.user{align-self:flex-end;align-items:flex-end}
.asst-turn.bot{align-self:flex-start}
.asst-bubble{white-space:pre-wrap;overflow-wrap:anywhere;font-size:.84375rem;line-height:1.45;
  padding:9px 12px;border-radius:12px;background:var(--ground-2);color:var(--ink)}
.asst-turn.user .asst-bubble{background:var(--brand-50);border:1px solid var(--brand-100)}
.asst-source{font-size:.75rem;color:var(--muted);margin-top:4px}
.asst-gap{font-size:.8125rem;padding:10px 12px;border-radius:10px;background:#FFF6E5;border-left:3px solid #E8B341;
  display:flex;flex-direction:column;gap:8px}
.asst-help{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:.8125rem;color:var(--ink-2)}
.asst-help form,.asst-gap form{margin:0}
.asst-actions{display:flex;gap:8px;justify-content:flex-end;align-items:center}
.asst-ask{display:flex;flex-direction:column;gap:8px;margin-top:4px}
.asst-ask textarea{font:inherit;font-size:.875rem;padding:8px 10px;border:1px solid var(--rule);border-radius:8px;
  background:var(--surface);color:var(--ink);resize:vertical;box-shadow:var(--shadow-xs)}
.asst-ask textarea:focus{outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue)}
.asst-wait{display:none;font-size:.78125rem;color:var(--muted)}
.asst-ask.htmx-request .asst-wait{display:inline}
.asst-foot{font-size:.75rem;color:var(--muted);margin:0}
/* The assistant's draft and the exchange on /feedback, folded under the problem. */
.fb-text details{margin-top:8px}
.fb-text summary{cursor:pointer;font-size:.75rem;font-weight:600;color:var(--brand-700)}
pre.fb-text{font:inherit;font-size:.78125rem;margin:6px 0 0;padding:8px 10px;background:var(--ground-2);border-radius:6px;max-width:60ch}
/* The ? square took 41px of a 375px bar and "My schedule" became "My schedu".
   Under 430px the bar gives the room back from its own padding and gaps, so
   the tab, both squares, Password and Log out all fit unclipped. */
@media(max-width:430px){
  .sidebar{gap:6px;padding:10px 10px}
  .brand{padding-right:0}
  .sidenav a{padding:10px 8px}
  .userbox{gap:5px}
  .userbox a{padding:10px 4px}
  .fb-top{margin-right:0}
}
.asst-drawer .drawer-head h2{flex:1}

/* The "?" help mark (plan 2026-09-28, Part C). A button, so it works on a tap
   and from the keyboard; app.js toggles .open on the wrapper. The sentence is
   help_text.HELP, printed by the `help()` template global. */
.help-wrap{position:relative;display:inline-block;vertical-align:middle;margin-left:4px}
.help{
  width:16px;height:16px;padding:0;border-radius:50%;
  border:1px solid var(--brand-300);background:var(--surface);color:var(--brand-700);
  font:700 .6875rem/14px -apple-system,"Helvetica Neue",Helvetica,Arial,sans-serif;
  text-align:center;cursor:pointer;letter-spacing:0;text-transform:none;
}
.help:hover,.help:focus-visible,.help-wrap.open .help{background:var(--brand-700);border-color:var(--brand-700);color:#fff;outline:none}
.help-pop{
  display:none;position:absolute;z-index:60;left:-8px;top:calc(100% + 6px);
  width:max-content;max-width:260px;padding:8px 10px;border-radius:6px;
  background:var(--brand-900);color:#fff;font-size:.78125rem;font-weight:400;line-height:1.45;
  text-transform:none;letter-spacing:0;white-space:normal;text-align:left;
  box-shadow:0 4px 14px rgba(16,44,82,.22);
}
.help-wrap.open .help-pop{display:block}
@media (max-width:640px){
  .help{width:20px;height:20px;line-height:18px}
  .help-wrap{position:static}
  .help-pop{left:16px;right:16px;max-width:none;width:auto}
}

/* Systems Tasks: the client above the job name (28 Sep, D3). */
.col-job .job-client{display:block;font-size:.75rem;font-weight:600;color:var(--ink-2);
  text-transform:uppercase;letter-spacing:.03em;text-decoration:none;margin-bottom:1px}
.col-job .job-client:hover{color:var(--brand-700);text-decoration:underline}

/* The job page, rebuilt 28 Sep (plan Part B): one question per block, the
   state first, the Next line on top, the hand corrections in one disclosure. */
.next-line{font-size:.9375rem;line-height:1.45;margin:2px 0 14px;padding:10px 12px;
  background:var(--brand-50);border-left:3px solid var(--brand-700);border-radius:4px}
.next-line b{color:var(--brand-700)}
.standing-inline{display:inline-flex;align-items:center;gap:4px;margin-left:10px}
.job-block{margin-top:18px;padding-top:14px;border-top:1px solid var(--rule)}
.job-state .card-head h2,.job-facts .card-head h2{font-size:.875rem;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-2)}
.po-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.job-links{margin-top:6px}
.job-notes{white-space:pre-wrap;margin:12px 0 0;padding:10px 12px;background:var(--sunk);border-radius:4px;font-size:.84375rem}
.job-fixes{margin-top:22px;padding-top:12px;border-top:1px solid var(--rule)}
.job-fixes .fix-item{padding:10px 0;border-top:1px dashed var(--rule)}
.job-fixes .fix-item:first-of-type{border-top:none}
.job-fixes h3{font-size:.84375rem;margin:0 0 6px}
.statelist .quiet-edit.inline-edit{margin-top:6px}
