/* ============================================================
   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 name on its own line above Password and Log out (visual QA, 14 Oct):
   in one row the links squeezed it to "Moniq... Faulkn...". The two icons
   stand in for the words only in the folded rail. */
.userbox .ub-i{display:none}
@media(min-width:821px){
  .userbox{flex-wrap:wrap;row-gap:3px}
  .userbox .uname{flex:1 0 100%;white-space:nowrap}
  .userbox a:first-of-type{margin-left:0}
}

/* 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}
  /* Under the brand mark, not over the last menu icons (visual QA, 14 Oct). */
  html.nav-folded .nav-fold{position:static;flex:none;margin:0 auto 10px}
  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;flex-direction:column;gap:4px}
  html.nav-folded .userbox a{margin-left:0;padding:4px 0;font-size:.9375rem;line-height:1}
  html.nav-folded .userbox .ub-i{display:inline}
  html.nav-folded .userbox .ub-l{display:none}
}
@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. Two layers:
     the shadow stays at the box's edge (scroll) and a white cover rides at
     the end of the content (local), so it hides the shadow once nothing is
     left to scroll. One layer drew the shadow on every table (visual QA 14 Oct). */
  background:
    linear-gradient(to left,var(--surface) 40%,rgba(255,255,255,0)) right center/40px 100% no-repeat local,
    linear-gradient(to right,rgba(16,44,82,0),rgba(16,44,82,.10)) right center/14px 100% no-repeat scroll,
    var(--surface);
}
/* 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;flex-wrap:wrap;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)}
/* Every typing box starts in the same look as the dropdown above (visual QA
   14 Oct): until then only text and number boxes inside certain sections were
   styled, so the password page, every date, email and url box and every text
   area were bare browser boxes in a typewriter font. `:where` keeps this at
   zero specificity so every scoped rule further down still wins. Tick boxes,
   radios and the file picker are left alone. */
:where(input:not([type]),input[type=text],input[type=email],input[type=tel],input[type=date],
input[type=time],input[type=number],input[type=search],input[type=password],input[type=url],textarea){
  font:inherit;font-size:.8125rem;font-weight:500;line-height:1.3;padding:7px 10px;border:1px solid var(--rule);border-radius:8px;
  background:var(--surface);color:var(--ink);box-shadow:var(--shadow-xs);
  transition:border-color .14s ease,box-shadow .14s ease;
}
:where(input:not([type]),input[type=text],input[type=email],input[type=tel],input[type=date],
input[type=time],input[type=number],input[type=search],input[type=password],input[type=url],textarea):focus{
  outline:none;border-color:var(--brand-500);box-shadow:var(--glow-blue);
}
:where(textarea){line-height:1.45}

/* ============================================================
   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}
/* E-016: a clash an On site day was saved over, inside a green Saved banner. */
.banner-body .warn{color:var(--warn);font-weight:600}
.banner-title{display:block;font-weight:700;font-size:.875rem;letter-spacing:-.005em;margin-bottom:1px}
/* 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}
/* E-118 (9 Oct): the match box and the five routes on a card. The routes
   sit in one row; a route with fields opens under its button, the suggested
   one open from the start. */
.request-match{display:flex;flex-wrap:wrap;align-items:center;gap:4px 10px;margin-top:8px;
  padding-top:8px;border-top:1px solid var(--rule-soft);font-size:.8125rem}
.request-client{display:flex;align-items:center;gap:6px;margin-left:auto}
/* E-197 (10 Oct): one client box. A known client's box hides behind a
   small "wrong client?" link; Quote it is one press, not a panel. */
.request-fix{margin-left:auto}
.request-fix > summary{list-style:none;cursor:pointer;color:var(--muted);font-size:.78125rem;text-decoration:underline}
.request-fix > summary::-webkit-details-marker{display:none}
.request-fix[open]{flex:1 1 100%;display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.request-fix[open] .request-client{margin-left:0}
.request-client-hint{flex:1 1 100%;text-align:left}  /* under the box it explains (visual QA 14 Oct, G1-24) */
.route-quote{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px}
.route-quote form{margin:0}
.request-client input{width:200px;max-width:100%;font-size:.78125rem}
.request-routes{display:flex;flex-wrap:wrap;align-items:flex-start;gap:6px 8px;margin-top:8px}
.request-routes details.route{flex:0 0 auto}
.request-routes details.route[open]{flex:1 1 100%;order:-1;min-width:0;max-width:100%}
.request-routes details.route > summary{list-style:none;display:inline-block;cursor:pointer}
.request-routes details.route > summary::-webkit-details-marker{display:none}
.route-form{margin-top:8px;padding:8px 10px;background:var(--sunk);border:1px solid var(--rule-soft);
  border-radius:8px;display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.route-form .rulegrid{flex:1 1 100%}
.route-form{min-width:0}
.route-form select{max-width:100%}
.route-form label.wide{min-width:0}
.route-form label.wide select{width:100%;text-overflow:ellipsis}
.agreement-lines input[type=text]{width:100%}
.agreement-lines select{width:100%;max-width:100%}
/* A "client wrote" flag from Belongs to this, on a job or a proposal. */
.client-flag{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 10px;margin:0 0 10px;padding:8px 12px;
  border-radius:9px;background:#FFF7E8;border:1px solid rgba(150,89,15,.2);font-size:.8125rem}
.client-flag form{margin:0 0 0 auto}
/* 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}
.masterdetail > *{min-width:0}
@media(max-width:900px){.masterdetail{grid-template-columns:minmax(0,1fr)}}
.clientlist{
  background:var(--surface);border:1px solid var(--rule);border-radius:12px;
  box-shadow:var(--shadow);overflow:hidden;position:sticky;top:22px;
  /* its own scroll box: 164 names ran 6,500px down the page (visual QA 14 Oct) */
  max-height:calc(100vh - 44px);overflow-y:auto;
}
.clientlist .search{position:sticky;top:0;z-index:2}
/* On a phone the client you opened comes first and the list follows it in a
   short box; on /clients with nobody open the list stays on top. */
@media(max-width:900px){
  .clientlist{position:static;max-height:420px}
  .masterdetail:has(.clientlist a.crow.active) > .clientlist{order:2}
}
.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-wide{grid-column:1 / -1}  /* a field that needs the whole line, e.g. a subject (visual QA 14 Oct) */
/* A lone setting takes a sensible width, not one 210px track in a wide card (G4b-20) */
.detail-kv:has(> .kv:only-child){grid-template-columns:minmax(0,560px)}
/* The caption only (`>`, visual QA 14 Oct): a bold word inside the help line
   under a field used to turn into a caption on a line of its own. */
.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 > small.muted{display:block;margin-top:4px;line-height:1.45}
.detail-kv .kv span{font-size:.875rem;color:var(--ink);overflow-wrap:anywhere}  /* a long email breaks rather than running into the next field (G1-12) */
/* 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{
  /* E-184 (Monique, 9 and 13 Oct): the days bar stays visible while she
     scrolls. The header cells are sticky, but sticky pins to the nearest
     scrolling ancestor, and this wrapper scrolled sideways only, so the page
     scrolled past the header. The wrapper now scrolls both ways inside the
     viewport, and the header sticks to its top. */
  overflow:auto;max-height:calc(100vh - 150px);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;
}
/* Previous, the period and Next travel as one; the weekend note takes its own
   line under the buttons so Add to schedule stays at the right (visual QA 14 Oct) */
.weeknav .wn-period{display:inline-flex;align-items:center;gap:10px;flex:none}
.weeknav .hidden-note{font-size:.75rem;order:1;flex-basis:100%}
.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 1 100%;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;
}
/* An On site day from a task (E-016): Other work in the client's colour, a
   soft tint with the client's edge, so it reads as theirs without passing
   for a booked audit. --tone is set inline by the grid, as for audits. */
.sched .ent.blocked.work.taskday{
  background:var(--tone-soft,#EAF1FB);border-color:var(--tone,#224F8F);
  border-left:3px solid var(--tone,#224F8F);color:#1F2A44;cursor:pointer;
}
.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}
/* A leave, RDO or other work note gets the same one line as .l1 and .l2; the
   full note is on hover and in the drawer (visual QA 14 Oct) */
.sched.month .ent small{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;
  white-space:nowrap;flex-wrap:wrap;row-gap:2px}  /* "8:00 AM" stays on one line; the dot drops under it if it must (14 Oct) */
.inv-dot{width:6px;height:6px;border-radius:50%;background:#9AA3AF;flex:none}
.inv-dot.sent,.inv-dot.updated,.inv-dot.adopted{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}

/* Fortnight view: all fourteen days on a 1440 laptop (visual QA 14 Oct). A
   fixed grid like the month, so a long client name wraps inside its day rather
   than widening the table past the screen; weekends narrower, a word wider
   than its day breaks rather than spilling into the next. */
.sched:not(.month){table-layout:fixed;min-width:1000px}
.sched:not(.month) th,.sched:not(.month) td{min-width:0;padding:4px 2px}
.sched:not(.month) thead th:first-child,.sched:not(.month) td.rowhead{width:96px;min-width:96px;padding:9px 8px;white-space:normal;line-height:1.25}
.sched:not(.month) th.wknd:not(.busy){width:48px}
.sched:not(.month) .ent{padding:4px 4px 4px 5px;font-size:.6875rem;letter-spacing:-.01em;hyphens:auto;overflow-wrap:break-word}
/* the cross floats beside the first line only, so the note below gets the
   chip's full width */
.sched:not(.month) .ent.blocked{padding-right:4px}
.sched:not(.month) .ent-x{position:static;float:right;margin:-3px -2px 0 2px}

/* 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:var(--brand-50);  /* flat: a gradient restarted in every cell and boxed the amount (visual QA 14 Oct) */
  font-size:.78125rem;color:var(--ink-2);padding:6px 15px 6px 32px;
}
tbody tr.subrow:hover td{background:var(--brand-100)}

/* ============================================================
   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}
/* minmax(0,1fr), not 1fr: a bare 1fr track never shrinks below its widest
   child, so a long email or a wide table pushed the page past a phone's edge. */
.quotegrid > *{min-width:0}
@media(max-width:1000px){.quotegrid{grid-template-columns:minmax(0,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;flex-wrap:wrap;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,.remaster 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;font-weight:500;line-height:1.3;padding:7px 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)}
/* Even columns, like the roster below (visual QA 14 Oct), not a ragged wrap. */
.rules-checks{display:grid;grid-template-columns:repeat(auto-fill,minmax(270px,1fr));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(min(380px,100%),1fr));gap:8px 22px}  /* name, role and workload pill on one line (visual QA 14 Oct) */
.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-inline label.wide{flex:1 1 280px}  /* Site address shows its whole hint (visual QA 14 Oct, G4a-08) */
.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 24px 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)}
/* a name or an email box does not need 1,100px (visual QA 14 Oct, G4b-20) */
.newthing label:not(.wide),.task-form label:not(.wide){max-width:560px}
/* `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. Nor
   is a radio (visual QA 14 Oct: per visit / for the whole job floated mid-form). */
.newthing label input[type=checkbox],.task-form label input[type=checkbox],
.stackform label input[type=checkbox],.newthing label input[type=radio],
.task-form label input[type=radio],.stackform label input[type=radio]{
  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:120px 1fr auto;gap:6px 16px;align-items:baseline;  /* 120: "START-UP QUESTIONNAIRE" (visual QA 14 Oct) */
  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:100px}  /* 74px until E-017; "05 Aug" wrapped one step up; 100 so "REQUESTED" fits (visual QA 14 Oct) */
.c-assign{width:210px}  /* a full name in the dropdown (visual QA 14 Oct) */
.c-money{width:112px}  /* "FEE (EX GST)" and "VALUE (EST)" whole (visual QA 14 Oct) */
.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-visit{display:block;font-size:.75rem;color:var(--ink-2)}
.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}
/* Visual QA 14 Oct: quiet links line up with the text above them; an opened
   route form is a tidy stack with the row's other cells at the top. */
.col-act .btn-quiet{padding-left:0;padding-right:0}
.col-act details.route > summary{white-space:normal;text-align:left;line-height:1.3}
/* The three ways off To book as one set (Nathan, 17 Oct; E-264): Propose
   dates, Book agreed dates, For later stacked in one column, the same width
   and height, one line each, and Book now alone on a For later row. The
   opened Book agreed dates form drops below the set at the cell's width. */
.tobook-acts{display:flex;flex-direction:column;align-items:stretch;gap:4px;max-width:170px;margin:0}
.tobook-acts > form{margin:0}
.tobook-acts .btn,
.tobook-acts details.route > summary.btn{display:block;width:100%;box-sizing:border-box;margin:0;
  text-align:center;white-space:nowrap;line-height:1.3}
.tobook-acts details.route > summary{list-style:none;cursor:pointer}
.tobook-acts details.route > summary::-webkit-details-marker{display:none}
.tobook-acts:has(details.route[open]){max-width:none}
.col-act .route-form .rulegrid{display:grid;gap:6px}
.col-act .route-form label{display:flex;flex-direction:column;gap:2px;font-size:.75rem}
.col-act .route-form input,.col-act .route-form select{width:100%;box-sizing:border-box}
.group tr:has(details.route[open]) td{vertical-align:top}

/* 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}
table.money td.c-client{white-space:normal}  /* Invoicing Review: the whole client name, wrapped (G4b-15) */
.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:96px}

/* 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:minmax(0,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:110px}  /* "DOCUMENT" whole (visual QA 14 Oct) */
.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(--ink-2);font-size:1.125rem;line-height:1;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:minmax(0,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 5px;text-align:left;border-bottom:1px solid var(--rule);vertical-align:middle}
.visits th{font-size:.71875rem;color:var(--ink-2);font-weight:600;letter-spacing:.05em}
.visits tr.past{opacity:.6}
.visits .v-day,.visits .v-inv{white-space:nowrap}
.visits th:first-child,.visits td:first-child{padding-left:2px}
.visits th:last-child,.visits td:last-child{padding-right:0}  /* a day and an invoice number on one line (visual QA 14 Oct) */
.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}
/* Visual QA 14 Oct (G2a-10): four boxes in a 590px card cut what was typed,
   so on a laptop each site is two boxes a line, Site and Address over Contact
   and Email, the headings laid out the same way as a key and styled like
   every other caption, and a finger-sized cross. */
@media (min-width:721px){
  .visit-sites-head,.visit-site-row{grid-template-columns:1fr 1fr 32px}
  .visit-sites-head > :nth-child(3),.visit-site-row > :nth-child(3){grid-column:1;grid-row:2}
  .visit-sites-head > :nth-child(4),.visit-site-row > :nth-child(4){grid-column:2;grid-row:2}
  .visit-sites-head > :nth-child(5),.visit-site-row > :nth-child(5){grid-column:3;grid-row:1 / span 2}
  .visit-site-row + .visit-site-row{border-top:1px dashed var(--rule);padding-top:6px}
}
.visit-sites-head span{font-size:.65625rem;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:700}
.visit-site-row .btn-remove{min-height:32px}
@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 28px}
.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){
  /* Not for the help sheet (visual QA, 14 Oct): it stays open across pages,
     so its backdrop left every next page dimmed and untappable. */
  body.drawer-open:not(.asst-open){overflow:hidden}
  body.drawer-open:not(.asst-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:calc(76px + var(--days,22) * 72px)}  /* 72 px a day, readable; it scrolls inside .schedwrap (visual QA 14 Oct, G3-07) */
  .sched.month thead th:first-child,.sched.month td.rowhead{width:76px;min-width:76px}
}


/* ============================================================
   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-wrap:anywhere;  /* two lines, like the client (visual QA 14 Oct, G5-23) */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.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)}
/* the second entry on one day: the date is not printed twice (G5-21) */
.vr.same-day{border-top-style:dashed}
.vr.same-day .vr-date{visibility:hidden}
.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;margin-bottom:28px}

@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:0}
.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}

/* visual QA 14 Oct, B: the help panel, the two doors and the menu */
/* The two doors at rest are two small round icons; the words are in the
   tooltip and the accessible name. As full pills they were about 340px wide
   and covered totals, Approve and Issue report at the bottom right. A phone
   keeps them in the top bar. */
@media(min-width:821px){
  .doors{gap:6px}
  .doors .fb-label{display:none}
  .help-trigger,.doors .fb-trigger{width:40px;height:40px;padding:0;gap:0;justify-content:center;border-radius:50%}
  .help-trigger .ni,.doors .fb-trigger .ni{width:auto;font-size:1rem}
}
/* Help open on a computer: the page narrows beside it instead of the panel
   lying over its right-hand 380px (Nathan, 14 Oct). From 1200px only: below
   that the page's own two-column layouts no longer fit beside the panel, so
   a small window keeps the panel over the page as before. Its own door
   hides, and the flag and the report box step left of any open panel. */
@media(min-width:1200px){
  body.asst-open .shell{padding-right:380px}
}
/* The page's own two-column layouts step to one column at the page width
   they would without the panel (their breakpoints assume the full window). */
@media(min-width:1200px) and (max-width:1379px){
  body.asst-open .quotegrid,body.asst-open .quotegrid.answer-first{grid-template-columns:minmax(0,1fr)}
}
@media(min-width:1200px) and (max-width:1479px){
  body.asst-open .quotegrid.lines-left{grid-template-columns:minmax(0,1fr)}
}
@media(min-width:1200px) and (max-width:1279px){
  body.asst-open .masterdetail{grid-template-columns:minmax(0,1fr)}
}
/* Beside the panel the page is phone-narrow for the list tables: the same
   floor on the name column, so the table scrolls in its box rather than the
   job name going to 0px, and a filter row too long for the card scrolls. */
@media(min-width:1200px) and (max-width:1679px){
  body.asst-open table:has(> colgroup) > colgroup > col:not([class]):not([style]){width:200px}
  body.asst-open .filterrow{max-width:100%;overflow-x:auto;padding-bottom:2px}
  body.asst-open .filterrow .tabs,body.asst-open .filterrow .filterlabel{flex:none}
}
@media(min-width:701px){
  body.asst-open .help-trigger{display:none}
  body.drawer-open .doors{right:404px}
  body.drawer-open .fb-dialog{right:404px;width:min(480px,calc(100vw - 428px))}
}
/* Help switched off: the panel carries its own Something not right? button,
   so the floating one steps aside and there is only ever one on screen. */
body:has(#assistant-drawer:not([hidden]) .asst-off) .fb-trigger,
body:has(#assistant-drawer:not([hidden]) .asst-off) .fb-top{display:none}
/* Help on a phone: a shorter sheet with no backdrop, and room under the page
   so its last rows can still be scrolled up above the sheet. The report box
   hides the sheet while it is open rather than stacking on top of it. */
@media(max-width:700px){
  .asst-drawer{max-height:50vh}
  body.asst-open .page{padding-bottom:calc(50vh + 24px)}
  body:has(#feedback-dialog[open]) #assistant-drawer{display:none}
}
/* The menu on a 900px-tall laptop: a little tighter, so more of it fits. */
@media(min-width:821px) and (max-height:980px){
  .sidenav{gap:1px}
  .sidenav a{padding-top:6px;padding-bottom:6px}
  .nav-h{padding:10px 12px 3px}
  .brand{padding-bottom:12px;margin-bottom:10px}
  html.nav-folded .sidenav a{padding:5px 0}
  html.nav-folded .nav-rule{margin:6px}
}
/* What still does not fit fades at the edge it continues past, so the menu
   reads as one that scrolls (app.js sets more-start and more-end). */
.sidenav{--fade-s:0px;--fade-e:0px}
.sidenav.more-start{--fade-s:22px}
.sidenav.more-end{--fade-e:34px}
.sidenav.more-start,.sidenav.more-end{
  -webkit-mask-image:linear-gradient(to bottom,transparent,#000 var(--fade-s),#000 calc(100% - var(--fade-e)),transparent);
  mask-image:linear-gradient(to bottom,transparent,#000 var(--fade-s),#000 calc(100% - var(--fade-e)),transparent)}
@media(max-width:820px){
  .sidenav.more-start{--fade-s:12px}
  .sidenav.more-end{--fade-e:24px}
  .sidenav.more-start,.sidenav.more-end{
    -webkit-mask-image:linear-gradient(to right,transparent,#000 var(--fade-s),#000 calc(100% - var(--fade-e)),transparent);
    mask-image:linear-gradient(to right,transparent,#000 var(--fade-s),#000 calc(100% - var(--fade-e)),transparent)}
}

/* visual QA 14 Oct, A: phone widths and tables */
/* A plain sideways scroll box for a wide table inside a card, with none of
   .tablewrap's border, so the laptop looks as it did. */
.scrollx{overflow-x:auto;max-width:100%;-webkit-overflow-scrolling:touch}
/* Record an agreement: seven columns of selects need their room, so the
   table scrolls on anything narrower. */
table.agreement-lines{min-width:1030px}
table.agreement-lines th,table.agreement-lines th:first-child{white-space:normal}
.agreement-form .rulegrid > .wide{grid-column:1/-1}
.agreement-form label[hidden],.agreement-form p[hidden]{display:none}
/* The client eyebrow on Systems Tasks can never paint over the next cell. */
.col-job{overflow:hidden}
/* Client details send row on a job: picker, email and button wrap as one
   group and never pass the card's edge. */
.standing-val form.inline{display:inline-flex;flex-wrap:wrap;align-items:center;gap:6px 8px;max-width:100%}
.standing-val select,.standing-val input{max-width:100%;min-width:0;box-sizing:border-box}
.standing-val form.inline input[type=email]{flex:1 1 200px;width:auto}
/* Receipts tabs sit straight in the page, not in a filter row. */
.page > .tabs{align-self:flex-start;max-width:100%;overflow-x:auto}
.page > .tabs a{white-space:nowrap}
/* "Add a job by hand": the grey note drops under the title on a phone. */
.newthing > .group-head{flex-wrap:wrap;row-gap:2px}
.newthing > .group-head b{white-space:nowrap}
.help{position:relative}
@media(max-width:820px){
  .head-actions{justify-content:flex-start}
  /* A table with a colgroup is fixed layout. On a phone its fixed columns
     add up to more than the screen and the one unsized column, the job,
     project or service name, came out 0px wide. A floor on that column makes
     the table wider than the phone, so it scrolls inside its box instead. */
  table:has(> colgroup) > colgroup > col:not([class]):not([style]){width:200px}
  table.project-rows td:first-child{white-space:normal}
  table.filing{min-width:600px}
  .route-form select{width:100%}
  /* The search box gets the whole line; the count drops under it. */
  .filtersearch{flex-wrap:wrap;overflow:visible}
  .filtersearch input[type="search"]{flex:1 1 100%}
  /* "Email <long client name> for it" wraps inside the card, not past it. */
  .po-row form.inline{max-width:100%;min-width:0}
  .po-row form.inline .btn{white-space:normal;text-align:left}
}
@media(max-width:700px){.hide-sm{display:none}}
/* The 20px "?" keeps its look and gets a finger-sized tap area. */
@media(max-width:640px){.help::after{content:"";position:absolute;inset:-10px}}

/* visual QA 14 Oct, C: forms, buttons, missing styles and spacing */
/* Styles the templates used that never existed. */
.nowrap{white-space:nowrap}
.plainlist{list-style:none;margin:0;padding:0}
.plainlist:not(.statelist) > li{padding:2px 0}
/* Add a job by hand: the deposit fields are for the Systems board only. */
.newthing form:has(select[name=side] option[value=ops]:checked) .sys-only{display:none}
/* To approve: the open route is the panel's heading, not a second button
   beside the panel's own submit (Nathan, 14 Oct). */
.request-routes details.route[open] > summary.btn,
.request-routes details.route[open] > summary.btn:hover{
  background:none;border-color:transparent;box-shadow:none;padding:0 0 2px;transform:none;
  font-size:.8125rem;font-weight:700;color:var(--ink-2);
}
.request-routes details.route[open] > summary.btn::after{content:" ▾";color:var(--muted);font-weight:400}
/* A button that sits in a section heading reads as a button, not the heading. */
.section-h .btn{text-transform:none;letter-spacing:0;font-size:.71875rem}
/* Client 360 add rows: the boxes, the dropdowns and the button one height. */
.addrow input:not([type=checkbox]):not([type=radio]),.addrow select,
.rules-inline input:not([type=checkbox]):not([type=radio]),.rules-inline select,
#client-filing form input[type=text]{height:34px;box-sizing:border-box}
.addrow .btn,.rules-inline .btn,#client-filing form .btn{
  height:34px;box-sizing:border-box;display:inline-flex;align-items:center;padding:0 12px}
/* The proposal number hint in its own case; the number itself stays capitals. */
.quote-number input::placeholder{text-transform:none}
/* The proposal's Quoted total reads as a total, not a column heading. */
tfoot th.num{font-size:.875rem;letter-spacing:0;text-transform:none;color:var(--ink);font-weight:700}
/* No empty band under the report drop box until there is something to say. */
.drop-status:empty{min-height:0;margin:0}
/* A card whose first thing is a heading starts at the top (Send the report). */
.card > .card-head:first-child{margin-top:0 !important}
/* The "?" after Email for it wraps with its button, not on a line of its own. */
.po-row form.inline{display:inline-flex;align-items:center;gap:4px}
/* Edit these details: both dropdowns the width of their column. */
.job-facts .detail-kv select{width:100%}
/* The receipt form's Send it button, with room before Your last few. */
.rcpt form ~ .card{margin-top:22px}
/* The client's dates link on Propose dates: the whole link, the card's width. */
.linkbox{display:block;width:100%;max-width:100%;box-sizing:border-box;font-size:.78125rem;color:var(--ink-2)}

/* visual QA 14 Oct, D: words, labels, dates and behaviour */
/* Other work on My schedule, blue like its block on the office Schedule (G3-20). */
.pill.work{background:#EAF1FB;color:#1F3B66;box-shadow:inset 0 0 0 1px rgba(34,79,143,.22)}

/* visual QA 14 Oct, E: squeezed tables, cut-off labels and the schedule */
/* The cross on a blocked day stays (Nathan, 14 Oct) and on a phone it is a
   finger-sized target: 28 px, beside the label, with the note on its own
   full-width line under them (G3-09). */
@media(max-width:820px){
  .sched .ent.blocked,.sched.month .ent.blocked{display:flex;flex-wrap:wrap;align-items:flex-start;column-gap:2px;padding-right:2px}
  .sched .ent.blocked > small{order:2;flex:1 1 100%;min-width:0}
  .sched .ent.blocked .ent-x{position:static;float:none;order:1;margin:-3px -1px 0 auto;
    min-width:28px;min-height:28px;display:inline-flex;align-items:center;justify-content:center;
    font-size:.875rem;opacity:.65}
  /* the fortnight on a phone scrolls inside its box at about 80 px a day */
  .sched:not(.month){min-width:1180px}
  .sched:not(.month) thead th:first-child,.sched:not(.month) td.rowhead{width:76px;min-width:76px}
}
/* The visit picker above the audit report: a chip per visit (G2a-16, G2b-19). */
.visit-picker{display:flex;flex-wrap:wrap;gap:4px 14px}
.visit-picker .vp{white-space:nowrap}
/* Receipts, Add a receipt: a box with no hint line sits level with the rest (G4b-21). */
#addform .rules-grid{align-items:end}
/* Feedback: date, name and page at the top of a tall row, beside the start of
   the problem they belong to (G4b-25). */
table.fbtable td{vertical-align:top}
/* The receipt form: no empty band under Take a photo until there is a message (G5-27). */
.rcpt .say:empty{display:none}

/* A long task description on Tasks: two lines, then "more" (14 Oct). The
   summary's own marker is hidden; "more" is the control, "less" when open,
   and the opened copy replaces the two-line preview rather than repeating it. */
.task-desc > summary{list-style:none;cursor:pointer}
.task-desc > summary::-webkit-details-marker{display:none}
.task-desc > summary .more{color:var(--brand-700);text-decoration:underline;white-space:nowrap}
.task-desc[open] > summary > span:first-child{display:none}
.task-desc[open] > summary .more{font-size:0}
.task-desc[open] > summary .more::after{content:"less";font-size:12.5px}

/* The site address on the job page (E-257): one line, the box takes the room. */
.site-address-edit{margin:6px 0 4px;max-width:640px}
.site-address-form{display:flex;gap:8px;align-items:center;margin-top:6px}
.site-address-form input[type="text"]{flex:1 1 auto;min-width:0}
