:root {
  --paper: #f3efe4;
  --panel: #faf7f1;
  --ink: #1c1915;
  --muted: #3f3b34;
  --line: #d9d2c5;
  --accent: #35597a;
  --accent-ink: #f7f4ee;
  --row: #e7eef4;
  --field: #ffffff;
  --field-line: #8a8377;
  --field-readonly: #efeae0;
  --good: #2f5d34;
  --bad: #6d2424;
  --bad-rule: #8a2b1d;
  --bad-bg: #f6e7e2;
  --bad-ink: #6d2418;
  --shadow: #1c1915;
  --split-base: #2f6ea8;
  --split-super: #d46322;
  --split-tax: #0b6f4c;
  --split-margin: #c94f87;
  --split-gst: #815a00;
}

/* Dark follows the system unless the reader chose light; the second block is the reader choosing
   dark. The two hold the same values, and a test keeps them so. Both are for the screen only: a
   printer drops the backgrounds, so a printed page always takes the light tokens, dark ink on white. */
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --paper: #1a1814;
    --panel: #221f1a;
    --ink: #ece6da;
    --muted: #bdb5a7;
    --line: #3d382f;
    --accent: #8fb4d6;
    --accent-ink: #1a1814;
    --row: #26303a;
    --field: #141210;
    --field-line: #857d70;
    --field-readonly: #2b2721;
    --good: #8fc79a;
    --bad: #f0a296;
    --bad-rule: #d0705f;
    --bad-bg: #3b211b;
    --bad-ink: #f3b5aa;
    --shadow: #000000;
    --split-base: #3987e5;
    --split-super: #d95926;
    --split-tax: #15855e;
    --split-margin: #e0628f;
    --split-gst: #c98500;
  }
}

@media screen {
  :root[data-theme="dark"] {
    color-scheme: dark;
    --paper: #1a1814;
    --panel: #221f1a;
    --ink: #ece6da;
    --muted: #bdb5a7;
    --line: #3d382f;
    --accent: #8fb4d6;
    --accent-ink: #1a1814;
    --row: #26303a;
    --field: #141210;
    --field-line: #857d70;
    --field-readonly: #2b2721;
    --good: #8fc79a;
    --bad: #f0a296;
    --bad-rule: #d0705f;
    --bad-bg: #3b211b;
    --bad-ink: #f3b5aa;
    --shadow: #000000;
    --split-base: #3987e5;
    --split-super: #d95926;
    --split-tax: #15855e;
    --split-margin: #e0628f;
    --split-gst: #c98500;
  }
}

/* A reader who chose light on a dark system: the browser's own controls must stay light too. */
:root[data-theme="light"] {
  color-scheme: light;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  line-height: 1.4;
}

.wrap {
  max-width: 96rem;
  margin: 0 auto;
  padding: 1rem 1rem 2.5rem;
}

/* The mark is three bars: a rate distribution, which is what the whole page reads. */
.brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  color: var(--ink);
  font-size: 1.45rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
}

/* The heading says what the page is, in the words people search for; the name above it is the brand. */
.page-title {
  margin: 0.35rem 0 0.2rem;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.3;
}

header p + p {
  margin-top: 0.3rem;
}

/* A page of reading, not a tool: its header, text and footer share one column, short enough to read
   and centred, so a wide screen has no empty side. */
.wrap-reading {
  max-width: 50rem;
}

.prose {
  margin-top: 1rem;
  line-height: 1.55;
}

.prose h2 {
  margin: 1.5rem 0 0.4rem;
}

.prose p,
.prose ul {
  margin: 0 0 0.7rem;
}

/* One whole, split into parts. Its colours pass the colour-blindness checks only with the gaps and the
   ordered legend beside them, so keep both. The figures sit in the legend: the thin parts have no room. */
.split-figure {
  margin: 0 0 1rem;
}

/* Each part's width is its share of the value: tests/test_static.py holds these to the formula. */
.split {
  position: relative;
  display: flex;
  gap: 2px;
  height: 20px;
}

.split-part {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  border-radius: 4px;
  print-color-adjust: exact;
}

.split-base { flex-grow: 72.42; }
.split-super { flex-grow: 8.69; }
.split-tax { flex-grow: 5.47; }
.split-margin { flex-grow: 4.33; }
.split-gst { flex-grow: 9.09; }

.split-base, .split-key-base { background: var(--split-base); }
.split-super, .split-key-super { background: var(--split-super); }
.split-tax, .split-key-tax { background: var(--split-tax); }
.split-margin, .split-key-margin { background: var(--split-margin); }
.split-gst, .split-key-gst { background: var(--split-gst); }

/* The dollars, above the part focused, or pointed at if split.js has not run. Faded rather than hidden,
   so a screen reader still reads them. Anchored to the part's right edge so the parts at the end stay on
   the screen; the first part is wide, so its tip sits at its middle. */
.split-tip {
  position: absolute;
  right: 0;
  bottom: calc(100% + 6px);
  padding: 0.2rem 0.45rem;
  background: var(--ink);
  color: var(--accent-ink);
  border-radius: 3px;
  font-size: 0.85rem;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
}

.split-base .split-tip {
  right: auto;
  left: 50%;
  transform: translateX(-50%);
}

.split-part:hover .split-tip,
.split-part:focus .split-tip {
  opacity: 1;
}

/* split.js draws the mouse's and the finger's tip, which follows the pointer. A keyboard's focus stays. */
.split-follows .split-part:hover .split-tip,
.split-follows .split-part:focus:not(:focus-visible) .split-tip {
  opacity: 0;
}

.split-layer {
  position: absolute;
  left: 0;
  bottom: calc(100% + 6px);
  width: 100%;
  overflow: visible;
  pointer-events: none;
}

.split-layer rect { fill: var(--ink); }
.split-layer text { fill: var(--accent-ink); font-size: 0.85rem; }

.prose .split-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 1rem;
  margin: 0.5rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.9rem;
}

.split-key {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  margin-right: 0.35rem;
  border-radius: 2px;
  print-color-adjust: exact;
}

.split-figure figcaption {
  margin-top: 0.4rem;
  color: var(--muted);
  font-size: 0.85rem;
}

.prose pre {
  margin: 0 0 0.7rem;
  padding: 0.6rem 0.75rem;
  overflow-x: auto;
  background: var(--panel);
  border: 1px solid var(--line);
}

.brand-mark {
  width: 1.5rem;
  height: 1.5rem;
  flex: none;
  fill: var(--accent);
}

.brand-name {
  letter-spacing: -0.015em;
}

/* The name and the theme switch share a line; the switch sits at the far end. */
.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.2rem;
}

.theme-toggle {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.theme-toggle[hidden] {
  display: none;
}

.theme-toggle-mark {
  width: 1rem;
  height: 1rem;
  flex: none;
}

.theme-toggle-mark circle {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
}

.theme-toggle-mark path {
  fill: currentColor;
}

/* The name and the full button need about 350px; under that the button is its mark alone. The words
   stay for a screen reader, hidden the way .sr-only hides a label. */
@media (max-width: 420px) {
  .theme-toggle {
    position: relative;
    min-width: 2.25rem;
    justify-content: center;
    padding: 0.35rem 0.5rem;
  }

  .theme-toggle-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
}

header p,
footer p {
  margin: 0;
  color: var(--muted);
}

h2 {
  margin: 0 0 0.55rem;
  font-size: 1rem;
  font-weight: 600;
}

h3 {
  margin: 0.9rem 0 0.35rem;
  font-size: 0.95rem;
}

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  padding: 0.85rem 1rem 1rem;
  margin-top: 0.85rem;
}

.field { margin: 0; }

label,
legend {
  display: block;
  margin-bottom: 0.15rem;
  font-size: 0.82rem;
  color: var(--muted);
}

label.check {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0.2rem 0.8rem 0.2rem 0;
  color: var(--ink);
  font-size: 0.95rem;
}

.hint {
  color: var(--muted);
  font-size: 0.88rem;
  margin: 0.25rem 0 0;
}

.error {
  color: var(--bad);
  margin: 0.45rem 0 0;
}

/* A cancelled notice is a fact worth stating, not an error the user caused. */
.status-line {
  margin: 0.5rem 0 0;
  padding: 0.5rem 0.7rem;
  border-left: 3px solid var(--bad-rule);
  background: var(--bad-bg);
  color: var(--bad-ink);
  font-size: 0.92rem;
}

input[type="text"],
input[type="date"],
select,
button {
  font: inherit;
  color: inherit;
  min-height: 2.25rem;
}

input[type="text"],
input[type="date"],
select {
  width: 100%;
  padding: 0.35rem 0.5rem;
  background: var(--field);
  border: 1px solid var(--field-line);
}

button {
  background: var(--accent);
  color: var(--accent-ink);
  border: 1px solid var(--accent);
  padding: 0.35rem 0.85rem;
  cursor: pointer;
  white-space: nowrap;
}

button.secondary {
  background: transparent;
  color: var(--accent);
}

button:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

.row {
  display: flex;
  gap: 0.5rem;
}

.row input { flex: 1; }

.toolbar,
.rates,
.pair {
  display: grid;
  gap: 0.55rem;
  align-items: end;
}

.toolbar {
  grid-template-columns: minmax(8rem, 1.2fr) minmax(8rem, 1.1fr) minmax(8rem, 1fr) minmax(7rem, 0.8fr);
}

/* The going door reads top to bottom: what to look for, then when and which rates to drop.
   The settings take the toolbar's four columns: Period spans the first two and the drop band
   the last two, so every control lines up under the field above it and each note sits under
   its own controls. The fields fill their group, so a preset leaves no empty half-row; Custom
   dates shares the period's columns with From and To. The groups stack when there is no room. */
.going-settings {
  display: grid;
  grid-template-columns: minmax(8rem, 1.2fr) minmax(8rem, 1.1fr) minmax(8rem, 1fr) minmax(7rem, 0.8fr);
  gap: 0.55rem;
  align-items: start;
  margin-top: 0.55rem;
}

.going-group { min-width: 0; }
.going-when { grid-column: 1 / 3; }
.going-band { grid-column: 3 / 5; }

/* The drop band takes the two columns it spans, so each box sits exactly under Agency and
   Reference: their left and right edges, and the gap between them. */
@supports (grid-template-columns: subgrid) {
  .going-band {
    display: grid;
    grid-template-columns: subgrid;
  }

  .going-band .going-fields {
    display: grid;
    grid-template-columns: subgrid;
    grid-column: 1 / -1;
  }

  .going-band .hint { grid-column: 1 / -1; }
}

.going-fields {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 0.55rem;
}

.going-fields > .field { flex: 1 1 0; min-width: 0; }
.going-fields .field-period { flex: 2 1 0; }

.going-go { margin-top: 0.7rem; }

.rates {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 0.55rem 0.65rem;
  margin-top: 0.8rem;
}

.rates .field-pct {
  width: 5.25rem;
}

.rates .field-state {
  width: 5.5rem;
}

.rates .field-band {
  flex: 1 1 18rem;
  min-width: 16rem;
}

.rates fieldset {
  flex: 1 1 100%;
}

#payroll-fields {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 0.55rem 0.65rem;
  /* Grows into the rest of the control row so the selects line up along one bottom
     edge with the percent fields. The note is NOT inside here: when it was, this box
     was two lines tall and .rates { align-items: end } bottom-aligned the percent
     fields against it, which is the ragged row the screenshots showed. */
  flex: 1 1 auto;
  min-width: 0;
}

#payroll-fields .field-state { width: 5.5rem; }
#payroll-fields .field-band { flex: 1 1 14rem; min-width: 12rem; }
/* The note is a sibling of the wrapper, so it takes its own full-width line under the
   controls instead of stretching the wrapper beside them. */
#payroll-note { flex: 1 1 100%; margin: 0.35rem 0 0; }

body.door-contract .field-margin { display: none; }

#notice,
#result-notice { display: none; }

/* A CN in a clickable row is a real control now, not just text. */
.cn-open {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  text-decoration: underline;
  cursor: pointer;
}

.assumptions-compact {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 0.3rem 0.7rem;
  position: relative;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0.15rem 0 0.1rem;
}

.assumptions-compact > h2,
.assumptions-compact > .hint {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

/* The payroll caveat is the paragraph the contract door exists to explain — it says the rate
   cannot be read off a notice. The compact row above was clipping it along with the generic
   hint, so exempt it and let it take a line of its own. */
.assumptions-compact > #payroll-caveat {
  position: static;
  width: auto;
  height: auto;
  overflow: visible;
  clip: auto;
  flex-basis: 100%;
}

.assumptions-compact .rates {
  margin: 0;
  gap: 0.3rem 0.7rem;
  align-items: end;
}

.assumptions-compact .rates .field-pct { width: 4.25rem; }

.assumptions-compact .rates fieldset {
  flex: 1 1 auto;
  margin: 0;
  border: 0;
  padding: 0;
}

.assumptions-compact #reset-form {
  margin: 0 0 0.05rem auto;
  padding: 0.28rem 0.55rem;
}

.share-box {
  margin-top: 0.85rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--line);
}

#share-summary {
  margin: 0.45rem 0;
  font-weight: 500;
}

#share-url {
  width: 100%;
  margin-top: 0.4rem;
}

.workbench {
  margin: 1.1rem 0 0.4rem;
  padding: 1rem 0 0.2rem;
  border-top: 1px solid var(--line);
}

.workbench h2 {
  margin-bottom: 0.75rem;
}

.match {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(11rem, 0.7fr) minmax(0, 1fr);
  gap: 0.7rem;
  align-items: stretch;
}

@media (max-width: 800px) {
  .match { grid-template-columns: 1fr; }
}

.match-card {
  background: var(--row);
  border-radius: 14px;
  padding: 0.85rem 1rem 0.75rem;
}

.match-card span,
.match-sub {
  display: block;
  color: var(--muted);
  font-size: 0.78rem;
}

.match-card strong {
  display: block;
  margin: 0.15rem 0 0.2rem;
  font-size: 2.35rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
  color: var(--accent);
}

#seen-rate {
  display: block;
  width: 100%;
  max-width: 100%;
  margin: 0.2rem 0 0.35rem;
  padding: 0 0 0.15rem;
  border: 0;
  border-bottom: 2px solid var(--accent);
  background: transparent;
  font-size: 2.35rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
}

.rate-gap {
  margin: 0;
  align-self: center;
  color: var(--muted);
  font-size: 0.95rem;
}

.rate-gap.matched {
  color: var(--accent);
  font-weight: 600;
}

.rate-gap.apart {
  color: var(--ink);
}

.knob {
  margin-top: 1rem;
}

.knob-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 0.25rem;
}

.knob-head label {
  margin: 0;
  color: var(--ink);
  font-size: 0.95rem;
}

#margin-readout {
  font-size: 1.35rem;
  font-weight: 600;
  color: var(--accent);
}

#margin-range {
  width: 100%;
  margin: 0.35rem 0 0.7rem;
  accent-color: var(--accent);
}

#match-rate {
  margin-top: 0.15rem;
}

/* The contract door's markup / gross margin choice, moved under the slider it changes the meaning
   of. The legend stays for screen readers; on screen, "Company margin" above names the group. */
.knob-mode fieldset {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.2rem 1rem;
  border: 0;
  margin: -0.2rem 0 0.6rem;
  padding: 0;
}

.knob-mode legend {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.contract-payroll {
  margin: 0 0 0.9rem;
}

/* The contract's value and hours now come first, so the assumptions row needs its own space below
   the Calculate button. */
#contract-assumptions {
  margin-top: 1rem;
}

input[readonly] {
  background: var(--field-readonly);
}

.door-choices {
  display: grid;
  /* Six cards in two rows of three: six in one row left each card about 155px wide just above the
     tablet breakpoint, and three a row leaves no empty cell. */
  grid-template-columns: repeat(3, 1fr);
  gap: 0.7rem;
}

button.door-choice {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
  width: 100%;
  min-height: 5.5rem;
  padding: 0.85rem 1rem;
  text-align: left;
  white-space: normal;
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line);
}

button.door-choice strong {
  font-size: 1.05rem;
}

button.door-choice span {
  color: var(--muted);
  font-size: 0.9rem;
}

/* The finder is in beta while its weights are tuned. A small outlined tag, not a second colour: it
   sits inside a card heading and a panel heading, and must not out-shout either. */
.beta {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0 0.4rem;
  border: 1px solid var(--accent);
  border-radius: 0.6rem;
  color: var(--accent);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  vertical-align: 0.15em;
}

button.door-choice span.beta {
  color: var(--accent);
  font-size: 0.72rem;
}

button.door-choice[aria-pressed="true"] {
  background: var(--row);
  border-color: var(--accent);
  color: var(--ink);
}

/*
 * The landing's aggregated view: a compact strip under the door chooser. Four figures in a row, two
 * short lists, and the recent years. It is hidden until the rollup answers, so an unbuilt view does
 * not leave a frame of dashes on the front page.
 */
/* Ruled off below as well as above: it sits under a department's picks, and without the rule the
   picks read as more of the national picture. */
.national {
  margin: 1.1rem 0;
  padding: 0.9rem 0 1rem;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

/* The strip is the door's empty state, so it steps aside while a department is open. Above the
   detail it pushed the answer a screen down, and its Commonwealth-wide supplier list read as the
   department's own. The browse list and the picks keep it underneath, as context. */
#department-detail:not([hidden]) ~ .national {
  display: none;
}

.national h3 {
  margin: 0 0 0.6rem;
  font-size: 1rem;
}

.national-figures {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.5rem 1.1rem;
  margin: 0 0 0.8rem;
}

.national-figures dt {
  color: var(--muted);
  font-size: 0.78rem;
}

.national-figures dd {
  margin: 0.1rem 0 0;
  font-size: 1.05rem;
  font-weight: 600;
}

.national-lists {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.6rem 1.1rem;
}

.national-list h4 {
  margin: 0 0 0.35rem;
  color: var(--muted);
  font-size: 0.85rem;
}

.national-list ul {
  display: grid;
  gap: 0.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A row is a grid, not a line of inline text: the name takes the slack, and the amount and the
   button sit in columns at the right, so they line up down the list instead of following the length
   of each name. Every row is a button's height, so the suppliers beside the departments line up row
   for row even though they have no button. */
.national-list li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.6rem;
  min-height: 2.25rem;
}

#national-departments-list li {
  grid-template-columns: minmax(0, 1fr) auto auto;
}

.national-amount {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* The pager sits under its list, the same height on both sides so the two columns stay level. The
   page number takes the slack between the buttons, keeping Previous on the left and Next on the
   right whatever the labels say. */
.national-pager {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.25rem;
  margin-top: 0.35rem;
}

.national-pager button {
  padding: 0.2rem 0.55rem;
  font-size: 0.8rem;
}

.national-page {
  color: var(--muted);
  font-size: 0.8rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.national-years {
  width: 100%;
  margin-top: 0.8rem;
  border-collapse: collapse;
  font-size: 0.9rem;
}

/* A heading for the table, so above it. The global caption rule puts captions underneath, where
   they serve as footnotes. */
.national-years caption {
  caption-side: top;
  padding-top: 0;
  padding-bottom: 0.35rem;
  color: var(--muted);
  font-size: 0.85rem;
  text-align: left;
}

.national-years th,
.national-years td {
  padding: 0.15rem 0.5rem 0.15rem 0;
  text-align: left;
}

.national-years th:not(:first-child),
.national-years td:not(:first-child) {
  text-align: right;
}

#reset-form {
  margin-top: 0.7rem;
}

/* justify-content: start keeps the button its own width. Without it the auto column took every pixel
   the field left over, and Look up stretched across the rest of the row. */
.vendor-bar {
  display: grid;
  grid-template-columns: minmax(14rem, 26rem) auto;
  justify-content: start;
  gap: 0.55rem;
  align-items: end;
}

#vendor-summary {
  margin: 0.6rem 0 0.4rem;
}

/* A supplier's or department's name heads the detail, with its ABN as the line under it. */
#vendor-summary h3,
#department-summary h3 {
  margin: 0.9rem 0 0;
  font-size: 1.25rem;
}

#vendor-summary .detail-abn,
#department-summary .detail-abn {
  margin: 0.1rem 0 0.8rem;
}

#vendor-summary .national-figures dd,
#department-summary .national-figures dd {
  overflow-wrap: anywhere;
}

/* A detail filtered to one party on the other door says so under its heading: "Only contracts with
   Hays", the name a link to that party whole, and a ✕ that shows this detail's party whole. */
.filter-chip {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.5rem;
  max-width: 100%;
  margin: 0 0 0.8rem;
  padding: 0.25rem 0.3rem 0.25rem 0.75rem;
  background: var(--row);
  border: 1px solid var(--line);
  border-radius: 0.4rem;
}

.filter-chip a {
  font-weight: 600;
  overflow-wrap: anywhere;
}

.filter-chip .filter-clear {
  min-width: 2rem;
  min-height: 2rem;
  padding: 0 0.5rem;
  border-radius: 0.3rem;
}

/* One-person contracts (plans/2026-10-13-supplier-contract-plan.md): the filter above a contracts
   table, and under a CN the button that opens that contract on the contract door. */
.people-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.75rem;
  margin: 0 0 0.6rem;
}

.people-filter .hint {
  margin: 0;
}

.people-filter .filter-chip {
  margin: 0;
}

.person-rate {
  display: block;
  min-height: 1.5rem;
  margin-top: 0.15rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font: inherit;
  font-size: 0.85em;
  text-align: left;
  text-decoration: underline;
  cursor: pointer;
}

.person-rate:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

#vendor-summary > .hint:last-child,
#department-summary > .hint:last-child {
  margin-bottom: 0.9rem;
}

/* The picks say what they are before the table starts. */
.picks-heading {
  margin: 0.9rem 0 0.4rem;
  font-size: 1rem;
  font-weight: 600;
}

/* What to do with a supplier's or department's numbers comes after them: the going-rate link and the
   share box, side by side when there is room. They used to sit between the summary and the figures. */
/*
 * The search door (plans/2026-10-23-contract-search-plan.md). The ready-made searches sit above the form
 * as a row of pressable buttons; the form is the words, the two names, when it ends and the order, with
 * the rest under "More filters".
 */
.contracts-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.7rem 0 0.8rem;
}

.contracts-preset {
  white-space: normal;
  text-align: left;
}

.contracts-preset[aria-pressed="true"] {
  background: var(--row);
  border-color: var(--accent);
  color: var(--ink);
}

.contracts-bar {
  display: grid;
  grid-template-columns: minmax(12rem, 1.5fr) minmax(9rem, 1fr) minmax(9rem, 1fr) minmax(9.5rem, 0.8fr) minmax(12.5rem, 0.9fr);
  gap: 0.55rem;
  align-items: end;
}

.contracts-checks {
  display: flex;
  flex-wrap: wrap;
  margin-top: 0.45rem;
}

.contracts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.55rem;
  align-items: end;
  margin: 0.6rem 0 0.7rem;
}

.contracts-count {
  margin: 0.9rem 0 0;
  font-weight: 600;
}

.contracts-austender,
.contracts-ref {
  display: block;
  font-size: 0.82em;
}

.contracts-ref {
  color: var(--muted);
  margin-top: 0.15rem;
}

.contracts-dates span {
  display: block;
}

.contracts-dates span,
td.contracts-dates {
  white-space: nowrap;
}

/* A cancelled notice is in the list but counts for nothing: its text is muted, and a tag says why,
   in the colours the contract door's own cancelled line uses. */
tr.contracts-cancelled td {
  color: var(--muted);
}

.cancelled-tag {
  display: inline-block;
  margin-top: 0.2rem;
  padding: 0 0.4rem;
  border-left: 3px solid var(--bad-rule);
  background: var(--bad-bg);
  color: var(--bad-ink);
  font-size: 0.78rem;
}

.contracts-pager {
  max-width: 28rem;
}

.detail-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 0.6rem 1.4rem;
  align-items: start;
  margin-top: 1.1rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line);
}

.detail-actions .share-box {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* A long button label wraps rather than running off a phone's edge. */
.detail-actions button {
  max-width: 100%;
  white-space: normal;
}

details.year-table {
  margin: 0.2rem 0 0.9rem;
}

details.year-table summary {
  font-weight: normal;
  color: var(--muted);
  font-size: 0.9rem;
}

#vendor-summary strong {
  font-size: 1.25rem;
}

/* The spellings fold sat flush against the breaks' footnote above it. */
#vendor-names,
#department-names {
  margin: 0.8rem 0;
}

#vendor-names-list {
  margin: 0.4rem 0 0.6rem;
  padding-left: 1.2rem;
  columns: 3 16rem;
}

#vendor-names-list li {
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .vendor-bar {
    grid-template-columns: 1fr;
  }

  #vendor-names-list {
    columns: 2 12rem;
  }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.rates fieldset {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  border: 0;
  margin: 0;
  padding: 0;
}

.rates legend {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.pair {
  grid-template-columns: 1fr 1fr auto;
  margin-top: 0.7rem;
}


.pair.calc {
  grid-template-columns: 1fr 1fr;
  align-items: start;
  margin-top: 1rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--line);
}

fieldset {
  border: 1px solid var(--line);
  margin: 0.7rem 0;
  padding: 0.4rem 0.7rem 0.55rem;
}

legend { padding: 0 0.25rem; }

input[type="checkbox"],
input[type="radio"] {
  margin: 0;
}

dl { margin: 0; }

dt {
  font-size: 0.82rem;
  color: var(--muted);
  margin-top: 0.4rem;
}

dd { margin: 0; }

.find {
  max-width: 28rem;
  margin-top: 0.8rem;
}

.table-wrap { overflow-x: auto; }

/* "Show N more" under a going table that lists only part of a broad scan. */
.going-more { margin: 0.5rem 0 1rem; white-space: normal; }

.table-wrap.scroll {
  max-height: 68vh;
  overflow: auto;
  margin-top: 0.35rem;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 0.35rem;
}

th,
td {
  text-align: left;
  vertical-align: top;
  padding: 0.32rem 0.4rem;
  border-bottom: 1px solid var(--line);
}

.scroll thead th {
  position: sticky;
  top: 0;
  background: var(--panel);
  z-index: 1;
}

/* The picks rows carry a Select button, which is taller than a line of text; top-aligned cells left
   every row's text riding above its own button. */
#vendor-picks-body td,
#department-picks-body td {
  vertical-align: middle;
}

#going-included td:nth-child(5),
#going-dropped td:nth-child(5) {
  max-width: 18rem;
}

#going-included td:nth-child(7),
#going-included td:nth-child(8),
#going-dropped td:nth-child(8),
#going-dropped td:nth-child(9) {
  white-space: nowrap;
}

/* The going tables never scroll sideways. An agency reference can be one unbroken string — fifty
   characters of PO numbers joined by commas — and held on one line it pushed the Included table past
   its box on a 1440px screen. The reference breaks inside its string when it has to; the other text
   columns are words, and breaking those mid-word read "Recruitme / nt". */
#going-included td:nth-child(3),
#going-dropped td:nth-child(3) {
  overflow-wrap: anywhere;
}

button.sort {
  background: transparent;
  color: inherit;
  border: 0;
  padding: 0;
  min-height: 0;
  font-weight: 600;
  text-align: inherit;
  width: 100%;
  white-space: normal;
}

th.num,
td.num { text-align: right; white-space: nowrap; }

th.num button.sort { text-align: right; }

/* The median is set larger, so the row lines up on the baseline: top-aligned, the other figures sat
   above it. */
.score td {
  vertical-align: baseline;
}

.score td:nth-child(4) {
  font-size: 1.35rem;
  font-weight: 600;
  color: var(--accent);
}

/* The going-rate breakdown's three views. The buttons are the page's existing secondary button,
   marked pressed like a door choice; a group name is a text button, not a link, because opening it
   changes the page's screen and adds a history entry. */
.breakdown-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.5rem 0 0.35rem;
}

.breakdown-tabs[hidden] { display: none; }

.breakdown-tab[aria-pressed="true"] {
  background: var(--row);
  border-color: var(--accent);
  color: var(--ink);
}

/* A table's Download CSV button and what it writes. The margins sit on the button and its hint, not on the bar,
   so a bar with both hidden takes no room. */
.csv-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.8rem;
}

/* The label says how many rows and of how many, so it can be long ("Download CSV, 3 of the 200 listed contracts"):
   it wraps, as the detail actions' buttons do, rather than make the page scroll sideways on a phone. */
.csv-bar .csv-download {
  margin: 0.5rem 0 0.35rem;
  max-width: 100%;
  white-space: normal;
  text-align: left;
}

.csv-bar .hint {
  flex: 1 1 18rem;
  margin: 0.5rem 0 0.35rem;
}

/* The Distribution table's per hour / per day switch: the same pressed button as the breakdown's tabs. */
.unit-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.5rem 0 0.35rem;
}

.unit-tabs[hidden] { display: none; }

.unit-tab[aria-pressed="true"] {
  background: var(--row);
  border-color: var(--accent);
  color: var(--ink);
}

#going-breakdown-table td:first-child {
  overflow-wrap: anywhere;
}

/* Only the desktop table needs the group column capped; on a phone `table.cards` owns the layout,
   and a max-width here would half-width every card (the id selector outranks `table.cards td`). */
@media (min-width: 641px) {
  #going-breakdown-table td:first-child { max-width: 20rem; }
}

.breakdown-open {
  background: transparent;
  border: 0;
  color: var(--accent);
  overflow-wrap: anywhere;
  padding: 0;
  text-align: left;
  text-decoration: underline;
  white-space: normal;
}

/* A dash or a starred same-period change has a title explaining the comparison; help makes it
   discoverable. */
.breakdown-change-note,
.breakdown-change-partial { cursor: help; }

/* A printed page shows the view on screen, not the control that switches it, and a group's name as
   text rather than as a button. */
@media print {
  .breakdown-tabs { display: none; }
  .unit-tabs { display: none; }
  .csv-bar { display: none; }
  .breakdown-open {
    color: inherit;
    min-height: 0;
    text-decoration: none;
  }
}

caption {
  caption-side: bottom;
  text-align: left;
  color: var(--muted);
  font-size: 0.88rem;
  padding-top: 0.4rem;
}

tr.clickable { cursor: pointer; }
tr.clickable:hover,
tr.clickable:focus { background: var(--row); }
tr.less td:first-child { padding-left: 1.2rem; }

.hourlies {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.75rem;
  margin: 0.8rem 0 0.4rem;
}

.hourlies div {
  border-top: 2px solid var(--accent);
  padding-top: 0.35rem;
}

.hourlies dd {
  font-size: 1.15rem;
  margin: 0;
}

details.notes { margin-top: 0.7rem; }

details summary {
  cursor: pointer;
  font-weight: 600;
}

details.notes .hint + .hint { margin-top: 0.55rem; }

ol.fine {
  margin: 0.7rem 0 0;
  padding-left: 1.2rem;
  color: var(--muted);
  font-size: 0.88rem;
}

a { color: var(--accent); }

/* Fine print: set apart below a rule, small and muted, across the page's width. Its links keep the
   muted colour and their underline, so they read as links without pulling the eye. */
footer {
  margin-top: 3rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-size: 0.78rem;
  line-height: 1.5;
}
footer p + p { margin-top: 0.6rem; }
footer a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.was {
  display: block;
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 400;
}

.chart-block {
  margin: 0.7rem 0 0.2rem;
}

/* "Where is your rate?" under the histogram. The fields reuse .going-fields; the sentence is the answer,
   so it reads at body size, not as a hint. */
.yours {
  margin: 0.9rem 0 0.4rem;
}
.going-fields > .field-yours { flex: 0 1 11rem; }
.going-fields > .field-yours-basis { flex: 1 1 15rem; }
.yours-result {
  margin: 0.6rem 0 0.2rem;
  font-variant-numeric: tabular-nums;
}
.yours-result:empty { display: none; }

.chart-caption {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  margin: 0.85rem 0 0.3rem;
  font-size: 0.85rem;
  color: var(--muted);
}

.chart-caption-name {
  color: var(--ink);
  font-weight: 600;
  letter-spacing: 0.01em;
}

.chart-caption-meta {
  font-size: 0.78rem;
  color: var(--muted);
}

.chart-block svg {
  display: block;
  width: 100%;
  height: auto;
}

/* Soft plate behind the bars, so the plot reads as its own surface. */
.chart-block .plot {
  fill: var(--row);
  fill-opacity: 0.55;
  stroke: var(--line);
  stroke-opacity: 0.9;
  stroke-width: 1;
}

.chart-block .bar {
  pointer-events: none;
  transform-box: fill-box;
  transform-origin: bottom;
  animation: chart-bar-grow 420ms cubic-bezier(0.22, 0.8, 0.24, 1) both;
}

@keyframes chart-bar-grow {
  from { transform: scaleY(0.02); }
  to { transform: scaleY(1); }
}

@media (prefers-reduced-motion: reduce) {
  .chart-block .bar { animation: none; }
}

.chart-block .stop-top {
  stop-color: var(--accent);
  stop-opacity: 0.92;
}

.chart-block .stop-bottom {
  stop-color: var(--accent);
  stop-opacity: 0.5;
}

/* The hover target is the whole column, not the bar, so an empty bin is still
   hoverable and a one-pixel bar is still easy to hit. */
.chart-block .hit {
  fill: transparent;
  pointer-events: all;
}

.chart-block .hit:hover {
  fill: var(--accent);
  opacity: 0.08;
}

/* The vendor and department charts' bars pick a year for the table below. The picked bar is solid and
   the rest step back, so the chart says which year the table is showing. */
#vendor-chart .hit,
#department-chart .hit { cursor: pointer; }
#vendor-chart .hit:focus-visible,
#department-chart .hit:focus-visible { outline: none; fill: var(--accent); opacity: 0.12; }
#vendor-chart svg.has-pick .bar,
#department-chart svg.has-pick .bar { opacity: 0.4; }
#vendor-chart svg.has-pick .bar.picked,
#department-chart svg.has-pick .bar.picked { opacity: 1; fill: var(--accent); }

.chart-block .axis,
.chart-block .grid,
.chart-block .tick,
.chart-block .marker,
.chart-block .marker-label,
.chart-block .tip-layer,
.chart-block .you-layer {
  pointer-events: none;
}

.chart-block .tip-box {
  fill: var(--ink);
  opacity: 0.95;
}

/* A shadow stays dark in both themes; in dark, --ink would make it a pale glow. */
.chart-block .tip-shadow {
  flood-color: var(--shadow);
  flood-opacity: 0.3;
}

.chart-block .tip-text {
  fill: var(--accent-ink);
  font-size: 12px;
  font-weight: 500;
}

.chart-block .axis {
  stroke: var(--muted);
  stroke-width: 1;
  opacity: 0.4;
}

.chart-block .grid {
  stroke: var(--muted);
  stroke-width: 1;
  opacity: 0.15;
  stroke-dasharray: 2 5;
}

.chart-block .tick {
  fill: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

/* These must be element-qualified: the labels carry the same marker-* classes, and a
   stroke on a text element outlines every glyph, which is what made the percentile
   labels look bold and blurry. */
.chart-block line.marker {
  stroke-width: 1.5;
  stroke-dasharray: 4 4;
}

.chart-block line.marker-p25,
.chart-block line.marker-p75 {
  stroke: var(--muted);
  opacity: 0.85;
}

.chart-block line.marker-median {
  stroke: var(--ink);
  stroke-width: 2;
  stroke-dasharray: none;
}

.chart-block .marker-label {
  fill: var(--muted);
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* Same weight as the quartiles on purpose: a heavier weight gets synthesised by font
   stacks that have no 600 face, and synthetic bold at 12px is what looked blurry. The
   median is set apart by colour and by its solid rule instead. */
.chart-block .marker-label.marker-median {
  fill: var(--ink);
}

/* The person's own rate. Not a colour of its own: a thick --ink rule inside a halo of --panel, so it reads
   over the --accent bars in both themes, with a flag at its top and its label on a row of its own. What
   sets it apart from the median's rule is the weight, the halo, the flag and the word "You", not hue. The
   rules are element-qualified, as the markers' are: a stroke on the label's text would outline every glyph. */
.chart-block line.you-halo {
  stroke: var(--panel);
  stroke-width: 8;
  stroke-linecap: round;
  opacity: 0.9;
}

.chart-block line.you-line {
  stroke: var(--ink);
  stroke-width: 3;
  stroke-linecap: round;
}

.chart-block polygon.you-flag {
  fill: var(--ink);
  stroke: var(--panel);
  stroke-width: 2;
  stroke-linejoin: round;
}

.chart-block .you-label {
  fill: var(--ink);
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 980px) {
  .door-choices,
  .toolbar,
  .going-settings,
  .pair,
  .pair.calc,
  .hourlies {
    grid-template-columns: 1fr 1fr;
  }

  /* The period takes a row, and the drop band the next, each at the full width. */
  .going-when,
  .going-band { grid-column: 1 / -1; }

  .vendor-bar button {
    grid-column: 1 / -1;
  }

  /* Six doors in a two-column grid fill three rows exactly. The search's words take a row of their own. */
  .contracts-bar {
    grid-template-columns: 1fr 1fr;
  }

  .contracts-bar .field:first-child {
    grid-column: 1 / -1;
  }
}

@media (max-width: 640px) {
  /* The count recounts as the person types, but under eight stacked fields it is two screens down.
     It rides the bottom of the screen while the fields are in view, and settles above the results. */
  .finder-status {
    position: sticky;
    bottom: 0;
    z-index: 1;
    margin: 0.8rem -1rem 0;
    padding: 0.55rem 1rem 0.6rem;
    background: var(--panel);
    border-top: 1px solid var(--line);
  }

  .finder-count {
    flex: 1 1 0;
    font-size: 1rem;
  }

  .finder-jump:not([hidden]) {
    display: inline-block;
  }
}

@media (max-width: 640px) {
  .door-choices,
  .contracts-bar,
  .toolbar,
  .pair,
  .pair.calc,
  .hourlies,
  .national-lists {
    grid-template-columns: 1fr;
  }

  /* Four figures in four phone-width columns broke the published span into four lines. The three
     short counts keep a row; the span takes a row of its own, where it fits on one line. */
  .national-figures {
    grid-template-columns: repeat(3, 1fr);
  }

  .national-figures > div:last-child {
    grid-column: 1 / -1;
  }

  /* On a phone the period takes a row, and the dates and the drop band pair up beneath it. */
  .going-fields > .field { flex: 1 1 calc(50% - 0.55rem); min-width: 0; }
  .going-fields > .field-period { flex-basis: 100%; }
  .going-go button { width: 100%; }

  /* Beside "Based in" the band select had about 15rem, and cut its label off before the rate. On a
     phone it takes a row of its own. */
  .rates .field-band,
  #payroll-fields .field-band {
    flex: 1 1 100%;
    min-width: 0;
  }

  /* A contract table is a stack of cards on a phone: one card per row, one line per cell, the
     column's name in a gutter on the left (app.js copies it from the header into data-label). As a
     table it scrolled sideways, and each row was as tall as its narrowest column's wrapped text. */
  table.cards,
  table.cards tbody,
  table.cards tr {
    display: block;
    width: 100%;
  }

  table.cards tr {
    padding: 0.45rem 0;
    border-bottom: 1px solid var(--line);
  }

  /* A grid, not an absolutely placed label: a long column name wraps inside its 7rem and the line
     grows to fit it, instead of running into the next line. */
  table.cards td,
  table.cards td.num {
    display: grid;
    grid-template-columns: 7rem minmax(0, 1fr);
    column-gap: 0.5rem;
    align-items: baseline;
    max-width: none;
    padding: 0.12rem 0;
    border: 0;
    text-align: left;
    white-space: normal;
    overflow-wrap: anywhere;
  }

  table.cards td > * {
    grid-column: 2;
    justify-self: start;
  }

  /* The desktop column rules name their tables by id, so they outrank the two rules above; these
     match every cell at the same weight, later, to lift the description cap and the no-wrap. */
  #going-included td:nth-child(n),
  #going-dropped td:nth-child(n) {
    max-width: none;
    white-space: normal;
  }

  table.cards td::before {
    content: attr(data-label);
    grid-column: 1;
    color: var(--muted);
    font-size: 0.8rem;
    overflow-wrap: normal;
  }

  table.cards td:empty {
    display: none;
  }

  /* The short summary tables (the year, supplier and agency breaks, and the distribution) stay
     tables. "Ceiling incl. GST" held its column to one line, and with a full-dollar figure beside a
     long supplier name it pushed Contracts off the edge. The headings wrap here and the cells are a
     little smaller and tighter, which fits the three columns from 360px up; below that the table
     scrolls. */
  .score table {
    font-size: 0.9rem;
  }

  .score th.num {
    white-space: normal;
  }

  .score th,
  .score td {
    padding-left: 0.3rem;
    padding-right: 0.3rem;
  }

  /* A sortable table keeps its sort buttons, as one wrapping row above the cards. */
  table.cards thead tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.2rem 0.8rem;
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--line);
  }

  table.cards thead tr::before {
    content: "Sort by";
    color: var(--muted);
    font-size: 0.8rem;
  }

  table.cards thead th {
    position: static;
    padding: 0;
    border: 0;
    font-size: 0.85rem;
  }

  table.cards thead:not(:has(button.sort)) {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }

  /* Touch-sized controls. The sort headings, the notice links in the cards, the fold-outs and the
     margin slider were sized for a mouse pointer: 16-22px tall, the sort headings packed a few px
     apart. A fingertip needs about 2rem, so each gets that much to land on. */
  table.cards thead tr {
    align-items: center;
    gap: 0.35rem 0.4rem;
  }

  table.cards thead button.sort {
    min-height: 2rem;
    padding: 0.2rem 0.6rem;
    border: 1px solid var(--line);
    border-radius: 1rem;
  }

  /* Sort chips over an empty table are a row of buttons that do nothing. */
  table.cards:not(:has(tbody tr)) thead {
    display: none;
  }

  table.cards td a {
    display: inline-block;
    padding: 0.3rem 0;
  }

  details summary {
    padding: 0.4rem 0;
  }

  #margin-range {
    height: 2rem;
  }
}

/* A going table that is wider than its box becomes cards: app.js (fitGoingTables) measures it after
   each paint and sets as-cards, so it stays a table whenever it fits and never scrolls sideways. These
   are the phone block's card rules, scoped to that class; on a phone the 640px block already applies. */
#going-panel table.as-cards,
#going-panel table.as-cards tbody,
#going-panel table.as-cards tr {
  display: block;
  width: 100%;
}

#going-panel table.as-cards tr {
  padding: 0.45rem 0;
  border-bottom: 1px solid var(--line);
}

#going-panel table.as-cards td,
#going-panel table.as-cards td.num {
  display: grid;
  grid-template-columns: 9rem minmax(0, 1fr);
  column-gap: 0.75rem;
  align-items: baseline;
  max-width: none;
  padding: 0.12rem 0;
  border: 0;
  text-align: left;
  white-space: normal;
  overflow-wrap: anywhere;
}

#going-panel table.as-cards td > * {
  grid-column: 2;
  justify-self: start;
}

#going-panel table.as-cards td:nth-child(n) {
  max-width: none;
  white-space: normal;
}

#going-panel table.as-cards td::before {
  content: attr(data-label);
  grid-column: 1;
  color: var(--muted);
  font-size: 0.85rem;
  overflow-wrap: normal;
}

#going-panel table.as-cards td:empty {
  display: none;
}

#going-panel table.as-cards thead tr {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2rem 0.8rem;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--line);
}

#going-panel table.as-cards thead tr::before {
  content: "Sort by";
  color: var(--muted);
  font-size: 0.85rem;
}

#going-panel table.as-cards thead button.sort {
  min-height: 2rem;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: 1rem;
}

#going-panel table.as-cards thead th {
  position: static;
  padding: 0;
  border: 0;
  font-size: 0.9rem;
}

/*
 * The finder door. Its fields wrap in a grid that keeps each about the width of what it holds; the
 * field the server says would split the remaining notices most is outlined, so the next question
 * to answer is visible without a wizard.
 */
.finder-fields {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(13rem, 100%), 1fr));
  gap: 0 0.8rem;
  align-items: start;
}

.finder-fields input,
.finder-fields select {
  width: 100%;
  min-width: 0; /* a date box's own minimum width would push past a narrow phone's column */
}

/* iOS centres a date's text; every other box here is left-aligned. */
.finder-fields input[type="date"]::-webkit-date-and-time-value {
  text-align: left;
}

/* A date box draws a little taller than a text box; one height keeps a row's boxes level. */
.finder-fields input[type="text"],
.finder-fields input[type="date"],
.finder-fields select {
  height: 2.4rem;
}

/* A thumb-sized tick: the label around it is the tap target, and it is at least 2rem tall. */
.finder-fields input[type="checkbox"] {
  width: 1.15rem;
  height: 1.15rem;
}

.finder-fields label.check {
  min-height: 2rem;
}

.finder-fields .field {
  display: grid;
  padding: 0.3rem 0.4rem 0.55rem;
  border: 1px solid transparent;
  border-radius: 0.4rem;
}

/* Each field is three rows — label, box, the month tick — shared across its row of the grid, so a
   label that wraps to two lines moves the whole row's boxes down together instead of only its own.
   Labels sit on the box, so a one-line label beside a two-line one stays next to its box. */
@supports (grid-template-rows: subgrid) {
  .finder-fields .field {
    grid-row: span 3;
    grid-template-rows: subgrid;
  }
}

.finder-fields .field > label:first-child {
  align-self: end;
}

/* "I only know the month" swaps the date box for a month and a year, so the day the person does not
   know is gone rather than left as a box they might think still counts. */
.finder-month-pick {
  display: flex;
  gap: 0.4rem;
}

.finder-month-pick[hidden] {
  display: none;
}

.finder-month-pick select:first-child {
  flex: 3 1 0;
}

.finder-month-pick select:last-child {
  flex: 2 1 0;
}

a.finder-austender {
  display: block;
  padding: 0.3rem 0;
  font-size: 0.82rem;
  white-space: nowrap;
}

.finder-fields .field.finder-next {
  border-color: var(--accent);
  background: var(--row);
}

.finder-status {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.8rem;
  margin-top: 0.8rem;
}

.finder-status .hint {
  flex: 1 1 100%;
}

/* The way down to the results is for phones, where they are screens below the fields. */
.finder-jump {
  display: none;
}

/* The short cut: a purchase order number is the notice's agency reference, so it skips the questions. */
.finder-po {
  margin: 0.4rem 0 0.8rem;
  padding: 0.55rem 0.7rem 0.65rem;
  border: 1px solid var(--line);
  border-radius: 0.4rem;
}

.finder-po label {
  color: var(--ink);
  font-size: 0.92rem;
  margin-bottom: 0.35rem;
}

.finder-po .hint {
  margin: 0.4rem 0 0;
}

/* The purchase order number and the questions are two ways to the same notice, not two steps:
   each is headed as a way in, with a ruled "or" between them. */
.finder-way {
  margin: 0 0 0.35rem;
}

.finder-or {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 0.6rem;
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.finder-or::before,
.finder-or::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--line);
}

/* What the person typed that the notices do not bear out — a vendor or department on none of them,
   a name too broad to use. Said once, above the list, rather than left to each row's reasons. */
.finder-notes {
  margin: 0.6rem 0 0;
  padding: 0.45rem 0.7rem;
  border-left: 3px solid var(--accent);
  background: var(--row);
  font-size: 0.92rem;
}

.finder-count {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
}

ul.finder-why {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.85rem;
}

ul.finder-why li::before {
  display: inline-block;
  width: 1.1rem;
  content: "·";
}

ul.finder-why li.ok::before { content: "✓"; color: var(--good); }
ul.finder-why li.miss::before { content: "✗"; color: var(--bad); }

.finder-confidence {
  white-space: nowrap;
}
