/* ============================================================================
   e-LaboraTorio v4 — styles.css (assembled)
   Design system "Bench": tokens + shared primitives live in tokens.css (frozen).
   References followed concretely:
     Stripe  — landing narrative: navy ink, restrained gradients, layered
               navy-tinted shadows, conservative radii, purposeful rhythm.
     Linear  — product surfaces (pipeline board, console): tight hierarchy,
               small mono labels, hairline borders, 100-200ms state motion,
               accent reserved for interaction + running states.
     Notion  — honest information: whisper borders, wash section bands,
               tables as first-class citizens, pill status tags, calm footer.
   Sections: 1) base layout & chrome  2) landing  3) pipeline board
              4) owner console
   Modules preserved for provenance in _v4/*.css
   POST-AUDIT PASS (2026-10-22): independent design review fixes applied directly
   here — running state gets its own teal tag (was done-green), running stations
   gained an animated progress sweep, station <details>/<pre> disclosures styled,
   .ill-dash strokes restored, unearned hover lifts removed from non-interactive
   cards, sub-8px gaps/paddings normalized onto the token grid, ad-hoc font sizes
   mapped to the type scale, vertical station connectors on mobile, focus rings
   keep control radii.
   FINAL REVIEW PASS (2026-10-23, autonomous run): (1) the last two off-scale
   sizes (.fact b .98rem and .fact-n .78rem) mapped onto --fs-body/--fs-cap —
   the type inventory is now 100% token-sized; (2) done-station connectors
   repainted from accent teal to the done-green of the state grammar (legend:
   teal = en curso), desktop + mobile; (3) the unearned accent hover on the
   informational .chip pills removed (hover is reserved for interactive
   elements, matching the post-audit rule). engine.js/parity untouched.
   ========================================================================== */
/* ============================================================================
   e-LaboraTorio v4 — BASE LAYOUT & SHARED SITE CHROME
   (consumes the frozen token system in tokens.css; no values invented here)
   ========================================================================== */

/* ---- view routing (mechanics identical to v3) ---- */
.view { display: none; }
.view.active { display: block; animation: fadein 180ms cubic-bezier(.25, .55, .3, 1); }
@keyframes fadein {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

/* ---- icons ---- */
.ic { display: inline-block; vertical-align: -.15em; flex: none; }

/* Linear's typographic identity: Inter with geometric alternates on */
body { font-feature-settings: "cv01", "ss03"; }

/* ---- topbar: sticky, blurred, hairline (Linear nav craft, light) ---- */
.topbar {
  position: sticky; top: 0; z-index: 40;
  padding: 9px 0;
  background: var(--topbar-bg);
  -webkit-backdrop-filter: blur(12px) saturate(1.35);
  backdrop-filter: blur(12px) saturate(1.35);
  border-bottom: 1px solid var(--line);
}
/* v7 vision pass (2026-10-23): the bar's contents sat on the page edge (brand
   x≈32, English pill x≈1400 at 1440) while every section lives on the .wrap
   grid (content axis x≈173) — the header and hero visibly answered to two
   different containers (Stripe keeps the header content on the page grid).
   The row is now an inner .topbar-in.wrap so the sticky bar shares the page's
   left axis; the bar itself keeps only the vertical padding + blur surface. */
.topbar-in { display: flex; align-items: center; gap: var(--s4); }
.brand {
  display: inline-flex; align-items: center; gap: var(--s2);
  color: var(--ink); font-weight: var(--tw-ui); font-size: var(--fs-body);
  letter-spacing: -.012em; text-decoration: none;
}
.brand:hover { text-decoration: none; }
.brand-word .accent { color: var(--accent-ink); }
.brand-mark { color: var(--ink); }
.logo-liquid { stroke: var(--accent); }
.logo-node   { fill: var(--accent); }
.topnav { display: flex; align-items: center; gap: var(--s1); margin-left: auto; }
.topnav a {
  display: inline-flex; align-items: center; gap: var(--s1);
  padding: 7px 13px; border-radius: var(--pill);
  color: var(--ink-2); font-size: var(--fs-small); font-weight: var(--tw-ui);
  letter-spacing: -.004em; text-decoration: none;
  transition: background var(--t-fast), color var(--t-fast);
}
.topnav a .ic { color: var(--ink-3); transition: color var(--t-fast); }
.topnav a:hover { background: var(--hover-bg); color: var(--ink); }
.topnav a:hover .ic { color: var(--ink-2); }
.topnav a.active { background: var(--accent-soft); color: var(--accent-ink); }
.topnav a.active .ic { color: var(--accent-ink); }
#langBtn { margin-left: var(--s2); }
#themeBtn { margin-left: var(--s1); }
.icon-btn { width: 32px; min-width: 32px; padding: 0; display: inline-flex; align-items: center; justify-content: center; }
.icon-btn .ic { margin: 0; }

/* ---- thin-line illustration system (one consistent stroke style) ---- */
.ill-line { color: var(--ink-2); }
.ill-line.thin { opacity: .65; }
.ill-stream {
  stroke: var(--accent); stroke-width: 1.7; stroke-dasharray: 4 5;
  color: var(--accent);
}
.ill-liquid { stroke: var(--accent); stroke-width: 2.4; }
.ill-nodes circle { fill: var(--accent); }
.ill-dash {
  stroke: var(--accent); stroke-width: 1.6;
  stroke-dasharray: 2 6; stroke-linecap: round;
}
figure > figcaption {
  font-size: var(--fs-micro); color: var(--ink-3);
  font-family: var(--font-mono); letter-spacing: .01em;
}

/* ---- shared text helpers ---- */
.lead { font-size: var(--fs-lead); color: var(--ink-2); max-width: 62ch; }
.actions { display: flex; flex-wrap: wrap; gap: var(--s4); margin-top: var(--s6); }

/* ---- shared form primitives (waitlist + console) ---- */
input[type="email"], input[type="text"], select {
  font: inherit; color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line-2); border-radius: var(--r-s);
  padding: 10px 12px; min-width: 0;
  transition: border-color var(--t), box-shadow var(--t);
}
input::placeholder { color: var(--ink-3); }
input:focus, select:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--ring);
}
.invite-row { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.invite-row > input, .invite-row > select { flex: 1; }
.micro.ok  { color: var(--ok); }
.micro.err { color: var(--bad); }

/* ---- demo section head: title left, run control right ---- */
#demo .section-head {
  max-width: none;
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--s8);
}
#demo .section-head > div:first-child { max-width: 640px; }
.run-side { display: flex; flex-direction: column; gap: var(--s2); align-items: flex-start; flex: none; }
.run-side .cycle { font-size: var(--fs-micro); color: var(--ink-3); min-height: 1.2em; margin: 0; }

/* ---- responsive chrome ---- */
@media (max-width: 1080px) {
  .topbar-in { gap: var(--s3); }
  .topnav a { padding: 7px 10px; }
}
@media (max-width: 860px) {
  #demo .section-head { flex-direction: column; align-items: flex-start; gap: var(--s4); }
}
@media (max-width: 640px) {
  .topbar { padding: 8px 0; }
  .topbar-in { gap: var(--s2); }
  .topnav a { padding: 6px 8px; font-size: var(--fs-small); }
  .topnav a .ic { display: none; }
  /* Producto / Seguridad are scroll anchors on the landing page — hide them
     in the header on phones (still reachable by scrolling the page). */
  .topnav a[data-scroll] { display: none; }
  .brand { font-size: var(--fs-body); }
}
@media (max-width: 480px) {
  .topbar-in { flex-wrap: wrap; row-gap: 4px; }
  .topnav { order: 3; margin-left: 0; width: 100%; justify-content: flex-start; }
  #langBtn { margin-left: auto; }
}
/* ============================================================================
   e-LaboraTorio v4 — LANDING NARRATIVE
   Stripe: restrained gradient wash, navy ink, purposeful section rhythm,
           accent shadow on the primary CTA only.
   Notion: whisper borders, first-class tables, calm complete footer.
   ========================================================================== */

/* ============================ HERO ============================ */
.hero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: clamp(28px, 4.5vw, 64px);
  align-items: center;
  /* block-only: .hero also carries .wrap, so the page gutter must not be
     zeroed (see tokens.css .section note). */
  padding-block: clamp(56px, 8.5vw, 104px) clamp(40px, 5vw, 56px);
  overflow: hidden;
}
/* lab graph-paper texture, fading to canvas at the edges (Stripe restraint) */
.hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(var(--dot) 1px, transparent 1.1px);
  background-size: 22px 22px;
  -webkit-mask-image: radial-gradient(76% 72% at 66% 24%, #000 0%, transparent 84%);
  mask-image: radial-gradient(76% 72% at 66% 24%, #000 0%, transparent 84%);
}
/* single accent glow behind the instrument frame */
.hero::after {
  content: ""; position: absolute; width: 560px; height: 460px;
  right: -140px; top: -140px; pointer-events: none;
  background: radial-gradient(closest-side, var(--accent-soft), transparent 72%);
}
.hero-copy { position: relative; z-index: 1; }
.hero-copy h1 em { font-style: italic; color: var(--accent-ink); }
.hero-chips {
  display: flex; flex-wrap: wrap; gap: var(--s2);
  margin: var(--s6) 0 0; padding: 0; list-style: none;
}
.chip {
  font-family: var(--font-mono); font-size: var(--fs-micro); letter-spacing: .015em;
  color: var(--ink-2); background: var(--paper);
  border: 1px solid var(--line-2); border-radius: var(--pill);
  padding: var(--s1) var(--s3); box-shadow: var(--shadow-xs);
}
/* chips are informational <li>s, not controls — the accent hover affordance
   was removed in the final review (2026-10-23): hover belongs to the interactive */

/* the hero instrument: illustration + miniature pipeline in one framed card */
.hero-art-frame {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; gap: var(--s5);
  padding: var(--s6);
  background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r-l);
  box-shadow: var(--shadow-m);
}
.hero-art {
  margin: 0; display: flex; flex-direction: column;
  align-items: center; gap: var(--s3); color: var(--ink-3);
}
.hero-art svg { width: 100%; max-width: 420px; height: auto; }
/* v4 pixel review, 2nd pass (2026-10-23): at 1440 the frame gives 433 px and the
   five pills needed 406 px + 4 gaps; with the --s2 (8 px) gap that was 438 px, so
   Revisión wrapped alone onto a second row (measured: four pills top=626, Revisión
   top=662). Tightening to the --s1 gap made one row of 422 px.
   SUPERSEDED the same day by the v6.3 vertical step list at the end of this file
   (see "v6.3": a tall instrument card reads top→bottom; the horizontal flow lives
   on the full-width demo board). These pill rules below remain for the ≤490 px
   grid bands only; the shipped hero strip is vertical. */
.mini-pipe {
  display: flex; flex-wrap: wrap; justify-content: flex-start;
  gap: var(--s1); margin: 0; padding: var(--s4) 0 0;
  border-top: 1px solid var(--line); list-style: none;
}
.mini-pipe li {
  display: inline-flex; align-items: center; gap: var(--s1);
  font-size: var(--fs-label); font-weight: 600; letter-spacing: 0;
  color: var(--ink-3); background: var(--bg);
  border: 1px solid var(--line); border-radius: var(--pill);
  padding: var(--s1) 6px;
  transition: border-color var(--t), background var(--t), color var(--t);
}
.mini-pipe li .ic { color: inherit; width: 12px; height: 12px; }
/* v4 pixel review (2026-10-23): the five pills must read as ONE flow. At 1440 the
   frame gives 433 px and the previous sizing needed 469 px, so Revisión wrapped
   alone onto a second line and read as an orphan/warning chip. Tightening to the
   system's pill size (--fs-label, 12 px icons, 6 px side padding) measures 387-391 px
   — one row at ≥1011 px. Below that the frame narrows faster than the labels can
   shrink; the strip reflows to a deterministic 3+2 (never a 4+1 orphan) in the two
   width bands where a natural wrap would leave one pill behind. */
@media (max-width: 1010px) and (min-width: 861px) {
  .mini-pipe { display: grid; grid-template-columns: repeat(3, max-content); }
}
@media (max-width: 490px) {
  .mini-pipe { display: grid; grid-template-columns: repeat(3, max-content); }
}
.mini-pipe li.is-done { color: var(--ok); border-color: rgba(14, 122, 67, .28); background: var(--ok-bg); }
.mini-pipe li.is-review { color: var(--warn); border-color: rgba(150, 98, 10, .45); background: var(--warn-bg); }
@media (prefers-reduced-motion: no-preference) {
  .mini-pipe li.is-review { animation: pipe-review 6s ease-in-out infinite; }
  @keyframes pipe-review { 50% { box-shadow: 0 0 0 4px rgba(150, 98, 10, .10); } }
}

/* ======================= SPLIT / FACTS ======================= */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, .88fr);
  gap: clamp(32px, 5vw, 72px); align-items: start;
}
/* v5 recomposition — claude-design slop tells 3 (feature-tile grid) + 7 (icon topper):
   three equal cards each topped by a rounded numbered disc above the copy is the
   Tailwind-template pattern, and it made an honest three-point argument read as
   marketing furniture. Replaced with a ruled editorial list (Notion ordered-list /
   Stripe documentation craft): one mono index in a fixed gutter, hairline rules
   between rows, no card fill, no disc, no shadow. Hierarchy now comes from rule
   weight, the gutter and type — not from chrome. */
.facts {
  list-style: none; margin: var(--s8) 0 0; padding: 0;
  display: flex; flex-direction: column;
  border-top: 1px solid var(--line);
}
.fact {
  display: grid; grid-template-columns: 2.25rem minmax(0, 1fr); gap: var(--s4);
  align-items: start; padding: var(--s5) 0;
  border-bottom: 1px solid var(--line);
}
.fact > .fact-n {
  font-size: var(--fs-cap); font-weight: 600; letter-spacing: .06em;
  color: var(--accent-ink); padding-top: 3px;
  transition: color var(--t-fast);
}
.fact:hover > .fact-n { color: var(--accent); }
.fact > div { display: flex; flex-direction: column; gap: var(--s1); min-width: 0; }
.fact b { font-weight: var(--tw-ui); font-size: var(--fs-body); letter-spacing: -.008em; }
.fact > div span { color: var(--ink-2); font-size: var(--fs-small); line-height: 1.55; }

/* v5: the illustration was pinned to its intrinsic 300x150 attributes inside a
   422–655 px panel, so the subject floated at 47 % of the panel width with a dead
   band below it — measured at five viewports (see _v4/dispositions-iteration55.md).
   It now scales to the panel with its 2:1 aspect preserved and sits centred. */
.art-col {
  display: flex; flex-direction: column; gap: var(--s4); justify-content: center;
  padding: var(--s8) var(--s6);
  background: var(--wash); border: 1px solid var(--line); border-radius: var(--r-l);
}
.side-art {
  margin: 0; display: flex; flex-direction: column;
  align-items: center; gap: var(--s3); color: var(--ink-3); width: 100%;
}
.side-art svg { width: 100%; max-width: 460px; height: auto; display: block; }

/* ================== STATUS TABLE (Notion craft) ================== */
.table-wrap {
  overflow-x: auto;
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-m); box-shadow: var(--shadow-xs);
}
.status-table { width: 100%; border-collapse: collapse; font-size: var(--fs-small); min-width: 620px; }
.status-table th {
  font-family: var(--font-mono); font-size: var(--fs-eyebrow); font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3);
  text-align: left; padding: var(--s4) var(--s5);
  background: var(--wash); border-bottom: 1px solid var(--line-2);
}
.status-table td {
  padding: var(--s4) var(--s5); vertical-align: top;
  border-bottom: 1px solid var(--line); color: var(--ink);
}
.status-table td:first-child { font-weight: var(--tw-ui); }
.status-table td.note { color: var(--ink-2); }
.status-table tbody tr { transition: background var(--t-fast); }
.status-table tbody tr:hover { background: var(--wash); }
.status-table tbody tr:last-child td { border-bottom: 0; }

/* ======================= TRUST (4 cards) ======================= */
.trust-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s5); }
.trust-card {
  display: flex; flex-direction: column; gap: var(--s3);
  padding: var(--s6);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-m); box-shadow: var(--shadow-xs);
}
.trust-card h3 { margin: 0; }
.trust-card > svg.ic {
  width: 36px; height: 36px; padding: 8px; box-sizing: border-box;
  color: var(--accent-ink); background: var(--accent-wash);
  border: 1px solid rgba(11, 117, 104, .22); border-radius: var(--r-s);
}
.trust-card p { color: var(--ink-2); font-size: var(--fs-small); line-height: 1.6; margin: 0; }

/* compact trust strip above pricing (4 one-line commitments) */
.trust-strip {
  display: flex; flex-wrap: wrap; gap: var(--s3) var(--s6);
  list-style: none; margin: 0 0 var(--s6); padding: 0;
}
.trust-item {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-size: var(--fs-small); color: var(--ink-2);
}
.trust-item .ic { color: var(--accent-ink); flex: none; }
.trust-item .micro { margin: 0; }

/* ======================= PRICING (Compare) ======================= */
.tiers {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s5); align-items: stretch;
}
.tier {
  position: relative;
  display: flex; flex-direction: column; gap: var(--s4);
  padding: var(--s7);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-l); box-shadow: var(--shadow-xs);
  transition: transform var(--t), box-shadow var(--t), border-color var(--t);
}
.tier:hover { transform: translateY(-2px); box-shadow: var(--shadow-m); }
.tier header { display: flex; flex-direction: column; gap: var(--s2); }
.tier h3 { margin: 0; font-size: var(--fs-h3); }
.price { margin: 0; font-size: var(--fs-h2); font-weight: 600; letter-spacing: -.015em; }
/* v4 third-pass review: the suffix used to sit inline, so "para siempre" broke
   mid-phrase and "· indicativo" led the wrapped line as a stray bullet. Every
   price is now exactly two lines — figure, then unit — so the three cards share
   one price grammar and the baselines below align. */
.price span {
  display: block; margin-top: 2px;
  font-size: var(--fs-cap); font-weight: 400;
  color: var(--ink-3); letter-spacing: 0;
}
/* v4 pixel review: when the price slot holds a WORD instead of a figure ("A consultar"),
   it is wrapped in span.val so it takes the price size/weight/ink like the figures;
   the unit suffixes stay caption-size on their own line. (The earlier :only-child
   selector accidentally promoted every suffix to 32.8 px, so all three prices
   rendered as two full-size lines — fixed in the third pass.) */
.price > span.val {
  font-size: inherit; font-weight: 600; color: var(--ink); letter-spacing: inherit;
  /* v7 vision pass (2026-10-23): the slot is mono (p.price.mono — figures are
     data), but "A consultar" is a WORD: at 32.8 px JetBrains Mono it rendered as
     tracked-out caps next to tight numerals. The system rule is mono for
     data/values — prose takes the UI face. */
  font-family: var(--font-ui);
}
.tier ul {
  list-style: none; margin: var(--s2) 0 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--s3); flex: 1;
}
.tier li {
  position: relative; padding-left: 27px;
  font-size: var(--fs-small); color: var(--ink-2); line-height: 1.5;
}
.tier li::before {
  content: ""; position: absolute; left: 0; top: 1px;
  width: 17px; height: 17px; border-radius: var(--pill);
  background-color: var(--accent-soft);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.4l2.7 2.7L12 5.2' fill='none' stroke='%230b7568' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: center;
  background-size: 11px 11px;
}
.tier > .button { margin-top: var(--s2); }
/* v4 pixel review: .tier is a flex COLUMN, so its flex-item children stretch across
   the cross axis — the status tag painted as a full-width track (289 px for a 100 px
   label) and read as a progress meter instead of a status pill. */
.tier > .tag { align-self: flex-start; }
.tier.featured {
  border-color: rgba(11, 117, 104, .5);
  background: linear-gradient(180deg, var(--accent-wash), var(--paper) 38%);
  box-shadow: var(--shadow-m);
}
.tier-rec {
  position: absolute; top: -11px; left: var(--s7);
  font-family: var(--font-mono); font-size: var(--fs-eyebrow); font-weight: 600;
  letter-spacing: .13em; text-transform: uppercase;
  color: #fff; background: var(--accent);
  padding: 4px 11px; border-radius: var(--pill);
  box-shadow: var(--shadow-acc);
}

/* ======================= WAITLIST ======================= */
.waitlist {
  display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  gap: clamp(28px, 4vw, 64px); align-items: start;
  padding: var(--s8);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-l); box-shadow: var(--shadow-s);
}
.wl-form { display: flex; flex-direction: column; gap: var(--s3); }
.wl-form .invite-row { gap: var(--s3); }
.wl-form .button { flex: none; }
.wl-form .lbl { margin-bottom: calc(-1 * var(--s2)); }
.wl-form input, .wl-form select { width: 100%; }
.wl-done {
  display: flex; align-items: center; gap: var(--s2);
  padding: var(--s3) var(--s4); border-radius: var(--r-m);
  background: var(--wash); border: 1px solid var(--line);
}
.wl-done .ic.ok { color: var(--ok, #1a7f37); flex: none; }
.wl-done[hidden] { display: none; }

/* ======================= CONTACTO ======================= */
.contact { max-width: 760px; }
.contact-actions { display: flex; flex-wrap: wrap; gap: var(--s4); margin: var(--s6) 0 var(--s5); }
.note-card {
  display: flex; flex-direction: column; gap: var(--s2);
  padding: var(--s5); max-width: 560px;
  background: var(--wash); border: 1px solid var(--line); border-radius: var(--r-m);
}
/* v4 pixel review: same flex-column stretch as the pricing tags — the EMAIL pill
   painted 518 px wide inside a 520 px card. */
.note-card > .tag { align-self: flex-start; }
.note-card p { margin: 0; font-size: var(--fs-small); color: var(--ink-2); }
/* the address is the card's only datum: it must outrank the disclaimer around it.
   (The previous bare `.fine-mail` colour rule never applied — `.note-card p` is more
   specific, so the email rendered exactly like the fine print: 14.24 px, ink-2, 400.) */
.note-card p.fine-mail {
  color: var(--ink); font-size: var(--fs-body); font-weight: 500;
}
.pricing-note {
  margin-top: var(--s8); padding: var(--s6); max-width: 560px;
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-m); box-shadow: var(--shadow-xs);
}
.pricing-note p { color: var(--ink-2); font-size: var(--fs-small); margin: 0; }
.faq-h { margin-top: var(--s12); }
.faq { display: flex; flex-direction: column; margin-top: var(--s4); border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s4) var(--s2);
  font-weight: var(--tw-ui); color: var(--ink);
  transition: background var(--t-fast), color var(--t-fast);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+"; flex: none;
  font-family: var(--font-mono); font-size: var(--fs-h3); color: var(--ink-3);
  transition: transform var(--t), color var(--t);
}
.faq details[open] summary { color: var(--accent-ink); }
.faq details[open] summary::after { transform: rotate(45deg); color: var(--accent-ink); }
.faq details p {
  padding: 0 var(--s2) var(--s5); margin: 0;
  color: var(--ink-2); font-size: var(--fs-small); max-width: 62ch; line-height: 1.6;
}

/* ======================= FOOTER ======================= */
.footer {
  background: var(--wash);
  border-top: 1px solid var(--line);
  padding: var(--s12) 0 var(--s8);
}
.foot-grid {
  display: grid; grid-template-columns: 1.25fr .8fr 1.45fr 1fr;
  gap: var(--s8);
}
.foot-grid h4 {
  margin: 0 0 var(--s4);
  font-family: var(--font-mono); font-size: var(--fs-eyebrow); font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3);
}
.foot-brand {
  display: inline-flex; align-items: center; gap: var(--s3);
  color: var(--ink); font-weight: var(--tw-ui); margin-bottom: var(--s3);
  text-decoration: none;
}
.foot-brand:hover { text-decoration: none; }
.foot-brand .brand-word { font-size: var(--fs-h3); }
.foot-nav { display: flex; flex-direction: column; gap: var(--s2); }
/* footer links are the only persistent nav once the topbar wraps on a phone:
   give them a real hit area (WCAG 2.5.8 asks 24×24; audit measured 22 px) */
.foot-nav a {
  display: flex; align-items: center; min-height: 28px;
  color: var(--ink-2); font-size: var(--fs-small); width: fit-content;
}
.foot-col p.micro a, .foot-legal a { display: inline-flex; align-items: center; min-height: 28px; }
.foot-col p.micro { line-height: 1.65; }
.foot-legal {
  grid-column: 1 / -1;
  border-top: 1px solid var(--line);
  margin-top: var(--s6); padding-top: var(--s5);
}

/* ======================= RESPONSIVE ======================= */
@media (max-width: 1080px) {
  .foot-grid { grid-template-columns: 1fr 1fr; gap: var(--s7); }
  .hero { grid-template-columns: minmax(0, 1fr) minmax(0, .92fr); }
}
@media (max-width: 860px) {
  .hero { grid-template-columns: 1fr; padding-top: var(--s16); }
  .hero-art-frame { max-width: 620px; }
  .split { grid-template-columns: 1fr; }
  .tiers { grid-template-columns: 1fr; gap: var(--s6); }
  .tier.featured { order: -1; }
  .waitlist { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .trust-grid { grid-template-columns: 1fr; }
  .foot-grid { grid-template-columns: 1fr; gap: var(--s6); }
  .waitlist, .pricing-note { padding: var(--s6); }
  .fact { padding: var(--s4) 0; grid-template-columns: 1.75rem minmax(0, 1fr); }
  .tier { padding: var(--s6); }
  .tier-rec { left: var(--s6); }
}
/* ============================================================================
   e-LaboraTorio v4 — THE LIVE PIPELINE BOARD (the product's proof)
   Linear monitor-surface craft on a light canvas: one instrument panel,
   stations as a connected horizontal flow, unmistakable states, and a
   legible results panel. Accent appears ONLY on interaction + running.
   ========================================================================== */

.pipeline-board {
  display: flex; flex-direction: column; gap: var(--s5);
  padding: var(--s6);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-l); box-shadow: var(--shadow-s);
}

/* ---- legend: quiet mono strip along the top edge of the instrument ---- */
.legend {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--s2) var(--s4); margin: 0;
  padding: 0;
  font-size: var(--fs-micro); color: var(--ink-2);
}
.legend-limit {
  margin: var(--s2) 0 0; padding: 0 0 var(--s4);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-micro); color: var(--ink-3);
}
.legend .dot {
  width: 8px; height: 8px; border-radius: var(--pill); flex: none;
  display: inline-block; margin-right: var(--s2);
}
.legend .dot.green { background: var(--ok); }
.legend .dot.teal  { background: var(--accent); }
.legend .dot.amber { background: var(--warn); }
.legend .dot.red   { background: var(--bad); }

/* ---- stations: the horizontal flow ---- */
.stations {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--s4);
}
.station {
  position: relative; min-width: 0;
  display: flex; flex-direction: column; gap: var(--s2);
  padding: var(--s4);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-m); box-shadow: var(--shadow-xs);
  transition: border-color var(--t), background var(--t),
              box-shadow var(--t), transform var(--t);
}
/* connector: a directional chevron between adjacent stations.
   v4 pixel review (2026-10-23, second pass): the previous 2 px dash had no
   arrowhead and the same weight as the card borders, so the five cards read as
   five parallel tiles rather than a left-to-right flow. A chevron states the
   direction; its colour stays inside the state grammar below. */
.station:not(:last-child)::after {
  content: ""; position: absolute; z-index: 1;
  top: calc(50% - 4px); left: calc(100% + 4px);
  width: 8px; height: 8px; box-sizing: border-box;
  border-top: 2px solid var(--line-3); border-right: 2px solid var(--line-3);
  border-radius: 1px; transform: rotate(45deg);
  transition: border-color var(--t);
}
/* done connectors wear the done-green of the state grammar (legend: green =
   completado); accent teal stays reserved for running (final review 2026-10-23) */
.station.is-done:not(:last-child)::after { border-color: rgba(14, 122, 67, .5); }
.station.blocked:not(:last-child)::after { border-color: rgba(179, 38, 30, .45); }

.station .num {
  font-family: var(--font-mono); font-size: var(--fs-eyebrow); font-weight: 600;
  letter-spacing: .1em; color: var(--ink-3);
  transition: color var(--t);
}
.st-head { display: flex; align-items: center; gap: var(--s2); }
.st-head h3 { margin: 0; font-size: var(--fs-body); font-weight: var(--tw-ui); letter-spacing: -.008em; }
.st-head .ic { color: var(--ink-2); transition: color var(--t); }
.st-sub { font-size: var(--fs-micro); color: var(--ink-3); line-height: 1.45;
          /* 1–2 line subtitles must not push the state chip off a shared
             baseline across the five cards (measured drift: 18 px) */
          min-height: calc(var(--fs-micro) * 1.45 * 2); }
.state-line {
  position: relative;
  display: flex; align-items: center; gap: var(--s2);
  margin-top: var(--s2); padding-top: var(--s2);
  border-top: 1px solid var(--line);
}
.state-line .ic { color: var(--ink-3); }
.st-io { margin: 0; font-size: var(--fs-micro); color: var(--ink-2); line-height: 1.6; overflow-wrap: anywhere; }
.st-io b { color: var(--ink); }
.defect-list { display: flex; flex-wrap: wrap; gap: var(--s1); margin-top: var(--s2); min-width: 0; }
/* A blocked station is only ~191 px wide at 1440 px and a Spanish defect label
   ("timestamps no monotónicos: 15") is longer than that: the nowrap pill used to
   paint past the card edge. Let defect chips wrap inside the card instead.
   (Audit before: article.station.blocked scrollWidth 264 vs clientWidth 191.) */
.defect-list .tag {
  white-space: normal; overflow-wrap: anywhere; max-width: 100%; text-align: left;
}

/* reproducibility disclosure inside a station: same craft as .metric
   (the JS injects <details><summary><pre> into every station card).
   v4 pixel review (2026-10-23, second pass): the disclosure used to sit right
   after the body text, so its baseline drifted card to card (per-card heights
   differed by up to 20 px). margin-top:auto pins it to the card floor. */
.station details { margin-top: auto; min-width: 0; padding-top: var(--s2); }
.station summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: var(--s1);
  min-height: 32px; padding-block: var(--s1);   /* 18 px → a real target */
  font-family: var(--font-mono); font-size: var(--fs-micro);
  color: var(--ink-2);
  transition: color var(--t-fast);
}
.station summary::-webkit-details-marker { display: none; }
.station summary::before { content: "+ "; }
.station summary:hover { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; }
.station details[open] summary::before { content: "- "; }
.station pre {
  margin: var(--s2) 0 0; padding: var(--s3);
  background: var(--code-bg); border: 1px solid var(--line);
  border-radius: var(--r-s);
  font-family: var(--font-mono); font-size: var(--fs-micro); line-height: 1.7;
  color: var(--ink-2); overflow-x: auto; white-space: pre;
}

/* ---- station states: unmistakable at a glance ---- */
/* queued: default paper card, slate tag (above) */
.station.running {
  border-color: var(--accent);
  background: linear-gradient(180deg, var(--accent-wash), var(--paper) 62%);
  box-shadow: var(--shadow-s);
}
.station.running .st-head .ic { color: var(--accent-ink); }
.station.running .num { color: var(--accent-ink); }
.station.running:not(:last-child)::after { border-color: var(--accent); }

.station.is-done { border-color: rgba(14, 122, 67, .32); }
.station.is-done .st-head .ic { color: var(--ok); }
.station.is-done .num { color: var(--ok); }

.station.blocked {
  border-color: rgba(179, 38, 30, .42);
  background: linear-gradient(180deg, var(--bad-bg), var(--paper) 68%);
}
.station.blocked .st-head .ic { color: var(--bad); }
.station.blocked .num { color: var(--bad); }

/* review station carries an amber tag; reinforce the card when supported */
.station:has(.state-line .tag.amber) {
  border-color: rgba(150, 98, 10, .34);
  background: linear-gradient(180deg, var(--warn-bg), var(--paper) 68%);
}

/* running activity indicator: a quiet pulse + a progress sweep on the
   state line, so "work advancing" is visible, not just a border color */
@media (prefers-reduced-motion: no-preference) {
  .station.running .st-head .ic { animation: station-pulse 1.6s ease-in-out infinite; }
  @keyframes station-pulse { 50% { opacity: .45; } }
  .station.running .state-line::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 2px;
    background: linear-gradient(90deg, var(--accent), transparent);
    transform-origin: 0 50%;
    animation: station-sweep 1.2s linear infinite;
  }
  @keyframes station-sweep { from { transform: scaleX(0); } to { transform: scaleX(1); } }
}

/* ---- results panel: #metrics is a grid; banners/tables span it ---- */
#metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(172px, 1fr));
  gap: var(--s4); min-width: 0;
}
#metrics > .metrics-banner,
#metrics > .mt-wrap,
#metrics > .run-summary,
#metrics > .micro { grid-column: 1 / -1; }

.metrics-banner {
  display: flex; flex-direction: column; gap: var(--s1);
  padding: var(--s4) var(--s5);
  border: 1px solid; border-radius: var(--r-m);
  font-size: var(--fs-small); line-height: 1.55;
}
.metrics-banner b {
  font-family: var(--font-mono); font-size: var(--fs-eyebrow); font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase;
}
.metrics-banner p { margin: 0; }
.metrics-banner.preview   { background: var(--accent-wash); border-color: rgba(11, 117, 104, .26); color: var(--ink-2); }
.metrics-banner.preview b { color: var(--accent-ink); }
.metrics-banner.blocked   { background: var(--bad-bg); border-color: rgba(179, 38, 30, .32); color: var(--ink-2); }
.metrics-banner.blocked b { color: var(--bad); }
.metrics-banner.uncertain   { background: var(--warn-bg); border-color: rgba(150, 98, 10, .32); color: var(--ink-2); }
.metrics-banner.uncertain b { color: var(--warn); }
.metrics-banner .defect-list { margin-top: var(--s2); }

/* ---- the reference metrics table (Notion-grade table craft) ---- */
.mt-wrap {
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-m); box-shadow: var(--shadow-xs);
  overflow-x: auto;
}
.metrics-table { width: 100%; border-collapse: collapse; font-size: var(--fs-small); min-width: 560px; }
.metrics-table th {
  font-family: var(--font-mono); font-size: var(--fs-eyebrow); font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3);
  padding: var(--s3) var(--s5); background: var(--wash);
  border-bottom: 1px solid var(--line-2);
}
.metrics-table th:first-child { text-align: left; }
.metrics-table th + th { text-align: right; }
.metrics-table td { padding: var(--s3) var(--s5); border-bottom: 1px solid var(--line); }
.metrics-table td:first-child {
  text-align: left; font-weight: var(--tw-ui);
  font-family: var(--font-mono); letter-spacing: .02em;
}
.metrics-table td + td {
  text-align: right; font-family: var(--font-mono);
  font-feature-settings: "tnum" on, "zero" on;
}
.metrics-table td.over { color: var(--bad); }
.metrics-table td.bad { color: var(--bad); font-weight: 600; }
.metrics-table tbody tr { transition: background var(--t-fast); }
.metrics-table tbody tr:hover { background: var(--wash); }
.metrics-table tbody tr:last-child td { border-bottom: 0; }
.mt-wrap .micro { padding: var(--s3) var(--s5) var(--s4); margin: 0; }

/* ---- results: ONE readout panel, deliberately NOT a second row of station cards ----
   v4 pixel review: after a clean run the five per-test blocks rendered as cards in the
   same grid grammar as the stations above, so the centrepiece read as two identical
   rows. They now live inside a single wash panel with a mono header and their own
   footer line — same information, a different object — and a p95 above the run's SLA
   limit wears the red encoding + "supera el límite" tag the legend defines (display
   only: the value is engine output and is never recomputed here). */
.results {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; gap: var(--s4);
  padding: var(--s5);
  background: var(--wash); border: 1px solid var(--line-2);
  border-radius: var(--r-m); box-shadow: var(--shadow-xs);
}
.results-head {
  margin: 0; padding-bottom: var(--s2);
  color: var(--ink-2); border-bottom: 1px solid var(--line-2);
  font-size: var(--fs-label); font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase;
}
.results-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(176px, 1fr));
  gap: var(--s4) var(--s5);
}
/* blocks, not cards: no fill, no radius, no shadow — the panel is the surface */
.metric {
  display: flex; flex-direction: column; gap: 0;
  min-width: 0; padding: 0;
  background: transparent; border: 0; box-shadow: none;
}
.metric > b {
  font-family: var(--font-mono); font-size: var(--fs-small); font-weight: 600;
  letter-spacing: .06em; color: var(--ink-3);
  padding-bottom: var(--s1); border-bottom: 1px solid var(--line-2);
}
.m-row {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: 0 var(--s2);
  font-size: var(--fs-micro); padding: var(--s1) 0;
  border-bottom: 1px solid var(--line);
}
.m-row:last-of-type { border-bottom: 0; }
.m-row span { color: var(--ink-3); }
.m-row strong {
  font-family: var(--font-mono); font-weight: 600; color: var(--ink);
  font-feature-settings: "tnum" on, "zero" on;
}
.m-row.over strong, .m-row strong.bad { color: var(--bad); }
/* the p95 row + its verdict: one ruled pair, both states equal height */
.m-p95 { border-bottom: 0; padding-bottom: 0; }
.m-flag {
  min-height: calc(var(--fs-micro) + var(--s2));
  padding-bottom: var(--s2); border-bottom: 1px solid var(--line);
}
/* v4 pixel review, finding 2 (parent session 2026-10-23): the tag rides inline with
   the value inside <strong> (same grammar as the reference table cell), so the gap
   is a real inset — margin-left:auto belonged to a sibling-flex draft that never
   shipped. translateY nudges the pill onto the value's optical midline. */
.m-row .tag { margin-left: var(--s2); transform: translateY(-1px); }
.metric.flagged > b { color: var(--warn); }
/* v4 third-pass review: the red MICRO header was a third failure encoding on top
   of the red p95 + verdict tag + red SLA value — the reader could not infer what
   it meant. Failure stays encoded on the values, not on the column header. */
.metric details { margin-top: auto; padding-top: var(--s2); }
.metric summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: var(--s1);
  min-height: 32px; padding-block: var(--s1);   /* 18 px → a real target */
  font-family: var(--font-mono); font-size: var(--fs-micro);
  color: var(--ink-2);
  transition: color var(--t-fast);
}
.metric summary::-webkit-details-marker { display: none; }
.metric summary::before { content: "+ "; }
.metric summary:hover { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; }
.metric details[open] summary::before { content: "- "; }
.metric pre {
  margin: var(--s2) 0 0; padding: var(--s3);
  background: var(--code-bg); border: 1px solid var(--line);
  border-radius: var(--r-s);
  font-family: var(--font-mono); font-size: var(--fs-micro); line-height: 1.7;
  color: var(--ink-2); overflow-x: auto; white-space: pre;
}
.run-summary {
  margin: 0; padding: var(--s3) 0 0; border-top: 1px solid var(--line);
  color: var(--ink-2); font-size: var(--fs-micro);
}
.board-caption { margin-top: var(--s4); }

/* ---- responsive: keep the flow readable at every width ---- */
@media (max-width: 1080px) {
  .stations { gap: var(--s3); }
  .station:not(:last-child)::after { left: calc(100% + 4px); }
  .station { padding: var(--s3) var(--s4); }
}
@media (max-width: 860px) {
  /* stacked cards read top-down; connectors only make sense in the row layout */
  .stations { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .station:not(:last-child)::after { display: none; }
  .pipeline-board { padding: var(--s5); }
}
@media (max-width: 640px) {
  .stations { grid-template-columns: 1fr; }
  /* stacked flow: the chevron turns downward between cards */
  .station:not(:last-child)::after {
    display: block; top: auto; bottom: calc(-1 * var(--s3) + 1px);
    left: var(--s4); width: 7px; height: 7px;
    border-color: var(--line-2); transform: rotate(135deg);
  }
  .station.is-done:not(:last-child)::after { border-color: rgba(14, 122, 67, .5); }
  .station.blocked:not(:last-child)::after { border-color: rgba(179, 38, 30, .45); }
  .legend { gap: var(--s2) var(--s3); }
  .pipeline-board { padding: var(--s4); }
}
/* ============================================================================
   e-LaboraTorio v4 — OWNER CONSOLE
   Linear operate-surface craft on a light canvas: tight hierarchy, small
   mono labels, hairline borders, 150ms state motion, accent only for
   interaction + running. Panels build on the frozen .panel primitive.
   ========================================================================== */

.console-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s5);
}
.console-grid .panel {
  display: flex; flex-direction: column; gap: var(--s4);
  padding: var(--s6); min-width: 0;
}
.console-grid .panel h3 { margin: 0; }
.console-grid .panel > .micro { margin: calc(-1 * var(--s2)) 0 0; }

/* ---- office: rooms (departments of the analysis line) ---- */
.rooms {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--s4); margin-bottom: var(--s8);
}
.room {
  display: flex; flex-direction: column; gap: var(--s3);
  padding: var(--s5); min-width: 0;
  background: var(--paper); border: 1px solid var(--line);
  border-top: 3px solid var(--slate);
  border-radius: var(--r-m); box-shadow: var(--shadow-xs);
}
.room.room-running { border-top-color: var(--accent); }
.room.room-done    { border-top-color: var(--ok); }
.room.room-wait    { border-top-color: var(--warn); }
.room-head { display: flex; align-items: center; gap: var(--s2); }
.room-head .ic { color: var(--ink-3); flex: none; }
.room-head b { font-weight: var(--tw-ui); font-size: var(--fs-small); }
.room-count { margin-left: auto; font-family: var(--font-mono); font-size: var(--fs-label); color: var(--ink-3); }
.room-agents { display: flex; flex-direction: column; gap: var(--s2); }
.room-agent { display: flex; align-items: center; gap: var(--s2); font-size: var(--fs-small); min-width: 0; }
.room-agent .avatar { width: 22px; height: 22px; font-size: 10px; flex: none; }
.room-agent small { color: var(--ink-3); margin-left: auto; flex: none; white-space: nowrap; }
.room-empty { font-size: var(--fs-micro); color: var(--ink-3); }

/* ---- office: two-column layout ---- */
.office-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5);
  margin-bottom: var(--s5);
}

/* ---- feed (live activity from agent messages) ---- */
.feed { display: flex; flex-direction: column; }
.feed-item { display: flex; gap: var(--s3); align-items: flex-start; padding: var(--s3) 0; border-bottom: 1px solid var(--line); }
.feed-item:last-child { border-bottom: 0; padding-bottom: 0; }
.feed-item:first-child { padding-top: 0; }
.feed-item .avatar { flex: none; margin-top: 1px; }
.feed-body { flex: 1; min-width: 0; }
.feed-meta { display: flex; gap: var(--s2); align-items: baseline; }
.feed-meta b { font-size: var(--fs-small); font-weight: var(--tw-ui); }
.feed-meta .dot { flex: none; align-self: center; }
.feed-meta time { margin-left: auto; font-family: var(--font-mono); font-size: var(--fs-label); color: var(--ink-3); white-space: nowrap; }
.feed-body p { margin: 2px 0 0; font-size: var(--fs-small); color: var(--ink-2); line-height: 1.5; }

/* ---- questions to the owner ---- */
.questions { display: flex; flex-direction: column; gap: var(--s3); }
.question {
  display: flex; flex-direction: column; gap: var(--s3);
  padding: var(--s4); border: 1px solid var(--line);
  border-left: 3px solid var(--warn); border-radius: var(--r-s);
  background: var(--wash);
}
.question .q-who { font-size: var(--fs-small); font-weight: var(--tw-ui); display: flex; align-items: center; gap: var(--s2); }
.question p { margin: 0; font-size: var(--fs-small); color: var(--ink-2); }
.question .q-actions { display: flex; gap: var(--s2); flex-wrap: wrap; }
.question .q-actions .button { padding: 5px 12px; font-size: var(--fs-cap); }
.question.answered { opacity: .6; border-left-color: var(--ok); }

/* ---- tabs ---- */
.tabs { display: flex; gap: var(--s2); border-bottom: 1px solid var(--line); margin-bottom: var(--s4); }
.tab {
  font: inherit; font-size: var(--fs-small); font-weight: var(--tw-ui);
  color: var(--ink-2); background: transparent; border: none;
  padding: var(--s2) var(--s3); cursor: pointer;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.tab:hover { color: var(--ink); }
.tab.active { color: var(--accent-ink); border-bottom-color: var(--accent); }
.tab-pane { display: none; }
.tab-pane.active { display: block; }

@media (max-width: 860px) {
  .rooms { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .office-grid { grid-template-columns: 1fr; }
}
@media (max-width: 480px) {
  .rooms { grid-template-columns: 1fr; }
}

/* ---- live activity: agent rows ---- */
.agent-list { display: flex; flex-direction: column; }
.agent {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) 0; border-bottom: 1px solid var(--line);
}
.agent:last-child { border-bottom: 0; padding-bottom: 0; }
.agent:first-child { padding-top: 0; }
.agent .avatar {
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-s);
  background: var(--slate-bg); color: var(--slate);
  border: 1px solid var(--line);
}
.agent .avatar.violet { background: var(--violet-bg); color: var(--violet); }
.agent .who { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.agent .who b { font-weight: var(--tw-ui); font-size: var(--fs-small); letter-spacing: -.006em; }
.agent .who small { color: var(--ink-3); font-size: var(--fs-micro); }

/* ---- progress: hero metric + labelled bars ---- */
.overall { display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap; }
.overall-num {
  font-family: var(--font-mono); font-weight: 600;
  /* v4 pixel review: at --fs-stat (40.8 px) the figure was 2.4x its own panel title and
     inverted the Monitor-surface hierarchy; --fs-h2 keeps it the panel's datum without
     shouting over the label, baseline-aligned with its caption. */
  font-size: var(--fs-h2);
  letter-spacing: -.02em; line-height: 1;
  font-feature-settings: "tnum" on, "zero" on;
  color: var(--ink);
}
.overall .micro { margin: 0; color: var(--ink-3); }
.progress-list { display: flex; flex-direction: column; gap: var(--s3); }
.pr-line {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s3); margin-bottom: var(--s1); font-size: var(--fs-small);
}
.pr-line span { color: var(--ink-2); }
.pr-line b {
  font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 600;
  color: var(--ink-3); font-feature-settings: "tnum" on;
}
.bar {
  height: 6px; border-radius: var(--pill);
  background: var(--slate-bg); overflow: hidden;
}
.bar i {
  display: block; height: 100%; width: 0;
  border-radius: inherit; background: var(--accent);
  transition: width var(--dur-fill) cubic-bezier(.25, .55, .3, 1);
}
/* a stage at 0% is an honest empty state — and the quiet default track IS the message.
   (v4 pixel review: the diagonal hatch painted across the whole empty track read as
   indeterminate/disabled and contradicted the honest-pending caption.) */

/* ---- blockers: severity via tag color + soft wash (no accent rails) ---- */
.blocker-list { display: flex; flex-direction: column; gap: var(--s3); }
.blocker {
  display: flex; flex-direction: column; gap: var(--s2);
  padding: var(--s4);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-m);
  transition: border-color var(--t), background var(--t);
}
.blocker .b-head { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.blocker .b-head b { font-size: var(--fs-small); font-weight: var(--tw-ui); letter-spacing: -.006em; }
.blocker p { margin: 0; font-size: var(--fs-small); color: var(--ink-2); line-height: 1.55; }
.blocker .b-act { color: var(--accent-ink); }
.blocker.amber {
  border-color: rgba(150, 98, 10, .3);
  background: linear-gradient(180deg, var(--warn-bg), var(--paper) 70%);
}
.blocker.red {
  border-color: rgba(179, 38, 30, .36);
  background: linear-gradient(180deg, var(--bad-bg), var(--paper) 70%);
}

/* ---- invite box: a proper code well ---- */
.invite-box { display: flex; flex-direction: column; gap: var(--s3); }
.invite-box .lbl { margin: var(--s2) 0 0; }
.invite-box .lbl:first-child { margin-top: 0; }
.invite-row code {
  flex: 1; min-width: 0;
  font-family: var(--font-mono); font-size: var(--fs-small);
  color: var(--ink); background: var(--code-bg);
  border: 1px solid var(--line); border-radius: var(--r-s);
  padding: 7px 10px; overflow-wrap: anywhere;
}
.snippet {
  margin: 0; padding: var(--s3) var(--s4);
  background: var(--code-bg); border: 1px solid var(--line);
  border-radius: var(--r-s);
  font-family: var(--font-mono); font-size: var(--fs-micro); line-height: 1.7;
  color: var(--ink-2); overflow-x: auto; white-space: pre;
}
.invite-box > .quiet { align-self: flex-start; }
.perm-grid {
  display: grid; grid-template-columns: 1fr;
  gap: var(--s2);
}
.perm {
  display: flex; align-items: flex-start; gap: var(--s2);
  min-width: 0;
  padding: var(--s2) var(--s3); border: 1px solid var(--line);
  border-radius: var(--r-s); background: var(--paper);
  font-size: var(--fs-small); color: var(--ink-2); cursor: pointer;
}
.perm input { accent-color: var(--accent); flex: none; margin-top: 2px; }
.perm span { flex: 1; min-width: 0; overflow-wrap: break-word; line-height: 1.35; }
.perm:hover { border-color: var(--line-2); }
.invite-box > .button { align-self: flex-start; }
.invite-box input[type="text"], .invite-box input[type="email"], .invite-box select { width: 100%; }
.agent .quiet { flex: none; }

/* ---- people panel ---- */
#roleDesc { margin: 0; }
.console-grid select { max-width: 100%; }

/* ---- responsive ---- */
@media (max-width: 1080px) {
  .console-grid { gap: var(--s4); }
  .console-grid .panel { padding: var(--s5); }
}
@media (max-width: 860px) {
  .console-grid { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .console-grid .panel { padding: var(--s4); }
}

/* ============================================================================
   v6 PIXEL-CLOSURE PASS — 2026-10-23
   Source: a vision review of the _v4/shots11 capture set (real Chromium, 1440x1000
   and 390x844) against Stripe (landing narrative), Linear (product surfaces) and
   the claude-design slop diagnostic. Each rule answers one defect that was SEEN in
   a rendered capture; the metric logic (engine.js / parity.node.js / fixture.js)
   is not touched anywhere in this block.
   ========================================================================== */

/* ---- HERO: the instrument card holds the column instead of floating in it ----
   Seen: the card ran y 287→668 inside a 174→830 px text column — 113 px of dead
   space above it, 162 px below, and an optical centre that answered to nothing.
   Now both columns stretch: the drawing centres in the free space and the pipeline
   strip is anchored to the frame's bottom edge, so the card is composed WITH the
   copy instead of placed beside it. */
.hero { align-items: stretch; }
.hero-art-frame { justify-content: space-between; }
.hero-art { flex: 1; justify-content: center; align-items: flex-start; }
.hero-art svg { width: 100%; max-width: 380px; }
.hero-art figcaption { font-size: var(--fs-eyebrow); letter-spacing: .06em; }

/* the single accent glow sat above the card's top-right corner, lighting empty
   canvas — it now sits behind the card's mass */
.hero::after { right: -120px; top: 4%; width: 640px; height: 560px; }

/* CTA hierarchy: the primary has to win on more than hue */
.hero .actions .button.primary { padding: 15px 26px; }
.hero .actions .button.secondary { padding: 12px 22px; }

/* the synthetic-data caveat is a footnote, not a fourth proof chip */
.hero-copy > .micro {
  margin-top: var(--s8); padding-top: var(--s5);
  border-top: 1px solid var(--line); max-width: 54ch;
}

/* ---- PRICING: structural parity (Stripe Compare craft) ----
   Seen: "A consultar" held one line while the other two prices wrapped to two, so
   card 3's status tag and list sat 49 px above its siblings and the three price
   baselines never aligned. The slot is now a fixed two-line block, and the grid
   gutter opens from 20 to 24 px so the featured card's shadow stops bleeding. */
.tiers { gap: var(--s6); }
.tier .price { line-height: 1.2; min-height: 2.4em; }

/* one bridge line on ALL three tiers — the ladder reads as "everything below,
   plus" on the two upper tiers, and "Incluye" anchors the free tier so the
   three feature lists start at the same height (v4 third-pass review: card 1
   previously had no line, so its list began ~28 px above its siblings). */
.tier .bridge {
  margin: calc(-1 * var(--s1)) 0 0;
  font-family: var(--font-mono); font-size: var(--fs-eyebrow);
  font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}

/* the RECOMENDADO badge was inset 32 px from the left edge and collided with the
   card border with no ring — it is now centred and punches a clean notch */
.tier-rec {
  left: 50%; transform: translateX(-50%);
  box-shadow: 0 0 0 5px var(--bg), var(--shadow-acc);
}

/* the recommended tier was 5 px taller than its siblings — imperceptible. The
   recommendation now reads from border + tint + shadow + the filled CTA alone:
   a translateY shift moved every baseline in the card off its siblings' grid
   (v4 third-pass review, measured: titles/price/tags all +5-6 px vs row). */
.tier.featured:hover { transform: translateY(-4px); }

/* "FASE 2" read as disabled rather than scheduled (same family as the header
   labels, ~3:1 contrast) */
.tier .tag.slate { color: var(--ink-2); }

/* ---- CONSOLE: panels size to their content ----
   Seen: "Actividad en vivo" carried three rows inside a 490 px box stretched to
   match its neighbour — 230 px of empty card, the most visible craft failure on
   that view. Content-sized panels are the Linear/Notion convention. */
.console-grid { align-items: start; }

/* ---- STATUS TABLE: a real band and a real card ----
   Seen: the header band was 35 px against 68 px rows with its labels at the floor
   of the contrast ramp, and the section's only container carried no elevation. */
.status-table th { padding: 14px var(--s5); color: var(--ink-2); }
.table-wrap { box-shadow: var(--shadow-s); }

@media (max-width: 860px) {
  .hero { align-items: start; }
}

/* ---- v6.1 second vision pass (same day) -----------------------------------
   The first pass made both columns share one frame — but the drawing stayed at
   380 px inside a 735 px panel, so the card read as a hollow frame (one ~190 px
   dead band between caption and pipeline). The drawing now fills the frame's
   width and the free space splits symmetrically around it; the frame drops its
   border (shadow-only separation, one surface cue), the proof chips stop
   impersonating buttons, and the compliance footnote steps up one ink. */
.hero-art svg { width: 100%; max-width: 100%; }
.hero-art-frame { border-color: transparent; }
.hero-chips .chip {
  background: none; border: 0; box-shadow: none; padding: 0;
}
.hero-copy > .micro { color: var(--ink-2); }

/* ---- v6.2: the hero pipeline preview becomes a VERTICAL flow ----------------
   In a 705 px-tall frame the horizontal pill strip left a ~200 px dead band
   under the caption and the fifth station had needed wrap workarounds (the old
   3+2 grid). A top→bottom step list is the natural grammar for a tall instrument
   card (design.md: the horizontal left→right flow stays on the full-width demo
   board, where it belongs). Rows are plain icon+label with connector ticks —
   they no longer look like buttons, which the pills previously did. */
.mini-pipe {
  display: flex; flex-direction: column;
  gap: 0; padding: var(--s4) 0 0; border-top: 1px solid var(--line);
}
.mini-pipe li {
  display: flex; align-items: center; gap: var(--s3);
  position: relative; padding: 9px 0;
  border: 0; background: none; border-radius: 0;
}
.mini-pipe li::before {          /* connector tick between the station icons */
  content: ""; position: absolute; left: 7px; top: -9px;
  width: 2px; height: 18px; background: var(--line-2);
}
.mini-pipe li:first-child::before { display: none; }
.mini-pipe li .ic { width: 15px; height: 15px; flex: none; }
.mini-pipe li.is-done { color: var(--ok); background: none; border-color: transparent; }
.mini-pipe li.is-review { color: var(--warn); background: none; border-color: transparent; }
.mini-pipe li.is-review { animation: none; }
@media (prefers-reduced-motion: no-preference) {
  .mini-pipe li.is-review { animation: pipe-review 6s ease-in-out infinite; }
}
/* final vision nits (same pass): the spine must visibly REACH Revisión, and the
   review ring was a 4 px amber halo that boxed the row off from the chain —
   both state signals, at state grammar scale (a tick and a whisper, not a box) */
.mini-pipe li.is-review::before { background: rgba(150, 98, 10, .35); }
@keyframes pipe-review { 50% { box-shadow: 0 0 0 3px rgba(150, 98, 10, .07); } }

/* ============================================================================
   v7 vision pass — hero instrument details (2026-10-23)
   Each rule answers one defect SEEN in a rendered capture (1440 and 390) and
   confirmed in the code before patching; engine.js / parity.node.js / fixture.js
   are not touched anywhere in this block.
   ============================================================================ */

/* The vertical pipeline preview had no name — its tie to the "pipeline
   verificable" claim in the lead was only implicit, and the hairline opened a
   bare list. The rule now opens a LABELLED instrument. */
.pipe-label {
  margin: 0; padding-top: var(--s4);
  border-top: 1px solid var(--line);
  font-family: var(--font-mono); font-size: var(--fs-eyebrow); font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
.mini-pipe { border-top: 0; padding-top: 0; }

/* Operator column — who runs each station (design.md role map: the assistant
   runs Ingest→Explain; a human signs off Revisión). It fills the row across the
   wide card and states WHY row 5 is amber: HUMANA uses the review state color. */
.mini-pipe li .op {
  margin-left: auto;
  font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
}
.mini-pipe li.is-review .op { color: var(--warn); }

/* ============================================================================
   v7.2 (2026-10-23, second vision pass) — eyebrow rail on phones.
   .eyebrow is inline-flex (tokens.css: dash ::before + gap + one text item),
   so when the label wraps at phone widths the second line hangs at the TEXT
   ITEM box, ~22 px right of the rail the H1/lead/buttons all share — an
   orphan word visibly off-axis (measured at 390: line 2 x=48 vs rail x=24;
   confirmed independently by two vision reviewers). Fix: below 640 px the
   eyebrow becomes a block and the dash floats, so wrapped lines return to
   the rail while line 1 keeps its dash+gap rhythm. Non-wrapping eyebrows
   render pixel-identically (float + one line = same positions).
   tokens.css untouched (owner's readability pass preserved). */
@media (max-width: 640px) {
  .eyebrow { display: block; }
  .eyebrow::before {
    float: left; margin: 7px 8px 0 0;   /* 2 px bar, optically centred on the first line */
  }
}

/* ============================================================================
   SECTION RHYTHM NORMALIZATION (2026-10-23)
   tokens.css gives .section a full padding-block of --sec-pad (clamp 58→100px)
   on BOTH sides, so two adjacent sections stacked ~200px of dead space between
   them (and ~172px under the hero) — the page read half-empty. The directive
   asks for ~96–120px between adjacent sections on desktop and a proportional
   ~60–72px on phones. Halving each side to ~48–60px desktop / ~30–36px mobile
   restores that rhythm. Title-to-content (the .section-head bottom margin) is
   already clamp 26→44px, i.e. 44px on desktop — inside the 32–48px band — so
   it is left as-is. Horizontal gutters, colour and type are untouched.
   ========================================================================== */
.section { padding-block: clamp(48px, 5vw, 60px); }

@media (max-width: 640px) {
  .section { padding-block: clamp(30px, 9vw, 36px); }
}
