/* ============================================================================
   Rampant Research — component layer
   Companion to tokens.css. Added 2026-08-09 after the nine-seat design review.

   WHY THIS FILE EXISTS
   --------------------
   The panel gallery documented a component system that no product page consumed.
   Every page re-implemented every component as an inline style string, and the
   copies had already drifted: ONE coverage state rendered five different ways, and
   the four ratified state words had become twelve strings across the site.

   A gallery that only *pictures* a system does not arrest drift. Classes do.

   THE SPLIT THIS FILE ENFORCES, AND IT IS THE POINT
   -------------------------------------------------
   Coverage state and entitlement are two ORTHOGONAL axes that had collapsed into one
   visual language: `◇ Research` and `◈ Desk` shipped with an identical
   --locked-text / --locked-fill / --locked border triple, and on a market panel the
   entitlement chip displaced the coverage chip entirely. A reader could not tell
   "we have not built this" from "you have not paid for this" — they differed by one
   12px glyph.

   That is not only a legibility problem. The free/paid membrane is an OPEN owner
   decision, and the design was required to survive either answer without re-cutting
   pages. Sharing one visual language meant moving the membrane would have re-styled
   every chip on the site.

     COVERAGE    = accent / parchment family · OUTLINE, never filled · ◆ ◇ ○ —
                   Always present on a panel. Says what WE have done.
     ENTITLEMENT = --locked-* family · FILLED wash · ◈ only
                   Present only where a gate exists. Says what YOU have bought.

   Never let one occupy the other's slot. A DESK-gated panel still shows ◆ Live.
   Convention: coverage leads (left), entitlement trails (right).
   ========================================================================= */

/* ---------------------------------------------------------------- chips */

.rr-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  white-space: nowrap;
}

.rr-chip::before {
  content: var(--glyph-flat);
  font-weight: 400;
}

/* --- COVERAGE: outline only. No fill — the fill channel belongs to entitlement. */

.rr-chip[data-state] {
  background: transparent;
  color: var(--txt-2);
  border: 1px solid var(--line);
}

.rr-chip[data-state='live'] {
  color: var(--accent);
  border-color: var(--accent-edge);
}
.rr-chip[data-state='live']::before { content: var(--glyph-live); }

.rr-chip[data-state='research']::before { content: var(--glyph-research); }

.rr-chip[data-state='watchlist'] {
  border-style: dashed;
}
.rr-chip[data-state='watchlist']::before { content: var(--glyph-watchlist); }

.rr-chip[data-state='not-covered'] {
  color: var(--txt-3);
}
.rr-chip[data-state='not-covered']::before { content: var(--glyph-notcovered); }

/* --- ENTITLEMENT: filled, desaturated, no hue. Violet is the put-side DATA colour
       and may never double as the paywall colour. */

.rr-chip[data-gate] {
  background: var(--locked-fill);
  color: var(--locked-text);
  border: 1px solid var(--locked);
}
.rr-chip[data-gate]::before { content: var(--glyph-locked); }

/* OPEN is not a paywall. It carries no lock glyph and no locked fill — a free thing
   should not be dressed in the language of a gated one. */
.rr-chip[data-gate='open'] {
  background: transparent;
  color: var(--txt-2);
  border-color: var(--line);
}
.rr-chip[data-gate='open']::before { content: ''; }

/* ---------------------------------------------------------------- stamp */

/*
  as_of is the DATA's date, never the render's. It renders at --txt-2, never --txt-3:
  the tier is a consequence of role. Since freshness self-diagnosis left the front end
  on 2026-07-30, this stamp is the ONLY freshness signal a reader gets, so it is not
  marginal and may not be dropped for space at any width.
*/
.rr-stamp {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--txt-2);
  white-space: nowrap;
}

.rr-stamp[data-vintage]::before { content: 'as filed through '; }
.rr-stamp:not([data-vintage])::before { content: 'as_of '; }

/* ---------------------------------------------------------------- label */

.rr-label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--txt-2);
}

/* ---------------------------------------------------------- source_ref */

/*
  A register row that cannot cite its artifact line does not render. The nine-field
  stat block already makes a bare percentage unrepresentable; this does the same job
  for a coverage claim, which is where the defect actually landed in round 2.
*/
.rr-source-ref {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--txt-3);
}
.rr-source-ref::before { content: 'source_ref · '; }

/* ------------------------------------------------------- register rows */

/*
  Below 600px a three-column register grid puts its REASON column — which is the
  entire payload — off-screen inside a horizontal scroller with no affordance. The
  responsive contract names the coverage chip, its reason and the as_of stamp as
  things that must stay legible at EVERY width, and the trust page is the surface
  most likely to be read on a tablet or phone. So the row restacks rather than
  scrolls.
*/
.rr-register-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 2fr);
  gap: var(--sp-3);
  align-items: baseline;
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line-2);
}

@media (max-width: 599px) {
  .rr-register-row {
    grid-template-columns: 1fr;
    gap: var(--sp-2);
  }
  .rr-register-row > * { min-width: 0; }
  /* A horizontal scroller is not an acceptable home for the reason text. */
  .rr-register-row .scroll-x { overflow-x: visible; }
}

/*
  On the register, the state chip IS the grid cell — it carried the row's padding and
  its segment of the divider as inline style. Moving the chip onto the shared class
  necessarily dropped both, so the pill floated across the row boundary and the
  divider broke under the stage column.

  The fix belongs here rather than back in the markup: the margin reproduces the
  sibling cells' padding box, and the ::after redraws the divider segment across the
  full cell width. ::before is already spoken for by the coverage glyph.
*/
.rr-register-rows > .rr-chip {
  position: relative;
  align-self: start;
  margin: var(--sp-3) var(--sp-4);
}

.rr-register-rows > .rr-chip::after {
  content: '';
  position: absolute;
  left: calc(-1 * var(--sp-4));
  right: calc(-1 * var(--sp-4));
  bottom: calc(-1 * var(--sp-3));
  border-bottom: 1px solid var(--line-2);
}

/*
  The last row closes on the card's own edge, and its sibling cells carry no divider —
  so the chip must not draw one either. Targeted by POSITION, not :last-of-type: the
  chips are spans among span siblings, so :last-of-type resolves to the final reason
  cell and the rule would silently never fire. A register row is exactly three
  children, so the final row's chip is the second-from-last child.
*/
.rr-register-rows > .rr-chip:nth-last-child(-n + 3)::after { border-bottom: 0; }

@media (max-width: 599px) {
  /* Restacked: the chip is a pill on its own line, and the row divider is drawn by
     the reason cell below it rather than by the chip. */
  .rr-register-rows > .rr-chip { margin: 0 var(--sp-4); align-self: start; }
  .rr-register-rows > .rr-chip::after { border-bottom: 0; }
}

/* --------------------------------------------------------- absence block */

/*
  The declaration block. Rendering what is deliberately not in the picture was a
  defensive detail and is now load-bearing: the end-to-end view is a completeness
  claim BY CONSTRUCTION, so the boundary has to render. It must read as integrity,
  not apology — which is why it does NOT borrow the paywall's desaturated-dashed
  language.

  🔑 TWO KINDS, and conflating them says the wrong thing. This block previously
  generated no label at all while its own comment claimed it rendered
  "absent — [reason], [date]", so the first page to use it hand-typed a word and the
  second did not — the documented-but-unenforced pattern, at small scale.

    data-declaration="absent"       we would show this; it is not wired or not
                                    available yet. A gap we acknowledge.
    data-declaration="not-covered"  we deliberately do not do this. NOT a gap —
                                    a scope boundary, and the register's ratified
                                    capability rows are these.

  Calling a deliberate exclusion "absent" reads as an apology for a decision, and
  calling an unwired series "not covered" claims a decision nobody made.
*/
.rr-absent {
  border-left: 3px solid var(--accent-edge);
  padding: var(--sp-3) var(--sp-4);
  background: transparent;
}

/*
  The label is GENERATED, never typed. A page cannot get it wrong by hand, and a
  block that does not declare its kind fails LOUDLY rather than silently picking
  one — the string below is also barred by scripts/check_design_fidelity.py, so an
  undeclared block fails the gate instead of shipping.
*/
.rr-absent::before {
  content: 'DECLARATION KIND NOT SET';
  display: block;
  margin-bottom: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--dead);
}

.rr-absent[data-declaration='absent']::before {
  content: 'Absent';
  color: var(--txt-2);
}

.rr-absent[data-declaration='not-covered']::before {
  content: 'Not covered';
  color: var(--txt-2);
}

.rr-absent .rr-absent-subject {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  color: var(--txt);
}

.rr-absent .rr-absent-reason {
  display: block;
  font-size: var(--fs-small);
  color: var(--txt-2);
}
