/* ==========================================================================
   buttons.css — Cypherpunk button set (UI KIT / 01)
   Loads AFTER style.css and v3.css. Restyles the EXISTING button classes,
   so no markup changes are required for site-wide application.

   Rules carried over from the kit:
     gold primary · teal secondary · all controls >= 44px
     one sanctioned gradient (the scanline CTA) — used once per page

   Families:
     01 cut-corner primary  .btn--gold          chamfer 12px, gold fill
        cut-corner outline  .btn--alarm         chamfer 12px, outline
     02 terminal prompt     .term-btn           $ sigil, blinking caret, teal
     03 bracket ghost       .btn--bracket       [ label ], tracking opens
        soft secondary      .btn--ghost         the workhorse
     04 status pill         .chip               teal/gold pills
     05 scanline CTA        .btn--cta           the one gradient
     06 segmented           .tiers / .tier      active segment fills gold
        disabled            [disabled]          35% ink wash
   ========================================================================== */

:root {
  /* the kit's chamfer, shared by every cut-corner control */
  --chamfer: polygon(12px 0, 100% 0, 100% calc(100% - 12px),
                     calc(100% - 12px) 100%, 0 100%, 0 12px);
  --chamfer-in: polygon(11px 0, 100% 0, 100% calc(100% - 11px),
                        calc(100% - 11px) 100%, 0 100%, 0 11px);
  --chamfer-lg: polygon(16px 0, 100% 0, 100% calc(100% - 16px),
                        calc(100% - 16px) 100%, 0 100%, 0 16px);

  /* teal secondary — the kit's lighter reading of the brand jade */
  --btn-teal:      #36d8ca;
  --btn-teal-a45:  rgba(54, 216, 202, .42);
  --btn-teal-a12:  rgba(54, 216, 202, .10);
  --btn-ink:       #16130f;          /* on-gold text */
  --btn-cream:     #f4efe2;
  --btn-cream-a28: rgba(244, 239, 226, .28);
  --btn-cream-a06: rgba(244, 239, 226, .06);
  --btn-wash:      rgba(244, 239, 226, .35);
}

@keyframes sbBlink { 0%, 55% { opacity: 1 } 56%, 100% { opacity: 0 } }
@keyframes sbScan  { 0% { transform: translateY(-100%) } 100% { transform: translateY(400%) } }
@keyframes sbSweep { 0% { transform: translateX(-120%) } 100% { transform: translateX(320%) } }

/* --------------------------------------------------------------------------
   Base — every control clears the 44px floor
   -------------------------------------------------------------------------- */
.btn { min-height: 46px; position: relative; overflow: hidden; }
.btn--sm { min-height: 44px; padding: .6rem 1.1rem; font-size: .6875rem; }

/* --------------------------------------------------------------------------
   01 · cut-corner primary — .btn--gold
   Fill brightens to wheat on hover.
   -------------------------------------------------------------------------- */
.btn--gold {
  clip-path: var(--chamfer);
  border-radius: 0;
  border: 0;
  background: var(--gold);
  color: var(--btn-ink);
  box-shadow: none;
}
.btn--gold:hover,
.btn--gold:focus-visible { background: var(--gold-bright); color: var(--btn-ink); }
.btn--gold:active { transform: translateY(1px); }

/* cut-corner outline — .btn--alarm (the "Abort" reading: destructive, gold rule)
   The border is a background layer so the chamfer cuts it cleanly. */
.btn--alarm {
  clip-path: var(--chamfer);
  border-radius: 0;
  border: 0;
  background: var(--gold);
  color: var(--gold-bright);
  padding: calc(.8rem + 1px) calc(1.5rem + 1px);
}
.btn--alarm::before {
  content: "";
  position: absolute; inset: 1px;
  background: var(--bg);
  clip-path: var(--chamfer-in);
  z-index: -1;   /* behind the label, above the gold border layer */
}
.btn--alarm { isolation: isolate; }
.btn--alarm > * { position: relative; z-index: 1; }
.btn--alarm:hover { color: var(--btn-ink); }
.btn--alarm:hover::before { background: var(--gold); }

/* --------------------------------------------------------------------------
   03 · soft secondary — .btn--ghost (the workhorse, "Scan wallet")
   -------------------------------------------------------------------------- */
.btn--ghost {
  background: var(--btn-cream-a06);
  border: 1px solid var(--btn-cream-a28);
  border-radius: 4px;
  color: var(--btn-cream);
}
.btn--ghost:hover,
.btn--ghost:focus-visible {
  background: var(--btn-teal-a12);
  border-color: var(--btn-teal-a45);
  color: var(--btn-teal);
}

/* bracket ghost — .btn--bracket ([ ENTER ]) : tracking opens on hover, teal sweep */
.btn--bracket { overflow: visible;
  background: none;
  border: 0;
  border-radius: 0;
  color: var(--btn-cream);
  padding-inline: .4rem;
  transition: letter-spacing .28s var(--ease, ease), color .28s ease;
}
.btn--bracket::before,
.btn--bracket::after {
  color: var(--gold);
  opacity: .85;
  transition: transform .28s ease, opacity .28s ease;
  display: inline-block;
}
.btn--bracket::before { content: "["; margin-right: .7em; }
.btn--bracket::after  { content: "]"; margin-left:  .7em; }
.btn--bracket:hover,
.btn--bracket:focus-visible { letter-spacing: .26em; color: #fff; }
.btn--bracket:hover::before { transform: translateX(-3px); opacity: 1; }
.btn--bracket:hover::after  { transform: translateX(3px);  opacity: 1; }

/* --------------------------------------------------------------------------
   05 · scanline CTA — .btn--cta
   The system's ONE sanctioned gradient. One per page, on the money action.
   -------------------------------------------------------------------------- */
.btn--cta {
  clip-path: var(--chamfer-lg);
  border-radius: 0;
  border: 0;
  background: linear-gradient(90deg, var(--gold-bright) 0%, var(--gold) 58%, #a98c4d 100%);
  color: var(--btn-ink);
  font-weight: 700;
  letter-spacing: .18em;
  min-height: 58px;
  padding: 1.15rem 1.9rem;
  isolation: isolate;
}
.btn--cta > * { position: relative; z-index: 2; }
/* the scanline pass */
.btn--cta::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0;
  height: 34%;
  background: linear-gradient(180deg, transparent, rgba(255, 255, 255, .12), transparent);
  animation: sbScan 4.6s linear infinite;
  z-index: 1;
  pointer-events: none;
}
/* the hover sweep */
.btn--cta::after {
  content: "";
  position: absolute; top: -20%; bottom: -20%; left: 0;
  width: 38%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .38), transparent);
  transform: translateX(-120%);
  z-index: 1;
  pointer-events: none;
}
.btn--cta:hover::after,
.btn--cta:focus-visible::after { animation: sbSweep .85s ease-out; }
.btn--cta:hover { filter: brightness(1.06); }
.btn--cta:active { transform: translateY(1px); }

/* --------------------------------------------------------------------------
   02 · terminal prompt — .term-btn
   Gold sigil, blinking block caret, teal bloom on hover.
   -------------------------------------------------------------------------- */
/* Demoted at rest (2026-09-12): the terminal is a secondary entrance, not a
   second primary. It holds a hairline and recessive ink until it is touched;
   the teal flood below is unchanged and still owns the hover state. */
.term-btn {
  border-radius: 6px;
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--text-secondary);
  text-transform: none;
  letter-spacing: .1em;
}
.term-btn .term-btn__glyph { color: var(--gold); opacity: .95; }
/* terminal.css runs `termKey` on this glyph as an idle infinite animation. It
   is a FOURTH resting heartbeat in the bar, so it is silenced here (buttons.css
   loads after terminal.css) and handed back on hover with the caret. */
.term-btn .term-btn__glyph { animation: none; }
.term-btn:hover .term-btn__glyph,
.term-btn:focus-visible .term-btn__glyph { animation: termKey 2.4s steps(1) infinite; }
.term-btn::after {
  content: "";
  display: inline-block;
  width: .5em; height: 1.05em;
  margin-left: .15em;
  background: currentColor;
  vertical-align: -.18em;
  /* IDLE SILENCE (2026-09-12): the caret no longer blinks on its own. A header
     that is always moving has nothing left to say when something happens. It
     rests dim and static, and only blinks once the control is addressed. */
  animation: none;
  opacity: .45;
}
.term-btn:hover::after,
.term-btn:focus-visible::after {
  animation: sbBlink 1.05s steps(1) infinite;
  opacity: 1;
}
.term-btn:hover,
.term-btn:focus-visible {
  background: rgba(54, 216, 202, .18);
  border-color: var(--instr, var(--btn-teal));
  box-shadow: 0 0 22px -6px var(--instr-a42, var(--btn-teal-a45));
}

/* --------------------------------------------------------------------------
   04 · status readout — .chip

   The pill became an engraved readout (2026-09-12). A 999px teal pill read as
   a third button in a row that already had two; the contract address is a
   READING, not an action you take. The frame is now eight static gold corner
   ticks — an instrument bezel, drawn in background-image so no markup and no
   border is needed. The tick colour is factored into --tick so the hover state
   restates one value instead of eight gradient layers.
   -------------------------------------------------------------------------- */
.chip {
  --tick: var(--gold-a30);
  border: 0;
  border-radius: 0;
  padding: .5rem .9rem;
  min-height: 44px;
  background:
    linear-gradient(var(--tick),var(--tick)) 0    0    / 10px 1px,
    linear-gradient(var(--tick),var(--tick)) 0    0    / 1px 10px,
    linear-gradient(var(--tick),var(--tick)) 100% 0    / 10px 1px,
    linear-gradient(var(--tick),var(--tick)) 100% 0    / 1px 10px,
    linear-gradient(var(--tick),var(--tick)) 0    100% / 10px 1px,
    linear-gradient(var(--tick),var(--tick)) 0    100% / 1px 10px,
    linear-gradient(var(--tick),var(--tick)) 100% 100% / 10px 1px,
    linear-gradient(var(--tick),var(--tick)) 100% 100% / 1px 10px;
  background-repeat: no-repeat;
}
.chip:hover {
  --tick: rgba(212,184,114,.55);
  background-color: color-mix(in oklab, var(--gold) 8%, transparent);
}
.chip__label { color: var(--gold); letter-spacing: .14em; }
.chip__addr { color: var(--text-secondary); }
.chip__icon { opacity: .4; transition: opacity var(--fast); }
.chip:hover .chip__icon { opacity: 1; }
/* the live lamp holds still until the readout is addressed */
.chip .chip__pulse {
  background: var(--btn-teal);
  animation: none;
  box-shadow: 0 0 6px 1px rgba(54,216,202,.45);
}
.chip:hover .chip__pulse,
.chip:focus-visible .chip__pulse { animation: pulse 2.6s infinite; }

/* --------------------------------------------------------------------------
   06 · segmented control — .tiers / .tier (the lock-tier selector)
   Active segment fills gold. Hairlines between, chamfer on the outer shell.
   -------------------------------------------------------------------------- */
.tiers {
  display: flex;
  gap: 0;
  border: 1px solid var(--btn-cream-a28);
  border-radius: 4px;
  overflow: hidden;
}
.tiers .tier {
  flex: 1 1 0;
  min-height: 52px;
  border: 0;
  border-left: 1px solid var(--btn-cream-a28);
  border-radius: 0;
  background: none;
  color: rgba(244, 239, 226, .8);
  transition: background .2s ease, color .2s ease;
}
.tiers .tier:first-child { border-left: 0; }
.tiers .tier:hover { background: var(--btn-cream-a06); color: var(--btn-cream); }
.tiers .tier[aria-pressed="true"] {
  background: var(--gold);
  color: var(--btn-ink);
  box-shadow: none;
}
/* stake.css colours these gold; on a gold fill that is invisible */
.tiers .tier[aria-pressed="true"] b { color: var(--btn-ink); }
.tiers .tier[aria-pressed="true"] i { color: rgba(22, 19, 15, .72); }
.tiers .tier b { font-size: .6875rem; letter-spacing: .06em; }

/* --------------------------------------------------------------------------
   Disabled — 35% ink wash across every family
   -------------------------------------------------------------------------- */
.btn[disabled],
.btn[aria-disabled="true"],
.tier[disabled] {
  background: none !important;
  background-image: none !important;
  border: 1px solid rgba(244, 239, 226, .16) !important;
  color: var(--btn-wash) !important;
  cursor: not-allowed;
  filter: none !important;
  box-shadow: none !important;
}
.btn[disabled]::before, .btn[disabled]::after,
.btn[aria-disabled="true"]::before, .btn[aria-disabled="true"]::after { animation: none !important; content: none !important; }
.btn--gold[disabled], .btn--cta[disabled], .btn--alarm[disabled] { clip-path: var(--chamfer); }

/* --------------------------------------------------------------------------
   Motion budget
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .btn--cta::before, .btn--cta::after, .term-btn::after { animation: none !important; }
  .btn--cta::before { opacity: .18; }
  .btn--bracket { transition: none; }
}

/* --------------------------------------------------------------------------
   Header row — every control on the same 44px rail (kit rule: >= 44px)
   -------------------------------------------------------------------------- */
.term-btn, .act-btn, .menu-btn { min-height: 44px; }

/* --------------------------------------------------------------------------
   Header pill — the address must never wrap. A wrapped address grows the pill
   past the 44px rail and breaks the header row (caught at 390px).
   -------------------------------------------------------------------------- */
.chip, .chip__addr, .nav__left, .nav__right { white-space: nowrap; }
.chip { flex: none; }

/* Very narrow: the pill keeps its label and its copy action, but the address
   itself has no room beside the logo, terminal, START and the CTA. */
@media (max-width: 600px) {
  .chip__addr { display: none !important; }
}

/* --------------------------------------------------------------------------
   START — the gold pill (kit card 04).
   The left cluster now carries both halves of the palette: START in gold,
   terminal in teal, so the two controls read as distinct instruments instead
   of one repeated chip. menu.css hardcodes jade into the lamp KEYFRAMES, so
   the glow needs its own gold animation, not just a colour override.
   -------------------------------------------------------------------------- */
/* A single chamfered corner instead of a rounded rectangle: the panel-cut
   reads as machined and it is the ONE shape in the row that is cut that way,
   so START is identifiable by silhouette alone. clip-path clips a border away,
   so the 1px frame is drawn as an inset ring instead of a border. */
.act-btn {
  border-radius: 0;
  border: 0;
  clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 0 100%);
  box-shadow: inset 0 0 0 1px rgba(196, 168, 98, .40);
  background: rgba(196, 168, 98, .08);
  color: var(--gold-bright);
}
/* An inset box-shadow draws a RECTANGULAR ring, and the clip-path then cuts a
   10px notch straight through it — measured, the diagonal came back as a naked
   edge with the ring only on the four straight sides. This hairline closes the
   cut: a 1px rule of length 10*sqrt(2), started at the notch and rotated onto
   it, nudged half a pixel down the inward normal so the parent's clip-path
   cannot shave it off. `position: relative` has to be restated at ID strength
   because v3.css pins `.nav__left #act-open` to static for the desktop grid;
   relative with no offsets moves nothing. */
.nav__left #act-open,
.act-btn { position: relative; }
.act-btn::after {
  content: "";
  position: absolute;
  left: calc(100% - 10.5px);
  top: .5px;
  width: 14.14px;
  height: 1px;
  transform-origin: 0 0;
  transform: rotate(45deg);
  background: rgba(196, 168, 98, .40);
  pointer-events: none;
}
.act-btn:hover,
.act-btn[aria-expanded="true"] {
  box-shadow: inset 0 0 0 1px var(--gold);
  background: rgba(196, 168, 98, .16);
  color: #e8d49a;
}
.act-btn:hover::after,
.act-btn[aria-expanded="true"]::after { background: var(--gold); }
@keyframes sbLampGold {
  0%, 100% { opacity: 1;   box-shadow: 0 0 6px 0 rgba(212, 184, 114, .5); }
  50%      { opacity: .35; box-shadow: 0 0 0 0 rgba(212, 184, 114, 0); }
}
/* CASCADE: this block MUST stay below sbLampGold above AND below menu.css's
   `act-lamp` idle animation (menu.css loads first). At rest the lamp is lit and
   completely still — it pulses only while the control is hovered, and sits
   solid-with-a-halo while the panel is open. */
.act-btn__lamp {
  background: var(--gold-bright);
  box-shadow: 0 0 6px 0 rgba(212, 184, 114, .5);
  animation: none;
  opacity: 1;
}
.act-btn:hover .act-btn__lamp,
.act-btn:focus-visible .act-btn__lamp {
  animation: sbLampGold 1.9s ease-in-out infinite;
}
.act-btn[aria-expanded="true"] .act-btn__lamp {
  animation: none;
  box-shadow: 0 0 8px 1px rgba(212, 184, 114, .55);
}
@media (prefers-reduced-motion: reduce) {
  .act-btn__lamp { animation: none; box-shadow: 0 0 6px 0 rgba(212, 184, 114, .5); }
}

/* --------------------------------------------------------------------------
   START menu — opens BELOW its own button (operator 2026-09-11).
   menu.js sets left/top from the button's measured rect; these two keep the
   growth animation and shadow pointing the right way now that the panel is
   anchored left rather than pinned to the right gutter.
   -------------------------------------------------------------------------- */
.actpanel { transform-origin: top left; }
/* With every group expanded the panel runs to ~520px. Anchored below the
   header that overflows a short viewport with no way to reach the lower
   items, so cap it and let it scroll inside itself. */
.actpanel { max-height: calc(100vh - 5.5rem); overflow-y: auto; overscroll-behavior: contain; }

/* --------------------------------------------------------------------------
   Tap targets in the shared chrome. The kit's floor is 44px; the footer brand
   link and the lab card's X icon were 26px and 30px on every page.
   -------------------------------------------------------------------------- */
.foot__brand .brand { min-height: 44px; }
/* the mobile nav logo is a 32px image; the link around it is the home target */
.nav .brand { min-height: 44px; display: inline-flex; align-items: center; }

/* v3.css sets `.foot__inner > .labcard .labcard__x` to 30px, which outranks a
   bare .labcard__x. Match its specificity to reach the tap-target floor.
   Lives here, not pages.css, so the homepage and stake page get it too. */
.foot__inner > .labcard .labcard__x { width: 40px; height: 40px; }

/* --------------------------------------------------------------------------
   The memory cell's tree block.

   v3.css gives `.cell--multi .tree { flex: 1 1 auto }`, so inside the 2x2
   tall cell the box grew to fill the column while its five rows stayed at the
   top — 217px of dead space at 1440. align-self does NOT fix this: in a
   column flex container that is the cross (horizontal) axis. flex-grow is
   the one that controls height here. v3.css already zeroes it below 1024,
   which is why the problem only showed on wide screens.
   -------------------------------------------------------------------------- */
.cell--multi .tree,
.cell .tree {
  flex: 0 0 auto;
  align-content: start;
  padding-bottom: 20px;
}

/* The memory cell spans 2x2, so its height was dictated by the two rows the
   small cells define (370 + 346 + gap = 734) rather than by its own content
   (~530). Let it size to itself and sit at the top of its grid area. */
.bento .cell--tall { align-self: start; }

/* ==========================================================================
   HEADER / FOOTER HUD
   A light instrument frame: taller header, hairline rules, a tick rail and a
   fine scanline texture. Built entirely from pseudo-elements so no markup
   changes are needed and any page carrying the shared chrome gets it.
   ========================================================================== */
:root {
  /* the fixed nav's real height, published so page padding can clear it
     instead of hardcoding a guess (it grew 62px -> 89px with the HUD) */
  --nav-h: 92px;
  --hud-rule:  rgba(244, 239, 226, .09);
  --hud-tick:  rgba(54, 216, 202, .30);
  --hud-sheen: rgba(196, 168, 98, .05);
}

/* ── the bar itself ──────────────────────────────────────────────────── */
.nav { position: fixed; }
/* ONE OWNER for the bar's vertical rhythm (2026-09-12).
   Four rules across three files were competing to set padding-block on this
   element, so the real bar height drifted away from --nav-h depending on which
   media query happened to be live. The height is now stated once, directly:
   min-height carries it and padding contributes nothing.
   --nav-h - 2px, because .nav adds a 1px border-bottom and .nav__progress adds
   a 1px strip below this element, which together make up the published height. */
.nav__inner {
  position: relative;
  padding-block: 0;
  min-height: calc(var(--nav-h) - 2px);
}

/* texture: fine scanlines plus a warm sheen falling from the top edge.
   Kept very low alpha — it should register as surface, not pattern. */
.nav::before,
.foot::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background:
    repeating-linear-gradient(0deg,
      rgba(244, 239, 226, .022) 0 1px,
      transparent 1px 3px),
    linear-gradient(180deg, var(--hud-sheen), transparent 58%);
}
.foot::before { background:
    repeating-linear-gradient(0deg,
      rgba(244, 239, 226, .018) 0 1px,
      transparent 1px 3px),
    linear-gradient(0deg, var(--hud-sheen), transparent 46%); }

/* tick rail — the same vocabulary as the status bar's velocity meter.
   Masked at both ends so it fades out rather than butting the viewport. */
.nav::after,
.foot::after {
  content: "";
  position: absolute; left: 0; right: 0;
  height: 5px;
  pointer-events: none;
  background: repeating-linear-gradient(90deg,
    var(--hud-tick) 0 1px, transparent 1px 14px);
  opacity: .55;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
.nav::after  { bottom: 1px; }      /* sits above .nav__progress */
.foot::after { top: 0; transform: scaleY(-1); }

/* corner brackets: the frame closes on itself at both ends */
.nav__inner::before,
.nav__inner::after {
  content: "";
  position: absolute; top: .55rem; bottom: .55rem;
  width: 9px;
  pointer-events: none;
  border-top: 1px solid var(--hud-rule);
  border-bottom: 1px solid var(--hud-rule);
}
.nav__inner::before { left: .5rem;  border-left: 1px solid var(--hud-rule); }
.nav__inner::after  { right: .5rem; border-right: 1px solid var(--hud-rule); }

/* the bar keeps a visible edge even before it is stuck */
.nav { border-bottom: 1px solid var(--hud-rule); }
.nav.is-stuck { border-bottom-color: var(--border); }

/* content sits above the texture and the brackets */
.nav__left, .nav__right, .nav__inner > .chip { position: relative; z-index: 2; }
.foot__inner, .foot__legal { position: relative; z-index: 2; }
.foot { position: relative; }

@media (max-width: 1080px) {
  :root { --nav-h: 100px; }
  /* padding-block is NOT set here — the single owner above carries the height */
  .nav__inner::before, .nav__inner::after { display: none; }
}

/* ==========================================================================
   ACCESSIBILITY REMEDIATION (audit 2026-09-11)
   ========================================================================== */

/* --text-faint (#5d6478) measured 3.2-3.4:1 on the dark ground — it fails the
   4.5:1 body minimum, and every use is 10-12px regular weight so the 3:1
   large-text allowance does not apply. #7d8794 keeps the same recessive role
   at 5.5:1. Overridden here rather than in style.css so deadguy's base file
   stays byte-for-byte what he shipped. */
:root { --text-faint: #7d8794; }

/* The stake amount field had `outline: none` and no replacement, so keyboard
   users got NO focus indication on the one input that sets a transaction
   amount. Every other control already shows a ring. */
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
#amount:focus {
  outline: 2px solid var(--gold-bright, #d4b872);
  outline-offset: 2px;
}

/* Footer social icons were 40px; the kit floor is 44px. */
.foot__social a,
.foot__social .foot__menu { width: 44px; height: 44px; }

/* ─────────── narrow header: nothing may refuse to shrink ───────────
   At 320px the bar intermittently measured 344px wide — a race where a child
   was briefly at its unshrunk width and the flex container grew with it. Flex
   and grid children default to min-width:auto, so they refuse to go below
   their content and push the container out instead of clipping. Zero those
   minimums and cap the chip, so the bar can never exceed the viewport
   whatever order things render in. */
@media (max-width: 1080px) {
  .nav__inner, .nav__left, .nav__right { min-width: 0; }
  .nav__inner > * { min-width: 0; }
  .nav__inner > .chip { max-width: 46vw; overflow: hidden; }
  .nav__left .term-btn__text, .nav__left .act-btn__text { min-width: 0; }
}

/* The bar's own gap and padding, not its contents, were the overflow at 320px:
   five controls total 232px but four gaps at clamp(1rem,3vw,2.5rem) plus the
   wrap padding added ~104px more, for 336-344px in a 320px viewport. Tighten
   the spacing rather than shrink the controls further; they are already at the
   44px tap-target floor. */
@media (max-width: 430px) {
  .nav__inner { gap: .4rem; padding-inline: .55rem; column-gap: .4rem; }
}

/* Belt. The ACTUAL cause of the 320px overflow turned out to be #read-msg in
   the readbar, not the nav (the nav is position:fixed with right:0, so it
   merely stretched to a document already widened by something else). This
   stays as a cheap guarantee. The bar is a
   fixed-position strip and the menu panel and terminal are appended to <body>,
   NOT inside it, so clipping here cannot hide anything. This makes a
   horizontally scrolling page structurally impossible whatever transient
   width a child reports during load. */
.nav { overflow: hidden; }

/* ==========================================================================
   MOBILE HEADER — one shape language (operator 2026-09-12)

   The bar carried four shapes (8px rect, 6px rect, 999px pill, chamfered
   polygon), three colour treatments and widths of 27/44/80/44. Two teal
   outlines sat side by side and a solid gold chamfer shouted over all of it.
   START was a 27px box holding a bare dot.

   Below 560px every control becomes the same quiet 44px square: one radius,
   one hairline border, one near-transparent ground. Colour is removed from
   the resting state and kept for meaning — the live lamp, and a single gold
   accent on the wallet action. Identity is carried by the logo, not by five
   competing chips.
   ========================================================================== */
@media (max-width: 560px) {
  .nav__inner { gap: .45rem; column-gap: .45rem; }

  /* the shared resting state */
  .nav__left .act-btn,
  .nav__left .term-btn,
  .nav__inner > .chip,
  .nav__right #btn-connect,
  .nav__right .btn--gold {
    height: 44px; min-height: 44px;
    border-radius: 11px;
    border: 1px solid rgba(244, 239, 226, .13);
    background: rgba(244, 239, 226, .035);
    box-shadow: none;
    clip-path: none;                 /* drop the chamfer at this size */
    color: var(--nav-ink, #e0e2e8);
    padding: 0 .7rem;
    transition: border-color .18s ease, background .18s ease, color .18s ease;
  }

  /* square icon buttons */
  .nav__left .act-btn,
  .nav__left .term-btn,
  .nav__right #btn-connect { width: 44px; padding: 0; display: inline-grid; place-items: center; }

  /* START: a bare pulsing dot is not an affordance at this size. Show a real
     menu glyph, and keep the lamp as a small live tick beside it. */
  .nav__left .act-btn { position: relative; }
  /* the chamfer is dropped at this size, so the hairline that closes its cut
     has nothing to close — it would draw a stray diagonal across the square */
  .nav__left .act-btn::after { display: none; }
  .nav__left .act-btn .act-btn__lamp {
    position: absolute; top: 9px; right: 9px;
    width: 5px; height: 5px;
  }
  .nav__left .act-btn::before {
    content: "";
    width: 15px; height: 11px;
    background:
      linear-gradient(currentColor, currentColor) 0 0   / 15px 1.5px no-repeat,
      linear-gradient(currentColor, currentColor) 0 50%  / 15px 1.5px no-repeat,
      linear-gradient(currentColor, currentColor) 0 100% / 10px 1.5px no-repeat;
    opacity: .8;
  }

  /* the terminal keeps its sigil, loses the loud teal frame */
  .nav__left .term-btn .term-btn__glyph { color: inherit; opacity: .85; font-size: .8125rem; }
  .nav__left .term-btn::after { display: none; }   /* the blinking caret is desktop detail */

  /* the token chip: label only, quiet, no pill */
  .nav__inner > .chip { gap: .4rem; }
  .nav__inner > .chip .chip__label { color: var(--gold-bright, #d4b872); font-size: .6875rem; letter-spacing: .1em; }
  .nav__inner > .chip .chip__pulse { width: 5px; height: 5px; }
  .nav__inner > .chip .chip__icon { width: 13px; height: 13px; opacity: .5; }

  /* the one accent: the wallet action reads gold without a solid fill */
  .nav__right #btn-connect,
  .nav__right .btn--gold {
    border-color: rgba(196, 168, 98, .42);
    background: rgba(196, 168, 98, .10);
    color: var(--gold-bright, #d4b872);
  }
  .nav__right .btn--gold { width: auto; padding: 0 .85rem; font-size: .6875rem; }

  /* pressed / open states are where colour returns */
  .nav__left .act-btn[aria-expanded="true"],
  .nav__left .term-btn[aria-expanded="true"],
  .nav__left .act-btn:active,
  .nav__left .term-btn:active,
  .nav__inner > .chip:active { border-color: var(--instr, #36d8ca); background: rgba(54, 216, 202, .12); color: var(--instr, #36d8ca); }
  .nav__right #btn-connect:active { border-color: var(--gold); background: rgba(196, 168, 98, .2); }
}

/* ==========================================================================
   INTERACTION SPEED (operator 2026-09-12: "buttons/menus open clean and snappy")

   Measured on a 4x-throttled phone: the START menu took 313ms from click to
   fully painted, 200ms of which was its own open animation on a decelerating
   curve. Under ~150ms a control feels instant; past ~250ms it feels like it
   is thinking. Openings are cut to 130ms on a fast-out curve, and the panel
   animates opacity and transform ONLY, which stay on the compositor.

   Closing stays quick but is not animated at all: nobody waits to watch a
   thing leave.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  .actpanel { animation: actin 130ms cubic-bezier(.2,.9,.3,1) both; }
  @keyframes actin {
    from { opacity: 0; transform: translateY(-4px) scale(.985); }
    to   { opacity: 1; transform: none; }
  }
}

/* the whole chrome responds faster to press/hover */
:root { --fast: 120ms; --base: 190ms; }

/* a press should register instantly, before any colour transition resolves */
.btn:active, .act-btn:active, .term-btn:active,
.chip:active, .addr__btn:active, .tier:active,
.foot__social a:active, .foot__menu:active {
  transition-duration: 0ms;
  transform: translateY(1px);
}

/* hint the compositor for the two panels that open most */
.actpanel, .term__win { will-change: opacity, transform; }


/* --------------------------------------------------------------------------
   STAKING PORTAL — header CTA (operator 2026-09-12)
   Bracket ghost (kit 03) as the base, with a brushed-metal label.

   Why the label is a <span>: the metal is a gradient clipped to the glyphs,
   which needs `color: transparent` on the text. The brackets are ::before /
   ::after on the <a>, and pseudo-elements INHERIT color — a transparent <a>
   would take the brackets out with it. So the metal is scoped to .btn__t and
   the brackets keep their own gold.

   The sheen only runs on hover/focus. An idle infinite animation on clipped
   text repaints the glyphs every frame, and this button sits in a fixed header
   on every page, so idle cost has to be zero.
   -------------------------------------------------------------------------- */
.btn--portal {
  background: none;
  border: 0;
  border-radius: 0;
  padding-inline: .45rem;
  font-weight: 600;
  letter-spacing: .14em;
  overflow: visible;
  transition: letter-spacing .28s var(--ease, ease);
}
.btn--portal::before,
.btn--portal::after {
  color: var(--gold);
  opacity: .8;
  display: inline-block;
  transition: transform .28s ease, opacity .28s ease;
}
.btn--portal::before { content: "["; margin-right: .6em; }
.btn--portal::after  { content: "]"; margin-left:  .6em; }

/* RANK (2026-09-12): this is the only destination in the right cluster and it
   was the quietest thing in the bar. Up one step in size and tracking, and
   underscored with a static gold rule that fades to nothing on the right — a
   drawn line, not an animation. Placed ABOVE the narrow-header ladder below so
   the 900px / 560px steps still win their tracking back. */
.btn--portal { font-size: .75rem; letter-spacing: .16em; }
.btn--portal .btn__t { position: relative; }
.btn--portal .btn__t::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -6px; height: 1px;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold-bright) 60%, transparent);
  opacity: .75;
}
.btn--portal:hover .btn__t::after { opacity: 1; }

/* brushed metal: hard stops read as milled facets, not a soft fade */
.btn--portal .btn__t {
  background-image: linear-gradient(
    100deg,
    #8a6f3a 0%, #c2a463 14%, #f4e3b4 26%, #fffaf0 33%,
    #e2cd93 41%, #a98c4d 55%, #d9c286 70%, #fff3d0 78%,
    #c9ab60 88%, #8a6f3a 100%
  );
  background-size: 230% 100%;
  background-position: 0% 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
/* no background-clip support: plain gold, never invisible text */
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .btn--portal .btn__t { color: var(--gold-bright, #d4b872); -webkit-text-fill-color: currentColor; }
}

.btn--portal:hover,
.btn--portal:focus-visible { letter-spacing: .2em; }
.btn--portal:hover::before, .btn--portal:focus-visible::before { transform: translateX(-3px); opacity: 1; }
.btn--portal:hover::after,  .btn--portal:focus-visible::after  { transform: translateX(3px);  opacity: 1; }
.btn--portal:active { transform: translateY(1px); }

@media (prefers-reduced-motion: no-preference) {
  .btn--portal:hover .btn__t,
  .btn--portal:focus-visible .btn__t { animation: sbPortalSheen .9s ease-out; }
}
@keyframes sbPortalSheen {
  from { background-position: 100% 0; }
  to   { background-position: 0% 0; }
}

/* Narrow headers: drop the tracking and the bracket margins before the label
   itself is ever at risk. "Staking Portal" is 3.5x the width of "stake". */
@media (max-width: 900px) {
  .btn--portal { letter-spacing: .08em; padding-inline: .25rem; }
  .btn--portal::before { margin-right: .35em; }
  .btn--portal::after  { margin-left:  .35em; }
}
@media (max-width: 560px) {
  .btn--portal { letter-spacing: .04em; }
  .btn--portal::before, .btn--portal::after { display: none; }
}

/* ==========================================================================
   IDLE SILENCE — the header holds still (2026-09-12)

   The bar ran three infinite animations at rest on every page: a blinking
   terminal caret, a pulsing START lamp and a pulsing chip dot. Three competing
   heartbeats in a fixed element that never leaves the viewport, none of them
   reporting anything. Motion is now reserved for two things only: a control
   that is being addressed, and reading position.

   The per-control rules live with their components above. What follows is the
   scroll-driven progress bar, the focus dim, the left-cluster spacing and the
   motion budget.
   ========================================================================== */

/* ── reading position, driven by the scroller itself ──────────────────────
   A scroll-driven animation is not an idle animation: it advances only as the
   page moves, off the main thread, and it is exactly correct at every position
   without a scroll listener. The JS width-writer in script.js keeps running
   underneath as the fallback for browsers without scroll timelines — harmless
   here, since width is pinned and the bar is driven by transform instead. */
@supports (animation-timeline: scroll()) {
  .nav__progress {
    width: 100% !important;
    transform: scaleX(0);
    transform-origin: 0 50%;
    transition: none;
    animation: navProg linear both;
    animation-timeline: scroll(root);
  }
  @keyframes navProg {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }
}

/* ── focus dim: while the menu is open, the rest of the bar steps back ──── */
@media (prefers-reduced-motion: no-preference) {
  .nav:has(.act-btn[aria-expanded="true"]) :is(.nav__right, .nav__inner > .chip) {
    opacity: .55;
    transition: opacity 160ms var(--ease);
  }
}

/* ── left cluster: the logo needs air before the instruments start ─────── */
@media (min-width: 1081px) {
  .nav__left .brand { margin-right: .75rem; }
}

/* ── motion budget: the addressed states are motion too ────────────────── */
@media (prefers-reduced-motion: reduce) {
  .term-btn:hover::after, .term-btn:focus-visible::after,
  .term-btn:hover .term-btn__glyph, .term-btn:focus-visible .term-btn__glyph,
  .act-btn:hover .act-btn__lamp, .act-btn:focus-visible .act-btn__lamp,
  .chip:hover .chip__pulse, .chip:focus-visible .chip__pulse { animation: none; }
}


/* --------------------------------------------------------------------------
   TERMINAL BUTTON — white→teal gradient outline (operator 2026-09-12)

   The demotion pass stripped this to a grey hairline. Teal returns, but as a
   RAKED GRADIENT rather than a flat border: white catching the top-left edge,
   falling to full teal through the bottom-right. Same "light across a machined
   edge" language as the Staking Portal metal, so the bar reads as one system.

   Why a masked pseudo-element and not `border-image` or the padding-box trick:
   border-image ignores border-radius, and the padding-box/border-box gradient
   trick needs an OPAQUE inner layer — which would punch a solid patch into a
   header that is deliberately translucent over the hero video. The mask
   composite draws a true 1px ring and leaves the interior genuinely empty.

   inset:-1px (not 0) because an absolutely positioned child is laid out against
   the PADDING box; -1px pushes the ring back out onto the border box so the
   control's geometry is untouched and it still measures 44px.

   No animation: the ring is static at rest and only changes opacity, which is
   compositor-only. The idle-silence guarantee holds.
   -------------------------------------------------------------------------- */
.term-btn { position: relative; border-color: transparent; }
.term-btn::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(135deg,
    rgba(255, 255, 255, .70) 0%,
    rgba(255, 255, 255, .34) 22%,
    var(--instr, #36d8ca) 58%,
    rgba(54, 216, 202, .34) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: .72;
  transition: opacity .18s var(--ease, ease);
  pointer-events: none;
}
.term-btn:hover::before,
.term-btn:focus-visible::before { opacity: 1; }

/* No mask-composite: fall back to a flat teal border rather than a filled box. */
@supports not ((-webkit-mask-composite: xor) or (mask-composite: exclude)) {
  .term-btn { border-color: var(--instr-a40, rgba(54,216,202,.40)); }
  .term-btn::before { display: none; }
}


/* --------------------------------------------------------------------------
   MOBILE HEADER ALIGNMENT (operator bug report 2026-09-12)

   Reported as "the chip and the portal sit ~8px too high". Measured at 390px,
   the truth is the reverse: .chip and .btn--portal are flex children of
   .nav__inner (align-items:center) and sit at mid 49.0 — dead centre of the
   98px bar. They are the only two that are correct.

   .nav__left carries `display:flex; align-items:center` ONLY inside v3.css's
   wide-viewport block. Below it the element falls back to `display:block`, so
   brand / START / terminal become INLINE boxes on `vertical-align: baseline`.
   All three are 44px tall and all three land on a different line:
     brand 44.7 · START 52.7 · terminal 53.3   (centre is 49.0)
   Baseline alignment, not a margin — which is why no single nudge fixes it and
   why the brand was 8.6px off the terminal while nobody was looking.

   So the fix is to centre the left cluster at EVERY width rather than push the
   two correct elements off-centre to meet it. All five then share mid 49.0.
   -------------------------------------------------------------------------- */
.nav__left {
  display: flex;
  align-items: center;
  gap: .5rem;
  min-width: 0;
}

/* The copy affordance is the whole point of the pill; hiding it on mobile left
   a tappable control with no sign it does anything. style.css drops it at
   <=720px, so it is restored here at a smaller size. */
@media (max-width: 720px) {
  .nav__inner > .chip .chip__icon {
    display: block;
    width: 12px;
    height: 12px;
    opacity: .55;
    flex: none;
  }
}
