/* =============================================================================
 * NeuralCiberGuard — SHARED COMPONENTS
 * Canonical source: sites/shared/components.css
 * Requires:         sites/shared/tokens.css, loaded FIRST
 * Documentation:    sites/shared/components.md — the markup contract is NOT
 *                   optional; several components are only accessible if the
 *                   required ARIA is present.
 * =============================================================================
 *
 * DEPLOYMENT — identical to tokens.css; see that file's header. Each property
 * serves a byte-identical copy from its own document root, because a
 * `sites/shared/` path has no public URL on any origin and a cross-origin
 * <link> is blocked by every property's `style-src 'self'`.
 *     diff sites/shared/components.css sites/geds/css/components.css
 *
 * ── MERGE HISTORY — READ BEFORE REPLACING THIS FILE ────────────────────────
 * This file is co-owned. The card grid, terminal card and standards strip were
 * authored by the geds workstream and are LIVE on sites/geds/index.html under
 * the class names `.card-grid…`, `.term-card…` and `.standards…`. The shared
 * design workstream then merged in the four remaining components of
 * DESIGN-UPGRADES-FROM-REFERENCES.md plus §S. Nothing was replaced.
 *
 * CLASS NAMING. The shared specification names two of these components
 * `.terminal-card` and `.credibility-strip`; geds already ships `.term-card`
 * and `.standards`. Both names are supported, as SELECTOR LISTS on a single
 * declaration block — one rule, two names, so they cannot drift apart. New
 * markup should use the canonical names; the geds hub keeps working untouched
 * and can migrate whenever its owner chooses.
 *      canonical                 also accepted (geds, live)
 *      .terminal-card…           .term-card…
 *      .terminal-card__pill      .term-pill
 *      .credibility-strip…       .standards…
 *
 * ── TOKEN CONTRACT ─────────────────────────────────────────────────────────
 * Every custom property read below is a `--ncg-*` name that tokens.css defines,
 * and every one is read through `var(--ncg-name, <fallback>)`. The fallback is
 * a literal the design system already owns, so this file renders correctly on a
 * page that has neural.css and no tokens.css, on a page that has tokens.css and
 * no neural.css, and on a page that has both. Nothing here can render unstyled,
 * invisible, or in a colour the design system does not own.
 *
 * Values are consumed through SEMANTIC roles (--ncg-surface-card, --ncg-text,
 * --ncg-accent…) rather than raw palette entries, which is what lets the same
 * markup render correctly under the editorial palette, the warm palette, dark
 * mode and the Senior preset without a fork.
 *
 * ── ACCESSIBILITY FLOOR — WCAG 2.2 AA, APPLIES TO EVERY COMPONENT ──────────
 *   · Interactive cells are real <a>/<button> elements. Nothing here turns a
 *     <div> into a control, so keyboard operation, Enter/Space activation and
 *     the accessibility tree come for free (SC 2.1.1, 4.1.2).
 *   · Every standalone target is at least --ncg-target-min (44px) on both axes,
 *     and automatically 58px under the Senior preset, which re-points that same
 *     token.
 *   · Nothing encodes meaning in colour alone (SC 1.4.1): every status pill
 *     carries a word, the ring carries a numeral, the ladder carries a tier
 *     name and a state word, and the accent cell is marked by an inset rule as
 *     well as by hue.
 *   · Text contrast is >= 4.5:1 on every surface a component supports. Each
 *     ratio in a comment below was MEASURED, not estimated.
 *   · Focus indicators are drawn for light AND dark control faces (SC 1.4.11),
 *     and are never removed (SC 2.4.7).
 *   · Wide content scrolls inside its own container so the page never scrolls
 *     horizontally at 320 CSS px (SC 1.4.10).
 *   · forced-colors and prefers-reduced-motion are handled at the foot of the
 *     file, not per component, so a new component cannot forget them.
 *
 * ── PERFORMANCE ────────────────────────────────────────────────────────────
 * Hover animates composited properties only — no hover in this file can thrash
 * layout. Column count is resolved by the grid engine (`auto-fit`/`minmax`), so
 * there is no media-query ladder and no JavaScript. `will-change` is not used
 * anywhere: ROOT §6 records exactly five deliberate declarations on the root
 * site, and a shared library that sprayed a sixth across every card would undo
 * that discipline. No images, no additional font requests, no scripts.
 *
 * ── SECURITY NOTES FOR THE CONSUMING ENGINEER (details in components.md §10) ─
 *   · Populate these components with createElement + textContent. Never
 *     innerHTML with remote or user data. ROOT §7.2 records the fund tracker's
 *     invariant and §7.3 the intel engine's; these components are held to the
 *     same rule. Attack class: stored / reflected XSS.
 *   · The numeric custom properties (--ring-value, --stat-pct) must be set with
 *     `el.style.setProperty(name, String(n))` AFTER validating that n is a
 *     finite number in range — never by concatenating an unvalidated value into
 *     a `style="…"` attribute. Attack class: CSS injection through the style
 *     attribute, which can exfiltrate data through a crafted url().
 * ========================================================================== */


/* ═══════════════════════════════════════════════════════════════════════════
 * 0 · SHARED PRIMITIVES
 * Namespaced so they cannot collide with the root site's existing `.sr-only`
 * (ROOT §5.4) or with anything in neural.css.
 * ══════════════════════════════════════════════════════════════════════════ */

.ncg-sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

/* The three sites already set `*{box-sizing:border-box}` globally, but a fourth
   consumer (the dashboard) may not, and a component that silently depends on a
   host reset is a component that breaks on adoption. */
.card-grid,.card-grid *,
.term-card,.term-card *,.terminal-card,.terminal-card *,
.chain,.chain *,
.ring,.ring *,.ring-card,.ring-card *,
.rank-ladder,.rank-ladder *,
.stat-bar,.stat-bar *,
.standards,.standards *,.credibility-strip,.credibility-strip *{box-sizing:border-box}


/* ═══════════════════════════════════════════════════════════════════════════
 * 1 · CARD GRID   (DESIGN-UPGRADES §1 — the decluttering answer)
 *     root #projects · geds product navigation · game hub · dashboard
 * ───────────────────────────────────────────────────────────────────────────
 * icon + title + short description + arrow affordance; hairline dividers
 * between cells; one accent cell; near-neutral background.
 *
 * The hairlines are the container's own background showing through a 1px gap.
 * One element, one paint — instead of per-cell borders that double up between
 * neighbours and mis-render at the ends of a wrapped row.
 *
 * TWO MARKUP MODES, NEVER MIXED (components.md §2):
 *   A  the whole cell is one <a>/<button class="card-grid__cell">. The arrow is
 *      then a decorative <span class="card-grid__arrow" aria-hidden="true">.
 *   B  the cell is a plain container and each action inside it is a real
 *      <a class="card-grid__go">.   <- what sites/geds/index.html uses today
 * Nesting a link inside a link is invalid HTML and breaks both keyboard order
 * and screen-reader output. The CSS supports both; the markup must pick one.
 * ══════════════════════════════════════════════════════════════════════════ */

.card-grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(18rem,1fr));
  gap:var(--ncg-hairline,1px);
  background:var(--ncg-line,#ECE9E0);
  border:var(--ncg-hairline,1px) solid var(--ncg-line,#ECE9E0);
  border-radius:var(--ncg-r-card,14px);
  overflow:hidden;                    /* clips cells to the container radius */
  margin:24px 0 0;
  padding:0;
  list-style:none;
}

/* One column below 34rem. At 320px the 18rem minimum would otherwise overflow
   and force horizontal scrolling, which SC 1.4.10 (Reflow) forbids. */
@media (max-width:34rem){
  .card-grid{grid-template-columns:1fr}
}

.card-grid__cell{
  display:flex;
  flex-direction:column;
  gap:6px;
  min-width:0;                        /* lets long <code> wrap, not stretch */
  min-height:var(--ncg-target-min,44px);
  padding:26px 24px 22px;
  margin:0;
  background:var(--ncg-surface-card,#FFFFFF);
}

/* Mode A only: the cell is itself the control. These selectors cannot match a
   <div>/<li> cell, so mode-B markup (geds today) is untouched by them. */
a.card-grid__cell,button.card-grid__cell{
  width:100%;
  cursor:pointer;
  text-align:left;
  text-decoration:none;
  border:0;                           /* neutralises the UA <button> border */
  font:inherit;
  color:var(--ncg-text,#1C1917);
  transition:background-color var(--ncg-dur-3,.2s) var(--ncg-ease,cubic-bezier(.22,.61,.36,1));
}
a.card-grid__cell:hover,button.card-grid__cell:hover{
  background:var(--ncg-surface-raised,#F3F1EA);
}
/* The ring is INSET. The container clips overflow, so an outward ring would be
   cut off at the grid edge and the indicator would disappear exactly where it
   matters most (SC 2.4.11, focus not obscured). */
.card-grid__cell:focus-visible{
  outline:3px solid var(--ncg-focus-color,#914955);
  outline-offset:-4px;
  background:var(--ncg-surface-raised,#F3F1EA);
}

/* The accent cell. Hue is the first signal; the inset rule on the leading edge
   is the second, so the cell stays distinguishable in greyscale, under a
   colour-vision deficiency, and in forced-colors mode (SC 1.4.1). */
.card-grid__cell--accent{
  background:var(--ncg-family-bg,#F3E9EB);
  box-shadow:inset 3px 0 0 var(--ncg-accent,#914955);
}

.card-grid__icon{
  width:40px;height:40px;
  display:grid;place-items:center;
  border-radius:var(--ncg-r-sm,10px);
  background:var(--ncg-info-bg,#E3ECF5);
  color:var(--ncg-info,#1E5285);      /* 6.76:1 on its own tint */
  margin-bottom:8px;
  flex:0 0 auto;
}
.card-grid__icon svg{width:22px;height:22px}
.card-grid__cell--accent .card-grid__icon{
  background:var(--ncg-surface-card,#FFFFFF);
  color:var(--ncg-accent-strong,#7A3B46);
  border:1px solid var(--ncg-accent-line,rgba(145,73,85,.22));
}

.card-grid__eyebrow{
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:11px;
  letter-spacing:.09em;
  text-transform:uppercase;
  color:var(--ncg-accent-strong,#7A3B46);
  margin:0;
}

.card-grid__title{
  font-family:var(--ncg-serif,var(--serif,'Fraunces',Georgia,serif));
  font-size:20px;
  font-weight:600;
  line-height:1.25;
  color:var(--ncg-text,#1C1917);
  margin:2px 0 0;
}

/* `flex:1 1 auto` is what pushes .card-grid__actions to the foot of the cell,
   so a row of cells whose descriptions differ in length still lines its
   buttons up. Without it the buttons sit at ragged heights.
   --ncg-text-2 rather than --ncg-text-3: a mode-A cell raises its ground on
   hover, and #78716C measures 4.24:1 there and FAILS AA. #44403C holds
   9.09:1 on that ground. tokens.css §1 documents the trap. */
.card-grid__desc{
  flex:1 1 auto;
  font-size:15px;
  line-height:1.55;
  color:var(--ncg-text-2,#44403C);
  margin:0;
}

/* Mode A affordance: decorative, inside a cell that is itself the link. Mark it
   aria-hidden in markup so it adds no duplicate announcement. */
.card-grid__arrow{
  display:inline-flex;align-items:center;justify-content:center;
  width:32px;height:32px;
  margin-top:12px;
  border:1px solid var(--ncg-line-ui,#78716C);   /* 4.56:1 — clears the 3:1
                                                    SC 1.4.11 threshold */
  border-radius:var(--ncg-r-sm,10px);
  color:var(--ncg-text-2,#44403C);
  flex:0 0 auto;
  transition:background-color var(--ncg-dur-3,.2s) var(--ncg-ease,cubic-bezier(.22,.61,.36,1)),
             color var(--ncg-dur-3,.2s) var(--ncg-ease,cubic-bezier(.22,.61,.36,1));
}
.card-grid__arrow svg{width:16px;height:16px;display:block}
a.card-grid__cell:hover .card-grid__arrow,
a.card-grid__cell:focus-visible .card-grid__arrow{
  background:var(--ncg-accent,#914955);
  border-color:var(--ncg-accent,#914955);
  color:var(--ncg-text-on-accent,#FAF9F6);       /* 6.07:1 light · 5.27:1 dark */
}

.card-grid__actions{
  display:flex;
  flex-wrap:wrap;
  gap:10px;
  margin:16px 0 0;
  padding-top:2px;
}

/* The arrow affordance from the reference. A real link, sized to the target
   floor, and never the only route to its destination. */
.card-grid__go{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:8px;
  min-height:var(--ncg-target-min,44px);
  min-width:var(--ncg-target-min,44px);
  padding:10px 18px;
  border-radius:var(--ncg-r-sm,10px);
  background:var(--ncg-text,#1C1917);
  color:var(--ncg-text-invert,#FAF9F6);
  border:1px solid var(--ncg-text,#1C1917);
  font-family:var(--ncg-sans,var(--sans,'Inter',system-ui,-apple-system,sans-serif));
  font-size:15px;
  font-weight:600;
  text-decoration:none;
  transition:background var(--ncg-dur-3,.2s) var(--ncg-ease,cubic-bezier(.22,.61,.36,1)),
             transform  var(--ncg-dur-3,.2s) var(--ncg-ease,cubic-bezier(.22,.61,.36,1));
}
.card-grid__go:hover{
  background:var(--ncg-accent-strong,#7A3B46);
  border-color:var(--ncg-accent-strong,#7A3B46);
  color:var(--ncg-text-invert,#FAF9F6);
}
.card-grid__go svg{width:16px;height:16px;flex:0 0 auto}

.card-grid__go--ghost{
  background:transparent;
  color:var(--ncg-text,#1C1917);
  /* --ncg-line is decorative-weight and can measure under 3:1. A control edge
     is non-text UI and must clear 3:1 (SC 1.4.11), which is what --ncg-line-ui
     is for. */
  border:1px solid var(--ncg-line-ui,#78716C);
}
.card-grid__go--ghost:hover{
  background:var(--ncg-accent-soft,rgba(145,73,85,.08));
  color:var(--ncg-accent-strong,#7A3B46);
  border-color:var(--ncg-accent-strong,#7A3B46);
}

/* A dark control needs a light INNER ring and a dark outer ring, so the
   indicator clears 3:1 against the control and against the page (SC 1.4.11).
   The ghost variant is light-on-light and takes the ordinary single ring. */
.card-grid__go:focus-visible{
  outline:3px solid var(--ncg-text-invert,#FAF9F6);
  outline-offset:-6px;
  box-shadow:0 0 0 4px var(--ncg-focus-color,#914955);
}
.card-grid__go--ghost:focus-visible{
  outline:3px solid var(--ncg-focus-color,#914955);
  outline-offset:2px;
  box-shadow:none;
}


/* ═══════════════════════════════════════════════════════════════════════════
 * 2 · AGENT TERMINAL CARD   (DESIGN-UPGRADES §2)          geds hero · dashboard
 *     canonical `.terminal-card…`  ·  also accepted `.term-card…` (geds, live)
 * ───────────────────────────────────────────────────────────────────────────
 * Hero art that SHOWS an AI-assisted detection instead of describing one.
 *
 * INTEGRITY CONSTRAINT — NON-NEGOTIABLE, AND CARRIED IN CSS AS WELL AS COPY.
 * This is a security product. It must never present sample data as a finding.
 * `.terminal-card__example` is therefore not decoration: it is the visible label
 * that makes the card honest, it sits at the top of the frame where it cannot
 * be cropped out of a screenshot of the card, and it uses the loudest treatment
 * in the component. Do not quieten it and do not remove it. Prefer a genuine,
 * anonymised detection from the desktop agent's own seven MITRE ATT&CK-mapped
 * rules (T1059 reverse shell is the most legible) over an invented one.
 * Authoring rule: DESIGN-UPGRADES-FROM-REFERENCES.md §2.
 *
 * The card is ALWAYS DARK, in both themes — the rule the root site's terminal
 * already follows (ROOT §1.4: "Terminal is always dark, in both themes"). Its
 * fallback literals are therefore the VERBATIM terminal palette of ROOT §1.4,
 * not theme roles.
 * ══════════════════════════════════════════════════════════════════════════ */

.term-card,
.terminal-card{
  background:var(--ncg-term-bg,#0E0A08);
  color:var(--ncg-term-ink,#e8e0d5);            /* 15.07:1 AAA */
  border:1px solid var(--ncg-term-line,#3a2d25);
  border-radius:var(--ncg-r-geds-lg,20px);
  overflow:hidden;
  box-shadow:var(--ncg-shadow-geds-lg,0 12px 24px rgba(26,24,20,.08),0 20px 40px rgba(26,24,20,.10));
  margin:0;
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:13px;
  line-height:1.6;
  max-width:100%;
}

.term-card__example,
.terminal-card__example{
  display:flex;
  align-items:center;
  gap:10px;
  flex-wrap:wrap;
  padding:12px 20px;
  background:var(--ncg-warn-bg,#FBEFD9);
  /* Measured 12.06:1 on #FBEFD9. Deliberately darker than the --ncg-warn-text
     minimum, which is 5.98:1 since the 2026-08-07 warn adjudication (tokens.css
     §4). This is the label that keeps the card honest, so it gets the strongest
     contrast in the component rather than the lowest passing one. */
  color:#3D2A00;
  border-bottom:1px solid var(--ncg-warn,#8A4B00);
  font-family:var(--ncg-sans,var(--sans,'Inter',system-ui,-apple-system,sans-serif));
  font-size:13.5px;
  font-weight:600;
  line-height:1.5;
}
.term-card__example b,
.terminal-card__example b{
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:11px;
  letter-spacing:.1em;
  text-transform:uppercase;
  background:var(--ncg-warn,#8A4B00);
  color:#FFFFFF;                                /* 6.80:1 on #8A4B00 — AA */
  padding:3px 9px;
  border-radius:var(--ncg-r-pill,999px);
  white-space:nowrap;
}

.term-card__chrome,
.terminal-card__bar{
  display:flex;
  align-items:center;
  gap:12px;
  padding:12px 20px;
  background:var(--ncg-term-chrome,#171210);
  border-bottom:1px solid var(--ncg-term-line,#3a2d25);
}
.term-card__dots,
.terminal-card__dots{display:flex;gap:6px;flex:0 0 auto}
.term-card__dots span,.term-card__dots i,
.terminal-card__dots span,.terminal-card__dots i{
  width:10px;height:10px;border-radius:var(--ncg-r-circle,50%);display:block;
  background:var(--ncg-term-line,#3a2d25);
}
/* The macOS traffic lights — VERBATIM ROOT §1.4 .td1/.td2/.td3. Decorative:
   mark the dot row aria-hidden in markup.
   Applied to the CANONICAL name only. The live geds hub deliberately renders a
   neutral monochrome dot row under `.term-card__dots`, and that is its owner's
   call to change, not this file's. */
.terminal-card__dots :first-child{background:var(--ncg-term-dot-1,#ff5f57)}
.terminal-card__dots :nth-child(2){background:var(--ncg-term-dot-2,#febc2e)}
.terminal-card__dots :nth-child(3){background:var(--ncg-term-dot-3,#28c840)}

.term-card__name,
.terminal-card__name{
  font-size:12px;
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--ncg-term-ink-2,#c9bdb0);          /* 10.08:1 on chrome AAA */
  min-width:0;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}

/* Long command lines scroll inside the card, never the page (SC 1.4.10). */
.term-card__body,
.terminal-card__body{padding:20px;overflow-x:auto}

.term-card__line,
.terminal-card__line{
  margin:0 0 4px;
  color:var(--ncg-term-ink-2,#c9bdb0);          /* 10.69:1 AAA */
  white-space:pre-wrap;word-break:break-word;
}
.term-card__line--cmd,
.terminal-card__line--cmd{color:var(--ncg-term-ink,#e8e0d5)}
.term-card__prompt,
.terminal-card__prompt{color:var(--ncg-term-ok,#28c840);font-weight:700} /* 8.85:1 */

.term-card__label,
.terminal-card__label{
  display:block;
  font-size:11px;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--ncg-term-ink-2,#c9bdb0);
  margin:18px 0 6px;
}

.term-card__analysis,
.terminal-card__analysis{
  margin:0;
  padding:14px 16px;
  background:var(--ncg-term-chrome,#171210);
  border-left:3px solid var(--ncg-accent,#914955);
  border-radius:0 var(--ncg-r-sm,10px) var(--ncg-r-sm,10px) 0;
  color:var(--ncg-term-ink,#e8e0d5);            /* 14.20:1 on chrome AAA */
  font-family:var(--ncg-sans,var(--sans,'Inter',system-ui,-apple-system,sans-serif));
  font-size:14.5px;
  line-height:1.65;
}

/* neural.css styles bare <code> for a cream page (cream fill, crimson text).
   Inside this dark panel that would read as a light chip on charcoal, so the
   inline code face is restated for the dark surface. */
.term-card__analysis code,
.terminal-card__analysis code{
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:13px;
  background:rgba(232,224,213,.10);
  border:1px solid var(--ncg-term-line,#3a2d25);
  color:var(--ncg-term-ink,#e8e0d5);
  padding:1px 5px;
  border-radius:5px;
  word-break:break-word;
}

/* Result tree. A real <ul>, so it is announced as a list of n items and its
   nesting is conveyed structurally rather than by indentation alone. */
.term-card__tree,
.terminal-card__tree{list-style:none;margin:10px 0 0;padding:0}
.term-card__tree li,
.terminal-card__tree li{
  display:flex;
  align-items:flex-start;
  gap:10px;
  flex-wrap:wrap;
  padding:9px 0;
  border-bottom:1px solid var(--ncg-term-line,#3a2d25);
  margin:0;
  color:var(--ncg-term-ink,#e8e0d5);
}
.term-card__tree li:last-child,
.terminal-card__tree li:last-child{border-bottom:0}
.term-card__tree ul,
.terminal-card__tree ul{
  list-style:none;margin:0;padding:0 0 0 18px;
  flex:1 1 100%;border-left:1px solid var(--ncg-term-line,#3a2d25);
}
.term-card__tree code,
.terminal-card__tree code{
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:12.5px;
  color:var(--ncg-term-ink,#e8e0d5);
  background:none;
  border:0;
  padding:0;
  min-width:0;
  word-break:break-word;
}

/* Status pills. Each states its status IN WORDS; colour is a second, redundant
   channel (SC 1.4.1). Every ratio below is measured against the CARD GROUND
   (#0E0A08 / #171210) — the pills carry no fill of their own, which is what
   keeps those measurements exactly true and matches the live geds hub. */
.term-pill,
.terminal-card__pill{
  display:inline-block;
  flex:0 0 auto;
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:10.5px;
  letter-spacing:.07em;
  text-transform:uppercase;
  font-weight:600;
  padding:3px 9px;
  border-radius:var(--ncg-r-pill,999px);
  border:1px solid currentColor;
  white-space:nowrap;
}
/* Live geds names — meanings unchanged. */
.term-pill--stopped{color:var(--ncg-term-ok,#28c840)}          /*  8.34:1 AAA */
.term-pill--flagged{color:var(--ncg-term-dot-2,#febc2e)}       /* 11.01:1 AAA */
.term-pill--info{color:var(--ncg-term-ink-2,#c9bdb0)}          /* 10.08:1 AAA */

/* Canonical names, including the three the upgrade document names verbatim:
   Reachable / Blocked / Not Exploitable. */
.terminal-card__pill--reachable{color:#F08A94}                 /*  7.76:1 AAA */
.terminal-card__pill--blocked{color:#84B583}                   /*  7.89:1 AAA */
.terminal-card__pill--not-exploitable{color:var(--ncg-term-ink-2,#c9bdb0)} /* 10.08:1 */
.terminal-card__pill--contained{color:var(--ncg-term-ok,#28c840)}          /*  8.34:1 */
.terminal-card__pill--flagged{color:var(--ncg-term-dot-2,#febc2e)}         /* 11.01:1 */
.terminal-card__pill--info{color:#8CB8E0}                      /*  8.89:1 AAA */

.term-card__foot,
.terminal-card__foot{
  padding:14px 20px;
  background:var(--ncg-term-chrome,#171210);
  border-top:1px solid var(--ncg-term-line,#3a2d25);
  color:var(--ncg-term-ink-2,#c9bdb0);
  font-family:var(--ncg-sans,var(--sans,'Inter',system-ui,-apple-system,sans-serif));
  font-size:13px;
  line-height:1.6;
}
.term-card__foot strong,
.terminal-card__foot strong{color:var(--ncg-term-ink,#e8e0d5)}

/* Any control inside the always-dark card needs a light ring: the crimson focus
   colour is tuned for a cream page and would sit near 2:1 on this ground. */
.term-card a:focus-visible,.term-card button:focus-visible,
.terminal-card a:focus-visible,.terminal-card button:focus-visible{
  outline:3px solid var(--ncg-term-ink,#e8e0d5);   /* 15.07:1 vs ground */
  outline-offset:3px;
  border-radius:var(--ncg-focus-r,4px);
}

@media (max-width:600px){
  .term-card,.terminal-card{font-size:12.5px}
  .term-card__body,.terminal-card__body{padding:16px}
}


/* ═══════════════════════════════════════════════════════════════════════════
 * 3 · CHAIN + FIX FOOTER   (DESIGN-UPGRADES §3)
 *     Ciber Traversal mission debrief · dashboard incident detail
 * ───────────────────────────────────────────────────────────────────────────
 * A numbered chain of steps leading to an outcome, then a DISTINCT footer band
 * carrying the remediation. On the dashboard the Fix footer maps onto the AI
 * assistant's recommendation and reinforces the correct boundary — the
 * assistant RECOMMENDS but never acts.
 *
 * The numbers come from a real <ol> plus a CSS counter. The <ol> is what makes
 * a screen reader announce "list, 4 items" and read each position; the counter
 * only draws the badge. Never replace the <ol> with divs and typed digits.
 * ══════════════════════════════════════════════════════════════════════════ */

.chain{
  border:1px solid var(--ncg-line,#ECE9E0);
  border-radius:var(--ncg-r-card,14px);
  background:var(--ncg-surface-card,#FFFFFF);
  overflow:hidden;
  margin:24px 0 0;
}

.chain__head{
  padding:20px 24px;
  border-bottom:1px solid var(--ncg-line,#ECE9E0);
  background:var(--ncg-surface-raised,#F3F1EA);
}
.chain__eyebrow{
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:11.5px;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--ncg-accent,#914955);          /* 5.65:1 on the raised ground */
  margin:0 0 4px;
}
.chain__title{
  font-family:var(--ncg-serif,var(--serif,'Fraunces',Georgia,serif));
  font-size:20px;
  font-weight:600;
  line-height:1.1;
  color:var(--ncg-text,#1C1917);            /* 15.47:1 on the raised ground */
  margin:0;
}

.chain__steps{
  counter-reset:ncg-chain;
  list-style:none;                    /* the badge replaces the marker; the
                                         <ol> semantics are untouched */
  margin:0;padding:20px 24px;
}
.chain__step{
  counter-increment:ncg-chain;
  position:relative;
  margin:0;padding:0 0 20px 48px;
}
.chain__step:last-child{padding-bottom:0}

/* The numeral badge. `content: counter()` is generated content: it mirrors the
   list position a screen reader already announces, so it duplicates nothing and
   loses nothing if generated content is suppressed. */
.chain__step::before{
  content:counter(ncg-chain);
  position:absolute;left:0;top:0;
  width:30px;height:30px;
  display:grid;place-items:center;
  border:1px solid var(--ncg-accent-line,rgba(145,73,85,.22));
  border-radius:var(--ncg-r-circle,50%);
  background:var(--ncg-accent-soft,rgba(145,73,85,.08));
  color:var(--ncg-accent,#914955);          /* 6.07:1 light · 4.93:1 dark */
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:12px;
  font-variant-numeric:tabular-nums;
  font-weight:600;
  line-height:1;
}
/* The connector. Purely decorative, so no contrast minimum applies; it is drawn
   between badges and stops before the last one. */
.chain__step:not(:last-child)::after{
  content:"";position:absolute;left:15px;top:34px;bottom:6px;
  width:1px;background:var(--ncg-line,#ECE9E0);
}

.chain__step-title{
  font-family:var(--ncg-sans,var(--sans,'Inter',system-ui,-apple-system,sans-serif));
  font-size:15px;
  font-weight:600;
  line-height:1.5;
  color:var(--ncg-text,#1C1917);
  margin:5px 0 4px;
}
.chain__step-detail{
  font-size:14px;
  line-height:1.65;
  color:var(--ncg-text-2,#44403C);          /* 9.76:1 — never text-3 here */
  margin:0;
}
.chain__step-detail code{
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:13px;
  word-break:break-word;
}

/* A step may carry a technique reference. Real link, target floor, own ring. */
.chain__ref{
  display:inline-flex;align-items:center;gap:6px;
  min-height:var(--ncg-target-min,44px);
  margin-top:4px;
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:12px;
  letter-spacing:.06em;
  color:var(--ncg-accent,#914955);
  text-decoration:underline;
  text-underline-offset:3px;
}
.chain__ref:hover{color:var(--ncg-accent-strong,#7A3B46)}
.chain__ref:focus-visible{
  outline:3px solid var(--ncg-focus-color,#914955);
  outline-offset:2px;
  border-radius:var(--ncg-focus-r,4px);
}

/* The remediation footer — a DISTINCT band, not another step. Its own ground,
   its own heading, and a 2px top rule so the eye reads the break. Measured
   4.72:1 (title) and 9.01:1 (body) on the tint. */
.chain__fix{
  padding:20px 24px;
  background:var(--ncg-ok-bg,#E7F3EB);
  border-top:2px solid var(--ncg-ok-line,rgba(31,122,58,.32));
  color:var(--ncg-text-2,#44403C);
}
.chain__fix-title{
  display:flex;align-items:center;gap:8px;
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:12px;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--ncg-ok-text,#1F7A3A);
  margin:0 0 8px;
}
.chain__fix p{
  font-size:14px;
  line-height:1.65;
  color:var(--ncg-text-2,#44403C);
  margin:0;
}
.chain__fix p + p{margin-top:8px}

/* The assistant-boundary note: the sentence that says the assistant recommends
   but never acts. Visually quieter, still >= 4.5:1. */
.chain__fix-note{
  display:block;
  margin-top:12px;
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:12px;
  line-height:1.5;
  color:var(--ncg-text-2,#44403C);
}

@media (max-width:520px){
  .chain__head,.chain__steps,.chain__fix{padding-left:16px;padding-right:16px}
  .chain__step{padding-left:38px}
}


/* ═══════════════════════════════════════════════════════════════════════════
 * 4 · COMPLETION RING   (DESIGN-UPGRADES §6)      Senior · PCT
 * ───────────────────────────────────────────────────────────────────────────
 * The upgrade document's accessibility clause, quoted in full:
 *   "the ring must not be the only signal. Pair it with a text percentage and
 *    aria-valuenow; never encode state in colour alone."
 * `.ring__value` is therefore a REQUIRED child of the markup contract, and the
 * component is documented as invalid without it, together with
 * role="progressbar" and aria-valuenow/valuemin/valuemax/valuetext.
 * See components.md §5.
 *
 * The arc is driven by ONE number, `--ring-value` (0–100). `pathLength="100"`
 * on the circle normalises the geometry, so no circumference arithmetic and no
 * JavaScript are needed to draw it.
 * ══════════════════════════════════════════════════════════════════════════ */

.ring{
  position:relative;
  display:inline-grid;
  place-items:center;
  width:132px;height:132px;
  flex:0 0 auto;
}
.ring__svg{width:100%;height:100%;display:block;transform:rotate(-90deg)}
.ring__track{
  fill:none;
  stroke:var(--ncg-line,#ECE9E0);
  stroke-width:10;
}
.ring__arc{
  fill:none;
  stroke:var(--ncg-accent,#914955);
  stroke-width:10;
  stroke-linecap:round;
  /* Plain declaration first, so a browser without number clamp() still draws an
     arc; the clamped declaration then wins where supported and defends against
     an out-of-range author value. */
  stroke-dasharray:var(--ring-value,0) 100;
  stroke-dasharray:clamp(0,var(--ring-value,0),100) 100;
  transition:stroke-dasharray .7s var(--ncg-ease-out,cubic-bezier(.16,1,.3,1));
}
.ring__value{
  position:absolute;
  font-family:var(--ncg-serif,var(--serif,'Fraunces',Georgia,serif));
  font-size:26px;
  font-weight:600;
  font-variant-numeric:tabular-nums;  /* no horizontal jitter as it counts up */
  line-height:1;
  color:var(--ncg-text,#1C1917);      /* 16.61:1 light · 15.46:1 dark */
}
.ring__unit{font-size:15px;font-weight:500;color:var(--ncg-text-2,#44403C)}

/* State modifiers recolour the arc only. They are never the sole signal: the
   numeral is always present and the surrounding row carries a word. */
.ring--ok .ring__arc{stroke:var(--ncg-ok-text,#1F7A3A)}
.ring--warn .ring__arc{stroke:var(--ncg-warn-edge,#8A4B00)}
.ring--danger .ring__arc{stroke:var(--ncg-danger-text,#B81D30)}

/* The daily-focus card the ring was designed for: a ring beside three concrete
   rows. For an audience of adults 65+ a clear ring and three rows beat any
   dashboard. */
.ring-card{
  display:flex;align-items:center;gap:24px;flex-wrap:wrap;
  padding:24px;
  border:1px solid var(--ncg-line,#ECE9E0);
  border-radius:var(--ncg-r-card,14px);
  background:var(--ncg-surface-card,#FFFFFF);
  margin:24px 0 0;
}
.ring-card__body{flex:1 1 16rem;min-width:0}
.ring-card__title{
  font-family:var(--ncg-serif,var(--serif,'Fraunces',Georgia,serif));
  font-size:20px;font-weight:600;line-height:1.1;
  color:var(--ncg-text,#1C1917);margin:0 0 12px;
}
.ring-card__list{list-style:none;margin:0;padding:0}
.ring-card__list li{
  display:flex;align-items:center;gap:12px;
  min-height:var(--ncg-target-min,44px);
  padding:8px 0;
  border-bottom:1px solid var(--ncg-line,#ECE9E0);
  color:var(--ncg-text-2,#44403C);
  font-size:15px;
}
.ring-card__list li:last-child{border-bottom:0}
/* Done / not-done is carried by a WORD in the markup as well as by this mark. */
.ring-card__mark{
  width:24px;height:24px;flex:0 0 auto;
  display:grid;place-items:center;
  border:1px solid var(--ncg-line-ui,#78716C);
  border-radius:var(--ncg-r-circle,50%);
  font-size:12px;
  color:var(--ncg-text-2,#44403C);
}
.ring-card__list li[data-done="true"] .ring-card__mark{
  background:var(--ncg-ok-bg,#E7F3EB);
  border-color:var(--ncg-ok-line,rgba(31,122,58,.32));
  color:var(--ncg-ok-text,#1F7A3A);
}


/* ═══════════════════════════════════════════════════════════════════════════
 * 5 · RANK LADDER   (DESIGN-UPGRADES §7)     Ciber Traversal · Career Roadster
 * ───────────────────────────────────────────────────────────────────────────
 * The platform already stores users.total_xp and eight badges but has NO
 * visible progression ladder, so the leaderboard has nothing to show but a
 * number. Ten tiers give every existing XP row meaning retroactively. "Tier art
 * can be pure CSS/SVG — no new binary assets required", and this implementation
 * adds none: the medal is a clip-path hexagon.
 *
 * The medal is DECORATIVE (mark it aria-hidden). Tier identity is carried by
 * `.rank-ladder__name`, the threshold by `.rank-ladder__xp`, and the state by
 * `.rank-ladder__state`, which is a WORD — "Earned" / "Current" / "Locked". A
 * reader who cannot see the medal loses nothing (SC 1.4.1).
 * ══════════════════════════════════════════════════════════════════════════ */

.rank-ladder{
  list-style:none;
  counter-reset:ncg-tier;
  margin:24px 0 0;padding:0;
  border:1px solid var(--ncg-line,#ECE9E0);
  border-radius:var(--ncg-r-card,14px);
  background:var(--ncg-surface-card,#FFFFFF);
  overflow:hidden;
}

.rank-ladder__tier{
  counter-increment:ncg-tier;
  display:flex;align-items:center;gap:16px;
  min-height:var(--ncg-target-min,44px);
  padding:14px 20px;
  margin:0;
  border-bottom:1px solid var(--ncg-line,#ECE9E0);
}
.rank-ladder__tier:last-child{border-bottom:0}

/* The hexagon. `clip-path` needs no asset, no mask image and no extra element.
   The hairline ring is an inset shadow rather than a border, because clip-path
   also clips borders. */
.rank-ladder__medal{
  position:relative;
  width:40px;height:44px;flex:0 0 auto;
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);
  background:var(--tier-fill,var(--ncg-line,#ECE9E0));
  box-shadow:inset 0 0 0 1px rgba(28,25,23,.28);
  display:grid;place-items:center;
}
.rank-ladder__medal::before{
  content:counter(ncg-tier);
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:13.5px;
  font-variant-numeric:tabular-nums;
  font-weight:600;
  color:var(--tier-ink,#FFFFFF);
  line-height:1;
}

/* Ten-step ramp: ink → copper → gold → green → crimson → charcoal. Every value
   is an existing declared palette entry. The medal is decorative, so no
   contrast minimum applies to the fill; the numeral inside it is paired with a
   per-tier ink chosen for legibility. */
.rank-ladder__tier:nth-child(1)  .rank-ladder__medal{--tier-fill:var(--ncg-cream-3,#ECE9E0);--tier-ink:var(--ncg-ink-2,#44403C)}
.rank-ladder__tier:nth-child(2)  .rank-ladder__medal{--tier-fill:var(--ncg-ink-3,#78716C);--tier-ink:#FFFFFF}
.rank-ladder__tier:nth-child(3)  .rank-ladder__medal{--tier-fill:var(--ncg-warm-copper-t,#8F5A22);--tier-ink:#FFFFFF}
.rank-ladder__tier:nth-child(4)  .rank-ladder__medal{--tier-fill:var(--ncg-warm-copper,#B87333);--tier-ink:#1A1512}
.rank-ladder__tier:nth-child(5)  .rank-ladder__medal{--tier-fill:var(--ncg-warm-gold,#C9973F);--tier-ink:#1A1512}
.rank-ladder__tier:nth-child(6)  .rank-ladder__medal{--tier-fill:var(--ncg-warm-green-t,#44693F);--tier-ink:#FFFFFF}
.rank-ladder__tier:nth-child(7)  .rank-ladder__medal{--tier-fill:var(--ncg-warm-green,#5B8C5A);--tier-ink:#1A1512}
.rank-ladder__tier:nth-child(8)  .rank-ladder__medal{--tier-fill:var(--ncg-crimson,#914955);--tier-ink:#FFFFFF}
.rank-ladder__tier:nth-child(9)  .rank-ladder__medal{--tier-fill:var(--ncg-crimson-d,#7A3B46);--tier-ink:#FFFFFF}
.rank-ladder__tier:nth-child(10) .rank-ladder__medal{--tier-fill:var(--ncg-charcoal,#1C1917);--tier-ink:#FAF9F6}

.rank-ladder__body{flex:1 1 auto;min-width:0}
.rank-ladder__name{
  display:block;
  font-family:var(--ncg-serif,var(--serif,'Fraunces',Georgia,serif));
  font-size:18px;
  font-weight:600;
  line-height:1.1;
  color:var(--ncg-text,#1C1917);
}
.rank-ladder__xp{
  display:block;
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:12px;
  font-variant-numeric:tabular-nums;
  letter-spacing:.06em;
  color:var(--ncg-text-2,#44403C);          /* 9.76:1 — never text-3 */
  margin-top:2px;
}

.rank-ladder__state{
  flex:0 0 auto;
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:10.5px;
  letter-spacing:.06em;
  text-transform:uppercase;
  padding:4px 10px;
  border:1px solid var(--ncg-line-ui,#78716C);
  border-radius:var(--ncg-r-pill,999px);
  color:var(--ncg-text-2,#44403C);
  white-space:nowrap;
}

/* Earned / current / locked. Each carries its own WORD in the markup; these
   rules only add a second channel. `aria-current="step"` marks the current
   tier — that is what a screen reader announces. */
.rank-ladder__tier--earned .rank-ladder__state{
  color:var(--ncg-ok-text,#1F7A3A);
  background:var(--ncg-ok-bg,#E7F3EB);
  border-color:var(--ncg-ok-line,rgba(31,122,58,.32));
}
.rank-ladder__tier--current{background:var(--ncg-accent-soft,rgba(145,73,85,.08))}
.rank-ladder__tier--current .rank-ladder__state{
  color:var(--ncg-text-on-accent,#FAF9F6);
  background:var(--ncg-accent,#914955);
  border-color:var(--ncg-accent,#914955);
}
/* Locked tiers stay fully legible. Dimming a whole row below 4.5:1 to signal
   "locked" is the single most common accessibility failure in this pattern —
   only the decorative medal is desaturated. */
.rank-ladder__tier--locked .rank-ladder__medal{filter:grayscale(1);opacity:.55}

@media (max-width:520px){
  .rank-ladder__tier{flex-wrap:wrap;gap:12px}
  .rank-ladder__state{order:3;margin-left:52px}
}


/* ═══════════════════════════════════════════════════════════════════════════
 * 6 · STAT BAR   (DESIGN-UPGRADES §10)      Ciber Traversal HUD · dashboard
 * ───────────────────────────────────────────────────────────────────────────
 * "numeric-labelled bars (never bare fills)". The numeral — "50/50" — is a
 * REQUIRED child of the markup contract, exactly as the ring's percentage is.
 *
 * The fill is driven by `--stat-pct` (0–100), computed by the caller from the
 * same two numbers it prints. Width is `calc(pct * 1%)` rather than a division
 * by a var(), because dividing by a variable is a newer CSS Values 4 feature
 * and a component library should not depend on it.
 * ══════════════════════════════════════════════════════════════════════════ */

.stat-bar{margin:12px 0 0}

.stat-bar__head{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  margin-bottom:6px;
}
.stat-bar__label{
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:11.5px;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--ncg-text-2,#44403C);
  min-width:0;
}
.stat-bar__value{
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:12px;
  font-variant-numeric:tabular-nums;  /* keeps "9/50" and "50/50" the same width
                                         — no jitter as the value moves */
  font-weight:600;
  color:var(--ncg-text,#1C1917);
  white-space:nowrap;
}

.stat-bar__track{
  position:relative;
  height:10px;
  border-radius:var(--ncg-r-pill,999px);
  background:var(--ncg-surface-raised,#F3F1EA);
  box-shadow:inset 0 0 0 1px var(--ncg-line,#ECE9E0);
  overflow:hidden;
}
.stat-bar__fill{
  display:block;height:100%;
  border-radius:inherit;
  background:var(--ncg-accent,#914955);
  width:calc(var(--stat-pct,0) * 1%);
  width:clamp(0%,calc(var(--stat-pct,0) * 1%),100%);   /* defends a bad value */
  transition:width .7s var(--ncg-ease-out,cubic-bezier(.16,1,.3,1));
}
/* Animating `width` affects layout in general, but here the animated box is the
   ONLY child of a fixed-height, overflow-hidden track, so the affected subtree
   is one node and nothing outside it reflows. This is the same trade the
   existing fund bar makes (ROOT §6.4). */

.stat-bar--ok .stat-bar__fill{background:var(--ncg-ok-text,#1F7A3A)}
.stat-bar--warn .stat-bar__fill{background:var(--ncg-warn-edge,#8A4B00)}
.stat-bar--danger .stat-bar__fill{background:var(--ncg-danger-text,#B81D30)}

.stat-bar--lg .stat-bar__track{height:14px}


/* ═══════════════════════════════════════════════════════════════════════════
 * 7 · STANDARDS CREDIBILITY STRIP   (DESIGN-UPGRADES §5)          root · geds
 *     canonical `.credibility-strip…`  ·  also accepted `.standards…` (live)
 * ───────────────────────────────────────────────────────────────────────────
 * The reference pattern for this slot is a customer logo wall. A capstone has
 * no customers, and inventing them would be the exact fabrication this release
 * has been removing everywhere else. The slot carries STANDARDS ATTRIBUTION
 * instead — MITRE ATT&CK (with the version the detection rules actually cite:
 * v18), OWASP, NIST, PIPEDA — both true, and more credible for an academic
 * showcase.
 *
 * COPY RULE for anyone editing the markup that uses this component: every entry
 * must be a standard the work genuinely aligns to or maps against. "Aligned to"
 * and "mapped to" are the permitted verbs. "Certified", "compliant",
 * "approved", "audited" and "partner" are claims ABOUT A THIRD PARTY and must
 * not appear unless that third party has said so in writing. No logos: these
 * are text wordmarks, which is also why the component needs no image request.
 * ══════════════════════════════════════════════════════════════════════════ */

.standards,
.credibility-strip{
  border-top:1px solid var(--ncg-line,#ECE9E0);
  border-bottom:1px solid var(--ncg-line,#ECE9E0);
  padding:22px 0;
  margin:32px 0 0;
}

.standards__label,
.credibility-strip__label{
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:11px;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--ncg-text-2,#44403C);
  margin:0 0 14px;
}

.standards__list,
.credibility-strip__list{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));
  gap:16px 26px;
  list-style:none;
  margin:0;
  padding:0;
}
.standards__list li,
.credibility-strip__list li{margin:0;min-width:0}

.standards__name,
.credibility-strip__name{
  display:block;
  font-family:var(--ncg-serif,var(--serif,'Fraunces',Georgia,serif));
  font-size:16px;
  font-weight:600;
  color:var(--ncg-text,#1C1917);
  line-height:1.3;
}

.standards__what,
.credibility-strip__what{
  display:block;
  font-size:13.5px;
  line-height:1.55;
  color:var(--ncg-text-2,#44403C);          /* 9.76:1 — never text-3 */
  margin-top:3px;
}

/* When an entry links out to the standard it must be a real link at the target
   floor with its own ring. ROOT §7.4 requires rel="noopener" on every
   target="_blank" — that belongs in the markup, not here. */
a.standards__name,
a.credibility-strip__name{
  display:inline-flex;align-items:center;
  min-height:var(--ncg-target-min,44px);
  text-decoration:underline;text-underline-offset:3px;
}
a.standards__name:hover,
a.credibility-strip__name:hover{color:var(--ncg-accent-strong,#7A3B46)}
a.standards__name:focus-visible,
a.credibility-strip__name:focus-visible{
  outline:3px solid var(--ncg-focus-color,#914955);
  outline-offset:2px;
  border-radius:var(--ncg-focus-r,4px);
}

/* The honesty line. Small, but it is the difference between attribution and an
   implied endorsement, so it is part of the component rather than optional page
   copy. */
.standards__note,
.credibility-strip__note{
  margin:14px 0 0;
  font-family:var(--ncg-mono,var(--mono,'JetBrains Mono',ui-monospace,Menlo,monospace));
  font-size:12px;
  line-height:1.5;
  color:var(--ncg-text-2,#44403C);
}


/* ═══════════════════════════════════════════════════════════════════════════
 * S · SENIOR / HIGH-LEGIBILITY TREATMENT   (DESIGN-UPGRADES §13)
 * ───────────────────────────────────────────────────────────────────────────
 * "The strongest accessibility precedent in this codebase is already inside
 * Ciber Traversal… The Senior web experience must inherit those choices rather
 * than reinvent them, then exceed them."
 *
 * Applies when a container carries `data-ncg-palette="senior"`; tokens.css §20
 * supplies the colours and raises --ncg-target-min to 58px. The rules below are
 * the type, leading, tracking and geometry half of the treatment, VERBATIM from
 * PARITY-INVENTORY-GEDS-GAME.md §B10.1 (game/ciber-traversal.html:2421–2445).
 *
 * THE DETAIL MOST LIKELY TO BE DROPPED, preserved here on purpose: the gold rule
 * covers `.el-detail strong` as well as `a[href^="tel"]`, so an emphasised fact
 * inside a scam scenario gets the same treatment as a phone number.
 *
 * Unlike the source, this file does NOT use `!important`. The source needed it
 * to beat the game's own CRT theme inside one page; a scoped opt-in attribute on
 * a purpose-built surface does not, and leaving it out keeps the treatment
 * overridable by a user stylesheet — which for this audience matters.
 * ══════════════════════════════════════════════════════════════════════════ */

[data-ncg-palette="senior"]{
  font-family:var(--ncg-sans,'Inter',system-ui,-apple-system,sans-serif);
  font-size:var(--ncg-senior-fs,20px);
  line-height:var(--ncg-senior-lh,1.75);
  letter-spacing:var(--ncg-senior-ls,.01em);
  background:var(--ncg-surface,#241016);
  color:var(--ncg-text,#FFF6E4);                    /* 16.85:1 AAA */
}
[data-ncg-palette="senior"] h1,
[data-ncg-palette="senior"] h2{
  color:var(--ncg-senior-head,#FFFFFF);             /* 18.09:1 AAA */
  font-size:1.9rem;font-weight:800;letter-spacing:0;
}
[data-ncg-palette="senior"] h3{
  color:var(--ncg-senior-gold,#FFD24A);             /* 12.55:1 AAA */
  font-size:1.4rem;font-weight:700;
}
[data-ncg-palette="senior"] p,
[data-ncg-palette="senior"] li,
[data-ncg-palette="senior"] .el-detail,
[data-ncg-palette="senior"] .el-action-label{
  font-size:1.2rem;
  line-height:var(--ncg-senior-lh-copy,1.8);
  color:var(--ncg-text,#FFF6E4);
}
/* BOTH selectors — the pairing §B10.1 flags as the one a rewrite drops. */
[data-ncg-palette="senior"] a[href^="tel"],
[data-ncg-palette="senior"] .el-detail strong{
  color:var(--ncg-senior-gold,#FFD24A);
  font-size:1.35rem;
  font-weight:800;
}
[data-ncg-palette="senior"] .el-action-label{
  color:var(--ncg-senior-action,#9FE07B);           /* 11.56:1 AAA — a SECOND
                                                       semantic colour, distinct
                                                       from the gold used for
                                                       facts and numbers */
  font-weight:800;font-size:1.15rem;
}
[data-ncg-palette="senior"] .el-section{
  max-width:var(--ncg-senior-measure,920px);        /* a controlled measure */
  padding:var(--ncg-senior-pad,38px 30px);
}
[data-ncg-palette="senior"] button,
[data-ncg-palette="senior"] .el-nav-btn,
[data-ncg-palette="senior"] [role="button"]{
  font-size:1.2rem;
  padding:16px 26px;
  min-height:var(--ncg-senior-target,58px);
  border-width:var(--ncg-senior-border,2px);
  border-style:solid;
  font-weight:700;
  border-radius:var(--ncg-senior-r,12px);
}
[data-ncg-palette="senior"] .el-nav-btn{
  background:var(--ncg-senior-btn,#3A1016);
  border-color:var(--ncg-senior-edge,#FF8A3D);
  color:var(--ncg-senior-gold,#FFD24A);             /* 11.51:1 AAA */
}
[data-ncg-palette="senior"] .el-nav-btn:hover{background:var(--ncg-senior-btn-hover,#4A171D)}
[data-ncg-palette="senior"] .el-action-section,
[data-ncg-palette="senior"] .el-action-step{
  background:var(--ncg-senior-surface,#2E1319);
  border:var(--ncg-senior-border,2px) solid var(--ncg-senior-edge-soft,rgba(255,138,61,.45));
  border-radius:var(--ncg-senior-r-card,14px);
  padding:18px 22px;
  margin:14px 0;
}
[data-ncg-palette="senior"] .el-nav{gap:8px}
/* Focus in Senior mode is thicker than the house ring. This audience is the
   reason the 44px floor exists; the ring should never be the thing they have to
   hunt for. 12.55:1 against the ground. */
[data-ncg-palette="senior"] :focus-visible{
  outline:4px solid var(--ncg-focus-color,#FFD24A);
  outline-offset:3px;
  border-radius:var(--ncg-focus-r,4px);
}


/* ═══════════════════════════════════════════════════════════════════════════
 * FORCED COLORS (Windows High Contrast)
 * background-color, background-image and box-shadow are discarded in this mode,
 * which would erase the grid hairlines, the accent cell's leading rule, every
 * pill fill, the ring track, the medal, the bar fill and every focus ring drawn
 * with a shadow. Each is restored with a system colour so nothing silently
 * disappears. `forced-color-adjust:none` is NOT used anywhere: overriding a
 * user's chosen high-contrast palette is the opposite of the point.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (forced-colors:active){
  .card-grid{border:1px solid CanvasText}
  .card-grid__cell{border-bottom:1px solid CanvasText}
  .card-grid__cell--accent{border-left:4px solid Highlight}
  .card-grid__icon,.card-grid__go,.card-grid__arrow,
  .term-card,.term-card__example,.term-card__analysis,.term-pill,
  .terminal-card,.terminal-card__example,.terminal-card__analysis,
  .terminal-card__pill,
  .chain,.chain__fix,.rank-ladder,.ring-card,
  .standards,.credibility-strip{border:1px solid CanvasText}

  .chain__step::before{border:1px solid CanvasText;color:CanvasText}
  .chain__step:not(:last-child)::after{background:CanvasText}

  /* SVG strokes survive, but the two rings would collapse to one colour. */
  .ring__track{stroke:GrayText}
  .ring__arc{stroke:Highlight}

  /* The medal is a clip-path shape with no border; give it a visible outline. */
  .rank-ladder__medal{box-shadow:inset 0 0 0 2px CanvasText;background:Canvas}
  .rank-ladder__medal::before{color:CanvasText}
  .rank-ladder__tier--current{outline:2px solid Highlight;outline-offset:-2px}
  .rank-ladder__tier--locked .rank-ladder__medal{filter:none;opacity:1}

  .stat-bar__track{border:1px solid CanvasText}
  .stat-bar__fill{background:Highlight}

  /* Rings must be re-declared: outline colour is forced, but a ring drawn with
     box-shadow would vanish entirely. */
  .card-grid__cell:focus-visible,
  .card-grid__go:focus-visible,.card-grid__go--ghost:focus-visible,
  .chain__ref:focus-visible,
  a.standards__name:focus-visible,a.credibility-strip__name:focus-visible,
  .term-card a:focus-visible,.term-card button:focus-visible,
  .terminal-card a:focus-visible,.terminal-card button:focus-visible,
  [data-ncg-palette="senior"] :focus-visible{
    outline:3px solid Highlight;outline-offset:2px;box-shadow:none;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
 * REDUCED MOTION (WCAG 2.2 SC 2.3.3)
 * Every transition declared above is decorative, so under a reduced-motion
 * preference they are removed outright rather than shortened — no residual
 * movement reaches a reader who asked for none, and the end state is identical,
 * so nothing is left hidden or half-drawn.
 *
 * Scoped to this file's own selectors on purpose. A blanket
 * `*{transition:none!important}` from a shared stylesheet would also reach the
 * eleven reduced-motion blocks the pages already ship (ROOT §5.11) and could
 * re-break behaviour those pages guard deliberately.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion:reduce){
  a.card-grid__cell,button.card-grid__cell,
  .card-grid__go,
  .card-grid__arrow,
  .ring__arc,
  .stat-bar__fill{transition:none}
  .card-grid__go:hover{transform:none}
}
