/* Hisaab — light theme: white surfaces, blue + black lettering, soft graphs.
   Every colour, radius, shadow and spacing step comes from tokens.css, which
   is loaded first; change the look there, not here. If you find yourself
   typing a hex below, the token is missing — add it there instead.

   Roughly in order: base, shell, surfaces, controls, data display, charts,
   overlays, the new page-level components, responsive. */

* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font: 14px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

header.top {
  display: flex; align-items: center; gap: 24px;
  padding: 12px 28px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 5;
  box-shadow: var(--shadow);
}
/* Brand: Fulcrum H mark + Archivo wordmark (see design "Hisaab Logo") */
header.top .brand {
  display: inline-flex; align-items: center; gap: 9px;
  text-decoration: none; flex: none;
}
header.top .brand img { display: block; }
header.top .wordmark {
  font-family: Archivo, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 700; font-size: 20px; letter-spacing: -0.035em;
  color: var(--brand-ink); line-height: 1;
}
/* Stacked lockup for the sign-in screen */
.lockup { display: flex; flex-direction: column; align-items: center; gap: 12px; margin-bottom: 22px; }
.lockup .wordmark {
  font-family: Archivo, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 700; font-size: 34px; letter-spacing: -0.035em; color: var(--brand-ink); line-height: 1;
}
.lockup .tagline {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--text-xs); letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-2);
}
header.top nav { display: flex; gap: 16px; }
header.top nav a { color: var(--ink-2); padding: 4px 2px; }
header.top nav a.on { color: var(--accent-deep); font-weight: 600; border-bottom: 2px solid var(--accent); }

main { max-width: 1320px; margin: 0 auto; padding: 24px 28px 64px; }
h1 { font-size: 22px; margin: 8px 0 2px; color: var(--accent-deep); }
h2 { font-size: 15px; margin: 28px 0 10px; color: var(--accent-deep); }
.sub { color: var(--ink-2); margin: 0 0 18px; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px 18px;
  box-shadow: var(--shadow);
}

/* Hero + stat tiles */
.hero { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.hero .big { font-size: 48px; font-weight: 650; letter-spacing: -0.5px; color: var(--ink); }
.hero .unit { color: var(--ink-2); }
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; margin-top: 16px; }
.tile {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: 12px 14px; box-shadow: var(--shadow); display: block; color: inherit;
}
a.tile:hover { border-color: var(--accent); text-decoration: none; box-shadow: var(--shadow-lift); }
.tile .lbl { color: var(--ink-2); font-size: 12.5px; }
.tile .val { font-size: 21px; font-weight: 650; margin-top: 2px; color: var(--ink); }
.tile .delta { font-size: 12px; margin-top: 2px; }
.delta.up { color: var(--good); }
.delta.down { color: var(--critical); }
.delta.neutral { color: var(--ink-2); }
.tile .note { font-size: 11.5px; color: var(--muted); margin-top: 2px; }

/* Sparkline (de-emphasis hue, current point in accent) */
.valrow { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
.spark { color: var(--seq-1); flex: none; margin-bottom: 4px; }
.spark circle { fill: var(--accent); stroke: var(--surface); stroke-width: 1.5; }

/* Horizontal bar charts */
.chart { margin-top: 6px; }
.crow { display: grid; grid-template-columns: 110px 1fr 92px; align-items: center; gap: 10px; padding: 3px 0; border-radius: 6px; }
.crow:hover { background: var(--accent-wash); }
.clabel { color: var(--ink-2); font-size: 12.5px; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctrack { position: relative; height: 16px; background: var(--accent-wash); border-radius: 0 4px 4px 0; }
.cbar { position: absolute; left: 0; top: 0; height: 16px; border-radius: 0 4px 4px 0; min-width: 2px; }
.cbar.s1 { background: var(--s1); }
.cbar.s2 { background: var(--s2); }
.cbar.s3 { background: var(--s3); }
.cval { font-size: 12.5px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
/* The three columns are fixed-label / flexible-track / fixed-value, which adds
   up to more than a phone is wide once the value is a lakh figure — the whole
   page then scrolled sideways because of one chart. Narrow the two fixed
   columns and let the track take what is left. */
@media (max-width: 560px) {
  /* minmax(0, …) rather than a flat width: a grid column defaults to a min
     content size, so a ₹10,42,616 refuses to shrink and pushes the whole page
     sideways by the few pixels it is over. */
  .crow { grid-template-columns: minmax(0, 72px) minmax(0, 1fr) minmax(0, 70px); gap: 6px; }
  .clabel, .cval { font-size: 11.5px; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .chart.wide .crow { grid-template-columns: minmax(0, 92px) minmax(0, 1fr) minmax(0, 70px); }
}
.legend { display: flex; gap: 16px; margin: 4px 0 10px; font-size: 12.5px; color: var(--ink-2); }
.legend .key { display: inline-flex; align-items: center; gap: 6px; }
.legend .sw { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.sw.s1 { background: var(--s1); } .sw.s2 { background: var(--s2); } .sw.s3 { background: var(--s3); } .sw.s3c { background: var(--s3c); }

/* Payout composition bar */
.compo { max-width: 720px; margin: 14px 0 4px; }
.compobar { display: flex; gap: 2px; height: 14px; }
.compobar .seg { display: block; min-width: 3px; }
.compobar .seg.s1 { background: var(--s1); } .compobar .seg.s2 { background: var(--s2); } .compobar .seg.s3c { background: var(--s3c); }
.compobar .seg:first-child { border-radius: 4px 0 0 4px; }
.compobar .seg:last-child { border-radius: 0 4px 4px 0; }
.compo .legend { margin: 8px 0 0; flex-wrap: wrap; }

/* Column chart (monthly trend) */
.colchart { display: flex; align-items: stretch; margin-top: 6px; }
.colslot { flex: 1; display: flex; flex-direction: column; min-width: 0; padding: 0 8px; }
.colarea { height: 190px; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; border-bottom: 1px solid var(--baseline); }
.colbar { width: 100%; max-width: 26px; background: linear-gradient(180deg, var(--s1), var(--accent)); border-radius: 6px 6px 0 0; }
.colslot:hover .colbar { background: var(--accent); }
.colval { font-size: 11px; color: var(--ink-2); margin-bottom: 5px; white-space: nowrap; }
.collabel { text-align: center; font-size: 12px; color: var(--ink-2); padding-top: 6px; }

.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 860px) { .grid2 { grid-template-columns: 1fr; } }

/* Tooltip */
#tip {
  position: fixed; pointer-events: none; z-index: 50; display: none;
  background: var(--ink-inverse); color: #fff;
  padding: 6px 10px; border-radius: 6px; font-size: 12.5px; max-width: 280px;
  box-shadow: 0 4px 14px rgba(16, 42, 90, 0.25);
}

/* Tables */
table.data { width: 100%; border-collapse: collapse; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: clip; box-shadow: var(--shadow); }
table.data th { text-align: left; font-size: 12px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--accent-deep); padding: 8px 10px; border-bottom: 1px solid var(--grid); background: var(--accent-wash); position: sticky; top: var(--sticky-top); }
table.data td { padding: 7px 10px; border-bottom: 1px solid var(--grid); }
table.data tr:last-child td { border-bottom: none; }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.data tbody tr:hover td { background: var(--accent-wash); }
table.data tfoot td { font-weight: 650; border-top: 2px solid var(--baseline); }
details.tableview { margin-top: 10px; }
details.tableview summary { cursor: pointer; color: var(--ink-2); font-size: 12.5px; }
details.tableview table.data th { position: static; }

/* Steps */
ol.steps { list-style: none; padding: 0; margin: 0; }
ol.steps li { display: flex; align-items: center; gap: 12px; padding: 9px 4px; border-bottom: 1px solid var(--grid); }
ol.steps li:last-child { border-bottom: none; }
.stepno { width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; background: var(--accent-wash); color: var(--accent-deep); flex: none; }
li.done .stepno { background: var(--good-badge); color: #fff; }
li.done .steptitle { color: var(--muted); text-decoration: line-through; }
.steptitle { flex: 1; }
.steplinks { display: flex; gap: 10px; font-size: 12.5px; }

/* Badges, chips, buttons */
.badge { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; border-radius: 999px; padding: 2px 10px; }
.badge.active { background: var(--good-wash); color: var(--good); }
.badge.inactive { background: var(--grid); color: var(--ink-2); }
.badge.open { background: var(--accent-wash); color: var(--accent-deep); }
.badge.completed { background: var(--good-wash); color: var(--good); }
.badge .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

button, .btn {
  font: inherit; font-size: 13px; font-weight: 600;
  background: var(--accent-deep); color: #fff; border: none;
  padding: 7px 14px; border-radius: var(--radius-sm); cursor: pointer;
}
button:hover, .btn:hover { background: var(--accent-deeper); text-decoration: none; }
button.ghost, .btn.ghost { background: transparent; color: var(--accent); border: 1px solid var(--baseline); }
button.ghost:hover, .btn.ghost:hover { background: var(--accent-wash); color: var(--accent-deep); }
button.tiny { padding: 3px 9px; font-size: 12px; }
button.danger { background: transparent; color: var(--critical); border: 1px solid var(--border); }
button.danger:hover { background: var(--critical-wash); }

input, select {
  font: inherit; color: var(--ink); background: var(--surface);
  border: 1px solid var(--baseline); border-radius: 7px; padding: 6px 8px;
}
input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: 0; }
input.cell { width: 72px; padding: 4px 6px; text-align: right; }
form.inline { display: inline; }
.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 14px 0; }
.spacer { flex: 1; }

/* labelled field in a toolbar form (daily attendance entry) */
/* min-width:0 so a long <option> (work order + job name, a supervisor's
   full name) can't force the field wider than its flex-basis and wrap the row */
.fld { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.fld > span { font-size: 12px; font-weight: 600; color: var(--ink-2); }
.fld > input, .fld > select { width: 100%; min-width: 0; }
.skillpick { display: flex; gap: 8px; flex-wrap: wrap; }
.skillbox {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
  border: 1px solid var(--baseline); border-radius: 999px; padding: 4px 11px;
  background: var(--surface);
}
.skillbox:hover { border-color: var(--accent); color: var(--accent-deep); }
.skillbox:has(input:checked) {
  background: var(--accent-wash); border-color: var(--accent); color: var(--accent-deep);
}
.chip {
  display: inline-block; font-size: 12px; font-weight: 600;
  background: var(--accent-wash); color: var(--accent-deep);
  border-radius: 999px; padding: 2px 9px; margin-right: 4px;
}

/* ---- Warning box ----------------------------------------------------------
   Severity is one custom property, so the left rail, the tinted ground and
   the disclosure triangle of a .wcollapse can never disagree — which they
   did, because two call sites overrode border-left-color inline while the
   triangle stayed orange. .crit blocks money moving, the default warns, and
   .info is context that is not a problem at all. */
.warnbox {
  --wb-hue: var(--warn);
  --wb-wash: var(--warn-wash);
  border-left: 3px solid var(--wb-hue); padding: 10px 14px;
  background: var(--surface); border-radius: 0 var(--radius) var(--radius) 0;
  margin: 8px 0; box-shadow: var(--shadow);
}
.warnbox.crit, .warnbox.bad { --wb-hue: var(--critical); --wb-wash: var(--critical-wash); }
.warnbox.info { --wb-hue: var(--accent); --wb-wash: var(--accent-wash); }
.warnbox.good { --wb-hue: var(--good-badge); --wb-wash: var(--good-wash); }
/* .tinted fills the box as well as railing it, for the two or three places
   where severity has to read from across a room rather than up close. */
.warnbox.tinted { background: var(--wb-wash); box-shadow: none; border: 1px solid var(--wb-hue); border-left-width: 3px; }

/* Dashboard sections */
.sec {
  margin-top: 22px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow); padding: 18px 20px 16px;
}
/* flatten nested cards & tiles inside a section card */
.sec .card { border: none; box-shadow: none; padding: 0; background: transparent; }
.sec .tile { box-shadow: none; background: var(--page); border-color: var(--grid); }
.sec a.tile:hover { border-color: var(--accent); box-shadow: var(--shadow-lift); }
.sechead {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  padding-bottom: 7px; margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
}
.sechead h2 { margin: 0; }
.sechead .meta { margin-left: auto; font-size: 12.5px; color: var(--ink-2); }
.sechead a.meta { color: var(--accent); }

.runhead { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.meter { display: inline-flex; align-items: center; gap: 8px; }
.meter .track { width: 110px; height: 6px; border-radius: 999px; background: var(--accent-wash); overflow: hidden; }
.meter .fill { display: block; height: 100%; border-radius: 999px; background: var(--accent); }
.statrow { display: flex; gap: 36px; flex-wrap: wrap; margin: 14px 0 2px; }
.statrow .lbl { display: block; font-size: 12px; color: var(--ink-2); }
.statrow .val { font-size: 20px; font-weight: 650; }
.statrow .delta { display: block; font-size: 12px; }
.card .warnbox { background: var(--page); box-shadow: none; }

/* Register rows needing attention */
table.data tr.attn td { background: var(--critical-wash); }
table.data tbody tr.attn:hover td { background: var(--critical-wash-deep); }
table.data tr.attn td:first-child { box-shadow: inset 3px 0 0 var(--critical); }
/* The second tier the registers were missing: a missing bank account is
   fixable, a wage below the statutory minimum is not — they should not
   shout at the same volume. */
table.data tr.warn td { background: var(--warn-wash); }
table.data tbody tr.warn:hover td { background: var(--warn-wash-deep); }
table.data tr.warn td:first-child { box-shadow: inset 3px 0 0 var(--warn); }
/* An unticked row in a pre-upload checklist: state belongs on the row, not
   only in the button's label. */
table.data tr.untick td:first-child { box-shadow: inset 3px 0 0 var(--warn); }

/* Dashboard tabs */
.tabs { display: flex; gap: 8px; margin: 14px 0 4px; }
.tab { padding: 6px 16px; border-radius: 999px; border: 1px solid var(--border); color: var(--ink-2); font-weight: 600; font-size: 13px; background: var(--surface); }
.tab:hover { text-decoration: none; border-color: var(--accent); color: var(--accent-deep); }
.tab.on { background: var(--accent-deep); border-color: var(--accent-deep); color: #fff; }
.muted { color: var(--muted); }
.small { font-size: 12.5px; }

/* Save nudge (toast) */
#toast {
  position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 12px);
  background: var(--good-badge); color: #fff; font-size: 13px; font-weight: 600;
  padding: 9px 18px; border-radius: 999px;
  box-shadow: 0 4px 14px rgba(16, 42, 90, 0.25);
  opacity: 0; transition: opacity 0.25s, transform 0.25s;
  z-index: 60; pointer-events: none;
}
#toast.show { opacity: 1; transform: translate(-50%, 0); }

/* ---- Popups: one treatment everywhere -------------------------------------
   No drawn edge — a hairline ring plus a deep shadow separates the dialog
   from the blurred page behind it. Size is the only per-dialog choice. */
dialog {
  border: 0; outline: 0;
  border-radius: var(--dialog-radius);
  padding: var(--dialog-pad);
  width: min(var(--dialog-width), 94vw);
  max-width: 94vw; max-height: 86vh; overflow-y: auto;
  background: var(--dialog-bg); color: var(--ink);
  box-shadow: var(--dialog-ring), var(--dialog-shadow);
}
dialog.wide { --dialog-width: var(--dialog-width-wide); }
dialog::backdrop {
  background: var(--dialog-backdrop);
  backdrop-filter: blur(var(--dialog-blur));
  -webkit-backdrop-filter: blur(var(--dialog-blur));
}
dialog h2 { margin-top: 0; }
/* the line under a dialog title, when it has one */
dialog h2 + p.small { margin-top: -4px; }
/* the action row always sits on a divider, so every popup ends the same way */
dialog form > .toolbar:last-child {
  margin-top: var(--space-5); padding-top: var(--space-3);
  border-top: 1px solid var(--grid);
}
/* inside a dialog the page header offset doesn't exist — table headers
   stick to the top of their own scroll container */
dialog table.data th { top: 0; }
dialog .data { box-shadow: none; }

/* Clickable worker-picker menu (inside dialogs) */
.wpick-menu {
  position: absolute; left: 0; top: 100%; z-index: 80;
  min-width: 260px; max-height: 220px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-pop);
}
.wpick-item { padding: 7px 11px; cursor: pointer; font-size: 13px; }
.wpick-item:hover { background: var(--accent-wash); color: var(--accent-deep); }

/* Collapsible month cards on the runs page */
/* The collapsible card. Payroll runs use it per year; R2 reuses it for its
   two register panels, which is why the rule carries both names — the class
   was called .month-group before the runs page grouped by year, and R2 was
   never about months at all. */
details.year-group, details.month-group {
  margin: 14px 0; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow); padding: 2px 16px;
}
details.year-group[open], details.month-group[open] { padding-bottom: 14px; }
details.year-group:hover, details.month-group:hover { border-color: var(--accent); }
details.year-group > summary, details.month-group > summary {
  cursor: pointer; display: flex; align-items: baseline; gap: 12px;
  padding: 12px 2px; list-style: none; user-select: none; flex-wrap: wrap;
}
details.year-group > summary::-webkit-details-marker,
details.month-group > summary::-webkit-details-marker { display: none; }
details.year-group > summary::before, details.month-group > summary::before {
  content: "\25B8"; color: var(--accent); font-size: 13px;
  transition: transform 0.15s; display: inline-block;
}
details.year-group[open] > summary::before,
details.month-group[open] > summary::before { transform: rotate(90deg); }
details.month-group > summary .mg-title {
  font-size: 15px; font-weight: 650; color: var(--accent-deep);
}
/* The year reads larger than a panel title: it is the thing you navigate by. */
details.year-group > summary .yg-title {
  font-size: 19px; font-weight: 700; color: var(--accent-deep);
  font-variant-numeric: tabular-nums;
}
/* The facts read as one line of consequence, separated rather than boxed. */
.yg-facts {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 14px;
  font-size: 12.5px; color: var(--muted);
}
.yg-facts > span { white-space: nowrap; }
.yg-facts .yg-paid { color: var(--ink-2); font-weight: 600; }
details.year-group > table, details.month-group > table { margin-top: 6px; box-shadow: none; }

/* A month heading inside the year's table — only drawn when the month has
   more than one payment run, so it never merely repeats a run's own label. */
tr.monthrow td {
  background: var(--accent-wash);
  font-weight: 650; color: var(--accent-deep);
  padding-top: 10px; padding-bottom: 6px;
}

/* Custom-FedOne wizard step crumbs */
.fw-crumbs { display: flex; gap: 8px; align-items: center; margin: 4px 0 6px; }
.fw-crumb { color: var(--ink-2); font-weight: 600; }
.fw-crumb.on { color: var(--accent-deep); }

/* Vertical tabs (R2: Wage register | PF | ESIC) */
.vtabs { display: grid; grid-template-columns: 140px minmax(0, 1fr); gap: 18px; align-items: start; margin-top: 14px; }
.vtab-rail { display: flex; flex-direction: column; gap: 4px; position: sticky; top: var(--rail-top); }
.vtab-rail button {
  text-align: left; padding: 9px 12px; border: 1px solid transparent; background: none;
  border-radius: 8px; color: var(--ink-2); cursor: pointer; font: inherit; font-weight: 600;
}
.vtab-rail button:hover { color: var(--accent-deep); background: var(--accent-wash); }
.vtab-rail button.on {
  background: var(--surface); border-color: var(--accent);
  color: var(--accent-deep); box-shadow: var(--shadow);
}
.vtab-rail button .small { display: block; font-weight: 500; color: var(--ink-2); }
.vtab-pane { display: none; min-width: 0; }
.vtab-pane.on { display: block; }
/* One media query for the rail, not two 90 lines apart. */
@media (max-width: 900px) {
  .vtabs, #ovtabs { grid-template-columns: 1fr; }
  /* Same reasoning as .htabs above: once the rail turns horizontal it needs a
     track, or the unselected tabs read as loose text. */
  .vtab-rail {
    flex-direction: row; position: static; flex-wrap: wrap;
    gap: 2px; padding: 4px; width: fit-content; max-width: 100%;
    background: var(--grid); border-radius: var(--radius-lg);
  }
  .vtab-rail button { border-color: transparent; }
  .vtab-rail button.on {
    background: var(--surface); border-color: var(--border); box-shadow: var(--shadow);
  }
}

/* by-work-order breakdown: W.O. sum rows expand to per-worker rows */
tr.wo-row td { cursor: pointer; background: var(--accent-wash); font-weight: 600; user-select: none; }
tr.wo-row .wo-arrow {
  display: inline-block; margin-right: 8px; color: var(--accent);
  font-size: 11px; transition: transform 0.15s;
}
tr.wo-row.open .wo-arrow { transform: rotate(90deg); }
tr.wo-line td:first-child { padding-left: 36px; }

/* Collapsible warning boxes with individual problem lines */
details.wcollapse > summary { cursor: pointer; list-style: none; user-select: none; }
details.wcollapse > summary::before {
  content: "▸"; color: var(--warn); margin-right: 6px; display: inline-block;
  transition: transform 0.15s;
}
details.wcollapse[open] > summary::before { transform: rotate(90deg); }
.wlist { margin: 8px 0 2px; padding-left: 26px; }
.wlist li { padding: 2px 0; }

/* compact table inside a warning box */
.wtable { border-collapse: collapse; margin: 10px 0 4px 22px; font-size: 13px; }
.wtable th {
  text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px;
  color: var(--ink-2); font-weight: 600; padding: 3px 22px 5px 0; border-bottom: 1px solid var(--grid);
}
.wtable td { padding: 4px 22px 4px 0; border-bottom: 1px solid var(--grid); }
.wtable tr:last-child td { border-bottom: none; }
.wtable td.num, .wtable th.num { text-align: right; font-variant-numeric: tabular-nums; }
.wtable td.num strong { color: var(--warn-deep); }

/* keep the wide register table inside the page column */
table.regtable th, table.regtable td { padding-left: 6px; padding-right: 6px; }
table.regtable th:first-child, table.regtable td:first-child { padding-left: 10px; }
table.regtable th:last-child, table.regtable td:last-child { padding-right: 10px; }

/* Daily tracker: the two equally-weighted ways to add attendance */
.entry-modes { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
.entry-mode {
  display: flex; flex-direction: column; gap: 4px; align-items: flex-start;
  text-align: left; padding: 16px 18px; cursor: pointer; font: inherit;
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  box-shadow: var(--shadow); color: var(--ink);
}
.entry-mode:hover { border-color: var(--accent); background: var(--accent-wash); }
.entry-mode .em-title { font-size: 15px; font-weight: 650; color: var(--accent-deep); }
.entry-mode .em-sub { font-size: 12.5px; color: var(--ink-2); font-weight: 400; }

/* A dialog that is mostly a list to fill in (the by-work-order wizard) */
.rowlist { max-height: 52vh; overflow-y: auto; padding: 2px; }
.rowlist .wrow { margin: 0 0 8px; }

/* Overview: alert chips above the tab rail */
.chiprow { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.alertchip {
  font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
  padding: 6px 12px; border-radius: 999px;
  background: var(--accent-wash); color: var(--accent-deep);
  border: 1px solid var(--border);
}
.alertchip.crit { background: var(--critical-wash); color: var(--critical-ink); border-color: var(--critical-line); }
.alertchip.warn { background: var(--warn-wash); color: var(--warn-ink); border-color: var(--warn-line); }
/* Chips are buttons, so they inherit button:hover — which paints the base
   accent and left the dark label unreadable on it. Each variant states its
   own hover: deepen the chip's own tint, never turn it into a primary. */
.alertchip:hover, .alertchip:focus-visible {
  background: var(--accent-wash-deep); color: var(--accent-deep); border-color: var(--accent);
}
.alertchip.crit:hover, .alertchip.crit:focus-visible {
  background: var(--critical-wash-deep); color: var(--critical-ink-deep); border-color: var(--critical-line);
}
.alertchip.warn:hover, .alertchip.warn:focus-visible {
  background: var(--warn-wash-deep); color: var(--warn-deep); border-color: var(--warn-line);
}

/* Overview tab rail: labels are longer than R2's, and must wrap on narrow screens */
#ovtabs { grid-template-columns: 178px minmax(0, 1fr); }
#ovtabs .vtab-pane > .sec:first-child,
#ovtabs .vtab-pane > section:first-child { margin-top: 0; }
.vtab-rail .small.crit { color: var(--critical); font-weight: 600; }

/* R2: workers with R1 attendance who are not in the register yet */
.suggestbox { margin: 0 0 12px; padding: 10px 12px; background: var(--accent-wash);
  border: 1px solid var(--border); border-radius: var(--radius-lg); }
.suggestbox > summary { cursor: pointer; font-size: 13px; color: var(--ink-2); }
.alertchip.sugg { background: var(--surface); font-weight: 500; }
.alertchip.sugg:hover { background: var(--accent); color: #fff; }
.alertchip.sugg:hover .muted { color: var(--seq-0); }

/* Horizontal variant of the tab rail (Workers: analytics | list) */
.vtabs.htabs { grid-template-columns: 1fr; gap: 12px; }
/* Laid out in a row, the rail needs a track. Vertically the buttons read as a
   list because they are stacked and aligned; in a row, with only the selected
   one carrying a border, the rest are just words sitting on the page and do
   not look clickable at all. The track is what says "these are one control". */
.vtabs.htabs .vtab-rail {
  flex-direction: row; position: static; flex-wrap: wrap;
  gap: 2px; padding: 4px; align-self: start;
  width: fit-content; max-width: 100%;
  background: var(--grid);
  border-radius: var(--radius-lg);
}
.vtabs.htabs .vtab-rail button { border-color: transparent; }
.vtabs.htabs .vtab-rail button:hover { background: var(--accent-wash); }
/* The selected segment lifts out of the track rather than being merely tinted. */
.vtabs.htabs .vtab-rail button.on {
  background: var(--surface); border-color: var(--border);
  box-shadow: var(--shadow);
}
.vtabs.htabs .vtab-rail button .small { display: inline; margin-left: 4px; color: var(--ink-2); }

/* Donut + legend */
.donutwrap { display: flex; gap: 20px; align-items: center; flex-wrap: wrap; }
.donutkey { list-style: none; margin: 0; padding: 0; flex: 1 1 190px; }
/* A legend row can carry a secondary line (the count behind a value share),
   so the label column stacks while the value stays right-aligned at the top. */
.donutkey li { display: flex; align-items: flex-start; gap: 8px; padding: 4px 0; font-size: 13px; }
.donutkey .sw { width: 11px; height: 11px; border-radius: 3px; flex: none; margin-top: 2px; }
.donutkey .k { color: var(--ink); display: flex; flex-direction: column; line-height: 1.25; }
.donutkey .k .small { font-size: 11.5px; }
.donutkey .v { margin-left: auto; padding-top: 1px; font-variant-numeric: tabular-nums; font-weight: 600; }
/* SVG presentation attributes cannot resolve var(), so the donut's centre
   type takes classes instead of fill="#…". */
.donutwrap .dnum { fill: var(--ink); }
.donutwrap .dcap { fill: var(--ink-2); }
.donutwrap .dnote { fill: var(--muted); }

.suggestbox.quiet { background: var(--page); border-style: dashed; margin-top: -4px; }
.suggestbox.quiet > summary { color: var(--ink-2); }

/* A bar that has crossed its target reads as an alert, not a series colour */
.cbar.over { background: var(--critical); }

/* ---- Company (MDEsthappan) vs platform (hisaab) ---------------------------
   The product mark brands the chrome; the company mark identifies whose
   books these are, so it sits with the account and in the footer — never
   competing with the hisaab lockup. */
header.top .tenant { display: inline-flex; align-items: center; opacity: 0.85; }
header.top .tenant img { display: block; }
header.top .tenant:hover { opacity: 1; }
.sitefoot {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 40px 0 0; padding-top: 14px; border-top: 1px solid var(--grid);
  font-size: var(--text-sm); color: var(--ink-2);
}
.sitefoot .sep { color: var(--baseline); }
.loginfoot {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--grid);
}
.loginfoot .co { font-weight: 650; color: var(--ink); font-size: 13px; }

/* Grid and flex items default to min-width:auto, so a wide table inside a
   tab pane stretches the pane instead of scrolling within it. */
.vtabs > *, .vtab-body, .vtab-pane, .grid2 > * { min-width: 0; }

/* ============================================================================
   Small screens
   The header, the pill tabs and the wide data tables were all laid out as
   single non-wrapping rows, so on a phone they pushed the page ~660px wider
   than the viewport and every screen scrolled sideways. Each one now either
   wraps or scrolls inside itself.
   ========================================================================= */
@media (max-width: 760px) {
  main { padding: 16px 14px 56px; }

  /* Header: brand and account stay put, the nav scrolls under them */
  header.top { flex-wrap: wrap; gap: 10px 14px; padding: 10px 14px; }
  header.top nav {
    order: 10; flex: 1 0 100%;
    gap: 14px; overflow-x: auto; scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  header.top nav::-webkit-scrollbar { display: none; }
  header.top nav a { white-space: nowrap; }
  header.top .spacer { display: none; }

  /* Pill tabs scroll rather than stretch the page */
  .tabs {
    overflow-x: auto; flex-wrap: nowrap; scrollbar-width: none;
    padding-bottom: 2px; -webkit-overflow-scrolling: touch;
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tab { white-space: nowrap; flex: none; }

  /* Wide registers scroll within their own box, not the document */
  table.data { display: block; overflow-x: auto; white-space: nowrap; }
  table.data th { position: static; }   /* sticky + block scroll fight */

  /* Toolbars of filters stack instead of running off the edge */
  .toolbar { gap: 8px; }
  .toolbar input, .toolbar select { max-width: 100%; }

  /* Charts and the flow diagram get their own scroll box */
  .colchart, .donutwrap { overflow-x: auto; }

  .tiles { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
  .sitefoot { margin-top: 28px; }
}

/* ---- Account menu ---------------------------------------------------------
   The signed-in name is the control; sign-out and user admin live under it
   so the header stops carrying two extra items. */
.acct { position: relative; flex: none; }
.acct > summary {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  list-style: none; padding: 5px 10px; border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--surface);
  font-size: var(--text-sm); color: var(--ink-2);
}
.acct > summary::-webkit-details-marker { display: none; }
.acct > summary:hover { border-color: var(--accent); color: var(--accent-deep); }
.acct .who { font-weight: 650; color: var(--ink); }
.acct .role { color: var(--muted); }
.acct .caret { color: var(--muted); font-size: 10px; }
.acct[open] > summary { border-color: var(--accent); }
.acct-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  min-width: 210px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-pop);
}
.acct-head { padding: 8px 10px 10px; border-bottom: 1px solid var(--grid); margin-bottom: 6px; }
.acct-head .who { font-size: 13.5px; }
.acct-menu a, .acct-menu .linkish {
  display: block; width: 100%; text-align: left; padding: 8px 10px;
  border-radius: var(--radius-sm); font-size: 13px; color: var(--ink);
  background: none; border: 0; cursor: pointer; font-family: inherit;
}
.acct-menu a:hover, .acct-menu .linkish:hover {
  background: var(--accent-wash); color: var(--accent-deep); text-decoration: none;
}
.acct-menu a.on { color: var(--accent-deep); font-weight: 600; }

/* Run kind chooser: two mutually exclusive cards inside the start dialog */
.runkind { border: 0; padding: 0; margin: 14px 0 4px; display: grid; gap: 8px; }
.runkind legend { padding: 0 0 6px; }
.runkind .kind {
  display: flex; gap: 10px; align-items: flex-start; cursor: pointer;
  padding: 11px 13px; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--surface);
}
.runkind .kind:hover { border-color: var(--accent); background: var(--accent-wash); }
.runkind .kind span { display: flex; flex-direction: column; gap: 2px; }
.runkind .kind:has(input:checked) { border-color: var(--accent); background: var(--accent-wash); }

/* ---- Multi-select filter ---------------------------------------------------
   Looks like the other filter controls; opens a checkbox panel and applies
   once, on close, so picking three designations is one page load not three. */
.msel { position: relative; display: inline-block; }
.msel > summary {
  list-style: none; cursor: pointer; white-space: nowrap;
  padding: 6px 26px 6px 11px; border: 1px solid var(--baseline);
  border-radius: var(--radius); background: var(--surface);
  font-size: 13px; color: var(--ink);
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
.msel > summary::-webkit-details-marker { display: none; }
.msel > summary:hover { border-color: var(--accent); }
.msel > summary.on { border-color: var(--accent); color: var(--accent-deep); font-weight: 600; }
.msel[open] > summary { border-color: var(--accent); }
.msel-menu {
  position: absolute; left: 0; top: calc(100% + 5px); z-index: 45;
  min-width: 210px; max-height: 300px; overflow-y: auto; padding: 8px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-pop);
}
.msel-menu label {
  display: flex; align-items: center; gap: 8px; padding: 5px 7px;
  border-radius: var(--radius-sm); font-size: 13px; cursor: pointer;
  white-space: nowrap;
}
.msel-menu label:hover { background: var(--accent-wash); }
.msel-actions {
  display: flex; gap: 8px; justify-content: flex-end;
  margin-top: 6px; padding-top: 8px; border-top: 1px solid var(--grid);
  position: sticky; bottom: -8px; background: var(--surface);
}

.msel-find {
  width: 100%; margin: 0 0 6px; padding: 6px 9px; font-size: 13px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  position: sticky; top: -8px; background: var(--surface); z-index: 1;
}

/* ---- Landing pulse: how the company is running, across domains -------------
   Deliberately not a money headline — people, work orders and invoices side
   by side, each with one lead figure and its supporting rows. */
.pulsegrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 14px; }
.pblock {
  padding: 14px 16px; border: 1px solid var(--border);
  border-radius: var(--radius-lg); background: var(--surface);
}
.pblock .ptitle {
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent-deep); font-weight: 700; margin-bottom: 8px;
}
.pblock .pmain { font-size: 26px; font-weight: 700; color: var(--ink); line-height: 1.1; }
.pblock .punit { font-size: 13px; font-weight: 500; color: var(--ink-2); }
.pblock .pdelta { font-size: 12.5px; margin: 2px 0 10px; }
.pblock .pdelta.up { color: var(--good); }
.pblock .pdelta.down { color: var(--critical); }
.pblock .pdelta.muted { color: var(--muted); }
.pblock .prow {
  display: flex; justify-content: space-between; gap: 10px;
  font-size: 13px; color: var(--ink-2); padding: 3px 0;
}
.pblock .prow strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.pblock .prow strong.bad { color: var(--critical); }
.pblock a.small { display: inline-block; margin-top: 8px; }
.spread { display: flex; gap: 2px; margin: 10px 0 4px; height: 22px; }
.spread .seg {
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; color: #fff; border-radius: 4px; min-width: 18px;
}
/* The four attendance bands are magnitude, not identity, so they take the
   sequential ramp. White clears AA only on the two deepest steps — the old
   step 2 carried white at 2.99:1 on the largest band of workers. */
.spread .s1 { background: var(--seq-5); }
.spread .s2 { background: var(--seq-4); }
.spread .s3 { background: var(--seq-2); color: var(--ink); }
.spread .s4 { background: var(--seq-0); color: var(--ink-2); }

/* ---------------------------------------------------------------------------
   Landing band — the first thing anyone sees. Deep brand panel, the four
   figures that say how big the operation is and whether it is healthy.
   ------------------------------------------------------------------------ */
.lander {
  margin-top: 16px; border-radius: var(--radius-xl); color: #fff;
  padding: 22px 26px 6px;
  background:
    radial-gradient(120% 140% at 88% -20%, rgba(46, 139, 255, 0.55) 0%, rgba(46, 139, 255, 0) 55%),
    radial-gradient(90% 120% at 8% 120%, rgba(63, 195, 148, 0.30) 0%, rgba(63, 195, 148, 0) 60%),
    linear-gradient(135deg, var(--on-dark-bg-1) 0%, var(--on-dark-bg-2) 55%, var(--on-dark-bg-3) 100%);
  box-shadow: 0 18px 44px -22px rgba(10, 31, 56, 0.7);
  overflow: hidden; position: relative;
}
.lander::after {                       /* faint blueprint rule, purely texture */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px);
  background-size: 100% 34px; opacity: 0.8;
}
.lander-top { display: flex; align-items: flex-start; gap: 18px; flex-wrap: wrap; }
.lander .eyebrow {
  font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--brand-accent-soft); font-weight: 700;
}
.lander h1 {
  font-family: var(--font-brand); font-size: 30px; line-height: 1.1;
  margin: 6px 0 4px; color: #fff;
}
.lander .lander-sub { color: var(--on-dark-ink); font-size: 13.5px; margin: 0; max-width: 62ch; }
.lander .lander-cta {
  margin-left: auto; flex: none; color: #fff; font-size: 13px; font-weight: 600;
  border: 1px solid rgba(255, 255, 255, 0.28); border-radius: var(--radius-pill);
  padding: 8px 16px; background: var(--on-dark-fill); white-space: nowrap;
}
.lander .lander-cta:hover { background: rgba(255, 255, 255, 0.18); text-decoration: none; }
.lander-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
  gap: 2px 0; margin-top: 18px; position: relative; z-index: 1;
}
.hstat { padding: 14px 20px 16px; border-left: 1px solid var(--on-dark-rule); }
.hstat:first-child { border-left: none; padding-left: 0; }
.hstat .hlbl {
  font-size: 11px; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--on-dark-muted); font-weight: 600;
}
.hstat .hval {
  font-size: 27px; font-weight: 700; line-height: 1.15; margin-top: 5px;
  font-variant-numeric: tabular-nums;
}
.hstat .hval .hunit { font-size: 13px; font-weight: 500; color: var(--on-dark-ink); }
.hstat .hnote { font-size: 12px; color: var(--on-dark-muted); margin-top: 3px; }
.hstat .hnote.up { color: var(--on-dark-up); }
.hstat .hnote.down { color: var(--on-dark-down); }
.hbars { display: flex; align-items: flex-end; gap: 2px; height: 26px; margin-top: 9px; }
.hbars span {
  flex: 1; min-width: 2px; border-radius: 2px 2px 0 0;
  background: rgba(127, 187, 255, 0.45);
}
.hbars span.last { background: var(--brand-accent); }
@media (max-width: 700px) {
  .lander { padding: 18px 18px 4px; }
  .lander h1 { font-size: 24px; }
  .hstat { border-left: none; padding: 10px 0 12px;
           border-top: 1px solid var(--on-dark-rule); }
  .hstat:first-child { border-top: none; }
}

/* ---------------------------------------------------------------------------
   Revenue vs wage cost — grouped columns, one rupee axis, margin underneath.
   ------------------------------------------------------------------------ */
.rcchart { display: flex; align-items: stretch; gap: 5px; margin-top: 4px; }
.rcslot { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.rcarea {
  height: 176px; display: flex; align-items: flex-end; justify-content: center;
  gap: 2px; border-bottom: 1px solid var(--baseline);
}
.rcbar { width: 46%; max-width: 19px; border-radius: 3px 3px 0 0; min-height: 2px; }
/* Revenue and cost are series 1 and 2 — the same two hues the batches chart
   and the payout composition bar use, rather than a private pair. */
.rcbar.rev { background: linear-gradient(180deg, var(--s1-lo), var(--s1-hi)); }
.rcbar.cost { background: linear-gradient(180deg, var(--s2-lo), var(--s2-hi)); }
.rcslot:hover .rcarea { background: var(--accent-wash); }
.rclabel {
  text-align: center; font-size: 11.5px; color: var(--ink-2); padding-top: 6px;
  white-space: nowrap; overflow: hidden;
}
.rcyear { text-align: center; font-size: 10px; color: var(--muted); }
.rcpct {
  text-align: center; font-size: 11px; font-weight: 700; padding: 4px 0 0;
  font-variant-numeric: tabular-nums;
}
.rcpct.up { color: var(--good); }
.rcpct.down { color: var(--critical); }
.rcpct.none { color: var(--muted); font-weight: 500; }
.rclegend { display: flex; gap: 16px; flex-wrap: wrap; margin: 12px 0 0; font-size: 12.5px; }
.rclegend .sw { width: 11px; height: 11px; border-radius: 3px; display: inline-block; margin-right: 6px; }
.rclegend .sw.rev { background: var(--s1); }
.rclegend .sw.cost { background: var(--s2); }

/* Small multiples — one metric each, sharing the month axis */
.smgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; }
.smcard {
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: 13px 15px 11px; background: var(--surface);
}
.smcard .smtitle {
  font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--accent-deep); font-weight: 700;
}
.smcard .smval { font-size: 24px; font-weight: 700; margin-top: 5px; font-variant-numeric: tabular-nums; }
.smcard .smval .smunit { font-size: 12.5px; font-weight: 500; color: var(--ink-2); }
.smcard .smchg { font-size: 12px; margin-top: 1px; }
.smcard .smchg.up { color: var(--good); }
.smcard .smchg.down { color: var(--critical); }
.smbars { display: flex; align-items: flex-end; gap: 3px; height: 52px; margin-top: 10px;
          border-bottom: 1px solid var(--grid); }
.smbars a { flex: 1; min-width: 3px; border-radius: 3px 3px 0 0; background: var(--seq-0); }
.smbars a:last-child { background: var(--accent); }
.smbars a:hover { background: var(--accent-deep); }
.smcard .smhint { font-size: 11.5px; color: var(--muted); margin: 8px 0 0; }
.smaxis { display: flex; gap: 3px; margin-top: 4px; }
.smaxis span { flex: 1; min-width: 3px; text-align: center; font-size: 10.5px; color: var(--ink-2); }

/* Bullet ladder — order value is the track, wage cost the fill, target a tick */
.ladder { display: flex; flex-direction: column; gap: 13px; margin-top: 2px; }
.blt .bhead { display: flex; align-items: baseline; gap: 8px; font-size: 13px; }
.blt .bhead .bjob { color: var(--muted); font-size: 12px; overflow: hidden;
                    text-overflow: ellipsis; white-space: nowrap; }
.blt .bhead .bpct { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.blt .bhead .bpct.hot { color: var(--critical); }
/* overflow:hidden used to live on the track, which cropped the very tick
   the chart is explained by. The fill rounds itself instead, and the tick
   carries a surface outline so it survives any fill under it. */
.btrack {
  position: relative; height: 15px; border-radius: 4px; margin-top: 5px;
  background: var(--grid);
}
.bfill { position: absolute; inset: 0 auto 0 0; border-radius: 4px; overflow: hidden;
         background: linear-gradient(90deg, var(--s1-lo), var(--s1-hi)); }
/* Past target is a status, not a warmer series — flat critical, no ramp. */
.bfill.hot { background: var(--critical); }
.bmark { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--ink);
         border-radius: 1px; outline: 1px solid var(--surface); z-index: 1; }
.blt .bfoot { display: flex; gap: 10px; flex-wrap: wrap; font-size: 11.5px;
              color: var(--muted); margin-top: 4px; }

/* ---------------------------------------------------------------------------
   Order-book timeline — every live work order on one time axis, with today
   marked. Bars clipped to the window; the tooltip carries the true dates.
   ------------------------------------------------------------------------ */
.tl { margin-top: 4px; }
.tlhead, .tlrow { display: grid; grid-template-columns: 128px 1fr; gap: 12px; align-items: center; }
.tlrow { padding: 2px 0; }
.tlrow:hover .tltrack { background: var(--accent-wash); }
.tlname {
  font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.tltrack { position: relative; height: 15px; border-radius: 3px; background: var(--page); }
.tltrack .tlgrid { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--grid); }
.tltrack .tlnow { position: absolute; top: -1px; bottom: -1px; width: 2px; background: var(--ink);
                  opacity: 0.55; }
.tlbar { position: absolute; top: 3px; height: 9px; border-radius: 5px; min-width: 5px; }
.tlbar.clipl { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.tlbar.clipr { border-top-right-radius: 0; border-bottom-right-radius: 0; }
/* Past its end date. Deliberately NOT a third colour: red beside the amber of
   "on extension" fails the palette checker under deuteranopia, and those are
   the two states this chart exists to separate. The bar keeps its status hue
   and takes a hatch plus a hard outline, which no colour vision can wash out. */
.tlbar.late {
  background-image: repeating-linear-gradient(135deg,
    rgba(255, 255, 255, 0.75) 0 2px, rgba(255, 255, 255, 0) 2px 5px);
  outline: 1.5px solid var(--critical);
  outline-offset: -1px;
}
.sw.late {
  background: var(--cat-2);
  background-image: repeating-linear-gradient(135deg,
    rgba(255, 255, 255, 0.75) 0 2px, rgba(255, 255, 255, 0) 2px 5px);
  outline: 1.5px solid var(--critical);
  outline-offset: -1px;
}
.tlaxis { position: relative; height: 17px; font-size: 11px; color: var(--ink-2); }
.tlaxis span { position: absolute; transform: translateX(-50%); white-space: nowrap; }
.tlaxis span.now { color: var(--ink); font-weight: 700; }
.tlrows { max-height: 430px; overflow-y: auto; padding-right: 2px; }
.tllegend { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 12px; font-size: 12.5px; }
.tllegend .sw { width: 11px; height: 11px; border-radius: 3px; display: inline-block; margin-right: 6px; }
@media (max-width: 700px) {
  .tlhead, .tlrow { grid-template-columns: 92px 1fr; gap: 8px; }
  .tlname { font-size: 11px; }
}

/* ============================================================================
   DOMAIN ACCENTS — which part of the business you are standing in
   ----------------------------------------------------------------------------
   Put ONE of these classes high on the page (on <main>, or on the outermost
   section) and everything below it picks up that area's hue: the section
   heading, the table header row, the eyebrow, the selected row. Nothing
   downstream needs a second class, and a page with no domain class renders
   exactly as it did before — every reader below falls back to the accent.

   Tokens: see tokens.css section 3b. Chrome only; never a chart mark.
   ========================================================================= */
.dom-payroll {
  --dom: var(--dom-payroll); --dom-wash: var(--dom-payroll-wash);
  --dom-line: var(--dom-payroll-line); --dom-ink: var(--dom-payroll-ink);
}
.dom-attendance {
  --dom: var(--dom-attendance); --dom-wash: var(--dom-attendance-wash);
  --dom-line: var(--dom-attendance-line); --dom-ink: var(--dom-attendance-ink);
}
.dom-invoices {
  --dom: var(--dom-invoices); --dom-wash: var(--dom-invoices-wash);
  --dom-line: var(--dom-invoices-line); --dom-ink: var(--dom-invoices-ink);
}
.dom-workorders {
  --dom: var(--dom-workorders); --dom-wash: var(--dom-workorders-wash);
  --dom-line: var(--dom-workorders-line); --dom-ink: var(--dom-workorders-ink);
}
.dom-people {
  --dom: var(--dom-people); --dom-wash: var(--dom-people-wash);
  --dom-line: var(--dom-people-line); --dom-ink: var(--dom-people-ink);
}

/* The readers. Each falls back to the blue the app used before, so these
   rules are invisible until a page opts in. */
h1 { color: var(--dom-ink, var(--accent-deep)); }
h2 { color: var(--dom-ink, var(--accent-deep)); }
.sechead { border-bottom-color: var(--dom-line, var(--border)); }
table.data th {
  background: var(--dom-wash, var(--accent-wash));
  color: var(--dom-ink, var(--accent-deep));
}
table.data tr.sel td { background: var(--dom-wash, var(--accent-wash)); }
table.data tr.sel td:first-child { box-shadow: inset 3px 0 0 var(--dom, var(--accent)); }
/* Opt-in section rail: an inset shadow rather than a border, so adding it
   never moves the content 3px sideways. */
.sec.railed { box-shadow: var(--shadow), inset 3px 0 0 var(--dom, var(--accent)); }
.card.railed { box-shadow: var(--shadow), inset 3px 0 0 var(--dom, var(--accent)); }

/* The uppercase micro-label, previously spelled six ways (.ptitle, .smtitle,
   .eyebrow, .hlbl, two table th rules) at four letter-spacings. One class. */
.eyebrow {
  font-size: var(--text-xs); letter-spacing: 0.13em; text-transform: uppercase;
  font-weight: 700; color: var(--dom-ink, var(--accent-deep));
}
.eyebrow.quiet { color: var(--muted); font-weight: 600; }
.eyebrow.on-dark { color: var(--brand-accent-soft); letter-spacing: 0.16em; }

/* ============================================================================
   PAYROLL STAGE HUES — where a rupee is in the month
   ----------------------------------------------------------------------------
   R1 is the wage the month earned; R2, R3, staff, PF, ESIC and advances are
   what it is cut into. One class sets the hue, its wash, its edge and its
   ink; the surface rules below read them. Put the SAME class on the tile,
   the bar segment, the legend swatch and the step circle and the reader only
   has to learn the colour once.

   .stage-src is an alias for R1: the source figure, drawn as the track the
   other stages fill rather than as another payment.
   ========================================================================= */
.stage-r1, .stage-src {
  --stage: var(--stage-r1); --stage-wash: var(--stage-r1-wash);
  --stage-line: var(--stage-r1-line); --stage-ink: var(--stage-r1-ink);
}
.stage-r2 {
  --stage: var(--stage-r2); --stage-wash: var(--stage-r2-wash);
  --stage-line: var(--stage-r2-line); --stage-ink: var(--stage-r2-ink);
}
.stage-r3 {
  --stage: var(--stage-r3); --stage-wash: var(--stage-r3-wash);
  --stage-line: var(--stage-r3-line); --stage-ink: var(--stage-r3-ink);
}
.stage-staff {
  --stage: var(--stage-staff); --stage-wash: var(--stage-staff-wash);
  --stage-line: var(--stage-staff-line); --stage-ink: var(--stage-staff-ink);
}
.stage-pf {
  --stage: var(--stage-pf); --stage-wash: var(--stage-pf-wash);
  --stage-line: var(--stage-pf-line); --stage-ink: var(--stage-pf-ink);
}
.stage-esic {
  --stage: var(--stage-esic); --stage-wash: var(--stage-esic-wash);
  --stage-line: var(--stage-esic-line); --stage-ink: var(--stage-esic-ink);
}
.stage-adv {
  --stage: var(--stage-adv); --stage-wash: var(--stage-adv-wash);
  --stage-line: var(--stage-adv-line); --stage-ink: var(--stage-adv-ink);
}

/* A stat tile that belongs to a stage wears a 3px rail in that stage's hue,
   matching the segment of the composition bar it corresponds to. */
.tile.stage-r1, .tile.stage-src, .tile.stage-r2, .tile.stage-r3,
.tile.stage-staff, .tile.stage-pf, .tile.stage-esic, .tile.stage-adv {
  border-left: 3px solid var(--stage); padding-left: 11px;
}
/* Bar segments, bars and legend swatches. */
.compobar .seg.stage-r1, .compobar .seg.stage-r2, .compobar .seg.stage-r3,
.compobar .seg.stage-staff, .compobar .seg.stage-pf, .compobar .seg.stage-esic,
.compobar .seg.stage-adv { background: var(--stage); }
.cbar.stage-r1, .cbar.stage-r2, .cbar.stage-r3, .cbar.stage-staff,
.cbar.stage-pf, .cbar.stage-esic, .cbar.stage-adv { background: var(--stage); }
.sw.stage-r1, .sw.stage-r2, .sw.stage-r3, .sw.stage-staff,
.sw.stage-pf, .sw.stage-esic, .sw.stage-adv { background: var(--stage); }
.colbar.stage-r1, .colbar.stage-r2, .colbar.stage-r3, .colbar.stage-staff,
.colbar.stage-pf, .colbar.stage-esic, .colbar.stage-adv { background: var(--stage); }
/* A pill naming a stage: its own wash, its own ink, never a status hue. */
.badge.stage-r1, .badge.stage-r2, .badge.stage-r3, .badge.stage-staff,
.badge.stage-pf, .badge.stage-esic, .badge.stage-adv,
.chip.stage-r1, .chip.stage-r2, .chip.stage-r3, .chip.stage-staff,
.chip.stage-pf, .chip.stage-esic, .chip.stage-adv {
  background: var(--stage-wash); color: var(--stage-ink);
}
/* A ghost bar: what the register says is due but nothing has paid yet. */
.cbar.planned, .colbar.planned {
  background: var(--stage, var(--s1)); opacity: 0.3;
  outline: 1px dashed var(--stage, var(--baseline)); outline-offset: -1px;
}

/* ============================================================================
   PAGE FURNITURE — every page starts the same way
   ========================================================================= */
/* Title block with a right-aligned action. Five templates hand-rolled the
   identical inline flex for this, each with its own margin on the button. */
.pagehead {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--space-4); flex-wrap: wrap;
}
.pagehead > .ph-main { min-width: 0; flex: 1 1 340px; }
.pagehead h1 { margin-top: 0; }
.pagehead .sub { margin-bottom: 10px; }
.pagehead .ph-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
.pagehead > .btn, .pagehead > button { margin-top: 10px; }
/* The status badge and the domain chips that sit beside a title. */
.pagehead .badge, .pagehead .chip { vertical-align: 3px; }

/* Back-link above a title. Six templates wrote this as a .sub paragraph with
   an inline margin, which read as orphaned prose rather than navigation. */
.crumb {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--text-sm); color: var(--ink-2); margin: 0 0 2px;
}
.crumb::before { content: "←"; color: var(--dom, var(--accent)); }
.crumb a { color: var(--ink-2); }
.crumb a:hover { color: var(--dom-ink, var(--accent-deep)); }

/* Identity block for a record's detail page: name, status, chips, figures. */
.entityhead { margin-bottom: 4px; }
.entityhead .eh-title { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.entityhead .eh-title h1 { margin: 0; }
.entityhead .eh-chips { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.entityhead .sub { margin: 6px 0 0; }


/* "Step 4 of 9 · Attendance", with the neighbours either side of it, so a
   working page says where in the month's sequence you are standing. */
.steprail {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: var(--text-sm); color: var(--ink-2); margin: 6px 0 12px;
}
.steprail .sr-pos { font-weight: 700; color: var(--dom-ink, var(--accent-deep)); }
.steprail .sr-sep { color: var(--baseline); }

/* ---- The R1 → R2 → R3 stage strip -----------------------------------------
   Three chips and the rules between them. The current stage is filled, a
   stage whose steps are all done carries a tick, a stage still ahead stays
   quiet. Same pill geometry as .tab so it matches the dashboard rail. */
.stagenav { display: flex; align-items: center; gap: 0; flex-wrap: wrap; margin: 10px 0 16px; }
.stagenav a {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 16px; border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--page);
  color: var(--muted); font-size: 13px; font-weight: 600; white-space: nowrap;
}
.stagenav a:hover { text-decoration: none; border-color: var(--accent); color: var(--accent-deep); }
.stagenav a { position: relative; }
.stagenav a + a { margin-left: 26px; }
/* the connector rule, drawn in the gap before every chip but the first */
.stagenav a + a::before {
  content: ""; position: absolute; right: 100%; top: 50%;
  width: 26px; height: 1px; background: var(--baseline);
}
.stagenav a.on {
  background: var(--stage-wash, var(--accent-wash)); border-color: var(--stage, var(--accent));
  color: var(--stage-ink, var(--accent-deep));
}
.stagenav a.done { color: var(--ink-2); background: var(--surface); }
.stagenav a.done::after { content: "✓"; color: var(--good-badge); font-weight: 700; }
.stagenav .sn-no {
  width: 18px; height: 18px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; background: var(--stage, var(--grid)); color: #fff;
}
.stagenav a:not(.on):not(.done) .sn-no { background: var(--grid); color: var(--ink-2); }

/* ============================================================================
   FIGURES — tiles, gates, trends
   ========================================================================= */
/* A tile that is also a pass/fail gate: the one number that says "safe to
   pay" should not look like the work-order line count next to it. */
.tile.gate .val { font-variant-numeric: tabular-nums; }
.tile.gate.ok { background: var(--good-wash); border-color: var(--good-line); }
.tile.gate.ok .val { color: var(--good); }
.tile.gate.ok .note::before { content: "✓ "; font-weight: 700; }
.tile.gate.ok .note { color: var(--good); }
.tile.gate.bad {
  background: var(--critical-wash); border-color: var(--critical-line);
  border-left: 3px solid var(--critical); padding-left: 11px;
}
.tile.gate.bad .val { color: var(--critical); }
.tile.gate.bad .note { color: var(--critical-ink); }
/* The lead figure of its block — what the button underneath actually pays. */
.tile.primary { border-color: var(--dom, var(--accent)); background: var(--dom-wash, var(--accent-wash)); }
.tile.primary .val { color: var(--dom-ink, var(--accent-deep)); font-size: 25px; }
.tile .note.warn { color: var(--warn-deep); }
.tile .note.crit { color: var(--critical); }
.tile .val.warn { color: var(--warn-deep); }
.tile .val.crit { color: var(--critical); }
.tile .val.good { color: var(--good); }

/* The .statrow figures were the last block still typed in the old idiom —
   sentence-case grey labels and non-tabular numerals beside four newer
   blocks that all use a tracked eyebrow and tabular figures. */
.statrow .lbl {
  font-size: var(--text-xs); letter-spacing: 0.13em; text-transform: uppercase;
  font-weight: 700; color: var(--dom-ink, var(--accent-deep));
}
.statrow .val { font-size: 24px; font-variant-numeric: tabular-nums; }
.statrow .note { display: block; font-size: 12px; color: var(--muted); }

/* One up/down/flat mark, replacing five near-copies (.delta, .pdelta,
   .smchg, .rcpct, .hnote). Flat is a real state: an unchanged figure must
   not render an up arrow. */
.trend { font-size: 12px; }
.trend.up { color: var(--good); }
.trend.down { color: var(--critical); }
.trend.flat, .trend.neutral { color: var(--ink-2); }
.trend.quiet { color: var(--muted); }
.trend.on-dark.up { color: var(--on-dark-up); }
.trend.on-dark.down { color: var(--on-dark-down); }
.trend.on-dark.flat { color: var(--on-dark-muted); }
.delta.flat { color: var(--ink-2); }
.delta .arrow { color: var(--ink-2); }

/* The run meter: colour says whether the month is done, length says how far. */
.meter .fill.good { background: var(--good-badge); }
.meter .fill.warn { background: var(--warn); }
.meter.wide .track { width: 160px; }
.meter.narrow .track { width: 72px; }

/* A table-cell-sized bullet: value against that row's own target. The
   .ladder does this at section scale and is far too tall for a row. */
.minibullet {
  position: relative; display: inline-block; width: 56px; height: 9px;
  border-radius: 3px; background: var(--grid); vertical-align: middle; margin-right: 7px;
}
.minibullet .mbfill { position: absolute; inset: 0 auto 0 0; border-radius: 3px; background: var(--accent); }
.minibullet .mbfill.over { background: var(--critical); }
.minibullet .mbmark {
  position: absolute; top: -2px; bottom: -2px; width: 2px; border-radius: 1px;
  background: var(--ink); outline: 1px solid var(--surface);
}

/* ============================================================================
   THE STEP LIST — done, next, and which stage each step belongs to
   ----------------------------------------------------------------------------
   Two colour systems, kept apart so neither lies. Progress uses the status
   hues: done is green, the NEXT step is accent, everything later recedes.
   Membership uses the stage hues, so the checklist and the money bar above
   it are visibly the same three stages.
   ========================================================================= */
ol.steps li.next {
  background: var(--accent-wash); box-shadow: inset 3px 0 0 var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
ol.steps li.next .steptitle { font-weight: 650; color: var(--accent-deep); }
ol.steps li.next .stepno { background: var(--accent); color: #fff; }
ol.steps li.next .youarehere {
  font-size: var(--text-xs); letter-spacing: 0.1em; text-transform: uppercase;
  font-weight: 700; color: var(--accent-deep);
}
/* Everything past the next step recedes, so three tiers exist where there
   used to be two and the eye lands on the one thing to do now. */
ol.steps li.later .stepno { background: var(--grid); color: var(--muted); }
ol.steps li.later .steptitle { color: var(--ink-2); }
/* Which of the month's three payment stages a step belongs to. */
.stepno.stage-r1, .stepno.stage-r2, .stepno.stage-r3, .stepno.stage-staff,
.stepno.stage-pf, .stepno.stage-esic, .stepno.stage-adv {
  background: var(--stage-wash); color: var(--stage-ink);
}
li.done .stepno.stage-r1, li.done .stepno.stage-r2, li.done .stepno.stage-r3,
li.done .stepno.stage-staff { background: var(--good-badge); color: #fff; }
/* The divider that groups the checklist into the stages the month has. */
.stepstage {
  display: flex; align-items: center; gap: 9px;
  padding: 12px 4px 5px; border-bottom: 1px solid var(--grid);
  font-size: var(--text-xs); letter-spacing: 0.12em; text-transform: uppercase;
  font-weight: 700; color: var(--stage-ink, var(--ink-2));
}
.stepstage::before {
  content: ""; width: 9px; height: 9px; border-radius: 2px; flex: none;
  background: var(--stage, var(--baseline));
}
.stepstage .ss-note { font-weight: 500; letter-spacing: 0; text-transform: none;
                      color: var(--muted); font-size: var(--text-sm); }

/* The FedOne wizard's crumbs, rebuilt on the same done/current/todo circles
   so a modal and the run page teach one vocabulary. */
.fw-crumb { display: inline-flex; align-items: center; gap: 7px; }
.fw-crumb .fwno {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; background: var(--accent-wash); color: var(--accent-deep);
}
.fw-crumb.done { color: var(--ink-2); }
.fw-crumb.done .fwno { background: var(--good-badge); color: #fff; }
.fw-crumb.now { color: var(--accent-deep); font-weight: 700; }
.fw-crumb.now .fwno { background: var(--accent); color: #fff; }
.fw-crumbs .fwsep { flex: 0 0 22px; height: 1px; background: var(--baseline); }

/* ============================================================================
   REGISTERS — which columns add, which subtract, which is the result
   ----------------------------------------------------------------------------
   A thirteen-column wage register is unreadable if every number is the same
   grey. .ded tints the columns that come off, .net marks the figure that is
   actually paid, and .colgroup-start draws the rule between the three
   groups: what was earned, what was taken off, what is left.
   ========================================================================= */
table.data th.ded, table.data td.ded { background: var(--warn-wash); }
table.data tbody tr:hover td.ded { background: var(--warn-wash-deep); }
table.data th.net, table.data td.net {
  background: var(--accent-wash); font-weight: 650; color: var(--ink);
}
table.data tbody tr:hover td.net { background: var(--accent-wash-deep); }
table.data th.colgroup-start, table.data td.colgroup-start { border-left: 2px solid var(--baseline); }

/* Signed money, anywhere a table prints rupees that can go the wrong way. */
td.num.neg, .num.neg, .val.neg { color: var(--critical); font-weight: 650; }
td.num.zero, .num.zero { color: var(--muted); font-weight: 400; }
td.num.pos, .num.pos { color: var(--ink); }
.txt-crit { color: var(--critical); font-weight: 600; }
.txt-warn { color: var(--warn-deep); font-weight: 600; }

/* A blank that has consequences — no UAN, no bank account — reads as a chip
   rather than as an un-greyed word lost in a 238-row table. */
.miss {
  display: inline-block; font-size: 12px; font-weight: 600;
  background: var(--warn-wash); color: var(--warn-ink);
  border: 1px solid var(--warn-line); border-radius: var(--radius-pill);
  padding: 1px 8px; white-space: nowrap;
}
.miss.crit { background: var(--critical-wash); color: var(--critical-ink); border-color: var(--critical-line); }

/* A figure and its unit, when one column carries ₹/day and ₹/month. The unit
   gets its own fixed column so the digits still line up. */
.unitcell { display: flex; justify-content: flex-end; align-items: baseline; gap: 6px; }
.unitcell .u { min-width: 34px; text-align: left; color: var(--muted); font-size: var(--text-sm); }

/* A day separator inside a long log, so one day reads as one block. */
table.data tr.daysep td {
  background: var(--dom-wash, var(--accent-wash)); font-weight: 650;
  color: var(--dom-ink, var(--accent-deep)); font-size: var(--text-sm);
  letter-spacing: 0.02em;
}

/* In-table editable controls show no chrome until you reach for them, so a
   register reads as a report and not as a form. */
select.plain, input.plain {
  background: transparent; border-color: transparent; color: inherit;
  padding: 3px 6px; border-radius: var(--radius-sm);
}
select.plain:hover, input.plain:hover { border-color: var(--baseline); background: var(--surface); }
select.plain:focus, input.plain:focus { border-color: var(--accent); background: var(--surface); }

/* A labelled two-column form, replacing table.data used as a form scaffold
   (which handed forms the register's row-hover and its shadow). */
.fieldgrid { display: grid; grid-template-columns: 150px minmax(0, 1fr); row-gap: 8px; column-gap: 14px; align-items: center; }
.fieldgrid > .lbl { color: var(--ink-2); font-size: var(--text-sm); }
.fieldgrid > input, .fieldgrid > select { width: 100%; }
.fieldgrid .fg-full { grid-column: 1 / -1; }
@media (max-width: 620px) { .fieldgrid { grid-template-columns: 1fr; row-gap: 4px; } }

/* ============================================================================
   ENTRY GRIDS — the state of a cell you have not filled in yet
   ----------------------------------------------------------------------------
   150 rows of ATT/OT/NH/Safety, and today a blank cell and a filled one are
   the same white box. Blanks read as holes in the sheet; a cell you have
   just typed into carries the save state on the row you are looking at,
   rather than only in a toast at the bottom of the screen.
   ========================================================================= */
input.cell::placeholder { color: var(--muted); }
input.cell:placeholder-shown {
  background: var(--page); border-style: dashed; border-color: var(--baseline); color: var(--muted);
}
input.cell.dirty { box-shadow: inset 2px 0 0 var(--warn); }
input.cell.saved { box-shadow: inset 2px 0 0 var(--good-badge); }
input.cell.over { border-color: var(--critical); color: var(--critical); font-weight: 650; }
/* This month's rate is not the worker's master rate. */
input.cell.ratediff, input.ratediff { border-bottom: 2px solid var(--warn); }
.was { display: block; font-size: 11.5px; color: var(--warn-deep); margin-top: 2px; white-space: nowrap; }
.ratehint { display: block; font-size: 11.5px; color: var(--muted); margin-top: 2px; }

/* A selectable list row that visibly changes state when it is ticked —
   generalising what .runkind .kind already does inside the start dialog. */
.pickrow {
  display: flex; gap: 10px; align-items: baseline; cursor: pointer;
  padding: 9px 12px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); margin-bottom: 6px;
}
.pickrow:hover { border-color: var(--accent); background: var(--accent-wash); }
.pickrow:has(input:checked) { border-color: var(--accent); background: var(--accent-wash); }
.pickrow .pk-id { font-weight: 650; }
.pickrow .pk-meta { margin-left: auto; color: var(--ink-2); font-size: var(--text-sm); font-variant-numeric: tabular-nums; }

/* The plain explanatory block. .suggestbox is the same thing locked to a
   <details>; this is the version you can put anywhere. */
.callout {
  background: var(--dom-wash, var(--accent-wash)); border-radius: var(--radius-lg);
  padding: 12px 16px; margin: 0 0 14px; color: var(--ink-2);
}
.callout strong, .callout .lead { color: var(--dom-ink, var(--accent-deep)); }
.callout.quiet { background: var(--page); border: 1px dashed var(--baseline); }

/* app.js has looked this element up by class since it was written; it had no
   rule anywhere, so four templates styled it inline. */
.dialog-error { display: none; color: var(--critical); font-weight: 600; font-size: var(--text-sm); }
.dialog-error.on { display: block; }

/* A persistent save state for the long autosaving grids, instead of two
   identical Save buttons 150 rows apart and a toast that has already gone. */
.savebar {
  position: sticky; bottom: 0; z-index: 4;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 14px; padding: 10px 14px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-pop);
  font-size: var(--text-sm); color: var(--ink-2);
}
.savebar .sb-state { display: inline-flex; align-items: center; gap: 7px; font-weight: 600; }
.savebar .sb-state::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--good-badge); }
.savebar.saving .sb-state::before { background: var(--warn); }
.savebar.unsaved .sb-state::before { background: var(--critical); }
.savebar.saving .sb-state { color: var(--warn-deep); }
.savebar.unsaved .sb-state { color: var(--critical); }

/* ============================================================================
   STATUS VOCABULARY — one status is one colour, everywhere
   ----------------------------------------------------------------------------
   The badge set was active / inactive / open / completed, so templates
   ternaried real statuses into the nearest of four: an invoice awaiting
   payment came out grey "inactive" while the donut beside it called it
   amber, and a work order on extension was grey in the list and green in the
   timeline. These variants take their tints from the same validated
   categorical set the charts use (tokens.css 5d), so a chip, an arc and a
   Gantt bar finally agree.
   ========================================================================= */
.badge.running { background: var(--cat-1-wash); color: var(--cat-1-ink); }
.badge.extension { background: var(--cat-2-wash); color: var(--cat-2-ink); }
.badge.pending { background: var(--cat-2-wash); color: var(--cat-2-ink); }
.badge.processing { background: var(--cat-1-wash); color: var(--cat-1-ink); }
/* A record whose lifecycle has ended — a completed work order, a complete
   invoice. Distinct from .badge.completed below, which is the state of
   something a person ticked; keeping both greens meant two hues nobody could
   resolve, so this one carries the status ramp and that one the good ramp. */
.badge.complete { background: var(--cat-3-wash); color: var(--cat-3-ink); }
.badge.state-done { background: var(--good-wash); color: var(--good); }
.badge.awaiting { background: var(--cat-4-wash); color: var(--cat-4-ink); }
.badge.none { background: var(--cat-other-wash); color: var(--cat-other-ink); }
.badge.crit { background: var(--critical-wash); color: var(--critical-ink); }
.badge.warn { background: var(--warn-wash); color: var(--warn-ink); }
/* Run type: a final run and a partial run are genuinely different things,
   and the partial — which does not re-check who is still active — is the one
   worth flagging. Replaces an inline style bolted onto .badge.open twice. */
.badge.final { background: var(--accent-wash); color: var(--accent-deep); }
.badge.partial { background: var(--warn-wash); color: var(--warn-deep); }
/* Role: whether this person settles at R3 or in the staff payroll. Staff
   takes the same aqua the composition bar gives them. */
.badge.labour { background: var(--accent-wash); color: var(--accent-deep); }
.badge.staff { background: var(--stage-staff-wash); color: var(--stage-staff-ink); }
.badge.consultant { background: var(--grid); color: var(--ink-2); }
/* Sized down for a cell in a 238-row table. */
.badge.tiny { font-size: 11px; padding: 1px 8px; }

/* Swatches for the sets that live in tokens.css, so a legend never retypes
   a hex that a Python constant also holds. */
.sw.cat-1 { background: var(--cat-1); } .sw.cat-2 { background: var(--cat-2); }
.sw.cat-3 { background: var(--cat-3); } .sw.cat-4 { background: var(--cat-4); }
.sw.cat-5 { background: var(--cat-5); } .sw.cat-other { background: var(--cat-other); }
.sw.cat-6 { background: var(--cat-6); } .sw.cat-7 { background: var(--cat-7); }
.sw.seq-1 { background: var(--seq-1); } .sw.seq-2 { background: var(--seq-2); }
.sw.seq-3 { background: var(--seq-3); } .sw.seq-4 { background: var(--seq-4); }
.sw.seq-5 { background: var(--seq-5); } .sw.seq-0 { background: var(--seq-0); }
.sw.good { background: var(--good-badge); } .sw.warn { background: var(--warn); }
.sw.crit { background: var(--critical); } .sw.baseline { background: var(--baseline); }
.sw.wo { background: var(--dom-workorders-wash); box-shadow: inset 0 0 0 1px var(--dom-workorders-line); }
.sw.wo-project { background: var(--dom-workorders-wash); box-shadow: inset 0 0 0 2px var(--dom-workorders); }

/* ============================================================================
   CHARTS — the key, the honest empty state, the month that is not closed yet
   ========================================================================= */
/* One legend. .legend, .rclegend and .tllegend were three near-copies; they
   keep their names so no template breaks, and now share one look. */
.chartkey, .legend, .rclegend, .tllegend {
  display: flex; gap: 16px; flex-wrap: wrap; margin: 12px 0 0;
  font-size: var(--text-sm); color: var(--ink-2);
}
.legend { margin: 4px 0 10px; }
.chartkey .key, .legend .key, .rclegend .key, .tllegend .key {
  display: inline-flex; align-items: center; gap: 6px;
}
.chartkey .sw, .legend .sw, .rclegend .sw, .tllegend .sw {
  width: 11px; height: 11px; border-radius: 3px; display: inline-block; flex: none;
}
.chartkey .v, .legend .v { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink); }
/* The trailing sentence that says what the colours mean in words. */
.chartkey-note { flex: 1 1 100%; color: var(--muted); font-size: var(--text-sm); margin-top: 2px; }
.chartkey.stacked { flex-direction: column; gap: 5px; }

/* A chart and its "View data" table as one unit, so the house rule is
   structural rather than remembered per template. */
.chartblock { margin-top: 4px; }
.chartblock > .cb-cap { font-size: var(--text-sm); color: var(--ink-2); margin: 0 0 8px; }

/* The period that is not finished yet must not be drawn as a genuine zero.
   An open month reads as an outline at the height of the figure beside it. */
.rcbar.pending, .colbar.wip, .cbar.wip {
  background: transparent; border: 1px dashed var(--baseline);
}
.hbars span.pending { background: transparent; border: 1px dashed var(--on-dark-rule); }
.hbars span.neg { background: var(--on-dark-down); }
/* Three jobs, three looks: a month axis, a distribution, and a bare strip. */
.hbars.dist span.last { background: rgba(127, 187, 255, 0.45); }
.axisnote { font-size: 11.5px; color: var(--ink-2); margin: 6px 0 0; }
.axismax { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
/* The average rule across a column chart, so near-identical months have
   something to be read against. */
.colarea { position: relative; }
.colavg { position: absolute; left: 0; right: 0; border-top: 1px dashed var(--baseline); }
.colavg .cav-lbl { position: absolute; right: 0; top: -14px; font-size: 10.5px; color: var(--ink-2); }
/* Margin against the business's own norm, not against zero. */
.rcpct.warn { color: var(--warn-deep); }
.rcpct.flat { color: var(--ink-2); }
/* A wider label column, for charts whose categories are spelled out. */
.chart.wide .crow { grid-template-columns: 150px 1fr 92px; }

/* A dashed placeholder that keeps the footprint of the thing that is not
   there yet, and says what would fill it. Better than half a white card. */
.emptyslot {
  display: flex; flex-direction: column; justify-content: center; gap: 6px;
  min-height: 150px; padding: 18px 20px; text-align: center;
  border: 1px dashed var(--baseline); border-radius: var(--radius-lg);
  background: var(--page); color: var(--ink-2); font-size: var(--text-sm);
}
.emptyslot .es-lead { font-weight: 600; color: var(--ink); }

/* A severity-dotted list row, replacing a bulleted <ul> of 35 flags in which
   a ₹13.5Cr settlement to verify sat between two possible double entries. */
.flaglist { list-style: none; margin: 6px 0 0; padding: 0; }
.flaglist .flagsub {
  display: flex; align-items: baseline; gap: 8px; margin: 12px 0 4px;
  font-size: var(--text-xs); letter-spacing: 0.12em; text-transform: uppercase;
  font-weight: 700; color: var(--ink-2);
}
.flagrow {
  display: flex; align-items: baseline; gap: 9px; padding: 5px 2px;
  border-bottom: 1px solid var(--grid); font-size: 13px;
}
.flagrow:last-child { border-bottom: none; }
.flagrow::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--flag-hue, var(--muted)); transform: translateY(-1px);
}
.flagrow.crit { --flag-hue: var(--critical); }
.flagrow.warn { --flag-hue: var(--warn); }
.flagrow.info { --flag-hue: var(--accent); }
.flagkind {
  flex: none; font-size: 11.5px; font-weight: 600; border-radius: var(--radius-pill);
  padding: 1px 8px; background: var(--grid); color: var(--ink-2); white-space: nowrap;
}
.flagrow.crit .flagkind { background: var(--critical-wash); color: var(--critical-ink); }
.flagrow.warn .flagkind { background: var(--warn-wash); color: var(--warn-ink); }
.flagrow.info .flagkind { background: var(--accent-wash); color: var(--accent-deep); }
.flagrow .flagval { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--ink); }

/* ---- The attendance flow diagram ------------------------------------------
   SVG presentation attributes cannot resolve var(), so every fill in the
   picture is a class here rather than a hex in the template. The source
   panel is flat rather than a gradient — the gradient was a fourth green
   that appeared nowhere else in the product, and its five tints of
   supporting type all failed contrast against it. Two tints, both measured:
   white at 6.75:1 and --aflow-ink-dim at 5.27:1.

   The picture used to paint an ordinary order in the staff teal and a project
   order in the R2 blue. That put the same two hues on /attendance saying
   "ordinary / project" here and "Labour / Staff" in the chart one scroll
   below — a stage hue has to keep meaning its stage. Everything in this
   diagram is a work order now, so everything wears the work-orders domain
   violet, and being a PROJECT order — the real difference, it pays no AWA —
   is drawn the way lateness is drawn on the timeline: a modifier on the mark
   (a solid accent stroke and a heavier ribbon) rather than a second hue that
   would have to be validated against a chart it does not belong to. */
.aflow { --aflow-panel: var(--dom-workorders-ink); --aflow-ink-dim: var(--flow-ink-dim); }
.aflow-panel { fill: var(--aflow-panel); }
.aflow-big { fill: #fff; font-weight: 700; }
.aflow-eyebrow, .aflow-sub { fill: var(--aflow-ink-dim); }
.aflow-recon { fill: var(--aflow-ink-dim); }
.aflow-recon .val { fill: #fff; font-weight: 700; }
.aflow-ribbon { fill: var(--flow-ribbon); }
.aflow-ribbon.project { fill: var(--flow-ribbon-project); }
.aflow-card { fill: var(--dom-workorders-wash); stroke: var(--dom-workorders-line); }
.aflow-card.project { stroke: var(--dom-workorders); stroke-width: 2; }
.aflow-label { fill: var(--dom-workorders-ink); font-weight: 650; }
.aflow-label.project { font-weight: 750; }
.aflow-days, .aflow-rail { fill: var(--ink-2); }
.aflow-note { fill: var(--muted); }
.svg-ink { fill: var(--ink); }
.svg-ink-2 { fill: var(--ink-2); }
.svg-muted { fill: var(--muted); }

/* ============================================================================
   SHELL — focus, the header's one button size, sign-in, zero states
   ========================================================================= */
/* Only inputs and .alertchip had any focus styling, so the whole header nav,
   every tab, rail item and dialog action was invisible to a keyboard. On a
   filled control the ring is drawn in the surface colour so it reads against
   the fill instead of disappearing into it. */
:where(a, button, .btn, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.tab.on:focus-visible, button:not(.ghost):not(.danger):focus-visible, .btn:not(.ghost):focus-visible {
  outline-color: var(--surface); outline-offset: -3px; box-shadow: var(--focus-ring);
}

/* One button metric in the header, instead of an inline padding on two of
   the three and the base size on the rest. */
.btn.hdr, button.hdr { padding: 5px 12px; font-size: var(--text-sm); }

/* The sign-in screen: a form column and a brand panel that reuses the
   landing band's background rather than leaving nine tenths of the viewport
   empty grey. Collapses to the form alone on a narrow screen. */
.authshell {
  display: grid; grid-template-columns: 420px minmax(0, 1fr);
  gap: 0; min-height: 100vh; align-items: stretch;
}
.authshell-form {
  display: flex; flex-direction: column; justify-content: center;
  padding: 40px 36px; background: var(--page);
}
.authshell-form .card { border-radius: var(--radius-lg); padding: 26px 28px; }
.authshell-brand {
  position: relative; overflow: hidden; color: #fff;
  display: flex; flex-direction: column; justify-content: center; gap: 14px;
  padding: 48px 52px;
  background:
    radial-gradient(120% 140% at 88% -20%, rgba(46, 139, 255, 0.55) 0%, rgba(46, 139, 255, 0) 55%),
    radial-gradient(90% 120% at 8% 120%, rgba(63, 195, 148, 0.30) 0%, rgba(63, 195, 148, 0) 60%),
    linear-gradient(135deg, var(--on-dark-bg-1) 0%, var(--on-dark-bg-2) 55%, var(--on-dark-bg-3) 100%);
}
.authshell-brand::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px);
  background-size: 100% 34px;
}
.authshell-brand > * { position: relative; z-index: 1; }
.authshell-brand h2 { font-family: var(--font-brand); font-size: 28px; color: #fff; margin: 0; }
.authshell-brand .as-tagline { font-size: var(--text-lg); color: var(--on-dark-ink); margin: 0; max-width: 44ch; }
.authshell-brand .as-proof { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 10px; }
.authshell-brand .as-proof li {
  color: var(--on-dark-ink); font-size: 13.5px; max-width: 52ch;
  padding-left: 20px; position: relative;
}
.authshell-brand .as-proof li::before { content: "—"; position: absolute; left: 0; color: var(--brand-accent-soft); }
@media (max-width: 860px) {
  .authshell { grid-template-columns: 1fr; min-height: 0; }
  .authshell-brand { display: none; }
  .authshell-form { padding: 8vh 18px 40px; }
}

/* A real zero state: a mark, a headline, one sentence in the house voice and
   one action — instead of an h1 and a shell command on bare page grey. */
.emptystate {
  max-width: 46ch; margin: 12vh auto 0; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
}
.emptystate-mark { opacity: 0.28; }
.emptystate h1 { margin: 0; }
.emptystate p { color: var(--ink-2); margin: 0; }
.emptystate-actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-top: 6px; }
.emptystate .es-operator { font-size: var(--text-sm); color: var(--muted); margin-top: 14px; }
.emptystate .es-operator code {
  font-family: var(--font-mono); font-size: 11.5px;
  background: var(--grid); border-radius: var(--radius-sm); padding: 1px 6px;
}

/* One overlay surface behind the three menus, which were near-copies at two
   radii, two border colours and one hand-retyped shadow. */
.popover {
  position: absolute; z-index: 45; min-width: 210px; padding: 8px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-pop);
}

/* The wordmark, set the same way in all three places it appears. */
.wordmark.sm {
  font-family: var(--font-brand); font-weight: 700; font-size: 13px;
  letter-spacing: -0.02em; color: var(--brand-ink);
}
.sitefoot .foot-right { margin-left: auto; display: flex; align-items: center; gap: 12px; color: var(--muted); }
.sitefoot .foot-right code { font-family: var(--font-mono); font-size: 11px; }
.sitefoot.stacked { justify-content: center; margin-top: 22px; }

/* A light version of the landing band, so a page other than the dashboard
   can open with the same headline block instead of a bare h1. */
.lander.quiet {
  background: var(--surface); border: 1px solid var(--border); color: var(--ink);
  box-shadow: var(--shadow); padding: 20px 24px 4px;
}
.lander.quiet::after { display: none; }
.lander.quiet h1 { color: var(--dom-ink, var(--accent-deep)); }
.lander.quiet .eyebrow { color: var(--dom-ink, var(--accent-deep)); }
.lander.quiet .lander-sub { color: var(--ink-2); }
.lander.quiet .lander-cta {
  color: var(--accent-deep); border-color: var(--accent);
  background: var(--accent-wash);
}
.lander.quiet .lander-cta:hover { background: var(--accent-wash-deep); }
.lander.quiet .hstat { border-left-color: var(--grid); }
.lander.quiet .hstat .hlbl { color: var(--dom-ink, var(--accent-deep)); }
.lander.quiet .hstat .hval { color: var(--ink); }
.lander.quiet .hstat .hval .hunit { color: var(--ink-2); }
.lander.quiet .hstat .hnote { color: var(--muted); }
.lander.quiet .hstat .hnote.up { color: var(--good); }
.lander.quiet .hstat .hnote.down { color: var(--critical); }
.lander.quiet .hbars span { background: var(--seq-0); }
.lander.quiet .hbars span.last { background: var(--accent); }

/* ============================================================================
   Touch — the daily tracker is used one-handed on a phone at a plant
   ----------------------------------------------------------------------------
   Desktop sizes are untouched; this only fires on a coarse pointer, where a
   22px delete button sitting beside a 22px OT field is a mis-tap that
   destroys an entry.
   ========================================================================= */
@media (pointer: coarse) {
  button, .btn, input, select, .skillbox, .alertchip, .tab {
    min-height: 44px;
  }
  button.tiny { padding: 8px 14px; font-size: 13px; }
  input, select { padding: 10px 10px; }
  input.cell { width: 82px; padding: 10px 8px; }
  .skillbox { padding: 10px 14px; }
  .vtab-rail button { min-height: 44px; }
  .msel > summary { padding: 12px 26px 12px 11px; }
  .wpick-item { padding: 12px 11px; }
  .pickrow { padding: 13px 12px; }
  /* a row action must be a target you can hit, not a 22px pill */
  table.data td .tiny.danger { min-width: 44px; }
}

/* ---- the assistant: floating button + docked panel ------------------- */
/* Sits above the anchored menus but below #tip (50) and #toast (60), so a
   tooltip or a save confirmation is never covered by the panel. */

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.chatfab {
  position: fixed; right: 22px; bottom: 22px; z-index: 46;
  width: 48px; height: 48px; padding: 0;
  border: 0; border-radius: 50%;
  background: var(--accent-deep); color: #fff;
  font-size: 20px; line-height: 1; cursor: pointer;
  box-shadow: var(--shadow-pop);
  transition: transform .15s, background .15s;
}
.chatfab:hover { background: var(--accent-deeper); transform: translateY(-1px); }
.chatfab[aria-expanded="true"] { background: var(--accent-deeper); }

.chatpanel {
  position: fixed; right: 22px; bottom: 80px; z-index: 47;
  width: min(420px, calc(100vw - 44px));
  height: min(640px, calc(100vh - 130px));
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-modal);
}
.chatpanel[hidden] { display: none; }
.chatpanel-head {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--grid);
  font-size: 13px; font-weight: 600; color: var(--ink);
}
.chatpanel-head > span:first-child { flex: 1; }
.chatpanel-full, .chatpanel-x {
  background: none; border: 0; cursor: pointer;
  color: var(--muted); text-decoration: none;
  font-size: 15px; line-height: 1; padding: 4px 6px; border-radius: var(--radius-sm);
}
.chatpanel-full:hover, .chatpanel-x:hover { color: var(--accent-deep); background: var(--accent-wash); }
.chatpanel iframe { flex: 1; width: 100%; border: 0; display: block; }

@media (max-width: 560px) {
  .chatpanel {
    right: 10px; left: 10px; bottom: 74px;
    width: auto; height: min(70vh, calc(100vh - 110px));
  }
  .chatfab { right: 16px; bottom: 16px; }
}

/* ---- dev page ---- */
/* A share-of-peak bar, not a chart: it answers "which day was expensive"
   at a glance without another axis to read. */
.devbar {
  display: block; height: 8px; min-width: 2px;
  background: var(--accent); border-radius: var(--radius-pill);
}
.chip.devchip { background: var(--ink-inverse); color: #fff; border-color: var(--ink-inverse); }
tr.off { opacity: .55; }
