
/* Fonts — FS Industrie, self-hosted from the External Handbook (already
   served publicly there, so web use is established). WOFF2 is the primary
   format (~half the OTF weight, so the swap window is short enough to avoid
   the visible FOUT in the header); the OTFs stay as a fallback source and
   keep handbook parity. The body weights (400/700/900) are preloaded in the
   page <head> so they download in parallel with the CSS. */
@font-face {
  font-family: "FS Industrie";
  src: url("/fonts/FSIndustrie-Book.woff2") format("woff2"),
       url("/fonts/FSIndustrie-Book.otf") format("opentype");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "FS Industrie";
  src: url("/fonts/FSIndustrie-Regular.woff2") format("woff2"),
       url("/fonts/FSIndustrie-Regular.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "FS Industrie";
  src: url("/fonts/FSIndustrie-Bold.woff2") format("woff2"),
       url("/fonts/FSIndustrie-Bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "FS Industrie";
  src: url("/fonts/FSIndustrie-Black.woff2") format("woff2"),
       url("/fonts/FSIndustrie-Black.otf") format("opentype");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}

/*
   Palette (CDS Brandbook v6, as implemented on the handbook), with the
   handbook's WCAG AA contrast table (on white):
     #1BA396 teal        — 2.92:1  decorative use only (borders, accents)
     #138078 dark teal   — 4.78:1  all text links / interactive elements
     #1B345C navy        — 12.4:1  headings
     #1B1B1B charcoal    — 17.3:1  body text
     #F05222 orange      — 3.54:1  large text / decorative only
     #E6007D magenta     — 4.50:1  passes, use sparingly
     #EDEDED grey        — backgrounds only, never text
   (Normal-size text needs 4.5:1 for AA.)
*/
:root {
  --cds-teal:      #1BA396;
  --cds-teal-dark: #138078;
  --cds-navy:      #1B345C;
  --cds-charcoal:  #1B1B1B;
  --cds-grey:      #EDEDED;
  --cds-white:     #FFFFFF;
  --cds-orange:    #F05222;
  --cds-magenta:   #E6007D;

  /* The one place to change type. Fallback stack matches the handbook. */
  --font-body: "FS Industrie", "Calibri", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-heading: var(--font-body);
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 400;
  color: var(--cds-charcoal);
  background: var(--cds-white);
  line-height: 1.5;
}

/* Headings: h1/h2 navy, h3 dark teal — as the handbook */
h1, h2, h3 {
  font-family: var(--font-heading);
  line-height: 1.2;
}
h1 { color: var(--cds-navy); font-weight: 900; }
h2 { color: var(--cds-navy); font-weight: 700; }
h3 { color: var(--cds-teal-dark); font-weight: 700; }

/* Links: dark teal, underlined (WCAG 1.4.1 — not colour alone) */
a {
  color: var(--cds-teal-dark);
  text-decoration: underline;
  text-underline-offset: 2px;
}
a:hover { text-decoration-thickness: 2px; }

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--cds-charcoal);
  color: var(--cds-white);
  padding: 0.5rem 1rem;
  z-index: 11; /* above the sticky header */
}
.skip-link:focus { position: fixed; }
.skip-link:focus { left: 0; }

/* Focus indicator — as the handbook (WCAG 2.4.7) */
:focus-visible {
  outline: 2px solid var(--cds-teal-dark);
  outline-offset: 2px;
}

/* Header: dark teal (white on it is 4.78:1), white logo asset.
   The header never moves (162883, supersedes sticky from 162882): the
   body is a non-scrolling shell and .page-scroll is the only scroll
   container — the header sits outside it. Anchor targets land inside
   the scroller, always clear of the header. Short viewports (and print)
   revert to normal flow so the header gives the space back.

   overscroll-behavior on the shell itself, not just .page-scroll: that
   property only suppresses bounce on an element that actually scrolls.
   On short pages .page-scroll has no overflow, and the header always
   sits outside it — in both cases the gesture chains to the viewport,
   which is what rubber-bands and drags the header. Killing the bounce
   on html/body (a non-scrolling shell) stops that everywhere. */
html, body { height: 100%; overscroll-behavior: none; }
body { display: flex; flex-direction: column; }
.page-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: none;
  scroll-padding-top: 0.5rem; /* anchored rows land with a little air */
  /* Sticky-footer layout (story 162971): the disclaimer banner sits at the
     bottom of the page, not floating mid-viewport on short pages. The 1fr
     content row grows to fill; the auto footer row pins to the bottom. On
     long pages the content row exceeds the viewport, the scroller scrolls,
     and the footer flows after the content. No bounce — overscroll is killed
     on the shell above. */
  display: grid;
  grid-template-rows: 1fr auto;
}
@media (max-height: 30rem), print {
  html, body { height: auto; }
  body { display: block; }
  .page-scroll { overflow-y: visible; }
}

/* Self-service profile export (FR-51). Reads cleanly on screen; the @media
   print block strips the app chrome so browser Save-as-PDF is a tidy document. */
.export-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
  margin-bottom: 1rem;
}
.profile-export h2 {
  border-bottom: 2px solid var(--cds-teal-dark);
  padding-bottom: 0.2rem;
  margin-top: 1.5rem;
}
.profile-export h3 {
  margin: 0.75rem 0 0.25rem;
  font-size: 0.95rem;
  color: var(--cds-charcoal);
}
.profile-export .export-sub { color: #555; margin-top: 0; }
.profile-export .export-stale { color: var(--cds-orange); font-weight: 700; }
.profile-export .x-empty { color: #777; font-style: italic; }
ul.export-list { list-style: none; padding: 0; margin: 0 0 0.5rem; }
ul.export-list li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.15rem 0;
  break-inside: avoid;
}
ul.export-list .x-name { font-weight: 700; }
ul.export-list .x-detail { color: #444; text-align: right; }
.export-foot { margin-top: 1.5rem; color: #666; }

@media print {
  header.site, footer.site, .skip-link, .no-print { display: none !important; }
  main { max-width: none; padding: 0; }
  .profile-export { color: #000; }
  .profile-export section { break-inside: avoid; }
  .profile-export h2 { break-after: avoid; }
  ul.export-list .x-detail { color: #000; }
}
header.site {
  background: var(--cds-teal-dark);
  color: var(--cds-white);
  padding: 0.6rem 1rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
}
header.site .logo {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--cds-white);
  text-decoration: none;
  font-weight: 700;
  font-size: 1.1rem;
}
/* Supplied CDS asset only — never recreated or distorted; exclusion zone
   respected by the surrounding flex gap/padding. */
/* The wordmark is ~1.7x the cap height of "Skills Matrix", so align-items
   centring (geometrically correct) still drops its base ~4.5px below the text
   baseline — and the eye lines things up on that shared baseline, so it reads
   as low. Lift it so the base sits on the baseline, letting the taller "d"
   rise above the caps as a larger letterform should. Value measured against
   the rendered header. Baseline-kiss sits at ~-4.5px (the wordmark is all
   round-bottomed letters, which overshoot the baseline to look aligned); the
   value here is lifted further by brand preference to ride higher in the bar.
   Repositions only; never scales/distorts the supplied asset. */
header.site .logo img { height: 1.8rem; width: auto; transform: translateY(-5.5px); }
header.site nav a {
  color: var(--cds-white);
  margin-right: 0.75rem;
  text-decoration: none;
}
header.site nav a:hover { text-decoration: underline; text-underline-offset: 2px; }

main {
  width: 100%; /* as a grid item it must fill the column up to max-width, not shrink to content */
  max-width: 60rem;
  margin: 0 auto;
  padding: 1rem;
}

/* Footer: charcoal — as the handbook */
footer.site {
  background: var(--cds-charcoal);
  color: rgba(255, 255, 255, 0.7);
  margin-top: 2rem;
  padding: 1rem;
  text-align: center;
  font-size: 0.875rem;
}
footer.site a { color: var(--cds-white); }

/* Tables: navy header row, grey even rows — as the handbook */
.table-wrap { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; margin: 0.5rem 0 1rem; }
th, td { text-align: left; padding: 0.5rem; border-bottom: 1px solid var(--cds-grey); }
thead th { background: var(--cds-navy); color: var(--cds-white); }
thead th a { color: var(--cds-white); text-decoration: none; }
thead th a:hover { text-decoration: underline; text-underline-offset: 2px; }
tbody tr:nth-child(even) { background: var(--cds-grey); }

/* Forms: stacked, generous targets (WCAG 2.2 target size). Modern control look
   applied app-wide (story 162918): a softer #878787 border (kept >=3:1 for WCAG
   1.4.11) and gentler radius than the handbook's heavier form style. */
label { display: inline-block; margin: 0.25rem 0; }
input, select, button, textarea {
  font: inherit;
  padding: 0.4rem 0.6rem;
  min-height: 24px;
  border: 1px solid #878787;
  border-radius: 6px;
  background: var(--cds-white);
  color: var(--cds-charcoal);
  max-width: 100%;
}
/* Buttons: dark teal with white text (4.78:1 — AA) */
button {
  background: var(--cds-teal-dark);
  color: var(--cds-white);
  border: none;
  font-weight: 700;
  cursor: pointer;
  padding: 0.45rem 0.9rem;
}
button:hover { background: var(--cds-navy); }
button:disabled, button:disabled:hover {
  background: var(--cds-grey);
  color: #6B6B6B;
  cursor: not-allowed;
}
/* A busy button (mid-save) is also disabled, so it greys via the rule above; the
   progress cursor distinguishes "working" from "you can't click this" (app.js
   sets aria-busy on the submitter while a save/import is in flight). */
button[aria-busy="true"], button[aria-busy="true"]:hover { cursor: progress; }

/* Selects, app-wide (story 162918): drop the native chrome and draw our own
   chevron, round the corners; hover warms the border, focus uses the global teal
   outline. The .edit-inline override (above) keeps panel selects full-width. */
select {
  appearance: none;
  -webkit-appearance: none;
  border-radius: 8px;
  padding: 0.45rem 2rem 0.45rem 0.7rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none' stroke='%23595959' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
  background-size: 0.85rem;
  line-height: 1.3;
  cursor: pointer;
}
select:hover { border-color: var(--cds-teal-dark); }

form { margin: 0.5rem 0; }

/* CSV import upload forms (story 162919): the form sits bare in a card, so it
   needs its own breathing room — the options fieldset is a tidy panel and the
   action buttons get a clear gap above and below rather than hugging the
   fieldset and the card edge. */
.upload-form { margin: 0.25rem 0; }
.upload-form > label { display: block; margin-bottom: 0.25rem; }
.import-options {
  margin: 1rem 0;
  padding: 0.4rem 1rem 0.85rem;
  border: 1px solid var(--cds-grey);
  border-radius: 8px;
}
.import-options legend { padding: 0 0.4rem; font-weight: 700; color: #595959; }
.import-options label.check { display: flex; align-items: center; gap: 0.55rem; margin: 0.55rem 0; }
.import-options input[type="checkbox"] {
  width: auto;
  min-height: 0;
  margin: 0;
  padding: 0;
}
.import-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; margin: 1.25rem 0 0.5rem; }

/* Sector multi-select on the client add/edit forms (Feature 163275): a tidy
   bordered fieldset of checkboxes, mirroring the import-options panel. */
.sector-picker {
  margin: 0.8rem 0;
  padding: 0.4rem 1rem 0.85rem;
  border: 1px solid var(--cds-grey);
  border-radius: 8px;
}
.sector-picker legend { padding: 0 0.4rem; font-weight: 700; color: #595959; }
.sector-picker label.check { display: flex; align-items: center; gap: 0.55rem; margin: 0.4rem 0; }
.sector-picker input[type="checkbox"] { width: auto; min-height: 0; margin: 0; padding: 0; }

/* A client with no sector yet (bold so meaning isn't carried by colour alone),
   and the inline action cluster on client/sector table rows. */
.needs-attention { color: var(--cds-orange); font-weight: 700; }
.row-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; }

/* Bid profile generation (§6.8): a page-level GET form in a card, plus the
   editable draft textarea. Mirrors the import-form breathing room. */
.bidprofile-form > label { display: block; margin: 0.7rem 0 0.25rem; }
/* The Emphasis free-text steer fills the form width on its own line (story
   163216) — at the browser default it only showed a few words. */
.bidprofile-form > label input[type="text"] { display: block; width: 100%; margin-top: 0.3rem; }
.bidprofile-form fieldset {
  border: 1px solid var(--cds-grey);
  border-radius: 8px;
  margin: 0.25rem 0 0.7rem;
  padding: 0.4rem 1rem 0.6rem;
}
.bidprofile-form legend { padding: 0 0.4rem; font-weight: 700; color: #595959; }
.bidprofile-form fieldset label,
.bidprofile-form label.check { display: flex; align-items: center; gap: 0.55rem; margin: 0.45rem 0; }
.bidprofile-form input[type="checkbox"],
.bidprofile-form input[type="radio"] {
  width: auto;
  min-height: 0;
  margin: 0;
  padding: 0;
}
.bidprofile-draft { width: 100%; font: inherit; }
/* Copy button is a JS-only action (story 163095): hidden until app.js sets .js,
   so no-JS users never see a dead control — they select the textarea by hand. */
.bidprofile-copy { display: none; }
.js .bidprofile-copy { display: inline-block; }

/* A field that only applies for one <select> value — e.g. the "Other — add a new
   category" free-text box on the cert forms (story 163132). It ships visible so
   it always works without JS; .js hides it and app.js reveals it only when the
   trigger value is chosen (data-reveal-target / data-reveal-when in app.js). */
.js .reveal { display: none; }
.js .reveal.revealed { display: block; }

td form { display: inline-block; margin: 0 0.25rem 0 0; }
.controls form { display: inline-block; margin: 0 0.5rem 0.25rem 0; }
input[type="number"] { width: 4.5em; }
.indent { padding-left: 1.75rem; }

/* Taxonomy: discipline cards, display-first rows, disclosure editing (162845) */
.card {
  border: 1px solid var(--cds-grey);
  border-radius: 8px;
  padding: 0.75rem 1.25rem 1rem;
  margin: 1.25rem 0;
  box-shadow: 0 1px 3px rgba(27, 27, 27, 0.08);
}
.card-head h2 { margin: 0.25rem 0; }
.card-head .meta { flex: 1; }
.row { display: flex; align-items: center; gap: 0.75rem; padding: 0.3rem 0; }
.cap-row { border-bottom: 2px solid var(--cds-teal); margin-top: 0.75rem; }
.cap-row .name { font-weight: 700; color: var(--cds-teal-dark); }
ul.skills { list-style: none; margin: 0; padding: 0 0 0 1rem; }
ul.skills .add-row { border-bottom: none; }
.row .name { min-width: 12rem; }
.row .desc { flex: 1; color: #595959; font-size: 0.9rem; }
.row .controls { display: flex; align-items: center; gap: 0.1rem; margin-left: auto; }
.row .controls form { margin: 0; }
/* Skills-library skill rows (story 163150): a fixed-width name column so the
   descriptions line up, with long names and descriptions wrapping instead of
   overflowing. Scoped to ul.skills so profile/catalogue/admin rows are
   untouched. align-items: start keeps a wrapped name aligned with its row. */
ul.skills .row { align-items: start; }
ul.skills .row .name { flex: 0 0 18rem; min-width: 0; overflow-wrap: anywhere; }
ul.skills .row .desc { min-width: 0; overflow-wrap: anywhere; }
/* A catalogue row's optional description: a quiet second line under the row,
   so the field we capture is actually shown (cert catalogue). */
.cert-desc { margin: 0 0 0.5rem; color: #595959; font-size: 0.9rem; max-width: 60rem; }
/* Post-save confirmation (e.g. the admin Settings page). */
.saved-note { color: var(--cds-teal-dark); font-weight: 700; }

button.ghost { background: transparent; color: #6b6b6b; border: none; font-weight: 400; padding: 0.2rem 0.45rem; }
button.ghost:hover { background: var(--cds-grey); color: var(--cds-teal-dark); }
button.ghost:disabled, button.ghost:disabled:hover { background: transparent; color: #c6c6c6; }

details.add > summary {
  list-style: none;
  cursor: pointer;
  color: var(--cds-teal-dark);
  font-weight: 600;
  padding: 0.2rem 0.45rem;
  display: inline-block;
}
details.add > summary::-webkit-details-marker { display: none; }

/* Inline edit panel (162847) — add-forms share the treatment (162850) */
.edit-link {
  font-weight: 600;
  padding: 0.2rem 0.45rem;
  text-decoration: none;
}
ul.skills > li.item { border-bottom: 1px solid var(--cds-grey); }
ul.stack { list-style: none; margin: 0; padding: 0; }
ul.stack > li.item { border-bottom: 1px solid var(--cds-grey); }
/* Project-experience activities/outcome shown under the row (story 163198). */
.exp-detail { color: #595959; font-size: 0.9rem; padding: 0 0 0.4rem; }
.exp-detail small { display: block; margin: 0.1rem 0; }
ul.skills > li.item > .row { border-bottom: none; }
.edit-inline,
details.add[open] > form {
  background: #fafafa;
  border-left: 4px solid var(--cds-teal);
  border-radius: 0 6px 6px 0;
  padding: 0.85rem 1.25rem 1rem;
  margin: 0.25rem 0 0.75rem;
}
.edit-inline label,
details.add label {
  display: block;
  margin: 0.5rem 0 0.75rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #595959;
}
/* Field hint: a <small> inside an add-form label is a sentence-case prompt,
   not part of the uppercase caption — drop it onto its own quiet line. */
details.add label small {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.8rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: #595959;
}
.edit-inline input,
.edit-inline select,
.edit-inline textarea,
details.add input,
details.add select,
details.add textarea {
  display: block;
  width: 100%;
  max-width: 34rem;
  margin-top: 0.3rem;
  font-size: 1rem;
  border: 1px solid #878787;
  border-radius: 6px;
}
/* Free-text boxes (e.g. Activities, Outcome & value on a project) need room to
   write in — the shared 24px min-height suits one-line inputs, not paragraphs. */
.edit-inline textarea,
details.add textarea {
  min-height: 5.5rem;
  resize: vertical;
}
.edit-inline form { margin: 0; }
.edit-footer { display: flex; align-items: center; gap: 1.25rem; margin-top: 0.75rem; }
details.add { margin: 0.5rem 0; }
details.add > form { padding: 0.5rem 0 0.25rem; }

a.cancel-add { margin-left: 1rem; }

/* Sort headers for stack lists (162861/162881): the header row and the data
   rows share one grid, with no content-sized tracks, so each sort link sits
   directly above the column it orders. */
.row.cols,
.sort-row {
  display: grid;
  grid-template-columns: minmax(12rem, 1.1fr) 1fr 1fr 4rem;
  gap: 0.75rem;
  align-items: center;
}
.sort-row { margin: 0.25rem 0; padding-bottom: 0.3rem; border-bottom: 1px solid var(--cds-grey); }
.sort-row a { margin-right: 0.9rem; text-decoration: none; font-weight: 400; }
.sort-row a.sort-active { font-weight: 700; }
.card > .table-wrap > table { margin-top: 0.25rem; }

/* Compact checkbox rows inside panels (162855) */
input[type="checkbox"] { accent-color: var(--cds-teal-dark); width: 1.1rem; height: 1.1rem; }
.edit-inline input[type="checkbox"] { display: inline-block; width: auto; max-width: none; margin: 0; }
.edit-inline label.check {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0.4rem 1.5rem 0.75rem 0;
  font-size: 1rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--cds-charcoal);
}

/* Permission grants: each checkbox carries a plain-English line on what it
   lets the person do, stacked rather than in a row (AB#162751). */
.perm-options { list-style: none; margin: 0 0 1.1rem; padding: 0; }
.perm-options li { margin: 0 0 0.9rem; }
.perm-options li:last-child { margin-bottom: 0; }
.edit-inline .perm-options label.check { margin: 0; font-weight: 700; }
.perm-options .perm-desc {
  margin: 0.15rem 0 0 1.55rem;
  max-width: 60ch;
  font-size: 0.9rem;
  line-height: 1.4;
  color: #3D3D3D;
}

/* Segmented eligibility pills (162854) */
.pills { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.pills form { margin: 0; }
button.pill {
  background: var(--cds-white);
  color: var(--cds-charcoal);
  border: 1px solid #b5b5b5;
  border-radius: 999px;
  padding: 0.25rem 0.8rem;
  font-weight: 400;
}
button.pill:hover {
  background: var(--cds-white);
  border-color: var(--cds-teal-dark);
  color: var(--cds-teal-dark);
}
button.pill-current,
button.pill-current:hover {
  background: var(--cds-teal-dark);
  border-color: var(--cds-teal-dark);
  color: var(--cds-white);
  font-weight: 700;
}

/* Browse-and-rate view (story 162880) */
.button-link {
  display: inline-block;
  background: var(--cds-teal-dark);
  color: var(--cds-white);
  text-decoration: none;
  font-weight: 700;
  padding: 0.45rem 0.9rem;
  border-radius: 6px;
}
.button-link:hover { background: var(--cds-navy); text-decoration: none; }
.browse-cta { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin: 0.75rem 0 0.25rem; }
details.browse > summary {
  cursor: pointer;
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  flex-wrap: wrap;
  list-style: none;
}
details.browse > summary::-webkit-details-marker { display: none; }
details.browse > summary::before { content: "▸"; color: var(--cds-teal-dark); }
details.browse[open] > summary::before { content: "▾"; }
details.browse > summary h2 { display: inline; margin: 0; font-size: 1.2rem; }
details.browse > summary .count { color: #595959; font-size: 0.9rem; }
details.browse h3.cap { margin: 0.9rem 0 0.2rem; }
/* The 0–4 key: a tinted callout panel so it reads as a distinct key, not
   floating text. Collapsed by default to the one-line legend (with a "what do
   these mean?" cue); expands to the behavioural anchor for each level. */
details.level-key {
  margin: 1.25rem 0;
  padding: 0.75rem 1.25rem 1rem;
  background: var(--cds-grey);
  border-radius: 8px;
}
details.level-key > summary {
  cursor: pointer;
  list-style: none;
  color: var(--cds-charcoal);
}
details.level-key[open] > summary { margin-bottom: 0.25rem; }
details.level-key .key-hint { color: var(--cds-teal-dark); }
details.level-key > summary::-webkit-details-marker { display: none; }
details.level-key > summary::before { content: "▸ "; color: var(--cds-teal-dark); }
details.level-key[open] > summary::before { content: "▾ "; }
details.level-key dl {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.3rem 0.9rem;
  margin: 0.6rem 0 0;
  max-width: 46rem;
}
details.level-key dt { white-space: nowrap; }
details.level-key dd { margin: 0; color: #404040; }
details.level-key .key-foot { margin: 0.6rem 0 0; color: #595959; }
/* Sticky variant (Browse all skills): the key floats down with the scroll so
   the slim one-liner stays in view while you click levels. The opaque grey
   panel hides the list scrolling underneath; z-index keeps it above the later
   siblings (filter row, skill tree) that would otherwise paint over it. Pins
   relative to .page-scroll — clear of the fixed header (162883). */
details.level-key.sticky {
  position: sticky;
  top: 0.5rem;
  z-index: 5;
  box-shadow: 0 1px 3px rgba(27, 27, 27, 0.08);
}
.filter-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin: 0.75rem 0 1rem; }
.filter-row input[type="search"] { flex: 1 1 12rem; min-width: 0; max-width: 20rem; }
/* The level pills (0–4) plus the worded "Not for me" opt-out. nowrap keeps the
   two-word "Not for me" on one line in a narrow mobile column. */
button.pill.lvl { min-width: 2.2rem; text-align: center; padding: 0.25rem 0.5rem; white-space: nowrap; }
/* "Not for me" is a deliberate choice, not a proficiency: grey fill when
   current, unlike the teal of a chosen level. An untouched skill has no pill
   current at all — nothing lit is the default. */
button.pill.unset.pill-current,
button.pill.unset.pill-current:hover {
  background: var(--cds-grey);
  border-color: #b5b5b5;
  color: var(--cds-charcoal);
}
.badge-new {
  background: var(--cds-teal-dark);
  color: var(--cds-white);
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  padding: 0.1rem 0.55rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  vertical-align: middle;
}

/* Certification expiry badges (§6.6). Meaning is never carried by colour
   alone (WCAG 1.4.1) — the word states it. Orange-on-charcoal "Lapsed" is
   the only solid orange (4.87:1 on white, AA); "expires soon" uses an orange
   outline rather than a fill to stay within the palette's contrast table. */
.cert-badge {
  display: inline-block;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  padding: 0.1rem 0.55rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  vertical-align: middle;
}
.cert-badge.lapsed { background: var(--cds-orange); color: var(--cds-charcoal); }
.cert-badge.expiring { background: var(--cds-white); color: var(--cds-charcoal); border: 1px solid var(--cds-orange); }
.cert-badge.working { background: var(--cds-grey); color: var(--cds-navy); }

/* Resourcing search — faceted filter rail + live results (story 162908) */
.search-layout {
  display: grid;
  grid-template-columns: minmax(15rem, 18rem) 1fr;
  gap: 1.5rem;
  align-items: start;
}
.intro { color: #3d3d3d; }

/* The rail is a disclosure: open with its summary hidden on desktop, a collapsible
   "Filters" panel on narrow screens (the breakpoint flips both). */
.rail-disclosure { margin: 0; }
.rail-disclosure > summary {
  display: none;
  cursor: pointer;
  font-weight: 700;
  color: var(--cds-teal-dark);
  padding: 0.4rem 0;
  list-style: none;
}
.rail-disclosure > summary::-webkit-details-marker { display: none; }
.filter-rail {
  position: sticky;
  top: 0.5rem;
  margin: 0;
  border: 1px solid var(--cds-grey);
  border-radius: 8px;
  padding: 0.75rem 1rem 1rem;
  box-shadow: 0 1px 3px rgba(27, 27, 27, 0.08);
}
.filter-rail fieldset { border: none; margin: 0 0 1.1rem; padding: 0; min-width: 0; }
.filter-rail legend {
  padding: 0;
  margin-bottom: 0.45rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #595959;
}
.filter-rowset { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.5rem; }
.filter-rowset select { flex: 1 1 8rem; min-width: 0; }
.filter-rail .add-row { padding: 0.2rem 0; font-size: 0.9rem; }
.rail-actions { margin-top: 0.25rem; }


/* Seniority pills: a real checkbox styled as a segmented toggle, so it submits and
   stays keyboard-accessible with JS off (cf. button.pill, story 162854). */
.pill-check {
  position: relative;
  display: inline-flex;
  align-items: center;
  border: 1px solid #b5b5b5;
  border-radius: 999px;
  padding: 0.25rem 0.8rem;
  margin: 0;
  cursor: pointer;
  font-weight: 400;
}
.pill-check input { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
.pill-check:hover { border-color: var(--cds-teal-dark); color: var(--cds-teal-dark); }
.pill-check:has(input:checked) {
  background: var(--cds-teal-dark);
  border-color: var(--cds-teal-dark);
  color: var(--cds-white);
  font-weight: 700;
}
.pill-check:has(input:focus-visible) { outline: 2px solid var(--cds-teal-dark); outline-offset: 2px; }

/* Active-filter chips + result list */
.active-filters { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; margin: 0 0 0.75rem; }
.chip-filter {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--cds-grey);
  color: var(--cds-navy);
  border-radius: 999px;
  padding: 0.2rem 0.3rem 0.2rem 0.8rem;
  font-size: 0.9rem;
}
.chip-filter .chip-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 999px;
  color: var(--cds-navy);
  text-decoration: none;
  font-weight: 700;
}
.chip-filter .chip-x:hover { background: rgba(27, 27, 27, 0.12); }
.clear-all { font-size: 0.9rem; }
.result-count { font-weight: 700; color: var(--cds-navy); margin: 0.25rem 0 0.6rem; }
.results-sort { margin: 0 0 0.4rem; color: #595959; font-size: 0.9rem; }
.results-sort a { margin-right: 0.9rem; text-decoration: none; }
.results-sort a.sort-active { font-weight: 700; }
ul.results { list-style: none; margin: 0; padding: 0; }
ul.results > li.result { padding: 0.55rem 0; border-bottom: 1px solid var(--cds-grey); }
.result-head { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.result-head .who { font-weight: 700; }
.result-head .muted { color: #595959; font-size: 0.9rem; }
/* CV download link sits at the end of the result row (§6.7, FR-39). */
.result-head .cv-link { margin-left: auto; font-size: 0.9rem; white-space: nowrap; }
.match-detail { color: #595959; font-size: 0.9rem; margin-top: 0.2rem; }
/* Action line: primary action + quiet action on one row (e.g. bulk-CV confirm). */
.action-line { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-top: 0.75rem; }

@media (max-width: 52rem) {
  .search-layout { grid-template-columns: 1fr; }
  .rail-disclosure > summary { display: block; }
  .filter-rail { position: static; margin-top: 0.5rem; }
}

/* Skills analytics (story 162920): a live cascading scope picker, summary stat
   tiles, a heat-mapped proficiency grid, and insight lists that drill through to
   the resourcing search. The whole #analytics block is the data-live swap target. */
.scope-picker { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.75rem; margin: 0; }
.scope-field { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.scope-field > select, .scope-field > input { min-width: 12rem; }
.scope-field-label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #595959;
}
.scope-context { color: #3d3d3d; margin: 0.25rem 0 1rem; }
/* The live form re-runs on change, so the submit is only a no-JS fallback — hide
   it once JS is in play (app.js adds a js class to the html element). */
.js .scope-picker .scope-submit { display: none; }

/* Stat tiles: a number, a label, a one-line gloss. Signal tiles colour the number
   orange (sparingly, per brand) only when there's something to act on. */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1rem;
  margin: 0 0 1.25rem;
}
.stat-tile {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--cds-grey);
  border-radius: 10px;
  padding: 0.9rem 1rem;
  box-shadow: 0 1px 3px rgba(27, 27, 27, 0.08);
}
.stat-num { font-size: 1.9rem; font-weight: 900; line-height: 1.1; color: var(--cds-navy); }
.stat-tile.signal .stat-num { color: var(--cds-orange); }
.stat-label { font-weight: 700; color: var(--cds-charcoal); margin-top: 0.15rem; }
.stat-sub { color: #595959; font-size: 0.85rem; margin-top: 0.1rem; }

/* Heat-mapped grid: cells shade teal by headcount; row/column totals on the edges. */
table.heat { border-collapse: collapse; }
table.heat th, table.heat td { text-align: center; border: 1px solid var(--cds-grey); }
table.heat thead th { background: var(--cds-navy); color: var(--cds-white); font-weight: 700; }
table.heat thead th span { display: block; font-size: 0.7rem; font-weight: 400; opacity: 0.85; }
table.heat tbody th, table.heat tfoot th { text-align: left; background: transparent; color: var(--cds-charcoal); }
table.heat tbody tr:nth-child(even) { background: transparent; }
table.heat td.cell { font-weight: 700; color: var(--cds-navy); padding: 0; }
table.heat td.cell.hot { color: var(--cds-white); }
table.heat td.cell a { display: block; padding: 0.5rem; color: inherit; text-decoration: none; }
table.heat td.cell a:hover { outline: 2px solid var(--cds-navy); outline-offset: -2px; }
table.heat td.cell:not(:has(a)) { padding: 0.5rem; }
table.heat .total { background: var(--cds-grey); color: var(--cds-navy); font-weight: 700; }
table.heat .total.grand { background: #d9d9d9; }

/* Insight lists: skill names link into the resourcing search; long lists flow into
   columns. Each item stays whole (never split across a column break). */
ul.signal-list { list-style: none; margin: 0.4rem 0 0; padding: 0; column-width: 18rem; column-gap: 2rem; }
ul.signal-list > li { margin: 0.2rem 0; break-inside: avoid; }

/* Dashboard nav tiles for hub/landing pages (story 162918): the home, Reporting
   and Administration hubs render their area links as a responsive grid of cards
   instead of a bare bullet list. */
.tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 1rem;
  margin: 1.25rem 0;
}
a.tile {
  display: block;
  border: 1px solid var(--cds-grey);
  border-radius: 10px;
  padding: 1rem 1.1rem;
  text-decoration: none;
  color: var(--cds-charcoal);
  box-shadow: 0 1px 3px rgba(27, 27, 27, 0.08);
  transition: border-color 0.12s ease, box-shadow 0.12s ease, transform 0.12s ease;
}
a.tile:hover {
  border-color: var(--cds-teal-dark);
  box-shadow: 0 4px 12px rgba(27, 27, 27, 0.12);
  transform: translateY(-1px);
}
.tile-title {
  display: block;
  font-weight: 700;
  color: var(--cds-navy);
  font-size: 1.05rem;
}
.tile-title::after { content: " →"; color: var(--cds-teal-dark); float: right; font-weight: 400; }
.tile-desc { display: block; color: #595959; font-size: 0.9rem; margin-top: 0.3rem; }

/* Identity card + seniority chip (162852) */
.identity { display: flex; align-items: center; gap: 1rem; }
.identity .who { flex: 1; }
.identity .who strong { font-size: 1.15rem; }
.chip {
  background: var(--cds-grey);
  color: var(--cds-navy);
  border-radius: 999px;
  padding: 0.25rem 0.9rem;
  font-weight: 600;
  white-space: nowrap;
}
/* Seniority chip as a link to the behaviours guide. Navy (not the teal link
   colour) to keep AA contrast on the grey pill; the ↗ glyph is the persistent
   affordance, with underline + a darker fill on hover/focus. */
a.chip-link {
  color: var(--cds-navy);
  text-decoration: none;
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
}
a.chip-link .ext { font-size: 0.85em; }
a.chip-link:hover,
a.chip-link:focus-visible { background: #dcdcdc; text-decoration: underline; text-underline-offset: 2px; }
/* Unset seniority ("Not set yet"): muted + italic so a placeholder never reads
   as a real grade. Renders this way in plain text and inside a .chip alike
   (overriding the chip's navy/600 weight). */
.unset { color: #6b6b6b; font-style: italic; font-weight: 400; }

/* ---- Profile completion (Feature 163223) ----------------------------------
   Status pills sit next to section headings and in the summary card. Status is
   carried by the word AND an icon, never colour alone (WCAG 2.2 AA); charcoal
   text on every variant keeps contrast well clear of 4.5:1. The three fills are
   only a reinforcing cue. */
.status-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  border-radius: 999px;
  padding: 0.25rem 0.65rem;
  font-size: 0.72rem;
  font-weight: 600;
  /* line-height:1 so the text isn't floated by the body's tall line-box —
     symmetric padding then centres it regardless of descenders (story 163225). */
  line-height: 1;
  letter-spacing: 0.01em;
  vertical-align: middle;
  color: var(--cds-charcoal);
  white-space: nowrap;
}
/* Centre the glyph in its own box so the circle/check sits on the chip's
   middle, not the text baseline. */
.status-chip .ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.05em;
  line-height: 1;
}
/* The geometric circle glyphs (○ not-started, ◐ in-progress) are drawn high in
   their em box, so flex-centring the box still leaves the visible circle above
   the optical centre (story 163230 centred the box but not the glyph within it).
   A small nudge sits them on the chip's middle. The check (✓) sits lower in its
   box and is already centred, so it's left alone. */
.status-todo .ic,
.status-progress .ic {
  transform: translateY(0.08em);
}
.status-todo     { background: var(--cds-grey); color: #5a5a5a; font-weight: 500; }
.status-progress { background: #fff; box-shadow: inset 0 0 0 1px var(--cds-teal); color: var(--cds-teal-dark); }
.status-done     { background: #d6ece9; color: #0d5d56; }
/* Heading chips are a touch smaller than the heading and don't inherit its weight. */
h2 .status-chip { font-size: 0.62em; transform: translateY(-0.12em); }

.setup-summary { border-left: 4px solid var(--cds-teal); }
.setup-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}
.setup-head h2 { margin: 0; }
.setup-count { margin: 0; color: var(--cds-charcoal); }
.setup-list { list-style: none; margin: 0.5rem 0 0.75rem; padding: 0; }
.setup-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0;
  border-top: 1px solid var(--cds-grey);
}
/* Label is a jump-link on "My profile" and a plain span on the read-only
   completion card — same weight either way. */
.setup-row a, .setup-row .setup-label { flex: 0 0 auto; font-weight: 600; }
.setup-row .status-chip { margin-left: auto; }
.setup-detail { color: #5a5a5a; }

/* "Waiting on you" action card (Feature 163288). Orange left border — a sparing
   use of the accent — marks it as a call to action, distinct from the teal
   setup card. The is-clear (empty) state drops the accent so it reads calm. */
.action-card { border-left: 4px solid var(--cds-orange); }
/* Calm teal accent when there's nothing genuinely waiting — the empty state and
   the discretionary-only ("worth a look") card. Orange is kept for action. */
.action-card.is-clear, .action-card.is-soft { border-left-color: var(--cds-teal); }
.action-card h2 { margin: 0 0 0.25rem; }
.action-card .worth-look-head { margin-top: 1rem; }
.action-clear { margin: 0; color: var(--cds-teal-dark); }
.action-list { list-style: none; margin: 0.5rem 0 0; padding: 0; }
.action-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.45rem 0;
  border-top: 1px solid var(--cds-grey);
}
.action-count {
  flex: 0 0 auto;
  min-width: 1.9rem;
  text-align: center;
  font-weight: 700;
  color: var(--cds-orange);
  font-size: 1.15rem;
}
.action-text { flex: 1 1 auto; }
.action-link { flex: 0 0 auto; font-weight: 600; }

/* Notice shown when the people list is filtered to a single view (e.g. pending
   eligibility) — explains the narrowing and offers a way back to all people. */
.filter-note { margin: 0 0 0.5rem; }

/* "Nothing to add" acknowledgement and the empty-state hints that carry an
   action button — block wrappers (not <p>) so the form nests validly. */
.ack-note, .empty-hint { margin: 0.5rem 0; }
.ack-note p, .empty-hint p { margin: 0 0 0.35rem; }
.ack-note { color: var(--cds-teal-dark); }

/* Profile-completion analytics (Reporter): per-area breakdown table + spread
   bar. Numbers carry the meaning; the bar is a reinforcing cue only. */
table.comp-areas th[scope], table.comp-areas td.num { text-align: right; }
table.comp-areas .num { text-align: right; font-variant-numeric: tabular-nums; }
table.comp-areas td.comp-spread { width: 40%; min-width: 8rem; }
.comp-bar {
  display: flex;
  height: 0.7rem;
  border-radius: 999px;
  overflow: hidden;
  background: var(--cds-grey);
}
.comp-bar .seg { height: 100%; }
.comp-bar .seg.done { background: var(--cds-teal); }
.comp-bar .seg.progress { background: #7fc6bd; }
.comp-bar .seg.todo { background: #d3d3d3; }

/* Divider before the optional "Extra tools" (story 163228). */
.extras-divider {
  border: 0;
  border-top: 2px solid var(--cds-grey);
  margin: 2.25rem 0 1rem;
}
.extras-head { margin-top: 0; }
.extras-intro { margin-top: 0; color: #3D3D3D; }

/* Warnings (e.g. taxonomy soft budget): orange accent, charcoal text */
strong { font-weight: 700; }
small { color: #3D3D3D; }

@media (max-width: 40rem) {
  main { padding: 0.75rem; }
  details.edit > .panel { position: static; min-width: 0; box-shadow: none; border: none; padding: 0.25rem 0; }
  .row { flex-wrap: wrap; }
  .row .name { min-width: 0; }
  /* Narrow screens: release the fixed skill-name column so rows stack. */
  ul.skills .row .name { flex-basis: auto; }
  /* Narrow screens: rows wrap, so column headers stop meaning anything —
     fall back to the inline sort-link row (162881). */
  .row.cols { display: flex; }
  .sort-row { display: block; border-bottom: none; padding-bottom: 0; }
  th, td { padding: 0.4rem 0.3rem; }
  input, select { width: 100%; margin-bottom: 0.25rem; }
  td form { display: block; }
  /* Browse rows: pills drop to their own full-width line under the name */
  details.browse .row .controls { margin-left: 0; width: 100%; }
  .filter-row input[type="search"] { width: auto; }
}
