/* SemText — vocabulary base
   Theme-independent structure: layout, spacing, the component rules, and the
   hide/show gating. Reads --sem-* custom properties but
   declares none — pair with a theme file such as themes/minimal-tech-light.css
   for values.

   BOTH AUTHORING FORMS FROM ONE RULE (D10). Every vocabulary selector is
   `:is(sem-x, .sem-x)`: the canonical custom element and its class-form
   alias (conventions Appendix A) render identically, before or without
   the Lit upgrade (conventions §4 rule 3). Element-form children use their
   bare tags (`<statement>`, `<highlight>`, `<name>`); the alias uses
   `.sem-*`. Parameters are read in both spellings where a rule must hold
   with NO script (`[status]`/`[data-status]`); a bare-spelling rule that
   renders `attr(<name>)` is guarded with `:not([data-<name>])` so `data-*`
   wins when both are present (conventions §2), while a value selector
   (`:is([data-status="done"], [status="done"])`) needs no guard — both
   spellings of one value yield one declaration. Rules that only apply once
   the script is driving the element key on the `data-*` spelling alone,
   which the core handler mirrors from the bare attribute before any other
   handler runs.

   HIDE RULES ARE GATED (D12). Nothing in this file hides content unless
   the marker `[data-sem-upgraded]` says the script is driving it — on the
   element that owns the behavior (claimed by the Lit component at
   connect, stamped by the vanilla handler when it wires the element), or
   on `<html>` for rules whose host is deliberately unmarked.
   With no script, every distractor, view, conclusion and body renders. */

/* ── default palette ──
   The file still "declares none" in the theme sense — these are the
   fallback values a page gets when it loads the vocabulary WITHOUT a
   theme (embedded panes, islands, quick embeds): every --sem-* resolves
   instead of falling back to nothing (transparent surfaces, invisible
   occlusions, borderless modals — the 0.9.0 defect class). `:where(html)`
   has ZERO specificity, so any theme mount ([data-sem-theme] rules, loaded
   before OR after this file) overrides every value here; a theme that
   declares all fourteen still changes nothing for its own pages. Values =
   minimal-tech-light, the reference palette. */
:where(html) {
  --sem-bg: #fafafa;
  --sem-surface: #ffffff;
  --sem-fg: #1e293b;
  --sem-muted: #64748b;
  --sem-border: #e2e8f0;
  --sem-accent: #2563eb;
  --sem-accent-fg: #ffffff;
  --sem-note-info: #2563eb;
  --sem-note-tip: #059669;
  --sem-note-warning: #d97706;
  --sem-note-danger: #dc2626;
  --sem-correct: #059669;
  --sem-wrong: #dc2626;
  --sem-occluded: #94a3b8;
}

body { margin: 0; }
/* Paint the element that carries the theme, not <body>: themes may mount
   on an embedded subtree (data-sem-theme on a pane div), where the tokens
   are invisible at body scope — an unguarded body rule then resolves
   var(--sem-fg) to nothing and resets page text to UA black over the
   host's dark background. [data-sem-theme] covers html/body mounts too. */
[data-sem-theme] { background: var(--sem-bg); color: var(--sem-fg); }
/* Document mount paints the viewport body as well — the R/W2 colour
   control's e2e contract asserts the body background in both modes.
   Guarded to the html carrier so an embedded pane mount (theme on a
   div) never leaks tokens onto the host document's body. */
html[data-sem-theme] body { background: var(--sem-bg); color: var(--sem-fg); }
:is(sem-enhanced-document, .sem-enhanced-document) { font-family: system-ui, sans-serif; line-height: 1.6; }

/* Custom elements are inline by default; the vocabulary is block-level. */
sem-enhanced-document, sem-agent, sem-audiences, sem-note, sem-facts, sem-fact,
sem-details, sem-detail, sem-procedure, sem-step, sem-properties, sem-property,
sem-views, sem-view, sem-reveal, sem-progress, sem-quota-meter, sem-question, sem-option,
sem-chronology, sem-event, sem-code, sem-references, sem-reference, sem-reader, sem-table, sem-source, sem-md,
sem-data-visualizer, sem-data-source, sem-tldr,
sem-agent > :is(name, bio, instructions), sem-fact > :is(statement, conclusion, incorrect-statement) { display: block; }
/* The audience fallback hides with the native attribute; keep it winning
   over the block rule above for element forms — and in every scope: doc
   panes ([data-sem-theme] roots without a sem-enhanced-document wrapper)
   carry the same vocabulary. */
:is([hidden], [data-sem-theme] [hidden], sem-enhanced-document [hidden], .sem-enhanced-document [hidden]) { display: none !important; }

/* motion — smooth anchor scrolling only for readers who did not opt out */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  :is(highlight, .sem-highlight, .sem-occluded, .sem-revealed, .sem-target) { transition: none !important; animation: none !important; }
}

/* deep-link target (transient runtime class set by fallback/target) */
.sem-target { outline: 2px solid var(--sem-accent); outline-offset: 4px; border-radius: 8px;
  transition: outline-color .6s; }

/* metadata */
:is(sem-agent, .sem-agent) { border: 1px solid var(--sem-border); border-radius: 12px;
  padding: 1rem; margin: 1.5rem 0; background: var(--sem-surface); }
:is(sem-agent, .sem-agent) :is(name, .sem-agent-name) { font-weight: 600; }
:is(sem-agent, .sem-agent) :is(bio, .sem-agent-bio) { color: var(--sem-muted); margin: .25rem 0; }
:is(sem-agent, .sem-agent) :is(instructions, .sem-agent-instructions) { font-size: .875rem; margin: .25rem 0 0; }

/* audiences — profile declarations render as a muted metadata strip */
:is(sem-audiences, .sem-audiences) { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center;
  margin: 1rem 0; font-size: .8rem; color: var(--sem-muted); }
:is(sem-audiences, .sem-audiences)::before { content: "audiences ·"; letter-spacing: .05em; text-transform: uppercase; font-size: .7rem; }
:is(sem-profile, .sem-profile) { display: inline-block; border: 1px solid var(--sem-border); border-radius: 999px;
  padding: .1rem .6rem; background: var(--sem-surface); }
:is(sem-profile, .sem-profile)::before { content: attr(id); }
:is(sem-profile, .sem-profile)[data-label]::before { content: attr(data-label); }
:is(sem-profile, .sem-profile)[label]:not([data-label])::before { content: attr(label); }

/* note */
:is(sem-note, .sem-note) { border-left: 4px solid var(--sem-note-info); border-radius: 8px;
  padding: .75rem 1rem; margin: 1rem 0; background: var(--sem-surface); }
:is(sem-note, .sem-note):is([data-variant="warning"], [variant="warning"]) { border-color: var(--sem-note-warning); }
:is(sem-note, .sem-note):is([data-variant="tip"], [variant="tip"])     { border-color: var(--sem-note-tip); }
:is(sem-note, .sem-note):is([data-variant="danger"], [variant="danger"])  { border-color: var(--sem-note-danger); }
:is(sem-note, .sem-note)[variant]:not([data-variant])::before { content: attr(variant) " · "; }
:is(sem-note, .sem-note):is([data-variant], [variant])::before { content: attr(data-variant) " · ";
  font-size: .75rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--sem-muted); display: block; }
:is(sem-note, .sem-note)[data-sem-upgraded][collapsed] > .sem-note-body { display: none; }
:is(sem-note, .sem-note)[collapsed] .sem-note-summary { cursor: pointer; color: var(--sem-accent); }
/* view-as="margin": floated aside on wide viewports, inline callout
   otherwise. Floats INSIDE the container by default; a document whose
   wrapper has a gutter can push it out with
   --sem-margin-offset: calc(-1 * (var(--sem-margin-width) + 1.5rem)). */
@media (min-width: 64rem) {
  :is(sem-note, .sem-note):is([data-view-as="margin"], [view-as="margin"]) { float: right; clear: right;
    width: var(--sem-margin-width, 14rem);
    margin: 0 var(--sem-margin-offset, 0) 1rem 1.5rem;
    font-size: .875rem; }
}

/* facts */
:is(sem-facts, .sem-facts) { margin: 1.5rem 0; }
.sem-facts-chrome { display: flex; gap: .5rem; align-items: center; margin: .5rem 0; }
.sem-facts-chrome button { font: inherit; border: 1px solid var(--sem-border); background: var(--sem-surface);
  color: var(--sem-fg); border-radius: 8px; padding: .25rem .75rem; cursor: pointer; }
.sem-facts-meter { color: var(--sem-muted); font-size: .875rem; }
:is(sem-fact, .sem-fact) { border: 1px solid var(--sem-border); border-radius: 12px;
  padding: 1rem; margin: .75rem 0; background: var(--sem-surface); }
:is(sem-fact, .sem-fact) :is(statement, .sem-statement) { font-weight: 600; }
:is(sem-fact, .sem-fact) :is(conclusion, .sem-conclusion) { margin: .5rem 0 0; color: var(--sem-muted); }
/* distractors are quiz decoys: hidden once a script drives the document,
   labelled and readable when none does (D12) */
:root[data-sem-upgraded] :is(sem-fact, .sem-fact) :is(incorrect-statement, .incorrect-statement) { display: none; }
:root:not([data-sem-upgraded]) :is(sem-fact, .sem-fact) :is(incorrect-statement, .incorrect-statement) {
  margin: .5rem 0 0; color: var(--sem-muted); font-size: .875rem; }
:root:not([data-sem-upgraded]) :is(sem-fact, .sem-fact) :is(incorrect-statement, .incorrect-statement)::before {
  content: "incorrect statement · "; font-variant-caps: all-small-caps; letter-spacing: .05em; }
/* quiz + flashcards (hide rules gated on the tier marker — JS-off stays readable) */
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="quiz"] :is(sem-fact, .sem-fact) :is(conclusion, .sem-conclusion) { display: none; }
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(sem-fact, .sem-fact) { display: none; cursor: pointer;
  min-height: 8rem; position: relative; }
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(sem-fact, .sem-fact).sem-current { display: block; }
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(sem-fact, .sem-fact) :is(conclusion, .sem-conclusion) { visibility: hidden; }
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(sem-fact, .sem-fact).sem-flipped :is(conclusion, .sem-conclusion) { visibility: visible; }
.sem-quiz-options { display: grid; gap: .5rem; margin-top: .75rem; }
.sem-quiz-options button { font: inherit; text-align: left; border: 1px solid var(--sem-border);
  background: var(--sem-surface); color: var(--sem-fg); border-radius: 8px;
  padding: .5rem .75rem; cursor: pointer; }
.sem-quiz-options button[data-correct="true"].sem-answered { border-color: var(--sem-correct); }
.sem-quiz-options button.sem-wrong-pick { border-color: var(--sem-wrong); }
/* a picked-wrong option is spent: dimmed and inert, the reader keeps
   picking until the correct option lands (0.9.1 contract) */
.sem-quiz-options button.sem-wrong-pick { cursor: default; opacity: .7; }
.sem-score { font-size: .875rem; color: var(--sem-muted); }
/* flashcard verdicts (✓ got it / ✗ wrong): authored nowhere, appended by
   the deck wiring inside each card; hidden until that card is flipped and
   the current one (hide rules stay marker-gated, D12) */
.sem-facts-verdict { display: none; gap: .5rem; margin-top: .75rem; }
.sem-facts-verdict button { font: inherit; font-weight: 600; border: 1px solid var(--sem-border);
  background: var(--sem-surface); border-radius: 8px; padding: .375rem .875rem; cursor: pointer; }
.sem-facts-verdict button[data-verdict="got"] { color: var(--sem-correct); border-color: var(--sem-correct); }
.sem-facts-verdict button[data-verdict="miss"] { color: var(--sem-wrong); border-color: var(--sem-wrong); }
.sem-facts-summary { margin: .75rem 0; padding: .75rem 1rem; border: 1px solid var(--sem-border);
  border-radius: 12px; background: var(--sem-surface); font-weight: 600; }
.sem-facts-summary .sem-facts-verdict { display: flex; }

/* details + highlight */
:is(sem-details, .sem-details) { margin: 1rem 0; }
:is(sem-detail, .sem-detail) { border: 1px solid var(--sem-border); border-radius: 12px;
  padding: 1rem; margin: .75rem 0; background: var(--sem-surface); cursor: pointer; }
:is(highlight, .sem-highlight) { font-style: normal; background: color-mix(in srgb, var(--sem-accent) 18%, transparent);
  border-radius: 4px; padding: 0 .2em; }
.sem-occluded { color: transparent; background: var(--sem-occluded); border-radius: 4px;
  cursor: pointer; user-select: none; transition: color .15s; min-width: 3ch; display: inline-block; }
.sem-revealed { color: inherit; background: color-mix(in srgb, var(--sem-accent) 18%, transparent); }

/* procedure */
:is(sem-procedure, .sem-procedure) { margin: 1rem 0; }
:is(sem-step, .sem-step) { counter-increment: sem-step; border-left: 3px solid var(--sem-border);
  padding: .5rem .75rem .5rem 2.25rem; margin: .25rem 0; position: relative;
  background: var(--sem-surface); border-radius: 0 8px 8px 0; }
:is(sem-step, .sem-step)::before { content: counter(sem-step); position: absolute; left: .6rem;
  top: .5rem; font-size: .75rem; color: var(--sem-muted); }
:is(sem-step, .sem-step):is([data-status="done"], [status="done"])::after { content: " ✓"; color: var(--sem-correct); }
:is(sem-step, .sem-step):is([data-status="current"], [status="current"]) { border-left-color: var(--sem-accent); }
:is(sem-step, .sem-step):is([data-status="current"], [status="current"])::after { content: " →"; color: var(--sem-accent); }
:is(sem-step, .sem-step):is([data-status="blocked"], [status="blocked"]) { border-left-color: var(--sem-wrong); color: var(--sem-muted); }
:is(sem-step, .sem-step):is([data-status="blocked"], [status="blocked"])::after { content: " ⛔"; color: var(--sem-wrong); }

/* ── sem-procedure ── */
/* todo steps: explicit `[status="todo"]` and the schema default (no
   status attribute at all). Dashed rule + ring glyph, the same todo
   marker sem-chronology events wear; an unstarted step stays fully
   legible — only the marker is muted. */
:is(sem-step, .sem-step):is([data-status="todo"], [status="todo"]),
:is(sem-step, .sem-step):not([data-status]):not([status]) {
  border-left-style: dashed;
}
:is(sem-step, .sem-step):is([data-status="todo"], [status="todo"])::after,
:is(sem-step, .sem-step):not([data-status]):not([status])::after {
  content: " ○"; color: var(--sem-muted);
}
/* ── end sem-procedure ── */

/* ── sem-step ── */
/* Status glyphs glue to the step's last word. Each ::after content
   begins with a plain space, which is a soft-wrap point: on a step whose
   text wraps (narrow panes, ~330px and under), the ✓/→/○/⛔ could
   orphan alone on its own line, reading as stray chrome. `nowrap`
   collapses the leading space to one space but forbids breaking inside
   the pseudo, so the glyph always rides with the word it annotates —
   a step that cannot fit wraps its last word and glyph together. */
:is(sem-step, .sem-step)::after { white-space: nowrap; }
/* ── end sem-step ── */

/* ── sem-bind hydration chrome ── */
/* The sem-bind runtime writes per-step status as `data-sem-bind-status`
   (the payload's exact spelling: complete|pending|error|skipped|none)
   PLUS the mapped catalog attribute (done|todo|blocked) so the glyphs
   above keep rendering. `skipped` and `none` have no catalog spelling —
   skipped gets its own muted marker; none clears both attributes. */
:is(sem-step, .sem-step)[data-sem-bind-status="skipped"] {
  border-left-style: dotted; color: var(--sem-muted);
}
:is(sem-step, .sem-step)[data-sem-bind-status="skipped"]::after {
  content: " ↷"; color: var(--sem-muted);
}
/* Bind payload chrome — comment line under a step, the taken fork(s),
   and the never-blank state line a bound element renders while loading,
   on error or when a payload comes back empty. */
.sem-bind-comment { color: var(--sem-muted); font-size: .85em; margin-top: .25rem; }
.sem-bind-choice { margin-top: .3rem; font-size: .9em; }
.sem-bind-choice-label { font-variant-caps: all-small-caps; color: var(--sem-muted); margin-right: .35em; }
.sem-bind-choice-option { font-weight: 600; }
.sem-bind-choice-reason { color: var(--sem-muted); }
.sem-bind-choice-walk { margin: .3rem 0 0; padding-left: 1.25rem; }
.sem-bind-choice-walk li { margin: .15rem 0; }
.sem-bind-state { font-size: .85em; margin-top: .25rem; }
.sem-bind-state:is(.sem-bind-error) { color: var(--sem-wrong); }
.sem-bind-state:is(.sem-bind-pending) { color: var(--sem-muted); }
.sem-bind-state:is(.sem-bind-empty) { color: var(--sem-muted); font-style: italic; }
/* sem-progress payload meter rides the same track/fill chrome the
   vanilla handler builds; only the caption row is its own. */
.sem-bind-progress-label { display: block; font-size: .85em; color: var(--sem-muted); }
/* ── end sem-bind ── */

/* properties */
:is(sem-properties, .sem-properties) { margin: 1rem 0; border: 1px solid var(--sem-border);
  border-radius: 12px; overflow: hidden; background: var(--sem-surface); }
:is(sem-property, .sem-property) { display: grid; grid-template-columns: minmax(8rem, 1fr) 2fr;
  gap: .75rem; padding: .5rem .9rem; }
:is(sem-property, .sem-property):nth-child(even) { background: color-mix(in srgb, var(--sem-border) 40%, transparent); }
:is(sem-property, .sem-property)::before { content: attr(data-key); color: var(--sem-muted);
  font-variant-caps: all-small-caps; }
:is(sem-property, .sem-property)[key]:not([data-key])::before { content: attr(key); }
/* narrow viewports: key above value instead of a squeezed value column */
@media (max-width: 34rem) {
  :is(sem-property, .sem-property) { grid-template-columns: minmax(0, 1fr); gap: .15rem; overflow-wrap: break-word; }
}

/* properties — glossary view (R/W1): term over definition; anchors get a
   preview from the reading bundle; :target highlight works with no script */
:is(sem-properties, .sem-properties):is([data-view-as="glossary"], [view-as="glossary"]) :is(sem-property, .sem-property) {
  display: block; padding: .6rem .9rem; }
:is(sem-properties, .sem-properties):is([data-view-as="glossary"], [view-as="glossary"]) :is(sem-property, .sem-property)::before {
  display: block; font-weight: 600; font-variant-caps: normal; color: var(--sem-fg); margin-bottom: .15rem; }
:is(sem-property, .sem-property):target { background: color-mix(in srgb, var(--sem-accent) 12%, transparent); }
:is(sem-enhanced-document, .sem-enhanced-document) dfn { font-style: normal; font-weight: 600; }
/* in-document links read against either colour scheme (citations, terms) */
:is(sem-enhanced-document, .sem-enhanced-document) a { color: var(--sem-accent); }
.sem-properties-ref { text-decoration: underline dotted; text-underline-offset: .15em; }

/* ── sem-property ── */
/* Child-scoped. Schema rendered form: "keys wrap, values keep
   whitespace" — the value is the element's own text, so pre-wrap keeps
   the author's line breaks; break-word stops a long unbroken token from
   spilling past the value column at any width. The row/grid rules above
   are the shared container's and are left untouched. */
:is(sem-property, .sem-property) { white-space: pre-wrap; overflow-wrap: break-word; }
/* ── end sem-property ── */

/* ── sem-chronology ── */
/* chronology — CSS-only timeline (pattern: procedure). The rail is the
   container's left border; each event's own left border is its status
   marker, drawn over the same line so rail and marker read as one.
   Date label: the authored <time> child, else attr(when) via ::before. */
:is(sem-chronology, .sem-chronology) { margin: 1.5rem 0; padding-left: 0;
  border-left: 2px solid var(--sem-border); }
:is(sem-chronology, .sem-chronology):is([data-view-as="list"], [view-as="list"]) { border-left: 0; padding-left: 0; }
:is(sem-event, .sem-event) { position: relative; margin: 0 0 .75rem; padding: .5rem .9rem;
  background: var(--sem-surface); border: 1px solid var(--sem-border);
  border-left: 3px solid var(--sem-border); border-radius: 0 10px 10px 0; }
:is(sem-event, .sem-event) > time { display: block; font-size: .75rem; color: var(--sem-muted);
  font-variant-caps: all-small-caps; letter-spacing: .05em; }
:is(sem-event, .sem-event):not(:has(time))::before { content: attr(data-when); display: block;
  font-size: .75rem; color: var(--sem-muted); font-variant-caps: all-small-caps; letter-spacing: .05em; }
:is(sem-event, .sem-event):not(:has(time)):is([data-until], [until])::before { content: attr(data-when) " – " attr(data-until); }
:is(sem-event, .sem-event):not(:has(time))[when]:not([data-when])::before { content: attr(when); }
:is(sem-event, .sem-event):not(:has(time))[when][until]:not([data-when])::before { content: attr(when) " – " attr(until); }
/* mixed spellings: `when` mirrors `data-when` and `until` mirrors `data-until`;
   a period authored half in each spelling still shows both dates. */
:is(sem-event, .sem-event):not(:has(time))[data-when][until]:not([data-until])::before { content: attr(data-when) " – " attr(until); }
:is(sem-event, .sem-event):not(:has(time))[when][data-until]:not([data-when])::before { content: attr(when) " – " attr(data-until); }
:is(sem-event, .sem-event):is([data-status="done"], [status="done"]) { border-left-color: var(--sem-correct); }
:is(sem-event, .sem-event):is([data-status="done"], [status="done"])::after { content: " ✓"; color: var(--sem-correct); }
:is(sem-event, .sem-event):is([data-status="current"], [status="current"]) { border-left-color: var(--sem-accent); }
:is(sem-event, .sem-event):is([data-status="current"], [status="current"])::after { content: " →"; color: var(--sem-accent); }
:is(sem-event, .sem-event):is([data-status="todo"], [status="todo"]) { border-left-color: var(--sem-muted); border-left-style: dashed; }
:is(sem-event, .sem-event):is([data-status="todo"], [status="todo"])::after { content: " ○"; color: var(--sem-muted); }
:is(sem-event, .sem-event):is([data-status="blocked"], [status="blocked"]) { border-left-color: var(--sem-wrong); color: var(--sem-muted); }
:is(sem-event, .sem-event):is([data-status="blocked"], [status="blocked"])::after { content: " ⛔"; color: var(--sem-wrong); }
/* Status glyphs glue to the event's last word — the same soft-wrap
   orphan the step marker had (mirrors the sem-step fix above): on a
   narrow pane (~330px and under) the ✓/→/○/⛔ could wrap alone onto
   its own line, reading as stray chrome. `nowrap` collapses the
   leading space but forbids breaking inside the pseudo, so the glyph
   always rides the word it annotates. */
:is(sem-event, .sem-event)::after { white-space: nowrap; }
/* list view — no rail; plain stacked rows, the date inline with the prose.
   The event's own left rule keeps the status marker in every view; the
   card surface drops away. */
:is(sem-chronology, .sem-chronology):is([data-view-as="list"], [view-as="list"]) :is(sem-event, .sem-event) {
  background: transparent; border-top-width: 0; border-right-width: 0;
  border-bottom-width: 0; border-radius: 0; padding: .2rem .9rem .2rem .75rem;
  margin: 0 0 .4rem; }
:is(sem-chronology, .sem-chronology):is([data-view-as="list"], [view-as="list"]) :is(sem-event, .sem-event) > time { display: inline; margin-right: .5rem; }
:is(sem-chronology, .sem-chronology):is([data-view-as="list"], [view-as="list"]) :is(sem-event, .sem-event):not(:has(time))::before { display: inline; margin-right: .5rem; }
/* ── end sem-chronology ── */

/* code — verbatim listing; chrome (reading bundle / Lit) is the first
   child; JS-off the filename is a CSS caption instead */
:is(sem-code, .sem-code) { margin: 1.25rem 0; border: 1px solid var(--sem-border); border-radius: 12px;
  background: var(--sem-surface); overflow: hidden; }
:is(sem-code, .sem-code) pre { margin: 0; padding: .9rem 1rem; overflow-x: auto; font-size: .875rem;
  line-height: 1.5; tab-size: 2; }
:is(sem-code, .sem-code):is([data-wrap], [wrap]) pre { white-space: pre-wrap; overflow-wrap: anywhere; }
:is(sem-code, .sem-code):not(:has(> .sem-code-chrome)):is([data-filename], [filename])::before {
  content: attr(data-filename); display: block; padding: .4rem 1rem; font-size: .75rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--sem-muted);
  border-bottom: 1px solid var(--sem-border); }
:is(sem-code, .sem-code):not(:has(> .sem-code-chrome))[filename]:not([data-filename])::before { content: attr(filename); }
.sem-code-chrome { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; padding: .4rem .75rem;
  border-bottom: 1px solid var(--sem-border); font-size: .75rem; color: var(--sem-muted); }
.sem-code-filename { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.sem-code-lang { border: 1px solid var(--sem-border); border-radius: 999px; padding: 0 .5rem;
  text-transform: uppercase; letter-spacing: .05em; font-size: .7rem; }
.sem-code-chrome button { border: 1px solid var(--sem-border); background: var(--sem-bg); color: var(--sem-fg);
  border-radius: 6px; padding: .15rem .6rem; cursor: pointer; font: inherit; }
.sem-code-chrome button:first-of-type { margin-left: auto; }
.sem-code-chrome button[aria-pressed="true"] { border-color: var(--sem-accent); color: var(--sem-accent); }
.sem-code-status { min-width: 3.5rem; font-size: .7rem; }
mark.sem-code-line { display: inline-block; width: 100%; color: inherit;
  background: color-mix(in srgb, var(--sem-accent) 14%, transparent);
  box-shadow: -1rem 0 0 color-mix(in srgb, var(--sem-accent) 14%, transparent); }

/* markdown — the element's text is Markdown; the Markdown bundle (or the
   Lit wrapper) renders it into .sem-md-body and keeps the normalised
   source in a sem-code fence (.sem-md-raw). With no tier marker nothing
   was generated, so the source itself reads as pre-wrapped text. */
:is(sem-md, .sem-md) { margin: 1.25rem 0; border: 1px solid var(--sem-border); border-radius: 12px;
  background: var(--sem-surface); overflow: hidden; }
:is(sem-md, .sem-md):not([data-sem-upgraded]) { white-space: pre-wrap; overflow-wrap: anywhere;
  padding: .9rem 1rem; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .875rem; line-height: 1.5; }
:is(sem-md, .sem-md):not([data-sem-upgraded]):is([data-label], [label])::before {
  content: attr(data-label); display: block; margin: -.9rem -1rem .6rem; padding: .4rem 1rem; font-size: .75rem;
  font-family: system-ui, sans-serif; color: var(--sem-muted); border-bottom: 1px solid var(--sem-border); white-space: normal; }
:is(sem-md, .sem-md):not([data-sem-upgraded])[label]:not([data-label])::before { content: attr(label); }
.sem-md-chrome { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; padding: .4rem .75rem;
  border-bottom: 1px solid var(--sem-border); font-size: .75rem; color: var(--sem-muted); }
.sem-md-label { font-weight: 600; color: var(--sem-fg); }
.sem-md-chrome button { border: 1px solid var(--sem-border); background: var(--sem-bg); color: var(--sem-fg);
  border-radius: 6px; padding: .15rem .6rem; cursor: pointer; font: inherit; }
.sem-md-chrome button:first-of-type { margin-left: auto; }
.sem-md-chrome button[aria-pressed="true"] { border-color: var(--sem-accent); color: var(--sem-accent); }
.sem-md-status { min-width: 3.5rem; font-size: .7rem; }
.sem-md-body { padding: .75rem 1rem; }
.sem-md-body > :first-child { margin-top: 0; }
.sem-md-body > :last-child { margin-bottom: 0; }
.sem-md-body table { border-collapse: collapse; width: 100%; margin: .75rem 0; font-size: .9rem; }
.sem-md-body th, .sem-md-body td { border: 1px solid var(--sem-border); padding: .4rem .7rem; text-align: left; vertical-align: top; }
.sem-md-body th { font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
.sem-md-body blockquote { margin: .75rem 0; padding: .25rem 1rem; border-left: 4px solid var(--sem-border); color: var(--sem-muted); }
.sem-md-body pre { margin: .75rem 0; padding: .75rem 1rem; border: 1px solid var(--sem-border); border-radius: 8px;
  background: var(--sem-bg); overflow-x: auto; font-size: .875rem; line-height: 1.5; }
.sem-md-body :not(pre) > code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .9em;
  background: var(--sem-bg); border: 1px solid var(--sem-border); border-radius: 4px; padding: 0 .3em; }
.sem-md-body hr { border: 0; border-top: 1px solid var(--sem-border); margin: 1rem 0; }
.sem-md-body img { max-width: 100%; height: auto; }
.sem-md-raw > :is(sem-code, .sem-code) { margin: 0; border: 0; border-radius: 0; }
/* the two views (hide rules gated on the tier marker; JS-off neither exists) */
:is(sem-md, .sem-md)[data-sem-upgraded]:not([data-view-as="raw"]) > .sem-md-raw { display: none; }
:is(sem-md, .sem-md)[data-sem-upgraded][data-view-as="raw"] > .sem-md-body { display: none; }

/* references — CSS-counter numbering in every tier; previews and
   backlinks come from the reading bundle */
:is(sem-references, .sem-references) { margin: 2rem 0 1rem; padding-top: .75rem;
  border-top: 1px solid var(--sem-border); font-size: .875rem; counter-reset: sem-reference; }
:is(sem-reference, .sem-reference) { counter-increment: sem-reference; position: relative;
  padding: .2rem 0 .2rem 2.25rem; margin: .25rem 0; border-radius: 6px; }
:is(sem-reference, .sem-reference)::before { content: counter(sem-reference) "."; position: absolute;
  left: .5rem; color: var(--sem-muted); }
:is(sem-references, .sem-references):is([data-kind="bibliography"], [kind="bibliography"]) :is(sem-reference, .sem-reference) {
  padding-left: 2.75rem; }
:is(sem-references, .sem-references):is([data-kind="footnotes"], [kind="footnotes"]) { margin: 1rem 0 .5rem; padding-top: .25rem; }
:is(sem-references, .sem-references):is([data-kind="footnotes"], [kind="footnotes"]) :is(sem-reference, .sem-reference) { margin: .1rem 0; padding: .1rem 0 .1rem 1.75rem; }
:is(sem-references, .sem-references):is([data-kind="footnotes"], [kind="footnotes"]) :is(sem-reference, .sem-reference)::before { left: .25rem; }
:is(sem-reference, .sem-reference):target { background: color-mix(in srgb, var(--sem-accent) 12%, transparent); scroll-margin-top: calc(8px + var(--sem-reader-offset, 0px)); }
.sem-references-backlinks { margin-left: .4rem; }
.sem-references-backlinks a, .sem-references-link { text-decoration: none; margin-left: .3rem; color: var(--sem-accent); }
.sem-references-ref { text-decoration: none; border-bottom: 1px dotted var(--sem-accent); }

/* popover — one preview surface per document (src/shared/popover.ts);
   native `popover` where supported, fixed div otherwise. Author rules
   override the UA `inset: 0; margin: auto` of an open popover. */
.sem-popover { position: fixed; inset: auto; margin: 0; max-width: min(24rem, calc(100vw - 2rem));
  font-family: system-ui, sans-serif;
  padding: .6rem .8rem; border: 1px solid var(--sem-border); border-radius: 10px;
  background: var(--sem-surface); color: var(--sem-fg); box-shadow: 0 8px 24px rgba(0, 0, 0, .15);
  font-size: .875rem; line-height: 1.45; z-index: 50; }
.sem-popover[hidden] { display: none; }
.sem-popover-term { display: block; font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }

/* review canvas — agent-kit upsell stub (src/lit/sem-review-canvas.ts).
   Pins anchor by percentage via --sem-review-x/--sem-review-y in both the
   interactive tier and the authored zero-JS fallback. */
:is(sem-review-canvas, .sem-review-canvas) { display: block; margin: 1.5rem 0; }
.sem-review-stage { position: relative; margin: 0; }
.sem-review-stage .sem-review-shot-img { display: block; width: 100%; height: auto;
  border: 1px solid var(--sem-border); border-radius: 10px; }
.sem-review-pin { position: absolute; left: var(--sem-review-x); top: var(--sem-review-y);
  transform: translate(-50%, -50%); width: 1.5rem; height: 1.5rem; border-radius: 50%;
  border: 2px solid var(--sem-surface, #fff); background: var(--sem-accent); color: #fff;
  font: inherit; font-size: .75rem; font-weight: 600; line-height: 1;
  cursor: pointer; padding: 0; }
.sem-review-pin[data-resolved] { background: var(--sem-note-tip, #2e8b57); }
.sem-review-pin:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; }
.sem-review-pop { position: absolute; left: var(--sem-review-x); top: var(--sem-review-y);
  transform: translate(min(0px, calc(-100% + 1.75rem)), .9rem); max-width: 16rem;
  padding: .5rem .7rem; border: 1px solid var(--sem-border); border-radius: 8px;
  background: var(--sem-surface, #fff); color: var(--sem-fg);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .12); font-size: .8125rem; z-index: 5; }
.sem-review-pop-author { display: block; font-variant-caps: all-small-caps; letter-spacing: .05em;
  color: var(--sem-muted); }
.sem-review-pop-body { margin: .25rem 0 0; }
.sem-review-draft { position: absolute; left: var(--sem-review-x); top: var(--sem-review-y);
  transform: translate(min(0px, calc(-100% + 1.75rem)), .9rem); display: flex; gap: .3rem; z-index: 6; }
.sem-review-draft-input { font: inherit; font-size: .8125rem; padding: .3rem .5rem;
  border: 1px solid var(--sem-border); border-radius: 6px; background: var(--sem-surface, #fff);
  color: var(--sem-fg); min-width: 12rem; }
.sem-review-draft-add { font: inherit; font-size: .8125rem; padding: .3rem .6rem;
  border: 1px solid var(--sem-accent); border-radius: 6px; background: var(--sem-accent);
  color: #fff; cursor: pointer; }
.sem-review-verdict { display: flex; flex-wrap: wrap; gap: .75rem; margin: .75rem 0 0;
  padding: .5rem .75rem; border: 1px solid var(--sem-border); border-radius: 8px; }
.sem-review-verdict legend { font-variant-caps: all-small-caps; letter-spacing: .05em;
  color: var(--sem-muted); padding: 0 .35rem; }
.sem-review-verdict label { display: inline-flex; gap: .35rem; align-items: center; font-size: .875rem; }
.sem-review-verdict-label { margin: .5rem 0 0; font-size: .875rem; color: var(--sem-muted); }
.sem-review-verdict-label[data-verdict="approve"] { color: var(--sem-note-tip, #2e8b57); }
.sem-review-verdict-label[data-verdict="changes"] { color: var(--sem-note-danger, #b23a3a); }
.sem-review-verdict-label[data-verdict="comment"] { color: var(--sem-accent); }
/* zero-JS fallback: screenshot with inert pins, comments listed beside it;
   hidden once the interactive tier takes over (gated on the tier marker) */
.sem-review-fallback { display: grid; grid-template-columns: minmax(0, 3fr) minmax(12rem, 1fr); gap: 1rem; align-items: start; }
.sem-review-fallback .sem-review-stage { margin: 0; }
.sem-review-comments { margin: 0; padding-left: 1.1rem; font-size: .8125rem; }
.sem-review-comment { margin: .35rem 0; }
.sem-review-comment-resolved { color: var(--sem-muted); text-decoration: line-through; }
:is(sem-review-canvas, .sem-review-canvas)[data-sem-upgraded] .sem-review-fallback { display: none; }
@media (max-width: 40rem) { .sem-review-fallback { grid-template-columns: 1fr; } }

/* views */
:is(sem-views, .sem-views) { margin: 1.5rem 0; }
.sem-views-tabs { display: flex; gap: .25rem; border-bottom: 1px solid var(--sem-border); }
.sem-views-tabs button { font: inherit; border: 1px solid transparent; border-bottom: none;
  background: none; color: var(--sem-muted); border-radius: 8px 8px 0 0;
  padding: .4rem .9rem; cursor: pointer; }
.sem-views-tabs button[aria-selected="true"] { color: var(--sem-accent);
  border-color: var(--sem-border); background: var(--sem-surface); }
:is(sem-view, .sem-view) { border: 1px solid var(--sem-border); border-top: none;
  border-radius: 0 0 12px 12px; padding: 1rem; background: var(--sem-surface); }
/* one view at a time only while a script owns the tabs (D12); otherwise
   every view is stacked under its name */
:is(sem-views, .sem-views)[data-sem-upgraded] :is(sem-view, .sem-view) { display: none; }
:is(sem-views, .sem-views)[data-sem-upgraded] :is(sem-view, .sem-view)[data-active] { display: block; }
:is(sem-views, .sem-views):not([data-sem-upgraded]) :is(sem-view, .sem-view) { border-top: 1px solid var(--sem-border);
  border-radius: 12px; margin: .5rem 0; }
:is(sem-views, .sem-views):not([data-sem-upgraded]) :is(sem-view, .sem-view)::before { content: attr(data-name);
  display: block; font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); margin-bottom: .25rem; }
:is(sem-views, .sem-views):not([data-sem-upgraded]) :is(sem-view, .sem-view)[name]:not([data-name])::before { content: attr(name); }

/* ── sem-views ── */
/* Container-level chrome: keyboard focus on the generated tabs. No
   transitions are declared for the switch itself — the pitch is that the
   content does not move, so the swap is instant and reduced motion is
   respected by construction. Hover keeps the muted tab distinct from the
   selected one (accent + surface) with a quiet border hint only. */
.sem-views-tabs button:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: -2px; }
.sem-views-tabs button:hover:not([aria-selected="true"]) { border-color: var(--sem-border); }
/* ── end sem-views ── */

/* ── sem-reveal ── */
:is(sem-reveal, .sem-reveal) { margin: 1rem 0; border: 1px solid var(--sem-border);
  border-radius: 12px; background: var(--sem-surface); }
:is(sem-reveal, .sem-reveal):is([data-summary], [summary])::before { content: attr(data-summary);
  display: block; font-variant-caps: all-small-caps; color: var(--sem-muted);
  padding: .6rem .9rem 0; }
:is(sem-reveal, .sem-reveal)[summary]:not([data-summary])::before { content: attr(summary); }
:is(sem-reveal, .sem-reveal) .sem-reveal-body { padding: .5rem .9rem .75rem; }
:is(sem-reveal, .sem-reveal) details:not([open]) .sem-reveal-body { display: none; }
/* Once a script has built the <details>, its <summary> carries the
   question; the ::before caption above is the JS-off rendering of the same
   string and would duplicate it. Gated on the upgrade marker like every
   other rule that depends on a script having run (D12); the bare-`summary`
   spelling is accepted too — the caption may come from bare `summary`
   where the attrs pass never ran, and the <summary> carries the same
   string either way. */
:is(sem-reveal, .sem-reveal)[data-sem-upgraded]:is([data-summary], [summary])::before { content: none; }
:is(sem-reveal, .sem-reveal) summary { padding: .6rem .9rem; cursor: pointer; font-weight: 600; }
:is(sem-reveal, .sem-reveal) summary::marker { color: var(--sem-muted); }
/* The summary is the disclosure control: hover tints the row so the
   affordance reads before the first click; keyboard focus keeps the same
   accent outline every other control in this file uses. The toggle itself
   is instant (native <details>), so reduced motion needs no extra rule. */
:is(sem-reveal, .sem-reveal) summary:hover { background: color-mix(in srgb, var(--sem-accent) 8%, transparent); }
:is(sem-reveal, .sem-reveal) summary:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; border-radius: 6px; }
/* The Lit component (tag form) — the control row and the blur affordance.
   The hidden state must read as an affordance, not as broken rendering:
   the body is blurred and clipped behind the control until the reader
   acts. The blur gates on the upgrade marker (D12) so a JS-off page
   never blurs content nothing on the page can reveal. */
:is(sem-reveal, .sem-reveal)[data-sem-upgraded] .sem-reveal-control {
  display: flex; gap: .5rem; align-items: baseline; width: 100%;
  padding: .6rem .9rem; border: 0; background: none; cursor: pointer;
  font: inherit; color: inherit; text-align: left; }
:is(sem-reveal, .sem-reveal)[data-sem-upgraded] .sem-reveal-label { font-weight: 600; }
:is(sem-reveal, .sem-reveal)[data-sem-upgraded] .sem-reveal-hint {
  margin-left: auto; flex: none; font-variant-caps: all-small-caps;
  color: var(--sem-accent); border: 1px solid color-mix(in srgb, var(--sem-accent) 45%, transparent);
  border-radius: 999px; padding: .05rem .55rem; }
:is(sem-reveal, .sem-reveal)[data-sem-upgraded] .sem-reveal-control:hover .sem-reveal-hint {
  background: color-mix(in srgb, var(--sem-accent) 12%, transparent); }
:is(sem-reveal, .sem-reveal)[data-sem-upgraded] .sem-reveal-control:focus-visible {
  outline: 2px solid var(--sem-accent); outline-offset: 2px; border-radius: 6px; }
:is(sem-reveal, .sem-reveal)[data-sem-upgraded] .sem-reveal-head {
  padding: .6rem .9rem; font-weight: 600; font-variant-caps: all-small-caps; color: var(--sem-muted); }
:is(sem-reveal, .sem-reveal)[data-sem-upgraded]:not([data-revealed]) .sem-reveal-body {
  filter: blur(6px); max-height: 8rem; overflow: hidden;
  pointer-events: none; user-select: none; }
:is(sem-reveal, .sem-reveal)[data-sem-upgraded][data-revealed] .sem-reveal-body {
  filter: none; max-height: none; overflow: visible;
  transition: filter .24s ease; }
@media (prefers-reduced-motion: reduce) {
  :is(sem-reveal, .sem-reveal)[data-sem-upgraded][data-revealed] .sem-reveal-body { transition: none; }
}
/* ── end sem-reveal ── */

/* progress */
:is(sem-progress, .sem-progress) { margin: 1rem 0; color: var(--sem-muted); font-size: .875rem; }
/* JS-off: the meter is text only — `label :: value` from the attributes
   (spec/schema/sem-progress.md); no fake bar. An empty element with no
   tier marker otherwise rendered nothing at all. Plain attr() only: the
   fallback-argument form is not yet universal. */
:is(sem-progress, .sem-progress):not([data-sem-upgraded]):is([data-value], [value])::before {
  content: "progress :: " attr(data-value); }
:is(sem-progress, .sem-progress):not([data-sem-upgraded])[value]:not([data-value])::before {
  content: "progress :: " attr(value); }
:is(sem-progress, .sem-progress):not([data-sem-upgraded])[data-label][data-value]::before {
  content: attr(data-label) " :: " attr(data-value); }
:is(sem-progress, .sem-progress):not([data-sem-upgraded])[label][value]:not([data-value])::before {
  content: attr(label) " :: " attr(value); }
/* status pairs with the value (schema: done ⇔ 1); same catalog as sem-step */
:is(sem-progress, .sem-progress):is([data-status="done"], [status="done"])::after { content: " ✓"; color: var(--sem-correct); }
:is(sem-progress, .sem-progress) .sem-progress-track { display: block; height: .5rem;
  background: color-mix(in srgb, var(--sem-border) 60%, transparent);
  border-radius: 999px; overflow: hidden; margin-top: .25rem; }
:is(sem-progress, .sem-progress) .sem-progress-fill { display: block; height: 100%;
  background: var(--sem-accent); border-radius: 999px; }

/* quota meter — rolling usage window (e.g. a provider's 5-hour cap).
   Colour tiers are a data-level the Lit element owns (ok → warn at 75%,
   hot at 90%); each level reads a --sem-quota-meter-* token that falls
   back to a theme token, so a theme overrides without touching this file. */
:is(sem-quota-meter, .sem-quota-meter) { margin: 1rem 0; color: var(--sem-muted); font-size: .875rem; }
/* JS-off: text-only meter from the bare attributes, like sem-progress. */
:is(sem-quota-meter, .sem-quota-meter):not([data-sem-upgraded])[label][used][limit]::before {
  content: attr(label) " :: " attr(used) " of " attr(limit); }
:is(sem-quota-meter, .sem-quota-meter) .sem-quota-meter-label { font-weight: 600; color: var(--sem-fg); margin-right: .5rem; }
:is(sem-quota-meter, .sem-quota-meter) .sem-quota-meter-track { display: block; height: .5rem;
  background: color-mix(in srgb, var(--sem-border) 60%, transparent);
  border-radius: 999px; overflow: hidden; margin-top: .25rem; }
:is(sem-quota-meter, .sem-quota-meter) .sem-quota-meter-fill { display: block; height: 100%;
  background: var(--sem-quota-meter-ok, var(--sem-accent)); border-radius: 999px; transition: width .3s; }
:is(sem-quota-meter, .sem-quota-meter)[data-level="warn"] .sem-quota-meter-fill {
  background: var(--sem-quota-meter-warn, var(--sem-note-warning)); }
:is(sem-quota-meter, .sem-quota-meter)[data-level="hot"] .sem-quota-meter-fill {
  background: var(--sem-quota-meter-hot, var(--sem-note-danger)); }
:is(sem-quota-meter, .sem-quota-meter) .sem-quota-meter-reset { display: block; margin-top: .25rem; color: var(--sem-muted); }

/* reader — one chrome per document (R/W2, spec/schema/sem-reader.md).
   Sticky bar; the outline drops below it as a panel. The sticky rule is
   gated on the [data-sem-upgraded] marker
   the script sets when it wires the element, same as every other hide rule
   (D12). With no script running the marker is absent, so the element
   never matches this selector: it holds only an authored nav (or nothing)
   and stays static — there is no chrome to pin. */
:is(sem-reader, .sem-reader)[data-sem-upgraded] { position: sticky; top: 0; z-index: 40; }
.sem-reader-chrome { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: .4rem;
  padding: .45rem .75rem .55rem; background: var(--sem-surface); border-bottom: 1px solid var(--sem-border);
  font-family: system-ui, sans-serif; font-size: .8rem; color: var(--sem-muted); }
.sem-reader-chrome button, .sem-reader-chrome select { font: inherit; color: var(--sem-fg);
  background: var(--sem-bg); border: 1px solid var(--sem-border); border-radius: 6px;
  padding: .2rem .55rem; cursor: pointer; }
.sem-reader-chrome button[aria-pressed="true"], .sem-reader-chrome button[aria-expanded="true"] {
  border-color: var(--sem-accent); color: var(--sem-accent); }
.sem-reader-chrome button:disabled { opacity: .45; cursor: default; }
.sem-reader-chrome > select { margin-left: auto; }
.sem-reader-chrome > select ~ select { margin-left: 0; }
.sem-reader-progress { position: absolute; left: 0; right: 0; bottom: -1px; height: 3px;
  background: color-mix(in srgb, var(--sem-border) 60%, transparent); }
.sem-reader-progress-fill { display: block; height: 100%; width: 0; background: var(--sem-accent);
  transition: width .12s linear; }
:is(sem-reader, .sem-reader) > nav[aria-label="Contents"] { font-family: system-ui, sans-serif; font-size: .875rem; }
:is(sem-reader, .sem-reader)[data-sem-upgraded] > nav[aria-label="Contents"],
:is(sem-reader, .sem-reader)[data-sem-upgraded] > nav[aria-label="Contents"] {
  position: absolute; left: 0; right: 0; top: 100%; max-height: min(60vh, 24rem); overflow: auto;
  padding: .6rem 1rem; background: var(--sem-surface); border-bottom: 1px solid var(--sem-border);
  box-shadow: 0 12px 24px rgba(0, 0, 0, .12); }
:is(sem-reader, .sem-reader) > nav[aria-label="Contents"][hidden] { display: none; }
:is(sem-reader, .sem-reader) > nav :is(ol, ul) { margin: 0; padding-left: 1.1rem; }
:is(sem-reader, .sem-reader) > nav li { margin: .15rem 0; }
:is(sem-reader, .sem-reader) > nav a { color: var(--sem-fg); text-decoration: none; }
:is(sem-reader, .sem-reader) > nav a:hover { text-decoration: underline; }
:is(sem-reader, .sem-reader) > nav a[aria-current="location"] { color: var(--sem-accent); font-weight: 600; }
@media (prefers-reduced-motion: reduce) { .sem-reader-progress-fill { transition: none; } }
/* Once a script pins the bar, in-document targets (outline links, deep
   links, citations, glossary terms) stop short of it instead of landing
   underneath; --sem-reader-offset = the bar's height plus a little air. */
:is(sem-reader, .sem-reader)[data-sem-upgraded] ~ * :is(h1, h2, h3, h4, h5, h6, [id]),
:is(sem-reader, .sem-reader)[data-sem-upgraded] ~ [id] {
  scroll-margin-top: var(--sem-reader-offset, 4.5rem); }

/* reader-driven document state on <html> (session facts, never extracted) */
:root[data-sem-type="s"] :is(sem-enhanced-document, .sem-enhanced-document) { font-size: .9rem; }
:root[data-sem-type="l"] :is(sem-enhanced-document, .sem-enhanced-document) { font-size: 1.15rem; }
:root[data-sem-font="serif"] :is(sem-enhanced-document, .sem-enhanced-document) {
  font-family: Charter, Georgia, "Times New Roman", serif; }
/* color-scheme for [data-color-mode] lives in the theme file, beside its tokens */
/* focus mode: page chrome outside the root wrapper goes away, the measure
   narrows, margin notes fall back inline */
:root[data-sem-mode="focus"] body > :not(:is(sem-enhanced-document, .sem-enhanced-document), script, style, .sem-popover):not(:has(:is(sem-enhanced-document, .sem-enhanced-document))) { display: none; }
:root[data-sem-mode="focus"] :is(sem-enhanced-document, .sem-enhanced-document) {
  max-width: var(--sem-focus-measure, 42rem); margin-inline: auto; line-height: 1.75; }
:root[data-sem-mode="focus"] :is(sem-note, .sem-note):is([data-view-as="margin"], [view-as="margin"]) { float: none; width: auto; margin: 1rem 0; }

/* ── sem-source ── */
/* source — rendered/source section wrapper (spec/schema/sem-source.md).
   The fence is display:none until the reader asks for it; the hide rule
   for the rendered children is gated on a tier marker and screen-only,
   so JS-off and print always show the rendered content. */
.sem-source-chrome { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin: 1.5rem 0 .5rem;
  font-family: system-ui, sans-serif; font-size: .75rem; color: var(--sem-muted); }
.sem-source-label { margin-right: auto; text-transform: uppercase; letter-spacing: .05em; }
.sem-source-chrome button { font: inherit; color: var(--sem-fg); background: var(--sem-bg);
  border: 1px solid var(--sem-border); padding: .2rem .6rem; cursor: pointer; }
.sem-source-chrome button:first-of-type { border-radius: 6px 0 0 6px; }
.sem-source-chrome button:last-of-type { border-radius: 0 6px 6px 0; margin-left: -1px; }
.sem-source-chrome button[aria-pressed="true"] { border-color: var(--sem-accent); color: var(--sem-accent);
  position: relative; z-index: 1; }
.sem-source-chrome button:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; }
.sem-source-fence { display: none; }
.sem-source-fence > :is(sem-code, .sem-code) { margin-top: 0; }
@media screen {
  :is(sem-source, .sem-source)[data-sem-upgraded][data-view-as="source"] > .sem-source-fence { display: block; }
  :is(sem-source, .sem-source)[data-sem-upgraded][data-view-as="source"] > :not(.sem-source-chrome, .sem-source-fence) { display: none; }
}
/* ── end sem-source ── */

/* ── sem-table ── authored <table> is the contract (R/W2, spec/schema/sem-table.md);
   sticky header and comparison first column are CSS in every tier */
:is(sem-table, .sem-table) { margin: 1.25rem 0; overflow-x: auto; border: 1px solid var(--sem-border);
  border-radius: 12px; background: var(--sem-surface); }
:is(sem-table, .sem-table) table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: .9rem; }
:is(sem-table, .sem-table) caption { text-align: left; padding: .6rem .9rem 0; font-weight: 600; caption-side: top; }
:is(sem-table, .sem-table) th, :is(sem-table, .sem-table) td { padding: .45rem .9rem; text-align: left;
  border-bottom: 1px solid var(--sem-border); vertical-align: top; }
:is(sem-table, .sem-table) th { font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted);
  background: var(--sem-surface); }
:is(sem-table, .sem-table) tbody tr:last-child :is(th, td) { border-bottom: 0; }
:is(sem-table, .sem-table):is([data-sticky], [sticky]) thead th { position: sticky; top: var(--sem-reader-offset, 0); z-index: 1; }
/* The stick engages only against an internal scroll container: cap the
   element so a long table scrolls inside itself (sticky is a no-op against
   a page-level scroller once overflow-x makes the element the scrollport). */
:is(sem-table, .sem-table):is([data-sticky], [sticky]) { max-height: 24rem; }
:is(sem-table, .sem-table) table:is([data-kind="comparison"], [kind="comparison"]) :is(th, td):first-child,
:is(sem-table, .sem-table):is([data-kind="comparison"], [kind="comparison"]) :is(th, td):first-child,
:is(sem-enhanced-document, .sem-enhanced-document) > table:is([data-kind="comparison"], [kind="comparison"]) :is(th, td):first-child {
  position: sticky; left: 0; background: var(--sem-surface); z-index: 1; }
:is(sem-table, .sem-table):is([data-sticky], [sticky]) table:is([data-kind="comparison"], [kind="comparison"]) thead th:first-child { z-index: 2; }
.sem-table-chrome { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; padding: .5rem .9rem;
  border-bottom: 1px solid var(--sem-border); font-size: .8rem; color: var(--sem-muted);
  /* Pinned to the element's left edge while the body scrolls horizontally,
     so the filter and status stay in view on a narrow viewport. */
  position: sticky; left: 0; background: var(--sem-surface); z-index: 2; }
.sem-table-chrome:not(:has(input)):not(:has(.sem-table-status:not(:empty))) { display: none; }
.sem-table-filter { font: inherit; color: var(--sem-fg); background: var(--sem-bg); border: 1px solid var(--sem-border);
  border-radius: 6px; padding: .25rem .5rem; min-width: 12rem;
  scroll-margin-top: calc(8px + var(--sem-reader-offset, 0px)); }
.sem-table-status { min-height: 1em; }
.sem-table-sort { all: unset; font: inherit; cursor: pointer; display: inline-block; padding-right: 1.1em; position: relative; }
.sem-table-sort::after { content: "↕"; position: absolute; right: 0; opacity: .5; }
th[aria-sort="ascending"] .sem-table-sort::after { content: "↑"; opacity: 1; color: var(--sem-accent); }
th[aria-sort="descending"] .sem-table-sort::after { content: "↓"; opacity: 1; color: var(--sem-accent); }
.sem-table-sort:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; border-radius: 4px; }
/* ── end sem-table ── */

/* artifact card — agent-kit upsell stub (src/lit/sem-artifact-card.ts).
   Typed artifact body (markdown / json / diff / code) plus a version
   timeline; the authored fallback shows the active version only. */
:is(sem-artifact-card, .sem-artifact-card) { display: block; margin: 1.5rem 0; }
:is(.sem-artifact-ui, .sem-artifact-fallback) { border: 1px solid var(--sem-border);
  border-radius: 10px; padding: .9rem 1rem; }
.sem-artifact-head { display: flex; flex-wrap: wrap; gap: .5rem; align-items: baseline; margin: 0 0 .6rem; }
.sem-artifact-type { font-variant-caps: all-small-caps; letter-spacing: .05em;
  color: var(--sem-accent); font-weight: 600; }
.sem-artifact-lang { font-size: .75rem; padding: .1rem .5rem; border: 1px solid var(--sem-border);
  border-radius: 999px; color: var(--sem-muted); }
.sem-artifact-version { margin-left: auto; font-size: .8125rem; color: var(--sem-muted); }
.sem-artifact-body :is(h2, h3, h4) { margin: .9rem 0 .3rem; }
.sem-artifact-body p { margin: .4rem 0; }
.sem-artifact-body :is(ul, ol) { margin: .4rem 0; padding-left: 1.3rem; }
.sem-artifact-pre { margin: 0; padding: .7rem .8rem; overflow-x: auto; font-size: .8125rem;
  line-height: 1.45; border: 1px solid var(--sem-border); border-radius: 8px; background: var(--sem-surface, #fff); }
.sem-artifact-diff-add { display: block; color: var(--sem-note-tip, #2e8b57); }
.sem-artifact-diff-del { display: block; color: var(--sem-note-danger, #b23a3a); }
.sem-artifact-diff-hunk { display: block; color: var(--sem-accent); }
.sem-artifact-diff-hunk-meta, .sem-artifact-diff-ctx { display: block; color: inherit; }
.sem-artifact-timeline { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin: .7rem 0 0; }
.sem-artifact-timeline-label { font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
.sem-artifact-scrub { flex: 1 1 10rem; accent-color: var(--sem-accent); }
.sem-artifact-count { font-size: .8125rem; color: var(--sem-muted); font-variant-numeric: tabular-nums; }
.sem-artifact-actions { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin: .6rem 0 0; }
.sem-artifact-actions button { font: inherit; font-size: .8125rem; padding: .3rem .7rem;
  border: 1px solid var(--sem-border); border-radius: 6px; background: var(--sem-surface, #fff);
  color: var(--sem-fg); cursor: pointer; }
.sem-artifact-actions .sem-artifact-fork { border-color: var(--sem-accent);
  background: var(--sem-accent); color: #fff; }
.sem-artifact-status { font-size: .8125rem; color: var(--sem-muted); min-height: 1em; }
.sem-artifact-empty { color: var(--sem-muted); }
/* zero-JS fallback: active version only, no controls; hidden once the
   interactive tier takes over (gated on the tier marker) */
:is(sem-artifact-card, .sem-artifact-card)[data-sem-upgraded] .sem-artifact-fallback { display: none; }

/* data visualizer — native table rendered from an inline data source
   (spec/data-visualizer.md, phase 1); mirrors the sem-table base */
:is(sem-data-visualizer, .sem-data-visualizer) { margin: 1.25rem 0; }
:is(sem-data-source, .sem-data-source) { margin: .5rem 0; overflow-x: auto; border: 1px solid var(--sem-border);
  border-radius: 12px; background: var(--sem-surface); }
:is(sem-data-source, .sem-data-source) table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: .9rem; }
:is(sem-data-source, .sem-data-source) caption { text-align: left; padding: .6rem .9rem 0; font-weight: 600; caption-side: top; }
:is(sem-data-source, .sem-data-source) th, :is(sem-data-source, .sem-data-source) td { padding: .45rem .9rem;
  text-align: left; border-bottom: 1px solid var(--sem-border); vertical-align: top; }
:is(sem-data-source, .sem-data-source) th { font-variant-caps: all-small-caps; letter-spacing: .05em;
  color: var(--sem-muted); background: var(--sem-surface); }
:is(sem-data-source, .sem-data-source) tbody tr:last-child :is(th, td) { border-bottom: 0; }
:is(sem-data-source, .sem-data-source) .sem-data-schema { display: none; }
.sem-data-error { margin: 0; padding: .6rem .9rem; font-size: .85rem; color: var(--sem-note-danger, currentColor); }
.sem-data-sort { all: unset; font: inherit; cursor: pointer; display: inline-block; padding-right: 1.1em; position: relative; }
.sem-data-sort::after { content: "↕"; position: absolute; right: 0; opacity: .5; }
th[aria-sort="ascending"] .sem-data-sort::after { content: "↑"; opacity: 1; color: var(--sem-accent); }
th[aria-sort="descending"] .sem-data-sort::after { content: "↓"; opacity: 1; color: var(--sem-accent); }
.sem-data-sort:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; border-radius: 4px; }

/* data visualizer — async loads + query/view chrome (phases 4–5) */
.sem-data-pending { margin: 0; padding: .6rem .9rem; font-size: .85rem; color: var(--sem-muted); }
.sem-data-views { display: flex; gap: .4rem; padding: .5rem .9rem 0; flex-wrap: wrap; }
.sem-data-view { all: unset; font: inherit; font-size: .8rem; cursor: pointer; padding: .15rem .7rem;
  border: 1px solid var(--sem-border); border-radius: 999px; color: var(--sem-muted); }
.sem-data-view[aria-pressed="true"] { background: var(--sem-accent); border-color: var(--sem-accent); color: var(--sem-surface); }
.sem-data-view:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; }

/* ── sem-data-source ── */
/* zero-JS / bare / error / pending form: the authored payload reads as
   pre-wrapped text (schema sem-data-source.md §Rendered form — the sem-md
   precedent). Kept marker-agnostic: once the generated table is present
   the source's own text is the data-payload lane's echo to suppress. */
:is(sem-data-source, .sem-data-source):not(:has(> .sem-data-body)) {
  white-space: pre-wrap; overflow-wrap: anywhere; }
/* ── end sem-data-source ── */

/* ── sem-data-raw ── */
/* The authored payload (source rows / query statement), parked by
   reading/data.ts parkPayload: it stays in the DOM (extraction is
   unchanged) and hides while the element is wired — the container/
   runtime contract of schema sem-data-*.md §Rendered form, not
   authoring surface. JS-off pages never contain the box. */
:is(sem-data-source, .sem-data-source, sem-data-query, .sem-data-query)[data-sem-upgraded] > .sem-data-raw {
  display: none; }
@media print {
  :is(sem-data-source, .sem-data-source, sem-data-query, .sem-data-query) > .sem-data-raw {
    display: none !important; }
}
/* ── end sem-data-raw ── */

/* phase 6 — tools row + full-page modal viewer (spec/data-visualizer.md §10) */
.sem-data-tools { display: flex; align-items: center; justify-content: flex-end; gap: .4rem;
  padding: .3rem .9rem 0; flex-wrap: wrap; }
.sem-data-expand, .sem-data-copy { all: unset; font: inherit; font-size: .8rem; cursor: pointer;
  padding: .15rem .7rem; border: 1px solid var(--sem-border); border-radius: 999px; color: var(--sem-muted); }
.sem-data-expand:focus-visible, .sem-data-copy:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; }
.sem-data-copy-status { font-size: .8rem; color: var(--sem-muted); }
.sem-data-modal { position: fixed; inset: 0; z-index: 60; display: flex; align-items: center;
  justify-content: center; padding: 1.5rem; background: rgb(0 0 0 / .45); }
.sem-data-modal-panel { background: var(--sem-surface); color: inherit; box-sizing: border-box;
  border: 1px solid var(--sem-border); border-radius: 16px; width: min(64rem, 100%); max-height: 100%;
  overflow: auto; padding: 1rem; }
.sem-data-modal-close { all: unset; font: inherit; font-size: .8rem; cursor: pointer; margin-bottom: .5rem;
  padding: .15rem .9rem; border: 1px solid var(--sem-border); border-radius: 999px; }
.sem-data-modal-close:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; }
:is(sem-data-join, .sem-data-join) { margin: .25rem 0; }
:is(sem-data-query, .sem-data-query) { display: block; margin: .5rem 0; }
.sem-data-query-chrome { margin: .5rem 0; display: block; }
.sem-data-query-label { display: block; font-variant-caps: all-small-caps; letter-spacing: .05em;
  font-size: .85rem; color: var(--sem-muted); margin-bottom: .3rem; }
.sem-data-query-input { display: block; width: 100%; box-sizing: border-box; font: .85rem/1.5 ui-monospace, monospace;
  padding: .55rem .8rem; border: 1px solid var(--sem-border); border-radius: 10px;
  background: var(--sem-surface); color: inherit; resize: vertical; }
.sem-data-query-input:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 1px; }
.sem-data-query-controls { display: flex; align-items: center; gap: .75rem; margin: .4rem 0 .6rem; }
.sem-data-query-run { all: unset; font: inherit; font-size: .85rem; cursor: pointer; padding: .25rem 1rem;
  border: 1px solid var(--sem-border); border-radius: 999px; }
.sem-data-query-run:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; }
.sem-data-query-status { font-size: .8rem; color: var(--sem-muted); }
.sem-data-query-error { margin: 0; padding: .6rem .9rem; font-size: .85rem; color: var(--sem-note-danger, currentColor); }
.sem-data-query-results table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: .9rem;
  border: 1px solid var(--sem-border); border-radius: 12px; overflow: hidden; }
.sem-data-query-results :is(th, td) { padding: .45rem .9rem; text-align: left; border-bottom: 1px solid var(--sem-border); }
.sem-data-query-results th { font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
.sem-data-query-results tbody tr:last-child :is(th, td) { border-bottom: 0; }

/* print — everything a reader could open, none of the chrome. Reveal
   <details> are opened by fallback/target on `beforeprint`; CSS cannot. */
@media print {
  .sem-facts-chrome, .sem-quiz-options, .sem-views-tabs, .sem-note-summary,
  .sem-code-chrome, .sem-popover, .sem-references-backlinks, .sem-references-link,
  sem-reader, .sem-reader, .sem-table-chrome, .sem-source-chrome, .sem-source-fence,
  .sem-md-chrome, .sem-md-raw, .sem-data-tools, .sem-data-modal { display: none !important; }
  .sem-md-body { display: block !important; }
  :is(sem-table, .sem-table) { overflow: visible; }
  :is(sem-table, .sem-table) tbody tr[hidden] { display: table-row !important; }
  :is(sem-code, .sem-code) pre { white-space: pre-wrap; overflow: visible; }
  /* the href shows inside the references block only, never at the citation */
  :is(sem-reference, .sem-reference)[data-href]::after { content: " (" attr(data-href) ")"; color: var(--sem-muted); }
  :is(sem-reference, .sem-reference)[href]:not([data-href])::after { content: " (" attr(href) ")"; color: var(--sem-muted); }
  :is(sem-facts, .sem-facts) :is(sem-fact, .sem-fact) { display: block !important; min-height: 0 !important; }
  :is(sem-fact, .sem-fact) :is(conclusion, .sem-conclusion) { display: block !important; visibility: visible !important; }
  :is(sem-note, .sem-note)[collapsed] > .sem-note-body { display: block !important; }
  :is(sem-note, .sem-note):is([data-view-as="margin"], [view-as="margin"]) { float: none !important; width: auto !important; margin: 1rem 0 !important; }
  :is(sem-views, .sem-views) :is(sem-view, .sem-view) { display: block !important; border-top: 1px solid var(--sem-border);
    border-radius: 12px; margin: .5rem 0; }
  :is(sem-views, .sem-views) :is(sem-view, .sem-view)::before { content: attr(data-name); display: block;
    font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); margin-bottom: .25rem; }
  :is(sem-views, .sem-views) :is(sem-view, .sem-view)[name]:not([data-name])::before { content: attr(name); }
  :is(sem-reveal, .sem-reveal) summary { list-style: none; }
  .sem-occluded { color: inherit !important; background: none !important; }
  :is(sem-fact, .sem-fact), :is(sem-step, .sem-step), :is(sem-note, .sem-note), :is(sem-detail, .sem-detail),
  :is(sem-property, .sem-property), :is(sem-event, .sem-event), :is(sem-reference, .sem-reference) { break-inside: avoid; page-break-inside: avoid; }
  .sem-target { outline: none; }
}

/* ============================================================
   npl-* — NPL components (src/lit/npl/; recipe: that barrel's header).

   The same box contract the sem-* enumeration above gives every sem-*
   tag: custom elements are inline by default, the vocabulary is
   block-level, so each tag gets its box before any definition —
   `:not(:defined)` pre-upgrade, and for any element that never defines
   one, alike. The class-namespace alias follows conventions Appendix A
   (`:is(npl-x, .npl-x)`, one rule per authoring form).

   ONE LINE PER TAG, ALPHABETICAL. A new component inserts its own line
   here — nothing shared is ever edited, so parallel component branches
   merge clean. Do NOT convert this into one comma list.
   ============================================================ */
npl-agent, .npl-agent { display: block; }
npl-artifact, .npl-artifact { display: block; }
npl-cot, .npl-cot { display: block; }
npl-critique, .npl-critique { display: block; }
npl-declaration, .npl-declaration { display: block; }
npl-directive, .npl-directive { display: block; }
npl-example, .npl-example { display: block; }
npl-flag, .npl-flag { display: block; }
npl-flags, .npl-flags { display: block; }
npl-hormones, .npl-hormones { display: block; }
npl-intent, .npl-intent { display: block; }
npl-intent-assumption, .npl-intent-assumption { display: block; }
npl-intent-assumptions, .npl-intent-assumptions { display: block; }
npl-intent-outcomes, .npl-intent-outcomes { display: block; }
npl-intent-overview, .npl-intent-overview { display: block; }
npl-intent-scope, .npl-intent-scope { display: block; }
npl-mindread, .npl-mindread { display: block; }
npl-mode, .npl-mode { display: block; }
npl-mood, .npl-mood { display: block; }
npl-poa, .npl-poa { display: block; }
npl-ref, .npl-ref { display: block; }
npl-rubric, .npl-rubric { display: block; }
npl-section, .npl-section { display: block; }
npl-thought, .npl-thought { display: block; }
npl-vos, .npl-vos { display: block; }

/* npl-critique — structured critique card (component: src/lit/npl/npl-critique.ts).
   The component adds the `.npl-critique-*` part classes as theme hooks; every
   rule below names BOTH authoring forms (bare part tag / `.npl-` alias), so
   the JS-off box reads identically. Display-only: no focus chrome, no motion.
   Small-caps part labels identify the lists without relying on colour alone;
   label colours mix toward the foreground for AA at label size. */
:is(npl-critique, .npl-critique) { border: 1px solid var(--sem-border); border-radius: 12px;
  padding: 1rem; margin: 1rem 0; background: var(--sem-surface); }
:is(npl-critique, .npl-critique) > :is(subject, .npl-subject) { display: block; font-weight: 600; }
:is(npl-critique, .npl-critique) > :is(subject, .npl-subject)::before { content: "subject · ";
  font-weight: 400; font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
:is(npl-critique, .npl-critique) > :is(perspective, .npl-perspective) { display: block;
  margin-top: .25rem; color: var(--sem-muted); }
:is(npl-critique, .npl-critique) > :is(perspective, .npl-perspective)::before { content: "perspective · ";
  font-variant-caps: all-small-caps; letter-spacing: .05em; }
:is(npl-critique, .npl-critique) > :is(strengths, .npl-strengths),
:is(npl-critique, .npl-critique) > :is(weaknesses, .npl-weaknesses) { display: block; margin-top: .75rem; }
:is(npl-critique, .npl-critique) > :is(strengths, .npl-strengths)::before { content: "strengths · ";
  font-variant-caps: all-small-caps; letter-spacing: .05em;
  color: color-mix(in srgb, var(--sem-correct) 75%, var(--sem-fg)); }
:is(npl-critique, .npl-critique) > :is(weaknesses, .npl-weaknesses)::before { content: "weaknesses · ";
  font-variant-caps: all-small-caps; letter-spacing: .05em;
  color: color-mix(in srgb, var(--sem-wrong) 75%, var(--sem-fg)); }
/* pre-rewrite item children read as a list before the script runs; after the
   rewrite the generated ul (below) carries the list, so this stops matching —
   :not(.npl-critique-item) keeps the in-place native-ul upgrade from stacking
   item margin on top of the list padding */
:is(npl-critique, .npl-critique) > :is(strengths, .npl-strengths) > :is(item, li, .npl-item):not(.npl-critique-item),
:is(npl-critique, .npl-critique) > :is(weaknesses, .npl-weaknesses) > :is(item, li, .npl-item):not(.npl-critique-item) {
  display: list-item; margin-left: 1.25rem; }
:is(npl-critique, .npl-critique) .npl-critique-list { margin: .25rem 0 0; padding-left: 1.25rem; }
/* when the part IS the list (native ul/ol upgraded in place), its label sits
   inside the list padding — pull it back to the card edge so both authoring
   forms put the label in the same place */
:is(npl-critique, .npl-critique) > .npl-critique-strengths.npl-critique-list::before,
:is(npl-critique, .npl-critique) > .npl-critique-weaknesses.npl-critique-list::before { margin-left: -1.25rem; }
/* marker colour only — item text stays the foreground colour */
:is(npl-critique, .npl-critique) > :is(strengths, .npl-strengths) ::marker { color: color-mix(in srgb, var(--sem-correct) 75%, var(--sem-fg)); }
:is(npl-critique, .npl-critique) > :is(weaknesses, .npl-weaknesses) ::marker { color: color-mix(in srgb, var(--sem-wrong) 75%, var(--sem-fg)); }
/* the closing judgement: the highlighted line (accent bar + tint, never opaque) */
:is(npl-critique, .npl-critique) > :is(verdict, .npl-verdict) { display: block; margin-top: .75rem;
  padding: .5rem .75rem; border-left: 3px solid var(--sem-accent); border-radius: 6px;
  background: color-mix(in srgb, var(--sem-accent) 12%, transparent); font-weight: 500; }
:is(npl-critique, .npl-critique) > :is(verdict, .npl-verdict)::before { content: "verdict · ";
  font-weight: 400; font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-accent); }

/* npl-directive — inline directive chip (component: src/lit/npl/npl-directive.ts).
   The component wraps authored children into `.npl-directive-body` and mints
   `.npl-directive-glyph` / `.npl-directive-qualifier` chrome around it; the
   rules below key on those part classes so the authored text is never
   restyled out from under the JS-off box, which reads as the same accented
   block without the chrome. A directive is an instruction the agent must
   follow: it is accented, never occluded — the text stays fully readable
   (occlusion belongs to the quiz tier). The glyph gets its own margin so a
   tight authoring (`>be terse<`) cannot collide with the instruction, and
   the qualifier reads as a trailing label, never as part of the sentence.
   Display-only: no focus chrome, no motion. */
:is(npl-directive, .npl-directive) { display: block; margin: 1rem 0;
  padding: .625rem .75rem; border-left: 3px solid var(--sem-accent);
  border-radius: 6px; background: color-mix(in srgb, var(--sem-accent) 10%, transparent); }
:is(npl-directive, .npl-directive) > .npl-directive-glyph { margin-right: .4em; }
:is(npl-directive, .npl-directive) > .npl-directive-body { font-weight: 500; }
:is(npl-directive, .npl-directive) > .npl-directive-qualifier { margin-left: .6em;
  font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
:is(npl-directive, .npl-directive) > .npl-directive-qualifier::before { content: "· "; }

/* npl-declaration — version/extension banner for a rules document
   (component: src/lit/npl/npl-declaration.ts). The component hoists a
   `.npl-declaration-banner` header (`.npl-declaration-mark`, plus a
   `.npl-declaration-target` when an extend-target is authored) above the
   authored rules content; the rules below key on those part classes, so
   the JS-off box stays the plain authored prose the schema promises —
   nothing hidden, nothing generated. Enhanced, the banner is display-only
   chrome in the family accent: the mark reads as a version stamp (mono,
   accent), the target as a trailing small-caps label, and the rules below
   stay fully readable — a declaration never occludes its body (no focus
   chrome, no motion). */
:is(npl-declaration, .npl-declaration) { display: block; margin: 1rem 0; }
:is(npl-declaration, .npl-declaration) .npl-declaration-banner {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 .6em;
  padding: .5rem .75rem; margin-bottom: .75rem;
  border: 1px solid var(--sem-border); border-left: 3px solid var(--sem-accent);
  border-radius: 6px;
  background: color-mix(in srgb, var(--sem-accent) 8%, transparent); }
:is(npl-declaration, .npl-declaration) .npl-declaration-mark {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8125rem; letter-spacing: .02em; color: var(--sem-accent); }
:is(npl-declaration, .npl-declaration) .npl-declaration-target {
  font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
:is(npl-declaration, .npl-declaration) .npl-declaration-target::before { content: "→ "; }

/* ── npl-mindread ── */
/* npl-mindread — theory-of-mind reading card (component: src/lit/npl/npl-mindread.ts).
   The component mints its labels as real generated elements — the confidence
   meter, one `.npl-mindread-heading` per authored section, a type chip per
   signal, a label per inferred field — so the chrome rules below key on those
   `.npl-mindread-*` part classes; the section rules are box-semantics only,
   which is what keeps the JS-off box from fusing the authored prose into one
   run-on line (nothing hidden, nothing labelled, no generated masquerade).
   Enhanced, the reading lays out in canonical order under its meter: signals
   and inferred fields each get their own line with the small-caps chip or
   label in front, and the adaptation — the actionable conclusion — takes the
   family's accent bar + tint treatment. A reading explains and never
   occludes: every authored word stays fully readable; the unknown-type chip
   carries a "?" and its own text, never colour alone.
   Display-only: no focus chrome, no motion. */
:is(npl-mindread, .npl-mindread) { display: block; margin: 1rem 0; padding: 1rem;
  border: 1px solid var(--sem-border); border-radius: 12px; background: var(--sem-surface); }
:is(npl-mindread, .npl-mindread) > :is(subject, .npl-subject, signals, .npl-signals,
  inferred, .npl-inferred, adaptation, .npl-adaptation) { display: block; }
/* the confidence meter exists only after the upgrade (component-rendered):
   label · value on one line, the clamp note wrapping beneath */
:is(npl-mindread, .npl-mindread) .npl-mindread-confidence {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 .5em;
  margin-bottom: .25rem; padding-bottom: .75rem; border-bottom: 1px solid var(--sem-border); }
:is(npl-mindread, .npl-mindread) .npl-mindread-confidence-label {
  font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
:is(npl-mindread, .npl-mindread) .npl-mindread-confidence-value {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 600;
  color: color-mix(in srgb, var(--sem-accent) 80%, var(--sem-fg)); }
:is(npl-mindread, .npl-mindread) .npl-mindread-confidence-out {
  flex-basis: 100%; font-size: .75rem;
  color: color-mix(in srgb, var(--sem-wrong) 75%, var(--sem-fg)); }
/* generated section heading — small-caps label line, family rhythm */
:is(npl-mindread, .npl-mindread) .npl-mindread-heading {
  margin: .75rem 0 .25rem; font-size: .8125rem; font-weight: 600;
  font-variant-caps: all-small-caps; letter-spacing: .06em; color: var(--sem-muted); }
/* one evidence line per authored signal; the type rides in front as a chip */
:is(npl-mindread, .npl-mindread) > :is(signals, .npl-signals) > :is(signal, .npl-signal) {
  display: block; margin-top: .25rem; }
:is(npl-mindread, .npl-mindread) .npl-mindread-signal-type {
  display: inline-block; margin-right: .5em; padding: .05rem .55em;
  border: 1px solid var(--sem-border); border-radius: 999px; font-size: .75rem;
  font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
:is(npl-mindread, .npl-mindread) .npl-mindread-signal-unknown {
  border-color: color-mix(in srgb, var(--sem-wrong) 55%, var(--sem-border));
  color: color-mix(in srgb, var(--sem-wrong) 75%, var(--sem-fg)); }
:is(npl-mindread, .npl-mindread) .npl-mindread-signal-unknown::after { content: " ?"; }
/* the inferred read: motive / mood / cognitive / unspoken, one field per line */
:is(npl-mindread, .npl-mindread) > :is(inferred, .npl-inferred) >
  :is(motive, .npl-motive, mood, .npl-mood, cognitive, .npl-cognitive,
      unspoken, .npl-unspoken) { display: block; margin-top: .25rem; }
:is(npl-mindread, .npl-mindread) .npl-mindread-field-label {
  font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
:is(npl-mindread, .npl-mindread) .npl-mindread-field-label::after { content: "·"; margin: 0 .4em 0 .25em; opacity: .7; }
/* the closing adaptation: the line the reader acts on (accent bar + tint, never opaque) */
:is(npl-mindread, .npl-mindread) > :is(adaptation, .npl-adaptation) {
  margin-top: .75rem; padding: .5rem .75rem;
  border-left: 3px solid var(--sem-accent); border-radius: 6px;
  background: color-mix(in srgb, var(--sem-accent) 12%, transparent); font-weight: 500; }
/* ── end npl-mindread ── */


/* ── npl-poa ── */
/* npl-poa — plan-of-action block (component: src/lit/npl/npl-poa.ts).
   The authored children ARE the content: the mermaid fence degrades to a
   readable code block (no diagram runtime, ever), the reasoning and the
   selected path read as prose. <reasoning>/<selected> are unknown inline
   elements to the browser, so the block-level correction below is what
   keeps the JS-off box from fusing them into one run-on line behind the
   fence — box semantics only, no generated labels: the schema's JS-off
   promise is nothing hidden, nothing generated. Enhanced, the component
   stamps the tree `data-npl-poa-tree` + `data-direction` and features
   the chosen option as a generated `.npl-poa-choice` (`-label` /
   `-text` spans) after the authored `<selected>`; the choice is the one
   prominent element — accent bar + tint, never opaque, text fully
   readable — and the authored selected stays visible beneath it as the
   source of record (quieted, not hidden; a theme wanting a single
   presentation hides it in its own CSS, the base never does). Reasoning
   renders `white-space: pre-line` — the weighted paths are authored one
   per line and pre-line is what makes that authoring visible without
   re-writing the source.
   Display-only: no focus chrome, no motion. */
:is(npl-poa, .npl-poa) { margin: 1rem 0; }
:is(npl-poa, .npl-poa) > pre { margin: 0 0 .5rem; padding: .75rem 1rem;
  border: 1px solid var(--sem-border); border-radius: 8px;
  background: var(--sem-surface); overflow-x: auto; font-size: .875rem; }
:is(npl-poa, .npl-poa) > :is(reasoning, .npl-poa-reasoning) { display: block; margin: .5rem 0 0;
  white-space: pre-line; }
:is(npl-poa, .npl-poa) > :is(selected, .npl-poa-selected) { display: block; margin: .5rem 0 0; }
:is(npl-poa, .npl-poa)[data-sem-upgraded] > :is(selected, .npl-poa-selected) { color: var(--sem-muted); font-size: .875rem; }
:is(npl-poa, .npl-poa) > .npl-poa-choice { margin: .75rem 0 0; padding: .5rem .75rem;
  border-left: 3px solid var(--sem-accent); border-radius: 6px;
  background: color-mix(in srgb, var(--sem-accent) 12%, transparent); font-weight: 500; }
/* the label/text spans are children of the generated <p>, not of the host */
:is(npl-poa, .npl-poa) .npl-poa-choice-label { font-variant-caps: all-small-caps;
  letter-spacing: .05em; color: var(--sem-accent); }
:is(npl-poa, .npl-poa) .npl-poa-choice-label::after { content: " · "; font-weight: 400; }
/* ── end npl-poa ── */

/* ── npl-mood ── */
/* npl-mood — affective-state chip (component: src/lit/npl/npl-mood.ts).
   Display-only. The component mints `.npl-mood-chip` (`.npl-mood-emoji` +
   an optional `.npl-mood-qualifier`) and, when any detail child is
   authored, groups it once into a generated `.npl-mood-detail` panel —
   the authored tone / context / approach children are moved into it,
   never hidden or dropped. JS-off nothing is generated: the rule below
   surfaces the authored `mood` as the lead line (`attr(mood)`, the
   data-* spelling honoured) so the attribute is not lost, and the detail
   children read as plain prose; the part-class rules only bite once the
   generated chip / panel exist. The mood reads as a quiet badge —
   hairline border, surface fill, a small-caps qualifier in the accent
   mixed toward the foreground for AA at label size — never an opaque
   block that could hide the text. Display-only: no focus chrome, no
   motion. */
:is(npl-mood, .npl-mood) { display: block; margin: 1rem 0; }
/* JS-off lead line: the authored mood. Suppressed once upgraded (the chip
   then carries it). data-* spelling wins when both are present. */
:is(npl-mood, .npl-mood):not([data-sem-upgraded]):not([data-mood])::before {
  content: attr(mood); font-weight: 500; }
:is(npl-mood, .npl-mood):not([data-sem-upgraded])[data-mood]::before {
  content: attr(data-mood); font-weight: 500; }
/* Enhanced: the chip. */
:is(npl-mood, .npl-mood) > .npl-mood-chip {
  display: inline-flex; align-items: baseline; gap: .4em;
  padding: .15rem .6rem; border: 1px solid var(--sem-border);
  border-radius: 999px; background: var(--sem-surface); }
:is(npl-mood, .npl-mood) > .npl-mood-chip > .npl-mood-emoji {
  font-size: 1.1em; line-height: 1; }
:is(npl-mood, .npl-mood) > .npl-mood-chip > .npl-mood-qualifier {
  font-variant-caps: all-small-caps; letter-spacing: .05em;
  color: color-mix(in srgb, var(--sem-accent) 80%, var(--sem-fg)); }
/* Enhanced: the detail panel groups the authored tone / context / approach. */
:is(npl-mood, .npl-mood) > .npl-mood-detail { margin: .5rem 0 0; }
:is(npl-mood, .npl-mood) > .npl-mood-detail > :is(.npl-mood-tone, .npl-mood-context, .npl-mood-approach) {
  display: block; margin-top: .15rem; }
:is(npl-mood, .npl-mood) > .npl-mood-detail > :is(.npl-mood-tone, .npl-mood-context, .npl-mood-approach)::before {
  font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); font-weight: 400; }
:is(npl-mood, .npl-mood) > .npl-mood-detail > .npl-mood-tone::before { content: "tone · "; }
:is(npl-mood, .npl-mood) > .npl-mood-detail > .npl-mood-context::before { content: "context · "; }
:is(npl-mood, .npl-mood) > .npl-mood-detail > .npl-mood-approach::before { content: "approach · "; }
/* ── end npl-mood ── */

/* ── npl-mode ── */
/* npl-mode — cognitive lens declaration (component: src/lit/npl/npl-mode.ts).
   Display-only. The component mints one `.npl-mode-chip[data-type]` per
   typed `mode` child — `.npl-mode-chip-primary` on every chip when the
   declaration is primary, in either authoring spelling (the mirror writes
   the resolved `data-primary` on the host). These are the only consumers
   of the part classes; a lens chip is a label, never an occlusion: the
   label stays the foreground colour on the surface/accent tint it sits
   on (AA at the chip's reduced size), the primary mark is the accent
   border plus tint, never an opaque fill. Display-only: no focus chrome,
   no motion. */
:is(npl-mode, .npl-mode) > .npl-mode-chip {
  display: inline-block; margin: 0 .375rem .375rem 0;
  padding: .1rem .6rem; border: 1px solid var(--sem-border);
  border-radius: 999px; background: var(--sem-surface);
  color: var(--sem-fg); font-size: .8125rem; line-height: 1.5; }
:is(npl-mode, .npl-mode) > .npl-mode-chip-primary {
  border-color: color-mix(in srgb, var(--sem-accent) 55%, var(--sem-border));
  background: color-mix(in srgb, var(--sem-accent) 12%, transparent);
  font-weight: 600; }
/* ── end npl-mode ── */


/* ── npl-vos ── */
/* npl-vos — the psychodynamic-state bracket (component: src/lit/npl/npl-vos.ts).
   Display-only. The component mints a leading `.npl-vos-phase` bracket label
   and one `.npl-vos-row` per authored part (`.npl-vos-row-label` +
   `.npl-vos-row-body`); those part-class rules only bite once that chrome
   exists, so the JS-off box stays authored prose. JS-off, each part's own
   data-vos name still surfaces as a small-caps lead-in (attr(), the data-
   spelling guarded by the dual-form rule), so the bracket reads labelled
   without script — nothing hidden, nothing generated. The phase label is a
   quiet chip on the accent tint; rows read as a label/body grid down a
   single accent rule, the part name in accent-mixed small caps at AA for
   its size, the body in the foreground. Display-only: no focus chrome,
   no motion. */
:is(npl-vos, .npl-vos) { margin: 1rem 0; }
/* JS-off: surface the authored part name ahead of each part. data- wins
   when both spellings are present, so the bare rule is guarded. */
:is(npl-vos, .npl-vos):not([data-sem-upgraded]) > [vos]:not([data-vos])::before {
  content: attr(vos); }
:is(npl-vos, .npl-vos):not([data-sem-upgraded]) > [data-vos]::before {
  content: attr(data-vos); }
:is(npl-vos, .npl-vos):not([data-sem-upgraded]) > :is([vos], [data-vos])::before {
  font-variant-caps: all-small-caps; letter-spacing: .05em;
  color: var(--sem-muted); padding-right: .6em; }
/* Enhanced: the phase label leads the bracket as a quiet chip. */
:is(npl-vos, .npl-vos) > .npl-vos-phase {
  display: inline-block; margin: 0 0 .5rem; padding: .1rem .6rem;
  border: 1px solid color-mix(in srgb, var(--sem-accent) 65%, var(--sem-border));
  border-radius: 999px; background: color-mix(in srgb, var(--sem-accent) 12%, transparent);
  color: var(--sem-fg); font-size: .875rem; line-height: 1.5;
  font-variant-caps: all-small-caps; letter-spacing: .06em; }
/* Enhanced: the bracket itself — one accent rule down the left of the
   assembled rows, the "aside" reading, never an opaque panel over text. */
:is(npl-vos, .npl-vos) > .npl-vos-row {
  display: grid; grid-template-columns: minmax(6em, max-content) 1fr;
  gap: .1rem .75rem; padding: .25rem 0 .25rem .85rem;
  border-left: 2px solid color-mix(in srgb, var(--sem-accent) 35%, var(--sem-border)); }
:is(npl-vos, .npl-vos) > .npl-vos-row > .npl-vos-row-label {
  font-variant-caps: all-small-caps; letter-spacing: .05em; text-align: right;
  padding-top: .1em; color: color-mix(in srgb, var(--sem-accent) 75%, var(--sem-fg)); }
:is(npl-vos, .npl-vos) > .npl-vos-row > .npl-vos-row-body > :first-child { margin-top: 0; }
:is(npl-vos, .npl-vos) > .npl-vos-row > .npl-vos-row-body > :last-child { margin-bottom: 0; }
/* ── end npl-vos ── */


/* npl-agent — agent definition card (component: src/lit/npl/npl-agent.ts).
   The generated header (name · type · NPL@version, plus an `extends` part
   when a parent is authored) must read as card chrome, not as a run-on
   line of body words: the source form's `⌜…⌝` header marks those fields
   distinctly and the enhanced render carries the same information
   hierarchy. Small-caps field labels identify each part without relying
   on colour alone; the version renders `NPL@0.3`, the source grammar's
   own spelling. The card box is gated on the upgrade marker — JS-off the
   contract is plain prose, so no empty box frames it. Display-only: no
   focus chrome, no motion. */
:is(npl-agent, .npl-agent)[data-sem-upgraded] { border: 1px solid var(--sem-border);
  border-radius: 12px; padding: 1rem; margin: 1rem 0; background: var(--sem-surface); }
:is(npl-agent, .npl-agent)[data-sem-upgraded] > .npl-agent-header {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .125rem .875rem;
  padding-bottom: .5rem; margin-bottom: .75rem;
  border-bottom: 1px solid var(--sem-border); }
.npl-agent-header > .npl-agent-name { font-weight: 600; }
.npl-agent-header > :is(.npl-agent-type, .npl-agent-version, .npl-agent-extends) { color: var(--sem-muted); }
.npl-agent-header > :is(.npl-agent-name, .npl-agent-type, .npl-agent-version, .npl-agent-extends)::before {
  font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
.npl-agent-header > .npl-agent-name::before { content: "name · "; }
.npl-agent-header > .npl-agent-type::before { content: "type · "; }
.npl-agent-header > .npl-agent-version::before { content: "NPL@"; }
.npl-agent-header > .npl-agent-extends::before { content: "extends · "; }


/* ── npl-flag ── */
/* npl-flag — one runtime flag row (component: src/lit/npl/npl-flag.ts).
   The component renders the authored name into `.npl-flag-name` and the
   value into `.npl-flag-value`; the element itself is the apply control
   (role="button", focusable, `aria-pressed` mirrors the applied state).
   Every rule below is gated on the upgrade marker — JS-off the contract
   is plain prose, so no empty box frames a row whose name/value live in
   attributes. A flag is a labelled value the reader applies: the name
   reads as a muted mono label, the value as the row's payload, and the
   row carries a quiet hover/focus affordance. Nothing is ever occluded —
   an out-of-range value is a warning tint plus a glyph on the value span
   (the text stays fully readable; occlusion belongs to the quiz tier),
   and the applied state is a static check mark plus a calm border, never
   a motion effect. */
:is(npl-flag, .npl-flag)[data-sem-upgraded] { display: block; margin: .375rem 0;
  padding: .375rem .625rem; border: 1px solid var(--sem-border); border-radius: 8px;
  background: transparent; cursor: pointer; }
:is(npl-flag, .npl-flag)[data-sem-upgraded]:hover { border-color: color-mix(in srgb, var(--sem-accent) 55%, var(--sem-border)); }
:is(npl-flag, .npl-flag)[data-sem-upgraded]:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 1px; }
:is(npl-flag, .npl-flag)[data-sem-upgraded] > .npl-flag-name {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .875rem; color: var(--sem-muted); }
:is(npl-flag, .npl-flag)[data-sem-upgraded] > .npl-flag-name::after { content: " = "; }
:is(npl-flag, .npl-flag)[data-sem-upgraded] > .npl-flag-value { font-variant-numeric: tabular-nums; font-weight: 500; }
:is(npl-flag, .npl-flag)[data-sem-upgraded] > .npl-flag-value.npl-flag-invalid {
  background: color-mix(in srgb, var(--sem-note-warning) 16%, transparent);
  border-radius: 4px; padding: 0 .3em; }
:is(npl-flag, .npl-flag)[data-sem-upgraded] > .npl-flag-value.npl-flag-invalid::before {
  content: "⚠ "; color: var(--sem-note-warning); }
:is(npl-flag, .npl-flag)[data-applied] { border-color: color-mix(in srgb, var(--sem-correct) 55%, var(--sem-border)); }
:is(npl-flag, .npl-flag)[data-sem-upgraded] > .npl-flag-value.npl-flag-applied::after {
  content: " ✓"; color: var(--sem-correct); font-weight: 600; }
/* ── end npl-flag ── */


/* ── npl-flags ── */
/* npl-flags — preset-flagged runtime config block (component:
   src/lit/npl/npl-flags.ts). The component's only chrome is the
   `.npl-flags-preset` badge, hoisted ahead of the authored `npl-flag`
   children and note text; those children and notes are the author's own
   light DOM and the npl-flag block above styles them, so nothing here
   touches them. The container keeps the schema's `display: block` and
   frames the block as a card (border + surface), matching the npl-critique
   / npl-declaration family. The badge is accent-tinted chrome — `--sem-fg`
   on a 14% tint, AA at all sizes — and a badge for an unknown preset keeps
   the same shape in the note-warning colour AND appends an "unknown" cue,
   so the warning never rides on colour alone. Display-only: no focus
   chrome, no motion. */
:is(npl-flags, .npl-flags) { border: 1px solid var(--sem-border); border-radius: 12px;
  padding: 1rem; margin: 1rem 0; background: var(--sem-surface); }
:is(npl-flags, .npl-flags) > .npl-flags-preset {
  display: inline-block; margin: 0 0 .625rem; padding: .1rem .55rem;
  border: 1px solid color-mix(in srgb, var(--sem-accent) 55%, var(--sem-border));
  border-radius: 999px;
  background: color-mix(in srgb, var(--sem-accent) 14%, var(--sem-surface));
  color: var(--sem-fg); font-weight: 600; font-size: .72rem; line-height: 1.5;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-variant-caps: all-small-caps; letter-spacing: .05em; }
:is(npl-flags, .npl-flags) > .npl-flags-preset-invalid {
  border-style: dashed; border-color: var(--sem-note-warning);
  background: color-mix(in srgb, var(--sem-note-warning) 16%, var(--sem-surface));
  color: color-mix(in srgb, var(--sem-note-warning) 70%, var(--sem-fg)); }
:is(npl-flags, .npl-flags) > .npl-flags-preset-invalid::after { content: " — unknown"; }
/* ── end npl-flags ── */

/* sem-shell / sem-terminal — the interactive shell (light DOM: this
   stylesheet is the only style channel; every rule scopes to both the
   reusable core and the demo element). With the script absent the
   authored static transcript keeps these classes and reads as a terminal
   excerpt; the prompt line only ever exists after the upgrade. */
sem-terminal, sem-shell { display: block; }
sem-terminal .sem-shell-frame, sem-shell .sem-shell-frame { background: #101418; border: 1px solid var(--sem-border, #ccc); border-radius: 12px; color: #d6dde6;
  font: 13px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; padding: .75rem 1rem; max-height: 24rem; overflow: auto; }
sem-terminal .sem-shell-transcript, sem-shell .sem-shell-transcript { white-space: pre-wrap; overflow-wrap: anywhere; }
sem-terminal .sem-shell-line:empty::before, sem-shell .sem-shell-line:empty::before { content: "\00a0"; }
sem-terminal .sem-shell-cmd, sem-shell .sem-shell-cmd { color: #fff; }
sem-terminal .sem-shell-ps1, sem-shell .sem-shell-ps1 { color: #7ec8a2; }
sem-terminal .sem-shell-error, sem-shell .sem-shell-error { color: #ff8f7a; }
sem-terminal .sem-shell-prompt, sem-shell .sem-shell-prompt { display: flex; gap: .5rem; margin-top: .5rem; align-items: baseline; }
sem-terminal .sem-shell-input, sem-shell .sem-shell-input { flex: 1; min-width: 0; background: transparent; border: 0; border-top: 1px solid var(--sem-border, #ccc);
  color: inherit; font: inherit; padding: .35rem 0 .1rem; outline: none; }
sem-terminal .sem-shell-input:focus, sem-shell .sem-shell-input:focus { border-top-color: #7ec8a2; }
sem-terminal, sem-shell { position: relative; }
sem-terminal .sem-shell-replay, sem-shell .sem-shell-replay { position: absolute; top: .55rem; right: .7rem; background: transparent; color: #7ec8a2;
  border: 1px solid #2c3a37; border-radius: 6px; font: 600 11px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  padding: .25rem .55rem; cursor: pointer; opacity: .8; }
sem-terminal .sem-shell-replay:hover, sem-shell .sem-shell-replay:hover { opacity: 1; border-color: #7ec8a2; }
sem-terminal .sem-shell-status, sem-shell .sem-shell-status { color: #5b6b64; }
sem-terminal .sem-shell-comment, sem-shell .sem-shell-comment { color: #9aa7b5; font-style: italic; }
/* ANSI from commands (ls dir color, bat highlighting): fixed-code whitelist → spans */
sem-terminal .sem-ansi-b, sem-shell .sem-ansi-b { font-weight: 600; }
sem-terminal .sem-ansi-dim, sem-shell .sem-ansi-dim { opacity: .55; }
sem-terminal .sem-ansi-c30, sem-shell .sem-ansi-c30 { color: #4b5563; }
sem-terminal .sem-ansi-c31, sem-shell .sem-ansi-c31 { color: #ff8f7a; }
sem-terminal .sem-ansi-c32, sem-shell .sem-ansi-c32 { color: #8fd6a0; }
sem-terminal .sem-ansi-c33, sem-shell .sem-ansi-c33 { color: #e6c77a; }
sem-terminal .sem-ansi-c34, sem-shell .sem-ansi-c34 { color: #7ab8e6; }
sem-terminal .sem-ansi-c35, sem-shell .sem-ansi-c35 { color: #c79ae6; }
sem-terminal .sem-ansi-c36, sem-shell .sem-ansi-c36 { color: #6fd3d3; }
sem-terminal .sem-ansi-c37, sem-shell .sem-ansi-c37 { color: #d6dde6; }
/* the read-only flashcard view (semtext tui) */
sem-terminal .sem-tui, sem-shell .sem-tui { outline: none; margin-top: .5rem; display: flex; flex-direction: column; gap: .45rem; }
sem-terminal .sem-tui-head, sem-shell .sem-tui-head { color: #7ec8a2; }
sem-terminal .sem-tui-card, sem-shell .sem-tui-card { border: 1px solid #2c3a37; border-radius: 8px; padding: .5rem .7rem; background: #161b21; white-space: pre-wrap; }
sem-terminal .sem-tui-front, sem-shell .sem-tui-front { color: #fff; font-weight: 600; }
sem-terminal .sem-tui-back, sem-shell .sem-tui-back { color: #d6dde6; font-weight: 400; }
sem-terminal .sem-tui-meta, sem-shell .sem-tui-meta { color: #5b6b64; }
sem-terminal .sem-tui-empty, sem-shell .sem-tui-empty { font-weight: 400; color: #9aa7b5; }
sem-terminal .sem-tui-filter, sem-shell .sem-tui-filter { background: transparent; border: 0; border-bottom: 1px solid #2c3a37; color: inherit;
  font: inherit; padding: .25rem 0; outline: none; }
sem-terminal .sem-tui-filter:focus, sem-shell .sem-tui-filter:focus { border-bottom-color: #7ec8a2; }
sem-terminal .sem-tui-hint, sem-shell .sem-tui-hint { color: #5b6b64; }
@media print {
  sem-terminal .sem-shell-frame, sem-shell .sem-shell-frame { max-height: none; overflow: visible; background: none; border: 0; color: inherit; }
  sem-terminal .sem-shell-prompt, sem-shell .sem-shell-prompt { display: none; }
  sem-terminal .sem-shell-replay, sem-shell .sem-shell-replay { display: none; }
}

/* ── npl-hormones ── */
/* Synthetic-hormones panel (component: src/lit/npl/npl-hormones.ts).
   The component renders `.npl-hormones-row` bars plus state/triggered
   lines and `.npl-hormones-alert` cards; the rules below key on those
   part classes. JS-off, the box stays the authored prose the schema
   promises (only the box rule in the npl enumeration applies). JS-on,
   the authored `panel`/`state`/`triggered`/`alert` sources are hidden —
   the generated panel re-presents them, so nothing is shown twice (same
   upgrade-gated contract as sem-views). Display-only: no focus chrome,
   no motion. Colour never carries meaning alone: fired rows keep the
   accent bar + tint (never opaque — text stays fully readable), delta
   arrows carry their own glyph, and clamped values keep the numeric
   readout. */
:is(npl-hormones, .npl-hormones)[data-sem-upgraded] > :is(panel, state, triggered, alert) { display: none; }
:is(npl-hormones, .npl-hormones)[data-sem-upgraded] { padding: .25rem 0; }
:is(npl-hormones, .npl-hormones) .npl-hormones-row {
  display: grid; grid-template-columns: 3em minmax(6em, auto) 1fr 2.5em 1.25em;
  gap: 0 .6em; align-items: center; padding: .3rem .5rem;
  border-left: 3px solid transparent; border-radius: 6px; }
:is(npl-hormones, .npl-hormones) .npl-hormones-symbol {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8125rem; letter-spacing: .02em; color: var(--sem-muted); }
:is(npl-hormones, .npl-hormones) .npl-hormones-name { font-size: .875rem; }
:is(npl-hormones, .npl-hormones) .npl-hormones-bar {
  display: block; height: .5rem; min-width: 4rem; border-radius: 999px;
  background: var(--sem-border); overflow: hidden; }
:is(npl-hormones, .npl-hormones) .npl-hormones-fill {
  display: block; height: 100%; border-radius: 999px;
  background: color-mix(in srgb, var(--sem-accent) 80%, var(--sem-fg)); }
:is(npl-hormones, .npl-hormones) .npl-hormones-value {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8125rem; text-align: right; font-variant-numeric: tabular-nums; }
:is(npl-hormones, .npl-hormones) .npl-hormones-delta { text-align: center; font-size: .875rem; }
:is(npl-hormones, .npl-hormones) .npl-hormones-delta[data-delta="up"] {
  color: color-mix(in srgb, var(--sem-correct) 75%, var(--sem-fg)); }
:is(npl-hormones, .npl-hormones) .npl-hormones-delta[data-delta="down"] {
  color: color-mix(in srgb, var(--sem-wrong) 75%, var(--sem-fg)); }
:is(npl-hormones, .npl-hormones) .npl-hormones-delta[data-delta="flat"] { color: var(--sem-muted); }
/* the fired row: accent bar + tint, never opaque — the row reads as
   highlighted while every value stays fully legible */
:is(npl-hormones, .npl-hormones) .npl-hormones-row[data-fired] {
  border-left-color: var(--sem-accent);
  background: color-mix(in srgb, var(--sem-accent) 12%, transparent); }
/* a clamped row marks its value readout; the raw authored value rides
   the row's data-value attribute for extraction */
:is(npl-hormones, .npl-hormones) .npl-hormones-row[data-clamped] .npl-hormones-value {
  text-decoration: underline dotted color-mix(in srgb, var(--sem-wrong) 75%, var(--sem-fg)); }
:is(npl-hormones, .npl-hormones) .npl-hormones-state,
:is(npl-hormones, .npl-hormones) .npl-hormones-triggered {
  margin-top: .5rem; padding: 0 .5rem; font-size: .8125rem; color: var(--sem-muted); }
:is(npl-hormones, .npl-hormones) .npl-hormones-alert {
  display: block; margin: .5rem 0; padding: .5rem .75rem;
  border: 1px solid color-mix(in srgb, var(--sem-wrong) 45%, var(--sem-border));
  border-left: 3px solid var(--sem-wrong); border-radius: 6px;
  background: color-mix(in srgb, var(--sem-wrong) 8%, transparent); }
:is(npl-hormones, .npl-hormones) .npl-hormones-alert-head {
  display: block; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8125rem; letter-spacing: .02em;
  color: color-mix(in srgb, var(--sem-wrong) 75%, var(--sem-fg)); }
:is(npl-hormones, .npl-hormones) .npl-hormones-alert-body { display: block; margin-top: .25rem; font-size: .875rem; }
/* ── end npl-hormones ── */

/* ── npl-rubric ── */
/* npl-rubric — display-only weighted scoring rubric (component:
   src/lit/npl/npl-rubric.ts). The component renders one light-DOM
   `.npl-rubric-table`: a titled caption, a `.npl-rubric-criterion` row per
   authored criterion (weight · score right-aligned, tabular figures), and a
   `.npl-rubric-overall` footer row carrying the stated or computed figure.
   Class-form criteria (`.npl-criterion`) upgrade through the same table, so
   the two authoring forms read identically. The card box is gated on the
   upgrade marker — JS-off the authored criteria read as plain prose, so no
   empty frame is drawn. A rubric is read at a glance: the overall figure is
   the decision line, so the footer takes the family's accent bar + tint
   (never opaque — every figure stays fully legible), and an excluded
   criterion is quieted with its reason spelled out in words, never colour
   alone. Display-only: no focus chrome, no motion. */
:is(npl-rubric, .npl-rubric)[data-sem-upgraded] {
  border: 1px solid var(--sem-border); border-radius: 12px;
  padding: .875rem 1rem 1rem; margin: 1rem 0; background: var(--sem-surface);
  overflow-x: auto; }
:is(npl-rubric, .npl-rubric) .npl-rubric-table {
  width: 100%; border-collapse: collapse; text-align: left; font-size: .875rem; }
:is(npl-rubric, .npl-rubric) .npl-rubric-title {
  text-align: left; padding: 0 0 .5rem; font-weight: 600; font-size: .9375rem;
  color: var(--sem-fg); }
:is(npl-rubric, .npl-rubric) .npl-rubric-table thead th {
  padding: .35rem .5rem; border-bottom: 1px solid var(--sem-border);
  font-size: .75rem; font-weight: 500; text-transform: uppercase;
  letter-spacing: .06em; color: var(--sem-muted); }
:is(npl-rubric, .npl-rubric) .npl-rubric-table thead th:nth-child(n + 2),
:is(npl-rubric, .npl-rubric) .npl-rubric-criterion > td {
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
:is(npl-rubric, .npl-rubric) .npl-rubric-criterion {
  border-bottom: 1px solid color-mix(in srgb, var(--sem-border) 60%, transparent); }
:is(npl-rubric, .npl-rubric) .npl-rubric-criterion > th {
  padding: .4rem .5rem; font-weight: 500; color: var(--sem-fg); }
:is(npl-rubric, .npl-rubric) .npl-rubric-criterion > td {
  padding: .4rem .5rem; color: var(--sem-fg); }
/* an excluded row stays visible, quieted; the reason is spelled in words
   (`.npl-rubric-flag`), never signalled by colour alone */
:is(npl-rubric, .npl-rubric) .npl-rubric-criterion[data-excluded] > th,
:is(npl-rubric, .npl-rubric) .npl-rubric-criterion[data-excluded] > td { color: var(--sem-muted); }
:is(npl-rubric, .npl-rubric) .npl-rubric-flag {
  display: block; margin-top: .1rem; font-size: .75rem; font-weight: 400;
  color: color-mix(in srgb, var(--sem-wrong) 75%, var(--sem-fg)); }
/* the decision line: the overall figure, accent bar + tint, never opaque */
:is(npl-rubric, .npl-rubric) .npl-rubric-overall > th {
  padding: .5rem .5rem .5rem .6rem; border-left: 3px solid var(--sem-accent);
  border-radius: 6px 0 0 6px; font-weight: 600;
  background: color-mix(in srgb, var(--sem-accent) 12%, transparent); }
:is(npl-rubric, .npl-rubric) .npl-rubric-overall > td {
  padding: .5rem .5rem; border-radius: 0 6px 6px 0; text-align: right;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1rem; font-weight: 700; font-variant-numeric: tabular-nums;
  background: color-mix(in srgb, var(--sem-accent) 12%, transparent); }
:is(npl-rubric, .npl-rubric) .npl-rubric-source {
  margin-left: .4em; font-size: .7rem; font-weight: 400;
  font-variant-caps: all-small-caps; letter-spacing: .05em; color: var(--sem-muted); }
/* ── end npl-rubric ── */

/* ── npl-thought ── */
/* npl-thought — display-only typed associative thought bubble (component:
   src/lit/npl/npl-thought.ts). The authored set is a stack of typed children;
   each child annotates itself with `.npl-thought-<type>` and mirrors the
   resolved type to `data-type`, so one rule names the type with
   `attr(data-type)` instead of eleven hand-written labels. A thought reads
   as a quiet margin note — an accent rule, a faint tint and a small-caps
   type label — with its text always fully legible (nothing occluded;
   occlusion belongs to sem-spoiler / the quiz tier). The label is the
   non-colour cue: the eleven types are told apart by name, never by hue
   alone, and a theme varies the accent through the `.npl-thought-<type>`
   hook. An unknown type keeps the warning treatment — a dashed rule and an
   "unknown" suffix on the label — again never colour alone. Display-only:
   no focus chrome, no motion. Every rule hangs off the authored `data-type`,
   so JS-off (no mirror, no class, no attribute) a thought reads as plain
   prose. */
:is(npl-thought, .npl-thought) > :is(npl-thought, .npl-thought)[data-type] {
  display: block; margin: .5rem 0; padding: .35rem .55rem .35rem .7rem;
  border-left: 3px solid color-mix(in srgb, var(--sem-accent) 65%, var(--sem-border));
  border-radius: 0 8px 8px 0;
  background: color-mix(in srgb, var(--sem-accent) 6%, transparent); }
:is(npl-thought, .npl-thought) > :is(npl-thought, .npl-thought)[data-type]::before {
  content: attr(data-type); display: block;
  font-variant-caps: all-small-caps; letter-spacing: .06em;
  font-size: .72rem; font-weight: 600; line-height: 1.35; color: var(--sem-muted); }
/* the warning: an unknown type is named, never signalled by colour alone */
:is(npl-thought, .npl-thought) > :is(npl-thought, .npl-thought).npl-thought-unknown {
  border-left-style: dashed;
  border-left-color: color-mix(in srgb, var(--sem-note-warning) 85%, var(--sem-border));
  background: color-mix(in srgb, var(--sem-note-warning) 8%, transparent); }
:is(npl-thought, .npl-thought) > :is(npl-thought, .npl-thought).npl-thought-unknown::before {
  content: attr(data-type) " · unknown";
  color: color-mix(in srgb, var(--sem-note-warning) 72%, var(--sem-fg)); }
/* ── end npl-thought ── */

/* ── npl-section ── */
/* npl-section — generic typed section (component: src/lit/npl/npl-section.ts).
   A known `type` renders one `.npl-section-header` label as the first child
   ("Algorithm", "Pseudocode", …) and `npl-section-<type>` on the host; an
   unknown or missing type renders no label and `npl-section-warning`.
   Display-only chrome: the label is a small-caps rule above the body and the
   body stays fully legible beneath it — nothing occluded (hiding content
   belongs to sem-spoiler / the quiz tier). The unknown-type signal is a
   dashed warning rule plus the authored value named beside it — the reader
   is never told by colour alone — while the body still reads as plain prose.
   Every rule hangs off the upgrade marker, so JS-off the contract stays the
   plain block box from the shared npl lines. No focus chrome, no motion. */
:is(npl-section, .npl-section)[data-sem-upgraded] { margin: .875rem 0; }
:is(npl-section, .npl-section)[data-sem-upgraded] > .npl-section-header {
  display: block;
  font-variant-caps: all-small-caps; letter-spacing: .06em;
  font-size: .75rem; font-weight: 600; line-height: 1.4;
  color: var(--sem-muted);
  padding-bottom: .25rem; margin-bottom: .5rem;
  border-bottom: 1px solid color-mix(in srgb, var(--sem-border) 60%, transparent); }
/* the warning: name the problem, never colour alone — the resolved value is
   already mirrored to [data-type], so the label spells it out in words */
:is(npl-section, .npl-section)[data-sem-upgraded].npl-section-warning {
  border-left: 3px dashed color-mix(in srgb, var(--sem-note-warning) 85%, var(--sem-border));
  padding-left: .75rem; }
:is(npl-section, .npl-section)[data-sem-upgraded].npl-section-warning::before {
  content: attr(data-type) " · unknown type";
  display: block;
  font-variant-caps: all-small-caps; letter-spacing: .06em;
  font-size: .75rem; font-weight: 600; line-height: 1.4;
  color: color-mix(in srgb, var(--sem-note-warning) 72%, var(--sem-fg));
  margin-bottom: .5rem; }
/* a missing type mirrors no data-type — the label says so without attr() */
:is(npl-section, .npl-section)[data-sem-upgraded].npl-section-warning:not([data-type])::before {
  content: "section · missing type"; }
:is(npl-section, .npl-section)[data-sem-upgraded] pre {
  overflow-x: auto; max-width: 100%; }
/* ── end npl-section ── */

/* ============================================================
   semext-* — SemText extension components (src/lit/semext/;
   recipe: that barrel's header). Introduced EMPTY by the
   epic.semext-components walking skeleton: the namespace machinery
   (bundle, lazy loader, manifest, contract scaffolding) ships before
   the first component.

   The same box contract the sem-* enumeration above gives every sem-*
   tag: custom elements are inline by default, the vocabulary is
   block-level, so each tag gets its box before any definition —
   `:not(:defined)` pre-upgrade, and for any element that never defines
   one, alike. The class-namespace alias follows conventions Appendix A
   (`:is(semext-x, .semext-x)`, one rule per authoring form).

   ONE LINE PER TAG, ALPHABETICAL. A new component inserts its own line
   here — nothing shared is ever edited, so parallel component branches
   merge clean. Do NOT convert this into one comma list.
   ============================================================ */
/* first component inserts its display line here, e.g.
   semext-canvas, .semext-canvas { display: block; } */

/* Family B (feat/semext-embeds): the nine service-backed embeds over the
   cached-embed base. Cards use the vocabulary tokens only (var(--sem-*));
   nothing hard-coded. */

semext-annotate, .semext-annotate { display: block; }
semext-docptr, .semext-docptr { display: block; }
semext-media-prompt, .semext-media-prompt { display: block; }
semext-sig-logs, .semext-sig-logs { display: block; }
semext-sig-metrics, .semext-sig-metrics { display: block; }
semext-sig-synthetic-monitor, .semext-sig-synthetic-monitor { display: block; }
semext-sig-traces, .semext-sig-traces { display: block; }
semext-styleguide-theme, .semext-styleguide-theme { display: block; }
semext-styleguide-themes, .semext-styleguide-themes { display: block; }

/* shared card chrome — the cached-embed chrome div + the sig cards */
.sem-cached-embed-chrome {
  margin-top: .5rem;
  border: 1px solid color-mix(in srgb, var(--sem-border) 70%, transparent);
  border-radius: .375rem;
  padding: .625rem .75rem;
  font-size: .875rem; }
.sem-cached-embed-chrome[data-sem-chrome-source="error"] {
  color: var(--sem-muted); font-style: italic; }

/* docptr — pointer locator card */
.semext-docptr-card { margin: 0; }
.semext-docptr-locator {
  font-family: var(--sem-mono, ui-monospace, monospace);
  font-size: .8125rem; font-weight: 600; }
.semext-docptr-kind, .semext-docptr-class, .semext-docptr-fn, .semext-docptr-marker {
  font-variant-caps: all-small-caps; letter-spacing: .06em;
  color: var(--sem-muted); margin-right: .5rem; }
.semext-docptr-desc { margin: .25rem 0 0; }
.semext-docptr-snippet {
  margin: .5rem 0 0; padding: .5rem;
  background: color-mix(in srgb, var(--sem-border) 22%, transparent);
  border-radius: .25rem; overflow-x: auto; }
.semext-docptr-missing { color: var(--sem-muted); font-style: italic; margin: 0; }

/* styleguide — theme token cards */
.semext-styleguide-theme-card { margin: 0; }
.semext-styleguide-theme-card h3 { margin: 0 0 .25rem; font-size: 1rem; }
.semext-styleguide-theme-swatches { list-style: none; display: flex; gap: .375rem; padding: 0; margin: .25rem 0; }
.semext-styleguide-theme-dot {
  display: inline-block; width: 1rem; height: 1rem;
  border-radius: 50%; border: 1px solid color-mix(in srgb, var(--sem-border) 80%, transparent); }
.semext-styleguide-theme-typo { margin: .25rem 0; color: var(--sem-muted); font-size: .8125rem; }
.semext-styleguide-theme-preview { font-size: .8125rem; }
.semext-styleguide-themes-summary { color: var(--sem-muted); font-size: .8125rem; margin: 0; }

/* annotate — visitor threads (text-only chrome) */
.semext-annotate-head { color: var(--sem-muted); font-size: .8125rem; margin: 0 0 .375rem; }
.semext-annotate-empty { color: var(--sem-muted); font-style: italic; margin: 0; }
.semext-annotate-thread { border-top: 1px solid color-mix(in srgb, var(--sem-border) 55%, transparent); padding: .375rem 0; margin: 0; }
.semext-annotate-thread:first-of-type { border-top: 0; }
.semext-annotate-status {
  font-variant-caps: all-small-caps; letter-spacing: .06em;
  color: var(--sem-muted); margin-right: .375rem; }
.semext-annotate-title { font-weight: 600; margin-right: .375rem; }
.semext-annotate-anchor {
  margin: .25rem 0; padding: .25rem .5rem;
  border-left: 2px solid color-mix(in srgb, var(--sem-border) 70%, transparent);
  color: var(--sem-muted); font-style: italic; }
.semext-annotate-comment { margin: .25rem 0 0; }
.semext-annotate-author { font-weight: 600; margin-right: .375rem; }
.semext-annotate-when { color: var(--sem-muted); font-size: .75rem; margin-right: .375rem; }

/* sig — metrics / traces / logs cards */
.semext-sig-card { margin: 0; }
.semext-sig-title { margin: 0 0 .25rem; font-size: 1rem; }
.semext-sig-table { width: 100%; border-collapse: collapse; font-size: .8125rem; }
.semext-sig-table th, .semext-sig-table td {
  text-align: left; padding: .25rem .5rem;
  border-bottom: 1px solid color-mix(in srgb, var(--sem-border) 50%, transparent); }
.semext-sig-traces, .semext-sig-monitor-asserts { list-style: none; padding: 0; margin: 0; }
.semext-sig-trace { padding: .25rem 0; border-bottom: 1px solid color-mix(in srgb, var(--sem-border) 50%, transparent); }
.semext-sig-trace:last-child { border-bottom: 0; }
.semext-sig-trace[data-error="true"] .semext-sig-trace-root { font-weight: 600; }
.semext-sig-trace-id { font-family: var(--sem-mono, ui-monospace, monospace); font-size: .75rem; margin-right: .5rem; }
.semext-sig-trace-root { font-weight: 500; margin-right: .5rem; }
.semext-sig-trace-meta { color: var(--sem-muted); font-size: .8125rem; }
.semext-sig-loglines { list-style: none; padding: 0; margin: 0; font-family: var(--sem-mono, ui-monospace, monospace); font-size: .75rem; }
.semext-sig-logline { padding: .125rem 0; display: flex; gap: .5rem; flex-wrap: wrap; }
.semext-sig-log-ts { color: var(--sem-muted); }
.semext-sig-log-sev::before { content: "["; }
.semext-sig-log-sev::after { content: "]"; }
.semext-sig-logline[data-severity="error"] .semext-sig-log-sev { font-weight: 700; }
.semext-sig-monitor-interval { color: var(--sem-muted); font-size: .8125rem; margin: 0; }
.semext-sig-linkline { margin: .5rem 0 0; }
.semext-sig-link { font-size: .8125rem; }

/* media-prompt — authored prompt + output cache region */
.semext-media-prompt-chrome { margin-top: .5rem; }
.semext-media-prompt-params { margin: 0 0 .25rem; display: flex; gap: .375rem; flex-wrap: wrap; }
.semext-media-prompt-param {
  font-variant-caps: all-small-caps; letter-spacing: .06em;
  border: 1px solid color-mix(in srgb, var(--sem-border) 70%, transparent);
  border-radius: 999px; padding: 0 .5rem; font-size: .75rem; }
.semext-media-prompt-dir { font-family: var(--sem-mono, ui-monospace, monospace); font-size: .75rem; }
.semext-media-prompt-state { color: var(--sem-muted); font-size: .8125rem; margin: 0; }
.semext-media-prompt-empty {
  color: var(--sem-muted); font-style: italic; font-size: .8125rem; margin: 0;
  border: 1px dashed color-mix(in srgb, var(--sem-border) 80%, transparent);
  border-radius: .25rem; padding: .375rem .5rem; }
semext-media-prompt[data-semext-cache-region="empty"] > pre { opacity: .85; }

/* ============================================================
   agent-kit-* — agent-kit components (src/lit/agent-kit/; recipe: that
   barrel's header). Introduced EMPTY by the epic.semext-components
   walking skeleton: the namespace machinery (bundle, lazy loader,
   manifest, contract scaffolding) ships before the first component.

   The same box contract the sem-* enumeration above gives every sem-*
   tag: custom elements are inline by default, the vocabulary is
   block-level, so each tag gets its box before any definition —
   `:not(:defined)` pre-upgrade, and for any element that never defines
   one, alike. The class-namespace alias follows conventions Appendix A
   (`:is(agent-kit-x, .agent-kit-x)`, one rule per authoring form).

   ONE LINE PER TAG, ALPHABETICAL. A new component inserts its own line
   here — nothing shared is ever edited, so parallel component branches
   merge clean. Do NOT convert this into one comma list.
   ============================================================ */
agent-kit-acceptance-criteria, .agent-kit-acceptance-criteria { display: block; }
agent-kit-agent-persona, .agent-kit-agent-persona { display: block; }
agent-kit-artifact, .agent-kit-artifact { display: block; }
agent-kit-asset, .agent-kit-asset { display: block; }
agent-kit-board, .agent-kit-board { display: block; }
agent-kit-bug, .agent-kit-bug { display: block; }
agent-kit-chatroom, .agent-kit-chatroom { display: block; }
agent-kit-cucumber, .agent-kit-cucumber { display: block; }
agent-kit-cypress, .agent-kit-cypress { display: block; }
agent-kit-custom-assert, .agent-kit-custom-assert { display: block; }
agent-kit-epic, .agent-kit-epic { display: block; }
agent-kit-issue, .agent-kit-issue { display: block; }
agent-kit-organization, .agent-kit-organization { display: block; }
agent-kit-project, .agent-kit-project { display: block; }
agent-kit-review, .agent-kit-review { display: block; }
agent-kit-sub-task, .agent-kit-sub-task { display: block; }
agent-kit-task, .agent-kit-task { display: block; }
agent-kit-test-case, .agent-kit-test-case { display: block; }
agent-kit-test-suite, .agent-kit-test-suite { display: block; }
agent-kit-ticket-ref, .agent-kit-ticket-ref { display: block; }
agent-kit-user-persona, .agent-kit-user-persona { display: block; }
agent-kit-user-story, .agent-kit-user-story { display: block; }

/* ── sem-code ── */
/* JS-off the language badge is a caption too (schema/sem-code.md: "the
   filename renders as a caption through ::before …; the language badge
   likewise"). The filename caption owns ::before whenever a filename is
   authored, so these two rules fire only for a lang-only listing — e.g.
   `lang="sh"` with no provenance — which otherwise showed no badge at all.
   Dual spelling mirrors the filename pair: the styling rule keys on either
   spelling, then a later rule swaps the content to the bare `lang` value
   when no `data-lang` is present. */
:is(sem-code, .sem-code):not(:has(> .sem-code-chrome)):is([data-lang], [lang]):not(:is([data-filename], [filename]))::before {
  content: attr(data-lang); display: block; padding: .4rem 1rem; font-size: .7rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--sem-muted);
  text-transform: uppercase; letter-spacing: .05em;
  border-bottom: 1px solid var(--sem-border); }
:is(sem-code, .sem-code):not(:has(> .sem-code-chrome))[lang]:not([data-lang]):not(:is([data-filename], [filename]))::before {
  content: attr(lang); }
/* ── end sem-code ── */

/* ── npl-ref ── */
/* npl-ref — display-only post-hoc reflection (component: src/lit/npl/npl-ref.ts).
   `full` labels each authored section in place: the component adds
   `.npl-ref-section[data-section]` and a `.npl-ref-label` small-caps header
   as the section's first child; `compact` hides the authored sections and
   appends a `.npl-ref-lines` list of one `.npl-ref-line` per section. Both
   authoring spellings (tag and `.npl-<name>` class) upgrade through the
   same chrome, so they read identically. The card box is gated on the
   upgrade marker — JS-off the authored sections read as plain prose and no
   empty frame is drawn. A reflection is a record, not a verdict: the five
   slots stay visually equal (quiet small-caps labels, no accent hierarchy
   between them), sections divide by hairlines rather than boxes, and the
   compact lines keep the emoji as their only mark beside the spelled-out
   label. Display-only: no focus chrome, no motion; the compact variant's
   hidden sections are never the only copy — each is mirrored into a
   visible line. */
:is(npl-ref, .npl-ref)[data-sem-upgraded] {
  border: 1px solid var(--sem-border); border-radius: 12px;
  padding: .625rem 1rem .875rem; margin: 1rem 0; background: var(--sem-surface);
  overflow-x: auto; }
:is(npl-ref, .npl-ref) .npl-ref-section { display: block; }
:is(npl-ref, .npl-ref) .npl-ref-section:not(:last-child) {
  padding-bottom: .55rem; margin-bottom: .55rem;
  border-bottom: 1px solid color-mix(in srgb, var(--sem-border) 60%, transparent); }
:is(npl-ref, .npl-ref) .npl-ref-label {
  padding: .1rem 0 .2rem; font-size: .72rem; font-weight: 600;
  font-variant-caps: all-small-caps; letter-spacing: .06em;
  color: var(--sem-muted); }
:is(npl-ref, .npl-ref) .npl-ref-lines { margin: 0; padding: 0; list-style: none; }
:is(npl-ref, .npl-ref) .npl-ref-line {
  margin: .2rem 0; font-size: .875rem; line-height: 1.55; color: var(--sem-fg); }
/* ── end npl-ref ── */

/* ── sem-detail ── */
/* A passage is prose, not a control: reveal happens on its <highlight>
   chips only. The shared "details + highlight" rule above sets
   cursor: pointer on the card — a false affordance in both views (no
   handler is ever wired to the passage; lit + fallback + demo confirm
   chip-only clicks). Neutralize it here; cross-lane request open to drop
   the pointer at its source. cursor: text keeps the prose selectable and
   honest. */
:is(sem-detail, .sem-detail) { cursor: text; }
/* ── end sem-detail ── */

/* ── sem-fact ── */
/* A fact is a card, not prose. In flashcards view the current <sem-fact>
   is a click-to-flip control (schema/sem-facts.md: "Click a card to flip"),
   so a press-drag over the statement flipped the card AND text-selected the
   claim underneath. Make the flip target non-selectable there; list and
   quiz views keep their text selectable (a reader may want to copy a
   conclusion; only the flipping card is a control). */
:is(sem-facts, .sem-facts)[data-view-as="flashcards"] :is(sem-fact, .sem-fact) {
  user-select: none; -webkit-user-select: none; }
/* ── end sem-fact ── */

/* ── sem-facts ── */
/* deck chrome — the meter is the deck's position readout, so it sits
   centred between the arrows (tabular digits stop it jittering); the
   arrows take the row ends, the pattern every deck app uses. Touch
   targets clear 44px. */
.sem-facts-chrome { align-items: stretch; }
.sem-facts-chrome .sem-facts-meter { flex: 1; display: flex; align-items: center;
  justify-content: center; font-variant-numeric: tabular-nums; gap: .25rem; flex-wrap: wrap; }
/* 0.9.1: the meter is an INDEX of the deck (one chip per card, current
   highlighted), not a count readout — chips are chrome buttons, so the
   hover/focus rules above already apply. */
.sem-facts-meter button { font: inherit; font-size: .8125rem; padding: .125rem .5rem;
  border-radius: 999px; color: var(--sem-muted); }
.sem-facts-meter button[aria-current="true"] { background: var(--sem-accent);
  border-color: var(--sem-accent); color: var(--sem-accent-fg); }
.sem-facts-meter button.sem-facts-done[data-verdict="got"] { color: var(--sem-correct); border-color: var(--sem-correct); }
.sem-facts-meter button.sem-facts-done[data-verdict="miss"] { color: var(--sem-wrong); border-color: var(--sem-wrong); }
@media (pointer: coarse) {
  .sem-facts-chrome button { min-width: 2.75rem; min-height: 2.75rem; }
}
.sem-facts-chrome button:hover { border-color: var(--sem-accent); }
.sem-facts-chrome button:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; }

/* flashcards — the two faces overlay in one grid cell, so a flip never
   jumps the layout and the unrevealed conclusion reserves no dead gap
   (the shared visibility rules pick which face reads; card height is
   max(front, back) at all times). The flipped face drops out of both
   sight and the AT order while the back is up. */
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(sem-fact, .sem-fact).sem-current { display: grid; }
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(statement, .sem-statement),
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(conclusion, .sem-conclusion) { grid-area: 1 / 1; }
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(sem-fact, .sem-fact).sem-flipped :is(statement, .sem-statement) { visibility: hidden; }
/* flip affordance: a hint line on the current card names the gesture for
   both input modes; the card's own focus ring (keyboard stop is the
   current card alone, mirrored by tabindex in the component). */
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(sem-fact, .sem-fact).sem-current::after {
  grid-row: 2; align-self: end; justify-self: end; margin-top: .5rem;
  font-size: .72rem; color: var(--sem-muted);
  font-variant-caps: all-small-caps; letter-spacing: .05em;
  content: "click or press enter to reveal"; }
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(sem-fact, .sem-fact).sem-current.sem-flipped::after {
  content: "flip back"; }
/* verdict buttons share the hint's row: card front on row 2 start, the
   click-or-reveal hint on row 2 end. Visible only on the flipped current
   card (base rules keep .sem-facts-verdict display:none elsewhere). */
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(sem-fact, .sem-fact).sem-current.sem-flipped .sem-facts-verdict {
  display: flex; grid-row: 2; justify-self: start; align-self: end; }
:is(sem-facts, .sem-facts)[data-sem-upgraded][data-view-as="flashcards"] :is(sem-fact, .sem-fact):focus-visible {
  outline: 2px solid var(--sem-accent); outline-offset: 2px; }

/* quiz options — hover invites the pick; after the answer the correct
   option is marked even on a miss (schema: a miss teaches), the pick
   states carry a glyph as well as a border colour (never colour alone),
   and unmarked distractors recede. */
.sem-quiz-options button:hover { border-color: var(--sem-accent);
  background: color-mix(in srgb, var(--sem-accent) 8%, var(--sem-surface)); }
.sem-quiz-options button:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; }
.sem-quiz-options[data-answered] button { cursor: default; }
.sem-quiz-options[data-answered] button[data-correct="true"] {
  border-color: var(--sem-correct);
  background: color-mix(in srgb, var(--sem-correct) 10%, var(--sem-surface)); }
.sem-quiz-options button.sem-answered::before { content: "✓ "; color: var(--sem-correct); font-weight: 700; }
.sem-quiz-options button.sem-wrong-pick::before { content: "✗ "; color: var(--sem-wrong); font-weight: 700; }
.sem-quiz-options[data-answered] button:not(.sem-answered):not(.sem-wrong-pick):not([data-correct="true"]) {
  opacity: .55; }
@media (prefers-reduced-motion: no-preference) {
  .sem-facts-chrome button, .sem-quiz-options button {
    transition: border-color .15s ease, background-color .15s ease; }
}
/* ── end sem-facts ── */

/* ── sem-question ──
   The quiz block (component: src/lit/sem-question.ts, shipped 0.9.1).
   JS-off / pre-upgrade the authored sem-option elements read as a plain
   list inside the question card; once the component drives it (marker
   claimed) the authored options hide and the generated button row takes
   over — same D12 gate as the deck distractors. */
:is(sem-question, .sem-question) { border: 1px solid var(--sem-border); border-radius: 12px;
  padding: 1rem; margin: 1rem 0; background: var(--sem-surface); }
:is(sem-question, .sem-question) > :is(sem-option, .sem-option) { margin: .25rem 0; color: var(--sem-muted); }
:is(sem-question, .sem-question)[data-sem-upgraded] > :is(sem-option, .sem-option) { display: none; }
.sem-question-options { display: grid; gap: .5rem; margin-top: .75rem; }
.sem-question-options button { font: inherit; text-align: left; border: 1px solid var(--sem-border);
  background: var(--sem-surface); color: var(--sem-fg); border-radius: 8px;
  padding: .5rem .75rem; cursor: pointer; }
.sem-question-options button:hover:not(:disabled) { border-color: var(--sem-accent);
  background: color-mix(in srgb, var(--sem-accent) 8%, var(--sem-surface)); }
.sem-question-options button:focus-visible { outline: 2px solid var(--sem-accent); outline-offset: 2px; }
.sem-question-options button.sem-answered { border-color: var(--sem-correct);
  background: color-mix(in srgb, var(--sem-correct) 10%, var(--sem-surface)); }
.sem-question-options button.sem-answered::before { content: "✓ "; color: var(--sem-correct); font-weight: 700; }
.sem-question-options button.sem-wrong-pick { border-color: var(--sem-wrong); cursor: default; opacity: .7; }
.sem-question-options button.sem-wrong-pick::before { content: "✗ "; color: var(--sem-wrong); font-weight: 700; }
.sem-question-options button:disabled { cursor: default; }
.sem-question-options button:not(.sem-answered):not(.sem-wrong-pick):disabled { opacity: .55; }
.sem-question-retry { justify-self: start; }

/* ── sem-note ──
   Additive chrome only. The base accents, the collapsed hide rule (gated on
   [data-sem-upgraded]), the margin float and the print/focus overrides live
   in the shared vocabulary sections above. This block dresses the teaser:
   the Lit tier renders it as a real button (keyboard activation), so the UA
   control chrome is stripped and a visible focus ring restored. JS-off no
   teaser exists at all. */
:is(sem-note, .sem-note) .sem-note-summary {
  display: block;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; line-height: inherit; text-align: start;
  cursor: pointer; color: var(--sem-accent); }
:is(sem-note, .sem-note) .sem-note-summary:hover {
  text-decoration: underline; text-underline-offset: 3px; }
:is(sem-note, .sem-note) .sem-note-summary:focus-visible {
  outline: 2px solid var(--sem-accent); outline-offset: 2px; }
/* the expanded body keeps its focus ring: programmatic focus after the
   teaser click is the keyboard user's position marker — do not suppress */
/* ── end sem-note ── */

/* ── sem-tldr ──
   Walking-skeleton element (spec/schema/sem-tldr.md): the component is a
   no-logic display stub — authored children render as-is — and the
   "TL;DR" label is pure CSS chrome. ::before content sits outside
   textContent, so extraction (conventions §8 invariant) is byte-identical
   with the script on or off, and the same label draws in the .nojs
   artifact. Box comes from the block-level enumeration above. */
:is(sem-tldr, .sem-tldr) {
  border-left: 3px solid var(--sem-accent);
  background: color-mix(in srgb, var(--sem-accent) 8%, transparent);
  border-radius: 0 8px 8px 0;
  padding: 0.5rem 0.9rem 0.6rem;
  margin: 0.6rem 0;
}
:is(sem-tldr, .sem-tldr)::before {
  content: "TL;DR";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--sem-accent);
  margin-bottom: 0.15rem;
}
/* ── end sem-tldr ── */

/* ── sem-reader ── */
/* Keyboard focus (house standard). The chrome buttons/selects and the
   outline links are the only focus stops the reader owns; their UA
   default ring is unreliable over the theme's --sem-bg in both colour
   modes, and every other interactive vocabulary control spells this
   rule out. Outline links are the panel's keyboard exit route. */
.sem-reader-chrome :is(button, select):focus-visible,
:is(sem-reader, .sem-reader) > nav a:focus-visible {
  outline: 2px solid var(--sem-accent); outline-offset: 2px;
  border-radius: 6px; }
/* ── end sem-reader ── */

/* ── sem-browser ── */
/* The chrome-like document window (src/browser/sem-browser.ts). The
   .sem-window* classes are the shared window standard; every rule here
   is scoped to sem-browser so it never restyles sem-shell or sem-code
   windows.

   Zero-JS: the authored children ARE the document. The host draws a
   plain frame so the landing fallback (inert glyphs, address pill,
   framed deck) reads as a window with no script at all. No hide rule
   gates on anything the script did not stamp (D12): the element hides
   its own fallback children with [hidden] once wired. */
sem-browser:not([data-sem-upgraded]) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 10px;
  background: var(--sem-surface);
  overflow: hidden;
}
sem-browser:not([data-sem-upgraded]) > figure { margin: 0; }

/* Enhanced. Height is a token so embedders size the window; the size
   presets are spelled both ways (size="sm" and data-size="sm"). */
sem-browser[data-sem-upgraded] { display: block; }
sem-browser .sem-window { --sem-window-height: 26rem; }
sem-browser[size="sm"] .sem-window,
sem-browser[data-size="sm"] .sem-window { --sem-window-height: 16rem; }
sem-browser[size="lg"] .sem-window,
sem-browser[data-size="lg"] .sem-window { --sem-window-height: 38rem; }
sem-browser .sem-window-viewport {
  height: var(--sem-window-height);
  overflow: auto;
  padding: 1rem 1.25rem;
  background: var(--sem-bg);
  color: var(--sem-fg);
}
sem-browser .sem-browser-address {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.375rem 1rem;
  border-bottom: 1px solid var(--sem-border);
  font-family: ui-monospace, monospace;
  font-size: 0.8125rem;
  color: var(--sem-muted);
}
sem-browser .sem-browser-nav { display: inline-flex; gap: 0.625rem; }
sem-browser .sem-browser-nav span { opacity: 0.6; }
sem-browser .sem-browser-url {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
sem-browser .sem-browser-loading { opacity: 0.7; }
sem-browser .sem-browser-error-line { color: var(--sem-wrong); }

/* Focus (house standard, spelled out like every other vocabulary
   control): the window takes a ring while anything inside holds focus;
   the scrollable viewport carries its own inset ring. */
sem-browser[data-sem-upgraded]:focus-within {
  outline: 2px solid var(--sem-accent);
  outline-offset: 2px;
}
sem-browser .sem-window-viewport:focus-visible {
  outline: 2px solid var(--sem-accent);
  outline-offset: -2px;
}

@media (prefers-reduced-motion: no-preference) {
  sem-browser .sem-window-viewport { scroll-behavior: smooth; }
}
@media print {
  sem-browser .sem-browser-address { display: none; }
  sem-browser .sem-window-viewport { height: auto; overflow: visible; }
}
/* ── end sem-browser ── */

/* ── sem-shell (ansi dom) ── mirror of src/terminal/ansi/dom.ts ANSI_DOM_CSS; keep in sync ── */
sem-terminal .sem-ansi-i, sem-shell .sem-ansi-i { font-style: italic; }
sem-terminal .sem-ansi-u, sem-shell .sem-ansi-u { text-decoration: underline; }
sem-terminal .sem-ansi-strike, sem-shell .sem-ansi-strike { text-decoration: line-through; }
sem-terminal .sem-ansi-rev, sem-shell .sem-ansi-rev { filter: invert(1); }
sem-terminal .sem-ansi-blink, sem-shell .sem-ansi-blink { animation: sem-ansi-blink 1.1s step-end infinite; }
@keyframes sem-ansi-blink { 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) {
  sem-terminal .sem-ansi-blink, sem-shell .sem-ansi-blink { animation: none; }
}
sem-terminal .sem-ansi-c90, sem-shell .sem-ansi-c90 { color: #9aa5b1; }
sem-terminal .sem-ansi-c91, sem-shell .sem-ansi-c91 { color: #ff8f7a; }
sem-terminal .sem-ansi-c92, sem-shell .sem-ansi-c92 { color: #8fd6a0; }
sem-terminal .sem-ansi-c93, sem-shell .sem-ansi-c93 { color: #e6c77a; }
sem-terminal .sem-ansi-c94, sem-shell .sem-ansi-c94 { color: #7ab8e6; }
sem-terminal .sem-ansi-c95, sem-shell .sem-ansi-c95 { color: #c79ae6; }
sem-terminal .sem-ansi-c96, sem-shell .sem-ansi-c96 { color: #6fd3d3; }
sem-terminal .sem-ansi-c97, sem-shell .sem-ansi-c97 { color: #f2f5f8; }
sem-terminal .sem-ansi-bg40, sem-shell .sem-ansi-bg40 { background: rgba(107,114,128,.35); }
sem-terminal .sem-ansi-bg41, sem-shell .sem-ansi-bg41 { background: rgba(255,143,122,.28); }
sem-terminal .sem-ansi-bg42, sem-shell .sem-ansi-bg42 { background: rgba(143,214,160,.28); }
sem-terminal .sem-ansi-bg43, sem-shell .sem-ansi-bg43 { background: rgba(230,199,122,.28); }
sem-terminal .sem-ansi-bg44, sem-shell .sem-ansi-bg44 { background: rgba(122,184,230,.28); }
sem-terminal .sem-ansi-bg45, sem-shell .sem-ansi-bg45 { background: rgba(199,154,230,.28); }
sem-terminal .sem-ansi-bg46, sem-shell .sem-ansi-bg46 { background: rgba(111,211,211,.28); }
sem-terminal .sem-ansi-bg47, sem-shell .sem-ansi-bg47 { background: rgba(214,221,230,.22); }
sem-terminal .sem-ansi-bg100, sem-shell .sem-ansi-bg100 { background: rgba(107,114,128,.35); }
sem-terminal .sem-ansi-bg101, sem-shell .sem-ansi-bg101 { background: rgba(255,143,122,.28); }
sem-terminal .sem-ansi-bg102, sem-shell .sem-ansi-bg102 { background: rgba(143,214,160,.28); }
sem-terminal .sem-ansi-bg103, sem-shell .sem-ansi-bg103 { background: rgba(230,199,122,.28); }
sem-terminal .sem-ansi-bg104, sem-shell .sem-ansi-bg104 { background: rgba(122,184,230,.28); }
sem-terminal .sem-ansi-bg105, sem-shell .sem-ansi-bg105 { background: rgba(199,154,230,.28); }
sem-terminal .sem-ansi-bg106, sem-shell .sem-ansi-bg106 { background: rgba(111,211,211,.28); }
sem-terminal .sem-ansi-bg107, sem-shell .sem-ansi-bg107 { background: rgba(214,221,230,.22); }

/* ── shell-v2-osc-tabs ── */
/* The tab strip + status-dot tones for the shared window chrome
   (src/shared/window-chrome.ts: renderTabStrip / createTabStrip, and the
   tone option on the title bar — CORE-V2 §11). Class-scoped so every
   adopting host renders the same strip; host blocks may override. The
   base .sem-window-dot rule is provisional — no dot styling exists in the
   vocabulary yet; drop it if/when the chrome block grows one. Lane rule:
   NOT committed — the lead folds this into the vocabulary proper. */
.sem-window-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 999px;
  background: var(--sem-muted, #98a2b3);
  flex: none;
}
.sem-window-dot-busy { background: var(--sem-warning, #b45309); }
.sem-window-dot-alert { background: var(--sem-wrong, #b42318); }
.sem-window-tabs {
  display: flex;
  align-items: stretch;
  gap: 0.125rem;
  min-width: 0;
  overflow: hidden;
}
.sem-window-tabs .sem-window-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.75rem;
  border-radius: 6px;
  min-width: 0;
  cursor: pointer;
  color: var(--sem-muted, #667085);
}
.sem-window-tabs .sem-window-tab:focus-visible {
  outline: 2px solid var(--sem-accent, #4f46e5);
  outline-offset: -2px;
}
.sem-window-tabs .sem-window-tab-active {
  color: var(--sem-fg, #101828);
  background: var(--sem-surface, #ffffff);
}
.sem-window-tabs .sem-window-tab-title {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.sem-window-tab-close {
  appearance: none;
  border: 0;
  background: none;
  padding: 0 0.125rem;
  border-radius: 4px;
  font: inherit;
  line-height: 1;
  color: inherit;
  cursor: pointer;
}
.sem-window-tab-close:hover { background: rgba(127, 127, 127, 0.18); }
/* ── end shell-v2-osc-tabs ── */
/* ── shell-v2-canvas ── */
sem-terminal .sem-term-canvas, sem-shell .sem-term-canvas {
  display: block;
  width: 100%;
  height: 100%;
}
sem-terminal .sem-term-canvas-hidden, sem-shell .sem-term-canvas-hidden {
  display: none; /* the DOM view is promoted — canvas stands down (§8.5) */
}
sem-terminal .sem-term-mirror, sem-shell .sem-term-mirror {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  white-space: pre;
}
/* Hidden mode: the classic visually-hidden pattern — zero size, still in
   the a11y tree, still findable/selectable by platform services (§8.1). */
sem-terminal .sem-term-mirror[data-visible="false"], sem-shell .sem-term-mirror[data-visible="false"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  border: 0;
}
/* Promoted mode (§8.5b/c): the same paint as the visible text view. */
sem-terminal .sem-term-mirror[data-visible="true"], sem-shell .sem-term-mirror[data-visible="true"] {
  position: absolute;
  inset: 0;
  overflow: auto;
  cursor: text;
}
sem-terminal .sem-term-mirror-line, sem-shell .sem-term-mirror-line {
  white-space: pre;
  min-height: 1em;
}
sem-terminal .sem-term-mirror-live, sem-shell .sem-term-mirror-live {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
}
@media (prefers-reduced-motion: reduce) {
  sem-terminal .sem-term-mirror, sem-shell .sem-term-mirror { scroll-behavior: auto; }
}

/* ── shell-v2-integrate ── */
/* The paint surface: canvas + mirror live inside it (attach target). */
sem-terminal .sem-term-surface, sem-shell .sem-term-surface {
  position: relative; /* the promoted mirror's inset:0 anchor */
  overflow: hidden;   /* the scrollbar carries the scroll — the surface clips */
}
/* Scrollbar (sem-scroll) rides the transcript in the DOM view and the
   full line history while an app holds the alt screen. */
sem-terminal .sem-term-scrollbar, sem-shell .sem-term-scrollbar {
  display: block;
}
/* DOM view (dataset.paint="dom" or unpainted): transcript is the paint.
   (r2.1 fix: the element's transcript class is .sem-shell-transcript —
   the r2 sheet hid a .sem-term-transcript class nothing renders, so the
   canvas-mode DOM transcript stayed in flow: a thousands-of-pixels block
   inside the frame that scrolled the painted surface under the titlebar
   and, with the r2.1 flex frame, squeezed the surface to zero.) */
sem-terminal .sem-term-transcript,
sem-terminal .sem-shell-transcript,
sem-shell .sem-shell-transcript {
  display: block;
}
/* Canvas paint stands the round-1 transcript down — visually hidden but
   still in the log/a11y tree (§9); the promoted mirror is the text view.
   The attribute is set only on a successful canvas attach, so the DOM
   fallback (no JS paint, forced-colors, failed 2d) keeps the transcript. */
sem-terminal[data-paint="canvas"] .sem-term-transcript,
sem-terminal[data-paint="canvas"] .sem-shell-transcript,
sem-shell[data-paint="canvas"] .sem-shell-transcript {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  border: 0;
}

/* ── shell-v2-canvas-frame (r2.1) ──
   In canvas paint the terminal surface owns scrolling (sem-scroll); the
   frame must not. As a plain block the frame scrolled its taller-than-
   frame surface, sliding painted rows under the window titlebar — the
   r2 "row-0 overprint" — and the first metrics measure read the canvas's
   intrinsic bitmap height instead of a layout height, pinning the wrong
   rows. So canvas mode lays out top-down: the element takes a definite
   height (24rem — the frame's own cap; an author height overrides), the
   frame fills it as a flex column, and the surface takes the space left
   over from the titlebar/prompt. The first measure is then the real box,
   the metrics loop is stable, and the paint never leaves the frame.
   DOM mode keeps the round-1 auto-height, scrolling frame. */
sem-terminal[data-paint="canvas"],
sem-shell[data-paint="canvas"] {
  height: 24rem;
}
sem-terminal[data-paint="canvas"] .sem-shell-frame,
sem-shell[data-paint="canvas"] .sem-shell-frame {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  height: 100%;
  max-height: none;
  box-sizing: border-box; /* padding + border live inside the 100% */
}
sem-terminal[data-paint="canvas"] .sem-term-surface,
sem-shell[data-paint="canvas"] .sem-term-surface {
  flex: 1 1 auto;
  min-height: 0;
}

/* ── sem-tag-def / sem-tag-attr — markup-tag definition cards
   (spec/schema/sem-tag-def.md). The Lit component renders the card
   (header row, description, native table, children chips); class-form
   documents and JS-off pages keep the authored definition look. ── */
:is(sem-tag-def, .sem-tag-def) { display: block; margin: 1rem 0; }
:is(sem-tag-def, .sem-tag-def):not([data-sem-upgraded]) {
  padding-left: .9rem; border-left: 3px solid
  color-mix(in srgb, var(--sem-accent) 35%, transparent); }
:is(sem-tag-def, .sem-tag-def):not([data-sem-upgraded])::before {
  content: attr(data-tag); display: block; font-weight: 600;
  font-family: var(--sem-mono, ui-monospace, monospace); }
:is(sem-tag-def, .sem-tag-def):not([data-sem-upgraded])[tag]:not([data-tag])::before {
  content: attr(tag); }
:is(sem-tag-def, .sem-tag-def):not([data-sem-upgraded])[data-name]::after {
  content: " — " attr(data-name); font-variant-caps: all-small-caps; color: var(--sem-muted); }
:is(sem-tag-def, .sem-tag-def):not([data-sem-upgraded])[name]:not([data-name])::after {
  content: " — " attr(name); font-variant-caps: all-small-caps; color: var(--sem-muted); }
/* JS-off rows: `name :: description` with type + requiredness from attr() */
:is(sem-tag-attr, .sem-tag-attr):not([data-sem-upgraded]) { display: block; margin: .35rem 0; }
:is(sem-tag-attr, .sem-tag-attr):not([data-sem-upgraded])::before {
  content: attr(data-name) " :: "; font-weight: 600; }
:is(sem-tag-attr, .sem-tag-attr):not([data-sem-upgraded])[name]:not([data-name])::before {
  content: attr(name) " :: "; font-weight: 600; }
:is(sem-tag-attr, .sem-tag-attr):not([data-sem-upgraded])[data-type]::after {
  content: " (" attr(data-type) ")"; color: var(--sem-muted); }
:is(sem-tag-attr, .sem-tag-attr):not([data-sem-upgraded])[type]:not([data-type])::after {
  content: " (" attr(type) ")"; color: var(--sem-muted); }
:is(sem-tag-attr, .sem-tag-attr):not([data-sem-upgraded])[data-required][data-type]::after {
  content: " (" attr(data-type) ", required)"; color: var(--sem-muted); }
:is(sem-tag-attr, .sem-tag-attr):not([data-sem-upgraded])[data-required][type]:not([data-type])::after {
  content: " (" attr(type) ", required)"; color: var(--sem-muted); }
:is(sem-tag-attr, .sem-tag-attr):not([data-sem-upgraded])[data-required]:not([data-type]):not([type])::after {
  content: " (required)"; color: var(--sem-muted); }
/* component card */
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; margin: 0 0 .35rem; }
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-tag {
  font-weight: 600; font-family: var(--sem-mono, ui-monospace, monospace); }
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-name { font-weight: 600; }
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-group {
  font-variant-caps: all-small-caps; color: var(--sem-accent);
  border: 1px solid color-mix(in srgb, var(--sem-accent) 45%, transparent);
  border-radius: 999px; padding: .05rem .55rem; }
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-desc { margin: 0 0 .5rem; }
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-table,
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-table {
  border-collapse: collapse; width: 100%; font-size: .875rem; margin: .5rem 0; }
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-table th,
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-table td,
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-table th,
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-table td {
  border: 1px solid color-mix(in srgb, var(--sem-border) 70%, transparent);
  padding: .3rem .55rem; text-align: left; vertical-align: top; }
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-table th,
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-table th {
  font-variant-caps: all-small-caps; font-weight: 600; color: var(--sem-muted); }
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-cell-required,
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-cell-required {
  font-variant-caps: all-small-caps; color: var(--sem-muted); }
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-children {
  display: flex; flex-wrap: wrap; gap: .4rem; align-items: baseline; margin: .35rem 0 0; }
:is(sem-tag-def, .sem-tag-def)[data-sem-upgraded] .sem-tagdef-child {
  border: 1px solid color-mix(in srgb, var(--sem-border) 80%, transparent);
  border-radius: 999px; padding: .05rem .5rem; font-size: .8125rem; }
/* ── end sem-tag-def ── */

/* ── sem-api-call / sem-api-param — API-call definition cards
   (spec/schema/sem-api-call.md). Same card pattern as sem-tag-def with
   `METHOD endpoint` header chips and per-`in` group tables. ── */
:is(sem-api-call, .sem-api-call) { display: block; margin: 1rem 0; }
:is(sem-api-call, .sem-api-call):not([data-sem-upgraded]) {
  padding-left: .9rem; border-left: 3px solid
  color-mix(in srgb, var(--sem-accent) 35%, transparent); }
:is(sem-api-call, .sem-api-call):not([data-sem-upgraded])::before {
  content: attr(data-method) " " attr(data-endpoint); display: block; font-weight: 600;
  font-family: var(--sem-mono, ui-monospace, monospace); }
:is(sem-api-call, .sem-api-call):not([data-sem-upgraded])[method]:not([data-method])::before {
  content: attr(method) " " attr(endpoint); }
/* JS-off rows: `name :: description` with the `in` group from attr();
   type/requiredness stay table-tier (the component's full render). */
:is(sem-api-param, .sem-api-param):not([data-sem-upgraded]) { display: block; margin: .35rem 0; }
:is(sem-api-param, .sem-api-param):not([data-sem-upgraded])::before {
  content: attr(data-name) " :: "; font-weight: 600; }
:is(sem-api-param, .sem-api-param):not([data-sem-upgraded])[name]:not([data-name])::before {
  content: attr(name) " :: "; font-weight: 600; }
:is(sem-api-param, .sem-api-param):not([data-sem-upgraded])[data-in]::after {
  content: " [" attr(data-in) "]"; color: var(--sem-muted); }
:is(sem-api-param, .sem-api-param):not([data-sem-upgraded])[in]:not([data-in])::after {
  content: " [" attr(in) "]"; color: var(--sem-muted); }
/* component card */
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; margin: 0 0 .35rem; }
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-method {
  font-variant-caps: all-small-caps; font-weight: 700; color: var(--sem-accent);
  border: 1px solid color-mix(in srgb, var(--sem-accent) 45%, transparent);
  border-radius: 999px; padding: .05rem .55rem; }
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-endpoint {
  font-family: var(--sem-mono, ui-monospace, monospace); font-weight: 600; }
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-status {
  font-variant-caps: all-small-caps; color: var(--sem-muted);
  border: 1px solid color-mix(in srgb, var(--sem-border) 80%, transparent);
  border-radius: 999px; padding: .05rem .55rem; }
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-desc { margin: 0 0 .5rem; }
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-group { margin: .35rem 0 0; }
:is(sem-api-call, .sem-api-call)[data-sem-upgraded] .sem-apicall-group-label {
  font-variant-caps: all-small-caps; font-weight: 600; color: var(--sem-muted); }
/* ── end sem-api-call ── */
/* ── shell-v3-tabs-ui ──
   Tab strip container + the new-tab (+) button (CORE-V2 §11.2/§11.3).
   The tabs themselves reuse the shell-v2-osc-tabs .sem-window-tab styles. */
sem-terminal .sem-term-tabs, sem-shell .sem-term-tabs {
  display: flex;
  align-items: stretch;
  gap: 0.125rem;
  min-width: 0;
  padding: 0 0.5rem;
  border-bottom: 1px solid var(--sem-border, #e4e7ec);
}
sem-terminal .sem-window-tab-new, sem-shell .sem-window-tab-new {
  appearance: none;
  border: 0;
  background: none;
  align-self: center;
  margin-left: 0.25rem;
  padding: 0 0.5rem;
  border-radius: 6px;
  font: inherit;
  font-size: 1.05em;
  line-height: 1.4;
  color: var(--sem-muted, #667085);
  cursor: pointer;
}
sem-terminal .sem-window-tab-new:hover, sem-shell .sem-window-tab-new:hover {
  color: var(--sem-fg, #101828);
  background: rgba(127, 127, 127, 0.14);
}
sem-terminal .sem-window-tab-new:focus-visible, sem-shell .sem-window-tab-new:focus-visible {
  outline: 2px solid var(--sem-accent, #4f46e5);
  outline-offset: -2px;
}
@media (prefers-reduced-motion: reduce) {
  sem-terminal .sem-window-tab-new, sem-shell .sem-window-tab-new { transition: none; }
}
/* ── end shell-v3-tabs-ui ── */

/* ── sem-containers family A ──
   Static knowledge/doc containers (spec/schema/sem-{kb,runbook,howto,
   requirement,threat-model,guard-rails,mockup,rubric,eval,philosophy,
   summary,plan,tsgs,faqs,changelogs}.md). Every element registers a Lit
   display stub (no CSS-only elements) that claims `data-sem-upgraded`;
   ALL visible chrome here is pseudo-element CSS whose ::before/::after
   content sits outside textContent, so the conventions §8 extraction
   invariant holds: byte-identical with the script on or off, and the
   same boxes draw in the .nojs artifacts. Each rule carries its own
   display:block (the shared enumeration above is append-only for other
   lanes). Dual-form: custom element + .sem-<name> class alias. */

/* knowledge-base article */
:is(sem-kb, .sem-kb) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-kb, .sem-kb)::before {
  content: "knowledge base";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-kb, .sem-kb)[kind]::before {
  content: "knowledge base · " attr(kind);
}

/* runbook */
:is(sem-runbook, .sem-runbook) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-runbook, .sem-runbook)::before {
  content: "runbook";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-runbook, .sem-runbook)[kind]::before {
  content: "runbook · " attr(kind);
}
:is(sem-runbook, .sem-runbook)[audience]::after {
  content: "for " attr(audience);
  display: block;
  width: fit-content;
  margin-top: 0.45rem;
  padding: 0.05rem 0.5rem;
  border: 1px solid var(--sem-border);
  border-radius: 999px;
  font-size: 0.68rem;
  color: var(--sem-muted);
}

/* how-to guide */
:is(sem-howto, .sem-howto) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-howto, .sem-howto)::before {
  content: "how-to";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-howto, .sem-howto) > :is(name, .sem-name) {
  display: block;
  font-size: 1.05em;
  font-weight: 650;
  margin: 0 0 0.3rem;
}
:is(sem-howto, .sem-howto) > :is(tags, .sem-tags) {
  display: block;
  color: var(--sem-muted);
  font-size: 0.85em;
  margin-top: 0.4rem;
}

/* requirement statement */
:is(sem-requirement, .sem-requirement) {
  display: block;
  border: 1px solid var(--sem-border);
  border-left: 3px solid var(--sem-accent);
  border-radius: 0 8px 8px 0;
  background: var(--sem-surface);
  padding: 0.6rem 0.9rem 0.7rem;
  margin: 0.7rem 0;
}
:is(sem-requirement, .sem-requirement)::before {
  content: "requirement";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-accent);
  margin-bottom: 0.25rem;
}
:is(sem-requirement, .sem-requirement)[kind]::before {
  content: "requirement · " attr(kind);
}
:is(sem-requirement, .sem-requirement)[status]::after {
  content: attr(status);
  display: block;
  width: fit-content;
  margin-top: 0.45rem;
  padding: 0.05rem 0.55rem;
  border: 1px solid var(--sem-border);
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--sem-muted);
}

/* threat model */
:is(sem-threat-model, .sem-threat-model) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-threat-model, .sem-threat-model)::before {
  content: "threat model";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-threat-model, .sem-threat-model)[kind]::before {
  content: "threat model · " attr(kind);
}
:is(sem-threat-model, .sem-threat-model)[scope]::after {
  content: "scope: " attr(scope);
  display: block;
  width: fit-content;
  margin-top: 0.45rem;
  padding: 0.05rem 0.5rem;
  border: 1px solid var(--sem-border);
  border-radius: 999px;
  font-size: 0.68rem;
  color: var(--sem-muted);
}

/* guard rails: collection + entries */
:is(sem-guard-rails, .sem-guard-rails) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-guard-rails, .sem-guard-rails)::before {
  content: "guard rails";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-guard-rails, .sem-guard-rails)[kind]::before {
  content: "guard rails · " attr(kind);
}
:is(sem-guard-rail, .sem-guard-rail) {
  display: block;
  border-left: 3px solid var(--sem-note-info);
  background: color-mix(in srgb, var(--sem-note-info) 6%, transparent);
  border-radius: 0 6px 6px 0;
  padding: 0.45rem 0.8rem 0.55rem;
  margin: 0.5rem 0;
}
:is(sem-guard-rail, .sem-guard-rail)[severity="warn"] {
  border-left-color: var(--sem-note-warning);
  background: color-mix(in srgb, var(--sem-note-warning) 8%, transparent);
}
:is(sem-guard-rail, .sem-guard-rail)[severity="block"] {
  border-left-color: var(--sem-note-danger);
  background: color-mix(in srgb, var(--sem-note-danger) 8%, transparent);
}
:is(sem-guard-rail, .sem-guard-rail)[severity]::before {
  content: attr(severity);
  display: block;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.15rem;
}
:is(sem-guard-rail, .sem-guard-rail)[scope]::after {
  content: "scope: " attr(scope);
  display: block;
  font-size: 0.72rem;
  color: var(--sem-muted);
  margin-top: 0.25rem;
}

/* mockup (mode text = preformatted mono; mode html = normal flow) */
:is(sem-mockup, .sem-mockup) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-mockup, .sem-mockup)::before {
  content: "mockup";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-mockup, .sem-mockup)[kind]::before {
  content: "mockup · " attr(kind);
}
:is(sem-mockup, .sem-mockup):not([mode]),
:is(sem-mockup, .sem-mockup)[mode="text"] {
  font-family: var(--sem-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.85em;
  white-space: pre-wrap;
  overflow-x: auto;
}

/* rubric */
:is(sem-rubric, .sem-rubric) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-rubric, .sem-rubric)::before {
  content: "rubric";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-rubric, .sem-rubric)[kind]::before {
  content: "rubric · " attr(kind);
}
:is(sem-rubric, .sem-rubric)[max-score]::after {
  content: "max " attr(max-score);
  display: block;
  width: fit-content;
  margin-top: 0.45rem;
  padding: 0.05rem 0.55rem;
  border: 1px solid var(--sem-border);
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--sem-muted);
}

/* evaluation spec */
:is(sem-eval, .sem-eval) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-eval, .sem-eval)::before {
  content: "evaluation";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-eval, .sem-eval)[kind]::before {
  content: "evaluation · " attr(kind);
}
:is(sem-eval, .sem-eval)[status]::after {
  content: attr(status);
  display: block;
  width: fit-content;
  margin-top: 0.45rem;
  padding: 0.05rem 0.55rem;
  border: 1px solid var(--sem-border);
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--sem-muted);
}

/* philosophy (spelled with the h) */
:is(sem-philosophy, .sem-philosophy) {
  display: block;
  border: 1px solid var(--sem-border);
  border-left: 3px solid var(--sem-accent);
  border-radius: 0 8px 8px 0;
  background: var(--sem-surface);
  padding: 0.6rem 0.9rem 0.7rem;
  margin: 0.7rem 0;
}
:is(sem-philosophy, .sem-philosophy)::before {
  content: "philosophy";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-accent);
  margin-bottom: 0.25rem;
}
:is(sem-philosophy, .sem-philosophy)[kind]::before {
  content: "philosophy · " attr(kind);
}

/* summary (heavier document-level wrap; sem-tldr is the light skim) */
:is(sem-summary, .sem-summary) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-summary, .sem-summary)::before {
  content: "summary";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-summary, .sem-summary)[kind]::before {
  content: "summary · " attr(kind);
}

/* plan (record, not workflow — no transitions, no engine) */
:is(sem-plan, .sem-plan) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-plan, .sem-plan)::before {
  content: "plan";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-plan, .sem-plan)[kind]::before {
  content: "plan · " attr(kind);
}
:is(sem-plan, .sem-plan)[status]::after {
  content: attr(status);
  display: block;
  width: fit-content;
  margin-top: 0.45rem;
  padding: 0.05rem 0.55rem;
  border: 1px solid var(--sem-border);
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--sem-muted);
}

/* troubleshooting guides: collection + entries */
:is(sem-tsgs, .sem-tsgs) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-tsgs, .sem-tsgs)::before {
  content: "troubleshooting";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-tsgs, .sem-tsgs)[kind]::before {
  content: "troubleshooting · " attr(kind);
}
:is(sem-tsg, .sem-tsg) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 6px;
  padding: 0.5rem 0.8rem 0.6rem;
  margin: 0.5rem 0;
}
:is(sem-tsg, .sem-tsg) > :is(name, .sem-name) {
  display: block;
  font-weight: 650;
}
:is(sem-tsg, .sem-tsg) > :is(title, .sem-title) {
  display: block;
  font-weight: 600;
  margin: 0.1rem 0 0.2rem;
}
:is(sem-tsg, .sem-tsg) > :is(description, .sem-description) {
  display: block;
  color: var(--sem-muted);
}
:is(sem-tsg, .sem-tsg) > :is(when, .sem-when) {
  display: block;
  margin-top: 0.25rem;
}
:is(sem-tsg, .sem-tsg) > :is(when, .sem-when)::before {
  content: "when · ";
  color: var(--sem-muted);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.05em;
}
:is(sem-tsg, .sem-tsg) > :is(tags, .sem-tags) {
  display: block;
  color: var(--sem-muted);
  font-size: 0.85em;
  margin-top: 0.3rem;
}

/* FAQs: collection + entries (never a disclosure — Q and A both visible) */
:is(sem-faqs, .sem-faqs) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-faqs, .sem-faqs)::before {
  content: "FAQ";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-faqs, .sem-faqs)[kind]::before {
  content: "FAQ · " attr(kind);
}
:is(sem-faq, .sem-faq) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 6px;
  padding: 0.5rem 0.8rem 0.6rem;
  margin: 0.5rem 0;
}
:is(sem-faq, .sem-faq) > :is(question, .sem-question) {
  display: block;
  font-weight: 650;
  margin-bottom: 0.2rem;
}
:is(sem-faq, .sem-faq) > :is(question, .sem-question)::before {
  content: "Q · ";
  color: var(--sem-accent);
  font-weight: 700;
}
:is(sem-faq, .sem-faq) > :is(answer, .sem-answer) {
  display: block;
}
:is(sem-faq, .sem-faq) > :is(answer, .sem-answer)::before {
  content: "A · ";
  color: var(--sem-muted);
  font-weight: 700;
}

/* changelogs: collection + entries */
:is(sem-changelogs, .sem-changelogs) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 8px;
  background: var(--sem-surface);
  padding: 0.7rem 0.95rem 0.8rem;
  margin: 0.8rem 0;
}
:is(sem-changelogs, .sem-changelogs)::before {
  content: "changelog";
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sem-muted);
  margin-bottom: 0.3rem;
}
:is(sem-changelogs, .sem-changelogs)[kind]::before {
  content: "changelog · " attr(kind);
}
:is(sem-changelog, .sem-changelog) {
  display: block;
  border: 1px solid var(--sem-border);
  border-radius: 6px;
  padding: 0.5rem 0.8rem 0.6rem;
  margin: 0.5rem 0;
}
:is(sem-changelog, .sem-changelog)::before {
  content: attr(date);
  display: block;
  font-family: var(--sem-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--sem-muted);
  margin-bottom: 0.2rem;
}
:is(sem-changelog, .sem-changelog)[name]::before {
  content: attr(date) " · " attr(name);
}
:is(sem-changelog, .sem-changelog)[title]::before {
  content: attr(date) " · " attr(title);
}
:is(sem-changelog, .sem-changelog)[title][name]::before {
  content: attr(date) " · " attr(title);
}
:is(sem-changelog, .sem-changelog) > :is(tags, .sem-tags) {
  display: block;
  color: var(--sem-muted);
  font-size: 0.85em;
  margin-top: 0.3rem;
}
:is(sem-changelog, .sem-changelog):not([date])::before {
  content: attr(name);
}
:is(sem-changelog, .sem-changelog):not([date])[title]::before {
  content: attr(title);
}
/* ── end sem-containers family A ── */
/* ── sem-workflow / sem-site-tree / sem-file-tree ──
   Interactive containers (spec/schema/sem-workflow.md, sem-site-tree.md,
   sem-file-tree.md). Family A part 2: the authored DOM is the record —
   every label/badge here is ::before/::after attr() chrome or gated
   generated-class styling; nothing JS-on hides or rewrites authored
   content without the container's [data-sem-upgraded] marker (D12). */

/* container blocks */
:is(sem-workflow, .sem-workflow),
:is(sem-site-tree, .sem-site-tree),
:is(sem-file-tree, .sem-file-tree) { display: block; margin: 1rem 0; }
:is(node, .sem-node) { display: block; }

/* -- workflow: JS-off ordered list (own counter scope, so procedure and
      workflow sequences never share a number) -------------------------- */
:is(sem-workflow, .sem-workflow) { counter-reset: sem-wf-step; }
:is(sem-workflow, .sem-workflow) :is(sem-step, .sem-step)::before {
  counter-increment: sem-wf-step;
  content: counter(sem-wf-step);
}
/* check badge rides the ordinal pseudo (the ordinal pseudo is otherwise
   unused for steps that carry no check) */
:is(sem-workflow, .sem-workflow) :is(sem-step, .sem-step):is([check], [data-check])::before {
  content: counter(sem-wf-step) " ▸ " attr(check);
}
:is(sem-workflow, .sem-workflow) :is(sem-step, .sem-step)[data-check]:not([check])::before {
  content: counter(sem-wf-step) " ▸ " attr(data-check);
}
/* gate badge takes the status glyph's slot (::after) — a gated step
   shows the gate, the status stays on the attribute (machine-readable) */
:is(sem-workflow, .sem-workflow) :is(sem-step, .sem-step):is([gate], [data-gate])::after {
  content: " ⛨ " attr(gate);
  color: var(--sem-muted);
  font-size: .8rem;
}
:is(sem-workflow, .sem-workflow) :is(sem-step, .sem-step)[data-gate]:not([gate])::after {
  content: " ⛨ " attr(data-gate);
  color: var(--sem-muted);
  font-size: .8rem;
}

/* -- workflow: JS-on if-no branch (generated chrome; gated) ------------- */
:is(sem-workflow, .sem-workflow)[data-sem-upgraded] .sem-step-branch-toggle {
  display: inline-block;
  margin-left: .4rem;
  padding: 0 .3rem;
  font: inherit;
  font-size: .75rem;
  color: var(--sem-muted);
  background: none;
  border: 1px solid var(--sem-border);
  border-radius: 6px;
  cursor: pointer;
}
:is(sem-workflow, .sem-workflow)[data-sem-upgraded] .sem-step-branch-toggle::before {
  content: "if-no ";
  font-style: italic;
}
:is(sem-workflow, .sem-workflow)[data-sem-upgraded] .sem-step-branch-toggle[aria-expanded="true"] {
  color: var(--sem-fg);
  border-color: var(--sem-accent);
}
:is(sem-workflow, .sem-workflow)[data-sem-upgraded] .sem-step-branch {
  display: block;
  margin: .35rem 0 0;
  padding: .35rem .6rem;
  border-left: 2px dashed var(--sem-accent);
  color: var(--sem-muted);
  font-size: .85rem;
}
:is(sem-workflow, .sem-workflow)[data-sem-upgraded] .sem-step-branch-label {
  display: block;
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .06em;
}

/* -- trees: JS-off static structure (guides + counters + attr labels) --- */
:is(sem-site-tree, .sem-site-tree),
:is(sem-file-tree, .sem-file-tree) { counter-reset: sem-tree-node; }
:is(sem-site-tree, .sem-site-tree) :is(node, .sem-node),
:is(sem-file-tree, .sem-file-tree) :is(node, .sem-node) {
  counter-increment: sem-tree-node;
  margin: .15rem 0 .15rem .35rem;
  padding: .1rem 0 .1rem .9rem;
  border-left: 1px solid var(--sem-border);
}
/* the label is ::before chrome (counter + label/path); shown JS-off only —
   JS-on the engine renders label buttons/spans instead */
:is(sem-site-tree, .sem-site-tree):not([data-sem-upgraded]) :is(node, .sem-node)::before,
:is(sem-file-tree, .sem-file-tree):not([data-sem-upgraded]) :is(node, .sem-node)::before {
  content: counter(sem-tree-node) ". " attr(label);
  color: var(--sem-fg);
}
:is(sem-site-tree, .sem-site-tree):not([data-sem-upgraded]) :is(node, .sem-node)[data-label]:not([label])::before,
:is(sem-file-tree, .sem-file-tree):not([data-sem-upgraded]) :is(node, .sem-node)[data-label]:not([label])::before {
  content: counter(sem-tree-node) ". " attr(data-label);
}
:is(sem-site-tree, .sem-site-tree):not([data-sem-upgraded]) :is(node, .sem-node):not([label]):not([data-label])[path]::before,
:is(sem-file-tree, .sem-file-tree):not([data-sem-upgraded]) :is(node, .sem-node):not([label]):not([data-label])[path]::before {
  content: counter(sem-tree-node) ". " attr(path);
}
:is(sem-site-tree, .sem-site-tree):not([data-sem-upgraded]) :is(node, .sem-node):not([label]):not([data-label])[data-path]:not([path])::before,
:is(sem-file-tree, .sem-file-tree):not([data-sem-upgraded]) :is(node, .sem-node):not([label]):not([data-label])[data-path]:not([path])::before {
  content: counter(sem-tree-node) ". " attr(data-path);
}
/* text form: the authored pre IS the record; verbatim, nothing fabricated */
:is(sem-file-tree, .sem-file-tree) > pre { margin: .25rem 0; }

/* -- trees: JS-on chrome (collapse / filter / find; all gated) ---------- */
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] :is(node, .sem-node)[collapsed] > :is(node, .sem-node),
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] :is(node, .sem-node)[collapsed] > :is(node, .sem-node) { display: none; }
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-file-tree-view .sem-tree-view-row[data-branch-hidden],
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-file-tree-view .sem-tree-view-row[data-branch-hidden] { display: none; }
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] > pre,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] > pre { display: none; }
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] [data-filter-hidden],
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] [data-filter-hidden] { display: none; }

:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-tree-chrome,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-chrome {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  align-items: center;
  margin: 0 0 .4rem;
}
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-tree-filter,
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-tree-find,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-filter,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-find {
  font: inherit;
  font-size: .8rem;
  color: var(--sem-fg);
  background: var(--sem-surface);
  border: 1px solid var(--sem-border);
  border-radius: 6px;
  padding: .15rem .45rem;
  min-width: 8rem;
}
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-tree-toggle,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-toggle {
  display: inline-block;
  margin: 0;
  padding: 0 .15rem;
  font: inherit;
  color: var(--sem-fg);
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
}
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-tree-toggle::before,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-toggle::before {
  content: "▾ ";
  color: var(--sem-muted);
}
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-tree-toggle[aria-expanded="false"]::before,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-toggle[aria-expanded="false"]::before {
  content: "▸ ";
}
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-tree-label,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-label {
  color: var(--sem-fg);
}
/* kind glyph on generated rows (text form); structured kinds ride the
   same selector via the authored node */
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-tree-toggle::after,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-toggle::after {
  content: "";
  color: var(--sem-muted);
}
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] :is(node, .sem-node)[data-kind="file"] .sem-tree-label::after,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-view-row[data-kind="file"] .sem-tree-label::after {
  content: " ·file";
  color: var(--sem-muted);
  font-size: .75rem;
}
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] :is(node, .sem-node)[data-kind="dir"] .sem-tree-label::after,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-view-row[data-kind="dir"] .sem-tree-label::after {
  content: " ·dir";
  color: var(--sem-muted);
  font-size: .75rem;
}
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-tree-count,
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-tree-count {
  font-size: .75rem;
  color: var(--sem-muted);
  white-space: nowrap;
}
/* find marks */
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] [data-match],
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] [data-match] {
  outline: 2px dotted var(--sem-accent);
  outline-offset: 1px;
}
:is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] [data-match-current],
:is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] [data-match-current] {
  background: var(--sem-accent);
  color: var(--sem-bg);
}

@media (prefers-reduced-motion: reduce) {
  :is(sem-workflow, .sem-workflow)[data-sem-upgraded] .sem-step-branch,
  :is(sem-site-tree, .sem-site-tree)[data-sem-upgraded] .sem-file-tree-view,
  :is(sem-file-tree, .sem-file-tree)[data-sem-upgraded] .sem-file-tree-view { transition: none; }
}
/* ── end sem-workflow / sem-site-tree / sem-file-tree ── */

/* ── agent-kit card chrome ────────────────────────────────────────
   One named section per component family, APPENDED below the last —
   never edited in place, so parallel component branches merge clean.
   Tokens only (the palette above); dual `:is(tag, .class)` selectors
   so the class-form alias styles identically. Everything generated by
   a component lives under `.agent-kit-chrome`; with JavaScript off
   none of this applies to anything visible except the authored
   record's plain block boxes. ─────────────────────────────────── */

/* tickets: the card frame, shared by all six tags */
:is(agent-kit-issue, .agent-kit-issue),
:is(agent-kit-epic, .agent-kit-epic),
:is(agent-kit-bug, .agent-kit-bug),
:is(agent-kit-user-story, .agent-kit-user-story),
:is(agent-kit-task, .agent-kit-task),
:is(agent-kit-sub-task, .agent-kit-sub-task) {
  box-sizing: border-box;
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  background: var(--sem-surface, #ffffff);
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 8px;
  color: var(--sem-fg, #1e293b);
}

/* ticket part tags read as their authored role before enhancement */
:is(agent-kit-issue, .agent-kit-issue) > :is(agent-kit-title, .agent-kit-title),
:is(agent-kit-epic, .agent-kit-epic) > :is(agent-kit-title, .agent-kit-title),
:is(agent-kit-bug, .agent-kit-bug) > :is(agent-kit-title, .agent-kit-title),
:is(agent-kit-user-story, .agent-kit-user-story) > :is(agent-kit-title, .agent-kit-title),
:is(agent-kit-task, .agent-kit-task) > :is(agent-kit-title, .agent-kit-title),
:is(agent-kit-sub-task, .agent-kit-sub-task) > :is(agent-kit-title, .agent-kit-title) {
  display: block;
  margin: 0 0 0.25rem;
  font-size: 1.05em;
  font-weight: 600;
}

:is(agent-kit-issue, .agent-kit-issue) > :is(agent-kit-description, .agent-kit-description),
:is(agent-kit-epic, .agent-kit-epic) > :is(agent-kit-description, .agent-kit-description),
:is(agent-kit-bug, .agent-kit-bug) > :is(agent-kit-description, .agent-kit-description),
:is(agent-kit-user-story, .agent-kit-user-story) > :is(agent-kit-description, .agent-kit-description),
:is(agent-kit-task, .agent-kit-task) > :is(agent-kit-description, .agent-kit-description),
:is(agent-kit-sub-task, .agent-kit-sub-task) > :is(agent-kit-description, .agent-kit-description) {
  display: block;
  margin: 0 0 0.5rem;
}

:is(agent-kit-issue, .agent-kit-issue) > :is(agent-kit-last-updated, .agent-kit-last-updated),
:is(agent-kit-epic, .agent-kit-epic) > :is(agent-kit-last-updated, .agent-kit-last-updated),
:is(agent-kit-bug, .agent-kit-bug) > :is(agent-kit-last-updated, .agent-kit-last-updated),
:is(agent-kit-user-story, .agent-kit-user-story) > :is(agent-kit-last-updated, .agent-kit-last-updated),
:is(agent-kit-task, .agent-kit-task) > :is(agent-kit-last-updated, .agent-kit-last-updated),
:is(agent-kit-sub-task, .agent-kit-sub-task) > :is(agent-kit-last-updated, .agent-kit-last-updated),
:is(agent-kit-issue, .agent-kit-issue) > :is(agent-kit-state, .agent-kit-state),
:is(agent-kit-epic, .agent-kit-epic) > :is(agent-kit-state, .agent-kit-state),
:is(agent-kit-bug, .agent-kit-bug) > :is(agent-kit-state, .agent-kit-state),
:is(agent-kit-user-story, .agent-kit-user-story) > :is(agent-kit-state, .agent-kit-state),
:is(agent-kit-task, .agent-kit-task) > :is(agent-kit-state, .agent-kit-state),
:is(agent-kit-sub-task, .agent-kit-sub-task) > :is(agent-kit-state, .agent-kit-state),
:is(agent-kit-issue, .agent-kit-issue) > :is(agent-kit-labels, .agent-kit-labels),
:is(agent-kit-epic, .agent-kit-epic) > :is(agent-kit-labels, .agent-kit-labels),
:is(agent-kit-bug, .agent-kit-bug) > :is(agent-kit-labels, .agent-kit-labels),
:is(agent-kit-user-story, .agent-kit-user-story) > :is(agent-kit-labels, .agent-kit-labels),
:is(agent-kit-task, .agent-kit-task) > :is(agent-kit-labels, .agent-kit-labels),
:is(agent-kit-sub-task, .agent-kit-sub-task) > :is(agent-kit-labels, .agent-kit-labels) {
  display: block;
  margin: 0 0 0.25rem;
  font-size: 0.85em;
  color: var(--sem-muted, #64748b);
}

/* chrome: the key anchor is invisible; the meta row is a chip strip */
.agent-kit-ticket-anchor { display: block; height: 0; }
.agent-kit-ticket-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  margin: 0 0 0.5rem;
  font-size: 0.8em;
}
.agent-kit-ticket-type {
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: var(--sem-accent, #2563eb);
  color: var(--sem-accent-fg, #ffffff);
  font-weight: 600;
  letter-spacing: 0.02em;
}
.agent-kit-ticket-key {
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-muted, #64748b);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.agent-kit-ticket-state {
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  color: var(--sem-muted, #64748b);
}
.agent-kit-ticket-state[data-state='done'], .agent-kit-ticket-state[data-state='review'] {
  border-color: var(--sem-correct, #059669);
  color: var(--sem-correct, #059669);
}
.agent-kit-ticket-state[data-state='cancelled'] {
  border-color: var(--sem-wrong, #dc2626);
  color: var(--sem-wrong, #dc2626);
}
.agent-kit-ticket-label {
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: rgba(37, 99, 235, 0.1);
  color: var(--sem-accent, #2563eb);
}
.agent-kit-ticket-updated, .agent-kit-ticket-snapshot {
  color: var(--sem-muted, #64748b);
  font-size: 0.95em;
}
.agent-kit-ticket-snapshot {
  display: block;
  margin: 0.5rem 0 0;
  border-top: 1px dashed var(--sem-border, #e2e8f0);
  padding-top: 0.375rem;
  font-size: 0.8em;
}
.agent-kit-ticket-open {
  display: inline-block;
  margin-top: 0.5rem;
  color: var(--sem-accent, #2563eb);
  font-size: 0.85em;
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.agent-kit-ticket-open:hover, .agent-kit-ticket-open:focus-visible {
  border-bottom-color: var(--sem-accent, #2563eb);
}

/* ticket-ref: the inline chip; the link affordance is behavior on the
   element itself, styled only under the upgrade claim */
agent-kit-ticket-ref[data-sem-upgraded], .agent-kit-ticket-ref[data-sem-upgraded] {
  cursor: pointer;
}
:is(agent-kit-ticket-ref, .agent-kit-ticket-ref) {
  display: inline-block;
  padding: 0.05rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-accent, #2563eb);
  font-size: 0.9em;
}
:is(agent-kit-ticket-ref, .agent-kit-ticket-ref):hover,
:is(agent-kit-ticket-ref, .agent-kit-ticket-ref):focus-visible {
  border-color: var(--sem-accent, #2563eb);
  outline: none;
}
/* ── end agent-kit tickets ── */

/* ── agent-kit personas ───────────────────────────────────────────
   agent-kit-user-persona / agent-kit-agent-persona — one generic
   renderer behind both tags (spec/schema/agent-kit/personas.md).
   The authored body (persona-name/role/bio/metadata parts) is the
   record; the chrome header (avatar from the CACHED url attr + the
   kind chip) and the snapshot metadata strip live inside the
   agent-kit-chrome container. Tokens only; dual spellings throughout.
   ============================================================ */

/* personas: the card frame, shared by both tags */
:is(agent-kit-user-persona, .agent-kit-user-persona),
:is(agent-kit-agent-persona, .agent-kit-agent-persona) {
  box-sizing: border-box;
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  background: var(--sem-surface, #ffffff);
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 8px;
  color: var(--sem-fg, #1e293b);
}

/* persona part tags read as their authored role before enhancement */
:is(agent-kit-user-persona, .agent-kit-user-persona) > :is(agent-kit-persona-name, .agent-kit-persona-name),
:is(agent-kit-agent-persona, .agent-kit-agent-persona) > :is(agent-kit-persona-name, .agent-kit-persona-name) {
  display: block;
  margin: 0 0 0.25rem;
  font-size: 1.05em;
  font-weight: 600;
}
:is(agent-kit-user-persona, .agent-kit-user-persona) > :is(agent-kit-persona-role, .agent-kit-persona-role),
:is(agent-kit-agent-persona, .agent-kit-agent-persona) > :is(agent-kit-persona-role, .agent-kit-persona-role) {
  display: block;
  margin: 0 0 0.5rem;
  color: var(--sem-muted, #64748b);
  font-size: 0.95em;
}
:is(agent-kit-user-persona, .agent-kit-user-persona) > :is(agent-kit-persona-bio, .agent-kit-persona-bio),
:is(agent-kit-agent-persona, .agent-kit-agent-persona) > :is(agent-kit-persona-bio, .agent-kit-persona-bio) {
  display: block;
  margin: 0 0 0.5rem;
}
:is(agent-kit-user-persona, .agent-kit-user-persona) > :is(agent-kit-persona-metadata, .agent-kit-persona-metadata),
:is(agent-kit-agent-persona, .agent-kit-agent-persona) > :is(agent-kit-persona-metadata, .agent-kit-persona-metadata) {
  display: block;
  margin: 0;
  white-space: pre-line;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em;
  color: var(--sem-muted, #64748b);
}

/* chrome: header row — round cached avatar + kind chip */
.agent-kit-persona-chrome .agent-kit-persona-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.5rem;
}
.agent-kit-persona-chrome .agent-kit-persona-avatar {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  border: 1px solid var(--sem-border, #e2e8f0);
  object-fit: cover;
  background: var(--sem-bg, #fafafa);
}
.agent-kit-persona-chrome .agent-kit-persona-kind {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
  letter-spacing: 0.02em;
}
.agent-kit-persona-chrome .agent-kit-persona-kind[data-persona-kind='agent'] {
  color: var(--sem-accent, #2563eb);
}

/* chrome: snapshot metadata chip strip (enrichment only) */
.agent-kit-persona-chrome .agent-kit-persona-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.5rem 0 0;
}
.agent-kit-persona-chrome .agent-kit-persona-meta-item {
  display: inline-block;
  padding: 0.05rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-fg, #1e293b);
  font-size: 0.85em;
}
.agent-kit-persona-chrome .agent-kit-persona-meta-item b {
  color: var(--sem-muted, #64748b);
  font-weight: 600;
}
/* ── end agent-kit personas ── */

/* ── agent-kit structured lists (acceptance criteria, custom asserts) ─
   agent-kit-acceptance-criteria: authored <agent-kit-criterion> parts,
   each a given/when/then triple. agent-kit-custom-assert: authored
   expr/expect pairs. Display-only renderers (spec/schema/agent-kit/
   acceptance-criteria.md, custom-assert.md); the only chrome is the
   header chip. Tokens only; dual spellings throughout.
   ============================================================ */

:is(agent-kit-acceptance-criteria, .agent-kit-acceptance-criteria),
:is(agent-kit-custom-assert, .agent-kit-custom-assert) {
  box-sizing: border-box;
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  background: var(--sem-surface, #ffffff);
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 8px;
  color: var(--sem-fg, #1e293b);
}

/* criteria: each criterion reads as a labelled g/w/t row */
:is(agent-kit-acceptance-criteria, .agent-kit-acceptance-criteria) > :is(agent-kit-criterion, .agent-kit-criterion) {
  display: block;
  margin: 0.5rem 0;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 6px;
  background: var(--sem-bg, #fafafa);
}
:is(agent-kit-acceptance-criteria, .agent-kit-acceptance-criteria) :is(agent-kit-given, .agent-kit-given),
:is(agent-kit-acceptance-criteria, .agent-kit-acceptance-criteria) :is(agent-kit-when, .agent-kit-when),
:is(agent-kit-acceptance-criteria, .agent-kit-acceptance-criteria) :is(agent-kit-then, .agent-kit-then) {
  display: block;
  margin: 0.15rem 0;
}
:is(agent-kit-acceptance-criteria, .agent-kit-acceptance-criteria) :is(agent-kit-given, .agent-kit-given)::before {
  content: 'Given ';
  color: var(--sem-muted, #64748b);
  font-weight: 600;
}
:is(agent-kit-acceptance-criteria, .agent-kit-acceptance-criteria) :is(agent-kit-when, .agent-kit-when)::before {
  content: 'When ';
  color: var(--sem-muted, #64748b);
  font-weight: 600;
}
:is(agent-kit-acceptance-criteria, .agent-kit-acceptance-criteria) :is(agent-kit-then, .agent-kit-then)::before {
  content: 'Then ';
  color: var(--sem-muted, #64748b);
  font-weight: 600;
}

/* asserts: expr rows carry the expression; expect rows the expectation */
:is(agent-kit-custom-assert, .agent-kit-custom-assert) > :is(agent-kit-assert-expr, .agent-kit-assert-expr) {
  display: block;
  margin: 0.5rem 0 0.1rem;
  padding: 0.3rem 0.6rem;
  border-radius: 4px;
  background: var(--sem-bg, #fafafa);
  border: 1px solid var(--sem-border, #e2e8f0);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
}
:is(agent-kit-custom-assert, .agent-kit-custom-assert) > :is(agent-kit-assert-expect, .agent-kit-assert-expect) {
  display: block;
  margin: 0 0 0.4rem 0.9rem;
  color: var(--sem-muted, #64748b);
}
:is(agent-kit-custom-assert, .agent-kit-custom-assert) > :is(agent-kit-assert-expect, .agent-kit-assert-expect)::before {
  content: '→ expect: ';
  color: var(--sem-accent, #2563eb);
  font-weight: 600;
}

/* chrome header chips (count labels) */
.agent-kit-acceptance-chrome .agent-kit-acceptance-chip,
.agent-kit-assert-chrome .agent-kit-assert-chip {
  display: inline-block;
  margin: 0 0 0.5rem;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
  letter-spacing: 0.02em;
}
/* ── end agent-kit structured lists ── */

/* ── agent-kit board ──────────────────────────────────────────────
   agent-kit-board: authored <agent-kit-column heading> parts holding
   ticket refs (spec/schema/agent-kit/board.md). Display stub — layout
   only; the only chrome is the header chip + optional snapshot stamp.
   Tokens only; dual spellings throughout.
   ============================================================ */

:is(agent-kit-board, .agent-kit-board) {
  box-sizing: border-box;
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  background: var(--sem-surface, #ffffff);
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 8px;
  color: var(--sem-fg, #1e293b);
}

:is(agent-kit-board, .agent-kit-board) > :is(agent-kit-column, .agent-kit-column) {
  display: block;
  margin: 0.5rem 0;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 6px;
  background: var(--sem-bg, #fafafa);
}
/* the column label rides the heading attribute — visible with styles
   on or off, never part of any extracted record */
:is(agent-kit-board, .agent-kit-board) > :is(agent-kit-column, .agent-kit-column)::before {
  content: attr(heading);
  display: block;
  margin: 0 0 0.35rem;
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
/* kanban-ish row when the viewport allows it; the chrome header takes
   the full first row so the chip never becomes a "column" */
.agent-kit-board-chrome {
  flex-basis: 100%;
}
@media (min-width: 40rem) {
  :is(agent-kit-board, .agent-kit-board) {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: flex-start;
  }
  :is(agent-kit-board, .agent-kit-board) > :is(agent-kit-column, .agent-kit-column) {
    flex: 1 1 12rem;
    margin: 0;
  }
}

/* chrome header chip + optional snapshot stamp */
.agent-kit-board-chrome .agent-kit-board-chip {
  display: inline-block;
  margin: 0 0 0.5rem;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
  letter-spacing: 0.02em;
}
.agent-kit-board-chrome .agent-kit-board-snapshot {
  display: inline-block;
  margin: 0.5rem 0 0;
  color: var(--sem-muted, #64748b);
  font-size: 0.85em;
}
/* ── end agent-kit board ── */

/* ── agent-kit reference cards + chatroom ─────────────────────────
   agent-kit-organization / agent-kit-project: one generic reference
   renderer (spec/schema/agent-kit/reference-cards.md) — authored
   name/description parts are the record; chrome = kind chip + slug
   footer. agent-kit-chatroom (chatroom.md): authored messages are the
   record; author labels ride the attribute through ::before. Tokens
   only; dual spellings throughout.
   ============================================================ */

/* reference cards: the card frame, shared by both tags */
:is(agent-kit-organization, .agent-kit-organization),
:is(agent-kit-project, .agent-kit-project) {
  box-sizing: border-box;
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  background: var(--sem-surface, #ffffff);
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 8px;
  color: var(--sem-fg, #1e293b);
}
:is(agent-kit-organization, .agent-kit-organization) > :is(agent-kit-name, .agent-kit-name),
:is(agent-kit-project, .agent-kit-project) > :is(agent-kit-name, .agent-kit-name) {
  display: block;
  margin: 0 0 0.25rem;
  font-size: 1.05em;
  font-weight: 600;
}
:is(agent-kit-organization, .agent-kit-organization) > :is(agent-kit-description, .agent-kit-description),
:is(agent-kit-project, .agent-kit-project) > :is(agent-kit-description, .agent-kit-description) {
  display: block;
  margin: 0;
}
.agent-kit-reference-chrome .agent-kit-reference-head {
  margin: 0 0 0.5rem;
}
.agent-kit-reference-chrome .agent-kit-reference-kind {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-accent, #2563eb);
  font-size: 0.8em;
  letter-spacing: 0.02em;
}
.agent-kit-reference-chrome .agent-kit-reference-foot {
  margin: 0.5rem 0 0;
}
.agent-kit-reference-chrome .agent-kit-reference-open {
  color: var(--sem-accent, #2563eb);
  font-size: 0.9em;
}
.agent-kit-reference-chrome .agent-kit-reference-snapshot {
  display: inline-block;
  margin: 0.5rem 0 0;
  color: var(--sem-muted, #64748b);
  font-size: 0.85em;
}

/* chatroom: transcript card */
:is(agent-kit-chatroom, .agent-kit-chatroom) {
  box-sizing: border-box;
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  background: var(--sem-surface, #ffffff);
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 8px;
  color: var(--sem-fg, #1e293b);
}
:is(agent-kit-chatroom, .agent-kit-chatroom) > :is(agent-kit-chatroom-name, .agent-kit-chatroom-name) {
  display: block;
  margin: 0 0 0.5rem;
  font-size: 1.05em;
  font-weight: 600;
}
:is(agent-kit-chatroom, .agent-kit-chatroom) > :is(agent-kit-chat-msg, .agent-kit-chat-msg) {
  display: block;
  margin: 0.35rem 0;
  padding: 0.4rem 0.7rem;
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 6px;
  background: var(--sem-bg, #fafafa);
}
/* the author label rides the attribute — visible with styles on or
   off, never part of any extracted record */
:is(agent-kit-chatroom, .agent-kit-chatroom) > :is(agent-kit-chat-msg, .agent-kit-chat-msg)::before {
  content: attr(author) ': ';
  display: block;
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
  font-weight: 600;
}
:is(agent-kit-chatroom, .agent-kit-chatroom) > :is(agent-kit-chat-msg, .agent-kit-chat-msg)[role='assistant'] {
  border-left: 3px solid var(--sem-accent, #2563eb);
}
.agent-kit-chatroom-chrome .agent-kit-chatroom-chip {
  display: inline-block;
  margin: 0 0 0.5rem;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
  letter-spacing: 0.02em;
}
.agent-kit-chatroom-chrome .agent-kit-chatroom-snapshot {
  display: inline-block;
  margin: 0.5rem 0 0;
  color: var(--sem-muted, #64748b);
  font-size: 0.85em;
}
/* ── end agent-kit reference cards + chatroom ── */

/* ── agent-kit media (asset, artifact, review) ────────────────────
   Cached cards promoting the sem-media-gallery / sem-artifact-card /
   sem-review-canvas shapes (spec/schema/agent-kit/{asset,artifact,
   review}.md). Authored captions/content/comments are the records;
   the src image, mime/type/verdict chips and version list are chrome.
   Tokens only; dual spellings throughout.
   ============================================================ */

:is(agent-kit-asset, .agent-kit-asset),
:is(agent-kit-artifact, .agent-kit-artifact),
:is(agent-kit-review, .agent-kit-review) {
  box-sizing: border-box;
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  background: var(--sem-surface, #ffffff);
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 8px;
  color: var(--sem-fg, #1e293b);
}

/* asset */
:is(agent-kit-asset, .agent-kit-asset) > :is(agent-kit-caption, .agent-kit-caption) {
  display: block;
  margin: 0.35rem 0 0;
  color: var(--sem-muted, #64748b);
  font-size: 0.9em;
}
.agent-kit-asset-chrome .agent-kit-asset-image {
  display: block;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 6px;
  background: var(--sem-bg, #fafafa);
}
.agent-kit-asset-chrome .agent-kit-asset-mime {
  display: inline-block;
  margin: 0.35rem 0 0;
  padding: 0.05rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.agent-kit-asset-chrome .agent-kit-asset-snapshot {
  display: inline-block;
  margin: 0.35rem 0 0;
  color: var(--sem-muted, #64748b);
  font-size: 0.85em;
}

/* artifact */
:is(agent-kit-artifact, .agent-kit-artifact) > :is(agent-kit-artifact-content, .agent-kit-artifact-content) {
  display: block;
  margin: 0.5rem 0 0;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 6px;
  background: var(--sem-bg, #fafafa);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em;
  white-space: pre-wrap;
}
.agent-kit-artifact-chrome .agent-kit-artifact-type {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-accent, #2563eb);
  font-size: 0.8em;
  letter-spacing: 0.02em;
}
.agent-kit-artifact-chrome .agent-kit-artifact-snapshot {
  display: inline-block;
  margin: 0.35rem 0 0;
  color: var(--sem-muted, #64748b);
  font-size: 0.85em;
}
.agent-kit-artifact-chrome .agent-kit-artifact-versions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.5rem 0 0;
}
.agent-kit-artifact-chrome .agent-kit-artifact-version {
  display: inline-block;
  padding: 0.05rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
}

/* review */
:is(agent-kit-review, .agent-kit-review) > :is(agent-kit-comment, .agent-kit-comment) {
  display: block;
  margin: 0.35rem 0;
  padding: 0.4rem 0.7rem;
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 6px;
  background: var(--sem-bg, #fafafa);
}
/* the reviewer label rides the attribute — visible with styles on or
   off, never part of any extracted record */
:is(agent-kit-review, .agent-kit-review) > :is(agent-kit-comment, .agent-kit-comment)::before {
  content: attr(author) ': ';
  display: block;
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
  font-weight: 600;
}
.agent-kit-review-chrome .agent-kit-review-verdict {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  font-size: 0.8em;
  letter-spacing: 0.02em;
  color: var(--sem-muted, #64748b);
}
.agent-kit-review-chrome .agent-kit-review-verdict[data-verdict='approve'] {
  color: var(--sem-correct, #16a34a);
  border-color: var(--sem-correct, #16a34a);
}
.agent-kit-review-chrome .agent-kit-review-verdict[data-verdict='request-changes'] {
  color: var(--sem-wrong, #dc2626);
  border-color: var(--sem-wrong, #dc2626);
}
.agent-kit-review-chrome .agent-kit-review-count {
  margin-left: 0.5rem;
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
}
.agent-kit-review-chrome .agent-kit-review-snapshot {
  display: inline-block;
  margin: 0.35rem 0 0;
  color: var(--sem-muted, #64748b);
  font-size: 0.85em;
}
/* ── end agent-kit media ── */

/* ── agent-kit testing (suite, case, cypress, cucumber) ───────────
   The suite totals its authored branch rows; the case lists steps to
   an expectation; the script pair displays its authored text/plain
   source verbatim (plain CSS promotion — identical JS-off).
   Tokens only; dual spellings throughout.
   ============================================================ */

:is(agent-kit-test-suite, .agent-kit-test-suite),
:is(agent-kit-test-case, .agent-kit-test-case),
:is(agent-kit-cypress, .agent-kit-cypress),
:is(agent-kit-cucumber, .agent-kit-cucumber) {
  box-sizing: border-box;
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  background: var(--sem-surface, #ffffff);
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 8px;
  color: var(--sem-fg, #1e293b);
}

/* suite — branch rows with attribute-borne stats */
:is(agent-kit-test-suite, .agent-kit-test-suite) > :is(agent-kit-branch, .agent-kit-branch) {
  display: block;
  margin: 0.35rem 0;
  padding: 0.4rem 0.7rem;
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 6px;
  background: var(--sem-bg, #fafafa);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em;
}
:is(agent-kit-test-suite, .agent-kit-test-suite) > :is(agent-kit-branch, .agent-kit-branch)::after {
  content: ' — ' attr(passed) ' passed, ' attr(failed) ' failed';
  color: var(--sem-muted, #64748b);
}
.agent-kit-suite-chrome .agent-kit-suite-totals {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
}
.agent-kit-suite-chrome .agent-kit-suite-snapshot {
  display: inline-block;
  margin: 0.35rem 0 0;
  color: var(--sem-muted, #64748b);
  font-size: 0.85em;
}

/* case — ordered steps to one expectation */
:is(agent-kit-test-case, .agent-kit-test-case) > :is(agent-kit-step, .agent-kit-step) {
  display: block;
  margin: 0.3rem 0;
  padding-left: 1.6rem;
  position: relative;
}
:is(agent-kit-test-case, .agent-kit-test-case) > :is(agent-kit-step, .agent-kit-step)::before {
  content: counter(agent-kit-step) '. ';
  counter-increment: agent-kit-step;
  position: absolute;
  left: 0;
  color: var(--sem-muted, #64748b);
  font-size: 0.85em;
}
:is(agent-kit-test-case, .agent-kit-test-case) {
  counter-reset: agent-kit-step;
}
:is(agent-kit-test-case, .agent-kit-test-case) > :is(agent-kit-expected, .agent-kit-expected) {
  display: block;
  margin: 0.5rem 0 0;
  padding: 0.4rem 0.7rem;
  border-left: 3px solid var(--sem-accent, #2563eb);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-fg, #1e293b);
}
:is(agent-kit-test-case, .agent-kit-test-case) > :is(agent-kit-expected, .agent-kit-expected)::before {
  content: '→ expect: ';
  color: var(--sem-muted, #64748b);
  font-size: 0.85em;
}
.agent-kit-case-chrome .agent-kit-case-count {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
}

/* script cards — the authored text/plain source, promoted by plain CSS
   (author origin beats the UA's script { display: none }): browsing the
   page with JavaScript DISABLED shows the panel exactly the same; the
   .nojs BUILD artifact strips scripts wholesale (its own invariant), so
   only there the panel is absent */
:is(agent-kit-cypress, .agent-kit-cypress) > script[type='text/plain'][data-agent-kit-script],
:is(agent-kit-cucumber, .agent-kit-cucumber) > script[type='text/plain'][data-agent-kit-script] {
  display: block;
  margin: 0.5rem 0 0;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--sem-border, #e2e8f0);
  border-radius: 6px;
  background: var(--sem-bg, #fafafa);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.8em;
  white-space: pre-wrap;
}
.agent-kit-script-chrome .agent-kit-script-kind {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--sem-border, #e2e8f0);
  background: var(--sem-bg, #fafafa);
  color: var(--sem-accent, #2563eb);
  font-size: 0.8em;
  letter-spacing: 0.02em;
}
.agent-kit-script-chrome .agent-kit-script-file {
  margin-left: 0.5rem;
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
}
.agent-kit-script-chrome .agent-kit-script-file code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.agent-kit-script-chrome .agent-kit-script-inline {
  margin-left: 0.5rem;
  color: var(--sem-muted, #64748b);
  font-size: 0.8em;
}
/* ── end agent-kit testing ── */
