/*
 * What this slice needed and the prototype did not have.
 *
 * Loaded after `styles.css`, which is the copied design system. Everything here is either a small
 * adaptation of the prototype's chrome to a header-led layout, or a treatment for something the
 * prototype never had to show: a proposal, a refusal, a confirmation, an action class.
 *
 * The standing treatments are the part that matters. HUMAN_AI_INTERFACE section 8 forbids blurring
 * a recorded fact, a human decision, an AI inference and a proposal into one look, so each has its
 * own border, its own tint and its own badge, and none of them is only a colour — the colour is
 * always carried by a word as well, because a reader who cannot distinguish teal from amber is
 * still entitled to know whether the thing in front of them has happened.
 */

/* ---------------------------------------------------------------- chrome */

:root {
  --app-header-height: 74px;
}

.app-shell {
  display: block;
  min-height: 100vh;
  padding-top: var(--app-header-height);
}

/* Three groups: what this build has on the left, the five primary contexts centred, the utility
   controls on the right. The centre track is `auto` between two equal `1fr` tracks so the circular
   group is centred over the workspace whatever the groups either side of it weigh — FR-PO-09 asks
   for centred, and a flex row would put it wherever the wordmark left it.

   The tracks are declared here rather than inherited from `styles.css`'s `.app-header`, which is
   the prototype's own three-column grid for a header with different children. Same intent, our
   own rule, per AGENTS.md. */
.app-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 35;
  height: var(--app-header-height);
  padding: 0 26px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 24px;
  background: rgba(244, 243, 238, 0.94);
  backdrop-filter: blur(12px);
  pointer-events: auto;
}

.header-lead {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 22px;
}

.app-header .brand {
  padding: 0;
  display: flex;
  flex-direction: column;
  /* `styles.css`'s `.brand` centres its row; this one is a column, and a centred column would
     float the mark over the middle of the descriptor beneath it. */
  align-items: flex-start;
  gap: 1px;
  color: var(--ink-strong);
  text-decoration: none;
}

/* The wordmark is the prototype's logo image rather than the word "Continuum". The image carries
   the accessible name in its `alt`; see `Page.brandMarkSource` for why it is there and not on the
   anchor. The descriptor beneath it is unchanged, and is still hidden below 1546px by the rule
   further down — the measured threshold is the descriptor's width, which this does not change.

   Sized here rather than by `styles.css`'s `.brand-mark`, which is the prototype's 44px sidebar
   mark; this header is 74px tall and also carries the descriptor beneath it.

   The drop-shadow is the prototype's own (`styles.css`'s `.app-header .brand-mark`) and is wanted:
   its header logo carries it. It is restated rather than inherited because inheriting it would
   make this header's appearance depend on a prototype structural class — tidy that sheet and our
   header would change silently. The value is the one that rule renders today; a change to it there
   is now a deliberate change here. */
.app-header .brand .brand-mark {
  width: 34px;
  height: 34px;
  display: block;
  object-fit: contain;
  filter: drop-shadow(0 5px 7px rgba(42, 36, 29, 0.11));
}

.app-header .brand small {
  color: var(--muted);
  font-size: 11px;
}

/* The screens this build has that PROTOTYPE_SPEC's navigation has no position for. Plain text
   links, deliberately quieter than the circular controls beside them, and on their own class
   rather than `.nav-item` so the prototype's circular treatment never reaches them. */
.build-nav {
  min-width: 0;
  display: flex;
  gap: 2px;
}

.build-nav-item {
  padding: 6px 10px;
  border-radius: 9px;
  color: var(--muted);
  text-decoration: none;
  font-size: 12px;
  white-space: nowrap;
}

.build-nav-item:hover {
  background: rgba(13, 36, 52, 0.05);
  color: var(--ink);
}

.build-nav-item.is-active {
  background: var(--teal-soft);
  color: var(--teal-dark);
}

/* FR-PO-09 through FR-PO-11: five circular primary contexts centred, four smaller utility controls
   at the right. `styles.css` already draws both from the prototype; these rules place the groups in
   our own header and say what an unbuilt one looks like. */
.primary-context-nav {
  justify-self: center;
}

.utility-context-nav {
  justify-self: end;
  padding-top: 0;
}

.app-header .context-nav-item {
  width: 44px;
  height: 44px;
}

/* The circular controls that exist are anchors, so each drew the browser's default underline
   beneath its glyph while the not-built ones — plain `span`s — drew none. That asymmetry read as
   a line under the built icons rather than as a link, so the underline goes. `.brand` and
   `.build-nav-item` above already reset it for the same reason; this is the third of the same
   rule, scoped to the header controls rather than to `a`, because the underlines elsewhere in
   this stylesheet are deliberate. */
.app-header .nav-item {
  text-decoration: none;
}

/* Every circular control is named exactly once, by the visually hidden caption inside it — there is
   no `aria-label`, deliberately, so a reader, a screen reader and a test all agree about the name.
   `styles.css` hides that caption outright (`.nav-item > span:not(.nav-icon)`, which at (0,2,1)
   beats `.sr-only`), and the only other child is the `aria-hidden` glyph, so the control would be
   left with no accessible name at all and the tooltip pseudo-element would be standing in for one
   by accident. The technique is restated here at a weight that wins inside our header; it stays as
   invisible as `.sr-only` intends. */
.app-header .nav-item > .sr-only {
  display: block;
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Restoring that caption is only half of naming the control once. `styles.css` draws the hover
   tooltip as `.nav-item::after { content: attr(data-label) }` held at `opacity: 0`, and opacity
   hides a thing from the eye and not from the accessibility tree — so name-from-content
   concatenates the two and Brands announces as "Brands Brands", an unbuilt one as
   "Focus · not built Focus — not built yet".

   The `/ ''` is the generated content's alt text: it empties the pseudo-element's accessible name
   while the tooltip draws exactly as the prototype draws it. That is why the tooltip is overridden
   rather than removed — it is the prototype's own affordance and this is not the place to take it
   away.

   Where the alt-text syntax is unsupported (Chrome before 77, Safari before 17.4, Firefox before
   133) the whole declaration is invalid and dropped, so the cascade falls back to `styles.css`'s
   plain `content: attr(data-label)`: the tooltip still draws and the name is merely doubled again.
   That is the state this rule improves on and it is still better than a control with no name from
   content at all, so nobody is left worse off. Deleting this rule as redundant is exactly how the
   doubling comes back. */
.app-header .nav-item::after {
  content: attr(data-label) / '';
}

/* Three of the nine controls name something that does not exist yet. They keep their specified
   position and are visibly not available: dashed edge, no shadow, dimmed, and not a link at all —
   so there is nothing to click, nothing to focus and nothing that hover promises. */
.app-header .nav-item.is-not-built {
  border-style: dashed;
  border-color: rgba(160, 148, 132, 0.55);
  background: transparent;
  box-shadow: none;
  color: rgba(140, 129, 116, 0.62);
  cursor: default;
}

.app-header .nav-item.is-not-built:hover {
  transform: none;
  border-color: rgba(160, 148, 132, 0.55);
  background: transparent;
  color: rgba(140, 129, 116, 0.62);
}

/* The header carries three groups and the middle one must stay centred, so the side tracks are
   equal. That only works while the left group fits its track: past that it would slide under the
   circular controls, which is exactly what it did at 1280. The subtitle goes first, and below the
   width where even that is not enough the header stops centring and simply spaces the three groups
   out — a centred group that overlaps its neighbour is worse than one a few pixels off centre.

   1546 is measured, not chosen. The wordmark descriptor "governed consumer content and its
   lineage" is wide enough that the left group overruns the centred circles well above the 1400
   this rule used to carry: "Provenance" was measured over the first circle by 46px at 1401, 34px
   at 1440, 11px at 1512 and 0.28px at 1546, and first clear at 1547. So the subtitle is hidden up
   to one pixel below that. Do not round it to 1500 or 1600 because it reads more tidily; the
   number is the measurement, and a tidier one either leaves the collision or hides the subtitle
   from people who could have had it. A shorter descriptor is not the alternative — the previous
   wording still overlapped at 1401 and 1440, so it only makes the collision small enough to miss.

   This is deliberately a symptom fix, and only for today's descriptor string. The real fault is
   structural and is not addressed here: the primary nav is centred over the workspace while the
   left group beside it is variable-width, so a left group that grows can overrun it. Any future
   copy change to the wordmark or its subtitle can widen that group again and re-trigger exactly
   this collision — at which point the threshold has to be re-measured the way the numbers above
   were, not guessed. */
@media (max-width: 1546px) {
  .app-header {
    gap: 14px;
  }

  .app-header .brand small {
    display: none;
  }

  .build-nav-item {
    padding: 6px 8px;
  }
}

@media (max-width: 1150px) {
  .app-header {
    grid-template-columns: auto auto auto;
    justify-content: space-between;
  }

  .header-lead {
    gap: 12px;
  }

  .build-nav {
    overflow-x: auto;
  }
}

.workspace-main {
  max-width: 1460px;
  margin: 0 auto;
  padding: 30px 32px 130px;
}

.bottom-dock {
  left: 0;
  height: auto;
  min-height: 62px;
  padding: 10px 26px;
  gap: 24px;
  align-items: center;
}

.signed-in-principal {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.principal-summary {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  text-align: right;
  color: var(--muted);
  font-size: 11px;
}

.principal-summary strong {
  color: var(--ink-strong);
  font-size: 12px;
}

/* A session the API could not identify is a dead end for every consequential action, so it is
   marked as a refusal rather than left looking like a slow answer. */
.principal-unidentified {
  padding: 5px 9px;
  border-radius: var(--radius-sm);
  background: var(--red-soft);
}

.principal-unidentified strong,
.principal-unidentified small {
  color: var(--red);
}

/* --------------------------------------- three vocabularies, one badge and one panel

   `.pill-badge` and `.tinted-panel` are shapes and nothing else. What a badge *means* comes from
   the vocabulary class beside it, and there are three of them, each with its own section below:

     `.standing-*`    what kind of claim this is — HUMAN_AI_INTERFACE section 8's trust contract
     `.lifecycle-*`   what became of a piece of work — open, completed, abandoned, superseded
     `.entry-kind-*`  what a thread entry is — evidence, a plan, a record of activity

   They share the shape because a reader recognises a badge as a badge. They share nothing else, and
   they must not: a thread's lifecycle drawn in the standing vocabulary is what badged six shipped
   threads WITHDRAWN, and each vocabulary sets its own ink, tint and edge for that reason.

   **The marker says which vocabulary; the colour says which value within it.** `.pill-badge::before`
   draws a different silhouette for each of the three — a dot for a standing, a bar for a lifecycle,
   an arrow for an entry kind — and no vocabulary may draw another's. That division is the load
   bearing half: colour alone is not a distinction every reader has, so three vocabularies telling
   themselves apart by hue would be the same blur one layer down, which is how a purple SUPERSEDED
   pill came to sit beside a purple AI PROPOSAL pill drawn identically.

   Standing's own markers stay exactly as they are: a proposal's rotated square, an agent's square
   and an open decision's hollow dot are section 8 distinctions *within* the trust contract, and the
   two new vocabularies were given silhouettes of their own rather than any of standing's flattened
   away. A new value inside standing varies the dot for the same reason — never by borrowing the bar
   or the arrow another vocabulary already answers a different question with.

   `scripts/check-vocabularies.mjs` reads this file and fails the build if two vocabularies ever draw
   the same marker, if two values in one vocabulary take the same ink, or if any two badges anywhere
   resolve to the same treatment. It also holds this file and the three Elm modules to the same list
   of classes, so a value can neither lose its treatment nor keep one nothing renders. */

/* ------------------------------------------------- standing: the trust contract */

.standing {
  --pill-ink: var(--muted);
  --pill-tint: var(--surface-soft);
  --pill-edge: var(--line-strong);
}

.standing-fact {
  --pill-ink: #3d6578;
  --pill-tint: var(--blue-soft);
  --pill-edge: #b6cdd8;
}

.standing-proposal {
  --pill-ink: var(--amber);
  --pill-tint: var(--amber-soft);
  --pill-edge: #e3c48c;
}

.standing-agent {
  --pill-ink: var(--purple);
  --pill-tint: var(--purple-soft);
  --pill-edge: #c6bade;
}

/* Not a proposal in either flavour, and it must not look like one: nothing is on the table, so a
   reader has to be able to tell at a glance that this one wants an answer rather than an approval.
   It takes neither the amber a proposal wears nor the purple an agent's does. */
.standing-open-decision {
  --pill-ink: #8a4a6b;
  --pill-tint: #f8ecf2;
  --pill-edge: #ddbdcd;
}

.standing-decision {
  --pill-ink: var(--teal-dark);
  --pill-tint: var(--teal-soft);
  --pill-edge: #9ecbba;
}

.standing-withdrawn {
  --pill-ink: var(--subtle);
  --pill-tint: #f0f0ec;
  --pill-edge: var(--line-strong);
}

.standing-refused {
  --pill-ink: var(--red);
  --pill-tint: var(--red-soft);
  --pill-edge: #e0b1ab;
}

.pill-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border: 1px solid var(--pill-edge);
  border-radius: 999px;
  background: var(--pill-tint);
  color: var(--pill-ink);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  white-space: nowrap;
}

.pill-badge::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

/* A standing's marker is a dot, and the three variations below are distinctions *inside* the trust
   contract — section 8's own, and not to be traded away to tell one vocabulary from another. */

/* A proposal is not a fact, so it does not get a fact's flat edge. */
.standing-proposal.pill-badge::before {
  border-radius: 1px;
  transform: rotate(45deg);
}

.standing-agent.pill-badge::before {
  border-radius: 1px;
}

/* Both proposals are filled marks — something is there, on the table. An open decision is the case
   where nothing is, so its mark is the same dot left hollow: the answer is the part that is missing,
   and a reader who cannot separate this hue from a proposal's still meets a different shape. It is
   still a dot, so it is still a standing; the outline distinguishes a value inside the trust
   contract, exactly as the rotated square and the square above do. */
.standing-open-decision.pill-badge::before {
  background: transparent;
  border: 1px solid currentColor;
}

.standing-note {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.standing-note small {
  color: var(--muted);
  font-size: 11px;
}

.tinted-panel {
  border-left: 4px solid var(--pill-edge);
  background: linear-gradient(90deg, var(--pill-tint) 0%, var(--surface) 42%);
}

.tinted-panel.standing-proposal {
  border-style: dashed;
  border-left-style: solid;
}

/* --------------------------------------------- lifecycle: what became of the work

   A thread's own vocabulary, and not a standing. Completed work reads as an arrival, abandoned work
   reads as a stop, superseded work reads as a hand-off, and a thread closed before this record could
   say which reads as the plain fact that it is closed. None of them borrows the withdrawn treatment,
   which is what "WITHDRAWN" on six shipped threads looked like.

   Every one of them draws the same marker — a bar, a length of work rather than a point of claim —
   because the marker is what says *lifecycle* rather than *standing*, and a lifecycle that borrowed
   a standing's dot would be telling the two apart by hue alone. Colour is left to do the job it can
   do here, which is to separate the five values from each other. */

.lifecycle {
  --pill-ink: var(--muted);
  --pill-tint: var(--surface-soft);
  --pill-edge: var(--line-strong);
}

.lifecycle-open {
  --pill-ink: var(--teal-dark);
  --pill-tint: var(--teal-soft);
  --pill-edge: #9ecbba;
}

.lifecycle-completed {
  --pill-ink: #2f6b4f;
  --pill-tint: #dff0e5;
  --pill-edge: #a5cdb4;
}

.lifecycle-abandoned {
  --pill-ink: var(--amber);
  --pill-tint: var(--amber-soft);
  --pill-edge: #e3c48c;
}

.lifecycle-superseded {
  --pill-ink: var(--purple);
  --pill-tint: var(--purple-soft);
  --pill-edge: #c6bade;
}

.lifecycle-unrecorded {
  --pill-ink: var(--subtle);
  --pill-tint: var(--surface-soft);
  --pill-edge: var(--line-strong);
}

/* The lifecycle marker, drawn once for the whole vocabulary. No standing draws a bar. */
.lifecycle.pill-badge::before {
  width: 12px;
  height: 5px;
  border-radius: 999px;
}

/* Nobody said how this ended, so the marker is an outline rather than a filled mark. It is the same
   bar: an absent ending is still a lifecycle, and saying so in another vocabulary's shape would be
   the borrowing this whole section exists to stop. */
.lifecycle-unrecorded.pill-badge::before {
  background: transparent;
  border: 1px solid currentColor;
}

/* ------------------------------------------------ entry kind: what an entry is

   Evidence, a plan, or a record of activity — section 4's own list. Nothing here says anything about
   who wrote the entry: that is stated in words on the same card, and deriving this badge from the
   author's actor type is what put "AI proposal" beside a chip reading "Evidence".

   Its marker is an arrow, which neither of the other two draws, and `plan` takes an ink of its own
   rather than the purple a superseded thread wears: the thread's own state sits at the top of the
   same page as its entries, so two new vocabularies agreeing on a colour there is precisely the
   confusion this slice was written to remove. */

.entry-kind {
  --pill-ink: var(--muted);
  --pill-tint: var(--surface-soft);
  --pill-edge: var(--line-strong);
}

.entry-kind-evidence {
  --pill-ink: #3d6578;
  --pill-tint: var(--blue-soft);
  --pill-edge: #b6cdd8;
}

.entry-kind-plan {
  --pill-ink: #4a5f8a;
  --pill-tint: #eaeef8;
  --pill-edge: #bcc6e0;
}

.entry-kind-activity {
  --pill-ink: var(--subtle);
  --pill-tint: var(--surface-soft);
  --pill-edge: var(--line-strong);
}

/* The entry-kind marker, drawn once for the whole vocabulary: an entry points at the next thing in
   the narrative, and neither a standing nor a lifecycle draws an arrow. */
.entry-kind.pill-badge::before {
  width: 0;
  height: 0;
  background: transparent;
  border-radius: 0;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  border-left: 7px solid currentColor;
}

/* ------------------------------------------------------------ action classes */

.action-class {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 8px;
  border-radius: 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.action-class-safe {
  background: var(--teal-soft);
  color: var(--teal-dark);
}

.action-class-reversible {
  background: var(--amber-soft);
  color: var(--amber);
}

.action-class-consequential {
  background: var(--red-soft);
  color: var(--red);
}

.operation-note {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}

.operation-note small {
  color: var(--muted);
  font-size: 11px;
}

/* --------------------------------------------------------------- confirming */

.confirm-panel {
  margin-top: 16px;
  border: 1px solid #e0b1ab;
  border-radius: var(--radius);
  background: linear-gradient(180deg, #fdf6f5 0%, var(--surface) 60%);
}

.confirm-panel h3 {
  margin: 10px 0 6px;
  font:
    650 16px/1.3 'Manrope',
    system-ui,
    sans-serif;
  color: var(--ink-strong);
}

.confirm-summary {
  margin: 0 0 12px;
  padding: 11px 13px;
  border-left: 3px solid var(--red);
  background: var(--surface-soft);
  color: var(--ink);
  font-size: 13px;
}

/* What is true of this subject right now, under what the operation always means. Same left rule as
   the summary because it is the same disclosure continued, and not a warning: closing work with
   questions still open is permitted, so nothing here is dressed as a refusal. */
.confirm-disclosures {
  margin: -6px 0 12px;
  padding: 9px 13px;
  border-left: 3px solid var(--red);
  background: var(--surface-soft);
  color: var(--ink);
  font-size: 13px;
}

.confirm-disclosures p {
  margin: 0 0 6px;
}

.confirm-disclosures p:last-child {
  margin-bottom: 0;
}

.confirm-refusal {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}

.confirm-refusal small {
  color: var(--muted);
  font-size: 11px;
}

/* Rejecting is safe, so this panel is deliberately not dressed like the confirmation one. It asks
   for one thing: the reason that goes on the record. */
.reject-panel {
  margin-top: 16px;
}

.confirm-blocked {
  margin: 10px 0;
  padding: 9px 11px;
  border-radius: var(--radius-sm);
  background: var(--red-soft);
  color: var(--red);
}

.confirm-actions,
.decide-actions,
.proposal-actions {
  display: flex;
  gap: 9px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 14px;
}

.consequential-button {
  border-color: var(--red);
  background: var(--red);
  color: white;
}

.consequential-button:hover:not(:disabled) {
  border-color: #8f3830;
  background: #8f3830;
}

.failure-panel {
  border-color: #e0b1ab;
  margin: 14px 0;
}

.failure-code {
  display: inline-block;
  margin-top: 8px;
  padding: 2px 7px;
  border-radius: 5px;
  background: var(--surface-soft);
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
}

/* --------------------------------------------------------------- proposals */

.proposal-list {
  display: grid;
  gap: 16px;
}

.proposal-claim {
  margin: 0 0 14px;
  color: var(--ink);
  font-size: 13px;
}

.before-after {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 16px;
}

.before-after-side {
  padding: 12px 13px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-soft);
  min-width: 0;
}

.before-after-side h4 {
  margin: 0 0 8px;
  font:
    650 11px/1.2 'Manrope',
    system-ui,
    sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.subsection {
  margin-bottom: 16px;
}

.subsection-title {
  margin: 0 0 7px;
  font:
    650 11px/1.2 'Manrope',
    system-ui,
    sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.proposal-uncertainty {
  margin-top: 12px;
  padding: 9px 11px;
  border-radius: var(--radius-sm);
  background: var(--amber-soft);
  color: var(--amber);
}

.proposal-subject {
  color: var(--muted);
}

.source-versions {
  margin: 6px 0 0;
  padding-left: 17px;
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
}

.key-value {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 5px;
}

.key-value li {
  display: grid;
  grid-template-columns: minmax(0, 130px) minmax(0, 1fr);
  gap: 10px;
  align-items: baseline;
}

.key-value small {
  color: var(--muted);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.key-value span {
  min-width: 0;
  overflow-wrap: anywhere;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
}

/* ----------------------------------------------------------------- lineage */

.lineage-panel {
  margin-bottom: 26px;
}

.lineage-toolbar {
  align-items: flex-start;
  gap: 20px;
}

.lineage-toolbar h3 {
  margin: 0;
  font:
    650 15px/1.3 'Manrope',
    system-ui,
    sans-serif;
}

.lineage-toolbar p {
  margin: 3px 0 0;
  color: var(--muted);
  font-size: 12px;
}

.original-source {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 14px;
  border: 1px solid var(--line-strong);
  border-left: 4px solid var(--teal);
  border-radius: var(--radius-sm);
  background: var(--teal-soft);
  max-width: 360px;
}

.original-source small {
  color: var(--teal-dark);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.original-source small:last-child {
  text-transform: none;
  letter-spacing: 0;
  color: var(--muted);
}

.original-source-link {
  color: var(--ink-strong);
  text-decoration: none;
}

.original-source-link:hover {
  text-decoration: underline;
}

.lineage-node {
  display: block;
  text-decoration: none;
  min-width: 158px;
  max-width: 200px;
}

.lineage-node.is-source {
  border-left: 3px solid var(--teal);
}

.lineage-node-author {
  margin-top: 5px;
  text-transform: none !important;
  letter-spacing: 0 !important;
  color: var(--subtle) !important;
}

.lineage-node-here {
  position: absolute;
  top: -9px;
  right: 8px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--teal);
  color: white;
  font-size: 8px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.lineage-path {
  padding: 0 22px 18px;
}

.lineage-path > small {
  color: var(--muted);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.lineage-path ol {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 7px 0 0;
  padding: 0;
  list-style: none;
}

.lineage-path li::after {
  content: '→';
  margin-left: 8px;
  color: var(--subtle);
}

.lineage-path li:last-child::after {
  content: '';
}

.lineage-path li.is-here {
  font-weight: 600;
  color: var(--ink-strong);
}

.lineage-facts {
  padding: 0 22px 6px;
}

.lineage-facts h3 {
  margin: 0 0 10px;
  font:
    650 13px/1.3 'Manrope',
    system-ui,
    sans-serif;
}

/* Deliberately not the prototype's `.adoption-table`: its `max-width: 760px` block in `styles.css`
   hides columns 2 and 3, which here are Parent and Original source — the two columns this table
   exists to show. */
.lineage-facts-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.lineage-facts-table th {
  padding: 7px 9px;
  border-bottom: 1px solid var(--line-strong);
  color: var(--muted);
  font-size: 10px;
  font-weight: 700;
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.lineage-facts-table td {
  padding: 9px;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.lineage-facts-table tr.is-subject {
  background: var(--teal-soft);
}

.lineage-facts-table a {
  color: var(--ink-strong);
}

/* ------------------------------------------------------------------- pages */

.families-layout,
.family-layout,
.component-layout,
.deliveries-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 380px);
  gap: 22px;
  align-items: start;
}

.family-list {
  display: grid;
  gap: 10px;
}

.family-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 15px 18px;
  text-decoration: none;
  color: inherit;
}

.family-row:hover {
  border-color: var(--teal);
}

.family-row-identity {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.family-row-identity strong {
  font:
    650 14px/1.3 'Manrope',
    system-ui,
    sans-serif;
  color: var(--ink-strong);
}

.family-row-identity small {
  color: var(--muted);
  font-size: 11px;
}

.family-row-state {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}

.family-row-state small {
  color: var(--muted);
  font-size: 10px;
}

.component-item {
  display: block;
  text-decoration: none;
}

.component-generation {
  color: var(--muted);
  font-size: 10px;
}

/* ------------------------------------------------------------ provenance */

.activity-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 3px;
}

/* The prototype's `.activity-list li` is a two-child dot+content grid. A provenance entry has
   four parts, so it declares its own layout — with a specificity that beats the borrowed rule —
   and puts every child in the content column, leaving the 9px track to the timeline dot alone. */
li.activity-item {
  display: grid;
  grid-template-columns: 9px minmax(0, 1fr);
  column-gap: 10px;
  row-gap: 5px;
  padding: 13px 2px;
  border-bottom: 1px solid var(--line);
}

li.activity-item > * {
  grid-column: 2;
}

.activity-item:last-child {
  border-bottom: 0;
}

.activity-head {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
}

.activity-head strong {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  color: var(--ink-strong);
}

.activity-when {
  margin-left: auto;
  color: var(--subtle);
  font-size: 11px;
}

.activity-item small {
  color: var(--muted);
  font-size: 11px;
}

.activity-confirmation {
  display: grid;
  gap: 3px;
  padding: 9px 11px;
  border-left: 3px solid var(--teal);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--teal-soft);
}

.confirmation-statement {
  color: var(--teal-dark);
  font-size: 12px;
  font-style: italic;
}

.activity-provenance {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
}

.activity-link a {
  color: var(--teal-dark);
}

/* The prototype's `.version-history-list li` is a three-part 38px chip + content + status grid.
   A version row here is a label above its timestamp and change note, so it owns its layout —
   borrowing the prototype's card surface, not its column tracks. */
.version-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 9px;
}

.version-entry {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  padding: 12px 13px;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--surface-soft);
}

.version-entry small {
  color: var(--muted);
  font-size: 11px;
}

.quiet-copy {
  color: var(--muted);
  font-size: 12px;
}

.check-item {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 12px 0;
}

.check-item label {
  font-size: 12px;
  color: var(--ink);
}

/* ------------------------------------------------------ the attention inbox */

/* The list is the prototype's inbox stream — one compact row per item, the detail elsewhere — and
   every class below is ours rather than the prototype's, for the reason at the top of this file.
   `.inbox-item`, `.inbox-stream`, `.inbox-copy` and `.inbox-state` all exist in `styles.css` with
   their own column tracks and their own `display`; borrowing one and restating `display` and `gap`
   leaves the borrowed `grid-template-columns` winning at equal specificity, which is how three
   earlier surfaces here broke. Colour, type and spacing are taken from the prototype freely; the
   tracks are declared here.

   `.attention-involvement`, `.attention-state` and `.attention-when` are renames of three classes
   that did collide with `styles.css`: `.inbox-state` there is a right-aligned grid, and it was
   quietly deciding the `display` of a pill this file thought it owned. */
.inbox-rows {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

.inbox-rows > li {
  display: block;
  min-width: 0;
}

/* One item, as the thing you read to decide which to open. It is a button and it offers nothing
   else: every affordance on this screen lives in the overlay, beside the disclosures that belong
   to it. */
.inbox-row {
  width: 100%;
  padding: 15px 17px;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) minmax(0, 204px);
  gap: 14px;
  align-items: start;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.inbox-rows > li:first-child .inbox-row {
  border-top: 0;
}

.inbox-row:hover {
  background: var(--surface-soft);
}

.inbox-row:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: -2px;
}

.inbox-row.is-open {
  background: var(--blue-soft);
}

/* An anchor for the eye, tinted by actor type. FR-CI-01's distinction is never carried by the
   tint: `.inbox-row-from` says which kind of actor this is in words, on every row, always. */
.inbox-row-mark {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 11px;
  background: var(--surface-soft);
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.inbox-row-mark.actor-ai-agent {
  background: var(--teal-soft);
  color: var(--teal);
}

.inbox-row-mark.actor-external-agency {
  background: var(--amber-soft);
  color: var(--amber);
}

.inbox-row-mark.actor-team {
  background: var(--purple-soft);
  color: var(--purple);
}

.inbox-row-mark.actor-integration {
  background: var(--blue-soft);
  color: var(--ink);
}

.inbox-row-copy {
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 4px;
}

.inbox-row-from {
  color: var(--subtle);
  font-size: 11px;
}

/* A question may be 2,000 characters. Keep the whole value in the row for assistive technology
   and the detail overlay, while keeping triage rows to two visible lines. */
.inbox-row-headline {
  display: -webkit-box;
  max-height: 2.7em;
  overflow: hidden;
  font-size: 14px;
  font-weight: 650;
  line-height: 1.35;
  overflow-wrap: anywhere;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.inbox-row-why {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.inbox-row-standing {
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: end;
  gap: 6px;
  text-align: right;
}

/* Whether an item is assigned, suggested or informational is not decoration: AI-CM-01 requires it
   stated, and the word carries it, never the colour alone. */
.attention-involvement,
.attention-state {
  padding: 2px 8px;
  border-radius: 6px;
  background: var(--surface-soft);
  color: var(--muted);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

.attention-when {
  color: var(--subtle);
  font-size: 11px;
}

/* FR-CI-05, in the prototype's own shape for this control: pressed toggles rather than a select.
   Its own tracks, because `styles.css`'s `.inbox-filters` is a flex row for a different set of
   children. */
.inbox-filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-bottom: 15px;
}

.inbox-filter {
  padding: 8px 13px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
}

.inbox-filter:hover:not(:disabled) {
  border-color: var(--ink);
  color: var(--ink);
}

.inbox-filter.is-active {
  border-color: var(--ink-strong);
  background: var(--ink-strong);
  color: var(--surface);
}

.inbox-filter:disabled {
  opacity: 0.55;
  cursor: default;
}

/* The item itself, over the list: the prototype's right-hand drawer, at the width this content
   actually needs. It is a real modal — see `Page.Inbox.overlay` for the four things that make it
   one — and the classes are ours rather than `styles.css`'s `.drawer*`, which is a 430px sheet
   sized for a preview card and positioned under a topbar this build does not have. */
.inbox-overlay-layer {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  justify-content: flex-end;
}

.inbox-overlay-scrim {
  position: absolute;
  inset: 0;
  background: rgba(13, 36, 52, 0.42);
  backdrop-filter: blur(2px);
}

/* A focusable nothing either side of the dialog. `opacity: 0` rather than `display: none` or
   `visibility: hidden`, both of which would take it out of the tab order — which is the one thing
   it is for. */
.inbox-overlay-edge {
  position: fixed;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.inbox-overlay {
  position: relative;
  z-index: 1;
  width: min(760px, 100%);
  height: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--line);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}

.inbox-overlay:focus {
  outline: none;
}

.inbox-overlay:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: -3px;
}

.inbox-overlay-header {
  padding: 20px 24px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: start;
  border-bottom: 1px solid var(--line);
}

.inbox-overlay-title {
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 7px;
}

.inbox-overlay-eyebrow {
  color: var(--subtle);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.inbox-overlay-header h2 {
  margin: 0;
  font-size: 19px;
  line-height: 1.32;
  overflow-wrap: anywhere;
}

.inbox-overlay-mark {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.inbox-overlay-body {
  flex: 1;
  min-height: 0;
  padding: 20px 24px 26px;
  overflow-y: auto;
}

.inbox-overlay-footer {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
  padding: 13px 24px;
  border-top: 1px solid var(--line);
  background: var(--surface-soft);
}

.inbox-overlay-footer small {
  color: var(--muted);
  font-size: 11px;
  line-height: 1.5;
}

/* Says it cannot be used while it stays focusable: disabling it would take an anchor of the focus
   trap away at the moment nothing may tab out. `Page.Inbox.closeButton` has the argument. */
.inbox-overlay-close.is-inert {
  opacity: 0.55;
  cursor: default;
}

.inbox-why {
  margin: 0 0 14px;
  color: var(--ink);
  font-size: 13px;
}

.inbox-expected,
.inbox-changed {
  margin-top: 10px;
}

.inbox-expected small,
.inbox-changed small {
  color: var(--muted);
  font-size: 11px;
}

/* "Changed so far" is the sentence that keeps "the agent finished" from reading as "the output is
   approved", so it is set apart rather than left as one more line of grey. */
.inbox-changed {
  padding: 9px 11px;
  border-left: 3px solid var(--line-strong);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--surface-soft);
}

/* What closing the overlay does to an unsent statement, answer or reason. It sits at the foot of the
   item, under whatever form is open, so it is read while the writing is happening rather than after
   it is gone. `Page.Inbox.draftsAreNotKept` has the argument. */
.inbox-drafts {
  margin: 16px 0 0;
  color: var(--muted);
  font-size: 11px;
  line-height: 1.5;
}

.inbox-landing {
  margin-bottom: 20px;
}

.inbox-landing p {
  color: var(--muted);
  font-size: 12px;
  margin: 10px 0;
}

.queued-action {
  margin-top: 16px;
}

/* A decision waiting on this reader, in its inbox overlay. Sibling of `.queued-action` and not a reuse
   of it: they are two surfaces, and one inheriting a change meant for the other is the failure this
   stylesheet keeps warning about. */
.open-decision {
  margin-top: 16px;
}

.open-decision-question {
  margin: 4px 0 6px;
  font-size: 15px;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.open-decision-context {
  margin: 0;
  line-height: 1.55;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

/* What an agent reported about itself when an agent raised the question — a claim, and drawn as
   quietly as the same claim under a thread entry. */
.open-decision-model {
  display: block;
  margin-top: 6px;
  color: var(--muted);
  font-size: 11px;
}

/* A queued action whose subject has moved cannot be confirmed at all. It says so before the person
   starts writing a statement, in the treatment a thing out of play deserves. */
.queued-stale {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin: 12px 0;
  padding: 10px 12px;
  border-left: 3px solid var(--line-strong);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: #f0f0ec;
}

.queued-stale small {
  color: var(--muted);
  font-size: 11px;
  min-width: 0;
}

/* An expired proposal is the same situation reached the other way — nothing here can be acted on —
   so it is said in the same treatment, in place of the decision controls rather than beside them.
   Its own class, not `.queued-stale` reused: two surfaces sharing one class is how one of them ends
   up inheriting a change meant for the other. */
.inbox-expired {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin: 12px 0;
  padding: 10px 12px;
  border-left: 3px solid var(--line-strong);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: #f0f0ec;
}

.inbox-expired small {
  color: var(--muted);
  font-size: 11px;
  min-width: 0;
}

/* The same situation on a queued action's card rather than a proposal's. Its own class for the
   reason `.inbox-expired` has one: the two cards are different surfaces, and one inheriting a
   change meant for the other is how that goes wrong. */
.queued-blocked {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin: 12px 0;
  padding: 10px 12px;
  border-left: 3px solid var(--line-strong);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: #f0f0ec;
}

.queued-blocked small {
  color: var(--muted);
  font-size: 11px;
  min-width: 0;
}

/* Why this reader may not make a call the item is still open to. Deliberately without the treatment
   above and without any standing badge: an authority the reader does not hold is a fact about them,
   and it changes nothing about where the item stands. */
.inbox-blocked {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 12px 0;
}

.inbox-blocked small {
  color: var(--muted);
  font-size: 11px;
  min-width: 0;
}

/* ------------------------------------------------------- outcome threads */

/* HUMAN_AI_INTERFACE section 4. Every class below is our own rather than a prototype structural
   one, for the reason written up at `.families-layout`: an inherited column track has broken three
   separate surfaces here already, and restating only `display` and `gap` does not help, because the
   cascade is per property and the prototype's tracks still win at equal specificity. So the tracks
   are declared here. */

.thread-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
}

.thread-item {
  display: block;
  text-decoration: none;
  color: inherit;
  min-width: 0;
}

.thread-item:hover {
  border-color: var(--line-strong);
}

.thread-item-head,
.thread-member-head,
.thread-entry-head,
.thread-decision-head,
.thread-approval-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  min-width: 0;
}

.thread-outcome {
  display: block;
  margin: 8px 0 4px;
  font-size: 15px;
  line-height: 1.35;
}

.thread-context {
  margin: 0 0 4px;
  color: var(--muted);
  font-size: 12px;
}

.thread-owner,
.thread-when,
.thread-ended,
.thread-member-kind,
.thread-decision-source {
  color: var(--muted);
  font-size: 11px;
  min-width: 0;
}

/* How the work ended, who confirmed it and when — under the badge that names the ending, because a
   badge saying "Abandoned" with nobody's name against it states an outcome without the
   accountability that makes it one. */
.thread-ended {
  display: block;
  margin-top: 4px;
}

/* The thread that took this work over. A link, so a superseded thread is not a dead end. */
.thread-successor {
  margin: 10px 0 0;
  font-size: 12px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.thread-when {
  margin-left: auto;
}

/* The two times a backdated entry has, stacked at the end of its head row.
   `thread-when` keeps its `margin-left: auto` when it is the only thing there, so the wrapper takes
   over that job when there are two of them; declaring the tracks on our own class rather than
   leaning on a prototype row is the rule at the top of this file, and a stacked pair inside a
   baseline-aligned flex row is exactly where an inherited one would put them side by side. */
.thread-entry-when {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  margin-left: auto;
  min-width: 0;
}

.thread-entry-when .thread-when {
  margin-left: 0;
}

/* When this system heard it, under what the author says happened. Quieter than the claim above it
   but never absent: it is the one of the two this system can vouch for, and a reader who cannot see
   both cannot tell a backdated entry from a contemporaneous one. */
.thread-when-recorded {
  color: var(--muted);
  font-size: 11px;
  opacity: 0.8;
  min-width: 0;
}

/* Two columns of sections. The left is what the thread stores, the right is what it derives — a
   distinction the headings state in words too, because a reader deciding something is entitled to
   know whether they are looking at a record or at a view assembled from one. */
.thread-layout {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  gap: 24px;
  align-items: start;
}

.thread-column {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
  min-width: 0;
}

.thread-members,
.thread-entries,
.thread-decisions,
.thread-approvals {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
}

.thread-member-name {
  display: block;
  margin: 8px 0 4px;
  text-decoration: none;
  color: inherit;
  overflow-wrap: anywhere;
}

.thread-member-outcome {
  display: block;
  color: var(--muted);
  font-size: 11px;
}

.thread-entry-body,
.thread-statement {
  margin: 8px 0 4px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.thread-statement {
  font-style: italic;
}

.thread-entry-model {
  display: block;
  color: var(--muted);
  font-size: 11px;
}

/* A decision this work is waiting on, in the thread's open-decisions panel: the question, then the
   reasoning that makes it answerable. Its own classes rather than the entry body's, because the two
   say different things — an entry is something somebody said, a decision is something somebody was
   asked — and one inheriting a change meant for the other is how that distinction goes quiet. */
.thread-decision-question {
  margin: 8px 0 4px;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.thread-decision-context {
  margin: 0 0 6px;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

/* A fact the API withheld because this reader could not have fetched it. Deliberately quiet and
   deliberately without a standing badge: withholding a fact says nothing about where the thing
   itself stands. */
.thread-withheld {
  color: var(--muted);
  font-size: 11px;
}

.thread-activity {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
}

.thread-activity-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  padding: 8px 14px;
  border-bottom: 1px solid var(--line);
  min-width: 0;
}

.thread-activity-row:last-child {
  border-bottom: none;
}

/* The event type takes whatever room is left, so the identifier stays on the row rather than
   wrapping under it as soon as an event type gets long. */
.thread-activity-row > span {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.thread-activity-id {
  margin-left: auto;
  color: var(--muted);
  font-family: var(--mono, monospace);
  font-size: 11px;
}

/* An action the contract says this reader may not make. Same treatment as `.inbox-blocked`, and its
   own class for the same reason that one has: two surfaces, and one inheriting a change meant for
   the other is how it goes wrong. */
.thread-blocked small {
  color: var(--muted);
  font-size: 11px;
  min-width: 0;
}

/* The one link from an inbox item to the piece of work it belongs to. */
.inbox-threads {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  margin: 10px 0 0;
  min-width: 0;
}

.inbox-thread-link {
  font-size: 12px;
  overflow-wrap: anywhere;
}

/* --------------------------------------------------------- putting a file in
 *
 * The file field on the three cards that can carry content. It gets its own class rather than
 * reusing a prototype form class for the reason recorded throughout this file: an inherited column
 * track has broken three surfaces here already, and this block stacks a filename, a size, a note
 * and a button, which is not the shape any prototype field has.
 *
 * Deliberately no progress bar. `Http.track` would give one, and a percentage that stalls at 100
 * while the API is still reading the object back would say the record is written when it is not —
 * which is exactly the claim this whole slice exists to stop the interface making.
 */
.upload-field {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  padding: 13px;
  margin-bottom: 16px;
  border: 1px dashed var(--line);
  border-radius: 11px;
  background: var(--surface-soft);
}

.upload-field .quiet-copy {
  margin: 0;
}

.upload-chosen {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  min-width: 0;
}

.upload-chosen strong {
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: 13px;
}

.upload-chosen small {
  color: var(--muted);
  font-size: 11px;
}

/* What a version's bytes are, under the change note on the version list. */
.version-content {
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--muted);
  font-size: 11px;
}

@media (max-width: 1080px) {
  .families-layout,
  .family-layout,
  .component-layout,
  .deliveries-layout,
  .thread-layout,
  .before-after {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* --------------------------------------- brands and campaigns: structural rows

   PROTOTYPE_SPEC FR-PO-05 and FR-PO-06 for the brand rows, FR-PO-01 through FR-PO-03 for the
   campaign timeline. Colour, type and spacing are the prototype's `.brand-row` and `.hq-gantt`;
   the tracks are declared here because both surfaces have fewer columns than the prototype's do —
   only the columns the contract can answer — and inheriting a grid built for five would leave the
   ones we have sitting in the wrong tracks. */

.structure-summary {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: -14px 0 20px;
  color: var(--muted);
  font-size: 12px;
  white-space: nowrap;
}

.structure-summary strong {
  color: var(--ink-strong);
  font-size: 13px;
}

.structure-summary span {
  padding-left: 14px;
  border-left: 1px solid var(--line);
}

.structure-list {
  display: grid;
  gap: 12px;
}

.structure-row {
  display: grid;
  grid-template-columns: 62px minmax(220px, 1.2fr) minmax(180px, 1fr) minmax(150px, 0.7fr);
  align-items: start;
  gap: 20px;
  padding: 18px 20px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: rgba(255, 253, 249, 0.78);
}

.structure-mark {
  width: 58px;
  height: 58px;
  display: grid;
  place-items: center;
  border-radius: 18px;
  background: linear-gradient(145deg, #3e725f, #275b4d);
  color: #fff;
  font:
    700 16px 'Manrope',
    system-ui,
    sans-serif;
  box-shadow: 0 12px 22px rgba(46, 91, 75, 0.17);
}

.structure-mark-small {
  width: 38px;
  height: 38px;
  border-radius: 12px;
  font-size: 12px;
  box-shadow: 0 7px 14px rgba(46, 91, 75, 0.14);
}

.structure-identity {
  min-width: 0;
}

.structure-identity small {
  display: block;
  color: var(--muted);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.structure-identity strong {
  display: block;
  margin-top: 4px;
  color: var(--ink-strong);
  font:
    600 20px 'Manrope',
    system-ui,
    sans-serif;
}

.structure-identity em {
  display: block;
  margin-top: 5px;
  color: var(--muted);
  font-size: 11px;
  font-style: normal;
}

.structure-column {
  min-width: 0;
  padding-left: 18px;
  border-left: 1px solid var(--line);
}

.structure-column > small {
  display: block;
  margin-bottom: 6px;
  color: var(--muted);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.structure-listing {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 7px;
}

.structure-listing strong {
  display: block;
  color: var(--ink);
  font-size: 13px;
}

.structure-listing small {
  display: block;
  color: var(--muted);
  font-size: 11px;
}

.structure-count strong {
  display: block;
  color: var(--ink);
  font-size: 13px;
}

.structure-count small {
  display: block;
  margin-top: 4px;
  color: var(--muted);
  font-size: 11px;
}

/* The families that belong to no brand, stated beneath the rows. A sentence and not a row: global
   is a scope a family is in rather than a brand it belongs to, so it gets no monogram, no column
   tracks and nothing else a `.structure-row` has — drawing it as a row is the same category error
   as drawing `uncategorised` as a seventh Resources category. Quiet, because it states a fact about
   the workspace rather than asking for anything. */
.structure-global {
  margin-top: 14px;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-soft);
}

.structure-global small {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.6;
}

.structure-global strong {
  color: var(--ink);
}

/* A read that has not landed yet, and a real answer of "none". They are different sentences and
   they are drawn differently, because "no campaigns" is a claim about a brand and a screen still
   waiting for the list is not entitled to make it. */
.structure-pending {
  color: var(--line-strong);
  font-size: 13px;
}

.structure-none {
  color: var(--muted);
  font-size: 13px;
}

/* And the third: a read the API refused. Neither of the two above may stand in for it — the
   ellipsis would say the answer is still coming and "None" would assert an absence nobody
   established. Quiet and small like the rows around it, and no badge: what kind of claim a thing is
   belongs to `Standing`, and a read that did not arrive is not a claim at all. */
.structure-unread {
  color: var(--subtle);
  font-size: 12px;
  font-style: normal;
}

/* Inside a timeline row the copy's own type rules are more specific than the class, so the same
   treatment is restated at that weight rather than being quietly overruled by them. */
.campaign-timeline-copy .structure-unread {
  color: var(--subtle);
  font-size: 11px;
}

/* And the same third state beside a form control. It is pulled up under the field it belongs to,
   because `.field`'s own bottom margin would otherwise leave the sentence reading as a caption on
   the control below it — which is the wrong control entirely. No border, no tint and no badge: a
   read that did not arrive is not a claim, and this one sits inside a card that is already a panel. */
.field-unread {
  margin-top: -11px;
  margin-bottom: 15px;
}

/* What the screen is specified to show and does not, said on the screen. */
.structure-omissions {
  margin-top: 26px;
  padding: 14px 16px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--muted);
}

.structure-omissions > small {
  display: block;
  font-size: 11px;
}

.structure-omissions ul {
  margin: 8px 0 0;
  padding-left: 18px;
  display: grid;
  gap: 4px;
  font-size: 11px;
}

/* ------------------------------------------ the one shared campaign time axis */

.campaign-timeline {
  border-top: 1px solid var(--line);
}

.campaign-timeline-axis,
.campaign-timeline-row {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
}

.campaign-timeline-axis {
  min-height: 46px;
  border-bottom: 1px solid var(--line);
}

.campaign-timeline-axis-label {
  padding: 12px 14px 10px 2px;
}

.campaign-timeline-axis-label strong {
  display: block;
  color: var(--ink-strong);
  font:
    600 11px 'Manrope',
    system-ui,
    sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.campaign-timeline-axis-label span {
  display: block;
  margin-top: 4px;
  color: var(--muted);
  font-size: 10px;
}

.campaign-timeline-scale {
  position: relative;
  border-left: 1px solid var(--line);
}

.campaign-timeline-tick {
  position: absolute;
  top: 14px;
  padding-left: 6px;
  border-left: 1px solid var(--line);
  color: var(--muted);
  font-size: 10px;
  white-space: nowrap;
}

.campaign-timeline-row {
  min-height: 84px;
  align-items: center;
  border-bottom: 1px solid var(--line);
}

.campaign-timeline-label {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 14px 14px 2px;
  min-width: 0;
}

.campaign-timeline-copy {
  min-width: 0;
}

.campaign-timeline-copy strong {
  display: block;
  color: var(--ink-strong);
  font:
    600 14px/1.3 'Manrope',
    system-ui,
    sans-serif;
  overflow-wrap: anywhere;
}

.campaign-timeline-copy small {
  display: block;
  margin-top: 3px;
  color: var(--muted);
  font-size: 11px;
}

.campaign-timeline-copy em {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: 10px;
  font-style: normal;
}

.campaign-timeline-track {
  position: relative;
  min-width: 0;
  height: 84px;
  border-left: 1px solid var(--line);
}

.campaign-timeline-rule {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--line);
}

/* One bar, one meaning: the interval the campaign was declared to run for. Nothing here is a
   status, so nothing here is coloured as one. */
.campaign-timeline-bar {
  position: absolute;
  top: 50%;
  height: 30px;
  min-width: 34px;
  padding: 0 10px;
  display: flex;
  align-items: center;
  border: 1px solid #b6cdd8;
  border-radius: 9px;
  background: var(--blue-soft);
  color: #3d6578;
  font-size: 11px;
  transform: translateY(-50%);
  box-shadow: 0 4px 10px rgba(66, 48, 27, 0.045);
}

.campaign-timeline-bar span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 1240px) {
  .structure-row {
    grid-template-columns: 62px minmax(0, 1fr);
  }

  .structure-column {
    grid-column: 2;
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--line);
    padding-top: 10px;
  }

  .campaign-timeline-axis,
  .campaign-timeline-row {
    grid-template-columns: 190px minmax(0, 1fr);
  }
}

/* ------------------------------------------------- focus: the clean carousel

   PROTOTYPE_SPEC's focus surface and `prototype/app.js` have diverged, and the captain's choice is
   the prototype's newer `clean-focus` carousel rather than the specification's spatial orbit
   (AGENTS.md, "The prototype and PROTOTYPE_SPEC.md have diverged"). Sizes, radii and rhythm are
   that carousel's; the colours are this application's own tokens rather than the prototype's warm
   hexes, because every other screen here is already in them.

   The classes are ours rather than `styles.css`'s `.clean-focus-*` for the reason AGENTS.md gives:
   the card carries one column fewer than the prototype's and one row it never had, and inheriting a
   grid built for the prototype's children would put ours in the wrong tracks. Restating `display`
   would not have helped — the cascade is per property, so the prototype's tracks would still win. */

.focus-page {
  display: grid;
  gap: 18px;
}

/* Where the prototype asserted PRIORITIZED FOR YOU. It states the API's actual ordering rule, and
   that nothing is ranking the list. See `Page.Focus.utility`. */
.focus-utility {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
}

.focus-utility-actions {
  display: flex;
  gap: 14px;
}

.focus-why {
  padding: 4px 0;
  border: 0;
  background: none;
  color: var(--teal);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
  text-decoration: underline;
  text-underline-offset: 4px;
  cursor: pointer;
}

.focus-why:hover {
  color: var(--teal-dark);
}

/* The truthful answer to "why first?". Quiet rather than tinted: it is not a standing, a lifecycle
   or an entry kind, and borrowing one of their treatments would put it in a vocabulary it is not
   in. */
.focus-explanation {
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-soft);
}

.focus-explanation strong {
  display: block;
  margin-bottom: 8px;
  color: var(--ink-strong);
  font-size: 14px;
}

.focus-explanation p {
  margin: 0 0 8px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.55;
}

.focus-explanation p:last-child {
  margin-bottom: 0;
}

.focus-centre {
  display: grid;
  justify-items: start;
}

.focus-centre h1 {
  margin: 6px 0 14px;
  color: var(--ink-strong);
  font:
    600 clamp(28px, 3vw, 40px) / 1.14 'Manrope',
    system-ui,
    sans-serif;
  letter-spacing: -0.035em;
}

.focus-centre .structure-summary {
  margin: 0 0 18px;
}

.focus-centre > *:last-child {
  width: 100%;
}

/* The card and the control that advances it. The next button sits outside the card, as the
   prototype's does, and disappears below where there is no room beside it. */
.focus-carousel {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 62px;
  align-items: stretch;
  gap: 12px;
}

.focus-card {
  display: grid;
  grid-template-columns: 86px minmax(0, 1fr) 230px;
  align-items: start;
  gap: 22px;
  padding: 22px 24px;
  border: 1px solid var(--line);
  border-radius: 19px;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

.focus-card-mark {
  width: 76px;
  height: 76px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border-radius: 18px;
  background: var(--surface-soft);
  color: var(--muted);
}

.focus-card-mark > i {
  font:
    600 25px 'Manrope',
    system-ui,
    sans-serif;
  font-style: normal;
  line-height: 1;
}

.focus-card-mark > small {
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* One tint per kind of already-governed record the item is a projection of. It says what kind of
   thing is waiting and nothing about how much it matters — which is why it is a mark on the card
   and not a badge: the badge shape belongs to the three vocabularies `check-vocabularies.mjs`
   guards, and this is not a fourth one. */
.focus-card-mark-proposal {
  background: var(--blue-soft);
  color: #2f6076;
}

.focus-card-mark-queued {
  background: var(--teal-soft);
  color: var(--teal-dark);
}

.focus-card-mark-decision {
  background: var(--purple-soft);
  color: var(--purple);
}

.focus-card-copy {
  min-width: 0;
  display: grid;
  gap: 7px;
}

/* A position and a total, never a score. See `Page.Focus.position`. */
.focus-card-place {
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Focus has more room than an inbox row, but it is still a headline rather than the decision brief.
   Three visible lines keep the surrounding reason, people, state and action on the card. */
.focus-card-copy > strong {
  display: -webkit-box;
  max-height: 3.72em;
  overflow: hidden;
  color: var(--ink-strong);
  font:
    600 22px / 1.24 'Manrope',
    system-ui,
    sans-serif;
  letter-spacing: -0.02em;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}

.focus-card-why {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

.focus-card-context {
  min-width: 0;
  padding-left: 20px;
  display: grid;
  justify-items: start;
  gap: 8px;
  border-left: 1px solid var(--line);
}

.focus-card-context > small {
  color: var(--muted);
  font-size: 11px;
  line-height: 1.45;
}

.focus-card-context > strong {
  color: var(--ink-strong);
  font-size: 11px;
}

.focus-people {
  display: flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
}

.focus-people i {
  width: 30px;
  height: 30px;
  margin-right: -5px;
  display: grid;
  place-items: center;
  border: 2px solid var(--surface);
  border-radius: 50%;
  background: var(--surface-soft);
  color: var(--muted);
  font-size: 9px;
  font-style: normal;
  font-weight: 700;
}

/* The row the prototype's card never had: the one clear next action, when it was raised, and the
   way to the only surface where it can be acted on. */
.focus-card-foot {
  grid-column: 1 / -1;
  display: grid;
  gap: 8px;
  margin-top: 4px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.focus-card-do {
  color: var(--ink);
  font-size: 12px;
  line-height: 1.5;
}

.focus-card-do strong {
  color: var(--ink-strong);
}

.focus-card-when {
  color: var(--muted);
  font-size: 11px;
}

.focus-card-link {
  justify-self: start;
  color: var(--teal);
  font-size: 12px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 4px;
}

.focus-next {
  border: 0;
  border-radius: 18px;
  background: transparent;
  color: var(--muted);
  font:
    400 34px / 1 'Manrope',
    system-ui,
    sans-serif;
  cursor: pointer;
  transition:
    background 150ms ease,
    color 150ms ease;
}

.focus-next:hover {
  background: var(--surface-soft);
  color: var(--teal);
}

.focus-dots {
  margin-top: 20px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.focus-dots button {
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--line-strong);
  cursor: pointer;
  transition:
    width 180ms ease,
    background 180ms ease;
}

.focus-dots button:hover {
  background: var(--subtle);
}

.focus-dots button.is-showing {
  width: 23px;
  border-radius: 99px;
  background: var(--teal);
}

@media (max-width: 1080px) {
  .focus-carousel {
    grid-template-columns: minmax(0, 1fr);
  }

  .focus-card {
    grid-template-columns: 76px minmax(0, 1fr);
  }

  .focus-card-context {
    grid-column: 2;
    padding: 12px 0 0;
    border-left: 0;
    border-top: 1px solid var(--line);
  }

  .focus-next {
    justify-self: start;
    width: 62px;
    height: 44px;
  }
}

/* ------------------------------------------------- resources: the six categories

   PROTOTYPE_SPEC FR-PO-07 and FR-PO-08. The prototype has a `.resource-grid` and a
   `.resource-card` in `styles.css` and this deliberately reuses neither, for the reason recorded
   throughout this file: the prototype's grid declares `repeat(3, minmax(0,1fr))` and its card
   declares a fixed `min-height` around content this build does not have — no owner, no "current
   activity", no invented count — so inheriting its tracks would leave six shorter cards padded out
   to a shape built for a different set of facts. Colour, type, spacing, radius and the hover lift
   are the prototype's; the tracks are ours.

   The card is an anchor rather than a div with a button because a category has exactly one
   affordance: FR-PO-19 requires selecting Media to open the content library. */

.resources-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.resources-card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  padding: 21px;
  color: var(--ink);
  text-decoration: none;
  transition:
    transform 160ms ease,
    border-color 160ms ease;
}

.resources-card:hover {
  transform: translateY(-2px);
  border-color: var(--line-strong);
}

.resources-card > strong {
  margin-top: 21px;
  color: var(--ink-strong);
  font-size: 20px;
  font-weight: 600;
}

.resources-card > p {
  margin: 7px 0 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.5;
}

.resources-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.resources-card-top small {
  color: var(--subtle);
  font-size: 11px;
  text-align: right;
}

.resources-mark {
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border-radius: 14px;
  background: var(--surface-soft);
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.resources-card-meta {
  margin-top: auto;
  padding-top: 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-top: 1px solid var(--line);
}

.resources-card-meta small {
  color: var(--subtle);
  font-size: 11px;
}

/* How much material the six do not cover. Stated rather than styled as a warning: AI-PO-01 makes
   uncategorised a legitimate state, so a workspace with material in it is behaving as specified. */
.resources-uncategorised {
  margin-top: 20px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-soft);
}

.resources-uncategorised strong {
  display: block;
  color: var(--ink-strong);
  font-size: 13px;
}

.resources-uncategorised small {
  display: block;
  margin-top: 5px;
  color: var(--muted);
  font-size: 11px;
  line-height: 1.5;
}

.resources-trail {
  margin: -14px 0 18px;
  font-size: 12px;
}

.resources-trail a {
  color: var(--muted);
  text-decoration: none;
}

.resources-trail a:hover {
  color: var(--ink-strong);
}

@media (max-width: 1180px) {
  .resources-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

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

/* ---------------------------------------------------------------- the evidence library
 *
 * A reference is not an asset family, and these are its own classes rather than the family row's
 * for the reason `AGENTS.md` records three surfaces breaking on: an inherited layout track carries
 * meaning, and the cascade is per property, so reusing a structural class here would tie two
 * different lists together until one of them needed to differ. They look alike on purpose and are
 * declared apart on purpose.
 */

.reference-list {
  display: grid;
  gap: 10px;
}

.reference-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 15px 18px;
  text-decoration: none;
  color: inherit;
}

.reference-row:hover {
  border-color: var(--teal);
}

.reference-row-identity {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.reference-row-identity strong {
  font:
    650 14px/1.3 'Manrope',
    system-ui,
    sans-serif;
  color: var(--ink-strong);
}

.reference-row-identity small {
  color: var(--muted);
  font-size: 11px;
}

.reference-row-state {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}

.reference-row-state small {
  color: var(--muted);
  font-size: 10px;
}

/* What cites a reference: the direction the join table exists to make answerable. */

.citation-list {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.citation-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
}

.citation-row a {
  text-decoration: none;
  color: inherit;
}

.citation-row a:hover strong {
  color: var(--teal);
}

.citation-row small {
  color: var(--muted);
  font-size: 11px;
}

/* Choosing what a version will cite, on the three forms that create one. */

.citation-picker {
  display: grid;
  gap: 8px;
  margin-bottom: 6px;
}

.citation-option {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.citation-option small {
  margin-left: 26px;
  color: var(--muted);
  font-size: 11px;
}

/* ------------------------------------------------------------------ Deliveries

   The composed things and, on every version of each, the manifest of exact component versions it is
   made of (`PROTOTYPE_SPEC.md:109`).

   These are our own classes rather than the prototype's structural ones, for the reason recorded at
   every other rule in this file: an inherited column track has broken three separate surfaces here,
   and restating only `display` and `gap` does not help because the cascade is per property.

   A manifest is drawn as an ordered list and never as a badge. This build has four badge
   vocabularies, `npm run vocabularies:check` holds each to a silhouette and an ink set, and a part
   is neither a kind of claim nor a state — it is a row naming an exact version. Nothing below
   declares a `.pill-badge` treatment, and nothing here should acquire one. */

.deliverable-list {
  display: grid;
  gap: 10px;
}

.deliverable-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 15px 18px;
  text-decoration: none;
  color: inherit;
}

.deliverable-row:hover {
  border-color: var(--teal);
}

.deliverable-row-identity {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.deliverable-row-identity strong {
  font:
    650 14px/1.3 'Manrope',
    system-ui,
    sans-serif;
  color: var(--ink-strong);
}

.deliverable-row-identity small {
  color: var(--muted);
  font-size: 11px;
}

.deliverable-row-state {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}

.deliverable-row-state small {
  color: var(--muted);
  font-size: 10px;
}

/* One immutable composition, and the note saying what changed. */

.deliverable-version {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 15px 18px;
  margin-bottom: 10px;
}

.deliverable-version-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.deliverable-version-heading strong {
  font:
    650 14px/1.3 'Manrope',
    system-ui,
    sans-serif;
  color: var(--ink-strong);
}

.deliverable-version-heading small {
  color: var(--muted);
  font-size: 10px;
}

.deliverable-change-note {
  color: var(--muted);
  font-size: 11px;
}

/* The manifest itself: an ordered list, because the order is part of what a composition is. */

.manifest-list {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: manifest;
}

.manifest-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 14px 10px 38px;
  position: relative;
  border: 1px solid var(--line);
  border-radius: 10px;
  counter-increment: manifest;
}

/* The position, which is a fact about the composition rather than a vocabulary marker: a plain
   number in the row's own gutter, not a badge and not a `::before` on `.pill-badge`. */
.manifest-row::before {
  content: counter(manifest);
  position: absolute;
  left: 14px;
  top: 10px;
  color: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.manifest-row a {
  text-decoration: none;
  color: inherit;
}

.manifest-row a:hover strong {
  color: var(--teal);
}

.manifest-row small {
  color: var(--muted);
  font-size: 11px;
}

/* Where the component a part names stands now, which is a reading of the present sitting beside an
   immutable record. It is drawn only on the parts that have something to say, so it needs an edge a
   reader's eye can find without one being put on every row — a rule on the left, in the row's own
   gutter beside the position, and nothing else.

   Emphatically not a `.pill-badge` and it declares no `--pill-ink`: "the component has been written
   past this" is neither a kind of claim nor a state of this part, and a badge treatment would owe
   `npm run vocabularies:check` a fifth vocabulary for something that is not one. It is also not a
   warning colour. The screen reports what is true and says nothing about whether it matters, so the
   ink is the ordinary muted one every other line in this row uses.

   The same class carries the archived reading, on a written part and on one a person has just added
   to a draft (`Authoring.Manifest`), deliberately: archived material may be composed with (captain,
   2026-08-17) and the state is a fact about the material rather than a fault in the composition, so
   it gets the muted line every other reading of the present gets and never a caution colour. */
.manifest-now {
  margin-top: 4px;
  padding-left: 10px;
  border-left: 2px solid var(--line);
  max-width: 74ch;
  line-height: 1.5;
}

/* The copy a publication owns: the other half of a composition, and a list for the same reason the
   manifest is one. It is neither a kind of claim nor a state, so nothing here is a `.pill-badge` and
   nothing here declares `--pill-ink` — a badge treatment would owe `npm run vocabularies:check` a
   vocabulary for something that is not one.

   Our own classes rather than the prototype's, for the reason recorded at every other rule in this
   file: an inherited column track has broken three separate surfaces here, and restating only
   `display` and `gap` does not help because the cascade is per property.

   The name is drawn small and above the words, deliberately: it is a person's word for this text
   rather than a slot this product knows, so it must not read as a field label with a value beside
   it. */

.deliverable-copy {
  display: grid;
  gap: 6px;
  margin-top: 4px;
}

.deliverable-copy-heading {
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.copy-list {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.copy-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
}

.copy-name {
  color: var(--muted);
  font-size: 11px;
}

.copy-text {
  color: var(--ink);
  font-size: 13px;
  line-height: 1.5;
  max-width: 74ch;
}

/* ------------------------------------------------- composing one of them

   Choosing the exact component versions a composition is made of, and writing the copy it owns.
   Both halves are written by one call because they are one immutable record, so they are one card.

   Our own classes rather than the prototype's, for the reason recorded at every other rule in this
   file: an inherited column track has broken three separate surfaces here, and restating only
   `display` and `gap` does not help because the cascade is per property.

   The chosen parts reuse `.manifest-list` and `.manifest-row` deliberately, rather than getting a
   form treatment of their own: this is the same fact one moment earlier, and a person who confirms
   a manifest here should meet it in the same shape on the record afterwards.

   Nothing below is a `.pill-badge` and nothing declares `--pill-ink`. A part is neither a kind of
   claim nor a state where it is read, and choosing one does not make it either. */

.manifest-compose {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.manifest-chosen .manifest-row > strong {
  font:
    650 13px/1.3 'Manrope',
    system-ui,
    sans-serif;
  color: var(--ink-strong);
}

/* Every version of the chosen component, each with its own control. Deliberately a list of rows and
   not a select: a select has a selected option from the moment it is drawn, so a version nobody
   touched would be the version sent — which is "whatever is latest" wearing a manifest's clothes. */

.version-choices {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.version-choice {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-soft);
}

.version-choice-identity {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.version-choice-identity strong {
  font:
    650 13px/1.3 'Manrope',
    system-ui,
    sans-serif;
  color: var(--ink-strong);
}

.version-choice-identity small {
  color: var(--muted);
  font-size: 11px;
  overflow-wrap: anywhere;
}

.version-choice-note {
  color: var(--ink);
}

.version-choice .button {
  padding: 6px 10px;
  font-size: 12px;
  white-space: nowrap;
}

/* One piece of copy being written. The same shape a footnote field has, because it is the same kind
   of thing: two fields and the controls that move them, told apart from its neighbours by a card
   rather than by an indent. */

.copy-field {
  display: grid;
  gap: 6px;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-soft);
}

/* ---------------------------------------------------------------- key messages

   What a version says, on the component screen that reads it. Read-only: there is no operation that
   edits a tree or attaches one, so nothing below is a control, and nothing below should acquire the
   look of one — a call to action is a kind of statement on the record, not a button.

   Our own classes rather than the prototype's, for the reason recorded at every other rule in this
   file: an inherited column track has broken three separate surfaces here, and restating only
   `display` and `gap` does not help because the cascade is per property.

   A node's kind is a word and a left rule, never a `.pill-badge`. `npm run vocabularies:check` holds
   each badge vocabulary to a silhouette and an ink set, and what kind of statement a node is is none
   of them — the same reading that keeps a Resources category and a deliverable's manifest off the
   badge. Nothing here declares `--pill-ink`, and nothing here should. */

.key-message-list {
  display: grid;
  gap: 12px;
  margin-bottom: 18px;
}

.key-message-description {
  color: var(--ink);
  font-size: 13px;
  line-height: 1.55;
  max-width: 74ch;
}

/* The supporting messages, numbered in their own gutter because the recorded order is a fact about
   the message. The number is the author's sequence and not a rank: this build ranks nothing, and the
   plain counter is the same treatment `.manifest-row` gives a part's position. */

.message-node-list {
  display: grid;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: supporting;
}

.message-node-list > li {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  position: relative;
  padding-left: 24px;
  counter-increment: supporting;
}

.message-node-list > li::before {
  content: counter(supporting);
  position: absolute;
  left: 0;
  top: 12px;
  color: var(--subtle);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.message-node {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: 10px;
  background: var(--surface-soft);
}

/* The two kinds, told apart by the rule down the side as well as by the word above the statement.
   A reader who meets only one node still has the word; a reader scanning several has the colour. */

.message-node-statement {
  border-left-color: var(--teal);
}

.message-node-call-to-action {
  border-left-color: var(--amber);
  background: var(--amber-soft);
}

.message-node-kind {
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.message-node-call-to-action .message-node-kind {
  color: var(--amber);
}

.message-statement {
  margin: 0;
  color: var(--ink-strong);
  font-size: 14px;
  line-height: 1.5;
  max-width: 74ch;
  overflow-wrap: anywhere;
}

/* The figure, and the caption saying whose it is. The author wrote it and nothing recomputes it —
   the same distinction a stored object's established size and its claimed hash are drawn with. */

.message-value {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 0;
}

.message-value small {
  color: var(--muted);
  font-size: 10px;
}

.message-value strong {
  font:
    650 15px/1.3 'Manrope',
    system-ui,
    sans-serif;
  color: var(--ink-strong);
  font-variant-numeric: tabular-nums;
}

.message-footnotes {
  display: grid;
  gap: 3px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.message-footnotes li {
  display: flex;
  gap: 6px;
  color: var(--muted);
  font-size: 11px;
  line-height: 1.5;
}

.message-footnote-marker {
  color: var(--ink-strong);
  font-variant-numeric: tabular-nums;
}

/* A cited reference, read back. The words are the picker's, because one module owns how a reference
   is put in front of a person; this is the same reference without the checkbox — plus where the
   record stands, which the picker never needs because it only ever offers active ones.

   The standing badge is the evidence library's own (`Ui.standingBadge`), so nothing here may restate
   its colour or its shape: the rules below are scoped to our own element classes rather than to the
   bare `span` they used to select, because a descendant selector on `span` outranks `.pill-badge` at
   equal specificity and would quietly repaint a vocabulary this file does not own. */

.citation-list {
  display: grid;
  gap: 3px;
}

.citation-list-caption {
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.citation-cited {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  padding: 6px 0 0;
}

.citation-cited-citation {
  color: var(--ink);
  font-size: 12px;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.citation-cited-state {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 2px 0 1px;
}

.citation-cited-state small {
  color: var(--muted);
  font-size: 10px;
}

.citation-cited > small {
  color: var(--muted);
  font-size: 11px;
}

/* ------------------------------------------------- composing a key message

   The other half of the section above: writing what a version will say, on the form that creates
   that version. Everything here IS a control, which is the whole difference from the read side —
   so nothing here borrows the read side's classes, and the read side's rule about a call to action
   never looking like a button does not apply to a form where every node is being edited.

   Our own classes rather than the prototype's, for the reason recorded at every other rule in this
   file: an inherited column track has broken three separate surfaces here, and restating only
   `display` and `gap` does not help because the cascade is per property.

   No `--pill-ink` anywhere below, and none should appear. `npm run vocabularies:check` holds each
   badge vocabulary to a silhouette and an ink set, and what kind of statement a node is is none of
   them — the same reading that keeps this off a badge where it is read. */

.key-message-compose {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

/* One node's fields, told apart from its neighbours by an indent and a rule rather than by a card:
   a nested card inside a card inside a card reads as three levels of importance, and these are one
   statement among several. */

.key-message-compose .subsection .subsection {
  margin-left: 10px;
  padding-left: 12px;
  border-left: 2px solid var(--line);
}

.footnote-fields,
.supporting-fields {
  display: grid;
  gap: 10px;
  min-width: 0;
}

.footnote-field {
  display: grid;
  gap: 6px;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-soft);
}

/* Where a supporting message sits and how it moves. The buttons wrap rather than compress, because
   a card column here is narrow and a truncated "Remove this supporting message" is a control
   nobody can read before pressing. */

.node-ordering {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.node-ordering .button {
  padding: 6px 10px;
  font-size: 12px;
}

/* How many references this version would cite, against the bound the contract publishes. The count
   is a number and the sentence beside it is the contract's own; neither is a treatment that says
   the API has refused anything, because nothing has been sent. */

.citation-ceiling {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}

.citation-ceiling > small {
  color: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.citation-ceiling-over > small {
  color: var(--red);
  font-weight: 650;
}

/* What a form cannot be sent for yet. Deliberately not `.failure-panel`: nothing has been sent and
   nothing has been refused, so this must not wear the treatment that says the API answered no. */

.not-ready {
  margin: 10px 0;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  background: var(--surface-soft);
}

.not-ready > small {
  color: var(--muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.not-ready ul {
  margin: 6px 0 0;
  padding-left: 18px;
  display: grid;
  gap: 4px;
}

.not-ready li {
  color: var(--ink);
  font-size: 12px;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- corrections

   What a record used to say, drawn where a person meets what it says now (captain's decision,
   2026-08-16: a correction appends, it never erases).

   Our own classes rather than the prototype's, for the reason recorded at every other rule in this
   file: an inherited column track has broken three separate surfaces here, and restating only
   `display` and `gap` does not help because the cascade is per property.

   A correction is a list and never a badge. This build's badge vocabularies each answer "what kind
   of thing is this", and a correction is neither a kind of claim nor a state — the same reading
   that keeps a Resources category and a deliverable's manifest off the badge. Nothing below
   declares `--pill-ink`, and nothing here should acquire one. */

.correction-list {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.correction-row {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
}

/* The two values and the word between them. It wraps rather than truncating: a name is the thing
   being read here, and half a name is worse than a long row. */
.correction-move {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

.correction-move strong {
  font:
    650 13px/1.35 'Manrope',
    system-ui,
    sans-serif;
  color: var(--ink-strong);
  overflow-wrap: anywhere;
}

/* Not an arrow glyph: the relationship is stated in words, so a screen reader meets the same
   sentence a sighted reader does. */
.correction-arrow {
  color: var(--muted);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.correction-row small {
  color: var(--muted);
  font-size: 11px;
}

/* ── The chromeless address of a published view ──────────────────────────────────────────────
   A view the contract publishes has an address that shows the screen and nothing else, so a tool
   can hand somebody the live screen rather than a picture of one. `Page.chromeless` has the
   argument for what it keeps and drops.

   Its own tracks, per the rule at the top of this file: `.app-shell` declares a two-column grid
   with a fixed sidebar, and reusing it here would leave a column of empty sidebar beside the
   content. This is a single column with no sidebar and no dock, so it says so. */
.embed-shell {
  min-height: 100vh;
  display: grid;
  grid-template-rows: 1fr auto;
  background: var(--paper);
}

.embed-main {
  width: 100%;
  max-width: 1040px;
  margin: 0 auto;
  padding: 30px 32px 24px;
}

/* Not the bottom dock: it states no authority and offers no switcher, because a chromeless view
   has neither. It says which screen this is and where the workspace is, quietly. */
.embed-foot {
  padding: 14px 32px 22px;
  border-top: 1px solid var(--line);
}

.embed-foot small {
  display: block;
  max-width: 1040px;
  margin: 0 auto;
  color: var(--subtle);
  font-size: 11px;
}

/* The browser's own words about why a credential could not be renewed, printed rather than
   paraphrased. Muted and small because it is a diagnostic beneath the sentence that matters, and
   never a badge: this is not a standing, a lifecycle or an entry kind. */
.signed-out-reason {
  margin: 0 auto 15px;
  max-width: 400px;
  color: var(--subtle);
  font-size: 11px;
}
