/* ==========================================================================
   TalentCorp | DataFlow
   Source of truth: HelloKindred CI Guideline 2024 v1.5

   Palette is basalt blue + fresh lime and nothing else. The secondary
   colours (fuzzy peach, lavender haze, plum royale, meadow dew, sky mist)
   are restricted by the guideline to charts and process artwork in
   PowerPoint and Word, so they do not appear here at all.

   Fresh lime is the highlighter device only — slanted strip, basalt text
   reversed out — and never more than twice on one page.

   Type is Aptos with Georgia Bold Italic for emphasis: the guideline's
   specified electronic fonts, picked there for PC/Mac compatibility.
   Gilroy and Larken are the primary brand faces but are licensed, so they
   are neither embedded nor hotlinked. Nothing here makes an external
   request, so the site renders offline and calls out to nobody.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Tokens — now aliases onto the house theme
   kin-theme.css is loaded before this file and defines the Hello Kindred
   design system as shipped by the Employment Equity Tool. DataFlow keeps its
   own token names, because ~2,700 lines below read them and renaming those
   would be a rewrite rather than a rebrand, but every name now resolves to a
   theme token. Change a colour in kin-theme.css and it moves here too.

   WHY EACH ONE MAPS WHERE IT DOES. The old tints were Basalt at five opacities
   used for three different jobs — ink, lines and grounds — and a single ramp
   cannot be accessible at all three. The theme separates them, so each alias
   below points at the token for the job that name is actually doing in the
   rules further down (checked: -80 and -60 are ink only; -05 is a ground in
   34 of 36 uses; -40 is mixed ink and lines).

   Two of these are also contrast fixes, not just renames:
     --basalt-40 was rgba(9,38,45,.40) = #94a0a3 on white, about 2.9:1 — below
       the 3:1 that WCAG 1.4.11 wants for the edge of a control, and it draws
       every input border. --control-line is .55 = 3.7:1.
     --basalt-60 was 4.0:1 as body ink. --text-faint is the theme's measured
       replacement at 5.4:1 on paper.
   -------------------------------------------------------------------------- */
:root {
  /* Basalt itself is unchanged — the theme's chrome colour is the same
     #09262d the CI guideline specifies. */
  --basalt:     var(--sidebar-bg);

  /* Ink. */
  --basalt-80:  var(--text-muted);
  --basalt-60:  var(--text-faint);

  /* Mixed: de-emphasised micro text and control edges. */
  --basalt-40:  var(--control-line);

  /* Lines, and the palest grounds. */
  --basalt-10:  var(--border);
  --basalt-05:  var(--surface-2);

  /* Fresh lime. The guideline calls it a highlighter; the theme states the
     same rule more strictly — it is a FILL and never ink, because lime text
     on paper is about 1.2:1. --accent is the fill, --accent-ink is what you
     colour text with, and anything sitting on lime takes --on-accent. */
  --lime:       var(--accent);

  --paper:      var(--surface);
  --rule:       var(--border);

  /* Gilroy first now, matching the rest of the family; Aptos remains the
     documented fallback while the licensed webfont files are unavailable. */
  --font: Gilroy, Aptos, 'Segoe UI', system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --font-em: Georgia, 'Times New Roman', serif;

  --measure: 46rem;   /* one comfortable reading column */
  --gap: var(--space-5);
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.65;
  color: var(--basalt);
  background: var(--paper);
}

h1, h2, h3 { line-height: 1.2; letter-spacing: -0.01em; margin: 0; }
h1 { font-size: clamp(1.9rem, 1.4rem + 2vw, 2.6rem); font-weight: 700; }
h2 { font-size: 1.4rem; font-weight: 700; }
h3 { font-size: 1.05rem; font-weight: 700; }
p  { margin: 0 0 1rem; }
a  { color: var(--basalt); text-decoration: underline; text-underline-offset: 0.15em; }
a:hover { text-decoration-thickness: 2px; }

:focus-visible {
  outline: 3px solid var(--basalt);
  outline-offset: 2px;
}

/* Georgia Bold Italic — the guideline's emphasis face. */
.em, .lead-em {
  font-family: var(--font-em);
  font-weight: 700;
  font-style: italic;
}

/* --------------------------------------------------------------------------
   The highlighter device
   Slanted lime strip, basalt text reversed out. Two per page maximum —
   the guideline is explicit that overuse loses the emphasis.
   `isolation` keeps the strip behind the text without escaping the span.
   -------------------------------------------------------------------------- */

.hl {
  position: relative;
  isolation: isolate;
  display: inline-block;
  color: var(--basalt);
  padding: 0 0.2em;
  white-space: nowrap;
}

.hl::before {
  content: '';
  position: absolute;
  inset: 0.1em -0.1em 0.08em -0.1em;
  background: var(--lime);
  transform: skewX(-12deg);
  z-index: -1;
}

/* --------------------------------------------------------------------------
   Dark band: top bar and footer
   -------------------------------------------------------------------------- */

.topbar {
  background: var(--basalt);
  color: var(--paper);
  display: flex;
  align-items: center;
  gap: var(--gap);
  flex-wrap: wrap;
  padding: 0.85rem 1.5rem;
}

.lockup {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  text-decoration: none;
  color: var(--paper);
  flex-shrink: 0;
}

.lockup-mark { font-weight: 700; letter-spacing: -0.01em; }
.lockup-bar  { width: 1px; height: 1.1em; background: rgba(255,255,255,0.35); }
.lockup-name { font-weight: 400; opacity: 0.85; }

/* The brand block: holding lockup naming the owning function, operating brands
   beneath it. Two lines rather than one row of four names, so the hierarchy reads
   correctly — TalentCorp owns, the affiliates sit under it — and so the bar does not
   run out of room next to the nav on a laptop. Signed-in pages only; see render.mjs. */
.brand { display: flex; flex-direction: column; gap: 0.15rem; flex-shrink: 0; }

.affiliates {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  /* Quiet enough to stay subordinate to the lockup, still over 4.5:1 on basalt. */
  color: rgba(255, 255, 255, 0.62);
}

.affiliates li + li::before {
  content: '·';
  margin: 0 0.45rem;
  color: rgba(255, 255, 255, 0.32);
}

/* On a narrow screen the affiliate line is the first thing worth dropping: the
   lockup still says whose site this is. */
@media (max-width: 30rem) {
  .affiliates { display: none; }
}

.topnav {
  display: flex;
  gap: 1.25rem;
  flex-wrap: wrap;
  margin-left: auto;
}

.topnav a {
  color: var(--paper);
  text-decoration: none;
  font-size: 0.92rem;
  opacity: 0.8;
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
}

.topnav a:hover { opacity: 1; border-bottom-color: rgba(255,255,255,0.5); }
.topnav a[aria-current='page'] { opacity: 1; border-bottom-color: var(--paper); }

/* The account menu. A <details> disclosure: keyboard-operable, no script, and the
   name and Sign out live inside it rather than taking up room in the bar. */
.who { position: relative; margin-left: 0.25rem; }

.who-badge {
  list-style: none;
  cursor: pointer;
  width: 2rem; height: 2rem;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  display: grid; place-items: center;
  font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--paper);
}

.who-badge::-webkit-details-marker { display: none; }
.who-badge::marker { content: ''; }
.who-badge:hover { border-color: var(--paper); }
.who-badge:focus-visible { outline: 3px solid var(--paper); outline-offset: 2px; }
.who[open] .who-badge { background: rgba(255, 255, 255, 0.14); }

/* Sign out is the one destructive item in the menu, so it reads differently
   without shouting. */
.who-signout { border-top: 1px solid var(--basalt-40); font-weight: 600; }

.who-panel {
  position: absolute;
  top: calc(100% + 0.55rem);
  right: 0;
  z-index: 60;
  min-width: 13rem;
  background: var(--paper);
  border: 1px solid var(--basalt-40);
  border-radius: 2px;
  box-shadow: 0 10px 28px rgba(9, 38, 45, 0.22);
  padding: 0.7rem 0;
}

.who-who   { margin: 0 0.9rem 0.1rem; font-weight: 700; color: var(--basalt); }
.who-email { margin: 0 0.9rem 0.55rem; font-size: 0.8rem; color: var(--basalt-60); word-break: break-all; }

.who-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.45rem 0.9rem;
  font: inherit;
  font-size: 0.9rem;
  color: var(--basalt);
  background: none;
  border: 0;
  border-top: 1px solid var(--rule);
  text-decoration: none;
  cursor: pointer;
}

.who-item:hover { background: var(--basalt-05); color: var(--basalt); }
.who-form { margin: 0; }

.inline-form { display: inline; margin: 0; }

.linkish {
  background: none;
  border: 0;
  color: var(--paper);
  opacity: 0.65;
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
  padding: 0;
}

.linkish:hover { opacity: 1; }

/* --------------------------------------------------------------------------
   List rows
   One anchor per row, so clicking anywhere along the bar opens it. A grid and not
   a table because a <tr> cannot be a link, and wrapping each cell in its own
   anchor would announce one row as several links. Column counts are utility
   classes: the CSP forbids style attributes, so this cannot be an inline var.
   -------------------------------------------------------------------------- */

.list-rows { border-top: 1px solid var(--rule); }

.list-head,
.list-row {
  display: grid;
  gap: 0.75rem;
  align-items: baseline;
  padding: 0.7rem 0.75rem;
  border-bottom: 1px solid var(--rule);
}

.list-head {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--basalt-60);
}

.list-row {
  color: var(--basalt);
  text-decoration: none;
}

.list-row:hover { background: var(--basalt-05); }

/* Keyboard users get the same target, visibly. */
.list-row:focus-visible {
  outline: 2px solid var(--basalt);
  outline-offset: -2px;
  background: var(--basalt-05);
}

/* The first column carries the name of the thing, so it leads and it is the part
   that looks like a link. */
.list-title {
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.cols-2 { grid-template-columns: minmax(9rem, 2fr) minmax(6rem, 1fr); }
.cols-3 { grid-template-columns: minmax(9rem, 2fr) repeat(2, minmax(6rem, 1fr)); }
.cols-4 { grid-template-columns: minmax(9rem, 2fr) repeat(3, minmax(6rem, 1fr)); }
.cols-5 { grid-template-columns: minmax(9rem, 2fr) repeat(4, minmax(6rem, 1fr)); }
.cols-6 { grid-template-columns: minmax(9rem, 2fr) repeat(5, minmax(5rem, 1fr)); }

@media (max-width: 45rem) {
  .list-head { display: none; }
  .list-row { grid-template-columns: 1fr; gap: 0.15rem; }
  .list-row span:not(.list-title) { color: var(--basalt-60); font-size: 0.85rem; }
}

/* --------------------------------------------------------------------------
   Attaching a file, and the context block
   -------------------------------------------------------------------------- */

.attach input[type="file"] { padding: 0.45rem; }

/* A picture pasted into an answer. It sits above the questions rather than inside the
   file arrow, because it belongs beside what is being typed — the file box means "this
   file is my entry", and this means "here is a screenshot of what I just described". */
/* The invitation to drag or paste. Set as a panel rather than as a note, because a note
   is what people have learned to skip and this is a thing they cannot discover any other
   way — nothing about a text box says you may drop a PDF on it. */
/* The full reasoning, behind an arrow. Two lines to read before typing; all of it one
   click away for anybody who wants it, and nothing thrown out to get there. */
/* Three arrows across the top instead of stacked down it.
   Closed, they are three chips on one line. Opened, the one you opened takes the whole
   width — a details element left in a third of the page would put the AI prompt in a
   gutter. Pure CSS, so it needs no script and cannot get out of step with what is open. */
.assist-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  align-items: start;
  margin: 0 0 1.25rem;
}
.assist-row > .assist { margin: 0; }
.assist-row > .assist[open] { grid-column: 1 / -1; }

/* Closed, a summary is the whole control, so it gets to look like one. */
.assist-row > .assist:not([open]) > .disclose {
  display: block;
  padding: 10px 12px;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--paper);
  font-size: 0.86rem;
  line-height: 1.35;
}
.assist-row > .assist:not([open]) > .disclose:hover {
  border-color: var(--basalt-40);
  background: var(--basalt-05);
}

/* The date is off the page unless the work was not today. It is still recorded — the map
   is built on dates and an entry without one cannot be put in order. */
.assist-date { margin: 0 0 1.25rem; }

@media (max-width: 700px) {
  .assist-row { grid-template-columns: minmax(0, 1fr); }
  .assist-row > .assist[open] { grid-column: auto; }
}

/* Choosing what the diary asks. Cards rather than a dropdown: the difference between
   the two is a paragraph, not a word, and a dropdown would hide the paragraph that
   matters — one of them cannot record direction, and nobody should discover that after
   switching. */
/* Folding the long admin pages.
   These had grown to a lot of scrolling for somebody who came to look at one thing. The
   head becomes the handle; the first section on each page stays open so the page still
   says something before anybody clicks.
   <details> rather than script: it survives the CSP, works with scripting off, and there
   is no remembered state to get out of step with what is on screen. */
.part.fold > .part-head {
  cursor: pointer;
  list-style: none;
  position: relative;
  padding-right: 32px;
}
.part.fold > .part-head::-webkit-details-marker { display: none; }

/* The arrow, drawn rather than fetched, and turned when open. */
.part.fold > .part-head::after {
  content: "";
  position: absolute;
  top: 0.55em;
  right: 6px;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--basalt-40);
  border-bottom: 2px solid var(--basalt-40);
  transform: rotate(45deg);
  transition: transform 120ms ease;
}
.part.fold[open] > .part-head::after { transform: rotate(-135deg); }
.part.fold > .part-head:hover::after { border-color: var(--basalt); }

/* Closed, the intro is noise — the heading is the whole control. Open, it belongs. */
.part.fold:not([open]) > .part-head .part-intro { display: none; }

@media (prefers-reduced-motion: reduce) {
  .part.fold > .part-head::after { transition: none; }
}

/* --------------------------------------------------------------------------
   The skill repository
   -------------------------------------------------------------------------- */

.skill-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 14px;
}

.skill-card {
  padding: 16px 18px;
  border: 1px solid var(--rule);
  border-left: 4px solid var(--basalt-40);
  border-radius: 10px;
  background: var(--paper);
}
.skill-card h3 { margin: 0 0 6px; font-size: 1rem; }
.skill-does { margin: 0 0 8px; font-size: 0.88rem; color: var(--basalt-80); }

.skill-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin: 0;
  font-size: 0.78rem;
  color: var(--basalt-60);
}
.skill-meta span::before { content: "· "; color: var(--basalt-40); }
.skill-meta span:first-child::before { content: none; }

.skill-state {
  display: inline-block;
  padding: 2px 9px 3px;
  border-radius: 999px;
  font-size: 0.76rem;
  font-weight: 600;
  border: 1px solid transparent;
}
.skill-state.is-waiting   { background: #fdf1de; color: #7a4c12; border-color: #edd6ac; }
.skill-state.is-approved  { background: #e8f2ec; color: #1f6f5c; border-color: #c4ded2; }
.skill-state.is-declined  { background: #fbe9e6; color: #8c2f22; border-color: #edc4bd; }
.skill-state.is-withdrawn { background: var(--basalt-05); color: var(--basalt-60); border-color: var(--basalt-10); }

/* Somebody's own words, unedited, and shown as such. */
.skill-prompt {
  margin: 0;
  padding: 14px 16px;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--basalt-05);
  font-size: 0.84rem;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.sub-h {
  margin: 18px 0 8px;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--basalt-60);
}

.skill-review {
  padding: 18px 20px;
  margin-bottom: 16px;
  border: 1px solid var(--rule);
  border-left: 4px solid #c08a2e;
  border-radius: 12px;
  background: var(--paper);
}
.skill-review h3 { margin: 0; font-size: 1.05rem; }
.skill-review h4 {
  margin: 14px 0 4px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--basalt-60);
}
.skill-review p { margin: 0; }

/* Who it is for. Cards, because the difference between them is a sentence and a
   dropdown would hide the sentence that matters. */
.audience-choice { display: grid; gap: 8px; }
.audience-option {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "radio name" ". detail";
  gap: 2px 10px;
  padding: 10px 12px;
  border: 1px solid var(--rule);
  border-radius: 8px;
  cursor: pointer;
}
.audience-option:hover { border-color: var(--basalt-40); }
.audience-option input { grid-area: radio; }
.audience-name { grid-area: name; font-weight: 600; color: var(--basalt); }
.audience-detail { grid-area: detail; font-size: 0.82rem; color: var(--basalt-60); }

/* Downloads. A row each, the name and size where somebody can see what they are about
   to take, and the button on the right where a button belongs. */
/* Answered or not, at a glance. A tick and a dot rather than words, because the point of
   the table is the shape of the gaps down a column. */
.tick {
  display: inline-block;
  width: 1.2em;
  color: var(--basalt-40);
  font-weight: 700;
}
.tick.is-on { color: #1f6f5c; }
.answered-grid tr.is-outstanding td:first-child { box-shadow: inset 3px 0 0 #c08a2e; }
.answered-grid th { vertical-align: bottom; }

/* On hold. Above everything, in the highlighter, because it is the one thing on the page
   that has to be read before anybody does anything else. */
.paused-bar {
  padding: 12px 20px;
  background: var(--lime);
  color: var(--basalt);
  font-size: 0.9rem;
  line-height: 1.45;
  text-align: center;
}
.paused-bar strong { font-weight: 700; }

.download-list { display: grid; gap: 10px; }
.download-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 18px;
  border: 1px solid var(--rule);
  border-radius: 10px;
  background: var(--paper);
}
.download-row h3 { margin: 0 0 3px; font-size: 1rem; }
.download-detail { margin: 0; font-size: 0.86rem; color: var(--basalt-80); }
.download-name {
  margin: 4px 0 0;
  font-size: 0.78rem;
  color: var(--basalt-40);
  font-variant-numeric: tabular-nums;
}

.template-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
  align-items: start;
}

.template-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px 20px;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: var(--paper);
  box-shadow: 0 1px 2px rgba(9, 38, 45, 0.04);
}
.template-card.is-on {
  border-color: var(--basalt);
  box-shadow: inset 0 0 0 1px var(--basalt);
}
.template-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.template-head h3 { margin: 0; font-size: 1.05rem; }
.template-minutes {
  margin: 0;
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--basalt-40);
}
.template-summary { margin: 0; font-size: 0.9rem; color: var(--basalt-80); }
/* What it costs, set apart from what it saves — the sentence somebody must not skim. */
.template-detail {
  margin: 0;
  padding-left: 12px;
  border-left: 2px solid var(--basalt-10);
  font-size: 0.83rem;
  color: var(--basalt-60);
}
.template-use { margin-top: auto; }
.template-use .btn { width: 100%; }
.template-use .btn:disabled { cursor: default; opacity: 0.7; }

/* The preview is the real renderer with everything switched off, so it cannot be typed
   into and cannot be mistaken for the form itself. */
.template-preview {
  margin-top: 10px;
  padding: 14px;
  border: 1px dashed var(--basalt-10);
  border-radius: 8px;
  background: var(--basalt-05);
  pointer-events: none;
}
.template-preview .input { background: var(--paper); }

/* One box, three questions. Numbered, because they are still three questions and a
   paragraph of them reads as one. */
.one-box-questions {
  margin: 0 0 10px;
  padding-left: 20px;
  font-weight: 600;
  color: var(--basalt);
}
.one-box-questions li { margin-bottom: 2px; }

/* Told, not silently done. Text reappearing in a box without explanation reads like a
   bug, and the person needs to know they can throw it away. */
.draft-note {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 1.25rem;
  padding: 10px 14px;
  border: 1px solid var(--basalt-10);
  border-left: 4px solid var(--lime);
  border-radius: 8px;
  background: var(--basalt-05);
  font-size: 0.86rem;
  color: var(--basalt-80);
}

.drop-invite {
  margin: 0 0 1.25rem;
  padding: 12px 14px;
  border: 1px dashed var(--basalt-40);
  border-radius: 8px;
  background: var(--basalt-05);
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--basalt-80);
}
.drop-invite strong { color: var(--basalt); }

/* Something is over the drop zone. Loud on purpose: a drag has no cursor of its own to
   tell you whether letting go will work, so the target has to say. */
.attach.is-dropping {
  outline: 2px dashed var(--basalt-40);
  outline-offset: 4px;
  background: var(--basalt-05);
  border-radius: 8px;
}
.input.is-dropping,
textarea.is-dropping {
  border-color: var(--basalt);
  box-shadow: inset 0 0 0 2px var(--basalt-10);
}

.pasted {
  margin: 0 0 1.25rem;
  padding: 14px 16px;
  border: 1px solid var(--rule);
  border-left: 4px solid var(--basalt-40);
  border-radius: 10px;
  background: var(--basalt-05);
}
.pasted.is-hidden { display: none; }
.pasted-body { display: flex; align-items: flex-start; gap: 14px; }
.pasted-thumb {
  width: 132px;
  height: auto;
  max-height: 132px;
  object-fit: contain;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--paper);
}
.pasted-name { margin: 0 0 8px; font-size: 0.86rem; color: var(--basalt-80); }

.attach-status {
  margin: 0.4rem 0 0;
  font-size: 0.85rem;
  color: var(--basalt-60);
}

.attach-status.is-saved { color: var(--basalt); font-weight: 600; }
.attach-status.is-error { color: var(--danger, #9c2b2b); font-weight: 600; }

/* The context block. A read-only textarea rather than a styled div, so it can always be
   selected and copied by hand even if the button fails. */
/* Help for filling the form in, so it sits above the first field. The prompt itself is behind
   a disclosure: four thousand characters above the Date box would bury the form. */
.assist {
  border: 1px solid var(--rule);
  border-left: 3px solid var(--basalt);
  padding: 1rem 1.1rem;
  margin-bottom: 2rem;
}

/* Sits above each shortcut, so nobody reads an arrow as a requirement. Styled exactly like
   the "required" marker beside a field label — same size, weight, case, tracking and colour —
   because it is the same kind of note about the same kind of thing. */
.optional-note {
  font-weight: 400;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--basalt-40);
  margin: 0 0 0.4rem;
}

.assist h2 { font-size: 1.02rem; margin-bottom: 0.4rem; }
.assist p { color: var(--basalt-80); margin-bottom: 0.8rem; max-width: 40rem; }
.assist .actions { margin-bottom: 0.6rem; }
.assist details { margin-top: 0.5rem; }

/* The file box lives inside the AI block, because the PDF is what comes out of it. */
.assist-attach {
  margin-top: 1rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--rule);
}
.assist textarea { font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.8rem; }

.copybox { margin-bottom: 1.5rem; }
.copybox textarea { font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.82rem; }
.copy-said { font-size: 0.85rem; color: var(--basalt-60); align-self: center; }

/* --------------------------------------------------------------------------
   The Work Flow — and then what happens
   A chain read along rather than looked at. The numbered rail down the left is
   the sequence; each card is one hand the work passed through.
   -------------------------------------------------------------------------- */

.wf-chains { display: grid; gap: 22px; }

.wf-chain {
  border: 1px solid var(--rule);
  border-left: 5px solid var(--basalt-10);
  border-radius: 12px;
  background: var(--paper);
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(9, 38, 45, 0.04);
}
.wf-chain.is-special    { border-left-color: #7d1d14; }
.wf-chain.is-personal   { border-left-color: #b4453a; }
.wf-chain.is-commercial { border-left-color: #c08a2e; }
.wf-chain.is-business   { border-left-color: var(--basalt-40); }

.wf-chain-head {
  padding: 16px 20px 14px;
  border-bottom: 1px solid var(--rule);
  background: linear-gradient(var(--basalt-05), rgba(9, 38, 45, 0));
}
.wf-chain-head h3 { margin: 4px 0 0; font-size: 1.15rem; letter-spacing: -0.01em; }
.wf-to { font-weight: 400; color: var(--basalt-40); }
.wf-summary { margin: 4px 0 0; font-size: 0.84rem; color: var(--basalt-60); }
.wf-more { margin: 8px 0 0; font-size: 0.82rem; color: #8c2f22; }

/* The rail. A numbered marker with a line running through it, so the eye follows
   the sequence downwards without every card having to be an arrow. */
.wf-steps { list-style: none; margin: 0; padding: 6px 0 10px; }

.wf-stop {
  position: relative;
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  align-items: start;
}
.wf-marker { position: relative; display: flex; justify-content: center; padding-top: 18px; }
.wf-marker::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: -8px;
  width: 2px;
  background: var(--basalt-10);
}
.wf-stop:first-child .wf-marker::before { top: 18px; }
.wf-stop:last-child .wf-marker::before { bottom: auto; height: 18px; }

.wf-num {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--basalt);
  color: var(--paper);
  font-size: 0.76rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.wf-stop.is-system   .wf-num { background: #a86a2f; }
.wf-stop.is-internal .wf-num { background: #1d4d57; }
.wf-stop.is-team     .wf-num { background: #3d5b62; }
.wf-stop.is-outside  .wf-num { background: #8a3f2f; }
.wf-stop.is-role     .wf-num { background: #5d7a80; }
.wf-stop.is-client   .wf-num { background: #6f2f28; }

.wf-card { padding: 14px 20px 14px 4px; min-width: 0; }
.wf-card h4 { margin: 0; font-size: 1rem; }
.wf-where { margin: 1px 0 0; font-size: 0.8rem; color: var(--basalt-60); }
.wf-onward { margin-top: 10px; padding-top: 10px; border-top: 1px dotted var(--basalt-10); }
.wf-meta { margin: 2px 0 0; font-size: 0.78rem; color: var(--basalt-60); }

/* Where the chain chose. Never hidden: a reader not told about the branch will
   believe a picture that is tidier than the company actually is. */
.wf-branch {
  margin: 6px 0 0;
  font-size: 0.78rem;
  color: var(--basalt-60);
  font-style: italic;
}
.wf-n { font-variant-numeric: tabular-nums; color: var(--basalt-40); }

/* A hand-off nobody can account for is the most useful thing on this page, so it
   is marked rather than left blank. */
.wf-blank { margin: 0; font-size: 0.8rem; font-weight: 600; color: #8c2f22; }
.wf-end {
  margin: 10px 0 0;
  padding-top: 10px;
  border-top: 1px dotted var(--basalt-10);
  font-size: 0.8rem;
  color: var(--basalt-60);
}

/* --------------------------------------------------------------------------
   The Data Chart — left to right, start to finish
   A ribbon's thickness is how much travels and its colour is the most sensitive
   thing in it. Those two facts are the whole diagram; everything else here is
   getting out of their way.
   -------------------------------------------------------------------------- */

.sk-wrap {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 14px;
  padding: 4px;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(9, 38, 45, 0.05), 0 12px 32px -20px rgba(9, 38, 45, 0.35);
}

.sk-svg { display: block; width: 100%; height: auto; grid-column: 1; }

/* Sits below the toolbar, not behind it. */
.sk-head {
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  fill: var(--basalt-40);
}

.sk-bands { pointer-events: auto; }

/* Blocks sit above the ribbons, so a thin one in a crowded column is still hoverable. */
.sk-nodes { pointer-events: auto; }

/* A hairline of paper between neighbouring ribbons. Butted together they read as one
   wide band, and the whole point of stacking them at a block edge is that each is a
   separate route you can point at. */
.sk-band {
  stroke: var(--paper);
  stroke-width: 0.75;
  opacity: 0.42;
  transition: opacity 90ms linear;
}
.sk-band:hover { opacity: 0.92; }
.sk-wrap.is-tracing .sk-band { opacity: 0.08; }
.sk-wrap.is-tracing .sk-band.is-lit {
  opacity: 0.95;
  stroke: var(--basalt);
  stroke-width: 1.5;
}
.sk-wrap.is-tracing .sk-band.is-origin {
  stroke: var(--lime);
  stroke-width: 2.5;
}
.sk-wrap.is-tracing .sk-node { opacity: 0.25; }
.sk-wrap.is-tracing .sk-node.is-lit { opacity: 1; }
.sk-wrap.is-tracing .sk-node.is-lit .sk-block {
  stroke: var(--lime);
  stroke-width: 2.5;
}

/* The same four bands as everywhere else on the site, so the colour means one thing
   whichever page you learned it on. Grey is not a fifth level — it is the absence of
   an answer, and it should look like one. */
.sk-band.is-special    { fill: #7d1d14; }
.sk-band.is-personal   { fill: #b4453a; }
.sk-band.is-commercial { fill: #c08a2e; }
.sk-band.is-business   { fill: #4a6f78; }
.sk-band.is-unknown    { fill: var(--basalt-40); opacity: 0.22; }
.sk-band.is-unknown:hover { opacity: 0.6; }

/* Work coming back to a hand that has already had it. Worth seeing: a round trip is
   usually either a review loop or the same information being handled twice. */
.sk-band.is-back { opacity: 0.3; }
.sk-band.is-back:hover { opacity: 0.85; }

.sk-block {
  fill: var(--basalt);
  stroke: var(--paper);
  stroke-width: 1;
}
.sk-node.is-system   .sk-block { fill: #a86a2f; }
.sk-node.is-internal .sk-block { fill: #1d4d57; }
.sk-node.is-team     .sk-block { fill: #3d5b62; }
.sk-node.is-outside  .sk-block { fill: #8a3f2f; }
.sk-node.is-role     .sk-block { fill: #5d7a80; }
.sk-node.is-client   .sk-block { fill: #6f2f28; }
.sk-node.is-end      .sk-block { stroke: var(--lime); stroke-width: 2; }

.sk-name {
  font-size: 13.5px;
  font-weight: 600;
  fill: var(--basalt-80);
  paint-order: stroke;
  stroke: var(--paper);
  stroke-width: 3.5;
  stroke-linejoin: round;
  pointer-events: none;
}
.sk-n { font-weight: 400; fill: var(--basalt-40); }

.web-key .k-special    { background: #7d1d14; }
.web-key .k-commercial { background: #c08a2e; }
.web-key .k-business   { background: #4a6f78; }
.web-key .k-unknown    { background: var(--basalt-40); }

/* --------------------------------------------------------------------------
   The Data Chart — who deals with what
   Read by directors, so it is built to be read rather than operated: generous
   line length, real hierarchy, and the sensitivity of a thing carried by a
   colour band rather than by a word you have to look up.
   Cool is ours, warm is not ours, red is personal — the same language as the
   flow chart, so learning one teaches the other.
   -------------------------------------------------------------------------- */

.dk-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
  margin: 0 0 2rem;
}

.dk-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 16px 18px;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: var(--paper);
  box-shadow: 0 1px 2px rgba(9, 38, 45, 0.04);
}
.dk-card-n { font-size: 2rem; font-weight: 600; line-height: 1.05; color: var(--basalt); }
.dk-card-l { font-size: 0.86rem; font-weight: 600; color: var(--basalt-80); }
.dk-card-s { font-size: 0.78rem; color: var(--basalt-60); }

/* The chips. One vocabulary for a kind of information, used identically in the
   dossiers, the route table and the per-kind blocks, so it is learned once. */

.dk {
  display: inline-block;
  padding: 2px 9px 3px;
  margin: 0 2px 4px 0;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.45;
  border: 1px solid transparent;
  white-space: nowrap;
}
.dk-n {
  margin-left: 6px;
  padding-left: 6px;
  border-left: 1px solid currentColor;
  font-weight: 400;
  opacity: 0.75;
}
.dk-special    { background: #7d1d14; color: #fff; }
.dk-personal   { background: #fbe9e6; color: #8c2f22; border-color: #edc4bd; }
.dk-commercial { background: #fdf1de; color: #7a4c12; border-color: #edd6ac; }
.dk-business   { background: var(--basalt-05); color: var(--basalt-80); border-color: var(--basalt-10); }
.dk-system     { background: #eef3f4; color: #1d4d57; border-color: #cfe0e3; font-weight: 500; }

/* One person, fully. The band down the left is the worst thing they handle, so a
   page of these can be skimmed for the ones that matter without reading a word. */

.dk-people { display: grid; gap: 18px; }

.dk-person {
  border: 1px solid var(--rule);
  border-left: 5px solid var(--basalt-10);
  border-radius: 12px;
  background: var(--paper);
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(9, 38, 45, 0.04);
}
.dk-person.is-special    { border-left-color: #7d1d14; }
.dk-person.is-personal   { border-left-color: #b4453a; }
.dk-person.is-commercial { border-left-color: #c08a2e; }
.dk-person.is-business   { border-left-color: var(--basalt-40); }

.dk-person-head {
  padding: 16px 20px 14px;
  border-bottom: 1px solid var(--rule);
  background: linear-gradient(var(--basalt-05), rgba(9, 38, 45, 0));
}
.dk-person-head h3 { margin: 0; font-size: 1.18rem; letter-spacing: -0.01em; }
.dk-role { margin: 2px 0 0; font-size: 0.86rem; color: var(--basalt-60); }
.dk-worst { margin: 8px 0 0; font-size: 0.8rem; color: var(--basalt-80); }

.dk-person-body {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 0;
}
.dk-block {
  padding: 16px 20px;
  border-top: 1px solid var(--rule);
  border-right: 1px solid var(--rule);
  min-width: 0;
}
.dk-block h4 {
  margin: 0 0 8px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--basalt-60);
}
.dk-block .note { margin: 0; }
.dk-chips { margin: 10px 0 0; }

/* Somebody's own words are set apart and in the serif, so it is never in doubt
   which sentences are theirs and which are ours. */
.dk-said {
  margin: 0;
  padding: 0 0 0 14px;
  border-left: 2px solid var(--basalt-10);
  font-family: var(--font-em);
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--basalt-80);
}

.dk-flow { list-style: none; margin: 0; padding: 0; }
.dk-flow li {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 5px 0;
  border-bottom: 1px dotted var(--basalt-10);
  font-size: 0.88rem;
}
.dk-flow li:last-child { border-bottom: 0; }
.dk-who { font-weight: 600; color: var(--basalt); }
.dk-sub { font-size: 0.78rem; color: var(--basalt-60); }
.dk-count {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  font-size: 0.78rem;
  color: var(--basalt-60);
}

.dk-person-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 20px;
  padding: 10px 20px;
  border-top: 1px solid var(--rule);
  background: var(--basalt-05);
  font-size: 0.78rem;
  color: var(--basalt-60);
}

/* The evidence. Closed by default so the page can be skimmed; one click from
   any claim to the sentence it came from. */
.dk-evidence > summary {
  cursor: pointer;
  font-size: 0.78rem;
  color: var(--basalt-60);
  padding: 4px 0;
}
.dk-evidence > summary:hover { color: var(--basalt); }
.dk-evidence ul { margin: 6px 0 0; padding-left: 18px; }
.dk-evidence li { font-size: 0.82rem; line-height: 1.5; margin-bottom: 6px; }
.dk-evidence q { font-family: var(--font-em); color: var(--basalt-80); }
.dk-hit {
  font-weight: 700;
  background: var(--lime);
  padding: 0 3px;
  border-radius: 2px;
  color: var(--basalt);
}

/* The route table. */
.dk-routes td { vertical-align: top; }
.dk-routes tr.is-personal td:first-child { box-shadow: inset 3px 0 0 #b4453a; }
.dk-route { min-width: 260px; }
.dk-route .dk-sub { display: block; }
.dk-arrow { display: block; color: var(--basalt-40); margin: 2px 0; }

/* One block per kind of information. */
.dk-kinds { display: grid; gap: 16px; }
.dk-kind {
  padding: 18px 20px;
  border: 1px solid var(--rule);
  border-top: 4px solid var(--basalt-40);
  border-radius: 12px;
  background: var(--paper);
}
.dk-kind.is-special    { border-top-color: #7d1d14; }
.dk-kind.is-personal   { border-top-color: #b4453a; }
.dk-kind.is-commercial { border-top-color: #c08a2e; }
.dk-kind header { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.dk-kind h3 { margin: 0; font-size: 1.05rem; }
.dk-band {
  margin: 0;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--basalt-60);
}
.dk-why { margin: 8px 0 0; max-width: var(--measure); }
.dk-law {
  margin: 6px 0 14px;
  max-width: var(--measure);
  font-size: 0.85rem;
  color: var(--basalt-60);
}
.dk-kind h4 {
  margin: 0 0 6px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--basalt-60);
}

.dk-no { color: #8c2f22; font-weight: 600; }
.lead-sm { max-width: var(--measure); color: var(--basalt-80); }

@media (max-width: 640px) {
  .dk-block { border-right: 0; }
  .dk-card-n { font-size: 1.6rem; }
}

/* --------------------------------------------------------------------------
   The flow chart — the whole company as one web
   Obsidian's graph, with the four things it does not do: direction, volume,
   an explanation on hover, and a mark on anything carrying personal data.
   All of it works with scripting switched off; the script only adds pan and
   zoom on top of a picture that is already correct.
   -------------------------------------------------------------------------- */

.web-wrap {
  position: relative;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(9, 38, 45, 0.045), rgba(9, 38, 45, 0) 62%),
    var(--paper);
  border: 1px solid var(--rule);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(9, 38, 45, 0.05), 0 12px 32px -20px rgba(9, 38, 45, 0.35);
}

.web-tools {
  position: absolute;
  top: 8px;
  left: 10px;
  padding: 3px 8px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(3px);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 6px;
}

.web-hint { margin: 0 0 0 6px; }

/* The chart and the readout sit side by side. The explanation used to follow the
   mouse, which meant it covered the very thing you had just pointed at and vanished
   the moment you tried to read it. Parked on the side it stays still, stays put
   while you compare two, and can be as long as the truth requires. */
.web-wrap[data-chart],
.sk-wrap[data-chart] {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  position: relative;
}

/* Full screen. A fifteen-column diagram inside a column of a web page is a diagram
   read through a letterbox. The panel comes along — the explanation is the point of
   looking closely, so leaving it behind would be the wrong half. */
.web-wrap.is-full,
.sk-wrap.is-full {
  width: 100vw;
  height: 100vh;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: var(--paper);
  grid-template-columns: minmax(0, 1fr) 340px;
  grid-template-rows: 100%;
}
.web-wrap.is-full .js-pan,
.sk-wrap.is-full .js-pan {
  height: 100%;
  width: 100%;
}
.web-wrap.is-full .web-readout,
.sk-wrap.is-full .web-readout {
  height: 100%;
  overflow-y: auto;
}
.js-fullscreen[hidden] { display: none; }

/* Behaviour hooks. The js- prefix says so: these carry no appearance of their own,
   they are how the script finds the surface to drag and the group to move. */
/* Dragging a chart was selecting every label it passed over, so the page ended up
   blue and the drag ended up looking like a mistake. A chart is a surface you move,
   not a paragraph you highlight. */
.js-pan {
  touch-action: none;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
}
.js-pan-group { will-change: transform; }
.is-dragging .js-pan { cursor: grabbing; }

.web-svg {
  display: block;
  width: 100%;
  height: auto;
  touch-action: none;
  cursor: grab;
  grid-column: 1;
}

.web-readout {
  grid-column: 2;
  border-left: 1px solid var(--rule);
  background: rgba(9, 38, 45, 0.025);
  padding: 52px 18px 18px;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--basalt-80);
  overflow-wrap: anywhere;
}
.web-readout-idle { margin: 0; color: var(--basalt-40); font-size: 0.82rem; }
.web-readout h4 { margin: 0 0 4px; font-size: 0.98rem; line-height: 1.3; color: var(--basalt); }
.web-readout p { margin: 0 0 6px; }
.web-readout-tag {
  display: inline-block;
  margin: 0 0 8px;
  padding: 2px 8px 3px;
  border-radius: 999px;
  background: var(--basalt-05);
  border: 1px solid var(--basalt-10);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--basalt-60);
}
/* Pinned, and saying so. A panel that has stopped following the mouse without
   telling you looks like a panel that has broken. */
.web-readout-pin {
  margin: 0 0 10px;
  padding: 5px 9px;
  border-radius: 6px;
  background: var(--lime);
  color: var(--basalt);
  font-size: 0.76rem;
  font-weight: 700;
}
.web-readout-go {
  display: inline-block;
  margin-top: 6px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--basalt);
}

/* The panel is a list of answers, so headings and items are set as such rather than
   as more paragraphs. */
.web-readout-head {
  margin: 12px 0 3px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--basalt-60);
}
.web-readout-list { margin: 0; padding-left: 16px; }
.web-readout-list li { font-size: 0.83rem; line-height: 1.45; }

/* Every connection as a button the size of a line of text. A route two pixels tall in a
   crowded block is not clickable, and telling somebody to aim better is not a fix. */
.web-readout-links { list-style: none; margin: 4px 0 0; padding: 0; }
.web-readout-link {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  padding: 5px 8px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: none;
  font: inherit;
  font-size: 0.83rem;
  text-align: left;
  color: var(--basalt-80);
  cursor: pointer;
}
.web-readout-link:hover,
.web-readout-link:focus {
  background: var(--basalt-05);
  border-color: var(--basalt-10);
  outline: none;
}
.web-readout-link:focus { border-color: var(--basalt-40); }
.web-readout-dir { color: var(--basalt-40); font-weight: 700; }
.web-readout-name { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.web-readout-n {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-size: 0.76rem;
  color: var(--basalt-60);
}

.web-readout-said {
  padding-left: 10px;
  border-left: 2px solid var(--basalt-10);
  font-family: var(--font-em);
  color: var(--basalt-60);
}

@media (max-width: 820px) {
  .web-wrap[data-chart],
  .sk-wrap[data-chart] { grid-template-columns: minmax(0, 1fr); }
  .web-svg, .sk-svg, .web-readout { grid-column: 1; }
  .web-readout { border-left: 0; border-top: 1px solid var(--rule); padding-top: 16px; }
}



/* The group the script moves. Panning rewrites its transform attribute, so warn
   the browser it will change and let it keep the layer on the GPU. */
.web-pan { will-change: transform; }

/* Lines are only hoverable ON the line. Filled curves would each claim the whole
   area under their arc, and the top one would swallow every hover on the map. */
/* The visible line is not the target — its invisible twin is. */
.web-links { pointer-events: none; }
.web-hit {
  fill: none;
  stroke: transparent;
  stroke-width: 16;
  pointer-events: stroke;
  cursor: pointer;
}

.sk-band { cursor: pointer; }

/* Nodes sit above the lines, so a small dot in a busy patch is still reachable. */
.web-nodes { pointer-events: auto; }

/* The department each island is. Set behind everything, large and very pale, so it
   labels the cluster without competing with the names of the people in it. */
.web-islands { pointer-events: none; }

/* The ground of an area answers for the whole department. The name across the top does
   not — a label is for reading, and catching hovers with it only makes the thing behind
   it unreachable. Nodes are drawn after these, so a person always wins over the ground
   they are standing on. */
.web-zone { pointer-events: none; }
.web-zone-box { pointer-events: all; cursor: help; }

/* Each area has a rectangle it has to itself. Drawn faintly — it is a boundary, not a
   feature — but drawn, because "these eight belong together" is otherwise something the
   reader has to infer from proximity, and proximity is exactly what was failing. */
.web-zone-box {
  fill: rgba(9, 38, 45, 0.022);
  stroke: var(--basalt-10);
  stroke-width: 1;
}

.web-island {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  fill: var(--basalt-60);
}
.web-island-n { font-weight: 400; letter-spacing: 0; }

/* Lines --------------------------------------------------------------------
   Thin and pale by default. A hundred routes drawn boldly is wool; the eye has
   to be able to find the node before it can follow the line out of it. */

.web-link {
  fill: none;
  stroke: rgba(9, 38, 45, 0.22);
  stroke-width: 1.1;
  stroke-linecap: round;
  transition: stroke-width 90ms linear, opacity 90ms linear;
}

.web-link.is-often { stroke-width: 2; }
.web-link.is-heavy { stroke-width: 3.2; }

/* Personal information is the reason this site exists, so it is the one thing
   marked on the line itself rather than left to a hover. */
.web-link.has-personal {
  stroke: #b4453a;
  stroke-dasharray: 7 4;
}

.web-arrowhead { fill: rgba(9, 38, 45, 0.3); }

/* Named together in one answer, so we know they are connected and not which way it went.
   Drawn without an arrow and with a lighter touch: a real connection, honestly less than
   the ones that say where the work came from. */
.web-link.is-undirected {
  stroke-dasharray: 2 5;
  opacity: 0.75;
}

.web-link.w-0 { stroke: #1f6f5c; }
.web-link.w-1 { stroke: #8a4b2a; }
.web-link.w-2 { stroke: #3a5a8c; }
.web-link.w-3 { stroke: #7a3b62; }
.web-link.w-4 { stroke: #5a6a1f; }
.web-link.w-5 { stroke: #2a6a7a; }
.web-link.w-6 { stroke: #8a6a1f; }
.web-link.w-7 { stroke: #4a4a7a; }

/* Nodes --------------------------------------------------------------------
   Shape carries the same meaning as colour — a square is a system, a circle is
   a person or a party — so the map still reads printed in black and white, or
   to somebody who cannot separate the two greens. */

.web-node { cursor: pointer; }
.web-shape {
  fill: var(--basalt-40);
  stroke: var(--paper);
  stroke-width: 1.5;
  transition: fill 90ms linear;
}

/* Cool is us, warm is not us. A reader who learns nothing else about this map can still
   see at a glance how much of the company's information leaves the building. */
.web-node.is-person   .web-shape { fill: var(--basalt); }
.web-node.is-team     .web-shape { fill: #3d5b62; }
.web-node.is-internal .web-shape { fill: #1d4d57; }
.web-node.is-system   .web-shape { fill: #a86a2f; }
.web-node.is-outside  .web-shape { fill: #8a3f2f; }
/* A role is ours but not a person, so it sits in the family without being one of the
   circles you can put a face to. A client is firmly outside. */
.web-node.is-role     .web-shape { fill: #5d7a80; }
.web-node.is-client   .web-shape { fill: #6f2f28; }
.web-node.is-focus    .web-shape { fill: var(--basalt); stroke: var(--lime); stroke-width: 3.5; }

.web-label {
  font-size: 11px;
  font-weight: 500;
  fill: var(--basalt-80);
  paint-order: stroke;
  stroke: var(--paper);
  stroke-width: 3.5;
  stroke-linejoin: round;
  pointer-events: none;
  transition: opacity 90ms linear;
}

/* Zoomed out, the quiet names are faded rather than removed. Removed would mean
   the map silently omits the person somebody came here to find; faded means the
   busy names are readable and the rest are still there when you lean in. */
.web-wrap:not(.is-near) .web-node:not(.is-major):not(.is-focus) .web-label { opacity: 0.28; }
.web-node.is-major .web-label { font-size: 12.5px; font-weight: 600; fill: var(--basalt); }

/* Following one thread ------------------------------------------------------
   Hover or keyboard-focus a node and everything it does not touch drops back.
   This is the answer to "which of these lines is hers", and it is the single
   most useful thing on the page once there are more than about thirty ends. */

.web-wrap.is-tracing .web-link,
.web-wrap.is-tracing .web-node { opacity: 0.08; }

/* The area names go back with everything else, and the ones involved come forward. An
   area whose name has faded is an area you can stop reading, which is most of the value
   of following one thread in the first place. */
.web-wrap.is-tracing .web-zone { opacity: 0.25; }
.web-wrap.is-tracing .web-zone.is-lit { opacity: 1; }
.web-wrap.is-tracing .web-zone.is-lit .web-island { fill: var(--basalt); }
.web-wrap.is-tracing .web-zone.is-lit .web-zone-box {
  stroke: var(--basalt-40);
  fill: rgba(9, 38, 45, 0.05);
}
.web-wrap.is-tracing .web-zone.is-origin .web-zone-box {
  stroke: var(--lime);
  stroke-width: 3;
}

/* Fading everything else is not enough on its own. At a glance a dimmed line and a
   lit one differ only in how grey they are, which is a judgement call the reader has
   to make about every line on the page. An outline is not a judgement call. */
.web-wrap.is-tracing .web-link.is-lit {
  opacity: 1;
  stroke-width: 3.4;
  paint-order: stroke;
}

.web-wrap.is-tracing .web-node.is-lit { opacity: 1; }
.web-wrap.is-tracing .web-node.is-lit .web-label { opacity: 1; font-weight: 700; }

/* Everything lit gets a ring; the one you actually chose gets a thicker one in the
   highlighter colour, so "this is what I clicked" and "this is what it touches" are
   two different statements rather than one vague one. */
.web-wrap.is-tracing .web-node.is-lit .web-shape {
  stroke: var(--basalt);
  stroke-width: 2.5;
}
.web-wrap.is-tracing .web-node.is-origin .web-shape {
  stroke: var(--lime);
  stroke-width: 4;
}

/* A line cannot carry a second stroke, so the chosen one is doubled: the halo is drawn
   by its own hit path, which is otherwise invisible. */
.web-wrap.is-tracing .web-hit.is-chosen {
  stroke: var(--lime);
  stroke-width: 9;
}

/* With scripting off there is no tracing class, so hovering a single line still
   has to lift it on its own. */

.web-node:hover .web-shape,
.web-node:focus .web-shape { stroke: var(--basalt); stroke-width: 2.5; }
.web-node:focus { outline: none; }
.web-node:focus .web-label { opacity: 1; }

.web-key {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  align-items: center;
  margin: 10px 0 0;
  font-size: 0.82rem;
  color: var(--muted);
}
.web-key b { font-weight: 600; color: var(--basalt); }
.web-key .dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 5px;
  vertical-align: -1px;
}
.web-key .dot.sq { border-radius: 2px; }
.web-key .k-person { background: var(--basalt); }
.web-key .k-internal { background: #1d4d57; }
.web-key .k-system { background: #a86a2f; }
.web-key .k-team { background: #3d5b62; }
.web-key .k-outside { background: #8a3f2f; }
.web-key .k-role { background: #5d7a80; }
.web-key .k-client { background: #6f2f28; }
.web-key .k-personal { background: #b4453a; }

@media (prefers-reduced-motion: reduce) {
  .web-link, .web-node, .web-shape, .web-label { transition: none; }
}

/* --------------------------------------------------------------------------
   Following one flow through a tangle
   Hovering a line lifts it and fades the rest. Pure CSS: the strict CSP forbids
   inline handlers, and this works with scripting off entirely. It is the only
   thing that actually answers "which line is that one" on a map this dense.
   -------------------------------------------------------------------------- */

.map-svg:hover .flow-link { opacity: 0.12; }

.map-svg .flow-link:hover {
  opacity: 1;
  stroke-width: 3;
}

/* Eight colours per workflow, so where two flows cross it is two colours meeting
   rather than two identical lines. Chosen for contrast against each other and to
   stay legible on paper; the palette is deliberately muted so the map does not
   turn into a rainbow. */
.flow-link.w-0 { stroke: #1f6f5c; }
.flow-link.w-1 { stroke: #8a4b2a; }
.flow-link.w-2 { stroke: #3a5a8c; }
.flow-link.w-3 { stroke: #7a3b62; }
.flow-link.w-4 { stroke: #5a6a1f; }
.flow-link.w-5 { stroke: #2a6a7a; }
.flow-link.w-6 { stroke: #8a6a1f; }
.flow-link.w-7 { stroke: #4a4a7a; }

/* A team is an end that work moves to. Drawn as a rounded tag rather than a circle or a
   square, so it reads as neither a person nor a system at a glance. */
.flow-node.is-team .node-shape {
  fill: var(--basalt-10);
  stroke: var(--basalt-60);
  stroke-width: 1.5;
}

/* --------------------------------------------------------------------------
   The Claude learning section
   Cards for topics, rows for lessons, one lesson at a time. Nothing decorative:
   the same basalt, the same rules, the same spacing as everywhere else.
   -------------------------------------------------------------------------- */

.topic-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.topic-card {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--rule);
  text-decoration: none;
  color: var(--basalt);
}

.topic-card:hover { border-color: var(--basalt); background: var(--basalt-05); }
.topic-card:focus-visible { outline: 2px solid var(--basalt); outline-offset: -2px; }
.topic-title { font-weight: 700; font-size: 1.02rem; }
.topic-sum { color: var(--basalt-80); font-size: 0.9rem; }
.topic-meta { color: var(--basalt-60); font-size: 0.8rem; margin-top: 0.2rem; }

/* Lessons within a topic. A grid so the number, title and description line up. */
.lesson-list { border-top: 1px solid var(--rule); margin-bottom: 1.25rem; }

.lesson-row {
  display: grid;
  grid-template-columns: 2rem minmax(9rem, 1fr) minmax(0, 1.4fr) auto;
  gap: 0.75rem;
  align-items: baseline;
  padding: 0.7rem 0.5rem;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: var(--basalt);
}

.lesson-row:hover { background: var(--basalt-05); }
.lesson-row:focus-visible { outline: 2px solid var(--basalt); outline-offset: -2px; }
.lesson-row.is-static:hover { background: none; }
.lesson-n { color: var(--basalt-60); font-variant-numeric: tabular-nums; }
.lesson-title { font-weight: 600; }
.lesson-sum { color: var(--basalt-60); font-size: 0.88rem; }

/* One lesson. Narrow measure, because this is the only part of the site meant to be
   read rather than scanned. */
.lesson { max-width: 38rem; margin-bottom: 1.5rem; }
.lesson p { margin-bottom: 0.9rem; }
.lesson-part { margin-bottom: 1.25rem; }

.lesson-part h3 {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--basalt-60);
  margin-bottom: 0.35rem;
}

/* An example is something to copy, so it reads as a block rather than as prose. */
.lesson-part.is-example p {
  border-left: 3px solid var(--basalt-10);
  padding-left: 0.9rem;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.88rem;
  white-space: pre-wrap;
}

.lesson-part.is-remember p {
  border-left: 3px solid var(--basalt);
  padding-left: 0.9rem;
  font-weight: 600;
}

.lesson-nav { flex-wrap: wrap; gap: 0.5rem; }
.done-form { margin: 1rem 0 1.5rem; }

.crumbs { font-size: 0.85rem; color: var(--basalt-60); margin-bottom: 0.5rem; }

/* What not to put in. The rule leads, because that is what somebody is checking. */
.care-list { border-top: 1px solid var(--rule); margin-bottom: 1.5rem; }

.care-row {
  display: grid;
  grid-template-columns: 6rem minmax(10rem, 1fr) minmax(0, 1fr);
  gap: 0.75rem;
  align-items: baseline;
  padding: 0.7rem 0.5rem;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: var(--basalt);
}

.care-row:hover { background: var(--basalt-05); }
.care-row:focus-visible { outline: 2px solid var(--basalt); outline-offset: -2px; }
.care-kind { font-weight: 600; }
.care-af { color: var(--basalt-60); font-size: 0.88rem; font-style: italic; }

.care-rule {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 700;
  padding: 0.15rem 0.4rem;
  align-self: start;
}

.care-rule.is-never { background: var(--basalt); color: var(--paper); }
.care-rule.is-ask { background: var(--basalt-10); color: var(--basalt); }

.in-af { color: var(--basalt-80); }

.af-tag {
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--basalt-60);
  margin-right: 0.3rem;
}

/* Search results. */
.results { border-top: 1px solid var(--rule); }

.result {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.8rem 0.5rem;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: var(--basalt);
}

.result:hover { background: var(--basalt-05); }
.result:focus-visible { outline: 2px solid var(--basalt); outline-offset: -2px; }
.result-head { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
.result-title { font-weight: 600; }
.result-parent { color: var(--basalt-60); font-size: 0.8rem; }
.result-snip { color: var(--basalt-80); font-size: 0.9rem; }

@media (max-width: 45rem) {
  .lesson-row { grid-template-columns: 1.5rem 1fr; }
  .lesson-row .lesson-sum, .lesson-row .lesson-done { grid-column: 2; }
  .care-row { grid-template-columns: 1fr; gap: 0.2rem; }
  .care-rule { justify-self: start; }
}

/* A disclosure summary on a light background. .linkish is white, for the dark bar. */
.disclose {
  cursor: pointer;
  color: var(--basalt);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.disclose:hover { color: var(--basalt-80); }

.foot {
  border-top: 1px solid var(--rule);
  margin-top: 4rem;
  padding: 1.5rem;
  color: var(--basalt-60);
  font-size: 0.85rem;
}

.foot p { margin: 0; }

/* --------------------------------------------------------------------------
   Shell
   -------------------------------------------------------------------------- */

.shell {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 3rem 1.5rem 2rem;
}

.shell-wide { max-width: 76rem; }

.page-head { margin-bottom: 2.5rem; }

.page-head .lead {
  font-size: 1.1rem;
  color: var(--basalt-80);
  max-width: 38rem;
}

.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.13em;
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--basalt-60);
  margin: 0 0 0.6rem;
}

/* --------------------------------------------------------------------------
   Parts
   -------------------------------------------------------------------------- */

.part { margin: 0 0 3.5rem; }

.part-head {
  border-top: 2px solid var(--basalt);
  padding-top: 0.9rem;
  margin-bottom: 1.75rem;
}

.part-number {
  font-family: var(--font-em);
  font-weight: 700;
  font-style: italic;
  color: var(--basalt-60);
  font-size: 0.95rem;
  display: block;
  margin-bottom: 0.15rem;
}

.part-intro {
  color: var(--basalt-80);
  margin: 0.6rem 0 0;
  max-width: 34rem;
}

/* --------------------------------------------------------------------------
   The spine — part two only
   Eight questions in the order they actually happen. The spine exists to
   carry that order, which is why it appears here and nowhere else.
   -------------------------------------------------------------------------- */

.spine { position: relative; padding-left: 2.25rem; }

.spine::before {
  content: '';
  position: absolute;
  left: 0.4rem;
  top: 0.55rem;
  bottom: 1.5rem;
  width: 2px;
  background: var(--basalt-10);
}

.spine > .field { position: relative; }

.spine > .field::before {
  content: '';
  position: absolute;
  left: -2.25rem;
  top: 0.5rem;
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--basalt-40);
}

/* The `copies` marker is filled lime — the one place on the spine that is. */
.spine > .field-emphasis::before {
  background: var(--lime);
  border-color: var(--basalt);
}

/* --------------------------------------------------------------------------
   Fields
   -------------------------------------------------------------------------- */

.field { margin-bottom: 2.25rem; }

.field-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.field-label {
  display: block;
  font-weight: 700;
  font-size: 1.05rem;
  margin-bottom: 0.3rem;
}

.req {
  font-weight: 400;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--basalt-40);
  margin-left: 0.4rem;
}

.hint {
  color: var(--basalt-60);
  font-size: 0.9rem;
  margin: 0 0 0.7rem;
  max-width: 36rem;
}

.input {
  width: 100%;
  font: inherit;
  color: var(--basalt);
  background: var(--paper);
  border: 1px solid var(--basalt-40);
  border-radius: 2px;
  padding: 0.6rem 0.7rem;
}

.input:hover { border-color: var(--basalt-60); }

.input:focus {
  outline: 3px solid var(--basalt);
  outline-offset: 1px;
  border-color: var(--basalt);
}

.input:disabled {
  background: var(--basalt-05);
  color: var(--basalt-40);
  border-style: dashed;
  cursor: not-allowed;
}

.input-date { width: auto; min-width: 12rem; }

textarea.input { resize: vertical; line-height: 1.6; display: block; }

/* Textarea sizes are utility classes, not style attributes: the CSP forbids
   inline styles. */
.ta-s { min-height: 4.5rem; }
.ta-m { min-height: 7.5rem; }
.ta-l { min-height: 13rem; }

/* The emphasised field — `copies`. Distinct without reaching for a second
   colour: a basalt keyline and a tinted ground. */
.field-emphasis {
  background: var(--basalt-05);
  border-left: 3px solid var(--basalt);
  padding: 1.25rem 1.25rem 1.4rem;
  margin-left: -1.25rem;
}

.field-emphasis .hint { color: var(--basalt-80); max-width: 40rem; }

/* Not sure toggle */
.notsure {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: var(--basalt-60);
  flex-shrink: 0;
}

.notsure input { width: 1rem; height: 1rem; accent-color: var(--basalt); margin: 0; }
.notsure label { cursor: pointer; user-select: none; }

.radio-row { display: flex; gap: 1.25rem; flex-wrap: wrap; padding-top: 0.2rem; }
.radio-item { display: inline-flex; align-items: center; gap: 0.4rem; }
.radio-item input { width: 1rem; height: 1rem; accent-color: var(--basalt); margin: 0; }
.radio-item label { cursor: pointer; }

.is-hidden { display: none; }

/* --------------------------------------------------------------------------
   Buttons — basalt, never lime. Lime is the highlighter and nothing else.
   -------------------------------------------------------------------------- */

.btn {
  display: inline-block;
  font: inherit;
  font-weight: 700;
  background: var(--basalt);
  color: var(--paper);
  border: 2px solid var(--basalt);
  border-radius: 2px;
  padding: 0.65rem 1.5rem;
  cursor: pointer;
  text-decoration: none;
}

.btn:hover { background: rgba(9, 38, 45, 0.88); color: var(--paper); }

.btn-ghost { background: transparent; color: var(--basalt); }
.btn-ghost:hover { background: var(--basalt-05); color: var(--basalt); }

.actions {
  display: flex;
  gap: 1rem;
  align-items: center;
  flex-wrap: wrap;
  border-top: 1px solid var(--rule);
  padding-top: 1.5rem;
  margin-top: 2.5rem;
}

.actions .note { color: var(--basalt-60); font-size: 0.88rem; margin: 0; }

/* --------------------------------------------------------------------------
   Flashes, tags, cards
   -------------------------------------------------------------------------- */

.flash {
  border: 1px solid var(--basalt);
  border-left-width: 4px;
  padding: 0.8rem 1rem;
  margin-bottom: 1.75rem;
  background: var(--basalt-05);
}

.flash-error { border-color: var(--basalt); font-weight: 600; }

.tag {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  padding: 0.15rem 0.5rem;
  border: 1px solid var(--basalt-40);
  border-radius: 2px;
  color: var(--basalt-80);
}

/* NOT SURE must read as a deliberate answer, distinct from an empty one. */
.tag-notsure { border-color: var(--basalt); color: var(--basalt); border-style: solid; font-weight: 700; }
.tag-empty   { border-style: dashed; color: var(--basalt-40); }

.card {
  border: 1px solid var(--rule);
  padding: 1.25rem 1.4rem;
  margin-bottom: 1rem;
}

.card h3 { margin-bottom: 0.35rem; }
.card .meta { color: var(--basalt-60); font-size: 0.85rem; margin: 0; }

.stack { display: grid; gap: 0.75rem; }
.row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; }
@media (max-width: 40rem) { .row-2 { grid-template-columns: 1fr; } }

.ro-value { white-space: pre-wrap; margin: 0; color: var(--basalt-80); }
.field-ro { margin-bottom: 1.25rem; }
.field-ro .field-label { font-size: 0.95rem; margin-bottom: 0.1rem; }

/* --------------------------------------------------------------------------
   Admin
   -------------------------------------------------------------------------- */

.admin-bar {
  display: flex;
  gap: 1rem;
  align-items: center;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 1rem;
  margin-bottom: 2rem;
}

.admin-bar .grow { margin-right: auto; }

.resp {
  border: 1px solid var(--rule);
  border-top: 3px solid var(--basalt);
  padding: 1.5rem;
  margin-bottom: 2rem;
}

.resp-head { display: flex; gap: 1rem; justify-content: space-between; flex-wrap: wrap; margin-bottom: 1.25rem; }
.resp-head .meta { color: var(--basalt-60); font-size: 0.85rem; margin: 0; }
.resp-account { font-size: 0.85rem; color: var(--basalt-60); }

.qa { border-top: 1px solid var(--rule); padding: 0.9rem 0; }
.qa:last-child { border-bottom: 1px solid var(--rule); }
.qa-q { font-weight: 700; font-size: 0.9rem; margin: 0 0 0.25rem; }
.qa-a { white-space: pre-wrap; margin: 0; color: var(--basalt-80); }
.qa-key { font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace; font-size: 0.75rem; color: var(--basalt-40); }

table.grid { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
table.grid th, table.grid td { text-align: left; padding: 0.55rem 0.7rem; border-bottom: 1px solid var(--rule); vertical-align: top; }
table.grid th { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--basalt-60); }
.scroll-x { overflow-x: auto; }

/* --------------------------------------------------------------------------
   Chevrons
   Three stages of one journey — never arrived, arrived and stopped, arrived and
   logged nothing — so they point into each other rather than sitting in three
   separate boxes. clip-path rather than borders or background images: one shape,
   no extra requests, and it scales with the text.
   -------------------------------------------------------------------------- */

/* Landing on the strip rather than flush against the viewport edge, so the heading
   above it is still readable when a tab is clicked. */
.chevrons,
.admin-tabs { scroll-margin-top: 1.5rem; }

.chevrons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin: 0 0 1.25rem;
}

.chevron {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1.6rem 0.6rem 1.9rem;
  background: var(--basalt-05);
  color: var(--basalt-80);
  text-decoration: none;
  font-size: 0.86rem;
  /* Pointed right, notched left, so consecutive chevrons interlock. */
  clip-path: polygon(0 0, calc(100% - 0.9rem) 0, 100% 50%, calc(100% - 0.9rem) 100%, 0 100%, 0.9rem 50%);
}

/* The first one has nothing to interlock with, so it gets a flat left edge. */
.chevron:first-child {
  padding-left: 1.1rem;
  clip-path: polygon(0 0, calc(100% - 0.9rem) 0, 100% 50%, calc(100% - 0.9rem) 100%, 0 100%);
}

.chevron:hover { background: var(--basalt-10); }

.chevron.is-on {
  background: var(--basalt);
  color: var(--paper);
}

.chevron-label { font-weight: 600; }

.chevron-n {
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  opacity: 0.75;
}

/* Stacked on a narrow screen, where a row of interlocking arrows would be unreadable.
   Pointing down instead of right keeps the meaning. */
@media (max-width: 40rem) {
  .chevrons { flex-direction: column; gap: 0.15rem; }
  .chevron,
  .chevron:first-child {
    padding: 0.55rem 1.1rem 0.9rem;
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - 0.6rem), 50% 100%, 0 calc(100% - 0.6rem));
  }
}

/* --------------------------------------------------------------------------
   Landing
   -------------------------------------------------------------------------- */

.hero { margin-bottom: 3rem; }
.hero h1 { max-width: 32rem; }
.hero .lead { font-size: 1.15rem; color: var(--basalt-80); max-width: 36rem; margin-top: 1rem; }

.why { border-left: 3px solid var(--basalt); padding: 0.2rem 0 0.2rem 1.25rem; margin: 2rem 0 2.5rem; }
.why p { margin-bottom: 0.6rem; }
.why p:last-child { margin-bottom: 0; }

.steps { list-style: none; padding: 0; margin: 0 0 2.5rem; counter-reset: step; }

.steps li {
  counter-increment: step;
  position: relative;
  padding-left: 2.5rem;
  margin-bottom: 1rem;
  color: var(--basalt-80);
}

.steps li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0.05rem;
  width: 1.7rem; height: 1.7rem;
  border: 2px solid var(--basalt);
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: 0.8rem; font-weight: 700;
  color: var(--basalt);
}

/* --------------------------------------------------------------------------
   Dashboard — the administrator's view
   -------------------------------------------------------------------------- */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  margin-bottom: 3rem;
}

.stat {
  background: var(--paper);
  padding: 1.1rem 1.2rem;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.stat-figure { font-size: 1.9rem; font-weight: 700; line-height: 1.1; }

.stat-label {
  font-size: 0.78rem;
  color: var(--basalt-60);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  line-height: 1.35;
}

/* Recent activity */
.feed { list-style: none; padding: 0; margin: 0; }

.feed-item {
  display: grid;
  grid-template-columns: 9.5rem 1fr;
  gap: 0.25rem 1rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--rule);
}

.feed-item:first-child { border-top: 1px solid var(--rule); }

.feed-when {
  color: var(--basalt-40);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  padding-top: 0.1rem;
}

.feed-what { font-size: 0.95rem; }

.feed-detail {
  grid-column: 2;
  color: var(--basalt-60);
  font-size: 0.87rem;
}

@media (max-width: 34rem) {
  .feed-item { grid-template-columns: 1fr; }
  .feed-detail { grid-column: 1; }
}

/* Coverage panels */
.panel { border: 1px solid var(--rule); padding: 1rem 1.1rem 0.5rem; margin-bottom: 1.25rem; }

.panel h3 {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--basalt-60);
  margin-bottom: 0.5rem;
}

.panel table.grid td { padding: 0.35rem 0; border-bottom: 1px solid var(--basalt-05); }
.panel table.grid tr:last-child td { border-bottom: none; }

td.num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 700; width: 3.5rem; }

@media print {
  .topbar, .topnav, .actions, .foot { display: none; }
  body { color: #000; }
}

/* --------------------------------------------------------------------------
   The gate — the only thing an anonymous visitor sees
   -------------------------------------------------------------------------- */

.gate { max-width: 34rem; padding-top: 2rem; }
.gate h1 { margin-bottom: 1rem; }
.gate .lead { font-size: 1.1rem; color: var(--basalt-80); }
.gate .actions { margin-top: 2rem; }
.gate .note { margin-top: 1.5rem; color: var(--basalt-60); font-size: 0.88rem; }

/* --------------------------------------------------------------------------
   Live character counter
   Encouragement bands set by the owner: red -> orange -> yellow -> green ->
   blue as an answer gets longer.

   NOTE ON BRAND: the CI guideline restricts this site to basalt and lime, and
   an earlier amber accent was removed as off-brand. These five hues are a
   deliberate exception, requested by the owner for the encouragement device
   only. They appear nowhere else, and never as a background or a heading.

   NOTE ON CONTRAST: each hue is a darkened variant so it clears 4.5:1 on
   white. Pure yellow (#FFD400) measures about 1.6:1 and is unreadable as
   text, so the "yellow" band uses a dark gold and carries a yellow dot.
   -------------------------------------------------------------------------- */

.counter {
  font-size: 0.82rem;
  font-weight: 600;
  margin: 0.4rem 0 0;
  min-height: 1.2em;          /* reserve the line so nothing jumps as you type */
  display: flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--basalt-60);
  transition: color 0.15s;
}

/* The dot carries the true hue; the text carries a legible variant. */
.counter::before {
  content: '';
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
  opacity: 0;
  transition: opacity 0.15s, background 0.15s;
}

.counter.is-plain  { color: var(--basalt-40); }
.counter.is-red    { color: #c0362c; }
.counter.is-orange { color: #b85c00; }
.counter.is-yellow { color: #8f7000; }
.counter.is-green  { color: #1e7a45; }
.counter.is-blue   { color: #1d5fb4; }

.counter.is-red::before,
.counter.is-orange::before,
.counter.is-yellow::before,
.counter.is-green::before,
.counter.is-blue::before { opacity: 1; }

/* True hues on the dot only, where contrast does not apply. */
.counter.is-red::before    { background: #e03b2f; }
.counter.is-orange::before { background: #f08000; }
.counter.is-yellow::before { background: #ffd400; }
.counter.is-green::before  { background: #23a05a; }
.counter.is-blue::before   { background: #2a7fe0; }

/* A disabled box (Not sure) shows no encouragement. */
.input:disabled + .counter { color: var(--basalt-40); }
.input:disabled + .counter::before { opacity: 0; }

/* --------------------------------------------------------------------------
   Voice notes
   -------------------------------------------------------------------------- */

.voice {
  border: 1px solid var(--rule);
  border-left: 3px solid var(--basalt);
  padding: 1rem 1.1rem;
  background: var(--basalt-05);
}

.voice-controls { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }

.voice-status { font-size: 0.85rem; color: var(--basalt-60); }
.voice-status.is-recording { color: #c0362c; font-weight: 600; }
.voice-status.is-saved     { color: #1e7a45; font-weight: 600; }
.voice-status.is-error     { color: #c0362c; }

/* A quiet pulse while recording, so it is obvious the microphone is live. */
.voice-status.is-recording::before {
  content: '';
  display: inline-block;
  width: 0.6rem; height: 0.6rem;
  border-radius: 50%;
  background: #e03b2f;
  margin-right: 0.45rem;
  animation: voicePulse 1.2s ease-in-out infinite;
}

@keyframes voicePulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

@media (prefers-reduced-motion: reduce) {
  .voice-status.is-recording::before { animation: none; }
}

.voice-player { display: block; width: 100%; max-width: 22rem; margin-top: 0.9rem; }

/* --------------------------------------------------------------------------
   Administrator portal
   -------------------------------------------------------------------------- */

.admin-tabs {
  margin: 0 0 2rem;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 0.75rem;
  gap: 1.5rem;
}

.admin-tabs a {
  color: var(--basalt-60);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.95rem;
  opacity: 1;
  border-bottom: 2px solid transparent;
  padding-bottom: 0.35rem;
}

.admin-tabs a:hover { color: var(--basalt); }
.admin-tabs a[aria-current='page'] { color: var(--basalt); border-bottom-color: var(--basalt); }

/* State tags. Basalt only — a role or an account state is not an encouragement,
   so it does not borrow the counter's colours. */
.tag-on  { border-color: var(--basalt); color: var(--basalt); }
.tag-off { border-style: dashed; border-color: var(--basalt); color: var(--basalt); text-decoration: line-through; }

/* A failed sign-in or an administrative change should catch the eye when
   scanning, without a colour. */
tr.row-notable td { background: var(--basalt-05); font-weight: 600; }
tr.row-inactive td { opacity: 0.45; }

td.wrap { word-break: break-word; max-width: 18rem; }

/* One cell for who somebody is, instead of five columns. Thirteen columns had squeezed
   the address down to one character per line. The name leads, the address sits under it
   at full width, and the staff details run as one quiet line. */
.who-cell { min-width: 15rem; }
.who-cell .who-name { font-weight: 600; }
.who-cell .who-addr,
.who-cell .who-meta { display: block; font-size: 0.82rem; color: var(--basalt-60); }
/* Break an address at its punctuation rather than mid-word. */
.who-cell .who-addr { overflow-wrap: anywhere; }
.who-cell .who-meta { margin-top: 0.1rem; }
td.nowrap, th.nowrap { white-space: nowrap; }

.action-cell { display: flex; gap: 0.35rem; flex-wrap: wrap; align-items: center; }

.btn-outline-sm, .btn-danger-sm {
  font: inherit;
  font-size: 0.78rem;
  padding: 0.25rem 0.6rem;
  border-radius: 2px;
  cursor: pointer;
  background: transparent;
  white-space: nowrap;
}

.btn-outline-sm { border: 1px solid var(--basalt-40); color: var(--basalt); }
.btn-outline-sm:hover { border-color: var(--basalt); background: var(--basalt-05); }

/* Destructive actions are outlined and underlined rather than coloured red: the
   palette is basalt and lime, and red here would compete with the counter. */
.btn-danger-sm { border: 1px solid var(--basalt); color: var(--basalt); text-decoration: underline; }
.btn-danger-sm:hover { background: var(--basalt); color: var(--paper); }

.admin-bar .grow { margin-right: auto; }

/* --------------------------------------------------------------------------
   The maps
   Basalt only. Volume is size and weight, direction is position and arrowhead,
   and nothing depends on hue — so both maps read in greyscale and in print.
   No rotated text: labels near the top and bottom of a circle came out vertical
   and unreadable.
   -------------------------------------------------------------------------- */

.map-wrap {
  border: 1px solid var(--rule);
  background: var(--paper);
  margin-bottom: 1.25rem;
  overflow-x: auto;
  padding: 0.5rem;
}

.map-svg { display: block; width: 100%; height: auto; min-width: 38rem; }

/* --- the company sunburst --- */
.dept-wedge {
  fill: var(--basalt-05);
  stroke: var(--paper);
  stroke-width: 2;
  transition: fill 0.15s;
}
.dept-wedge.has-logged { fill: rgba(9, 38, 45, 0.22); }
.dept-wedge:hover { fill: rgba(9, 38, 45, 0.42); }

.person-dot { fill: var(--paper); stroke: var(--basalt-40); stroke-width: 1.3; }
.person-dot.has-logged { fill: var(--basalt); stroke: var(--basalt); }

.core circle { fill: var(--basalt); }
.core-total { font-family: var(--font); font-size: 34px; font-weight: 700; fill: var(--paper); }
.core-word  { font-family: var(--font); font-size: 12px; fill: var(--paper); opacity: 0.85; letter-spacing: 0.1em; text-transform: uppercase; }
.core-sub   { font-family: var(--font); font-size: 11px; fill: var(--paper); opacity: 0.6; }

.label-leader { fill: none; stroke: var(--basalt-40); stroke-width: 1; }
.label-name  { font-family: var(--font); font-size: 13px; font-weight: 700; fill: var(--basalt); }
.label-count { font-family: var(--font); font-size: 11px; fill: var(--basalt-60); }

/* --- the flow columns --- */
.col-head {
  font-family: var(--font);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  fill: var(--basalt-40);
}

.flow-link {
  fill: none;
  stroke: var(--basalt-40);
  stroke-width: 1.6;
  transition: stroke 0.15s, stroke-width 0.15s;
}
.flow-link.has-personal { stroke: var(--basalt); stroke-width: 2.4; }
.flow-link:hover { stroke: var(--basalt); stroke-width: 3.2; }

.flow-node .node-shape { fill: var(--paper); stroke: var(--basalt); stroke-width: 1.8; }
.flow-node.is-person .node-shape { fill: var(--basalt); }
.flow-node.is-system .node-shape { fill: var(--basalt); }
.flow-node.is-outside .node-shape { fill: var(--paper); stroke-dasharray: 2.5 2; }
.flow-node.is-focus .node-shape { stroke-width: 3.5; }

.node-label { font-family: var(--font); font-size: 13px; font-weight: 600; fill: var(--basalt); }
.node-sub   { font-family: var(--font); font-size: 10.5px; fill: var(--basalt-60); }

/* --- key --- */
.map-key {
  list-style: none;
  padding: 0;
  margin: 0 0 1.25rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  font-size: 0.85rem;
  color: var(--basalt-60);
}
.map-key li { display: flex; align-items: center; gap: 0.45rem; }

.key-line { width: 1.8rem; height: 0; border-top: 2px solid var(--basalt-40); }
.key-line.has-personal { border-top-color: var(--basalt); border-top-width: 3px; }
.key-mark { width: 0.72rem; height: 0.72rem; flex-shrink: 0; }
.key-mark.is-logged { background: var(--basalt); border-radius: 50%; }
.key-mark.is-party  { border: 1.5px dashed var(--basalt); border-radius: 50%; }
.key-mark.is-system { background: var(--basalt); border-radius: 2px; }
.key-swatch { width: 1.4rem; height: 0.8rem; flex-shrink: 0; border: 1px solid var(--paper); }
.key-swatch.is-wedge { background: var(--basalt-05); outline: 1px solid var(--basalt-10); }
.key-swatch.is-wedge-live { background: rgba(9, 38, 45, 0.22); }

/* A person on the staff list whose sign-in access is currently withdrawn: still in
   their department, visibly not active. */
.person-dot.no-access { fill: var(--paper); stroke: var(--basalt-10); stroke-width: 1; }
.key-mark.is-noaccess { border: 1px solid var(--basalt-10); border-radius: 50%; }

/* An internal system is ours; an external one is not; an unrecognised endpoint is
   neither claim. Three distinguishable fills, still basalt only. */
.flow-node.is-internal .node-shape { fill: var(--basalt); stroke: var(--basalt); }
.flow-node.is-system .node-shape { fill: var(--paper); stroke: var(--basalt); stroke-width: 2; }
.flow-node.is-outside .node-shape { fill: var(--paper); stroke: var(--basalt-40); stroke-dasharray: 2.5 2; }
.key-mark.is-external { border: 2px solid var(--basalt); border-radius: 2px; }

/* Department filter chips. Links, not buttons, so they work with scripting blocked
   and the resulting view can be bookmarked or sent to someone. */
.chips { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; margin: 0 0 0.6rem; }
.chips .field-label { margin: 0 0.4rem 0 0; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.82rem;
  font-weight: 600;
  padding: 0.28rem 0.7rem;
  border: 1px solid var(--basalt-40);
  border-radius: 999px;
  color: var(--basalt);
  text-decoration: none;
  background: var(--paper);
}

.chip:hover { border-color: var(--basalt); background: var(--basalt-05); }
.chip.is-on { background: var(--basalt); border-color: var(--basalt); color: var(--paper); }
.chip.is-on .chip-n { color: var(--paper); opacity: 0.75; }
.chip.is-quiet { color: var(--basalt-40); border-color: var(--basalt-10); }
.chip-n { font-weight: 400; color: var(--basalt-60); font-variant-numeric: tabular-nums; }
.chip.is-clear { border-style: dashed; font-weight: 400; }

/* Saved flows: a named selection you can reopen, rename or drop. */
.saved { border: 1px solid var(--rule); border-left: 3px solid var(--basalt); padding: 0.9rem 1rem; margin-bottom: 1.25rem; background: var(--basalt-05); }
.saved-head { display: flex; align-items: baseline; gap: 0.6rem; margin-bottom: 0.5rem; }
.saved-flow { display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.2rem 0.3rem; border: 1px solid var(--basalt-10); border-radius: 999px; background: var(--paper); }
.saved-rename { display: inline-flex; align-items: center; gap: 0.25rem; }
.rename-input { width: 9rem; padding: 0.18rem 0.4rem; font-size: 0.8rem; }
.saved-new { margin-top: 0.6rem; }
.saved-new input:disabled { background: var(--basalt-05); color: var(--basalt-40); }

/* --------------------------------------------------------------------------
   Restored: these were lost when the map styles were replaced "wholesale" and
   the replacement truncated everything appended after them. The markup kept
   referencing classes that no longer existed, so the access slider rendered as
   a bare checkbox and the name-matching feedback had no colour at all.
   -------------------------------------------------------------------------- */

/* The access switch. A real checkbox, drawn as a slider: keyboard focus, screen
   readers and a scripting-blocked browser all keep working. */
.switch { position: relative; display: inline-block; width: 2.5rem; height: 1.35rem; vertical-align: middle; }

.switch input {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  margin: 0;
  opacity: 0;                 /* invisible, but still the thing being clicked */
  cursor: pointer;
  z-index: 1;
}

.switch-track {
  position: absolute;
  inset: 0;
  border-radius: 1rem;
  background: var(--paper);
  border: 1.5px solid var(--basalt-40);
  transition: background 0.15s, border-color 0.15s;
  pointer-events: none;
}

.switch-track::after {
  content: '';
  position: absolute;
  top: 0.16rem; left: 0.2rem;
  width: 0.9rem; height: 0.9rem;
  border-radius: 50%;
  background: var(--basalt-40);
  transition: transform 0.15s, background 0.15s;
}

.switch input:checked + .switch-track { background: var(--basalt); border-color: var(--basalt); }
.switch input:checked + .switch-track::after { background: var(--paper); transform: translateX(1.05rem); }
.switch input:focus-visible + .switch-track { outline: 3px solid var(--basalt); outline-offset: 2px; }
.switch input:disabled { cursor: not-allowed; }
.switch.is-fixed .switch-track { opacity: 0.45; }

@media (prefers-reduced-motion: reduce) {
  .switch-track, .switch-track::after { transition: none; }
}

/* Bulk actions over a selection. */
.bulk-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--basalt);
  background: var(--basalt-05);
  padding: 0.7rem 0.9rem;
  margin-bottom: 1rem;
  position: sticky;
  top: 0;
  z-index: 5;
}

/* Setting a staff detail on everyone selected. Sits in the bulk bar with the actions,
   because it is the same gesture: tick people, then say what to do. */
.bulk-country {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.bulk-country .field-label { margin: 0; font-size: 0.78rem; }
.bulk-country .input { width: 11rem; }

.bulk-count { font-size: 0.85rem; font-weight: 600; color: var(--basalt-60); }
.row-select, [data-select-all] { width: 1.1rem; height: 1.1rem; accent-color: var(--basalt); margin: 0; cursor: pointer; }

/* Live "is that a colleague?" feedback under the person fields on the work log. */
.match { font-size: 0.82rem; font-weight: 600; margin: 0.35rem 0 0; min-height: 1.2em; display: flex; align-items: center; gap: 0.4rem; }
.match::before { content: ''; width: 0.6rem; height: 0.6rem; border-radius: 50%; flex-shrink: 0; opacity: 0; }
.match.is-found { color: #1e7a45; }
.match.is-found::before { background: #23a05a; opacity: 1; }
.match.is-missing { color: #c0362c; }
.match.is-missing::before { background: #e03b2f; opacity: 1; }

/* Role control in the People table. */
.role-control { margin-top: 0.3rem; }
.role-select { padding: 0.15rem 0.3rem; font-size: 0.78rem; width: auto; min-width: 8rem; }

/* Read-only stand-in for the access switch, shown to a view-only Admin. Deliberately
   not a faded slider: a control that looks interactive and does nothing reads as a
   fault rather than as a permission. */
.switch-static {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.15rem 0.5rem;
  border: 1px dashed var(--basalt-40);
  border-radius: 2px;
  color: var(--basalt-60);
}
.switch-static.is-on { border-style: solid; border-color: var(--basalt); color: var(--basalt); }

/* --------------------------------------------------------------------------
   @mentions on the work log
   -------------------------------------------------------------------------- */

.mention { position: relative; }

.mention-list {
  position: absolute;
  z-index: 40;
  left: 0;
  right: 0;
  top: calc(100% - 1.4rem);
  margin: 0;
  padding: 0.25rem 0;
  list-style: none;
  max-height: 14rem;
  overflow-y: auto;
  background: var(--paper);
  border: 1px solid var(--basalt);
  border-radius: 2px;
  box-shadow: 0 12px 30px rgba(9, 38, 45, 0.2);
}

.mention-option {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.4rem 0.75rem;
  font-size: 0.9rem;
  cursor: pointer;
}

.mention-option.is-active, .mention-option:hover { background: var(--basalt); color: var(--paper); }
.mention-kind { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.09em; opacity: 0.65; }

/* The buttons that make the picker visible.
   The help line beneath them had been the only invitation to use the picker at
   all, and the live data says nobody took it: one system mention across 28
   answers. A row of buttons is a thing you can see without reading. */
.mention-add { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.45rem 0 0; }
.mention-add:empty { display: none; }
.btn-sm { padding: 0.28rem 0.62rem; font-size: 0.82rem; line-height: 1.2; }
.mention-help { font-size: 0.8rem; color: var(--basalt-60); margin: 0.35rem 0 0; }
.mention-chips { font-size: 0.82rem; font-weight: 600; color: var(--basalt); margin: 0.3rem 0 0; min-height: 1.1em; }


/* ==========================================================================
   EE ALIGNMENT LAYER
   ==========================================================================
   Everything above this line is DataFlow's own design system, now drawing its
   colours from the house tokens. This last section is what makes the app look
   like the Employment Equity Tool rather than merely share its palette: the
   furniture — chrome, page ground, panels, controls, buttons, chips, tables —
   restated in EE's shapes.

   WHY A LAYER AND NOT A REWRITE. About 200 of the 327 class names above are
   DataFlow's data visualisations: the sankey ribbons, the company web, the
   work-flow chains, the sunburst, the chevrons. In those, colour and shape
   carry meaning — "cool is ours, warm is not ours, red is personal" — and
   restyling them to match a compliance tool would delete information rather
   than rebrand it. They keep their rules and inherit the new neutrals through
   the token aliases at the top of this file. This layer deliberately does not
   touch them.

   THE THREE HOUSE RULES, inherited from the theme:
     1. Fresh Lime is a FILL, never ink. Matches DataFlow's own highlighter
        rule, stated more strictly.
     2. The chrome is Basalt in both themes and does not invert. Only the
        content column flips. That is why .topbar below takes --rail-* tokens
        and not --text / --surface.
     3. The content column is paper: --bg is the page ground, --surface is
        what panels are made of. DataFlow used to paint the whole body white,
        which left cards with nothing to sit on.

   ONE THING THIS LAYER DOES NOT DO. EE's shell is a Basalt left rail plus a
   Basalt topbar. DataFlow has a horizontal top nav and a large set of
   anonymous single-question pages that no rail would suit, so the build
   item's "closest compatible component" rule applies: the top bar is dressed
   as EE's topbar rather than folded into a rail. If Luke wants the rail
   itself, that is a layout change to render.mjs and a separate item.
   ========================================================================== */

/* ── the page ground ───────────────────────────────────── */
body{background:var(--bg);color:var(--text);font-size:var(--text-base);
  line-height:var(--leading-normal)}

/* EE's heading ink is a touch deeper than body ink. */
h1,h2,h3{color:var(--heading-ink)}
h1{font-size:var(--text-xl);font-weight:600}
h2{font-size:var(--text-lg);font-weight:600}
h3{font-size:var(--text-md);font-weight:600}

/* Links in running text keep their underline — that is EE's rule too. */
a{color:var(--accent-ink)}

/* One focus treatment for the product: a Basalt line doing the contrast work
   with the lime halo behind it. Replaces the 3px hard outline. */
:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px;
  box-shadow:0 0 0 5px var(--focus-halo)}

/* ── chrome: the Basalt band ───────────────────────────── */
/* Rule 2. These take --rail-* rather than --paper/--text because the band must
   stay Basalt when the content column flips to dark. --paper is now
   var(--surface), which is #0c2b33 in dark mode — ink that would have vanished
   against the band it sits on. */
.topbar{background:var(--topbar-bg);color:var(--rail-ink);
  padding:0 var(--space-5);min-height:var(--topbar-h);
  gap:var(--space-5);border-bottom:1px solid var(--rail-line)}

.lockup{color:var(--rail-ink-strong)}
.lockup-mark{font-size:var(--text-md);letter-spacing:normal}
.lockup-bar{background:var(--rail-line)}
.lockup-name{color:var(--rail-ink);opacity:1;font-size:var(--text-sm)}

.affiliates{font-size:var(--text-xs);letter-spacing:.18em;
  color:var(--rail-ink-muted)}
.affiliates li + li::before{color:var(--rail-line)}

.topnav{gap:var(--space-1)}
.topnav a{color:var(--rail-ink);opacity:1;font-size:var(--text-sm);
  font-weight:500;padding:6px var(--space-3);border-bottom:0;
  border-radius:var(--r);
  transition:background var(--fast) var(--ease),color var(--fast) var(--ease)}
.topnav a:hover{background:var(--rail-hover);color:var(--rail-ink-strong)}
/* The current page is marked the way the theme marks an active rail item:
   a filled slot with a lime edge, not lime text. */
.topnav a[aria-current]{background:var(--rail-active);
  color:var(--rail-ink-strong);font-weight:600;
  box-shadow:inset 0 -2px 0 var(--accent)}
/* Inside the Basalt band the focus pair swaps — lime line, Basalt halo. */
.topnav a:focus-visible,.lockup:focus-visible,.who-badge:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;box-shadow:none}

/* The administration tabs borrow .topnav for its layout, but unlike the rail
   they sit on the light page — so they were inheriting --rail-ink, which is
   rgba(255,255,255,.82) because the rail is dark, and rendering white on
   near-white at 1.13:1. Invisible, not merely low contrast.
   Scoped one class deeper than `.topnav a` so the override does not depend on
   which rule happens to come later in the file. Measured on --paper:
   6.5:1 for a resting tab and 14.3:1 for the current one, both past AA. */
/* .topnav sets a tight rail gap later in the file than .admin-tabs sets its
   own, so the rail won. Without the pill padding to separate them the tabs
   ran together, so the gap has to be restated here too. */
.topnav.admin-tabs { gap: 1.75rem; flex-wrap: wrap; }

/* Set as letter-spaced uppercase, the way the theme already sets its stat
   labels. Without the pills, eight body-weight words in a row read as a
   sentence — "Overview People Activity Map Software Names Security Settings" —
   rather than as a set of choices. The case change is what separates them;
   spacing alone does not do it. */
.topnav.admin-tabs a {
  color: var(--text-muted);
  background: none;
  border-radius: 0;
  padding: 0 0 0.4rem;
  box-shadow: none;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-size: 0.78rem;
  font-weight: 600;
}
.topnav.admin-tabs a:hover {
  color: var(--text);
  background: none;
  border-bottom-color: var(--control-line);
}
/* The current tab keeps the theme's marker — a lime edge, not lime text — but
   in page ink rather than rail ink. */
.topnav.admin-tabs a[aria-current] {
  color: var(--text);
  background: none;
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--accent);
}
.topnav.admin-tabs a:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}


/* The account badge is the theme's .avatar: lime fill, Basalt ink. */
.who-badge{background:var(--accent);color:var(--on-accent);
  border:0;border-radius:50%;width:32px;height:32px;
  display:grid;place-items:center;font-size:var(--text-xs);font-weight:700;
  cursor:pointer;list-style:none}
.who-badge::-webkit-details-marker{display:none}
.who-badge::marker{content:""}

.who-panel{background:var(--surface);color:var(--text);border:0;
  border-radius:var(--r-lg);box-shadow:var(--shadow-lg);padding:var(--space-3)}
.who-who{font-size:var(--text-base);font-weight:600;color:var(--heading-ink)}
.who-email{font-size:var(--text-sm);color:var(--text-muted)}
.who-item{font-size:var(--text-sm);border-radius:var(--r-sm);
  padding:6px var(--space-2)}
.who-item:hover{background:var(--accent-soft)}
.who-signout{color:var(--danger)}

.paused-bar{background:var(--warning-soft);color:var(--warning);
  border-bottom:1px solid var(--warning-line);padding:10px var(--space-5);
  font-size:var(--text-sm)}

.foot{background:var(--sidebar-bg);color:var(--rail-ink-muted);
  font-size:var(--text-sm);padding:var(--space-5)}
.foot a{color:var(--rail-ink-strong)}

/* ── the content column ────────────────────────────────── */
/* EE's content column is wider than a reading measure because it carries
   panels and tables, not prose. The survey pages keep a comfortable measure
   for their question text via .field/.hint max-widths further up. */
.shell{max-width:60rem;padding:var(--space-6) var(--space-5) var(--space-8)}
.shell-wide{max-width:var(--content-max)}

.page-head{margin-bottom:var(--space-6)}
.page-head .lead{font-size:var(--text-base);color:var(--text-muted);
  line-height:var(--leading-normal)}
/* The theme's eyebrow: same idea DataFlow already had, at the house values. */
.eyebrow{font-size:var(--text-xs);font-weight:600;letter-spacing:.18em;
  color:var(--text-faint);margin:0 0 var(--space-2)}

/* Section heads. A 2px Basalt slab above every part was the heaviest rule on
   the page and read as a divider between documents rather than sections of
   one. The house uses a hairline and lets the heading do the work. */
.part-head{border-top:1px solid var(--border);padding-top:var(--space-4);
  margin-bottom:var(--space-5)}
.part-number{color:var(--text-faint);font-size:var(--text-sm)}
.part-intro{color:var(--text-muted);line-height:var(--leading-normal)}

/* ── panels and cards ──────────────────────────────────── */
/* The single biggest visual difference. DataFlow drew hairline boxes with 2px
   corners directly on white; EE floats --surface panels with an 18px radius
   and a soft shadow on the --bg ground. */
.card,.panel{background:var(--surface);border:0;border-radius:var(--r-xl);
  box-shadow:var(--shadow);padding:var(--space-5);margin-bottom:var(--space-4)}
.card h3{color:var(--heading-ink);margin-bottom:var(--space-1)}
.card .meta{color:var(--text-muted);font-size:var(--text-sm)}

.stat{background:var(--surface);border:0;border-radius:var(--r-xl);
  box-shadow:var(--shadow);padding:var(--space-4)}
.stat-figure{font-size:var(--text-xl);font-weight:600;
  color:var(--heading-ink);line-height:var(--leading-tight)}
.stat-label{font-size:var(--text-xs);font-weight:600;letter-spacing:.18em;
  text-transform:uppercase;color:var(--text-faint)}

/* ── fields ────────────────────────────────────────────── */
/* The survey's question labels stay full-size sentence case — they are the
   question, not a form label, and shrinking them to an uppercase eyebrow
   would change how the page reads. Everything around them takes the house
   treatment. */
.field{margin-bottom:var(--space-6)}
.field-label{font-size:var(--text-md);font-weight:600;
  color:var(--heading-ink);margin-bottom:var(--space-2)}
.req{font-size:var(--text-xs);font-weight:600;letter-spacing:.18em;
  color:var(--text-faint)}
.hint{font-size:var(--text-sm);color:var(--text-muted);
  line-height:var(--leading-normal)}

.input{font-size:var(--text-base);padding:10px 13px;border-radius:var(--r);
  background:var(--surface);color:var(--text);
  border:1px solid var(--control-line);
  transition:border-color var(--fast) var(--ease),
    box-shadow var(--fast) var(--ease)}
.input::placeholder{color:var(--text-faint)}
.input:hover{border-color:var(--accent-ink)}
.input:focus{outline:none;border-color:var(--accent-ink);
  box-shadow:0 0 0 5px var(--focus-halo)}
.input:disabled{background:var(--surface-2);color:var(--text-faint);
  border-style:solid}

/* The emphasised field keeps its keyline, in the house tint. */
.field-emphasis{background:var(--surface-2);border-left:3px solid var(--accent);
  border-radius:0 var(--r-lg) var(--r-lg) 0;padding:var(--space-5)}

/* ── buttons ───────────────────────────────────────────── */
/* DataFlow's note above says "basalt, never lime — lime is the highlighter".
   The theme resolves that differently and it is worth being explicit rather
   than leaving two rules in the same codebase contradicting each other: the
   objection to lime is lime as INK, which is unreadable. Lime as a FILL under
   Basalt ink is 14.9:1 and is the house primary action. So the primary button
   is lime here, and the highlighter budget above is untouched. */
.btn{font-size:var(--text-base);font-weight:600;
  background:var(--accent);color:var(--on-accent);
  border:1px solid var(--on-accent);border-radius:var(--r);
  padding:9px var(--space-5);box-shadow:var(--shadow-sm);
  transition:background var(--fast) var(--ease),
    border-color var(--fast) var(--ease),box-shadow var(--fast) var(--ease)}
.btn:hover{background:var(--accent-hover);color:var(--on-accent)}
.btn:focus-visible{outline:none;
  box-shadow:var(--shadow-sm),0 0 0 5px var(--focus-halo)}

.btn-ghost{background:transparent;color:var(--accent-ink);
  border-color:var(--control-line);box-shadow:none}
.btn-ghost:hover{background:var(--accent-soft);border-color:var(--accent-ink);
  color:var(--accent-ink)}

.btn-sm,.btn-outline-sm,.btn-danger-sm{font-size:var(--text-sm);
  font-weight:600;padding:6px var(--space-3);border-radius:var(--r);
  border:1px solid var(--control-line);background:transparent;
  color:var(--accent-ink);cursor:pointer;text-decoration:none;
  display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--fast) var(--ease),
    border-color var(--fast) var(--ease)}
.btn-outline-sm:hover,.btn-sm:hover{background:var(--accent-soft);
  border-color:var(--accent-ink)}
.btn-danger-sm{color:var(--danger);border-color:var(--danger-line)}
.btn-danger-sm:hover{background:var(--danger-soft)}

.actions{border-top:1px solid var(--border);padding-top:var(--space-5);
  margin-top:var(--space-6);gap:var(--space-3)}
.actions .note{color:var(--text-muted);font-size:var(--text-sm)}

/* ── flashes ───────────────────────────────────────────── */
/* The theme's ink / soft / line triplets. The old flash was one Basalt box for
   every kind of news, so a refusal and a confirmation looked identical.
   Two kinds are actually emitted, flash('notice') and flash('error'), plus a
   bare .flash used as a status line. Notice keeps the neutral informational
   tone rather than success green: several of them report a restriction ("your
   account can only...") and dressing that as a success would misread it.
   .flash-notice is spelled out rather than left to fall through to the base
   rule, so the class the code emits has a rule of its own. */
.flash,.flash-notice{border:1px solid var(--info-line);border-left-width:1px;
  background:var(--info-soft);color:var(--info);
  border-radius:var(--r);padding:10px 14px;font-size:var(--text-sm);
  margin-bottom:var(--space-5)}
.flash-error{background:var(--danger-soft);color:var(--danger);
  border-color:var(--danger-line);font-weight:400}

/* ── tags and chips ────────────────────────────────────── */
.tag,.chip{font-size:var(--text-xs);font-weight:600;letter-spacing:.06em;
  padding:2px 9px;border-radius:var(--r-pill);
  background:var(--draft-soft);color:var(--draft);
  border:1px solid var(--draft-line)}
.tag-notsure{background:var(--warning-soft);color:var(--warning);
  border-color:var(--warning-line)}
.tag-empty{background:transparent;color:var(--text-faint);
  border-style:dashed;border-color:var(--control-line)}
.tag-on{background:var(--success-soft);color:var(--success);
  border-color:var(--success-line)}
.tag-off{background:transparent;color:var(--text-faint);
  border-color:var(--control-line)}

/* ── tables ────────────────────────────────────────────── */
/* DataFlow's admin tables are plain <table>s inside .scroll-x wrappers. They
   take the theme's data-table treatment: uppercase tracked header row,
   hairline rows, a quiet hover, tabular numerals. */
/* .scroll-x is a bare overflow wrapper used 30 times, mostly around charts and
   SVGs rather than tables, so the panel treatment is scoped to the two cases
   that want it — a wrapper whose child is a table, and the row list. Painting
   every .scroll-x would have put an 18px radius and 24px of padding around
   full-bleed diagrams that are drawn to their own edges. */
.scroll-x:has(> table),.scroll-x.list-rows{background:var(--surface);
  border-radius:var(--r-xl);box-shadow:var(--shadow);
  padding:var(--space-2) var(--space-5)}

table{width:100%;border-collapse:collapse;font-size:var(--text-sm)}
th{text-align:left;padding:12px 12px 12px 0;
  font-size:var(--text-xs);font-weight:600;letter-spacing:.18em;
  text-transform:uppercase;color:var(--text-faint);
  border-bottom:1px solid var(--border)}
td{padding:11px 12px 11px 0;border-bottom:1px solid var(--border);
  vertical-align:middle}
tr:last-child td{border-bottom:0}
tbody tr{transition:background var(--fast) var(--ease)}
tbody tr:hover{background:var(--surface-2)}
.num{font-variant-numeric:tabular-nums;font-weight:600}

/* ── the row list ──────────────────────────────────────── */
/* One anchor per row, laid out on a grid — that structure is DataFlow's and is
   left alone. Only the surface treatment changes. */
.list-rows{border-top:0}
.list-head{font-size:var(--text-xs);font-weight:600;letter-spacing:.18em;
  color:var(--text-faint);border-bottom:1px solid var(--border)}
.list-row{border-bottom:1px solid var(--border);color:var(--text);
  transition:background var(--fast) var(--ease)}
.list-row:last-child{border-bottom:0}
.list-row:hover{background:var(--surface-2)}
.list-row:focus-visible{outline:2px solid var(--focus-ring);outline-offset:-2px;
  background:var(--surface-2);box-shadow:none}
.list-title{color:var(--heading-ink);font-weight:600}

/* ── the gate ──────────────────────────────────────────── */
/* The one page an anonymous visitor sees takes EE's auth treatment: a Basalt
   field with one radial lift, and a single paper card floating on it. */
.gate{background:var(--surface);border:0;border-radius:var(--r-xl);
  box-shadow:var(--shadow-lg);padding:var(--space-6);
  max-width:404px;margin-inline:auto}

/* ── motion ────────────────────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  .topnav a,.list-row,.btn,.input,.scroll-x tbody tr{transition:none}
}

/* ── the brain map ─────────────────────────────────────── */
/* One picture of everything DataFlow knows, drawn by lib/pages/brain.mjs.
   It reuses .web-node, .web-link, .web-hit, .web-label and the whole tracing
   layer above, so the rules here are only the three things the other charts
   have no idea about: four kinds of node rather than seven kinds of endpoint,
   a line whose DASH says how well we know it, and a node that is visibly
   missing something.

   THE DASH IS LEAD, NOT DECORATION. It is the one visual property carrying
   "how much should I trust this", and it is a dash rather than a colour on
   purpose: the colour channel is already spoken for by what kind of thing a
   node is, and stacking a second meaning on it would make both unreadable.
   Solid is recorded, dashed is somebody's own account, dotted is joined up
   from two entries. */

/* A grid item's automatic minimum size is its content, and an <svg> with a
   viewBox and height:auto reports that as its intrinsic width -- 1180px here.
   So `width: 100%` loses to a min-width nobody wrote, the track is blown out
   past its column, and the right-hand third of the map is cut off by the
   wrap's own overflow:hidden. It is invisible on a wide screen and takes half
   the picture on a phone.

   Fixed on .bm-wrap only, deliberately. The shared .web-svg rule is five other
   charts as well; correcting all of them would change how pages this work was
   not asked to touch are laid out, and that is a separate decision from
   drawing a new map correctly. */
.bm-wrap .web-svg { min-width: 0; }

.bm-wrap .bm-link { fill: none; stroke: var(--basalt-40); opacity: 0.55; }
.bm-edge.is-recorded .bm-link { stroke-dasharray: none; opacity: 0.7; }
.bm-edge.is-reported .bm-link { stroke-dasharray: 7 4; }
.bm-edge.is-inferred .bm-link { stroke-dasharray: 1.5 4.5; stroke-linecap: round; }
.bm-wrap .bm-hit { fill: none; stroke: transparent; stroke-width: 14; cursor: pointer; }
.bm-wrap .bm-hit:focus { outline: none; }

/* An accountability line is the one relationship a reader should be able to
   find without hovering anything, because "who do I ask" is the first question
   asked of every box on every map anybody has ever drawn. */
.bm-edge.is-owns .bm-link { stroke: #1d4d57; opacity: 0.85; }
.bm-edge.is-flows-to .bm-link { stroke: #a86a2f; }

.bm-node.is-dept   .bm-shape { fill: #2f5560; }
.bm-node.is-person .bm-shape { fill: var(--basalt); }
.bm-node.is-system .bm-shape { fill: #a86a2f; }
.bm-node.is-data   .bm-shape { fill: #6b4a7a; }

/* Missing something. A dashed outline rather than a colour, for the same
   reason the lines are dashed: "incomplete" is a different axis from "what
   kind of thing is this", and it has to stay legible on all four fills. */
.bm-node.has-gap .bm-shape { stroke: var(--warning); stroke-width: 2.5; stroke-dasharray: 3 2.5; }
.bm-node.is-focus .bm-shape,
.bm-node.is-centre .bm-shape { stroke: var(--lime); stroke-width: 4; stroke-dasharray: none; }
.bm-node.is-hit .bm-shape { stroke: var(--info); stroke-width: 3.5; stroke-dasharray: none; }
.bm-node.is-centre .bm-label { font-weight: 700; font-size: 13px; opacity: 1; }
.bm-wrap:not(.is-near) .bm-node:not(.is-centre):not(.is-focus):not(.is-hit) .bm-label {
  opacity: 0.42;
}

/* ── the map's own controls ── */

.bm-bar { align-items: center; gap: 8px; flex-wrap: wrap; }
.btn-outline-sm.is-on { background: var(--basalt); color: var(--paper); border-color: var(--basalt); }

.bm-search {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 var(--space-3);
}
.bm-search .input { flex: 1 1 240px; min-width: 0; max-width: 420px; }
.bm-found { margin: 0 0 var(--space-3); }

.bm-chips { flex-wrap: wrap; gap: 6px; }
.bm-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid var(--control-line);
  background: var(--surface); color: var(--text);
  font-size: 0.84rem; font-weight: 600; text-decoration: none;
}
.bm-chip:hover, .bm-chip:focus-visible { border-color: var(--basalt); }
.bm-chip.is-on { background: var(--basalt); border-color: var(--basalt); color: #fff; }
.bm-chip-n { font-weight: 500; opacity: 0.7; font-variant-numeric: tabular-nums; }

/* The trail. Where somebody has been, so going three steps into the estate and
   wanting to come back two is a click rather than a reconstruction. It is in
   the URL, so it survives a reload and can be pasted to somebody else. */
.bm-trail {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  margin: 0 0 var(--space-3); font-size: 0.86rem;
}
.bm-crumb {
  padding: 3px 9px; border-radius: var(--r);
  background: var(--surface-2); color: var(--text-muted); text-decoration: none;
}
.bm-crumb:hover, .bm-crumb:focus-visible { background: var(--surface-3); color: var(--text); }
.bm-crumb.is-here { background: var(--basalt); color: #fff; font-weight: 600; }
.bm-crumb-sep { color: var(--text-faint); }

.bm-legend {
  display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-6);
  margin: var(--space-3) 0; padding: var(--space-3);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-lg);
}
.bm-legend-group { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; }
.bm-key { display: inline-flex; align-items: center; gap: 6px; font-size: 0.82rem; color: var(--text-muted); }
.bm-key-mark { width: 13px; height: 13px; display: inline-block; flex: 0 0 auto; }
.bm-key-dept { background: #2f5560; border-radius: 7px; height: 9px; }
.bm-key-person { background: var(--basalt); border-radius: 50%; }
.bm-key-system { background: #a86a2f; border-radius: 2px; }
.bm-key-data { background: #6b4a7a; transform: rotate(45deg); }
.bm-key-gap { background: transparent; border: 2.5px dashed var(--warning); border-radius: 50%; }
.bm-key-line { width: 26px; height: 0; flex: 0 0 auto; border-top: 2px solid var(--basalt-40); }
.bm-key-reported { border-top-style: dashed; }
.bm-key-inferred { border-top-style: dotted; border-top-width: 3px; }

/* What the map cannot tell you. On the page, not only in a tooltip: a reader
   looking for what to fix next should not have to hover a hundred nodes. */
.bm-gaps, .bm-list { margin: var(--space-3) 0; }
.bm-gaps > summary, .bm-list > summary {
  cursor: pointer; font-weight: 600; color: var(--heading-ink); padding: 6px 0;
}
.bm-gap-list { list-style: none; margin: var(--space-3) 0 0; padding: 0; }
.bm-gap-list li {
  display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline;
  padding: 6px 0; border-bottom: 1px solid var(--border);
}
.bm-gap-kind { font-size: 0.78rem; color: var(--text-faint); }
.bm-gap-why { font-size: 0.82rem; color: var(--warning); flex: 1 1 240px; }

@media (max-width: 720px) {
  /* The readout goes under the picture rather than beside it. On a 375px
     screen the shared rule gives the chart `minmax(0, 1fr)` next to a fixed
     300px panel, which leaves the map about nine pixels wide.

     Stacking needs THREE declarations, not one, and the missing two cost an
     afternoon: .web-svg and .web-readout are pinned to grid-column 1 and 2 by
     the shared rules, so a single-column template does not stack them -- the
     panel's `grid-column: 2` quietly creates an implicit second column and the
     whole wrap overflows the phone exactly as before. The tracks and the
     placement have to be undone together. */
  .bm-wrap[data-chart] { grid-template-columns: minmax(0, 1fr); }
  .bm-wrap .web-svg,
  .bm-wrap .web-readout { grid-column: 1; }
  .bm-wrap .web-readout {
    border-left: 0;
    border-top: 1px solid var(--rule);
    padding-top: 18px;
  }
  /* The tool strip is absolutely positioned over the top-left of the chart;
     on a narrow screen its hint runs under the buttons. */
  .bm-wrap .web-hint { display: none; }
  .bm-legend { gap: var(--space-3); }
}


/* ---------------------------------------------------------------------------
   Software and subscriptions
   The AI cards are their own shape because the question is "who is on this?",
   which is a list per product, not another column in a table. */
.pill-ai{background:#0f3b34;color:#cbff02}
.pill-warn{background:#5a3a12;color:#ffd88a}
.ai-grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fill,minmax(19rem,1fr))}
.ai-card{border:1px solid var(--line,#2a3b3f);border-radius:10px;padding:1rem}
.ai-card h3{margin:0 0 .25rem}
.ai-lines{list-style:none;margin:.6rem 0 0;padding:0;display:flex;
  flex-direction:column;gap:.45rem}
.ai-lines li{display:grid;grid-template-columns:1fr auto;gap:.25rem .75rem;
  align-items:baseline;font-size:.875rem;
  border-top:1px solid var(--line,#2a3b3f);padding-top:.45rem}
.ai-lines li:first-child{border-top:0;padding-top:0}
.ai-desc{min-width:0;overflow-wrap:anywhere}
.ai-price{font-variant-numeric:tabular-nums;white-space:nowrap}
.ai-lines .muted{grid-column:1/-1;font-size:.8125rem}


/* ---------------------------------------------------------------------------
   Galaxy map. The stage is a two-column grid so the reading panel sits beside
   the canvas rather than under it -- the point of clicking a star is to read
   it without losing your place on the map. */
.galaxy-panel{padding-bottom:1rem}
.galaxy-bar{display:flex;gap:1rem;align-items:center;flex-wrap:wrap;
  margin-bottom:.75rem}
.galaxy-bar .muted{flex:1 1 16rem;min-width:0}
.galaxy-stage{display:grid;grid-template-columns:minmax(0,1fr) 19rem;gap:1rem;
  align-items:stretch}
.galaxy-stage canvas{width:100%;height:min(72vh,720px);display:block;
  border-radius:10px;background:radial-gradient(circle at 50% 45%,
    #0d2b30 0%, #071a1e 55%, #040f12 100%);cursor:grab;touch-action:none}
.galaxy-detail{border:1px solid var(--line,#2a3b3f);border-radius:10px;
  padding:.9rem;overflow:auto;max-height:min(72vh,720px);font-size:.875rem}
.galaxy-detail h3{margin:0 0 .25rem}
.galaxy-links{list-style:none;margin:.5rem 0 0;padding:0;display:flex;
  flex-direction:column;gap:.3rem}
.galaxy-links li{border-top:1px solid var(--line,#2a3b3f);padding-top:.3rem}
.galaxy-gap{margin-top:.7rem;color:#ffd88a}
@media (max-width:900px){
  .galaxy-stage{grid-template-columns:1fr}
  .galaxy-detail{max-height:none}
}
@media (prefers-reduced-motion:reduce){
  .galaxy-stage canvas{cursor:default}
}

/* A panel for money the totals could NOT include. It is deliberately styled as
   a warning rather than a footnote: an understated total that looks complete is
   the failure mode this page exists to avoid, so the gap has to carry as much
   weight on the screen as the figure it qualifies. */
.callout{background:var(--surface-2);border-left:3px solid #d08b00;
  border-radius:var(--r);padding:var(--space-4) var(--space-5);
  margin:var(--space-5) 0}
.callout h3{margin:0 0 .4rem;font-size:var(--text-sm);letter-spacing:.02em;
  text-transform:none;color:var(--text)}
.callout p{margin:.35rem 0}
.callout ul{margin:.5rem 0 .35rem;padding-left:1.1rem}
.callout li{margin:.2rem 0;font-variant-numeric:tabular-nums}

/* A row reference back into the workbook. Small and quiet, because it is there
   to be checked rather than read — but present on every figure, so no number on
   this page has to be taken on trust. */
.src{font-size:var(--text-xs);font-variant-numeric:tabular-nums;
  color:var(--text-faint);white-space:nowrap}
