/* ==========================================================================
   CUMPAUND — SCREENS
   Built on the adire system in app.css. Nothing here invents a token.
   ========================================================================== */

/* --------------------------------------------------------------------------
   SHELL
   -------------------------------------------------------------------------- */
.masthead {
  border-bottom: 1px solid var(--resist-line-firm);
  background: var(--indigo-900);
  position: sticky; top: 0; z-index: 40;
}
.masthead .wrap { display: flex; align-items: center; justify-content: space-between;
                  gap: var(--s4); height: 62px; }
.mark { display: flex; align-items: baseline; gap: var(--s2); text-decoration: none; color: var(--resist); }
.mark b { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-7); letter-spacing: 0.09em; text-transform: uppercase; }
.mark .wordmark { display: block; height: 19px; width: auto; }
.mark span { font-family: var(--face-data); font-size: var(--fs-2); color: var(--indigo-200); letter-spacing: .04em; }

.mast-right { display: flex; align-items: center; gap: var(--s4); }
.masthead nav { display: flex; gap: var(--s1); }
@media (max-width: 560px) {
  .mast-right { gap: var(--s2); }
  .masthead .wrap { gap: var(--s2); }
  /* The label collapses to the bare symbol on a phone, so give each toggle a
     real ~40px tap target instead of the 23px the glyph alone would leave. */
  .mast-right .ccy button { min-width: 40px; min-height: 40px; padding: 8px;
    display: inline-flex; align-items: center; justify-content: center; }
  .mast-right .ccy button span { display: none; }
}
/* The mark, the currency toggle and two nav links need about 500px and the row
   was locked to 62px with no wrap, so every page scrolled sideways on a phone —
   which this system bans outright. Below 480px the row breaks in two: identity
   above, controls below at full width. Nothing shrinks below its touch target. */
@media (max-width: 480px) {
  .masthead .wrap { flex-wrap: wrap; height: auto; padding-top: 10px; padding-bottom: 10px; row-gap: var(--s2); }
  /* The signed-in nav is four items plus the @handle menu; with the currency
     toggle it no longer fits one row on a phone. Let the controls wrap so the
     nav drops to its own line at full width instead of scrolling sideways. */
  .mast-right { flex: 1 1 100%; justify-content: space-between; flex-wrap: wrap; row-gap: var(--s2); }
  .masthead nav { flex-wrap: wrap; }
  /* Keep the dropdown on-screen when its trigger sits near the right edge. */
  .handle-panel { right: auto; left: 0; }
}
.navlink {
  padding: 7px var(--s3); font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2);
  letter-spacing: .13em; text-transform: uppercase; color: var(--resist-dim);
  border: 1px solid transparent; text-decoration: none;
}
.navlink:hover { color: var(--resist); border-color: var(--resist-line); }
.navlink[aria-current="page"] { color: var(--resist); border-color: var(--resist-line-firm); background: var(--indigo-800); }

/* The footer carries .wrap, which sets `padding: 0 var(--s5)` for the page
   gutter. This block used the padding SHORTHAND, so its `0` for the horizontal
   sides overwrote that gutter: the disclosure text measured left:0 while the
   masthead, every heading and every panel measured left:24. The compliance copy
   — the one block on the page a regulator would read first — was the only thing
   not on the page's left edge.

   Writing all four sides keeps the vertical rhythm and restores the gutter. */
.compliance-strip {
  border-top: 1px solid var(--resist-line);
  margin-top: var(--s8); padding: var(--s5) var(--s5) var(--s7);
  color: var(--resist-dim); font-size: var(--fs-4); line-height: 1.65;
}
/* Was an inline style="margin-top:8px" on the second paragraph — a literal
   outside the 4px warp. Same value, taken from the scale. */
.compliance-strip p + p { margin-top: var(--s2); }

/* The oversized wordmark signature at the foot of the page: full-bleed, paper on
   the vat ground, clipped at the baseline with overflow so it runs off the bottom
   edge like a bolt of cloth off the selvedge. The supplied artwork, never retyped;
   a low-contrast crop the brand guide permits, kept as a signature, not a logo. */
.footer-mark { overflow: hidden; line-height: 0; }
.footer-mark img {
  display: block; width: 100%; height: auto; opacity: .85;
  margin-bottom: -3.2vw;   /* negative margin under overflow:hidden clips the baseline */
}
@media (max-width: 620px) { .footer-mark img { opacity: .8; } }

/* --------------------------------------------------------------------------
   HOME
   -------------------------------------------------------------------------- */

.pie-index { display: grid; gap: 1px; background: var(--resist-line); border: 1px solid var(--resist-line); margin-top: var(--s6); }
@media (min-width: 780px)  { .pie-index { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1120px) { .pie-index { grid-template-columns: 1fr 1fr 1fr; } }

/* --------------------------------------------------------------------------
   THE DIP
   Pointing at a card lowers it one more time into the vat: dye rises from the
   bottom edge, a wet waterline travels up with it, and the cut left edge catches
   the light where the cloth breaks the surface.

   This is the section's only authored moment, and it is the same event the whole
   system is named for — depth of indigo IS quantity here, so a hover that
   deepens the dye is the one state change that means something. The obvious
   alternative, a diagonal shine sweeping across the card, is a stock web gloss
   that would have to pretend this surface is glass. Cloth has no specular
   highlight; a wet edge does.

   Everything that moves is transform-only on two pseudo-elements, so the whole
   grid animates on the compositor and nothing reflows.
   -------------------------------------------------------------------------- */
.pie-card {
  background: var(--indigo-900); padding: var(--s5); display: flex; flex-direction: column;
  gap: var(--s3); text-align: left; width: 100%; min-height: 200px;
  position: relative; overflow: hidden;
}

/* the dye itself, climbing from the bottom edge */
.pie-card::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: var(--indigo-800);
  transform: scaleY(0); transform-origin: bottom;
  transition: transform var(--dur-dip) var(--ease-vat);
}

/* The waterline, plus the glint where it meets the cut edge.
   Full-height box translated up from below, so its top border rides the dye's
   leading edge and the two stay locked without measuring anything.

   Two deliberate contrast decisions, both measured rather than eyeballed. The
   line is indigo-400 (5.00:1 against cotton) because it passes BEHIND the
   figures, and this system forbids animating any value that drops text below
   4.5:1 even for a frame; indigo-300 looked better on the lighter build card and
   measured 3.19:1, so it lost. The bright cotton glint fades to nothing by 20px,
   inside the 24px padding, so it provably never reaches type at all, which is
   why it can be full-strength cotton and carry the actual sparkle.

   A travelling highlight that dims the text it crosses is the usual way this
   effect fails, and it fails invisibly, because it only happens mid-transition
   where no screenshot catches it. */
.pie-card::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(90deg, var(--resist) 0, rgba(244, 239, 227, 0) 20px) 0 0 / 100% 2px no-repeat,
    linear-gradient(var(--indigo-400), var(--indigo-400)) 0 0 / 100% 2px no-repeat;
  transform: translateY(100%);
  transition: transform var(--dur-dip) var(--ease-vat);
}

/* type rides above the dye */
.pie-card > * { position: relative; z-index: 2; }

.pie-card:hover::before,
.pie-card:focus-visible::before { transform: scaleY(1); }
.pie-card:hover::after,
.pie-card:focus-visible::after { transform: translateY(0); }

/* --------------------------------------------------------------------------
   HEADING FACE
   Four headings did the same job in two different faces: the hero and the
   capability titles in Archivo, the pie and build titles in Archivo Black. That
   split is the thing that read as "not uniform".

   Unified on Archivo 600 rather than on Archivo Black, and deliberately so.
   Archivo Black is a chunky display grotesk; at sentence-case heading sizes it
   reads editorial, which is the least futuristic type on the page. The system's
   own Stamp Rule already says it should be "used only as a stamp, uppercase,
   widely tracked, small" — the Typography section contradicted that by handing
   it titles as well. Stamps keep it; headings do not.

   So the page now runs three faces with three jobs and no overlap:
     Archivo 600      every sentence-case heading, tracked tight
     Archivo Black    small tracked uppercase stamps only
     Martian Mono     every figure, date and measurement
   -------------------------------------------------------------------------- */
.pie-card h3 {
  font-family: var(--face-ui); font-weight: 600;
  font-size: var(--fs-6); letter-spacing: -.02em;
}
.pie-card .ret { font-family: var(--face-data); font-size: var(--fs-9); letter-spacing: -.03em; }
.ret-pair { display: flex; align-items: baseline; gap: var(--s2); flex-wrap: wrap; }
/* Same role, so the same tracking. These two carried .04em and normal, which is
   the kind of drift that reads as sloppiness without ever being nameable. */
.ret-tag { font-family: var(--face-data); font-size: var(--fs-4); color: var(--resist-dim); letter-spacing: .04em; }
.ret-alt { font-family: var(--face-data); font-size: var(--fs-5); color: var(--indigo-200);
           letter-spacing: .04em; margin-left: var(--s2); }

/* The return split into what price did and what dividends did — the product's
   decomposition band in miniature, sized by real backtest data. Fill pigments:
   indigo is price, oxidation gold is dividends, divided by a cotton resist seam
   (the 1px gap over the line beneath), matching the card grid's own hairlines.
   The share is also printed in words below, so the pigments are never the only
   signal. */
.pie-contrib { margin-top: var(--s3); display: flex; flex-direction: column; gap: 6px; }
.pie-contrib-bar { display: flex; height: 6px; gap: 1px; background: var(--resist-line-firm); }
.pie-contrib-bar .seg-price { background: var(--c-price); }
.pie-contrib-bar .seg-div   { background: var(--c-dividend); }
.pie-contrib-lab { font-size: var(--fs-1); letter-spacing: .1em; text-transform: uppercase;
                   color: var(--oxide-ink); }

/* A coverage window and a constituent count are MEASUREMENT, and this system
   sets measurement in mono. They were in the proportional prose face, which put
   a third type voice in a card that should carry two and made the whole tile
   read softer than the figure sitting above it. Mono also lets the two dates
   line up as a range instead of drifting. */
.pie-card .sub {
  font-family: var(--face-data); font-size: var(--fs-4);
  color: var(--resist-dim); letter-spacing: -.01em;
}
/* Loading: a thread being drawn through the vat, holding the figure's space. */
.ret-waiting { display: flex; align-items: center; gap: var(--s3); height: 34px; }
.ret-waiting i { display: block; width: 84px; height: 3px; background: var(--indigo-700); overflow: hidden; position: relative; }
.ret-waiting i::after { content: ''; position: absolute; inset: 0; width: 40%;
  background: var(--indigo-300); animation: soak 1.15s var(--ease-vat) infinite; }
.ret-waiting span { font-family: var(--face-data); font-size: var(--fs-4); color: var(--resist-dim); }
@media (prefers-reduced-motion: reduce) { .ret-waiting i::after { animation: none; width: 100%; } }

/* The build card takes the same dip one step deeper in the vat: it sits at the
   selected depth at rest and reaches the committed-action depth on hover, which
   is exactly what indigo-500 means everywhere else in the system. Same mechanic,
   different depth, so the two card types read as one family. */
.build-cta {
  background: var(--indigo-600); padding: var(--s5); display: flex; flex-direction: column;
  gap: var(--s3); justify-content: center; min-height: 200px; text-align: left; width: 100%;
  position: relative; overflow: hidden;
}
.build-cta::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: var(--indigo-500);
  transform: scaleY(0); transform-origin: bottom;
  transition: transform var(--dur-dip) var(--ease-vat);
}
.build-cta::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(90deg, var(--resist) 0, rgba(244, 239, 227, 0) 20px) 0 0 / 100% 2px no-repeat,
    linear-gradient(var(--indigo-400), var(--indigo-400)) 0 0 / 100% 2px no-repeat;
  transform: translateY(100%);
  transition: transform var(--dur-dip) var(--ease-vat);
}
.build-cta > * { position: relative; z-index: 3; }
.build-cta::after { z-index: 2; }
.build-cta:hover::before,
.build-cta:focus-visible::before { transform: scaleY(1); }
.build-cta:hover::after,
.build-cta:focus-visible::after { transform: translateY(0); }

.build-cta h3 {
  font-family: var(--face-ui); font-weight: 600;
  font-size: var(--fs-7); letter-spacing: -.02em;
}

/* --------------------------------------------------------------------------
   THE CLOTH
   One placement, at full strength.

   The band is the selvedge the cards are cut from: it carries no text, so it can
   be read as actual fabric without spending a point of contrast budget, and it
   is the only thing on this page that is unmistakably Nigerian rather than
   merely dark and technical.

   The BLOOM stencils the same cloth into the build card, between the dye and
   the type. A first attempt failed three ways and all three are worth naming,
   because they are the ways this effect usually fails:

   1. The mask was a radial tuned for a 330px card. At 529px its solid radius ran
      past the whole card and cloth covered everything. Percentage radii on a
      box whose width you do not control is a trap.
   2. It sat at 5% opacity at rest, which is the worst place a pattern can be:
      too faint to read as pattern, too present to read as clean.
   3. Cotton linework ran behind cotton type.

   The rebuild fixes the cause of each. The mask is now a VERTICAL band gradient,
   so it depends only on the card's height and holds at any width — cloth in the
   top and bottom thirds, and a clear channel through the middle where the copy
   sits. That channel is not a compromise, it is the idea: the type is itself a
   resist, the place the pattern does not reach.

   And the bloom is fully clipped away at rest rather than faded, so there is no
   ghost state at all. It is uncovered from the bottom up on the dip's own clock,
   which means the pattern appears exactly where the dye has climbed to. The
   lower band surfaces first because the vat reaches it first. That is the actual
   process, not an illustration of it.
   -------------------------------------------------------------------------- */
.cloth-svg { display: block; width: 100%; height: 100%; }

.adire-band {
  height: 56px; margin-top: var(--s6); color: var(--resist);
  opacity: .30; overflow: hidden;
  border: 1px solid var(--resist-line); border-bottom: 0;
}
/* The band and the grid are one piece of cloth, so the grid loses the margin
   that would otherwise open a seam between them. */
.adire-band + .pie-index { margin-top: 0; }

/* Unrolled rather than faded in: cloth arrives off a bolt. It runs once, on a
   surface with no text on it, so it costs the reader nothing. */
.adire-band.is-unrolling { animation: unroll 620ms var(--ease-vat) both; }
@keyframes unroll {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

.adire-bloom {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  color: var(--resist); opacity: .26;
  /* Clipped, not faded. At rest the cloth is not dimmed, it is simply not there
     yet, so the card has no half-present texture to explain. */
  clip-path: inset(100% 0 0 0);
  transition: clip-path var(--dur-dip) var(--ease-vat);
  /* Height-based, so it holds at every card width. Cloth top and bottom, clear
     channel through the middle where the copy sits. */
  -webkit-mask-image: linear-gradient(to bottom,
    #000 0, #000 18%, transparent 30%, transparent 72%, #000 84%, #000 100%);
          mask-image: linear-gradient(to bottom,
    #000 0, #000 18%, transparent 30%, transparent 72%, #000 84%, #000 100%);
}
/* z-index has to beat `.build-cta > *`, which puts type at 3. */
.build-cta > .adire-bloom { z-index: 1; }
.build-cta:hover .adire-bloom,
.build-cta:focus-visible .adire-bloom { clip-path: inset(0 0 0 0); }

/* The arrow leads by a few pixels, the way a pulled thread moves before the
   cloth does. Transform only, so the label never reflows under it. */
.build-cta .go { display: inline-block; transition: transform var(--dur-dip) var(--ease-vat); }
.build-cta:hover .go,
.build-cta:focus-visible .go { transform: translateX(5px); }

/* --------------------------------------------------------------------------
   BUILDER — two panels divided by a resist line
   -------------------------------------------------------------------------- */
.builder { display: grid; gap: 1px; background: var(--resist-line); }
@media (min-width: 1000px) { .builder { grid-template-columns: minmax(0,1fr) minmax(0,1.02fr); } }

.bench { background: var(--vat); padding: var(--s5); min-width: 0; }
.bench > header { margin-bottom: var(--s4); }
/* Sentence-case heading, so it takes the heading face like every other one.
   Fixing this only on the home screen would have swapped one inconsistency for
   a worse one: home in Archivo, builder in Archivo Black. */
.bench h2 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-6);
            letter-spacing: -.02em; color: var(--resist); }

/* ---- instrument cloth: a grid of stencil squares ---- */
.filters { display: flex; gap: var(--s2); margin: var(--s3) 0 var(--s3); flex-wrap: wrap; }
.chips { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: var(--s4); }
.chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px;
  border: 1px solid var(--resist-line); background: var(--indigo-900); color: var(--resist-soft);
  font-size: var(--fs-4); transition: background var(--dur-tap) var(--ease-vat),
  border-color var(--dur-tap) var(--ease-vat), color var(--dur-tap) var(--ease-vat); }
.chip i { font-family: var(--face-data); font-size: var(--fs-1); font-style: normal; color: var(--resist-dim); }
.chip:hover { background: var(--indigo-700); border-color: var(--resist-line-firm); color: var(--resist); }
.chip[aria-pressed="true"] { background: var(--indigo-300); border-color: var(--indigo-300); color: var(--vat); }
.chip[aria-pressed="true"] i { color: var(--indigo-800); }
.chip:active { transform: translateY(1px); }

.swatch-foot { display: flex; align-items: center; justify-content: space-between;
               gap: 6px; margin-top: auto; flex-wrap: wrap; }
.basis { font-family: var(--face-data); font-size: var(--fs-1); }
.basis.is-total { color: var(--vine-ink); }
.basis.is-priceonly { color: var(--oxide-ink); }
.filters .field { flex: 1 1 190px; }
.filters select.field { flex: 0 1 175px; }

.cloth {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 1px; background: var(--resist-line);
  border: 1px solid var(--resist-line);
  max-height: 560px; overflow-y: auto; overflow-x: hidden;
  scrollbar-width: thin; scrollbar-color: transparent transparent;
  transition: scrollbar-color 320ms var(--ease-vat);
}
/* A resist thread, not a chrome scrollbar: invisible at rest, dyed while the
   user is actually scrolling, and it never takes layout width. */
.cloth::-webkit-scrollbar { width: 8px; }
.cloth::-webkit-scrollbar-track { background: transparent; }
.cloth::-webkit-scrollbar-thumb {
  background-color: transparent; border: 3px solid transparent;
  background-clip: content-box; transition: background-color 320ms var(--ease-vat);
}
.cloth.is-scrolling { scrollbar-color: var(--indigo-400) transparent; }
.cloth.is-scrolling::-webkit-scrollbar-thumb { background-color: var(--indigo-400); }
.cloth:hover::-webkit-scrollbar-thumb { background-color: var(--indigo-500); }
.swatch {
  background: var(--indigo-900); padding: var(--s3); text-align: left;
  display: flex; flex-direction: column; gap: 5px; min-height: 96px;
  transition: background var(--dur-tap) var(--ease-vat);
  position: relative;
}
.swatch:hover:not(.is-blocked) { background: var(--indigo-700); }
.swatch[draggable="true"] { cursor: grab; }
.swatch[draggable="true"]:active { cursor: grabbing; }
.swatch:not(.is-blocked):active { background: var(--indigo-500); transform: translateY(1px); }
.swatch.is-lifting { opacity: .45; }
.swatch.is-picked.is-pulsing { animation: swatch-take 420ms var(--ease-vat); }
/* The "taken" flash rides an outline, not the background: interpolating the
   ground would dip text contrast below AA for the length of the animation. */
@keyframes swatch-take {
  0%   { outline: 2px solid var(--oxide); outline-offset: -2px; }
  70%  { outline: 2px solid var(--oxide); outline-offset: -2px; }
  100% { outline: 2px solid transparent; outline-offset: -2px; }
}
.swatch.is-blocked { opacity: .46; cursor: not-allowed; background: var(--indigo-900); }
.swatch.is-picked { background: var(--indigo-600); }
.swatch .sym { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-5); letter-spacing: .04em; }
.swatch .swatch .nm  { font-size: var(--fs-2); color: var(--resist-dim); line-height: 1.35;
               display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.swatch .cov { font-family: var(--face-data); font-size: var(--fs-1); color: var(--indigo-200); }
.swatch.is-picked .cov, .swatch.is-picked .nm { color: var(--resist-soft); }

.badge-filters { display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--s4); }
.axis { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.axis-label { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .12em;
  text-transform: uppercase; color: var(--resist-dim); width: 92px; flex: none; }
.chip-sm { padding: 3px 8px; font-size: var(--fs-1); }
.marks { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.mark { font-family: var(--face-data); font-size: var(--fs-1); color: var(--resist-dim); white-space: nowrap; }
.mark-full, .mark-reviewed, .mark-clean { color: var(--vine-ink); }
.mark-partial, .mark-stale { color: var(--oxide-ink); }
.mark-none, .mark-unreviewed, .mark-suspect { color: var(--kola-ink); }
.chip.mark-full[aria-pressed="true"], .chip.mark-reviewed[aria-pressed="true"], .chip.mark-clean[aria-pressed="true"] { background: var(--vine-ink); border-color: var(--vine-ink); color: var(--vat); }
.chip.mark-partial[aria-pressed="true"], .chip.mark-stale[aria-pressed="true"] { background: var(--oxide-ink); border-color: var(--oxide-ink); color: var(--vat); }
.chip.mark-none[aria-pressed="true"], .chip.mark-unreviewed[aria-pressed="true"], .chip.mark-suspect[aria-pressed="true"] { background: var(--kola-ink); border-color: var(--kola-ink); color: var(--vat); }

.swatch.is-unadjusted { box-shadow: inset 3px 0 0 0 var(--kola); }
.ca-warn { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .06em;
  color: var(--kola-ink); line-height: 1.3; }

/* Position alerts — minimal, and never crushed onto the symbol. A warning is a
   CRACKLE (the resist broke); its note floats in on hover or focus. Notes stay
   quiet stamped text. :empty collapses the row when a holding is clean. */
.pos-sym { display: inline; }
/* INLINE with the symbol, not a row beneath it — a block row of markers grew
   every flagged row a third of a line taller than the clean ones. The crackle
   rides the symbol's own line, vertically centred and sized under the cap
   height, so a flagged row is exactly as tall as an unflagged one. */
.pos-flags { display: inline-flex; align-items: center; gap: var(--s1);
             margin-left: var(--s2); vertical-align: middle; }
.pos-flags:empty { display: none; }

/* The crackle marker: kola-inked linework, small horizontal hit padding, no
   vertical padding so it never stretches the line. cursor:help signals there is
   more; the note reveals on hover or focus. */
.pos-flag.is-warn { position: relative; display: inline-flex; align-items: center;
  color: var(--kola-ink); cursor: help; padding: 0 2px; }
.pf-ico { display: inline-flex; align-items: center; }
.pf-ico .crackle { width: 8px; height: 11px; display: block; overflow: visible; }
/* The crackle glyph itself — kola linework that inherits currentColor from the
   caveat it marks, so it is kola in the positions marker and in every inline
   caveat label alike. One mark for a data caveat, never the ⚠ triangle. */
.crackle path { fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
/* Inline prefix before a caveat label (source ledger, reconcile preview): the
   crackle sits in front of the text, sized to the line, never wrapping away
   from its label. */
.crackle-mark { display: inline-flex; vertical-align: -1px; margin-right: 5px; flex: 0 0 auto; }
.crackle-mark .crackle { width: 9px; height: 11px; display: block; overflow: visible; }
/* On hover, focus, or a row hover, the note floats below the mark — positioned
   absolutely so the row never changes height. */
.pf-reveal { position: absolute; left: 0; top: calc(100% + 3px); z-index: 4;
  white-space: nowrap; font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
  letter-spacing: .06em; color: var(--kola-ink); background: var(--indigo-800);
  border: 1px solid color-mix(in srgb, var(--kola) 42%, transparent);
  padding: var(--s1) var(--s2); opacity: 0; transform: translateY(-4px);
  pointer-events: none;
  transition: opacity var(--dur-tap) var(--ease-vat), transform var(--dur-tap) var(--ease-vat); }
.pos-flag.is-warn:hover .pf-reveal,
.pos-flag.is-warn:focus-visible .pf-reveal,
.agree-tbl tr:hover .pos-flag.is-warn .pf-reveal { opacity: 1; transform: none; }
.pos-flag.is-warn:focus-visible { outline: 2px solid var(--oxide); outline-offset: 2px; }

/* Informational notes: quiet stamped text, no alarm, no border. */
.pos-note { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .06em;
  color: var(--resist-dim); line-height: 1.25; white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  .pf-reveal { transition-timing-function: linear; transform: none; }
}
.ca-warn-inline { color: var(--kola-ink); font-size: var(--fs-1); }
.ca-alert { border: 1px solid var(--kola); margin-top: var(--s6); background: rgba(192,75,51,.10); }
.ca-alert > h2 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-5);
  letter-spacing: -.02em;
  color: var(--kola-ink); padding: var(--s3) var(--s4); border-bottom: 1px solid var(--resist-line); }
.ca-alert > p { padding: var(--s4); font-size: var(--fs-4); line-height: 1.6; color: var(--resist); }

/* ---- tier seal ---- */
.seal { position: relative; display: inline-flex; align-items: center; flex: none;
        line-height: 0; cursor: help; }
.seal-mark { display: inline-flex; }
.seal.is-verified { color: var(--vine-ink); }
.seal.is-usable   { color: var(--oxide-ink); }
.seal.is-blocked  { color: var(--kola-ink); }

/* Hover/focus panel: a hairline card in the world's own language, never a
   rounded browser tooltip.

   Fixed and parented to <body>, because the instrument grid scrolls and would
   otherwise slice this open panel in half. JS supplies left/top and flips it on
   either axis near a viewport edge; the colour class it carries is the tier's,
   so the heading matches the mark that opened it. */
.seal-tip {
  position: fixed; z-index: 90; left: 0; top: 0;
  width: 244px; max-width: calc(100vw - 16px); padding: var(--s3);
  background: var(--indigo-800); border: 1px solid var(--resist-line-firm);
  line-height: 1.5; text-align: left; pointer-events: none;
  opacity: 0; visibility: hidden; transform: translateY(-3px);
  transition: opacity var(--dur-tap) var(--ease-vat),
              transform var(--dur-tap) var(--ease-vat), visibility var(--dur-tap);
}
.seal-tip.is-verified { color: var(--vine-ink); }
.seal-tip.is-usable   { color: var(--oxide-ink); }
.seal-tip.is-blocked  { color: var(--kola-ink); }
/* Laid out but not painted, so the flip maths can measure real dimensions. */
.seal-tip.is-measuring { visibility: hidden; opacity: 0; transition: none; }
.seal-tip.is-open { opacity: 1; visibility: visible; transform: none; }
.seal:focus-visible { outline: 2px solid var(--oxide); outline-offset: 3px; }
.seal-tip b { display: block; font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2);
              letter-spacing: .1em; text-transform: uppercase; color: currentColor; }
.seal-tip em { display: block; margin-top: 5px; font-style: normal;
               font-size: var(--fs-4); color: var(--resist-soft); }
.seal-tip ul { margin: var(--s2) 0 0; padding-left: 15px; }
.seal-tip li { font-size: var(--fs-1); color: var(--resist-dim); margin-bottom: 3px; }
@media (prefers-reduced-motion: reduce) { .seal-tip { transition: none; } }


/* ==========================================================================
   HUD LAYER
   Borrowed from the brief's reference: technical framing, floating readouts,
   measure ticks, live telemetry. Deliberately NOT borrowed: violet neon and
   glow-bloom, which would fight the dye world rather than extend it. Every
   mark here is hairline work, so it reads as instrumentation cut into cloth
   rather than light painted over it.
   ========================================================================== */

/* corner brackets: four L-marks, the reference's framing in resist hairlines */
.hud { position: relative; }
.hud::before, .hud::after,
.hud > .hud-b::before, .hud > .hud-b::after {
  content: ''; position: absolute; width: 11px; height: 11px; pointer-events: none;
  border-color: var(--indigo-200); border-style: solid; border-width: 0;
}
.hud::before { top: -1px; left: -1px; border-top-width: 1px; border-left-width: 1px; }
.hud::after { top: -1px; right: -1px; border-top-width: 1px; border-right-width: 1px; }
.hud > .hud-b::before { bottom: -1px; left: -1px; border-bottom-width: 1px; border-left-width: 1px; }
.hud > .hud-b::after { bottom: -1px; right: -1px; border-bottom-width: 1px; border-right-width: 1px; }

/* live telemetry strip: real dataset state, always visible */
.telemetry {
  display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap;
  padding: 7px 0; border-bottom: 1px solid var(--resist-line-faint);
  font-family: var(--face-data); font-size: var(--fs-1); color: var(--resist-dim);
  letter-spacing: .04em;
}
.telemetry b { color: var(--resist-soft); font-weight: 400; }
.pulse {
  width: 6px; height: 6px; background: var(--vine-ink); flex: none;
  box-shadow: 0 0 0 0 rgba(134,199,149,.55); animation: pulse 2.6s var(--ease-vat) infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(134,199,149,.5); }
  70%  { box-shadow: 0 0 0 6px rgba(134,199,149,0); }
  100% { box-shadow: 0 0 0 0 rgba(134,199,149,0); }
}
@media (prefers-reduced-motion: reduce) { .pulse { animation: none; } }

/* measure ticks: the reference's ruler marks, already our own idiom */
.ticks { display: flex; gap: 3px; margin-top: 6px; }
.ticks i { width: 1px; height: 9px; background: var(--resist-line-firm); }
.ticks i:nth-child(5n+1) { height: 11px; background: var(--indigo-200); }
.ticks i { transform-origin: bottom;
  transition: background var(--dur-tap) var(--ease-vat), transform var(--dur-tap) var(--ease-vat); }
.ticks i.lit { background: var(--vine-ink); transform: scaleY(1.7); }
.hud-stat b { font-variant-numeric: tabular-nums; }

/* floating stat readouts */
.hud-stat { display: flex; flex-direction: column; gap: 2px; }
.hud-stat span { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
  letter-spacing: .14em; text-transform: uppercase; color: var(--resist-dim); }
.hud-stat b { font-family: var(--face-data); font-size: var(--fs-8);
  font-weight: 500; letter-spacing: -.03em; color: var(--resist); }
/* Dividend events count carries the dividend pigment — the same oxidation gold
   that fills the seed-card decomposition bars, so the binding reads as one
   language across the page rather than an isolated accent. */
.hud-stat-div b { color: var(--oxide-ink); }
.hud-stat-div .ticks i.lit { background: var(--oxide); }

/* chamfered primary action: the reference's cut-corner CTA, which happens to
   be exactly our hard-cut geometry rather than a rounded pill */
.btn-cut {
  clip-path: polygon(11px 0, 100% 0, 100% calc(100% - 11px), calc(100% - 11px) 100%, 0 100%, 0 11px);
  padding: 13px var(--s5);
}

/* ==========================================================================
   HERO
   ========================================================================== */
.hero-hud { position: relative; display: grid; gap: var(--s6); padding: var(--s7) 0 var(--s6);
            border-bottom: 1px solid var(--resist-line); }
@media (min-width: 940px) { .hero-hud { grid-template-columns: minmax(0,1fr) minmax(0,1.05fr); align-items: center; } }

/* A — the adire cloth behind the hero. Mid-vat indigo linework, faint, and
   dye-depth gradient-masked so it emerges from the top-right (behind the figure)
   and washes to nothing before the reading column — the text area stays clean, so
   contrast is never touched. Suppressed for reduced-motion-agnostic reasons only
   as a static wash (it does not animate). */
.hero-cloth { position: absolute; inset: 0; z-index: 0; pointer-events: none;
  color: var(--indigo-700); opacity: .55; overflow: hidden;
  -webkit-mask-image: radial-gradient(130% 115% at 100% 0%, var(--vat) 0%, var(--vat) 38%, transparent 66%);
          mask-image: radial-gradient(130% 115% at 100% 0%, var(--vat) 0%, var(--vat) 38%, transparent 66%); }
.hero-cloth .cloth-svg { width: 100%; height: 100%; }
/* A2 — the reactive gold reveal. The same cloth in oxidation gold, shown only inside
   a soft circle that tracks the cursor (JS sets --gx / --gy / --on): the woven motifs
   light up gold near the pointer and fade at the edge, a flashlight over the pattern.
   Decorative gold here is a hero-only brand moment, not a data pigment. */
.hero-cloth-glow { position: absolute; inset: 0; z-index: 0; pointer-events: none;
  color: var(--oxide); overflow: hidden;
  opacity: calc(var(--on, 0) * .5);
  transition: opacity var(--fade, 2400ms) ease;
  -webkit-mask-image: radial-gradient(circle 210px at var(--gx, -1000px) var(--gy, -1000px), rgba(0,0,0,.82) 0%, rgba(0,0,0,.3) 40%, transparent 80%);
          mask-image: radial-gradient(circle 210px at var(--gx, -1000px) var(--gy, -1000px), rgba(0,0,0,.82) 0%, rgba(0,0,0,.3) 40%, transparent 80%); }
.hero-cloth-glow .cloth-svg { width: 100%; height: 100%; }
.hero-hud > div:not(.hero-cloth):not(.hero-cloth-glow) { position: relative; z-index: 1; }

/* Weight 600 to match every other heading. At 400 the largest type on the page
   was also the lightest, which is what let the hero and the card titles drift
   apart without either looking wrong on its own. */
.hero-hud h1 {
  font-family: var(--face-ui); font-weight: 600;
  font-size: var(--fs-hero); line-height: 1.02; letter-spacing: -0.035em;
  max-width: 15ch; color: var(--resist);
}
.hero-hud .lede { margin-top: var(--s4); max-width: 56ch; font-size: var(--fs-7);
                  line-height: 1.55; color: var(--resist-soft); }
.hero-cta { display: flex; align-items: center; gap: var(--s5); margin-top: var(--s6); flex-wrap: wrap; }
.cta-ghost { display: inline-flex; align-items: center; gap: var(--s2); padding-bottom: 5px;
  border-bottom: 1px solid var(--indigo-400); color: var(--resist);
  font-family: var(--face-data); font-size: var(--fs-4);
  transition: border-color var(--dur-tap) var(--ease-vat), color var(--dur-tap) var(--ease-vat); }
.cta-ghost:hover { border-color: var(--resist); color: var(--indigo-100); }

/* The hero money-story: the page's one Display-face moment, answering the
   headline with a real basket. The naira figure is the anchor; the read line
   names the dollar translation and lets the bound pigments carry the meaning —
   osun for what devaluation took, gold for what dividends added. No new colour,
   font, or size: it reuses .figure-hero (the Display treatment) and the bound
   pigment inks the rest of the product already uses. */
.hero-story { margin-top: var(--s5); min-height: 92px; }
/* The interactive setup line. Smaller than the old hero headline on purpose: the
   Display payoff below is the peak, this is the sentence that leads into it. The
   editable tokens carry a 1px resist underline (the .cta-ghost affordance) and
   take oxide on hover/focus — oxide is the system's bound "look here / a place
   the eye must go first" role, so an editable control earns it. */
.hero-head { min-height: 150px; }
.hero-hud .hero-h1 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-9);
  line-height: 1.25; letter-spacing: -.02em; max-width: 26ch; color: var(--resist-soft); }
.hero-tok { font: inherit; color: var(--resist); background: none; padding: 0 1px;
  border: 0; border-bottom: 1px solid var(--indigo-400); cursor: pointer;
  transition: border-color var(--dur-tap) var(--ease-vat), color var(--dur-tap) var(--ease-vat); }
.hero-tok:hover, .hero-tok:focus-visible { border-color: var(--oxide); color: var(--resist); outline: none; }
.hero-amt { font-family: var(--face-ui); font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.hero-amt-input { font: inherit; font-family: var(--face-ui); font-weight: 700; color: var(--resist);
  background: var(--indigo-800); border: 1px solid var(--indigo-300); padding: 0 6px; width: 8ch; }
.hero-money { margin-top: var(--s3); display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 0 var(--s3); color: var(--resist); }
.hero-money .hero-arrow { color: var(--indigo-300); }
.hero-lead { font-family: var(--face-ui); font-weight: 600; letter-spacing: normal;
  font-size: var(--fs-6); color: var(--resist-dim); }
.hero-result { color: var(--resist); }
.hero-meta { margin-top: var(--s2); color: var(--resist-dim); }

/* The woven decomposition bar — capital (undyed cotton) dipped to price (indigo)
   and oxidised to dividends (gold), the three threads drawing in from zero on
   load. Widths are set inline from real backtest data and animated by
   weaveHeroCloth; these rules hold the pigments, the seams and the resting look.
   The key beneath names each thread, so colour is never the only code. */
.hero-weave { margin-top: var(--s4); max-width: 30ch; display: flex;
  flex-direction: column; gap: var(--s2); }
.hero-weave-bar { display: flex; height: 12px; gap: 1px; overflow: hidden;
  background: var(--resist-line-firm); }
/* Width is the true (inline) size and the resting transform is identity, so the
   bar is always correct at rest. Only .is-drawing plays the keyframe — a
   compositor animation that self-completes and never needs rAF, so the threads
   can't stall half-drawn. They stagger left to right. */
.hero-weave-bar .wv { height: 100%; transform-origin: left center; will-change: transform; }
.hero-weave.is-drawing .wv { animation: weave-draw .8s var(--ease-vat) both; }
.hero-weave.is-drawing .wv-price  { animation-delay: .10s; }
.hero-weave.is-drawing .wv-income { animation-delay: .22s; }
.hero-weave-bar .wv-capital { background: var(--resist-soft); }
.hero-weave-bar .wv-price   { background: var(--c-price); }
.hero-weave-bar .wv-income  { background: var(--c-dividend); }
@keyframes weave-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) { .hero-weave.is-drawing .wv { animation: none; } }
.hero-weave-key { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4);
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .12em;
  text-transform: uppercase; color: var(--resist-dim); }
.hero-weave-key .wvk { display: inline-flex; align-items: center; gap: 6px; }
.hero-weave-key .wvk > i { width: 8px; height: 8px; }
.hero-weave-key .wvk-capital > i { background: var(--resist-soft); }
.hero-weave-key .wvk-price > i   { background: var(--c-price); }
.hero-weave-key .wvk-income > i  { background: var(--c-dividend); }

.hero-read { margin-top: var(--s4); max-width: 48ch; font-size: var(--fs-6);
  line-height: 1.5; color: var(--resist-soft); }
.hero-read .data { color: var(--resist); }
.hero-read .ink-fx { color: var(--osun); }
.hero-read .ink-div { color: var(--oxide-ink); }
.hero-src { margin-top: var(--s3); color: var(--resist-dim); }

/* the figure IS the dataset: every instrument plotted by coverage start */
.hero-figure { position: relative; padding: var(--s5); }
.hero-figure svg { display: block; width: 100%; height: auto; }
.figure-rail { display: flex; justify-content: space-between; margin-top: var(--s3); }
.hud-float { display: flex; flex-wrap: wrap; gap: var(--s6) var(--s7); margin-top: var(--s5); }

.hero-legend { display: flex; gap: var(--s4); flex-wrap: wrap; margin-top: var(--s3);
  font-family: var(--face-data); font-size: var(--fs-1); color: var(--resist-dim); }
.hero-legend i { display: inline-block; width: 7px; height: 7px; margin-right: 5px; }


/* ==========================================================================
   THE LOOM — hero figure
   Warp stands, weft weaves, marks plot, selvedge locks. One-shot on arrival.
   ========================================================================== */
.loom-wrap svg { display: block; width: 100%; height: auto; overflow: visible; }

.warp { stroke: var(--resist-line); stroke-width: 1; }
.weft { stroke: var(--indigo-600); stroke-width: 1; }
.selvedge-line { stroke: var(--resist-line-firm); stroke-width: 2; }
.ax { font-family: var(--face-data); font-size: var(--fs-1); fill: var(--resist-dim); }
.ax-r { text-anchor: end; }
.ax-mid { text-anchor: middle; }
.ax-cap { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .14em; fill: var(--resist-dim); }

/* resting state = fully woven (no JS, no motion support: still correct) */
.loom-wrap .warp, .loom-wrap .weft, .loom-wrap .mk, .loom-wrap .selvedge-line { opacity: 1; }

.loom-wrap.is-weaving .warp {
  stroke-dasharray: 300; stroke-dashoffset: 300;
  animation: warp-drop 520ms var(--ease-vat) both; animation-delay: var(--d, 0ms);
}
.loom-wrap.is-weaving .weft {
  stroke-dasharray: 620; stroke-dashoffset: 620;
  animation: weft-throw 620ms var(--ease-vat) both; animation-delay: var(--d, 0ms);
}
.loom-wrap.is-weaving .mk {
  opacity: 0; animation: mark-land 320ms var(--ease-vat) both; animation-delay: var(--d, 0ms);
}
.loom-wrap.is-weaving .selvedge-line {
  transform-origin: center bottom; animation: selvedge-lock 420ms var(--ease-vat) both;
  animation-delay: 1600ms;
}
@keyframes warp-drop   { to { stroke-dashoffset: 0; } }
@keyframes weft-throw  { to { stroke-dashoffset: 0; } }
@keyframes mark-land   { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: none; } }
@keyframes selvedge-lock { 0% { transform: scaleY(.2); } 70% { transform: scaleY(1.04); } 100% { transform: scaleY(1); } }

@media (prefers-reduced-motion: reduce) {
  .loom-wrap.is-weaving .warp, .loom-wrap.is-weaving .weft,
  .loom-wrap.is-weaving .mk, .loom-wrap.is-weaving .selvedge-line { animation: none !important; opacity: 1; }
}

/* the hero sits ON the loom: warp continues behind the whole first viewport,
   which also fills the void the left column had below the CTA */
.hero-hud { position: relative; }
.hero-hud::before {
  content: ''; position: absolute; inset: -8px -12px; z-index: -1; pointer-events: none;
  background-image: repeating-linear-gradient(90deg,
    var(--resist-line-faint) 0 1px, transparent 1px 84px);
  mask-image: linear-gradient(180deg, transparent, var(--vat) 22%, var(--vat) 72%, transparent);
  -webkit-mask-image: linear-gradient(180deg, transparent, var(--vat) 22%, var(--vat) 72%, transparent);
}

/* tighten the HUD brackets onto the figure instead of the whole column */
.hero-figure { padding: var(--s4) var(--s4) var(--s3); }

/* ==========================================================================
   CAPABILITY TRIPLET
   ========================================================================== */
.cap-head { display: flex; align-items: center; gap: var(--s4); margin: var(--s8) 0 var(--s4); }
.cap-head h2 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); font-weight: 400;
  letter-spacing: .16em; text-transform: uppercase; color: var(--resist-dim); white-space: nowrap; }
.cap-head hr { flex: 1; height: 1px; border: 0;
  background: linear-gradient(90deg, var(--indigo-400), transparent); }

.caps { display: grid; gap: 1px; background: var(--resist-line);
        border: 1px solid var(--resist-line); }
@media (min-width: 820px) { .caps { grid-template-columns: repeat(3, 1fr); } }
.cap { background: var(--indigo-900); padding: var(--s5); display: flex;
       flex-direction: column; gap: var(--s3); }
.cap svg { color: var(--indigo-200); }
/* Same tracking as every other heading; -.01em against -.02em elsewhere was a
   difference nobody could name and everybody could feel. */
.cap h3 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-7); letter-spacing: -.02em; }
.cap p { font-size: var(--fs-4); line-height: 1.6; color: var(--resist-soft); }
.cap a { display: inline-flex; align-items: center; gap: 6px; margin-top: auto;
  font-family: var(--face-data); font-size: var(--fs-4); color: var(--indigo-200);
  text-decoration: none; }
.cap a:hover { color: var(--resist); }
/* A capability whose action runs in-app (opens a live result) instead of
   navigating — a button styled exactly like the card's link so the row reads
   identically whether it routes or acts. */
.cap .cap-go { display: inline-flex; align-items: center; gap: 6px; margin-top: auto;
  font-family: var(--face-data); font-size: var(--fs-4); color: var(--indigo-200);
  background: none; border: 0; padding: 0; text-align: left; cursor: pointer; }
.cap .cap-go:hover { color: var(--resist); }

/* ---- the pie strip: cloth woven to a selvedge at 100% ---- */
.strip-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); margin-bottom: var(--s2); }
.strip-total { font-family: var(--face-data); font-size: var(--fs-6); }
.strip-total.is-short { color: var(--oxide-ink); }
.strip-total.is-over  { color: var(--kola-ink); }
.strip-total.is-done  { color: var(--vine-ink); }

.strip {
  position: relative; height: 46px; display: flex;
  border: 1px solid var(--resist-line); background: var(--indigo-900);
  overflow: hidden;
}
.strip .seg {
  height: 100%; position: relative; min-width: 0;
  border-right: 1px solid var(--vat);
  /* Deliberate exception to "never animate layout": the band resizing IS the
     signature mechanic, and transform:scaleX would squash the symbol label
     inside each segment. Bounded — at most a handful of segments, driven by
     discrete user input, and patched in place by livePatch() rather than
     rebuilt, so no layout thrash accumulates during a drag. */
  transition: width var(--dur-dip) var(--ease-vat), background var(--dur-dip) var(--ease-vat);
}
.strip .seg span {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .06em;
  color: inherit; overflow: hidden; white-space: nowrap;
}
/* the selvedge: the finished edge the cloth reaches at exactly 100% */
.selvedge {
  position: absolute; top: -3px; bottom: -3px; right: 0; width: 2px;
  background: var(--resist-dim);
  transition: background var(--dur-tap) var(--ease-vat);
}
.selvedge.is-done { background: var(--vine-ink); width: 3px; }
.selvedge.is-locking { animation: selvedge-lock 520ms var(--ease-vat); }
@keyframes selvedge-lock {
  0%   { transform: scaleY(.4); opacity: .3; }
  60%  { transform: scaleY(1.06); opacity: 1; }
  100% { transform: scaleY(1); opacity: 1; }
}
.strip-empty { display: grid; place-items: center; width: 100%;
               font-size: var(--fs-3); color: var(--resist-dim); letter-spacing: .04em; }

/* ---- constituent rows ---- */
.warp { border: 1px solid var(--resist-line); border-top: 0; }
.thread {
  display: grid; gap: var(--s3); align-items: center; padding: var(--s3);
  grid-template-columns: 1fr; border-bottom: 1px solid var(--resist-line);
  background: var(--indigo-900);
}
.thread:last-child { border-bottom: 0; }
@media (min-width: 620px) { .thread { grid-template-columns: 152px 1fr 96px 30px; } }
.thread .who { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.thread .who b { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-4); letter-spacing: .04em; }
.thread .who small { font-size: var(--fs-2); color: var(--resist-dim); }
.thread .wt { display: flex; align-items: center; gap: 6px; }
.thread .wt input[type="number"] { width: 66px; text-align: right; padding: 6px 8px; }
.thread .pull { color: var(--resist-dim); padding: 6px 8px; line-height: 1; font-size: var(--fs-6); }
.thread .pull:hover { color: var(--kola-ink); }

/* ---- the cutting rule: where coverage forces the window ---- */
.cutrule { border: 1px solid var(--resist-line); padding: var(--s4); background: var(--indigo-900); }
.cutrule .lede { font-size: var(--fs-4); line-height: 1.55; color: var(--resist-soft); }
.cutrule .lede b { color: var(--oxide-ink); font-weight: 600; }
.ruler { position: relative; height: 40px; margin: var(--s4) 0 var(--s2);
         border-left: 1px solid var(--resist-line-firm); border-right: 1px solid var(--resist-line-firm); }
.ruler .span {
  position: absolute; left: 0; right: 0; top: 15px; height: 3px;
  background: repeating-linear-gradient(90deg, var(--resist-line) 0 6px, transparent 6px 12px);
}
.ruler .live { position: absolute; top: 15px; height: 3px; background: var(--indigo-400);
               transition: left var(--dur-dip) var(--ease-vat), right var(--dur-dip) var(--ease-vat); }
.ruler .cut { position: absolute; top: 4px; bottom: 4px; width: 1px; background: var(--resist-line-firm); }
.ruler .cut.binding { background: var(--kola); width: 2px; top: 0; bottom: 0; }
.ruler .cut b { position: absolute; top: -3px; left: 5px; font-family: var(--face-stamp); font-weight: 700;
                font-size: var(--fs-1); letter-spacing: .08em; color: var(--kola-ink); white-space: nowrap;
                background: var(--indigo-900); padding: 1px 4px; }
.ruler-ends { display: flex; justify-content: space-between; font-family: var(--face-data);
              font-size: var(--fs-1); color: var(--resist-dim); }

.stakebox { border: 1px solid var(--resist-line); padding: var(--s4); background: var(--indigo-900); margin-top: var(--s4); }
.stakebox h3 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-5); letter-spacing: -.005em; margin-bottom: var(--s3); }
.stakegrid { display: grid; gap: var(--s3); }
@media (min-width: 520px) { .stakegrid { grid-template-columns: 1.4fr 1fr; } }
.stakegrid label { display: flex; flex-direction: column; gap: 5px; }
.stakegrid label > span { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
  letter-spacing: .12em; text-transform: uppercase; color: var(--resist-dim); }
.stakegrid input { text-align: right; }
.stakenote { margin-top: var(--s3); font-size: var(--fs-4); line-height: 1.55; color: var(--resist-soft); }

/* ---- window policy toggle ---- */
.policy { display: grid; gap: 1px; background: var(--resist-line); border: 1px solid var(--resist-line); margin-top: var(--s4); }
@media (min-width: 560px) { .policy { grid-template-columns: 1fr 1fr; } }
.policy button { background: var(--indigo-900); padding: var(--s3) var(--s4); text-align: left; display: flex; flex-direction: column; gap: 4px; }
.policy button:hover { background: var(--indigo-800); }
.policy button[aria-pressed="true"] { background: var(--indigo-600); }
.policy b { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-4); letter-spacing: -.005em; }
.policy small { font-size: var(--fs-3); line-height: 1.45; color: var(--resist-soft); }

.run-bar { display: flex; align-items: center; gap: var(--s3); margin-top: var(--s4); flex-wrap: wrap; }
.run-why { font-size: var(--fs-4); color: var(--oxide-ink); }

/* --------------------------------------------------------------------------
   RESULTS — decomposition is the hero
   -------------------------------------------------------------------------- */
.result-head { padding: var(--s6) 0 var(--s5); }
.ccy { display: inline-flex; border: 1px solid var(--resist-line-firm); }
.ccy button { padding: 6px 12px; font-family: var(--face-data); font-size: var(--fs-4); color: var(--resist-dim); }
.ccy button[aria-pressed="true"] { background: var(--indigo-300); color: var(--vat); font-weight: 600; }
.became { margin-top: var(--s4); display: flex; align-items: baseline; gap: var(--s4); flex-wrap: wrap; }
.became .arrow { color: var(--resist-dim); font-size: var(--fs-8); }
.fx-note { margin-top: var(--s2); font-size: var(--fs-3); color: var(--resist-dim); }

.rangebar { display: flex; gap: 4px; flex-wrap: wrap; margin-top: var(--s4); }
.range-btn { padding: 6px 13px; border: 1px solid var(--resist-line-firm); background: transparent;
  font-family: var(--face-data); font-size: var(--fs-4); color: var(--resist-soft);
  transition: background var(--dur-tap) var(--ease-vat), color var(--dur-tap) var(--ease-vat); }
.range-btn:hover:not(:disabled) { background: var(--indigo-700); color: var(--resist); }
.range-btn[aria-pressed="true"] { background: var(--indigo-300); border-color: var(--indigo-300); color: var(--vat); }
.range-btn:disabled { opacity: .38; cursor: not-allowed; }
.range-btn:not(:disabled):active { transform: translateY(1px); }
.range-note { margin-top: 6px; font-size: var(--fs-4); color: var(--resist-dim); }
/* --------------------------------------------------------------------------
   CUSTOM RANGE, OPENING AND CLOSING
   The panel collapses rather than vanishing, and the collapse is a real height
   change so everything below travels with it. Fading alone would have left the
   layout snapping shut at the end, which is the jump the fade was there to hide.

   The height is a grid track, not `height`, so this stays off the layout-
   animation path. But the track is pinned to a measured PIXEL value on the way
   out, never `1fr -> 0fr`. Measured here: `1fr` in an auto-height grid sizes
   from the item's min-content contribution, and the very properties that let an
   item collapse — `min-height:0`, `overflow:hidden` — drive that contribution to
   zero. The open panel rendered at 26px instead of 118px. Pinning to px first
   makes the start of the animation a fact rather than a resolution.

   Opening does not animate height on purpose. A disclosure appearing at full
   size when you ask for it is normal and reads as responsive; it was only the
   disappearing that felt abrupt.
   -------------------------------------------------------------------------- */
.custom-wrap { display: grid; grid-template-rows: auto; overflow: hidden; }
.custom-wrap > .custom-range { animation: custom-open var(--dur-dip) var(--ease-vat) both; }
@keyframes custom-open {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
/* JS pins grid-template-rows to the measured height, then adds this. */
.custom-wrap.is-closing {
  grid-template-rows: 0px;
  transition: grid-template-rows var(--dur-dip) var(--ease-vat);
}
.custom-wrap.is-closing > .custom-range {
  min-height: 0; overflow: hidden;
  opacity: 0; transform: translateY(-6px); animation: none;
  transition: opacity var(--dur-dip) var(--ease-vat),
              transform var(--dur-dip) var(--ease-vat);
}
@media (prefers-reduced-motion: reduce) {
  .custom-wrap > .custom-range { animation: none; }
  .custom-wrap.is-closing, .custom-wrap.is-closing > .custom-range { transition: none; }
}

.custom-range { position: relative; display: flex; gap: var(--s3); align-items: flex-end; flex-wrap: wrap;
  margin-top: var(--s3); padding: var(--s3); padding-right: var(--s6);
  border: 1px solid var(--resist-line); background: var(--indigo-900); }
.custom-range label { display: flex; flex-direction: column; gap: 4px; }
.custom-range label > span { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
  letter-spacing: .12em; text-transform: uppercase; color: var(--resist-dim); }
.custom-range .field { width: auto; }
.custom-range .range-note { width: 100%; margin: 0; }
/* Parked in the panel's own corner rather than in the control row, so it reads
   as dismissing the panel and never as a third date action. */
.custom-close {
  position: absolute; top: 6px; right: 6px;
  width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 1px solid transparent; color: var(--resist-dim);
  font-size: var(--fs-3); line-height: 1; cursor: pointer;
  transition: color var(--dur-tap) var(--ease-vat), border-color var(--dur-tap) var(--ease-vat);
}
.custom-close:hover, .custom-close:focus-visible {
  color: var(--resist); border-color: var(--resist-line-firm);
}

/* the woven decomposition band — the product's thesis, at full scale */
.weave { margin-top: var(--s6); }
.weave > h2 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-6);
              letter-spacing: -.005em; color: var(--resist); margin-bottom: var(--s3); }
.weave-band { display: flex; height: 84px; border: 1px solid var(--resist-line); background: var(--indigo-900); overflow: hidden; }
/* Widths are painted once when a result loads — no transition, nothing to tween. */
.weave-band .part { position: relative; min-width: 2px; }
.weave-band .part + .part { border-left: 1px solid var(--vat); }
.weave-keys { display: grid; gap: 1px; background: var(--resist-line); border: 1px solid var(--resist-line); border-top: 0; }
@media (min-width: 700px) { .weave-keys { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); } }
.weave-key { background: var(--indigo-900); padding: var(--s3); display: flex; flex-direction: column; gap: 5px; }
.weave-key .k { display: flex; align-items: center; gap: 7px; font-size: var(--fs-3); color: var(--resist-soft); }
.weave-key .chip { width: 10px; height: 10px; flex: none; }
.weave-key .v { font-family: var(--face-data); font-size: var(--fs-6); letter-spacing: -.02em; }
.weave-sum { margin-top: var(--s3); font-size: var(--fs-4); color: var(--resist-dim); }
/* The figure the cloth counts up to reads as data, in full cotton, so the eye
   catches it settling. Steps 4 in the ramp, so it sits with the sentence. */
.weave-total { font-family: var(--face-data); font-size: var(--fs-4);
               font-weight: 400; color: var(--resist); letter-spacing: -.01em; }

/* --- DIP THE CLOTH — the decomposition band entering the vat --------------- */
/* The band reveals left to right, the same clip-wipe the result band unrolls on,
   so both screens share one authored moment. Scoped to the portfolio variant:
   the result screen band has its own is-unrolling and must not double up. */
.pf-weave-band.is-dipping { animation: weave-dip 580ms var(--ease-vat) both; }
@keyframes weave-dip {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}
/* The legend rises a beat behind the cloth, key by key. `both` holds each key
   hidden through its delay, so nothing flashes before its turn. */
.pf-weave .weave-key.rise { animation: weave-key-rise 380ms var(--ease-vat) both;
                            animation-delay: var(--d, 0ms); }
@keyframes weave-key-rise {
  from { opacity: 0; transform: translateY(7px); }
  to   { opacity: 1; transform: none; }
}
/* Reduced motion asked for less: the band is simply present, the legend static,
   and the figure resolves flat in countValue — no dip, no rise, no count. */
@media (prefers-reduced-motion: reduce) {
  .pf-weave-band.is-dipping { animation: none; }
  .pf-weave .weave-key.rise { animation: none; opacity: 1; transform: none; }
}

/* growth curve */
.curve-wrap { margin-top: var(--s6); }
.curve-wrap h2 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-6);
                 letter-spacing: -.005em; color: var(--resist); margin-bottom: var(--s3); }
.curve { border: 1px solid var(--resist-line); background: var(--indigo-900); display: block; width: 100%; height: auto; }

/* stats */
.stats { display: grid; gap: 1px; background: var(--resist-line); border: 1px solid var(--resist-line); margin-top: var(--s6); }
@media (min-width: 560px) { .stats { grid-template-columns: 1fr 1fr; } }
@media (min-width: 900px) { .stats { grid-template-columns: repeat(4, 1fr); } }
.stat { background: var(--indigo-900); padding: var(--s4); display: flex; flex-direction: column; gap: 5px; }
.stat .v { font-family: var(--face-data); font-size: var(--fs-8); letter-spacing: -.03em; }

/* disclosures — visible, never buried in the receipt */
.disclosures { border: 1px solid var(--oxide); margin-top: var(--s6); }
.disclosures > h2 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-5);
                    letter-spacing: -.005em; color: var(--oxide-ink); padding: var(--s3) var(--s4);
                    border-bottom: 1px solid var(--resist-line); }
.disclosures ul { margin: 0; padding: var(--s3) var(--s4) var(--s4) calc(var(--s4) + 16px); }
.disclosures li { font-size: var(--fs-4); line-height: 1.6; color: var(--resist-soft); margin-bottom: 5px; }
.disclosures li b { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .08em; color: var(--oxide-ink); }

/* receipt */
.receipt { margin-top: var(--s6); border: 1px solid var(--resist-line); }
.receipt > summary {
  padding: var(--s4); cursor: pointer; list-style: none; display: flex;
  align-items: center; justify-content: space-between; gap: var(--s3);
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-5); letter-spacing: -.005em;
  background: var(--indigo-900);
}
.receipt > summary::-webkit-details-marker { display: none; }
.receipt > summary:hover { background: var(--indigo-800); }
.receipt[open] > summary { border-bottom: 1px solid var(--resist-line); }
.receipt-body { padding: var(--s4); background: var(--indigo-900); font-size: var(--fs-4); }
.receipt-row { display: grid; gap: var(--s2) var(--s4); padding: var(--s3) 0; border-bottom: 1px solid var(--resist-line-faint); }
@media (min-width: 720px) { .receipt-row { grid-template-columns: 190px 1fr; } }
.receipt-row:last-child { border-bottom: 0; }
.receipt-row dt { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .11em;
                  text-transform: uppercase; color: var(--resist-dim); }
.receipt-row dd { margin: 0; color: var(--resist-soft); line-height: 1.6; word-break: break-word; }
.receipt table { width: 100%; border-collapse: collapse; font-size: var(--fs-4); }
.receipt th { text-align: left; font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .1em;
              text-transform: uppercase; color: var(--resist-dim); padding: 6px 8px 6px 0;
              border-bottom: 1px solid var(--resist-line); }
.receipt td { padding: 7px 8px 7px 0; border-bottom: 1px solid var(--resist-line-faint); color: var(--resist-soft); }
.receipt td.num { font-family: var(--face-data); text-align: right; }
/* A numeric header must sit over its own column, not beside it: the values are
   right-aligned, so the label has to be too or the column reads as empty. */
.receipt th.num { text-align: right; }
.receipt th:first-child, .receipt td:first-child { width: 34%; }
.receipt th.num, .receipt td.num { width: 16%; white-space: nowrap; }

.hindsight { margin-top: var(--s5); padding: var(--s4); border: 1px solid var(--resist-line);
             color: var(--resist-soft); font-size: var(--fs-4); line-height: 1.6; background: var(--indigo-900); }

/* --------------------------------------------------------------------------
   STATES
   -------------------------------------------------------------------------- */
.notice { padding: var(--s4); border: 1px solid var(--kola); color: var(--resist);
          font-size: var(--fs-5); line-height: 1.6; background: rgba(192,75,51,.10); }
.loading { padding: var(--s8) 0; text-align: center; color: var(--resist-dim);
           font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-3); letter-spacing: .16em; text-transform: uppercase; }
.vat-fill { width: 108px; height: 3px; background: var(--indigo-700); margin: var(--s4) auto 0; overflow: hidden; }
.vat-fill i { display: block; height: 100%; width: 40%; background: var(--indigo-300); animation: soak 1.15s var(--ease-vat) infinite; }
@keyframes soak { 0% { transform: translateX(-100%); } 100% { transform: translateX(320%); } }

.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%);
  background: var(--indigo-500); border: 1px solid var(--indigo-200); color: var(--resist);
  padding: 10px var(--s4); font-size: var(--fs-4); z-index: 90;
  animation: dip-in 260ms var(--ease-vat) both;
}

/* drag feedback */
.cloth.is-dragging .swatch:not(.is-blocked) { outline: 1px dashed var(--resist-line); outline-offset: -3px; }
.drop-live { outline: 2px dashed var(--oxide); outline-offset: 3px; }


/* ==========================================================================
   MOTION
   Thesis: one authored moment, the currency re-dip. Everything else is
   feedback or continuity, and nothing makes the reader wait to read.
   ========================================================================== */

/* --- FOCAL MOMENT: re-translation ---------------------------------------
   Switching currency lifts every figure out of one vat and lowers it into the
   next. The figure desaturates and blurs a hair on the way out, then arrives
   sharp; it is the only place the interface animates a value rather than a
   state, because re-translation is the one thing the reader must notice. */
@keyframes redip {
  0%   { opacity: .55; filter: blur(3px); transform: translateY(-3px); }
  55%  { opacity: .9;  filter: blur(0);   transform: translateY(1px); }
  100% { opacity: 1;   filter: blur(0);   transform: none; }
}
/* Plays only on a currency change, never on every render: re-translation is
   the event worth noticing, and an entrance on each repaint would be noise. */
.is-redipping { animation: redip 320ms var(--ease-vat) both; }

/* --- LOAD: a list arriving as a list -------------------------------------
   Capped so the last item is never more than ~240ms behind the first: an
   Operate surface may not make anyone wait through choreography. */
.pie-index .pie-card, .pie-index .build-cta,
.cloth .swatch {
  animation: dip-in 300ms var(--ease-vat) both;
  animation-delay: calc(min(var(--i, 0), 11) * 20ms);
}

/* --- HOVER: one dye-depth step, plus the coverage line surfacing ---------- */
.swatch { transition: background var(--dur-tap) var(--ease-vat); }
.swatch:hover:not(.is-blocked) .cov { color: var(--oxide-ink); }
/* The deeper ground gives the SUPPORTING figures room to gain, so they are what
   respond to the dip: the currency codes and the second currency step up one
   level as the dye passes, on the dip's own clock so the colour arrives with the
   waterline rather than ahead of it.

   The headline figure deliberately does not move. It already sits at full
   cotton, the brightest ink in the system, so "brighten it on hover" can only be
   a no-op or a downgrade — the previous rule pushed it to indigo-100, which made
   the number dimmer the moment you pointed at it. Pigments are also out: gold
   means dividends everywhere in this product and would be lying here. */
.pie-card .ret-tag,
.pie-card .ret-alt,
.pie-card .sub { transition: color var(--dur-dip) var(--ease-vat); }
.pie-card:hover .ret-tag,
.pie-card:focus-visible .ret-tag { color: var(--resist-soft); }
.pie-card:hover .ret-alt,
.pie-card:focus-visible .ret-alt { color: var(--indigo-100); }
.pie-card:hover .sub,
.pie-card:focus-visible .sub { color: var(--resist-soft); }
.navlink { transition: color var(--dur-tap) var(--ease-vat), border-color var(--dur-tap) var(--ease-vat); }
.ccy button { transition: background var(--dur-tap) var(--ease-vat), color var(--dur-tap) var(--ease-vat); }
.ccy button:hover:not([aria-pressed="true"]) { background: var(--indigo-700); color: var(--resist); }
.thread { transition: background var(--dur-tap) var(--ease-vat); }
.thread:hover { background: var(--indigo-800); }

/* --- PRESS: exits faster than it enters ---------------------------------- */
.pie-card:active, .build-cta:active { transform: translateY(1px); }
.ccy button:active { transform: translateY(1px); }

@media (prefers-reduced-motion: reduce) {
  .pie-index .pie-card, .pie-index .build-cta, .cloth .swatch,
  .is-redipping { animation: none !important; }
  .is-redipping { opacity: 1; filter: none; }

  /* The dip keeps its meaning without its travel: the card still arrives at the
     deeper dye, it just gets there at once. Dropping the state entirely would
     leave these cards with no hover response at all, which is a worse answer
     than a still one. The waterline and the glint are pure travel, so they go. */
  .pie-card::before, .build-cta::before,
  .pie-card::after, .build-cta::after,
  .build-cta .go, .adire-bloom { transition: none !important; }
  .pie-card::after, .build-cta::after { display: none; }
  /* The cloth is still there, it just does not unroll or climb. */
  .adire-band.is-unrolling { animation: none !important; }
  .adire-bloom { clip-path: inset(0 0 0 0); opacity: .16; }
}

/* ==========================================================================
   SOURCE LEDGER
   The receipt for the DATA. Same register as the Backtest Receipt — resist
   hairlines, zero radius, mono for anything measured — but the served feed is
   struck in oxide so the one that produces the numbers is never in doubt.
   ========================================================================== */

/* The way in. Deliberately recessive: it must not compete with the tier seal,
   which is the answer most people want. It earns weight only on hover. */
.src-link {
  display: inline-block; margin-left: 8px; padding: 1px 5px;
  font-family: var(--face-data); font-size: var(--fs-1); letter-spacing: .06em;
  color: var(--resist-dim); background: none; border: 1px solid var(--resist-line);
  border-radius: 0; cursor: pointer;
  transition: color var(--dur-tap) var(--ease-vat),
              border-color var(--dur-tap) var(--ease-vat);
}
.src-link:hover, .src-link:focus-visible {
  color: var(--oxide-ink); border-color: var(--oxide-ink);
}

.ledger-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: var(--s5); padding: var(--s6) 0 var(--s5);
  border-bottom: 1px solid var(--resist-line-firm);
}
.ledger-head h1 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-9); margin: 4px 0 8px; }
.ledger-head .eyebrow {
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2);
  letter-spacing: .16em; color: var(--resist-dim);
}
.ledger-head .lede { color: var(--resist-soft); font-size: var(--fs-6); max-width: 60ch; }
.ledger-head .lede b { color: var(--oxide-ink); }

.src-card {
  margin-top: var(--s5); padding: var(--s4);
  border: 1px solid var(--resist-line);
  background: var(--indigo-900);
}
/* The served feed sits one dip deeper, with its left edge drawn as a firm resist
   rule. The earlier version used a 3px oxide border-left, which broke two rules
   at once: no coloured border above 1px exists in this system outside the
   selvedge, and gold is bound to dividends. Depth already says "this is the one
   in use", and the SERVED stamp says it in words. */
.src-card.is-served {
  background: var(--indigo-800);
  border-left: 1px solid var(--resist-line-firm);
}

.src-top { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.src-name { font-size: var(--fs-7); color: var(--resist); }
.src-flag {
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .12em;
  text-transform: uppercase; padding: 2px 6px;
  border: 1px solid var(--resist-line-firm); color: var(--resist-dim);
}
.src-flag.is-served { background: var(--oxide); color: var(--ink-on-oxide); border-color: var(--oxide); }

/* Price model carries its own colour because it is the dimension that decides
   whether a feed may be served at all — not a quality grade. */
.src-model {
  font-family: var(--face-data); font-size: var(--fs-1); padding: 2px 6px;
  border: 1px solid currentColor;
}
.src-model.is-raw      { color: var(--vine-ink); }
.src-model.is-adjusted { color: var(--kola-ink); }
.src-model.is-unknown  { color: var(--resist-dim); }

.src-reason {
  margin: var(--s2) 0 var(--s3); font-size: var(--fs-4);
  color: var(--resist-dim); max-width: 78ch;
}

.src-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px; background: var(--resist-line); border: 1px solid var(--resist-line);
}
.src-metric { background: var(--indigo-900); padding: var(--s3); }
.src-card.is-served .src-metric { background: var(--indigo-800); }
.m-label {
  display: block; font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
  letter-spacing: .14em; text-transform: uppercase; color: var(--resist-dim);
}
.m-value { display: block; font-size: var(--fs-5); color: var(--resist); margin: 5px 0 3px; }
.m-sub { display: block; font-size: var(--fs-1); color: var(--resist-dim); line-height: 1.4; }

.src-model-detail { margin-top: var(--s3); }
.src-model-detail summary {
  cursor: pointer; font-size: var(--fs-4); color: var(--resist-soft);
  padding: 6px 0; border-top: 1px solid var(--resist-line);
}
.src-model-detail p { font-size: var(--fs-4); color: var(--resist-dim); max-width: 78ch; margin: 6px 0; }
/* SIX COLOURED SIDE-BARS REMOVED (2-3px). DESIGN.md is explicit: borders are
   always 1px and always a resist tint, and the single filled 2-3px form in the
   system is the selvedge. A thick accent rail down one edge is also the most
   recognisable tell of generated UI, so the rule was earning its keep twice.
   Each is replaced with the vocabulary the system already owns: a 1px resist
   rule, a dye-depth change, or the pigment carried as a ground tint. */
.src-model-detail .evidence {
  font-size: var(--fs-3); color: var(--indigo-200);
  border-left: 1px solid var(--resist-line-firm); padding-left: var(--s3);
}

.src-agree { margin-top: var(--s4); }
.src-agree h4 {
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .14em;
  text-transform: uppercase; color: var(--resist-dim); margin: 0 0 var(--s2);
}
/* Wide tables scroll inside their own box; the page never scrolls sideways. */
.agree-tbl, .find-tbl { width: 100%; border-collapse: collapse; font-size: var(--fs-4); }
.src-agree, .src-findings { overflow-x: auto; }
.agree-tbl th, .find-tbl th {
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .12em;
  text-transform: uppercase; color: var(--resist-dim); text-align: left;
  padding: 6px 10px 6px 0; border-bottom: 1px solid var(--resist-line-firm); white-space: nowrap;
}
.agree-tbl th.num, .find-tbl th.num, .agree-tbl td.num { text-align: right; }
.agree-tbl td, .find-tbl td {
  padding: 7px 10px 7px 0; border-bottom: 1px solid var(--resist-line-faint);
  color: var(--resist-soft); vertical-align: top;
}
.agree-tbl td.num { font-family: var(--face-data); font-variant-numeric: tabular-nums; }
.agree-tbl td.num.is-flagged { color: var(--kola-ink); }

.src-findings { margin-top: var(--s6); }
.src-findings h3 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-7); margin: 0 0 4px; }
.find-tbl td.fine { max-width: 46ch; }

.rule-chip {
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .1em;
  text-transform: uppercase; padding: 2px 6px; border: 1px solid currentColor;
  white-space: nowrap; cursor: help;
}
.rule-chip.is-settled { color: var(--vine-ink); }
.rule-chip.is-open    { color: var(--oxide-ink); }

.fine { font-size: var(--fs-3); color: var(--resist-dim); line-height: 1.55; }
.muted { color: var(--resist-dim); }
.ledger-foot { margin: var(--s6) 0 var(--s7); max-width: 74ch; }

@media (max-width: 640px) {
  .ledger-head { flex-direction: column; }
  .src-grid { grid-template-columns: repeat(2, 1fr); }
}

/* A third feed's corroboration reads as a quoted witness, set apart from the
   arithmetic above it — the two are different kinds of claim. */
.witness {
  display: block; margin-top: 5px; padding-left: var(--s3);
  border-left: 1px solid var(--indigo-400);
  font-size: var(--fs-3); color: var(--indigo-200); line-height: 1.5;
}

/* ==========================================================================
   PORTFOLIO — Phase 5.A identity
   The key hand-off carries the weight here. It is the only moment the raw key
   exists on anything we control, so it gets a full screen and a kola-bordered
   statement of what losing it means, rather than a toast.
   ========================================================================== */
.pf-head { padding: var(--s6) 0 var(--s5); border-bottom: 1px solid var(--resist-line-firm); }
.pf-head h1 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-9);
              letter-spacing: -.02em; }
.pf-head .lede { margin-top: var(--s3); max-width: 62ch; color: var(--resist-soft);
                 font-size: var(--fs-6); line-height: 1.55; }

.pf-grid { display: grid; gap: 1px; background: var(--resist-line);
           border: 1px solid var(--resist-line); margin-top: var(--s5); }
@media (min-width: 780px) { .pf-grid { grid-template-columns: 1fr 1fr; } }

/* The portfolio page was five identical slabs of --indigo-900 at padding s5
   with zero margin between them: measured gaps were 0,0,0,0. They abutted into
   one undifferentiated wall, against the system's own rule of tight grouping
   inside a block and generous separation between blocks.

   Separated by a resist hairline rather than a shadow or a gap alone, because
   that is the material this system divides with everywhere else. */
.pf-panel { background: var(--indigo-900); padding: var(--s5); }
.pf-panel + .pf-panel { margin-top: var(--s6); }

/* ...but NOT when the panels are cells of the hairline grid.
   Inside .pf-grid the second panel is still an adjacent sibling, so it took the
   32px stacking margin INSIDE its own grid cell: measured tops were 284 and 316,
   headings 308 and 340. Two cards that should share a baseline sat a third of a
   heading apart, and the strip of --resist-line the margin uncovered read as a
   grey header band on the right card only.

   The 1px gap IS the separation here — that is what the hairline grid is for —
   so the stacking margin has nothing left to do. */
.pf-grid > .pf-panel + .pf-panel { margin-top: 0; }

/* A wide table must scroll INSIDE its panel, never drag the page sideways.
   Measured on a 375px viewport before this existed: the ledger table was 706px
   and the document scrolled to 755px, so the masthead, the headings and every
   disclosure slid off-screen together. The source-ledger screen already had the
   pattern; the portfolio simply never used it.

   overscroll-behaviour-x contains the gesture, so swiping a table to its end
   does not then start swiping the page. */
.tbl-scroll {
  overflow-x: auto;
  /* HORIZONTAL ONLY. `overflow-x: auto` with the default `overflow-y: visible`
     silently computes overflow-y to `auto` too (a CSS rule, not a bug), so the
     table drew a phantom vertical scrollbar over rows that already fit — the
     ledger shows a fixed, paginated set that is never meant to scroll down.
     Pinning overflow-y to `hidden` breaks that coupling; nothing clips, because
     the container sizes to its rows. */
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}
.tbl-scroll > table { min-width: 100%; }

/* The scroll affordance: a resist edge that appears only while the table
   actually overflows, so a narrow table shows nothing. */
@media (max-width: 720px) {
  .tbl-scroll { border-right: 1px solid var(--resist-line); }
}
.pf-grid > .pf-panel { min-height: 100%; }
/* Descendant, not child: the import panel's heading sits inside a flex row so
   it can share a line with its template link, and the child selector stopped
   matching it. It fell back to the browser default of 22.5px — the one size in
   the build that was not on the nine-step ramp. */
.pf-panel h2 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-7);
               letter-spacing: -.02em; margin-bottom: var(--s4); }
.pf-panel .row > h2 { margin-bottom: 0; }
.pf-panel .btn { margin-top: var(--s3); }
.pf-panel .fine { margin-top: var(--s3); max-width: 52ch; }
.pf-lab { display: flex; flex-direction: column; gap: 5px; margin-bottom: var(--s3); }
.pf-lab > span { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
                 letter-spacing: .12em; text-transform: uppercase; color: var(--resist-dim); }

.pf-key { display: grid; gap: var(--s5); margin-top: var(--s5); padding: var(--s5);
          border: 1px solid var(--resist-line); background: var(--indigo-900);
          align-items: start; }
@media (min-width: 720px) { .pf-key { grid-template-columns: minmax(0,1fr) auto; } }

/* The key is an identifier, so it takes the measurement face and breaks on any
   character: it has no words to keep whole, and a key that overflows its box is
   a key somebody transcribes wrong. */
.pf-code { display: block; margin-top: 6px; padding: var(--s3);
  font-family: var(--face-data); font-size: var(--fs-4); line-height: 1.6;
  color: var(--resist); background: var(--indigo-800);
  border: 1px solid var(--resist-line-firm);
  word-break: break-all; user-select: all; }

.pf-qr .qr { margin-top: 6px; padding: var(--s3); background: var(--indigo-800);
             border: 1px solid var(--resist-line-firm); line-height: 0; }
.pf-qr svg { display: block; width: 148px; height: 148px; }

/* --- 5.B entry + valuation ------------------------------------------------ */
.tx-form { display: grid; gap: var(--s3); margin-bottom: var(--s3); }
@media (min-width: 620px) { .tx-form { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* Advisory, not a refusal: kola marks the caution without the form ever
   blocking. A holder knows what they paid better than our feed does. */
.tx-flag {
  margin: 0 0 var(--s2); padding: var(--s2) var(--s3);
  border: 1px solid var(--kola); background: rgba(192, 75, 51, .10);
  font-size: var(--fs-4); line-height: 1.55; color: var(--resist-soft);
}

.pf-val { margin-top: var(--s5); }
.val-head { display: flex; justify-content: space-between; align-items: flex-start;
            gap: var(--s4); flex-wrap: wrap; margin-bottom: var(--s4); }
.val-big { display: block; font-family: var(--face-data); font-size: var(--fs-9);
           letter-spacing: -.03em; color: var(--resist); margin: 4px 0 3px; }
.div-toggle { display: inline-flex; align-items: center; gap: var(--s2);
              font-size: var(--fs-4); color: var(--resist-soft); cursor: pointer; }
.div-toggle input { accent-color: var(--oxide); }

/* The two measures get equal visual weight on purpose. Making one the headline
   would answer a question the reader did not ask. */
.ret-pair-grid { display: grid; gap: 1px; background: var(--resist-line);
  border: 1px solid var(--resist-line); margin-top: var(--s4); }
@media (min-width: 620px) { .ret-pair-grid { grid-template-columns: 1fr 1fr; } }
.ret-cell { background: var(--indigo-900); padding: var(--s4); }
.ret-cell .fine { margin-top: 6px; max-width: 46ch; }

.val-notes { margin: var(--s4) 0 0; padding-left: 18px; }
.val-notes li { font-size: var(--fs-4); color: var(--resist-dim);
                line-height: 1.55; margin-bottom: 5px; }

/* Gain and loss take the pigments already bound to those meanings. */
.agree-tbl td.num.is-up   { color: var(--vine-ink); }
.agree-tbl td.num.is-down { color: var(--kola-ink); }

/* --- ledger: heading + window count on one line, paged newest→oldest -------- */
/* The count is a measurement, so it takes the mono face and sits on the heading's
   baseline out at the right rather than dropping to a second line beneath it. */
.ledger-head-row { display: flex; align-items: baseline; gap: var(--s3);
                   flex-wrap: wrap; margin-bottom: var(--s4); }
.ledger-head-row h2 { margin-bottom: 0; }
.ledger-range { margin-left: auto; font-family: var(--face-data);
                font-size: var(--fs-4); letter-spacing: .01em;
                color: var(--resist-dim); white-space: nowrap; }

/* The pager reads as a stamped rule closing the table: one resist hairline above
   it, two hard-cut ghost controls, and the page marker in the same tabular voice
   as the count. Newer steps toward the top of the ledger, older toward the foot. */
.ledger-pager { display: flex; align-items: center; justify-content: center;
                gap: var(--s4); margin-top: var(--s4); padding-top: var(--s3);
                border-top: 1px solid var(--resist-line-faint); }
.lp-btn { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .1em;
          text-transform: uppercase; color: var(--indigo-100); background: none;
          cursor: pointer; border: 1px solid var(--resist-line-faint);
          padding: var(--s2) var(--s3);
          transition: color .12s ease, border-color .12s ease, background .12s ease; }
.lp-btn:hover:not(:disabled) { color: var(--resist); border-color: var(--resist-line);
          background: color-mix(in srgb, var(--indigo-700) 30%, transparent); }
.lp-btn:active:not(:disabled) { transform: translateY(1px); }
.lp-btn:focus-visible { outline: 2px solid var(--oxide); outline-offset: 2px; }
/* The documented disabled state: 42% opacity. The page marker beside it ("Page
   1 of 2") is the visible reason there is nothing newer to step to. */
.lp-btn:disabled { opacity: .42; cursor: not-allowed; }
.lp-at { font-family: var(--face-data); font-size: var(--fs-3); letter-spacing: .02em;
         color: var(--resist-dim); white-space: nowrap; }

/* --- 5.C the curve -------------------------------------------------------- */
/* Two hairlines and nothing else. The gap between them is the unrealised gain,
   so the chart says what the numbers say. No glow, no gradient, no area fill —
   that is the anti-reference this whole system is defined against. */
.pf-chart svg { display: block; width: 100%; height: auto; overflow: visible; }
.curve-value { stroke: var(--indigo-200); stroke-width: 1.6; }
.curve-cost  { stroke: var(--resist-dim); stroke-width: 1; stroke-dasharray: 3 3; }
/* Days we could not fully price are marked, never drawn as a dip that did not
   happen. Kola, because an absent price is a subtraction from what we can say. */
.pt-partial { stroke: var(--kola); stroke-width: 1; opacity: .45; }
.ax-mid { text-anchor: middle; }

.chart-key { display: flex; gap: var(--s4); flex-wrap: wrap; margin-top: var(--s3);
             font-size: var(--fs-3); color: var(--resist-dim); }
.chart-key span { display: inline-flex; align-items: center; gap: 6px; }
.chart-key i { width: 14px; height: 0; border-top: 2px solid currentColor; }
.chart-key .k-value { color: var(--indigo-200); }
.chart-key .k-cost { color: var(--resist-dim); border-top-style: dashed; }
.chart-key .k-partial { color: var(--kola-ink); }
/* A holding bought since the last snapshot: listed, because it IS held and the
   positions table below says so, but dimmed and dotted because one data point
   is not a line and a percentage drawn from it would be invented. */
.chart-key .k-toonew { opacity: 0.62; }
.chart-key .k-toonew .data { font-style: normal; letter-spacing: 0.02em; }

/* The entry panel doubles as the edit form; the oxide edge marks that the next
   save changes an existing row rather than appending one. */
.pf-panel.is-editing { background: var(--indigo-800);
                       outline: 1px solid var(--oxide); outline-offset: -1px; }

/* Stacked holdings. Flat fills, no gradient, no soft edge — each band is a dye
   depth and the boundary between two is the same hairline as every other
   division in the system. */
.pf-chart .band { stroke: var(--vat); stroke-width: 0.5; }
.chart-key .k-band { border: 0 !important; }

/* --- holdings chart: growth vs value ------------------------------------- */
.chart-modes { display: flex; gap: 1px; margin-bottom: var(--s3); }
.gline { stroke-width: 1.7; fill: none; stroke-linejoin: round; }
/* Where every holding started. A reference, not a series, so it stays a resist
   hairline rather than taking a series ink. */
.rebase-line { stroke: var(--resist-line-firm); stroke-width: 1; stroke-dasharray: 2 4; }
.chart-key .k-series { width: 16px; height: 0; border-top-width: 2px; }

/* What a ledger row will actually record, shown while it is typed. A mis-keyed
   unit count is invisible in a number field and unmistakable as a total. */
.tx-total {
  margin: 0 0 var(--s3); padding: var(--s2) var(--s3);
  border: 1px solid var(--resist-line); background: var(--indigo-800);
  font-family: var(--face-data); font-size: var(--fs-4); color: var(--resist-soft);
}
.tx-total:empty { display: none; }
/* Large but not refused: some holdings really are big, and blocking them would
   be worse than making them legible. Oxide is the system's "look here". */
.tx-total.is-large { border-left-color: var(--oxide); color: var(--oxide-ink); }


/* --------------------------------------------------------------------------
   5.D — CSV IMPORT
   The drop target is an undyed panel waiting to take dye: a resist hairline,
   nothing filled. It deepens on drag-over, which is the same grammar the rest
   of the cloth uses — depth of indigo is quantity, and here the quantity is
   "about to receive something".
   -------------------------------------------------------------------------- */
.imp-file { position: absolute; width: 1px; height: 1px; opacity: 0;
            overflow: hidden; clip-path: inset(50%); }

.imp-drop {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; padding: var(--s6) var(--s4); margin-top: var(--s3);
  border: 1px dashed var(--resist-dim); background: var(--indigo-800);
  cursor: pointer; text-align: center;
  transition: background 140ms linear, border-color 140ms linear;
}
.imp-drop:hover { background: var(--indigo-700); border-color: var(--resist); }
.imp-drop.is-over { background: var(--indigo-600); border-color: var(--indigo-300);
                    border-style: solid; }
.imp-drop .fine { margin: 0; }

.imp-paste-wrap { margin-top: var(--s3); }
.imp-paste-wrap > summary {
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .08em;
  text-transform: uppercase; color: var(--resist-dim); cursor: pointer;
  padding: var(--s2) 0;
}
.imp-paste-wrap > summary:hover { color: var(--resist); }
.imp-paste { width: 100%; font-family: var(--face-data); font-size: var(--fs-3);
             resize: vertical; margin-bottom: var(--s3); }

/* THEIR column on the left of the arrow, OURS as the label. The mapping is read
   downward as a list of our fields, because that is the set the reader has to
   satisfy — a grid keyed on their headers would change shape per broker. */
.imp-map {
  display: grid; gap: var(--s3) var(--s4); margin-top: var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
.imp-map .pf-lab { margin-bottom: 0; }
.imp-req { font-style: normal; color: var(--indigo-200); letter-spacing: .06em; }
.imp-pair.is-dupe > select { border-color: var(--kola-ink); }

.imp-warn, .imp-err {
  margin-top: var(--s3); padding: var(--s3); font-size: var(--fs-3);
  line-height: 1.6; border: 1px solid var(--kola-ink); color: var(--resist);
  background: rgba(192, 75, 51, .08);
}
.imp-alert { margin-top: var(--s4); }
.imp-posdate { gap: 8px; padding: 0 var(--s4) var(--s4); flex-wrap: wrap; }
.imp-posdate .field { width: auto; }

.imp-counts {
  margin-top: var(--s4); padding-top: var(--s3);
  border-top: 1px solid var(--resist-dim);
  font-size: var(--fs-4); color: var(--resist);
}
.imp-counts .is-bad { color: var(--kola-ink); }

/* Capped rather than endless: the reader is checking a sample, not auditing a
   spreadsheet, and the problem rows are pinned to the top of it. */
.imp-rows { max-height: 340px; overflow: auto; margin-top: var(--s3);
            border: 1px solid var(--resist-dim); }
.imp-rows thead th { position: sticky; top: 0; background: var(--indigo-900); z-index: 1; }
.imp-rows tr.is-bad > td { color: var(--kola-ink); background: rgba(192, 75, 51, .07); }
.imp-rows tr.is-bad > td.fine { color: var(--kola-ink); }

.imp-actions { gap: 8px; flex-wrap: wrap; margin-top: var(--s4); }

/* The settlement date, minimised. It read as a full grey "settles YYYY-MM-DD"
   under every row — a whole column of repeated noise. Now the trade date carries
   a quiet dotted underline, and the settlement floats in on hover or keyboard
   focus, positioned absolutely so the row never changes height. */
.agree-tbl td.tx-date { position: relative; cursor: help;
  text-decoration: underline dotted var(--resist-line-firm); text-underline-offset: 3px; }
.tx-settles { position: absolute; left: 0; top: calc(100% + 3px); z-index: 4;
  white-space: nowrap; font-family: var(--face-data); font-size: var(--fs-2);
  letter-spacing: .01em; color: var(--resist-dim); text-decoration: none;
  background: var(--indigo-800); border: 1px solid var(--resist-line);
  padding: var(--s1) var(--s2);
  opacity: 0; transform: translateY(-4px); pointer-events: none;
  transition: opacity var(--dur-tap) var(--ease-vat), transform var(--dur-tap) var(--ease-vat); }
.agree-tbl tr:hover .tx-settles,
.agree-tbl td.tx-date:focus-within .tx-settles { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .tx-settles { transition-timing-function: linear; transform: none; } }

/* A verdict that stays with the row. Kola only for a real finding — an
   unchecked price is an absence of evidence and takes the quiet resist grey, so
   the two never read as the same claim. */
.tx-mark { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
           letter-spacing: .06em; text-transform: uppercase;
           color: var(--resist-dim); white-space: nowrap; }
.tx-mark.is-off { color: var(--kola-ink); }
/* A passing check, stated. Muted and low-key — it reassures without competing
   with the warning marks, which are the ones that need the eye. */
.tx-mark.is-vwap { color: var(--resist-dim); opacity: .75; }

/* --------------------------------------------------------------------------
   CONTRACT NOTES — broker tag, reconcile preview, receipts
   The dye vocabulary carries the meaning: oxide (gold) names a broker, vine
   (green) is a clean add, kola (red) is a correction to make, dim is a nothing-
   to-do duplicate. Nothing leans on colour alone — every state also has a word.
   -------------------------------------------------------------------------- */

/* Broker tag on a ledger row */
.brk-tag { display: inline-block; margin-left: 8px; padding: 1px 7px;
           font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
           letter-spacing: .04em; border-radius: 0;
           color: var(--oxide-ink); border: 1px solid color-mix(in srgb, var(--oxide) 40%, transparent);
           background: color-mix(in srgb, var(--oxide) 12%, transparent);
           white-space: nowrap; vertical-align: baseline; }

/* Reconcile preview */
.note-loading { display: flex; flex-direction: column; gap: 4px; padding: 22px 4px; }
.note-head { display: flex; justify-content: space-between; align-items: baseline;
             gap: 12px; flex-wrap: wrap; padding-bottom: 10px;
             border-bottom: 1px solid var(--resist-line-faint); margin-bottom: 12px; }
.note-broker { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-3);
               color: var(--oxide-ink); letter-spacing: .02em; }
.note-tally { display: flex; gap: 6px; flex-wrap: wrap; }
.note-warn { color: var(--kola-ink); font-size: var(--fs-3); margin: 2px 0; }

.rc-chip { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
           padding: 2px 8px; border-radius: 0; letter-spacing: .04em;
           border: 1px solid var(--resist-line-faint); color: var(--resist-dim); }
.rc-chip.is-new { color: var(--vine-ink); border-color: color-mix(in srgb, var(--vine-ink) 40%, transparent); }
.rc-chip.is-rec { color: var(--kola-ink); border-color: color-mix(in srgb, var(--kola-ink) 40%, transparent); }
.rc-chip.is-tag { color: var(--oxide-ink); border-color: color-mix(in srgb, var(--oxide) 40%, transparent); }
.rc-chip.is-dup { color: var(--resist-dim); }

/* The reconcile list caps like the receipts drawer once it is long. */
.rc-scroll.is-capped { max-height: 340px; overflow-y: auto; padding-right: 4px; }
.rc-scroll.is-capped::-webkit-scrollbar { width: 6px; }
.rc-scroll.is-capped::-webkit-scrollbar-thumb { background: var(--resist-line); }

.rc-list { display: flex; flex-direction: column; gap: 2px; margin: 4px 0 2px; }
.rc-row { display: grid; align-items: center; gap: 10px; padding: 9px 10px;
          grid-template-columns: 22px 46px 1fr auto auto;
          border: 1px solid var(--resist-line-faint); border-radius: 0;
          background: color-mix(in srgb, var(--indigo-800) 30%, transparent);
          cursor: pointer; transition: border-color .12s ease, background .12s ease; }
.rc-row:hover { border-color: var(--resist-line); }
/* State is carried by the row's tag (its word + pigment ink below), never by a
   coloured side border: this system draws borders only as 1px resist rules, and a
   3px pigment edge is both the "side-tab" AI tell and a Pigment Rule breach. */
.rc-row.is-locked { opacity: .55; cursor: default;
                    background: color-mix(in srgb, var(--indigo-900) 40%, transparent); }
.rc-tick { width: 18px; height: 18px; accent-color: var(--oxide); }
.rc-tag { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .05em;
          text-transform: uppercase; color: var(--resist-dim); }
.rc-row.is-new .rc-tag { color: var(--vine-ink); }
.rc-row.is-reconcile .rc-tag { color: var(--kola-ink); }
.rc-row.is-tag .rc-tag { color: var(--oxide-ink); }
.rc-sym { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-3); color: var(--resist); }
.rc-line { color: var(--resist-soft); font-size: var(--fs-2); white-space: nowrap; }
.rc-date { color: var(--resist-dim); font-size: var(--fs-2); white-space: nowrap; }
.rc-diff { grid-column: 1 / -1; display: flex; gap: 14px; flex-wrap: wrap;
           padding-left: 78px; font-size: var(--fs-2); }
.rc-delta { color: var(--resist-dim); font-family: var(--face-data); }
.rc-delta s { color: var(--resist-dim); opacity: .7; text-decoration-color: var(--kola-ink); }
.rc-delta b { color: var(--vine-ink); font-weight: 400; }

/* Receipts — a fixed-height drawer, so three notes or thirty read the same */
.rcpt-wrap { margin-top: var(--s5); padding-top: var(--s4);
             border-top: 1px solid var(--resist-line-faint); }
.rcpt-head { display: flex; align-items: baseline; gap: var(--s2); margin: 0 0 var(--s3); }
.rcpt-title { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-3);
              color: var(--resist-soft); letter-spacing: .04em; margin: 0; }
.rcpt-count { font-family: var(--face-data); font-size: var(--fs-1);
              color: var(--oxide-ink); padding: 1px 7px; border-radius: 0;
              border: 1px solid color-mix(in srgb, var(--oxide) 34%, transparent);
              background: color-mix(in srgb, var(--oxide) 10%, transparent); }
.rcpt-recheck { margin-left: auto; font-family: var(--face-ui); font-size: var(--fs-2);
                color: var(--indigo-100); background: none; cursor: pointer;
                border: 1px solid var(--resist-line-faint); border-radius: 0;
                padding: 5px 11px; transition: border-color .12s ease, color .12s ease; }
.rcpt-recheck:hover { color: var(--resist); border-color: var(--resist-line); }
.rcpt-recheck:focus-visible { outline: 2px solid var(--oxide); outline-offset: 2px; }

/* The cap: ~4 rows tall, the rest scroll inside. A faint top/bottom fade hints
   there is more without a heavy scrollbar. */
.rcpt-scroll.is-capped { max-height: 216px; overflow-y: auto;
                         padding-right: 4px;
                         -webkit-mask-image: linear-gradient(to bottom,
                           transparent 0, #000 10px, #000 calc(100% - 10px), transparent 100%);
                         mask-image: linear-gradient(to bottom,
                           transparent 0, #000 10px, #000 calc(100% - 10px), transparent 100%); }
.rcpt-scroll.is-capped::-webkit-scrollbar { width: 6px; }
.rcpt-scroll.is-capped::-webkit-scrollbar-thumb {
  background: var(--resist-line); }

/* Broker group — a collapsible band; the summary is always visible, the notes
   fold away. One broker with thirty notes is one line until opened. */
.rcpt-group { border: 1px solid var(--resist-line-faint); border-radius: 0;
              background: color-mix(in srgb, var(--indigo-800) 22%, transparent);
              margin-bottom: var(--s2); overflow: hidden; }
.rcpt-group + .rcpt-group { margin-top: 0; }
.rcpt-sum { display: flex; align-items: center; gap: var(--s2); cursor: pointer;
            padding: var(--s2) var(--s3); list-style: none; user-select: none; }
.rcpt-sum::-webkit-details-marker { display: none; }
.rcpt-sum:hover { background: color-mix(in srgb, var(--indigo-700) 26%, transparent); }
.rcpt-sum:focus-visible { outline: 2px solid var(--oxide); outline-offset: -2px; }
.rcpt-chev { font-size: var(--fs-2); color: var(--resist-dim); flex: 0 0 auto;
             transition: transform .15s ease; transform: translateY(-1px); }
.rcpt-group[open] .rcpt-chev { transform: translateY(-1px) rotate(90deg); }
.rcpt-sum-meta { margin-left: auto; white-space: nowrap; }
.rcpt-brk { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
            letter-spacing: .03em; color: var(--oxide-ink); flex: 0 0 auto;
            padding: 1px 8px; border-radius: 0;
            border: 1px solid color-mix(in srgb, var(--oxide) 30%, transparent);
            background: color-mix(in srgb, var(--oxide) 8%, transparent); }

/* Notes inside a group — compact single lines, divided rather than boxed. */
.rcpt-group .rcpt-scroll { padding: 0 6px 6px; }
.rcpt-list { list-style: none; margin: 0; padding: 0; display: flex;
             flex-direction: column; }
.rcpt-item { display: flex; align-items: center; gap: 10px; padding: 6px 5px;
             border-top: 1px solid var(--resist-line-faint); min-width: 0; }
.rcpt-item:first-child { border-top: none; }
.rcpt-dl { display: grid; place-items: center; width: 30px; height: 30px;
           flex: 0 0 auto; border-radius: 0; text-decoration: none;
           color: var(--oxide-ink);
           border: 1px solid color-mix(in srgb, var(--oxide) 30%, transparent);
           background: color-mix(in srgb, var(--oxide) 9%, transparent);
           transition: background .12s ease, transform .12s ease; }
.rcpt-dl:hover { background: color-mix(in srgb, var(--oxide) 22%, transparent);
                 transform: translateY(-1px); }
.rcpt-dl:focus-visible { outline: 2px solid var(--oxide); outline-offset: 2px; }
.rcpt-ico { font-size: var(--fs-6); line-height: 1; }
.rcpt-name { color: var(--resist); font-size: var(--fs-2); flex: 1 1 auto;
             min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rcpt-sub { flex: 0 0 auto; white-space: nowrap; color: var(--resist-dim); }

@media (max-width: 560px) {
  .rc-row { grid-template-columns: 20px 40px 1fr; row-gap: 4px; }
  .rc-date { grid-column: 2 / -1; }
  .rc-diff { padding-left: 30px; }
}
@media (prefers-reduced-motion: reduce) {
  .rc-row, .rcpt-dl { transition: none; }
}

/* --------------------------------------------------------------------------
   TOUCH TARGETS
   Measured on the portfolio screen: 30 controls under 44px, including every
   range button at 32px and every small button at 34px. PRODUCT.md weights
   desktop and mobile equally, and a 32px control is a miss on a phone.

   Gated on a coarse pointer OR a phone-width viewport, so the desktop density
   the data screens depend on is untouched — a mouse does not need a 44px range
   button, and enlarging them everywhere would push the range bar onto two rows
   at 1280px. The viewport half of the test is not redundant: a desktop browser
   at 375px reports `pointer: fine`, so the coarse query alone is unverifiable in
   development and silently untested.
   -------------------------------------------------------------------------- */
@media (pointer: coarse), (max-width: 560px) {
  .btn, .btn-sm, .range-btn, .src-link, .pull,
  .chart-modes button, .imp-actions button, .lp-btn,
  .rcpt-sum, .rcpt-recheck {
    min-height: 44px;
  }
  /* The summary is a row, so centre its content once it is taller than its text. */
  .rcpt-sum { align-items: center; }
  /* The download control is an icon square; grow the whole target, not the glyph. */
  .rcpt-dl { width: 44px; height: 44px; }
  .btn-sm { padding-inline: var(--s3); }
  .range-btn { padding: 0 var(--s4); }
  /* Inline row actions in the ledger keep their type size but gain the target;
     they sit in a 4px-gap row, so widen the hit area rather than the glyph. */
  .agree-tbl .src-link, .agree-tbl .pull { min-width: 44px; }
  .field, select.field, input.field { min-height: 44px; }
  /* The label IS the target: a 13px checkbox is unhittable, and the whole
     "Include dividends" phrase is already clickable. Give the pair the height
     and enlarge the box itself, rather than leaving a 13px hotspot beside
     text that happens to work. */
  .div-toggle { min-height: 44px; }
  .div-toggle input { width: 20px; height: 20px; }
}

/* --------------------------------------------------------------------------
   THE SELVEDGE EDGE — dividing the portfolio's two jobs
   Above it: what the holding is. Below it: how the record is kept. They were
   five identical panels in one run, and a reader had no way to tell where one
   job ended.

   Named for the finished edge of woven cloth, which is already this system's
   word for "this region is complete" on the allocation strip. The rule is drawn
   in resist, like every other division here, and the label is stamped on it the
   way a pattern name is printed on a selvedge.
   -------------------------------------------------------------------------- */
.zone-edge {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s2) var(--s4);
  margin-top: var(--s8); padding-top: var(--s4);
  border-top: 1px solid var(--resist-line-firm);
}
.zone-edge + .pf-panel { margin-top: var(--s5); }
.zone-label {
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .14em;
  text-transform: uppercase; color: var(--resist);
}
.zone-note { font-size: var(--fs-4); color: var(--resist-dim); max-width: 52ch; }

/* --------------------------------------------------------------------------
   THE PORTFOLIO DECOMPOSITION BAND
   Same component as the result band, same semantic tokens, so a gold segment
   means dividends on both screens.
   -------------------------------------------------------------------------- */
.pf-weave { margin-top: var(--s5); }
.pf-weave-band { height: 56px; }
.pf-weave .fee-note { color: var(--kola-ink); }

/* THE AUTHORED MOMENT.
   Dye rising through cloth: the band wipes upward once, on arrival. One moment
   on this screen, not an entrance on every panel.

   clip-path, not height or scaleY: height would animate layout, and scaleY
   would squash the segment fills as they grew. The wipe rides a mask, so the
   bands beneath are already at their final size and nothing reflows.

   The result band deliberately paints its widths with no transition, and that
   still holds — this animates the REVEAL, never the values. A width that tweens
   is a number the reader watches change, which is a different and worse thing. */
@keyframes dye-rise { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }
.pf-weave-band { animation: dye-rise var(--dur-dip) var(--ease-vat) both; }
.pf-weave .weave-key { animation: key-settle var(--dur-tap) var(--ease-vat) both; }
@keyframes key-settle { from { opacity: 0; } to { opacity: 1; } }
.pf-weave .weave-key:nth-child(1) { animation-delay: 260ms; }
.pf-weave .weave-key:nth-child(2) { animation-delay: 320ms; }
.pf-weave .weave-key:nth-child(3) { animation-delay: 380ms; }
.pf-weave .weave-key:nth-child(4) { animation-delay: 440ms; }

/* A user who asked for less motion gets the finished cloth, not a slower wipe. */
@media (prefers-reduced-motion: reduce) {
  .pf-weave-band, .pf-weave .weave-key { animation: none; }
}

/* --------------------------------------------------------------------------
   THE NOTES, GIVEN ROLES
   `.fine` was carrying five unrelated jobs — prose paragraphs, table cells,
   captions — and its base rule set no measure at all. Only the contextual
   overrides capped it, so any note NOT inside a panel ran the full container:
   59ch on a phone, but the whole 1169px on a desktop, against the 62ch the
   type system specifies.

   Capped at the source. Table cells opt out, because a cell's width is set by
   its column and a max-width there fights the table.
   -------------------------------------------------------------------------- */
.fine { max-width: 62ch; }
td.fine, .fine.data, span.fine { max-width: none; }

/* A footnote sits under what it explains, close enough to belong to it. */
.ret-why { margin-top: var(--s3); }

/* Caveats — the only lines here that can ask the reader to DO something, so
   they take the same oxide treatment the result screen gives its disclosures
   rather than dissolving into the surrounding grey. */
.val-caveats { margin-top: var(--s5); border: 1px solid var(--oxide); }
.val-caveats > h3 {
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .12em;
  text-transform: uppercase; color: var(--oxide-ink);
  padding: var(--s3) var(--s4); border-bottom: 1px solid var(--resist-line);
}
.val-caveats ul { margin: 0; padding: var(--s3) var(--s4) var(--s4) calc(var(--s4) + 16px); }
.val-caveats li {
  font-size: var(--fs-4); line-height: 1.6; color: var(--resist-soft);
  max-width: 62ch; margin-bottom: 6px;
}
.val-caveats li:last-child { margin-bottom: 0; }

/* Provenance is the quietest thing on the screen: a stamped label and a line,
   reading as a footer rather than another sentence in the argument. */
.val-provenance {
  display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3); align-items: baseline;
  margin-top: var(--s5); padding-top: var(--s3);
  border-top: 1px solid var(--resist-line-faint);
  font-size: var(--fs-3); color: var(--resist-dim); line-height: 1.55;
}
.val-provenance > span:last-child { max-width: 62ch; }

/* The band's keys absorbed the sub-labels from the four cells that used to
   restate them, so a key now reads label / figure / what it means. */
.pf-weave .weave-key .m-sub {
  font-size: var(--fs-2); color: var(--resist-dim); line-height: 1.4;
}

/* --------------------------------------------------------------------------
   AUTH — passwordless sign-in (Stage 1)
   -------------------------------------------------------------------------- */
.auth-screen { max-width: 34rem; margin: var(--s7) auto 0; }
.auth-h { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-9);
          letter-spacing: -.02em; }
.auth-lede { margin-top: var(--s3); max-width: 60ch; color: var(--resist-soft);
             font-size: var(--fs-6); line-height: 1.55; }
.auth-err { margin-top: var(--s4); padding: var(--s2) var(--s3);
            border: 1px solid var(--kola); background: rgba(192, 75, 51, .10);
            color: var(--resist-soft); font-size: var(--fs-4); line-height: 1.5; }
.auth-form { margin-top: var(--s5); display: flex; flex-direction: column;
             gap: var(--s3); align-items: flex-start; }
.auth-form .pf-lab { width: 100%; max-width: 22rem; }
.auth-form .field { width: 100%; }
.auth-sent { margin-top: var(--s5); padding: var(--s4);
             border: 1px solid var(--vine-ink);
             background: color-mix(in srgb, var(--vine) 10%, transparent);
             color: var(--resist); font-size: var(--fs-6); line-height: 1.5; }
.auth-sent .fine { margin-top: var(--s2); color: var(--resist-dim); }
.auth-meta { margin-top: var(--s5); display: grid; gap: 1px;
             background: var(--resist-line); border: 1px solid var(--resist-line); }
.auth-meta > div { background: var(--indigo-900); padding: var(--s3) var(--s4);
                   display: flex; justify-content: space-between; align-items: baseline;
                   gap: var(--s4); }
.auth-meta dt { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .12em;
                text-transform: uppercase; color: var(--resist-dim); }
.auth-meta dd { font-size: var(--fs-5); color: var(--resist); }
.auth-screen > .btn { margin-top: var(--s5); }

/* Account screen — handle + claimed portfolios (Stage 1) */
.acct-block { margin-top: var(--s6); }
.acct-h { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-7);
          letter-spacing: -.02em; margin-bottom: var(--s3); }
.acct-block > .fine { max-width: 60ch; }
.acct-inline-form { margin-top: var(--s3); display: flex; gap: var(--s2);
                    align-items: stretch; max-width: 26rem; flex-wrap: wrap; }
.acct-inline-form .field { flex: 1 1 12rem; }
.acct-pf-list { list-style: none; margin: var(--s3) 0 0; padding: 0; display: grid;
                gap: 1px; background: var(--resist-line); border: 1px solid var(--resist-line); }
.acct-pf { background: var(--indigo-900); padding: var(--s3) var(--s4); display: flex;
           justify-content: space-between; align-items: center; gap: var(--s4); }
.acct-pf-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.acct-pf-away { color: var(--resist-dim); white-space: nowrap; }

/* Policy pages (Stage 1) */
.policy-screen { max-width: 62ch; margin: var(--s6) auto var(--s8); }
.policy-screen h1 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-9);
                    letter-spacing: -.02em; margin: var(--s5) 0 var(--s3); }
.policy-screen h2 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-7);
                    letter-spacing: -.02em; margin: var(--s6) 0 var(--s2); }
.policy-screen h3 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-3); letter-spacing: .04em;
                    margin: var(--s5) 0 var(--s2); color: var(--resist); }
.policy-screen p { color: var(--resist-soft); line-height: 1.6; margin: var(--s3) 0; }
.policy-screen ul { margin: var(--s3) 0; padding-left: var(--s4); color: var(--resist-soft);
                    line-height: 1.6; }
.policy-screen li { margin: 4px 0; }
.policy-screen a { color: var(--indigo-200); }
.policy-screen hr { border: 0; border-top: 1px solid var(--resist-line); margin: var(--s5) 0; }
.policy-screen blockquote { margin: var(--s4) 0; padding: var(--s2) var(--s4);
                            border-left: 1px solid var(--resist-line-firm);
                            color: var(--resist-dim); font-size: var(--fs-5); line-height: 1.55; }
.policy-screen code { font-family: var(--face-data); font-size: .9em; color: var(--resist); }
.policy-screen .tbl-scroll { margin: var(--s4) 0; }
.policy-meta { margin-bottom: var(--s4); color: var(--resist-dim); }

.policy-links { margin-top: var(--s4); display: flex; gap: var(--s4); flex-wrap: wrap; }
.policy-links a { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .1em;
                  text-transform: uppercase; color: var(--resist-dim); text-decoration: none; }
.policy-links a:hover { color: var(--resist); }

/* Account danger zone */
.acct-danger-row { margin-top: var(--s3); display: flex; gap: var(--s2); flex-wrap: wrap; }
.btn-danger { color: var(--kola-ink);
              border-color: color-mix(in srgb, var(--kola) 45%, transparent); }
.btn-danger:hover { background: color-mix(in srgb, var(--kola) 14%, transparent);
                    border-color: var(--kola-ink); }

/* ============================================================ STAGE 2 — pies */

/* Your-pies list on the account screen */
.acct-pie-list { list-style: none; margin: var(--s3) 0 0; padding: 0; display: grid;
                 gap: 1px; background: var(--resist-line); border: 1px solid var(--resist-line); }
.acct-pie { background: var(--indigo-900); padding: var(--s3) var(--s4); display: flex;
            justify-content: space-between; align-items: center; gap: var(--s4); }
.acct-pie-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.acct-pie-main b { font-size: var(--fs-5); color: var(--resist); }

/* Builder: save / edit affordances */
.run-signin { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .1em;
              text-transform: uppercase; color: var(--resist-dim); text-decoration: none;
              border-bottom: 1px solid var(--resist-line-firm); padding-bottom: 2px; }
.run-signin:hover { color: var(--resist); }
.pie-edit-bar { display: flex; align-items: baseline; gap: var(--s2); flex-wrap: wrap;
                margin-top: var(--s4); padding: var(--s2) var(--s3);
                border: 1px solid var(--resist-line-firm); background: var(--indigo-800); }
.pie-edit-tag { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .12em;
                text-transform: uppercase; color: var(--indigo-200); }
.pie-edit-bar b { color: var(--resist); font-size: var(--fs-5); }
.pie-edit-bar .fine { color: var(--resist-dim); }
.pie-edit-stop { margin-left: auto; background: none; border: 0; cursor: pointer;
                 font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .1em;
                 text-transform: uppercase; color: var(--resist-dim);
                 border-bottom: 1px solid var(--resist-line); padding-bottom: 2px; }
.pie-edit-stop:hover { color: var(--kola-ink); border-color: var(--kola-ink); }
.save-pie-form { width: 100%; margin-top: var(--s2); }
.save-pie-row { display: flex; gap: var(--s2); align-items: stretch; flex-wrap: wrap; }
.save-pie-row .field { flex: 1 1 12rem; min-width: 0; }
.save-pie-cancel { background: none; border: 0; cursor: pointer; padding: 0 var(--s2);
                   font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .1em;
                   text-transform: uppercase; color: var(--resist-dim); }
.save-pie-cancel:hover { color: var(--resist); }

/* Pie page */
.pie-screen { max-width: 52rem; margin: var(--s6) auto var(--s8); }
.pie-head { padding-bottom: var(--s3); border-bottom: 1px solid var(--resist-line); }
.pie-title { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-9);
             letter-spacing: -.025em; color: var(--resist); }
.pie-byline { margin-top: var(--s2); color: var(--resist-dim); font-size: var(--fs-4);
              display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.pie-vis { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .11em;
           text-transform: uppercase; color: var(--resist-dim);
           border: 1px solid var(--resist-line-firm); padding: 1px var(--s2); }
.pie-vis.is-public { color: var(--vine-ink); border-color: var(--vine-ink); }
.pie-desc { margin-top: var(--s3); color: var(--resist-soft); font-size: var(--fs-6);
            line-height: 1.5; }
.pie-redirect { margin-top: var(--s3); color: var(--resist-dim); }
.pie-redirect a { color: var(--indigo-200); }

.pie-banner { margin-top: var(--s4); padding: var(--s2) var(--s3);
              border: 1px solid var(--resist-line-firm); background: var(--indigo-800);
              display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
              font-family: var(--face-data); font-size: var(--fs-4); color: var(--resist-soft); }
.pie-banner-sep { color: var(--resist-dim); }
.pie-banner-state { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .1em;
                    text-transform: uppercase; color: var(--oxide-ink);
                    border: 1px solid var(--oxide-ink); padding: 0 var(--s2); }
.pie-latest { margin-left: auto; background: none; border: 0; cursor: pointer;
              font-family: var(--face-ui); font-size: var(--fs-4); color: var(--indigo-200); }
.pie-latest:hover { color: var(--resist); }

.pie-journal { margin-top: var(--s5); display: grid; gap: var(--s4); }
.pie-journal-block h3, .pie-holdings h3, .pie-assump h3, .pie-diff h3, .pie-versions h3 {
  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .09em;
  text-transform: uppercase; color: var(--resist-dim); margin-bottom: var(--s2); }
.pie-journal-block p { color: var(--resist-soft); font-size: var(--fs-6); line-height: 1.55; }

.pie-holdings { margin-top: var(--s5); }
.strip.is-ro { cursor: default; }
.pie-hold-list { list-style: none; margin: var(--s3) 0 0; padding: 0; display: grid;
                 gap: 1px; background: var(--resist-line); border: 1px solid var(--resist-line); }
.pie-hold { background: var(--indigo-900); padding: var(--s2) var(--s4); display: flex;
            justify-content: space-between; align-items: baseline; gap: var(--s4); }
.pie-hold-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pie-hold-who b { font-size: var(--fs-5); color: var(--resist); }
.pie-hold-who small { color: var(--resist-dim); font-size: var(--fs-3); }
.pie-hold-wt { font-size: var(--fs-6); color: var(--resist); }
.ca-warn-inline { display: inline-flex; align-items: center; gap: 4px; color: var(--kola-ink);
                  font-size: var(--fs-2); }

.pie-assump { margin-top: var(--s5); }
.pie-assump ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.pie-assump li { color: var(--resist-dim); }

.pie-diff { margin-top: var(--s5); }
.pie-diff-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px;
                 font-family: var(--face-data); font-size: var(--fs-4); }
.diff-add { color: var(--vine-ink); }
.diff-rm { color: var(--kola-ink); }
.diff-wt { color: var(--resist-soft); }

.pie-versions { margin-top: var(--s5); }
.pie-ver-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px;
                background: var(--resist-line); border: 1px solid var(--resist-line); }
.pie-ver { background: var(--indigo-900); }
.pie-ver.is-here { background: var(--indigo-800); }
.pie-ver-link { width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
                padding: var(--s2) var(--s4); display: flex; align-items: baseline; gap: var(--s3);
                color: var(--resist); }
.pie-ver-link:disabled { cursor: default; }
.pie-ver-link:not(:disabled):hover { background: var(--indigo-700); }
.pie-ver-link b { font-family: var(--face-data); font-size: var(--fs-5); }
.pie-ver-link .fine { color: var(--resist-dim); }

.pie-owner { margin-top: var(--s6); padding-top: var(--s4);
             border-top: 1px solid var(--resist-line); display: flex; gap: var(--s3);
             flex-wrap: wrap; align-items: center; }
.pie-owner .save-pie-form { flex-basis: 100%; }

/* ==================================================== COCKPIT RESTRUCTURE === */

/* @handle dropdown in the masthead */
.masthead nav { align-items: center; }
.handle-menu { position: relative; }
.handle-summary { display: inline-block; padding: 7px var(--s3); cursor: pointer;
                  font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .13em;
                  text-transform: uppercase; color: var(--resist-dim);
                  border: 1px solid transparent; list-style: none; user-select: none;
                  transition: color var(--dur-tap) var(--ease-vat), border-color var(--dur-tap) var(--ease-vat); }
.handle-summary::-webkit-details-marker { display: none; }
.handle-summary::marker { content: ""; }
.handle-summary:hover { color: var(--resist); border-color: var(--resist-line); }
.handle-menu[open] > .handle-summary { color: var(--resist); border-color: var(--resist-line-firm);
                                       background: var(--indigo-800); }
.handle-panel { position: absolute; right: 0; top: calc(100% + 4px); z-index: 40;
                min-width: 11rem; display: flex; flex-direction: column;
                background: var(--indigo-900); border: 1px solid var(--resist-line-firm); }
.handle-item { display: block; width: 100%; text-align: left; background: none; border: 0;
               cursor: pointer; padding: var(--s2) var(--s4); font-family: var(--face-ui);
               font-size: var(--fs-4); color: var(--resist-soft); text-decoration: none; }
.handle-item + .handle-item { border-top: 1px solid var(--resist-line); }
.handle-item:hover { background: var(--indigo-800); color: var(--resist); }

/* Sign-in gate note */
.auth-note { margin-top: var(--s4); padding: var(--s2) var(--s3);
             border: 1px solid var(--resist-line-firm); background: var(--indigo-800);
             color: var(--resist-soft); font-size: var(--fs-4); line-height: 1.5; }

/* Cockpit — the signed-in home */
/* ── The Cockpit HUD console ──────────────────────────────────────────────
   One framed console instead of stacked blocks. The frame is drawn only in
   resist hairlines + corner brackets (no glow, no radius, no shadow — Flat
   Cloth), depth carried by the vat ground shifting under each region. */
/* Fills the page container (#view is .wrap, max 1320px) the same way the portfolio
   page does — no second, narrower cap. The console then spreads full width, and the
   ledger columns inside it use that width instead of leaving a dead middle. */
.cockpit { margin: var(--s6) 0 var(--s8); }

.hud-console { position: relative; overflow: hidden;
               padding: calc(var(--s6) + 16px) var(--s6) var(--s5);
               border: 1px solid var(--resist-line-firm); background: var(--indigo-900); }
@media (max-width: 560px) { .hud-console { padding: calc(var(--s5) + 14px) var(--s4) var(--s4); } }

/* Top measure-rule — a sighted ruler stamped inside the frame's top edge, taller
   every fifth tick. Authored hairline linework, non-scaling so it stays crisp at
   any width (the 4K-crisp tell), never a machine grid over the ground. */
/* An SVG is a REPLACED element: left+right+width:auto is over-constrained, so it
   falls back to intrinsic width and stops part-way. A definite width makes it span
   the frame; preserveAspectRatio="none" then stretches the ticks edge to edge. */
.hud-measure { position: absolute; top: 9px; left: 14px; width: calc(100% - 28px); height: 16px;
               display: block; pointer-events: none; }
.hud-measure line { vector-effect: non-scaling-stroke; }
.hud-measure-base { stroke: var(--resist-line); }
.hud-measure-t { stroke: var(--resist-soft); }
.hud-measure-s { stroke: var(--resist-line-faint); }
@media (max-width: 560px) { .hud-measure { top: 8px; height: 12px; } }

/* Boot sweep — a single bright resist hairline that scans down the console once
   on load. A 1px bar, never a veil over type, so it never drops text contrast
   (the Contrast-Safe Motion Rule). Idle by default; only the boot class runs it. */
.hud-scan { position: absolute; left: 0; right: 0; top: 0; height: 2px; opacity: 0;
            pointer-events: none;
            background: linear-gradient(to right, transparent, rgba(244,239,227,.75) 50%, transparent); }
.hud-booting .hud-scan { animation: hud-sweep 760ms var(--ease-vat) forwards; }
@keyframes hud-sweep { 0% { opacity: 0; top: 0; } 10% { opacity: .9; } 90% { opacity: .9; }
                       100% { opacity: 0; top: 100%; } }

/* Corners sight in on boot — a quick converge, staggered a beat per corner. */
.hud-booting .hud-corner { animation: hud-sight 440ms var(--ease-vat) both; }
.hud-booting .hud-tr { animation-delay: 60ms; }
.hud-booting .hud-bl { animation-delay: 120ms; }
.hud-booting .hud-br { animation-delay: 180ms; }
@keyframes hud-sight { from { opacity: 0; transform: scale(1.7); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .hud-scan { display: none; }
  .hud-booting .hud-corner { animation: none; }
}

/* Corner brackets — two 1px arms per corner, pushed a hair outside the frame so
   the console reads as sighted-in, not merely bordered. */
.hud-corner { position: absolute; width: 14px; height: 14px; pointer-events: none; }
.hud-corner::before, .hud-corner::after { content: ""; position: absolute; background: var(--resist); }
.hud-corner::before { width: 14px; height: 1px; }
.hud-corner::after  { width: 1px; height: 14px; }
.hud-tl { top: -1px; left: -1px; }
.hud-tr { top: -1px; right: -1px; }
.hud-bl { bottom: -1px; left: -1px; }
.hud-br { bottom: -1px; right: -1px; }
.hud-tl::before, .hud-tl::after { top: 0; left: 0; }
.hud-tr::before { top: 0; right: 0; } .hud-tr::after { top: 0; right: 0; }
.hud-bl::before { bottom: 0; left: 0; } .hud-bl::after { bottom: 0; left: 0; }
.hud-br::before { bottom: 0; right: 0; } .hud-br::after { bottom: 0; right: 0; }

/* Authored adire selvedge — a faint woven edge down the right gutter, clear of
   the toolbar and the rows' controls. */
.adire-register { position: absolute; top: 96px; right: 16px; width: 40px; height: 340px;
                  opacity: .07; pointer-events: none; }
.adire-register path { stroke: var(--resist); stroke-width: 1.4; stroke-linecap: round; fill: none; }
.adire-register circle { fill: var(--resist); }
@media (max-width: 700px) { .adire-register { display: none; } }

/* Head: identity + consolidated toolbar on one line. */
.hud-head { position: relative; display: flex; align-items: flex-start; justify-content: space-between;
            gap: var(--s5); flex-wrap: wrap; }
/* COCKPIT — the console's panel stamp, leading the overview. Archivo Black,
   uppercase and tracked at headline scale: the bold spearhead the surface asked
   for, the same stamped voice a HUD panel labels itself in. */
.hud-id h1 { font-family: var(--face-stamp); font-weight: 700; font-weight: 400; text-transform: uppercase;
             font-size: clamp(30px, 4.4vw, 46px); letter-spacing: .1em; line-height: 1;
             color: var(--resist); }
.hud-who { margin-top: 10px; font-size: var(--fs-4); color: var(--indigo-200); letter-spacing: .02em; }
.hud-sub { margin-top: 10px; max-width: 52ch; color: var(--resist-soft);
           font-size: var(--fs-4); line-height: 1.5; }
.hud-toolbar { display: flex; gap: var(--s3); align-items: center; flex-wrap: wrap; }
.hud-ghost { background: transparent; }

/* Overview telemetry — a live tag plus three atomic PERSONAL readouts (value
   tracked, dividends booked, longest record), distributed across the strip between
   two hairlines. No masthead or tab-count duplication. */
.hud-ribbon { margin-top: var(--s5); display: flex; align-items: flex-start;
              justify-content: space-between; gap: var(--s4) var(--s6);
              flex-wrap: wrap; padding: var(--s4) 0; border-top: 1px solid var(--resist-line);
              border-bottom: 1px solid var(--resist-line); }
.ribbon-live { display: inline-flex; align-items: center; gap: 8px; align-self: center; }
.ribbon-cell { display: inline-flex; flex-direction: column; gap: 4px; min-width: 0; }
.ribbon-k { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .14em;
            text-transform: uppercase; color: var(--resist-dim); }
.ribbon-v { font-size: var(--fs-7); color: var(--resist); letter-spacing: -.01em;
            font-variant-numeric: tabular-nums; }
.ribbon-v.ink-oxide { color: var(--oxide-ink); }        /* dividends: the bound pigment */
.ribbon-usd { font-size: var(--fs-2); color: var(--resist-dim); }
.hud-ribbon-empty { align-items: center; gap: var(--s3); }
.ribbon-empty { color: var(--resist-soft); font-size: var(--fs-4); max-width: 66ch; margin: 0; }

/* Segmented switcher — spans the full console width so it lines up with the ledger
   below it (a left-packed control under a full-width table reads as unfinished);
   the tabs share the width equally. On mobile it falls back to natural-width tabs
   that scroll. overflow-y is pinned hidden so the overflow-x:auto quirk can never
   spawn a phantom vertical scrollbar. */
.hud-seg { position: relative; margin-top: var(--s5); display: flex; gap: 0;
           width: 100%; overflow-x: auto; overflow-y: hidden;
           border: 1px solid var(--resist-line-firm); }
.hud-tab { flex: 1 1 0; justify-content: center; }
@media (max-width: 560px) {
  .hud-seg { width: max-content; max-width: 100%; }
  .hud-tab { flex: 0 0 auto; justify-content: flex-start; }
}
.hud-tab { display: inline-flex; align-items: center; gap: 7px; background: transparent; border: 0;
           cursor: pointer; padding: 9px var(--s4); font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
           letter-spacing: .12em; text-transform: uppercase; color: var(--resist-dim);
           transition: color var(--dur-tap) var(--ease-vat), background var(--dur-tap) var(--ease-vat); }
.hud-tab + .hud-tab { border-left: 1px solid var(--resist-line); }
.hud-tab:hover { color: var(--resist-soft); background: var(--indigo-800); }
.hud-tab[aria-selected="true"] { color: var(--resist); background: var(--indigo-800); }
.hud-tab-n { color: var(--indigo-200); font-size: var(--fs-1); }
.hud-tab[aria-selected="true"] .hud-tab-n { color: var(--oxide-ink); }
/* The active tab's resist-thread underline — CSS off aria-selected, so it is
   always correct without measuring anything and never depends on an animation
   frame to become visible. It grows from the left on selection; if motion is
   suppressed (or a frame is missed) it simply rests full-width. */
.hud-tab { position: relative; }
.hud-tab[aria-selected="true"]::after { content: ""; position: absolute; left: 0; right: 0;
  bottom: -1px; height: 2px; background: var(--resist); transform-origin: left center;
  animation: hud-underline var(--dur-tap) var(--ease-vat); }
@keyframes hud-underline { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) { .hud-tab[aria-selected="true"]::after { animation: none; } }

/* Panel body + columnar ledger. The list is a data table: a stamped column header
   over rows that share one --hud-cols template (set per panel in JS), so a wide
   console fills with aligned information instead of a title-and-button gap. */
.hud-panel-body { margin-top: var(--s5); }
.hud-note { color: var(--resist-dim); max-width: 58ch; }
.hud-list { list-style: none; margin: 0; padding: 0; }

.hud-head-row { display: grid; grid-template-columns: var(--hud-cols); align-items: end;
                gap: var(--s4); padding: 0 var(--s3) var(--s2);
                border-bottom: 1px solid var(--resist-line); }
.hud-col-k { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .14em;
             text-transform: uppercase; color: var(--resist-dim); }

.hud-row { display: grid; grid-template-columns: var(--hud-cols); align-items: center;
           gap: var(--s4); padding: var(--s4) var(--s3);
           border-bottom: 1px solid var(--resist-line-faint);
           transition: background var(--dur-tap) var(--ease-vat); }
.hud-row:hover { background: var(--indigo-800); }
.hud-cell { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.hud-cell-v { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
              color: var(--resist-soft); font-size: var(--fs-5); }
.hud-cell-name .hud-cell-v { color: var(--resist); font-weight: 600; }
.hud-cell-k { display: none; }               /* stamped column labels inline only when stacked */
.hud-row-act { justify-self: end; }
.hud-away { color: var(--resist-dim); }

/* Seeds return, raised to the product's signature: the figure at ribbon weight
   over the price/dividend decomposition band, so the cockpit reads the cloth in
   the same bound pigments as the home cards and the hero weave — not a bare
   number floating in the column. */
.seed-ret { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.seed-ret-top { display: flex; align-items: baseline; gap: var(--s2); flex-wrap: wrap; }
.seed-ret-fig { font-size: var(--fs-8); letter-spacing: -.03em; color: var(--resist); }
.seed-ret-ccy { font-size: var(--fs-3); letter-spacing: .04em; color: var(--resist-dim); }
.seed-ret-alt { font-size: var(--fs-4); letter-spacing: .04em; color: var(--indigo-200); }
.seed-ret .pie-contrib { margin-top: 0; }

/* Below 640px the ledger stacks: the name and its action hold the top line, and
   each remaining column drops beneath as a stamped label + value pair. */
@media (max-width: 640px) {
  .hud-head-row { display: none; }
  .hud-row { grid-template-columns: minmax(0, 1fr) auto; align-items: start;
             row-gap: var(--s2); padding: var(--s4) var(--s2); }
  .hud-cell { grid-column: 1 / -1; flex-direction: row; align-items: baseline; gap: 8px; }
  .hud-cell-name { grid-column: 1; grid-row: 1; }
  .hud-row-act { grid-column: 2; grid-row: 1; align-self: center; }
  .hud-cell-v { white-space: normal; }
  .hud-cell-k { display: inline-block; flex: none; min-width: 9ch;
                font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .1em;
                text-transform: uppercase; color: var(--resist-dim); }
  .hud-cell-name .hud-cell-k { display: none; }
}

/* Trial status — bound pigment ink + dot, word alongside so greyscale survives. */
.hud-status { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
              font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .1em;
              text-transform: uppercase; }
.hud-status-dot { width: 6px; height: 6px; background: currentColor; }
.tone-valid { color: var(--vine-ink); }
.tone-await { color: var(--oxide-ink); }
.tone-stop  { color: var(--kola-ink); }

.hud-empty { padding: var(--s6) var(--s2); border-top: 1px solid var(--resist-line-faint); }
.hud-empty-h { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-6);
               color: var(--resist); margin-bottom: 6px; }
.hud-empty .fine { max-width: 56ch; }

.hud-claim { margin-top: var(--s4); display: flex; gap: var(--s2); }
.hud-claim .field { flex: 1; min-width: 0; }

/* Ribbon stagger-in: each cell rises on load, one after the next. */
.ribbon-in { opacity: 0; animation: ribbonrise var(--dur-dip) var(--ease-vat) forwards;
             animation-delay: calc(var(--ri) * 55ms); }
@keyframes ribbonrise { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .ribbon-in { animation: none; opacity: 1; }
}

/* Admin backend (Stage 9) — reuses the HUD console. Every screen is a decision:
   bands ordered by urgency, the bound pigments carrying meaning (oxide = needs
   attention, vine = clear/good), items as hairline-separated rows. */
.admin-band { display: flex; align-items: baseline; gap: 10px; margin: var(--s6) 0 var(--s3);
              font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-3); letter-spacing: .1em;
              text-transform: uppercase; color: var(--resist); }
.admin-band-n { font-family: var(--face-data); font-size: var(--fs-2); color: var(--resist-dim); }
.admin-band-block, .admin-band-block .admin-band-n { color: var(--oxide-ink); }  /* needs attention */
.admin-band-info, .admin-band-info .admin-band-n { color: var(--resist-dim); }

.admin-list { list-style: none; margin: 0; padding: 0;
              display: flex; flex-direction: column; gap: 1px; background: var(--resist-line-faint); }
.admin-item { background: var(--indigo-900); display: grid; grid-template-columns: 1fr auto;
              gap: var(--s2) var(--s4); padding: var(--s4) var(--s3); align-items: start; }
.admin-item-main b { font-size: var(--fs-5); color: var(--resist); }
.admin-item-main .fine { margin-top: 4px; max-width: 76ch; }
.admin-item-n { font-family: var(--face-data); font-size: var(--fs-7); color: var(--resist-soft);
                font-variant-numeric: tabular-nums; }
.admin-sample { grid-column: 1 / -1; list-style: none; margin: var(--s3) 0 0; padding: var(--s3) 0 0;
                border-top: 1px solid var(--resist-line-faint); display: flex; flex-direction: column; gap: 6px; }
.admin-sample-row { display: flex; gap: 12px; align-items: baseline; }
.admin-sample-row b { color: var(--resist); min-width: 11ch; }

.admin-clear { padding: var(--s7) var(--s2) var(--s6); margin-top: var(--s5);
               border-top: 1px solid var(--resist-line-faint); }
.admin-clear-h { font-family: var(--face-stamp); font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
                 font-size: var(--fs-7); color: var(--vine-ink); margin-bottom: 8px; }  /* clear = valid */
.admin-reason .hud-cell-v { color: var(--resist-soft); white-space: normal; }

/* Admin — triage item click-through + CA review (9C) */
.admin-item-side { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.admin-item-go { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .12em;
                 text-transform: uppercase; color: var(--indigo-200); }
.admin-item-go:hover { color: var(--resist); }

.admin-filters { display: flex; gap: 1px; margin: var(--s5) 0 var(--s2); width: max-content;
                 max-width: 100%; overflow-x: auto; border: 1px solid var(--resist-line-firm); }
.admin-chip { padding: 8px var(--s4); font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
              letter-spacing: .12em; text-transform: uppercase; color: var(--resist-dim);
              background: transparent; white-space: nowrap; }
.admin-chip + .admin-chip { border-left: 1px solid var(--resist-line); }
.admin-chip:hover { color: var(--resist-soft); background: var(--indigo-800); }
.admin-chip.is-on { color: var(--resist); background: var(--indigo-800); }

.admin-hypo { margin: var(--s3) 0 var(--s2); max-width: 76ch; color: var(--resist-soft);
              font-size: var(--fs-6); line-height: 1.55; }
.admin-decided { color: var(--oxide-ink); }

.admin-chart { margin: var(--s3) 0 var(--s2); }
.admin-chart .ca-chart { width: 100%; height: auto; display: block; }
.ca-chart line { vector-effect: non-scaling-stroke; }
.ca-base { stroke: var(--resist-line); stroke-width: 1; }
.ca-event { stroke: var(--resist-line-firm); stroke-width: 1; stroke-dasharray: 3 3; }
.ca-raw { stroke: var(--kola-ink); stroke-width: 2; vector-effect: non-scaling-stroke; }
.ca-adj { stroke: var(--vine-ink); stroke-width: 2; vector-effect: non-scaling-stroke; }
.ca-dot { fill: var(--kola-ink); }
.ca-chart-t { fill: var(--resist-dim); font-family: var(--face-stamp); font-weight: 700; font-size: 10px;
              letter-spacing: .12em; text-transform: uppercase; }
.ca-legend { display: flex; gap: var(--s4); margin-top: 8px; }
.ca-key { display: inline-flex; align-items: center; gap: 6px; }
.ca-key::before { content: ""; width: 14px; height: 2px; }
.ca-key-raw::before { background: var(--kola-ink); }
.ca-key-adj::before { background: var(--vine-ink); }

.ca-verdict { margin: var(--s3) 0 0; font-size: var(--fs-5); max-width: 78ch; line-height: 1.5;
              color: var(--resist-soft); }
.ca-verdict b { color: var(--resist); }
.ca-ok b { color: var(--vine-ink); }
.ca-bad b { color: var(--kola-ink); }

.admin-kv { list-style: none; margin: var(--s3) 0 var(--s2); padding: 0;
            display: flex; flex-direction: column; gap: 1px; background: var(--resist-line-faint); }
.admin-kv li { background: var(--indigo-900); display: grid; grid-template-columns: 16rem 1fr;
               gap: var(--s4); padding: var(--s3) var(--s3); }
.admin-kv-k { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .12em;
              text-transform: uppercase; color: var(--resist-dim); }
@media (max-width: 560px) { .admin-kv li { grid-template-columns: 1fr; gap: 2px; } }

.ca-decide { margin-top: var(--s5); border-top: 1px solid var(--resist-line); padding-top: var(--s4); }
.ca-reason { width: 100%; margin: var(--s2) 0 var(--s3); resize: vertical; min-height: 2.6em; }
.ca-actions { display: flex; flex-wrap: wrap; gap: var(--s3); }
.ca-blocked { margin-top: var(--s3); color: var(--kola-ink); max-width: 76ch; }

/* 9D — source health: the routing-authority strip. */
.src-authority { display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
                 margin: var(--s3) 0 var(--s2); }
.src-auth-node { padding: 6px 10px; background: var(--indigo-800); border: 1px solid var(--resist-line);
                 font-size: var(--fs-4); color: var(--resist); }
.src-authority .src-auth-node:first-of-type { border-color: var(--indigo-300); }
.src-arrow { color: var(--resist-dim); }

/* 9E — suspect-session quarantine ledger: filter + bulk-restore bar. */
.admin-filter-form { display: flex; gap: var(--s2); margin: var(--s4) 0 var(--s2); align-items: center; }
.sess-bulk { display: flex; gap: var(--s2); align-items: center; margin: var(--s2) 0 var(--s4); }
.sess-check { width: 16px; height: 16px; accent-color: var(--oxide); cursor: pointer; }

/* Admin sub-nav across the decision surfaces. */
.admin-subnav { display: flex; flex-wrap: wrap; gap: 2px; align-items: center; }
.admin-subnav-link { padding: 7px 11px; font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
                     letter-spacing: .1em; text-transform: uppercase; color: var(--resist-dim);
                     border: 1px solid transparent; white-space: nowrap; }
.admin-subnav-link:hover { color: var(--resist-soft); background: var(--indigo-800); }
.admin-subnav-link.is-on { color: var(--resist); background: var(--indigo-800);
                           border-color: var(--resist-line); }

/* 9E — tier override panel + the overridden-tier mark. */
.ov-panel { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center;
            margin: var(--s2) 0 var(--s2); }
.ov-set .hud-cell-v { color: var(--oxide-ink); }

/* 9E — moderation: kill-switch banner, report actions, screening classes. */
.mod-killswitch { padding: var(--s3); border: 1px solid var(--resist-line);
                  margin: var(--s2) 0 var(--s2); }
.ks-on b { color: var(--vine-ink); }
.ks-off { border-color: var(--kola); }
.ks-off b { color: var(--kola-ink); }
.mod-item { grid-template-columns: 1fr; }
.mod-actions { display: flex; gap: var(--s2); align-items: center; margin-top: var(--s3); flex-wrap: wrap; }
.mod-cats { list-style: none; margin: var(--s2) 0 0; padding: 0; display: grid;
            grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 1px;
            background: var(--resist-line-faint); }
.mod-cats li { background: var(--indigo-900); padding: var(--s3); display: flex;
               flex-direction: column; gap: 3px; }
.mod-cats li b { color: var(--oxide-ink); }

/* Artifacts — the public gallery of approved, forward-tested pies. Fills the page
   container (#view is .wrap, max 1320px) so the grid can reach three columns; the
   reading prose stays capped on its own. */
.artifacts { max-width: none; margin: var(--s6) 0 var(--s8); }
.artifacts-head h1 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-9);
                     letter-spacing: -.025em; color: var(--resist); }
.artifacts-head .sub { margin-top: var(--s2); max-width: 62ch; color: var(--resist-soft);
                       font-size: var(--fs-5); line-height: 1.5; }
.artifacts-gallery { margin-top: var(--s5); }
.artifacts-empty { padding: var(--s5); border: 1px solid var(--resist-line);
                   background: var(--indigo-900); }
.artifacts-empty h3 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-6);
                      letter-spacing: -.02em; color: var(--resist); }
.artifacts-empty p { margin-top: var(--s2); color: var(--resist-soft); font-size: var(--fs-5);
                     line-height: 1.55; max-width: 62ch; }
.artifacts-cta { margin-top: var(--s5); display: flex; flex-direction: column;
                 align-items: flex-start; gap: var(--s3); }
.artifacts-cta p { color: var(--resist-soft); font-size: var(--fs-6); }

/* The gallery grid reuses .pie-index (hairline columns) and .pie-card (the
   dye-climb hover and the return / window / measurement type roles). Only the
   held return slot and the creator identity line are Artifacts-specific. */
.artifacts-index { margin-top: var(--s5); }
.art-ret { min-height: 34px; display: flex; align-items: center; }
.art-meta { margin-top: auto; display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3);
            font-family: var(--face-data); font-size: var(--fs-4);
            color: var(--resist-dim); letter-spacing: -.01em; }

/* Publication gates — the two conditions a pie must pass to go public. */
.pub-gates { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s3); margin-top: var(--s2); }
.pub-gate { font-family: var(--face-ui); font-size: var(--fs-4); }
.pub-gate.is-ok { color: var(--vine-ink); }
.pub-gate.is-no { color: var(--kola-ink); }
.pub-flags { margin-top: var(--s2); color: var(--kola-ink); }

/* Build-as-editor: pending diff + version history below the builder */
.edit-panel { margin-top: var(--s4); padding-top: var(--s4);
              border-top: 1px solid var(--resist-line); display: grid; gap: var(--s4); }
.edit-panel h3 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .09em;
                 text-transform: uppercase; color: var(--resist-dim); margin-bottom: var(--s2); }
.edit-pending .pie-diff-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px;
                               font-family: var(--face-data); font-size: var(--fs-4); }

/* Per-pie visibility control (pie page, owner only) */
.vis-control { margin-top: var(--s6); padding-top: var(--s4);
               border-top: 1px solid var(--resist-line); }
.vis-control h3 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .09em;
                  text-transform: uppercase; color: var(--resist-dim); margin-bottom: var(--s2); }
.vis-state { color: var(--resist-soft); margin-bottom: var(--s3); }
.vis-seg { display: inline-flex; border: 1px solid var(--resist-line-firm); }
.vis-opt { background: var(--indigo-900); border: 0; cursor: pointer; padding: 7px var(--s4);
           font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .1em;
           text-transform: uppercase; color: var(--resist-dim); }
.vis-opt + .vis-opt { border-left: 1px solid var(--resist-line); }
.vis-opt:not(:disabled):hover { color: var(--resist); background: var(--indigo-800); }
.vis-opt.is-on { color: var(--resist); background: var(--indigo-700); cursor: default; }
.vis-actions { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.vis-review { margin-top: var(--s3); color: var(--resist-dim); max-width: 60ch; }

/* Back control on deep pages */
.back-link { display: inline-flex; align-items: center; gap: 4px; margin-bottom: var(--s3);
             background: none; border: 0; cursor: pointer; padding: 4px 0;
             font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .11em;
             text-transform: uppercase; color: var(--resist-dim); }
.back-link:hover { color: var(--resist); }

/* "You are here" for Settings, which lives under the @handle menu */
.handle-summary.is-current { color: var(--resist); border-color: var(--resist-line-firm);
                             background: var(--indigo-800); }

/* Performance gauge on the pie page */
.pie-perf { margin-top: var(--s5); padding: var(--s4);
            border: 1px solid var(--resist-line-firm); background: var(--indigo-900); }
.pie-perf h3 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .09em;
               text-transform: uppercase; color: var(--resist-dim); margin-bottom: var(--s3); }
.pie-perf .became { display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap; }
.pie-perf .figure-hero { font-family: var(--face-data); font-size: var(--fs-8); letter-spacing: -.03em;
                         color: var(--resist); }
.pie-perf .arrow { color: var(--resist-dim); font-size: var(--fs-6); }
.pie-perf-win { margin-top: var(--s2); color: var(--resist-dim); font-size: var(--fs-4); }
.pie-perf .fx-note { margin-top: var(--s2); }
.pie-perf-link { display: inline-block; margin-top: var(--s3); font-family: var(--face-ui);
                 font-size: var(--fs-4); color: var(--indigo-200); text-decoration: none; }
.pie-perf-link:hover { color: var(--resist); }

/* SB2 structure panel — a descriptive read of the basket, never a trade signal */
.pie-structure { margin-top: var(--s5); padding: var(--s4);
                 border: 1px solid var(--resist-line-firm); background: var(--indigo-900); }
.structure-body { margin-top: var(--s3); }
.struct-read { color: var(--resist-soft); font-size: var(--fs-5); line-height: 1.55;
               max-width: 64ch; }
.struct-metrics { margin-top: var(--s4); display: grid;
                  grid-template-columns: repeat(3, 1fr); gap: var(--s4); }
@media (max-width: 560px) { .struct-metrics { grid-template-columns: 1fr; gap: var(--s3); } }
.struct-metric { display: flex; flex-direction: column; gap: 4px;
                 border-top: 1px solid var(--resist-line); padding-top: var(--s2); }
.struct-k { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .12em;
            text-transform: uppercase; color: var(--resist-dim); }
.struct-v { font-size: var(--fs-6); color: var(--resist); letter-spacing: -.01em; }
.struct-sub { color: var(--resist-dim); }
.struct-note { margin-top: var(--s4); color: var(--resist-dim); max-width: 64ch;
               padding-top: var(--s3); border-top: 1px solid var(--resist-line-faint); }

/* REDIRECT top-up simulator (paper what-if) */
.pie-rsim { margin-top: var(--s5); padding: var(--s4);
            border: 1px solid var(--resist-line-firm); background: var(--indigo-900); }
.rsim-form { margin-top: var(--s3); display: flex; gap: var(--s3); align-items: flex-end;
             flex-wrap: wrap; }
/* Zero the label's bottom margin in this bottom-aligned row: with align-items:
   flex-end the 12px margin pushed the input fields' baseline 12px ABOVE the
   buttons, so the Simulate / Forward-test pair sat low against the fields. Same
   fix the import-mapping form already carries. */
.rsim-form .pf-lab { margin-bottom: 0; }
.rsim-form .field { width: 12rem; max-width: 100%; }
.rsim-out { margin-top: var(--s4); }
.rsim-drift { color: var(--resist-soft); font-size: var(--fs-5); }
.rsim-drift b { color: var(--resist); }
.rsim-cols { margin-top: var(--s4); display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5); }
@media (max-width: 560px) { .rsim-cols { grid-template-columns: 1fr; gap: var(--s4); } }
.rsim-cols .struct-k { display: block; margin-bottom: var(--s2); }
.rsim-tbl { width: 100%; border-collapse: collapse; }
.rsim-tbl th { text-align: left; font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
               letter-spacing: .1em; text-transform: uppercase; color: var(--resist-dim);
               font-weight: 400; padding: 4px 0; border-bottom: 1px solid var(--resist-line); }
.rsim-tbl td { padding: 6px 0; border-bottom: 1px solid var(--resist-line-faint);
               color: var(--resist-soft); font-size: var(--fs-4); }
.rsim-tbl td + td, .rsim-tbl th + th { text-align: right; padding-left: var(--s3); }
.rsim-summary { margin-top: var(--s4); color: var(--resist-soft); font-size: var(--fs-4);
                line-height: 1.55; }

/* REDIRECT forward record — two arms side by side */
.fwd-arms { margin-top: var(--s4); display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); }
@media (max-width: 560px) { .fwd-arms { grid-template-columns: 1fr; } }
.fwd-arm { display: flex; flex-direction: column; gap: 4px; padding: var(--s3);
           border: 1px solid var(--resist-line); }
.fwd-edge { margin-top: var(--s4); color: var(--resist-soft); font-size: var(--fs-5);
            line-height: 1.5; }
.fwd-edge b { font-size: var(--fs-6); letter-spacing: -.01em; }

/* A small cut button must match a small solid one in a row: same height, a
   proportionate notch. Full-size btn-cut keeps its 13px CTA padding. */
.btn-sm.btn-cut { padding: 7px 13px;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); }

/* Performance gauge controls (window + dividends) */
.pie-perf-head { display: flex; align-items: baseline; gap: var(--s3); }
.pie-perf-sub { color: var(--resist-dim); }
.pie-perf-controls { display: flex; gap: var(--s5); flex-wrap: wrap; margin: var(--s3) 0 var(--s4); }
.gauge-seg { display: inline-flex; border: 1px solid var(--resist-line-firm); }
.gauge-opt { background: var(--indigo-900); border: 0; cursor: pointer; padding: 6px var(--s3);
             font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .1em;
             text-transform: uppercase; color: var(--resist-dim); }
.gauge-opt + .gauge-opt { border-left: 1px solid var(--resist-line); }
.gauge-opt:not(:disabled):hover { color: var(--resist); background: var(--indigo-800); }
.gauge-opt.is-on { color: var(--resist); background: var(--indigo-700); }

/* Touch targets: the small segmented controls (gauge, visibility, range) and the
   nav are comfortable with a mouse but under 44px for a finger. On a coarse
   pointer, grow them to a proper tap size without touching the mouse layout. */
@media (pointer: coarse) {
  .gauge-opt, .vis-opt, .range-btn { min-height: 44px; padding-top: 11px; padding-bottom: 11px; }
  .navlink, .handle-summary { padding-top: 11px; padding-bottom: 11px; }
  .handle-item { padding-top: 13px; padding-bottom: 13px; }
  .back-link { padding-top: 8px; padding-bottom: 8px; }
}

/* Fork attribution — permanent, never dismissible */
.pie-forked-from { margin-top: var(--s2); font-size: var(--fs-4); color: var(--resist-dim); }
.pie-forked-from a { color: var(--indigo-200); }

/* Fork action, available to any viewer */
.pie-viewer { margin-top: var(--s6); padding-top: var(--s4);
              border-top: 1px solid var(--resist-line); display: flex; align-items: center;
              gap: var(--s3); flex-wrap: wrap; }
.pie-viewer .fine { color: var(--resist-dim); }

/* Share row — the Truth Card artifact + canonical link */
.pie-share { margin-top: var(--s3); display: flex; align-items: center;
             gap: var(--s3); flex-wrap: wrap; }
.pie-share .fine { color: var(--resist-dim); }
.pie-share a.btn { text-decoration: none; }

/* The relic lightbox — a framed viewer for the portrait Truth Card. The scrim is
   the dye vat at depth (a ground, not a shadow); the stage is flat and cornered
   like every other panel. */
.relic-overlay { position: fixed; inset: 0; z-index: 60; background: rgba(6, 17, 28, .93);
  display: flex; align-items: center; justify-content: center; padding: var(--s5);
  animation: relic-fade var(--dur-tap) var(--ease-vat); }
@keyframes relic-fade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .relic-overlay { animation: none; } }
.relic-stage { display: flex; flex-direction: column; max-width: min(560px, 94vw);
  max-height: 92vh; border: 1px solid var(--resist-line-firm); background: var(--indigo-900); }
.relic-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
  padding: var(--s3) var(--s4); border-bottom: 1px solid var(--resist-line); }
.relic-bar-t { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .14em;
  text-transform: uppercase; color: var(--resist-dim); }
.relic-bar-actions { display: flex; gap: var(--s2); }
.relic-bar-actions a.btn { text-decoration: none; }
.relic-scroll { overflow: auto; padding: var(--s4); }
.relic-img { display: block; width: 100%; height: auto; border: 1px solid var(--resist-line-faint); }

/* Moderation block — the screening findings that stopped a pie going public */
.vis-block { margin-top: var(--s3); padding: var(--s3) var(--s4);
             border: 1px solid var(--kola-ink); background: color-mix(in srgb, var(--kola) 10%, transparent); }
.vis-block > p { display: flex; align-items: baseline; gap: 6px; color: var(--resist);
                 font-size: var(--fs-4); line-height: 1.5; }
.vis-block-list { list-style: none; margin: var(--s2) 0 0; padding: 0; display: grid; gap: 4px; }
.vis-block-list li { color: var(--resist-soft); font-size: var(--fs-4); }
.vis-block-list b { color: var(--kola-ink); font-family: var(--face-stamp); font-weight: 700;
                    font-size: var(--fs-1); letter-spacing: .06em; text-transform: uppercase; }

/* Creator attestation prompt (before a first public publish) */
.attest-prompt { margin-top: var(--s3); padding: var(--s4);
                 border: 1px solid var(--resist-line-firm); background: var(--indigo-900); }
.attest-prompt h4 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .09em;
                    text-transform: uppercase; color: var(--resist-dim); margin-bottom: var(--s3); }
.attest-doc { max-height: 42vh; overflow-y: auto; padding: var(--s3);
              border: 1px solid var(--resist-line); margin-bottom: var(--s3);
              color: var(--resist-soft); font-size: var(--fs-4); line-height: 1.55; }
.attest-doc h1 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-6);
                 color: var(--resist); margin-bottom: var(--s2); }
.attest-doc ol, .attest-doc ul { padding-left: var(--s4); margin: var(--s2) 0; }
.attest-doc a { color: var(--indigo-200); }

/* Report control on a pie you don't own */
.pie-report { margin-left: auto; background: none; border: 0; cursor: pointer;
              font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .1em;
              text-transform: uppercase; color: var(--resist-dim); }
.pie-report:hover { color: var(--kola-ink); }

/* --- The three panels (Stage 5): HISTORICAL / FORWARD / LIVE --------------- *
 * A backtest is hindsight, a trial is a commitment, and there is no live feed.
 * The HISTORICAL panel is the widest — it holds the gauge — and carries the
 * hindsight line ALONE. FORWARD and LIVE share the row beneath it. Each panel
 * wears its result-type stamp in an honest accent: neutral indigo for the
 * backtest, verified vine for the forward record, muted for the absent live. */
.three-panel { display: grid; gap: var(--s3); margin-top: var(--s5);
               grid-template-columns: 1fr 1fr;
               grid-template-areas: "hist hist" "fwd live"; }
.tp-historical { grid-area: hist; }
.tp-forward    { grid-area: fwd; }
.tp-live       { grid-area: live; }
@media (max-width: 640px) {
  .three-panel { grid-template-columns: 1fr; grid-template-areas: "hist" "fwd" "live"; }
}
.tp-panel { position: relative; padding: var(--s4) var(--s4) var(--s4);
            border: 1px solid var(--resist-line-firm); background: var(--indigo-900); }
.tp-label { display: inline-block; font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
            letter-spacing: .14em; text-transform: uppercase; padding: 3px 9px;
            border: 1px solid currentColor; margin-bottom: var(--s3); }
.lb-backtest { color: var(--indigo-200); }
.lb-forward  { color: var(--vine); }
.lb-live     { color: var(--resist-dim); }

/* The gauge sits flush inside the historical panel — the panel owns the frame,
   so the nested box sheds its own border, ground and top margin. */
.tp-historical .pie-perf { margin-top: 0; padding: 0; border: 0; background: none; }
.tp-hindsight { margin-top: var(--s4); padding-top: var(--s3);
                border-top: 1px solid var(--resist-line);
                display: flex; align-items: baseline; gap: 8px;
                color: var(--resist-dim); font-size: var(--fs-3); line-height: 1.55; }

/* FORWARD panel body: a committed return, or the invitation to commit one.
   Never the hindsight line — its absence here is the entire point. */
.tp-forward-body { min-height: 3.2em; }
.tp-forward-line { display: flex; align-items: baseline; gap: var(--s2); flex-wrap: wrap; }
.tp-forward-line b { font-family: var(--face-data); font-size: var(--fs-6);
                     letter-spacing: -.02em; color: var(--resist); }
.tp-nohindsight { margin-top: var(--s2); color: var(--vine); font-size: var(--fs-3);
                  line-height: 1.5; }
.tp-forward-empty { margin-bottom: var(--s3); }
.tp-cta { margin-top: var(--s3); }

.tp-live-note { line-height: 1.55; }

/* Trial creation form (under a pie's viewer actions) */
.trial-form { width: 100%; margin-top: var(--s3); padding: var(--s3) var(--s4);
              border: 1px solid var(--resist-line-firm); background: var(--indigo-900);
              display: grid; gap: var(--s3); }
.trial-row { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.trial-row .pf-lab { display: flex; flex-direction: column; gap: 4px; }
.trial-row .field { width: 12rem; }

/* Trial certificate screen */
.trial-screen { max-width: 52rem; margin: var(--s6) auto var(--s8); }
.trial-label { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1); letter-spacing: .14em;
               text-transform: uppercase; color: var(--indigo-200); }
.trial-head h1 { font-family: var(--face-ui); font-weight: 600; font-size: var(--fs-9);
                 letter-spacing: -.025em; color: var(--resist); margin-top: var(--s1); }
.trial-byline { margin-top: var(--s2); color: var(--resist-dim); font-size: var(--fs-4); }
.trial-banner { margin-top: var(--s4); padding: var(--s2) var(--s3);
                border: 1px solid var(--resist-line-firm); background: var(--indigo-800);
                display: flex; align-items: baseline; gap: var(--s2); flex-wrap: wrap;
                font-family: var(--face-data); font-size: var(--fs-5); color: var(--resist); }
.trial-banner .fine { color: var(--resist-dim); }
.trial-banner.trial-scheduled { border-color: var(--oxide-ink); }
.trial-banner.trial-active { border-color: var(--vine-ink); }
.trial-banner.trial-stopped_early, .trial-banner.trial-invalidated { border-color: var(--kola-ink); }
.trial-nohindsight { margin-top: var(--s3); color: var(--resist-soft); font-size: var(--fs-5);
                     line-height: 1.5; max-width: 62ch; }
.trial-cert { margin-top: var(--s5); }
.trial-cert h3, .trial-terms dt { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2);
                                  letter-spacing: .09em; text-transform: uppercase; color: var(--resist-dim); }
.trial-holdings { list-style: none; margin: var(--s3) 0; padding: 0; display: grid; gap: 1px;
                  background: var(--resist-line); border: 1px solid var(--resist-line); }
.trial-holdings li { background: var(--indigo-900); padding: var(--s2) var(--s4);
                     display: flex; align-items: baseline; gap: var(--s2); flex-wrap: wrap; }
.trial-holdings b { font-size: var(--fs-5); color: var(--resist); }
.trial-tier { margin-left: auto; font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-1);
              letter-spacing: .08em; text-transform: uppercase; border: 1px solid currentColor;
              padding: 0 var(--s2); }
.tier-verified { color: var(--vine-ink); }
.tier-usable_with_disclosures { color: var(--oxide-ink); }
.tier-blocked { color: var(--kola-ink); }
.trial-terms { display: grid; gap: 1px; background: var(--resist-line);
               border: 1px solid var(--resist-line); margin-top: var(--s3); }
.trial-terms > div { background: var(--indigo-900); padding: var(--s2) var(--s4);
                     display: flex; justify-content: space-between; align-items: baseline; gap: var(--s4); }
.trial-terms dd { color: var(--resist-soft); font-size: var(--fs-4); text-align: right; }
.trial-hash { word-break: break-all; font-size: var(--fs-2); color: var(--resist-dim); }
.trial-screen > .btn { margin-top: var(--s4); }

/* Trial value + progression */
.trial-value { margin-top: var(--s4); padding: var(--s4);
               border: 1px solid var(--resist-line-firm); background: var(--indigo-900); }
.trial-value .became { display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap; }
.trial-value .figure-hero { font-family: var(--face-data); font-size: var(--fs-8);
                            letter-spacing: -.03em; color: var(--resist); }
.trial-value .arrow { color: var(--resist-dim); font-size: var(--fs-6); }
.trial-value .fine { margin-top: var(--s2); color: var(--resist-dim); }
.trial-building { color: var(--resist-soft); font-size: var(--fs-5); line-height: 1.5; }
.trial-next { margin-top: var(--s6); padding-top: var(--s4); border-top: 1px solid var(--resist-line); }
.trial-next h3 { font-family: var(--face-stamp); font-weight: 700; font-size: var(--fs-2); letter-spacing: .09em;
                 text-transform: uppercase; color: var(--resist-dim); margin-bottom: var(--s3); }
.trial-next-actions { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.trial-next-actions .fine { color: var(--resist-dim); }
.trial-next > .fine { margin-top: var(--s3); color: var(--resist-dim); }
