/* ============================================================
   Unizo component grammar: figures
   Spec: docs/visual-grammar.md · Reference: /grammar/

   Four figures, each with one job:
     g-record   one product object and its evidence
     g-cluster  several records: one exposure moving through the loop
     g-strip    time: steps in order
     g-path     space: the exposure path itself

   Three attributes carry meaning. Page authors never pick colours.
     data-tone  hue, RISK only: neutral | muted | exposure | closed
     data-work  not a hue: active (work in flight). Absent = nothing in flight.
     data-mark  optional: reopened (on an exposure-tone element)

   An exposure stays red the whole time it is investigated, planned,
   remediated and re-checked: nothing has changed in the environment until
   verification passes. There is deliberately no in-between hue. Work in
   flight is shown with a non-hue treatment (a dashed ink orbit) so a reader
   sees both facts at once: work is happening, the path is still open.

   Tones and marks are styling hooks: never product vocabulary, never shown
   to visitors. Meaning is in the visible label beside the colour.
   Colour marks markers, edges and borders only; text is always ink.

   Layout responds to the figure's own width (container queries).
   Namespace g- only. Never reuse pf-, ea-, co-, lsc- or uc- classes.
   ============================================================ */

/* ---------- context: colours per surface ---------- */
/* Light (default). Non-text ratios on #FFFFFF / #F4F6F9:
   neutral 6.33/5.85 · muted 3.67/3.39 · exposure 4.23/3.91 ·
   closed 6.27/5.79 · work orbit (ink-2) 7.32/6.76 */
.g-record, .g-cluster, .g-strip, .g-path, .g-artifact, .g-lane {
  --g-surface: #FFFFFF;
  --g-line: rgba(10, 13, 18, 0.12);
  --g-ink: #0F131A;
  --g-ink-2: #4C5768;
  --g-ink-3: #5c6779;
  --g-neutral: var(--gray-500);
  --g-muted: var(--gray-400);
  --g-exposure: var(--critical-600);
  --g-closed: #0f6e4a;
  --g-tone: var(--g-neutral);
}
/* Dark bands. Non-text ratios on #10151d: neutral and muted 4.99 ·
   exposure 6.10 · closed 9.74 · work orbit (ink-2) 7.92 */
:where(.uw-dark, .uw-hero, .uw-sig, .lsc-dark) :is(.g-record, .g-cluster, .g-strip, .g-path, .g-artifact, .g-lane) {
  --g-surface: #10151d;
  --g-line: #232d3c;
  --g-ink: #E4E8EE;
  --g-ink-2: #A2ABBB;
  --g-ink-3: #7C8698;
  --g-neutral: var(--gray-400);
  --g-muted: var(--gray-400);
  --g-exposure: var(--critical-500);
  --g-closed: var(--success-500);
}

/* ---------- tone: risk only ---------- */
[data-tone="neutral"]  { --g-tone: var(--g-neutral); }
[data-tone="muted"]    { --g-tone: var(--g-muted); }
[data-tone="exposure"] { --g-tone: var(--g-exposure); }
[data-tone="closed"]   { --g-tone: var(--g-closed); }

/* ---------- shared marks ----------
   Applied to a figure's marker (record head dot, strip step marker,
   path node marker).
   work:     dashed ink orbit, outside everything else
   reopened: solid double ring in the tone colour */
.g-record[data-mark="reopened"] .g-record__head::before,
.g-strip__step[data-mark="reopened"]::before,
.g-path__item[data-mark="reopened"] .g-path__node[data-role="target"]::before {
  box-shadow: 0 0 0 2px var(--g-surface), 0 0 0 4px var(--g-tone);
}
.g-record[data-work="active"] .g-record__head::before,
.g-strip__step[data-work="active"]::before,
.g-path__item[data-work="active"] .g-path__node[data-breakpoint]::before,
.g-path__item[data-work="active"] .g-path__route:not(:has([data-breakpoint])) .g-path__node:last-child::before {
  outline: 2px dashed var(--g-ink-2);
  outline-offset: 3px;
}
.g-record[data-work="active"][data-mark="reopened"] .g-record__head::before,
.g-strip__step[data-work="active"][data-mark="reopened"]::before { outline-offset: 6px; }

/* ---------- shared: evidence and scaffold type ---------- */
.g-ev { font-family: var(--font-mono); font-size: 0.9em; letter-spacing: 0; }
.g-label {
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider); text-transform: uppercase; color: var(--g-ink-2);
}

/* ============================================================
   g-record
   <div class="g-record" data-tone="exposure" data-work="active">
     <p class="g-record__head">Investigation</p>
     <p class="g-record__title">…</p>
     <dl class="g-record__rows">
       <div class="g-record__row"><dt>…</dt><dd>…</dd></div>
     </dl>
     <ul class="g-record__tags"><li class="g-tag" data-tone="exposure">…</li></ul>
     <p class="g-record__note">…</p>
   </div>
   ============================================================ */
.g-record {
  container: g-record / inline-size;
  min-width: 0;
  background: var(--g-surface);
  border: 1px solid var(--g-line);
  border-radius: var(--radius-lg);
  color: var(--g-ink);
  overflow: hidden;
}
.g-record:is([data-tone="exposure"], [data-tone="closed"]) { border-color: color-mix(in srgb, var(--g-tone) 55%, var(--g-line)); }
.g-record[data-tone="muted"] { border-style: dashed; }

.g-record__head {
  display: flex; align-items: center; gap: var(--space-3);
  margin: 0;
  padding-inline: var(--space-5); padding-block: var(--space-3);
  border-bottom: 1px solid var(--g-line);
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider); text-transform: uppercase;
  color: var(--g-ink-2);
}
.g-record__head::before {
  content: ""; flex: none; width: 10px; height: 10px; box-sizing: border-box; border-radius: 50%;
  margin-inline: 2px;
  background: var(--g-tone);
  border: 2px solid var(--g-tone);
}
.g-record:is(:not([data-tone]), [data-tone="neutral"], [data-tone="muted"]) .g-record__head::before { background: var(--g-surface); }
.g-record__title {
  margin: 0;
  padding-inline: var(--space-5); padding-block: var(--space-4) 0;
  font-size: var(--text-lg); font-weight: var(--fw-semibold);
  line-height: var(--lh-snug); letter-spacing: var(--ls-tight);
  color: var(--g-ink);
  overflow-wrap: anywhere;
}
.g-record__rows {
  display: grid; gap: var(--space-3);
  margin: 0;
  padding-inline: var(--space-5); padding-block: var(--space-4) 0;
}
.g-record__row { display: grid; gap: 2px; min-width: 0; }
.g-record__row dt {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--g-ink-3);
}
.g-record__row dd {
  margin: 0; min-width: 0;
  font-size: var(--text-md); line-height: var(--lh-normal);
  color: var(--g-ink);
  overflow-wrap: anywhere;
}
@container g-record (min-width: 26rem) {
  .g-record__row { grid-template-columns: minmax(9rem, auto) minmax(0, 1fr); column-gap: var(--space-4); align-items: baseline; }
  .g-record__row dd { text-align: end; }
}
.g-record__tags {
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  margin: 0; list-style: none;
  padding-inline: var(--space-5); padding-block: var(--space-3) 0;
}
.g-record__note {
  margin: 0;
  padding-inline: var(--space-5); padding-block: var(--space-2) 0;
  font-size: var(--text-md); line-height: var(--lh-normal); color: var(--g-ink-2);
}
.g-record__title + .g-record__note { padding-block-start: var(--space-1); }
/* body parts carry top spacing only; whichever comes last closes the card */
.g-record > :last-child { padding-block-end: var(--space-5); }
.g-record > .g-record__head:last-child { padding-block-end: var(--space-3); }

.g-tag {
  display: inline-flex; align-items: center;
  padding-inline: var(--space-2-5); padding-block: var(--space-1);
  border: 1px solid var(--g-line); border-radius: var(--radius-pill);
  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--g-ink-2);
}
.g-tag:is([data-tone="exposure"], [data-tone="closed"]) { border-color: color-mix(in srgb, var(--g-tone) 60%, var(--g-line)); }
.g-tag[data-tone="muted"] { border-style: dashed; }

/* ============================================================
   g-cluster
   <div class="g-cluster">
     <ol class="g-cluster__list">
       <li><div class="g-record" data-tone="…">…</div></li>
     </ol>
   </div>
   Order is the loop order. Narrow: a single column joined by a rail.
   Wide: two columns; an odd last record (the outcome) spans both.
   ============================================================ */
.g-cluster { container: g-cluster / inline-size; min-width: 0; }
.g-cluster__list {
  display: grid; gap: var(--space-4);
  margin: 0; padding: 0; list-style: none;
}
.g-cluster__list > li { position: relative; min-width: 0; display: grid; }
.g-cluster__list > li:not(:last-child)::after {
  content: ""; position: absolute;
  inset-inline-start: calc(var(--space-5) + 6.5px);
  inset-block-end: calc(-1 * var(--space-4));
  width: 1px; height: var(--space-4);
  background: var(--g-line);
}
@container g-cluster (min-width: 34rem) {
  .g-cluster__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .g-cluster__list > li::after { display: none; }
  .g-cluster__list > li:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* ============================================================
   g-strip
   <div class="g-strip">
     <ol class="g-strip__list">
       <li class="g-strip__step" data-tone="exposure" data-work="active">
         <span class="g-strip__label">…</span>
         <span class="g-strip__note">…</span>
       </li>
     </ol>
   </div>
   Narrow: vertical, marker left, rail down. Wide: horizontal, marker
   top, rail across. Text is HTML, so it wraps; nothing is fixed-size.
   ============================================================ */
.g-strip { container: g-strip / inline-size; min-width: 0; color: var(--g-ink); }
.g-strip__list {
  display: grid; gap: 0;
  margin: 0; padding: 0; list-style: none;
}
.g-strip__step {
  position: relative; min-width: 0;
  display: grid; align-content: start; gap: var(--space-1);
  padding-inline-start: calc(14px + var(--space-5));
  padding-block-end: var(--space-6);
}
.g-strip__step:last-child { padding-block-end: 0; }
.g-strip__step::before {
  content: ""; position: absolute; z-index: 1;
  inset-inline-start: 0; inset-block-start: 3px;
  width: 14px; height: 14px; box-sizing: border-box; border-radius: 50%;
  background: var(--g-surface);
  border: 2px solid var(--g-tone);
}
.g-strip__step:is([data-tone="exposure"], [data-tone="closed"])::before { background: var(--g-tone); }
.g-strip__step[data-tone="muted"]::before { border-style: dashed; }
.g-strip__step:not(:last-child)::after {
  content: ""; position: absolute;
  inset-inline-start: 6.5px; inset-block: 17px 0;
  width: 1px; background: var(--g-line);
}
.g-strip__label {
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider); text-transform: uppercase;
  color: var(--g-ink);
}
.g-strip__note {
  font-size: var(--text-md); line-height: var(--lh-normal); color: var(--g-ink-2);
  overflow-wrap: anywhere;
}
@container g-strip (min-width: 40rem) {
  .g-strip__list { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
  .g-strip__step {
    padding-inline-start: 0; padding-inline-end: var(--space-4);
    padding-block-start: calc(14px + var(--space-4)); padding-block-end: 0;
  }
  .g-strip__step::before { inset-inline-start: 4px; inset-block-start: 4px; }
  .g-strip__step:not(:last-child)::after {
    inset-inline: 18px 0; inset-block: 10.5px auto;
    width: auto; height: 1px;
  }
}

/* ============================================================
   g-path
   <div class="g-path">
     <div class="g-path__item" data-tone="exposure" data-work="active">
       <ol class="g-path__route">
         <li class="g-path__node" data-role="entry">…</li>
         <li class="g-path__node" data-breakpoint>… <span class="g-path__tag">…</span></li>
         <li class="g-path__node" data-role="target">…</li>
       </ol>
       <p class="g-path__note">…</p>
     </div>
   </div>
   Node labels are evidence (asset names), so they are mono. A Breakpoint
   is a place, not a risk, so its marker is ink, not a hue. One route per
   item; branching graphs stay a per-page SVG in the same colours.
   ============================================================ */
.g-path { container: g-path / inline-size; min-width: 0; color: var(--g-ink); display: grid; gap: var(--space-5); }
.g-path__item { min-width: 0; display: grid; gap: var(--space-2); }
.g-path__route {
  display: grid; gap: 0;
  margin: 0; padding: 0; list-style: none;
}
.g-path__node {
  position: relative; min-width: 0;
  display: grid; align-content: start; gap: var(--space-1);
  padding-inline-start: calc(14px + var(--space-4));
  padding-block-end: var(--space-4);
  font-family: var(--font-mono); font-size: var(--text-sm); line-height: var(--lh-snug);
  color: var(--g-ink);
  overflow-wrap: anywhere;
}
.g-path__node:last-child { padding-block-end: 0; }
.g-path__node::before {
  content: ""; position: absolute; z-index: 1;
  inset-inline-start: 0; inset-block-start: 1px;
  width: 14px; height: 14px; box-sizing: border-box; border-radius: 50%;
  background: var(--g-tone);
  border: 2px solid var(--g-tone);
}
.g-path__node[data-role="entry"]::before { background: var(--g-surface); }
.g-path__node[data-role="target"]::before { box-shadow: 0 0 0 4px color-mix(in srgb, var(--g-tone) 22%, transparent); }
.g-path__node[data-breakpoint]::before {
  background: var(--g-surface);
  border-color: var(--g-ink);
  box-shadow: none;
}
.g-path__node:not(:last-child)::after {
  content: ""; position: absolute;
  inset-inline-start: 6px; inset-block: 15px 0;
  width: 2px; background: var(--g-tone);
}
.g-path__tag {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--g-ink-2);
}
.g-path__note { margin: 0; font-size: var(--text-md); line-height: var(--lh-normal); color: var(--g-ink-2); }

/* neutral: hollow markers, route not yet qualified */
.g-path__item:is(:not([data-tone]), [data-tone="neutral"]) .g-path__node::before { background: var(--g-surface); }
/* muted: qualified out. Grey, dashed, receded */
.g-path__item[data-tone="muted"] .g-path__node { color: var(--g-ink-3); }
.g-path__item[data-tone="muted"] .g-path__node::before { background: var(--g-surface); }
.g-path__item[data-tone="muted"] .g-path__node:not(:last-child)::after {
  background: repeating-linear-gradient(to bottom, var(--g-tone) 0 4px, transparent 4px 8px);
}
/* closed: the route is broken after the Breakpoint */
.g-path__item[data-tone="closed"] .g-path__node[data-breakpoint] ~ .g-path__node::before { background: var(--g-surface); }
.g-path__item[data-tone="closed"] .g-path__node[data-breakpoint]::after {
  background: repeating-linear-gradient(to bottom, var(--g-tone) 0 4px, transparent 4px 8px);
}

@container g-path (min-width: 24rem) {
  .g-path__route { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
  .g-path__node {
    justify-items: center; text-align: center;
    padding-inline: var(--space-1); padding-block: calc(14px + var(--space-3)) 0;
  }
  .g-path__node::before { inset-inline-start: calc(50% - 7px); inset-block-start: 4px; }
  .g-path__node:not(:last-child)::after {
    inset-inline: calc(50% + 7px) calc(-50% + 7px); inset-block: 10px auto;
    width: auto; height: 2px;
  }
  .g-path__item[data-tone="muted"] .g-path__node:not(:last-child)::after,
  .g-path__item[data-tone="closed"] .g-path__node[data-breakpoint]::after {
    background: repeating-linear-gradient(to right, var(--g-tone) 0 4px, transparent 4px 8px);
  }
}

/* ============================================================
   g-artifact (A3.2)
   The evidence artifact: one exposure carried end to end on a
   single object. Composes a record (what it is), a path (where it
   reaches) and a strip (where it has got to), with a freshness
   line. Built on the CTEM-21 chain; the same artifact serves the
   Verified Closure page, the AI Exposure solution and the AI use
   case. Stop-gap until the product UI revamp (B10).

   <figure class="g-artifact" data-tone="exposure" data-work="active">
     <div class="g-artifact__head">…</div>
     <div class="g-artifact__body">
       <div class="g-record">…</div>
       <div class="g-path">…</div>
     </div>
     <div class="g-strip">…</div>
     <figcaption class="g-artifact__meta">checked-as-of …</figcaption>
   </figure>

   Freshness is its own element, never merged into the evidence
   (B2). A verification result is always "checked-as-of", never a
   permanent fact.
   ============================================================ */
.g-artifact {
  container: g-artifact / inline-size;
  min-width: 0; margin: 0;
  display: grid; gap: 0;
  background: var(--g-surface);
  border: 1px solid var(--g-line);
  border-radius: var(--radius-xl);
  overflow: hidden;
  color: var(--g-ink);
}
.g-artifact:is([data-tone="exposure"], [data-tone="closed"]) { border-color: color-mix(in srgb, var(--g-tone) 45%, var(--g-line)); }
.g-artifact__head {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  padding-inline: var(--space-6); padding-block: var(--space-4);
  border-bottom: 1px solid var(--g-line);
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider); text-transform: uppercase; color: var(--g-ink-2);
}
.g-artifact__head::before {
  content: ""; flex: none; width: 10px; height: 10px; box-sizing: border-box; border-radius: 50%;
  background: var(--g-tone); border: 2px solid var(--g-tone);
}
.g-artifact__id { margin-inline-start: auto; color: var(--g-ink-3); letter-spacing: var(--ls-wide); }
.g-artifact__body {
  display: grid; gap: var(--space-6);
  padding-inline: var(--space-6); padding-block: var(--space-6);
}
.g-artifact__body > * { min-width: 0; }
.g-artifact .g-record { background: none; border: 0; border-radius: 0; }
.g-artifact .g-record__head { display: none; }
.g-artifact .g-record__title,
.g-artifact .g-record__rows,
.g-artifact .g-record__note,
.g-artifact .g-record__tags { padding-inline: 0; }
.g-artifact .g-record > :last-child { padding-block-end: 0; }
.g-artifact__label {
  display: block; margin-block-end: var(--space-3);
  font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--ls-wide);
  text-transform: uppercase; color: var(--g-ink-3);
}
.g-artifact > .g-strip {
  padding-inline: var(--space-6); padding-block: var(--space-5);
  border-top: 1px solid var(--g-line);
  background: color-mix(in srgb, var(--g-ink) 3%, transparent);
}
.g-artifact__meta {
  padding-inline: var(--space-6); padding-block: var(--space-3) var(--space-4);
  border-top: 1px solid var(--g-line);
  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--g-ink-3);
}
@container g-artifact (min-width: 46rem) {
  .g-artifact__body { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-8); align-items: start; }
}

/* ============================================================
   g-lane
   <div class="g-lane">
     <div class="g-lane__grid">
       <div class="g-lane__col" data-added>
         <p class="g-lane__stage">Verify</p>
         <div class="g-lane__cell" data-lane="you">
           <span class="g-lane__actor">Your program</span>
           <p class="g-lane__text">…</p>
         </div>
         <div class="g-lane__cell" data-lane="unizo">…</div>
       </div>
     </div>
   </div>
   Stage columns with two actor lanes. Markup is column-major, so the
   narrow layout is stage cards that keep their pair of lanes rather
   than two long stacked lists. Wide: subgrid aligns the lanes into
   rows and only the first column shows its actor labels, which become
   the lane labels. `data-added` marks a column outside the framework
   being drawn: dashed edge, non-hue, same convention as data-work.
   ============================================================ */
.g-lane { container: g-lane / inline-size; min-width: 0; color: var(--g-ink); }
.g-lane__grid {
  display: grid; gap: var(--space-5);
  grid-template-columns: minmax(0, 1fr);
  margin: 0; padding: 0; list-style: none;
}
.g-lane__col {
  min-width: 0;
  display: grid; gap: var(--space-2); align-content: start;
}
.g-lane__stage {
  margin: 0;
  padding-block-end: var(--space-2);
  border-block-end: 1px solid var(--g-line);
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider); text-transform: uppercase;
  color: var(--g-ink-2);
}
.g-lane__col[data-added] .g-lane__stage { border-block-end-style: dashed; color: var(--g-ink); }
.g-lane__cell {
  min-width: 0;
  display: grid; gap: 2px; align-content: start;
  padding-inline: var(--space-4); padding-block: var(--space-3);
  border: 1px solid var(--g-line);
  border-radius: var(--radius-lg);
}
.g-lane__cell[data-lane="you"] { background: none; border-style: dashed; }
.g-lane__cell[data-lane="unizo"] { background: var(--g-surface); }
.g-lane__col[data-added] .g-lane__cell { border-color: color-mix(in srgb, var(--g-ink-3) 45%, var(--g-line)); }
.g-lane__actor {
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider); text-transform: uppercase;
  color: var(--g-ink-3);
}
.g-lane__text { margin: 0; font-size: var(--text-md); line-height: var(--lh-normal); color: var(--g-ink-2); }
.g-lane__cell[data-lane="unizo"] .g-lane__text { color: var(--g-ink); }
.g-lane__note {
  margin: var(--space-5) 0 0;
  font-size: var(--text-md); line-height: var(--lh-normal); color: var(--g-ink-2);
  max-width: var(--measure-md);
}
.g-lane__lead {
  margin: 0 0 var(--space-5);
  font-size: var(--text-md); line-height: var(--lh-normal); color: var(--g-ink-2);
}

@container g-lane (min-width: 56rem) {
  .g-lane__grid {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    grid-template-rows: auto auto auto;
    gap: var(--space-3);
  }
  .g-lane__col { grid-row: 1 / span 3; grid-template-rows: subgrid; }
  .g-lane__col:not(:first-child) .g-lane__actor { display: none; }
}
@supports not (grid-template-rows: subgrid) {
  @container g-lane (min-width: 56rem) {
    .g-lane__col { grid-row: auto; grid-template-rows: none; }
    .g-lane__col:not(:first-child) .g-lane__actor { display: block; }
  }
}

/* ============================================================
   g-table
   Content table: two or three columns of short text. Scrolls
   inside its own wrapper rather than pushing the page sideways.
   ============================================================ */
.g-tablewrap { overflow-x: auto; max-width: 100%; }
.g-table {
  width: 100%; min-width: 30rem; border-collapse: collapse;
  font-size: var(--text-md); color: var(--g-ink);
}
.g-table th, .g-table td {
  text-align: start; vertical-align: top;
  padding-inline: var(--space-4) ; padding-block: var(--space-4);
  border-block-end: 1px solid var(--g-line);
}
.g-table th:first-child, .g-table td:first-child { padding-inline-start: 0; }
.g-table th {
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider); text-transform: uppercase; color: var(--g-ink-3);
}
.g-table td { line-height: var(--lh-normal); color: var(--g-ink-2); }
.g-table td:first-child { color: var(--g-ink); }
