/* Buttons, fields, estimator, language picker, the walkthrough. */

/* --- buttons -------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  height: 36px;
  padding-inline: var(--s4);
  border-radius: var(--radius-pill);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: var(--track-tight);
  white-space: nowrap;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn--accent { background: var(--accent); color: var(--on-accent); }
/* The reference lights its centrepiece icon with an ambient halo on the same
   hue. A hover-only glow on the one accent button is the same device kept to
   an interaction state rather than a resting one, so it still answers to
   D-005's no-resting-shadow rule (D-019 follow-up). */
.btn--accent:hover {
  background: color-mix(in srgb, var(--accent) 84%, var(--ink));
  color: var(--on-accent);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 16%, transparent);
}
.btn--ghost { border: 1px solid var(--rule-strong); color: var(--ink-2); }
.btn--ghost:hover { border-color: var(--ink); color: var(--ink); }
.btn--wide { width: 100%; height: 44px; margin-top: var(--s4); }

/* Circular, ringed badge — the reference's icon treatment throughout (the
   achieve-goals row, the multi-channel hub) is a perfect circle with a thin
   border, not a square chip. Applied here to the one icon-only control the
   page already has (D-018 follow-up). */
.iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 1px solid transparent;
  color: var(--ink-2);
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.iconbtn:hover { color: var(--ink); background: var(--raised); border-color: var(--rule-strong); }
.iconbtn__moon { display: none; }
:root[data-theme='light'] .iconbtn__sun { display: none; }
:root[data-theme='light'] .iconbtn__moon { display: block; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) .iconbtn__sun { display: none; }
  :root:not([data-theme]) .iconbtn__moon { display: block; }
}

.menubtn__bars { display: grid; gap: 4px; width: 16px; }
.menubtn__bars i { display: block; height: 1.5px; background: currentColor; }

/* --- language picker ------------------------------------------------------ */
.langpick { position: relative; }
.langpick__btn {
  display: inline-flex; align-items: center; gap: var(--s2);
  height: 34px; padding-inline: var(--s3);
  border-radius: var(--radius);
  font-size: var(--fs-small); font-weight: 500; color: var(--ink-2);
}
.langpick__btn:hover { color: var(--ink); background: var(--raised); }
.langpick__btn svg { transition: transform var(--dur-fast) var(--ease); }
.langpick__btn[aria-expanded='true'] svg { transform: rotate(180deg); }
.langpick__menu {
  position: absolute; top: calc(100% + 6px); right: 0;
  min-width: 184px; z-index: 10;
  list-style: none; margin: 0; padding: var(--s1);
  background: var(--raised);
  /* The last drop shadow on the page, removed. D-005 says depth comes from
     hairlines; an overlay still has to separate from what it covers, so it
     takes a doubled hairline — a --rule-strong border over a --ground ring —
     instead of a blur that is invisible on a #000 ground anyway. */
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-card);
  outline: 3px solid var(--ground);
}
.langpick__menu:focus-visible { outline: 3px solid var(--ground); }   /* the list itself never draws a ring */
.langpick__opt {
  display: flex; align-items: center; gap: var(--s3);
  width: 100%; min-height: 34px; padding: 0 var(--s2) 0 var(--s3);
  border-radius: var(--radius);
  font-size: var(--fs-small); text-align: left; color: var(--ink);
  transition: background var(--dur-fast) var(--ease);
}
.langpick__opt > span:first-child { flex: 1; min-width: 0; }
/* Hover and keyboard focus are one state: the row lifts to --field (the menu
   is already --raised, so a --raised hover was invisible — D-022). The focus
   ring sits inside the row, not 3px outside it where it overran the menu's
   4px padding and read as a box drawn over the list. */
.langpick__opt:hover:not([aria-disabled='true']),
.langpick__opt:focus-visible { background: var(--field); }
.langpick__opt:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.langpick__opt[aria-disabled='true'] { color: var(--ink-3); cursor: not-allowed; }
.langpick__check { flex: none; width: 12px; height: 12px; color: var(--accent-text); visibility: hidden; }
.langpick__opt[aria-selected='true'] .langpick__check { visibility: visible; }
.langpick__soon {
  flex: none; margin-left: auto; padding: 2px 6px;
  font-size: 0.625rem; line-height: 1.2; letter-spacing: var(--track-eyebrow); text-transform: uppercase;
  color: var(--ink-3); border: 1px solid var(--rule); border-radius: var(--radius-pill);
}

/* --- URL bar ---------------------------------------------------------------
   The one control the page is built around, and — per the competitor pass —
   the one lane our closest analogue abandoned: same.new's homepage has no URL
   field, no clone affordance and no clone wording anywhere on it. So this is
   the loudest object on the page.

   Two changes of substance. (1) The four hard-coded greys that used to live
   here (#2a2a2f / #45454c / #eeeef1 / #d7d7de) are gone; they are now the
   --field and --field-rule tokens, so a palette change reaches them. (2) It is lit from behind
   rather than dropped-shadowed: a blurred accent bloom on a pseudo-element,
   Replit's trick (::before{inset:-10px; filter:blur(50px)}), which says
   "live" instead of "floating" and prints the accent without printing a
   coloured rectangle. See D-005 and D-010. */
.urlbar__field { position: relative; isolation: isolate; }
.urlbar__field::before {
  content: '';
  position: absolute; inset: -14px;
  z-index: -1;
  border-radius: inherit;
  background: radial-gradient(60% 120% at 50% 50%,
              color-mix(in srgb, var(--accent) 26%, transparent), transparent 70%);
  filter: blur(26px);
  opacity: 0.7;
  transition: opacity var(--dur) var(--ease);
  pointer-events: none;
}
.urlbar__field:focus-within::before { opacity: 1; }

.urlbar__strip {
  display: flex; align-items: center; gap: var(--s3);
  height: 60px; padding: 7px 8px;
  background: var(--field);
  border: 1px solid var(--field-rule);
  border-radius: var(--radius-pill);
  box-shadow: inset 0 1px 0 0 var(--rule-strong);
  transition: border-color var(--dur-fast) var(--ease);
}
/* Light the whole control on focus instead of only ringing the input —
   v0 does this with a one-step border darkening and no shadow. The input
   keeps its own :focus-visible outline underneath for keyboard users. */
.urlbar__field:focus-within .urlbar__strip { border-color: var(--ink-3); }
.urlbar__input {
  flex: 1; min-width: 0; height: 40px; padding-inline: 13px;
  background: transparent; border: 0; border-radius: var(--radius-pill);
  font-size: var(--fs-body);
}
.urlbar__input::placeholder { color: var(--ink-3); }
.urlbar__input:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.urlbar__submit {
  flex: none; height: 40px; padding-inline: var(--s5);
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--on-accent);
}
.urlbar__submit:hover {
  background: color-mix(in srgb, var(--accent) 84%, var(--ink));
  color: var(--on-accent);
}

/* --- ranges --------------------------------------------------------------- */
.field__range {
  -webkit-appearance: none; appearance: none;
  height: 18px; background: transparent; cursor: pointer;
  width: 100%;
}
.field__range::-webkit-slider-runnable-track {
  height: 2px; background: var(--rule-strong); border-radius: 2px;
}
.field__range::-moz-range-track {
  height: 2px; background: var(--rule-strong); border-radius: 2px;
}
.field__range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 12px; height: 12px; margin-top: -5px;
  background: var(--accent); border-radius: 50%;
}
.field__range::-moz-range-thumb {
  width: 12px; height: 12px; border: 0;
  background: var(--accent); border-radius: 50%;
}

/* --- estimator -------------------------------------------------------------
   Two halves of one instrument: what comes back on the left, what it costs on
   the right, divided by a single hairline rather than by a gap. Both halves
   carry the same padding so the divider reads as a rule through one object,
   the way Firecrawl's plan columns share single hairlines instead of floating
   as separate cards. */
.est__quote {
  padding: var(--s6);
  border-right: 1px solid var(--rule);
  min-width: 0;
}
.est__breakdown {
  padding: var(--s6);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--s5);
  min-width: 0;
}

/* The host readout. It is the echo of what you typed, so it is set in the
   monospaced-feeling tabular register the rest of the panel uses, and it
   keeps the accent — this row is the only place the visitor's own input
   appears on the page. */
.est__site {
  min-height: 24px;
  display: flex; align-items: center;
  margin-bottom: var(--s5);
  color: var(--ink);
  font-weight: 600;
  font-size: var(--fs-small);
  letter-spacing: 0;
  word-break: break-all;
}
.est__site::before {
  content: '';
  flex: none;
  width: var(--dot-pitch); height: var(--dot-pitch);
  margin-right: var(--s3);
  border-radius: var(--radius);
  background: var(--accent);
}

/* the spec: what the prototype contains, frontend and backend.
   Ruled rows, not a gapped list — Base44's hairline row list. The rule
   carries the eye across a row whose right half is a long dot-separated
   string, which is exactly where the old gapped version lost people. */
.est__speclabel { margin-bottom: var(--s2); }
.spec { margin: 0; display: block; font-size: var(--fs-small); }
.spec div {
  display: flex; gap: var(--s4);
  padding-block: var(--s3);
  border-top: 1px solid var(--rule);
}
.spec dt { flex: none; width: 5.5em; color: var(--ink-3); }
.spec dd { margin: 0; font-variant-numeric: tabular-nums; }

.est__price {
  font-size: clamp(2.75rem, 1.5rem + 4vw, 4.25rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--track-display);
  font-variant-numeric: tabular-nums;
  color: var(--accent-text);
}
.est__sym { font-family: var(--serif); font-weight: 400; font-size: 0.5em; vertical-align: 0.42em; margin-right: 0.06em; }
/* Honesty rule 3 says the price is labelled an estimate. Until now nothing on
   the page actually said so — the word only existed in class names. It says so
   here, in the same block as the number. */
.est__note { margin-top: var(--s3); }
.est__breakdown .btn--wide { margin-top: 0; }

/* --- the estimate before a URL: same rows, no numbers ---------------------
   The host row drops its accent dot while it holds no site, so the marker
   only ever appears next to something the visitor actually typed. */
.est__result[data-empty] .est__site { min-height: 0; margin-bottom: 0; }
.est__result[data-empty] .est__site::before { display: none; }
.est__result[data-empty] .est__price,
.est__result[data-empty] .spec dd { color: var(--ink-3); }
/* At display weight the em-dash reads as a redaction bar, so the placeholder
   price stays quiet and the real number arrives loud. */
.est__result[data-empty] .est__price {
  font-size: clamp(2rem, 1.4rem + 2vw, 2.75rem);
  font-weight: 400;
}

/* --- auth pages ----------------------------------------------------------- */
.authwrap { min-height: calc(100vh - var(--topbar-h)); display: grid; place-items: center; padding-block: var(--s8); }
.authcard { width: 100%; max-width: 400px; }
.authcard h1 { font-size: clamp(1.75rem, 1.2rem + 2vw, 2.5rem); margin-bottom: var(--s3); }
.authcard .lead { margin-bottom: var(--s6); font-size: var(--fs-body); }
.authcard label { display: block; font-size: var(--fs-small); font-weight: 600; margin-bottom: var(--s2); }
.authcard input[type='email'], .authcard input[type='password'] {
  width: 100%; height: 40px; margin-bottom: var(--s5);
  padding-inline: var(--s4);
  /* the same field surface as the URL bar, so the two forms read as one
     product rather than as a marketing page plus a login page */
  background: var(--field);
  border: 1px solid var(--field-rule);
  border-radius: var(--radius);
  font-size: var(--fs-small);
  transition: border-color var(--dur-fast) var(--ease);
}
.authcard input[type='email']:focus-within,
.authcard input[type='email']:focus,
.authcard input[type='password']:focus { border-color: var(--ink-3); }
.authnote {
  margin-top: var(--s5); padding: var(--s4);
  border: 1px dashed var(--rule-strong); border-radius: var(--radius);
  font-size: var(--fs-small); color: var(--ink-2); line-height: 1.55;
}

/* live field errors: sit right under the input they describe */
.fielderror {
  margin: calc(var(--s5) * -1) 0 var(--s5); font-size: var(--fs-small); color: var(--accent-text);
}
.fielderror:empty { display: none; }
.authcard input[aria-invalid='true'] { border-color: var(--accent-text); }

/* button loading/disabled state — prevents double-submit */
.btn[disabled] { opacity: 0.6; cursor: default; pointer-events: none; }

/* the read-only echo of the URL carried over from the homepage */
.siteecho {
  height: 40px; margin-bottom: var(--s5); padding-inline: var(--s4);
  display: flex; align-items: center;
  background: var(--raised); border: 1px solid var(--field-rule); border-radius: var(--radius);
  font-size: var(--fs-small); color: var(--ink-2);
}

/* --- dashboard -------------------------------------------------------------- */
.dashboard { max-width: 640px; margin-inline: auto; padding-block: var(--s8); }
.dashboard h1 { margin-bottom: var(--s5); }
.dashboard__verify { margin-bottom: var(--s6); }
.dashboard__request {
  padding: var(--s4); margin-bottom: var(--s3);
  border: 1px solid var(--field-rule); border-radius: var(--radius);
}
.dashboard__request-url { font-weight: 600; }

/* --- the walkthrough (#walk): state → action → state ----------------------- */
/* Two panes: a browser pane plays REAL screen recordings of public craigslist
   pages (captured signed out, nothing submitted — see the honesty rules in
   the README and PROVENANCE.md) while the tree pane logs the journey.
   Everything is tokens — both themes work untouched. */
/* The two panes are cells of one framed object now: .walk owns the border,
   the 6px radius and the overflow clip, and the 1px grid gap showing the
   wrapper's --rule background IS the divider between them. So the pane
   itself carries no border, no radius and no shadow. */
.walk__pane {
  margin: 0; min-width: 0;
  display: flex; flex-direction: column;
  background: var(--raised);
  overflow: hidden;
}
/* Both panes wear the same chrome bar, at the same height, so the pair reads
   as input and output of one machine rather than as a video beside a
   diagram. The left bar is a browser's; the right bar names the artifact and
   counts the states captured into it, live, off the same clock. */
.walk__chrome {
  display: flex; align-items: center; gap: var(--s3);
  /* 45px is what the left bar measures once its URL field and padding are
     counted. Pinning both bars to it is what makes the two panes read as one
     instrument — an 11px step between them read as a misprint. */
  min-height: 45px;
  padding: var(--s2) var(--s3);
  border-bottom: 1px solid var(--rule);
  flex: none;
}
.walk__chrome--tree { justify-content: space-between; }
.walk__paneid {
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-2);
  white-space: nowrap;
}
.walk__count {
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.walk__count b { color: var(--accent-text); font-weight: 600; }
/* the traffic lights the browser chrome wears */
.panel__lights { display: flex; gap: var(--s2); flex: none; padding-inline: var(--s2); }
.panel__lights i {
  width: var(--dot-pitch); height: var(--dot-pitch);
  border-radius: var(--radius);
  background: var(--rule-strong);
}
.walk__url {
  flex: 1; min-width: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 3px var(--s3);
  font-size: var(--fs-small); color: var(--ink);
  white-space: nowrap; overflow: hidden;
  background: var(--ground);
}
.walk__url span { color: var(--ink-3); }
/* Filled, not just outlined — the reference's status pills (Active, Pending)
   are a tinted fill behind the label, not a ring around it. Same move here:
   a soft wash of --accent behind the text reads as a state being reported,
   which is what "signed out" is (D-019 follow-up). */
.walk__tag {
  flex: none;
  font-size: var(--fs-eyebrow); letter-spacing: var(--track-eyebrow); text-transform: uppercase;
  color: var(--accent-text);
  border: 1px solid currentColor; border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  padding: 1px var(--s2);
  white-space: nowrap;
}
.walk__view {
  /* ratio-locked to the footage (recorded at 1440x1080). flex:none because
     aspect-ratio is inert against a flex-basis:0 block axis, and min-height:0
     so the ratio, not a floor, sets the height. */
  position: relative; flex: none; aspect-ratio: 4 / 3; min-height: 0;
  overflow: hidden;
  background: var(--ground);
}
.walk__video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center top;
  display: block; border: 0;
  background: var(--ground);
}

/* the capture shutter: one blink per captured state, quiet otherwise.
   --ink makes it a white flash in dark mode and a soft dim in light. */
.walk__shutter {
  position: absolute; inset: 0; z-index: 5;
  background: var(--ink); opacity: 0; pointer-events: none;
}
.walk__shutter.is-go { animation: walk-shutter 0.24s var(--ease); }
@keyframes walk-shutter {
  18% { opacity: 0.14; }
  100% { opacity: 0; }
}
/* the screenshot frame: after the flash it shrinks toward the corner,
   the way the macOS capture thumbnail flies away */
.walk__snap {
  position: absolute; inset: 6px; z-index: 6; pointer-events: none;
  border: 1.5px solid var(--ink-2); border-radius: 6px;
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  opacity: 0; transform-origin: 92% 94%;
}
.walk__snap.is-go { animation: walk-snap 0.8s var(--ease); }
@keyframes walk-snap {
  0% { opacity: 0; transform: scale(1); }
  18% { opacity: 0.9; transform: scale(1); }
  45% { opacity: 0.9; transform: scale(0.94); }
  100% { opacity: 0; transform: scale(0.14); }
}

/* the tree */
.walk__treebox { flex: 1; min-height: 0; position: relative; padding: var(--s3); }
/* explicit fill, not auto: an absolutely positioned svg with inset plus
   width/height:auto is over-constrained for a replaced element — the
   browser sized width from the horizontal inset, then derived height from
   the viewBox ratio while ignoring the bottom inset, so the tree silently
   overflowed its box and clipped (this is what let S4/S4' render outside
   the visible pane). Giving both dimensions explicit (non-auto) values
   removes that ambiguity: the svg's box is exactly the inset rectangle, and
   its own preserveAspectRatio (default "meet") letterboxes the 352x428
   content inside it — centered, nothing clipped, no layout contribution to
   the row (unlike sizing this via a normal-flow child, which would let the
   tree's own intrinsic size inflate the shared video/tree row height). */
.walk__svg {
  position: absolute; inset: var(--s3);
  width: calc(100% - 2 * var(--s3)); height: calc(100% - 2 * var(--s3));
}
/* The tree is VISIBLE BY DEFAULT and JS opts in to animating it, not the
   other way round. It used to be `opacity: 0` with walk.js adding `.is-on`,
   which meant the whole Sitetree pane painted nothing anywhere JS does not
   run — iOS link previews, for one, which render this page with scripts off.
   That is exactly the fault the competitor pass found in Builder.io, whose
   eleven `.hero-element { opacity: 0 }` nodes have no CSS rule that ever
   restores them. walk.js sets `.is-live` before its first beat, so the
   animated path is unchanged and the no-JS path degrades to the finished
   diagram instead of to an empty box. */
.walk__el { opacity: 1; transition: opacity var(--dur-slow) var(--ease); }
.walk__svg.is-live .walk__el { opacity: 0; }
.walk__svg.is-live .walk__el.is-on { opacity: 1; }
.walk__svg .wt-lab { font: 500 8.5px var(--sans); fill: var(--ink-2); }
.walk__svg .wt-lab--hi { fill: var(--ink); font-weight: 700; }
.walk__svg .wt-page { fill: var(--dot); }
.walk__svg .wt-page--key { fill: var(--dot); stroke: var(--accent); stroke-width: 2; }
/* the robot agents: one rides the chain, two split off to the side branches.
   walk.js sets their transforms per step; the transition makes the glide. */
.walk__svg .wt-bot {
  fill: var(--accent); opacity: 0;
  /* transform is a quick hop so the capture can fire right after the click */
  transition: transform var(--dur) var(--ease), opacity var(--dur-slow) var(--ease);
}
.walk__svg .wt-bot.is-on { opacity: 1; }
/* the camera pops on the node for the capture beat, then goes */
.walk__svg .wt-cam { fill: var(--ink); opacity: 0; pointer-events: none; }
.walk__svg .wt-cam.is-go { animation: wt-cam-pop 0.9s var(--ease); }
@keyframes wt-cam-pop {
  0% { opacity: 0; }
  15% { opacity: 1; }
  60% { opacity: 1; }
  100% { opacity: 0; }
}
.walk__svg .wt-edge { stroke: var(--rule-strong); stroke-width: 2; }
.walk__svg .wt-arrhead { fill: var(--rule-strong); }
/* the two sibling actions each fan leaves untaken */
.walk__svg .wt-stub { fill: var(--ink-3); fill-opacity: 0.55; }
.walk__svg .wt-stubedge { stroke: var(--rule-strong); stroke-width: 1.2; stroke-opacity: 0.55; }
.walk__svg.is-pulse .walk__el.is-on { animation: walk-pulse 0.9s var(--ease) 1; }
@keyframes walk-pulse { 35% { opacity: 0.35; } }
/* the ring that marks the two labeled depth-1 nodes when their agents start */
.walk__svg .wt-mark { fill: none; stroke: var(--accent); stroke-width: 2; }

/* the parallel ending: the browser pane splits into two smaller headful
   browsers, one per labeled depth-1 node — same cursor and click grammar */
.walk__duo {
  position: absolute; inset: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px; padding: 12px;
  opacity: 0; transition: opacity var(--dur-slow) var(--ease);
  pointer-events: none;
}
.walk__view.is-duo .walk__duo { opacity: 1; }
.walk__view.is-duo > .walk__video { opacity: 0; }
.duo {
  display: flex; flex-direction: column; min-height: 0;
  border: 1px solid var(--rule); border-radius: 8px; overflow: hidden;
}
.duo__url {
  flex: none; padding: 3px 8px; border-bottom: 1px solid var(--rule);
  background: var(--ground);
  font: 500 9px/1.4 ui-monospace, Menlo, monospace;
  color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.duo__view { position: relative; flex: 1; min-height: 0; overflow: hidden; }

.walk__foot { display: flex; gap: var(--s5); align-items: center; margin-top: var(--s4); flex-wrap: wrap; }
.walk__note { margin-top: var(--s3); max-width: 92ch; }

/* --- never a blank white block while the footage loads -------------------- */
.walk__poster {
  position: absolute; inset: 0; z-index: 2;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center top;
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
  pointer-events: none;
}
.walk__view.is-cold .walk__poster { opacity: 1; }
.walk__view.is-duo .walk__poster { opacity: 0; }

/* --- a way out of a 3px page on a phone ------------------------------------ */
.walk__ctl {
  flex: none;
  padding: 2px var(--s3);
  min-height: 24px;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-pill);
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-2);
}
.walk__ctl:hover { color: var(--ink); border-color: var(--ink); }

/* --- a transport, and a readout of where you are --------------------------- */
.walk__transport { display: flex; gap: var(--s3); align-items: center; flex: none; }
.walk__bar {
  flex: 1; min-width: 120px; height: 2px;
  background: var(--rule);
  border-radius: 2px;
  overflow: hidden;
}
.walk__bar span {
  display: block; height: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
}

/* The provenance strip. Baymard sells competitor research on the strength of
   its citations; this is the same move with the one claim we can make and
   they cannot — the footage is checkable. Every value here is copied from
   PROVENANCE.md and the committed beat ledgers; none of it is generated, and
   it names no firm. It is the slot competitors fill with a logo wall. */
.prov {
  display: flex; flex-wrap: wrap;
  gap: 0 var(--s5);
  margin-top: var(--s4);
  padding-top: var(--s3);
  border-top: 1px solid var(--rule);
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--ink-3);
}
.prov div { display: flex; gap: var(--s2); }
.prov dt { color: var(--ink-3); opacity: 0.72; }
/* The labels are uppercase; the VALUES are not. A sha256 and a session uuid
   are lowercase hex by convention, and upper-casing them makes a real,
   checkable value look like decoration — the opposite of the point. */
.prov dd {
  margin: 0;
  color: var(--ink-2);
  text-transform: none;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
}
/* The one value that is itself the safety claim — "submitted: nothing" —
   gets the reference's dot-plus-pill status treatment (its "Active" tag)
   instead of reading as plain text like the rest of the row (D-019 follow-up).
   Targeted by class, not :last-child — the hash row is often last in the DOM
   and must not inherit this pill. */
.prov dd.prov__status {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 1px var(--s2) 1px var(--s1);
  border-radius: 999px;
  color: var(--accent-text);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.prov dd.prov__status::before {
  content: '';
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--accent);
  flex: none;
}

@media (max-width: 1024px) {
  /* stacked panes: the absolute svg contributes no height, so floor the box */
  .walk__treebox { min-height: 400px; }
  /* the estimator stacks too, so its divider turns from a column rule into a
     row rule — otherwise the two halves butt together with no separation */
  .est__quote { border-right: 0; border-bottom: 1px solid var(--rule); }
}
@media (max-width: 560px) {
  /* The tag is a compliance label (REAL PUBLIC PAGE — SIGNED OUT) and never
     hides. At 420px it was winning the row outright and squeezing the URL
     field down to "craigsli", so: the traffic lights go (pure decoration),
     the tag tightens to 10px/0.06em so the pair fits one row, and flex-wrap
     stays as the safety net if a translation runs longer than the English. */
  .walk__chrome { flex-wrap: wrap; row-gap: var(--s2); }
  .walk__chrome .panel__lights { display: none; }
  .walk__url { flex: 1 1 9em; }
  .walk__tag { font-size: 0.625rem; letter-spacing: 0.06em; padding-inline: var(--s1); }
  .walk__treebox { min-height: 300px; }
}
